hoge diary - September 5, 2006

[Linux] Kopete の Keep-Alive と Regnessem

私は Kopete を使用していますが,そのうち MSN Messenger 上の友人から「空のメッセージが送られる」という指摘を受けました.Kopete にパッチを当てれば何とかなるんだろうなぁ,と思ってはいたのですが,詳しい原因が分からぬまま時は過ぎ...

今になってようやく,空のメッセージが送られるのは Regnessem 使用者であることがわかりました (私自身も Regnessem を使用したところ,Kopete を使用している他のユーザから 50 秒おきに空のメッセージが送信されることを確認しました).

「50 秒」というのが Kopete のソースを追いかける手がかりになりそうです.あとは kopete-3.5.4 のソースを展開し,「50」や「50000」などのキーワードで検索すると... ありました.msnswitchboardsocket.cpp の 812 行目,862 〜 868 行目に,Keep-alive メッセージを送信するコードが記述されています.以下に該当個所を引用しておきます.

812: if(!m_keepAlive)
813:  {
814:    m_keepAliveNb=20;
815:    m_keepAlive=new QTimer(this);
816:    QObject::connect(m_keepAlive, SIGNAL(timeout()) , this , SLOT(slotKeepAliveTimer()));
817:    m_keepAlive->start(50*1000);
818:  }
862:     if(!m_keepAlive)
863:     {
864:         m_keepAliveNb=20;
865:         m_keepAlive=new QTimer(this);
866:         QObject::connect(m_keepAlive, SIGNAL(timeout()) , this , SLOT(slotKeepAliveTimer()));
867:         m_keepAlive->start(50*1000);
868:     }

タイマーを使って 50 秒おきに Keep-alive メッセージを送っているようです.実際に送る関数 (slotKeepAliveTimer()) を見てみると... 次のようにコードが書かれています.

1100:    if ( onlineStatus() != Connected || m_chatMembers.empty())
1101:    {
1102:        //we are not yet in a chat.
1103:        //if we send that command now, we may get disconnected.
1104:        return;
1105:    }
1106:
1107:
1108:    QCString message = QString( "MIME-Version: 1.0\r\n"
1109:            "Content-Type: text/x-keepalive\r\n"
1110:            "\r\n" ).utf8();
1111:
1112:    // Length is appended by sendCommand()
1113:    QString args = "U";
1114:    sendCommand( "MSG", args, true, message );

どうやらチャットウィンドウが開いている状態でないと,Keep-alive メッセージは送信されないようにはなっていますが,1114 行目に sendCommand( "MSG", args, true, message ); と書いてあるので,おそらく普通のメッセージとして Keep-alive を送信しているのでしょう.試しに Regnessem 上で,Kopete ユーザのチャットウィンドウを閉じてみると... 確かにその人からの Keep-alive は来なくなります.

Content-Type: text/x-keepalive という MIME タイプを指定してはいますが,Regnessem からはこれが通常のメッセージであると見做してしまうようです.本家 MSN Messenger や Windows Live Messenger では Regnessem 相手にこのような現象が起こらないようなので,少なくとも Kopete のような Keep-alive メッセージは送っていないと判断し,ここは Kopete にパッチを当てて,この Keep-alive を抑制してみます.

パッチの当て方は至って簡単で,msnswitchboardsocket.cpp の 812 〜 818 行と,862 〜 868 行目をコメントアウトするだけです.

パッチを当てた Kopete を起動してみると,チャットウィンドウを開いたままの状態でも 50 秒おきに空メッセージが来ることはなくなりました.

次は,Regnessem を使用しているユーザがサインインしてオンラインになったとき,もしくは不可視状態からオンラインになったときに,Regnessem 側の会話ウィンドウ (もちろん相手は Kopete ユーザです) が開いてしまう,という点についても解決したいと思います.

