Hatena::ブログ(Diary)

ヒルズで働くholidays-lの技ログ このページをアンテナに追加 RSSフィード Twitter

2011年11月01日

[][]コマンドラインからMessage-IDを指定してメールを開く方法。それをOrgMode(Emacs)からも開けるようにする。

ThunderLink :: Add-ons for Thunderbirdを入れる。たったこれだけで

thunderbird.exe -thunderlink thunderlink://messageid=メッセージID

という風に-thunderlinkオプションを使って起動すれば指定したメールが開ける。

Thunderbirdが起動していなかったら単品メールウィンドウが、既に起動済みなら対象メールが選択された状態になる。


説明ではOSのシェルにurl handler関連付けるように書かれているが、必要でなければやらなくて良い。

というのも、元々やりたかったのが「OrgMode(on NTEmacs)において、メール本文ではなくメールへのリンクを埋め込みたい」だったので、thunderlinkをEmacsから開けるようにした。

まず、ffapでリンクを認識するためにffap-url-regexpを修正。

(setq ffap-url-regexp (replace-regexp-in-string "mailto:" "thunderlink:\\\\|mailto:" ffap-url-regexp)) ;; for ThunderLink

次に認識したURLを開くための設定をする。

;; ↓Cygwin専用。Cygwinじゃない場合は適宜修正する。
(defun browse-url-thunderlink (url &optional new-window)
  (interactive (browse-url-interactive-arg "URL: "))
  (if (string-match "^thunderlink://" url)
      (progn
        (start-process (concat "thunderbird " url) nil "cygstart" "thunderbird.exe" "-thunderlink" url)
        t)
    nil)
  )
(unless (listp browse-url-browser-function) (setq browse-url-browser-function (list (cons "." browse-url-browser-function))))
(add-to-list 'browse-url-browser-function '("^thunderlink:" . browse-url-thunderlink))

で、OrgModeにも対応。

(add-hook 'org-load-hook
          #'(lambda ()
              (add-to-list 'org-link-types "thunderlink")
              (org-make-link-regexps)
              (add-hook 'org-open-link-functions 'browse-url-thunderlink)
              ))

2011年09月21日

[][]tiarraのSystem::SendMessage(ControlPort経由)のログをLog::Channel経由で記録する

tiarraの普通の使い方は「(自分 → tiarra)同マシン → IRCサーバー」なのだと思いますが、主に社内IRCサーバーのログ取り用に「皆 → (IRCサーバー ← tiarra)同マシン」の構成になっており、Log::Channelでログを記録しています。

ところが(上記構成が原因なのかどうかはハッキリ分かりませんが、)ControlPortを使ってSystem::SendMessageでしゃべらせると、Log::Channelがそれを記録してくれません。(実はずっと前から困ってた)


System::SendMessage->control_requestedの引数をDumperで眺めてみたら何とかLog::Channelを呼べそうだったので、無理やりLog::Channel->message_arrivedを呼んでみました。senderとか超適当(IrcIO::*をnewしたりするのめんどいから引数に入ってたのをそのまま突っ込んだ)。良い子は真似しないように。

$ svn diff module/System/SendMessage.pm
Index: module/System/SendMessage.pm
===================================================================
--- module/System/SendMessage.pm        (リビジョン 39028)
+++ module/System/SendMessage.pm        (作業コピー)
@@ -56,6 +56,13 @@
            Auto::Utils::sendto_channel_closure(
                $chinfo->fullname, $command, undef, undef, undef, 0
               )->($text);
+               $this->_runloop->mod_manager->get('Log::Channel')->message_arrived(
+                       Tiarra::IRC::Message->new(
+                               Command => $command,
+                               Params  => [ $chinfo->fullname, $text ]
+                       ),
+                       $this->_runloop->{sockets}->[1]
+               );
        }
     }
     if ($matched) {

[][]tiarraのSystem::SendMessage(ControlPort経由)でnick宛に送信するパッチ

どうやらSystem::SendMessageはチャンネル宛にしか送れないらしい。IRC(仕様)もtiarraもNICK宛に送れるので処理が抜けてる気がする。ホントやっつけなんだけど、でっち上げた。

NOTIFY System::SendMessageのChannel部分にカンマ区切りでNICKを指定すると送れる。

マスクとか良く分からないので無視してるので良い子は悪戯しないように。

Index: module/System/SendMessage.pm
===================================================================
--- module/System/SendMessage.pm        (リビジョン 39028)
+++ module/System/SendMessage.pm        (作業コピー)
@@ -58,6 +58,17 @@
               )->($text);
        }
     }