動作から推測すると,Kopete 側において,コンタクトリストに登録されているユーザがオンラインになったときに,空の会話メッセージを送信しているような気がします.というわけで,Kopete のソースを追いかけて,コンタクトリスト上の相手のステータスが変化したときのイベントハンドラを探してみたのですが,途中で面倒になったので,もっと検索範囲を一気に絞りこみます.

おもむろに Wireshark (旧 ethereal) を起動して,MSN サーバとの通信をログに記録します.Regnessem 側にポップアップが表示されるところから考えて,MSG コマンドを送信しているはずです.ログ中に MSG がないかどうかを探すと... ありました.

MSG 2 D 595
MIME-Version: 1.0
Content-Type: application/x-msnmsgrp2p
P2P-Dest: (相手側のメールアドレス)

(この部分にも情報が書かれているが,ASCII 文字でないので省略)
To: <msnmsgr:(相手側のメールアドレス)>
From: <msnmsgr:(自分側のメールアドレス)>
Via: MSNSLP/1.0/TLP ;branch={A0B93F34-746D-3161-122D-AD856249368A}
CSeq: 0
Call-ID: {63F62291-626B-814E-35D2-6F2E98446455}
Max-Forwards: 0
Content-Type: application/x-msnmsgr-sessionreqbody
Content-Length: 99

EUF-GUID: {A4268EEC-FEC5-49E5-95C3-F126696BDBF6}
SessionID: 144262341
AppID: 1
Context: MA

(NULL)(NULL)(NULL)(NULL)(NULL)

以上のデータが送信されていました.あとはデータの断片を手がかりに Kopete のソースコードを検索すると... dispatcher.cpp の 79 〜 106 行目にそれらしきコードが見つかりました.

79: void Dispatcher::requestDisplayIcon(const QString& from, const QString& msnObject)
 80: {
 81:   Q_UINT32 sessionId = rand()%0xFFFFFF00 + 4;
 82:   TransferContext* current =
 83:     new IncomingTransfer(from, this, sessionId);
 84:
 85:   current->m_branch = P2P::Uid::createUid();
 86:   current->m_callId = P2P::Uid::createUid();
 87:   current->setType(P2P::UserDisplayIcon);
 88:   current->m_object = msnObject;
 89:   // Add the transfer to the list.
 90:   m_sessions.insert(sessionId, current);
 91:
 92:   kdDebug(14140) << k_funcinfo << "Requesting, " << msnObject << endl;
 93:
 94:   QString context = QString::fromUtf8(KCodecs::base64Encode(msnObject.utf8()));
 95:   // NOTE remove the \0 character automatically
 96:   // appended to a QCString.
 97:   context.replace("=", QString::null);
 98:   QString content =
 99:     "EUF-GUID: {A4268EEC-FEC5-49E5-95C3-F126696BDBF6}\r\n"
100:     "SessionID: " + QString::number(sessionId) + "\r\n"
101:     "AppID: 1\r\n"
102:     "Context: " + context + "\r\n"
103:     "\r\n";
104:   // Send the sending client an invitation message.
105:   current->sendMessage(INVITE, content);
106: }

強調部分が見付かったコードです.この関数の名前が requestDisplayIcon() であることから,おそらくはコンタクトリストの画像を要求しているコードと思います.

つまり,Kopete は,相手ユーザがオンラインになったときに,自動的に相手のコンタクトリスト画像を要求するメッセージを送信し,それを Regnessem が受け取って会話ウィンドウをオープンする,ということのようです.

Kopete の設定を変更してコンタクトリスト画像を要求しないようにすればいいのでしょうが,それは嫌なので,別な方法で解決する必要があります.

今日は力尽きたので,続きは次の機会にします.

コメント

名前(何でも可):

テキスト(http:// を含む内容は投稿できません):

トラックバック

トラックバック URI: https://www.pakunet.jp/hoge/trackback/2006090501

トラックバックはありません.


Valid XHTML 1.1! Valid CSS!
© 2004-2009 ぱくちゃん.
Last modified: Thu Nov 01 01:17:08 JST 2007