+    if ( !$matched ) {
+        my %nick;
+        $nick{$_} = 1 for split /,/msx, $mask;
+        foreach my $person ( $server->person_list ) {
+            if ( exists $nick{ $person->nick } ) {
+                ++$matched;
+                Auto::Utils::sendto_channel_closure( $person->nick, $command,
+                    undef, undef, undef, 0 )->($text);
+            }
+        }
+    }
     if ($matched) {
        my $reply = ControlPort::Reply->new(200, 'OK');
        $reply->MatchedChannels($matched);

2011年08月23日

[開発]GNU makeのMakefileに、シェルスクリプトを自然に書くたった一つの方法

たった一つとか嘘です。

ググッても中々出てこなくて、ちょっといじってたらできちゃったので書き残しておきます。


GNU makeでは1行毎に1つのシェルで実行されるので、

foo::
	if true ; then echo "make love" ; fi

foo::
	$(SHELL) -c 'if true ; then echo "make love" ; fi'

と同じような挙動になります。


よってシェルスクリプトが複数行に渡る場合、

foo::
	if true
	then
          echo "make love"
	fi

なんて書いてしまうと、

foo::
	$(SHELL) -c 'if true'
	$(SHELL) -c 'then'
	$(SHELL) -c '  echo "make love"'
	$(SHELL) -c 'fi'

という感じで実行されることになるので当然エラーになります。


そこで以下のような書き方が良く用いられています。

foo::
	if true ;\
	then \
	  echo "make love" ;\
	fi

これ見た目上は複数行に分けて書けてはいますが、セミコロンの有無がワケワカランことになる上に、長くなってくると非常に猛烈に見辛くなります。しんどいです。



ここで、GNU makeでヒアドキュメントのようなことをする方法を紹介しておきます。

defineを使うと、通常の変数宣言とは違って改行を含めることができます。GNU make 日本語訳(Coop編) - 変数の利用法

define FOO
a
b
c
endef

ただこれをそのまま変数として

foo::
	echo "$(FOO)"

のように使ってしまうと

foo::
	echo "a
b
c
"

と展開され、これまた各行が1行ずつシェルに実行されてしまうのでエラーになります。


そこで、変数をexportして環境変数として扱います。

export FOO
foo::
	echo "$${FOO}"


ここまでくれば後は簡単でしょう。

echoしたものをshに食わせれば良いだけです。

define MAKELOVE
if true
then
  echo "make love"
fi
endef
export MAKELOVE
foo::
	echo "$${MAKELOVE}" | $(SHELL)
あら?インタラクティブシェルじゃなくなってしまって困るぞ…。
foo::
	echo "$${MAKELOVE}" > /tmp/$$$$ ; $(SHELL) /tmp/$$$$ ; rm -f /tmp/$$$$
とりあえずこれでお茶を濁し中…

どや?

ちなみに、シェル変数は相変わらず$$varnameと$を重ねて書かないといけないので、完璧に自然なシェルスクリプトになるわけではありません。あしからず。


みんなもっとmake loveしようぜ。

make: don't know how to make love. Stop.

2011年08月19日

[その他]そして運ばれてくるアイスコーヒー4つ

俺「え〜持ち帰りで、」

店員「はい!お持ち帰りですね」

俺「メガマフィンセット、アイスコーヒーで」

店員「かしこまりました!」

俺「追加で、クーポン382番のアイスコーヒー」

店員「えっ?」

俺「ん?アイスコーヒー2つです」

店員「メガマフィンセット…アイスコーヒー2つ…クーポンご利用でアイスコーヒーですね!」

俺「(ん?何かアイスコーヒー多くね?分かってんのか?)アイスコーヒーは合計2つです」

店員「かしこまりました。こちらでお召し上がりですか?」

俺「いや、持ち帰りで(おめぇ話聞いてねぇのかよ…)」

店員「お会計460円になります」

…会計完了…

店員「ソーセージエッグマフィンセットとアイスコーヒーをお待ちのお客様、おまたせしました!」

俺「えっ。メガマフィンなんすけど(てめぇ話聞いてねぇのかよ…)」

値段を確認して30円追加で払う。店員レジ打ち直し中。

しかし遅い…。何回も打ち間違えて何枚もレシート出してる。

俺「…(一瞬見えた『Iコーヒー4』って何だよ…)」

そして裏から運ばれてくるアイスコーヒー2つ。

目の前に並べられる4つのアイスコーヒー。

『そして運ばれてくる生4つ』のコピペを思い出した。


今日も平和です。

2011年08月17日

[PHP]自分用のphp.iniを透過的に適用させる方法

phpに独自の設定をしたいんだけど、その方法が分からなくて困っていた。

いくつか方法はあるんだけど、どれも使い物にならない。

/etc/php.iniを編集するのは論外。他に影響が出ちゃう。

コマンドラインで直接設定してみたり、

$ /usr/bin/php -d a=1 -d b=2 foo.php

自分用設定ファイルを作っておいて読み込ませたり

$ echo -e "a=1\nb=2" > ~/.php/php.ini
$ /usr/bin/php -c ~/.php foo.php

動くには動くけど、毎回オプション付きで/usr/bin/phpを実行しなきゃいけない(=透過的じゃない)。

aliasしとけばいいじゃんって、aliasでは#! /usr/bin/phpなファイル(実行PHPファイル)を実行できない。

# ↓こうしておけば
$ alias php='php -c ~/.php'
# ↓これはできるけど
$ php /usr/bin/pear
# ↓これはできない
$ pear


# ↓これでできるよ、だって?
$ alias pear='/usr/bin/php -c ~/.php /usr/bin/pear'
# ↓コマンド増える度にalias増やすんかい。バカバカしい。
$ alias phpcs='/usr/bin/php -c ~/.php ~/.php/phpcs'
$ alias phpcd='/usr/bin/php -c ~/.php ~/.php/phpcd'


で、最近になってやっと見つけたのが環境変数PHP_INI_SCAN_DIR。たすかったー。

これに指定されたディレクトリから*.iniのファイルを読み込んでくれる。やったー。

ただしディレクトリ1個しか指定できない。えーなんでよー。

もしconfigureで--with-config-file-scan-dirが既に指定されていた場合、

PHP_INI_SCAN_DIRを設定するとそっちを読んでくれなくなる。アホー。

なのでシンボリックリンクで華麗にスルー。もーphpはホントに毎回毎回かゆいところに手が届かん、というかクソ。

$ mkdir ~/.php
$ cd ~/.php
$ ln -s /etc/php.d/* .
$ vi my-php.ini # 名前は.iniで終わっていれば何でもいい。
$ export PHP_INI_SCAN_DIR=~/.php

どや