プロトコルに関するいくつかの言葉
メッセージは、特定の形式のパケットで送信されます。 最初の44バイトは、次のようなヘッダーです。
struct.pack( '<7L16s', magic, # DEAD BEEF, , , MMP proto, # seq, # msg, # : / /... dlen, # from_, # , fromport, # , reserved # 16 )
ここの番号はUL形式で送信されます。これは、右から左に4バイトが書き込まれているように見えます。 したがって、数値10は00 00 00 0Aになります。 したがって、ULで梱包します。
class MRIMType(object): def __init__(self, value): self.value = value class UL(MRIMType): def pack(self): if isinstance(self.value, int): return struct.pack("<L", self.value) else: return struct.pack("<L", len(self.value))
テキストはLPS形式で送信されます-指定された長さの文字列(長さはULの形式で指定されます)。 このようにパックします:
class LPSZ(MRIMType): def pack(self): if isinstance(self.value, (list, tuple)): # data = "" data += UL(self.value).pack() for element in self.value: data += element.pack() return data elif isinstance(self.value, MRIMType): # data = self.value.pack() return struct.pack("<L", len(data)) + data else: data = self.value return struct.pack("<L", len(data)) + data
また、他のエンコーディングでLPSの行をパックする必要があります。
class LPSX(MRIMType): def __init__(self, value, encoding): super(LPSX, self).__init__(value) self.encoding = encoding def pack(self): encoded_data = self.value.encode(self.encoding) return struct.pack("<L", len(encoded_data)) + encoded_data class LPSW(LPSX): def __init__(self, value): super(LPSW, self).__init__(value, encoding="UTF-16LE") class LPSA(LPSX): def __init__(self, value): super(LPSA, self).__init__(value, encoding="cp1251")
書式設定されたテキストメッセージ
メッセージがどのように見えるか見てみましょう。 ヘッダーのmsgフィールドには、定数0x1008を入力する必要があります。そうでない場合、メッセージパケットは次のようになります。
HEADER UL(0x80), LPSA(recipient), # email LPSW(body), # , LPSZ(rtf_part)
パッケージの最後のコンポーネントは、テキストの書式設定に関連するメッセージの一部です。 フォーマットが不要な場合、rtf_partはスペースで構成する必要があります。 この場合、このメッセージが送信されるMail.Ruエージェントは、受信者エージェントのデフォルトのフォントを使用します。
フォーマットされたメッセージを送信する場合、パケットの最後の部分はLPSZ(rtf_part)である必要があります。ここで、
rtf_part = pack_rtf(rtf) def pack_rtf(rtf): msg = UL(2).pack() + LPSZ(rtf).pack() + LPSZ("\xFF\xFF\xFF\x00").pack() message = base64.b64encode(msg.encode('zlib')) return message
最後の用語は背景色です。メッセージを受信すると、チャットウィンドウの色が完全に変わります。
「qwerty」を記述するためのrtfは次のようになります。
r"{{\rtf1\ansi\ansicpg1252\deff0\deflang1033" \ # r"{{\fonttbl{{\f0\fnil\fcharset204 Tahoma;}}{{\f1\fnil\fcharset0 Tahoma;}}}}\ # , . r"{{\colortbl ;\red0\green0\blue0;}} " \ # r"\viewkind4\uc1\pard\cf1\f0\fs32 q\f1 werty\f0\par }}" # ,
最初の文字が1つのフォントで書かれ、残りが別のフォントで書かれていることに気付くかもしれません。 この動作を説明することはできませんが、取得したMail.Ruエージェントによって生成されたrtfはこのように見えました。 このプロパティを持たないrtfsは有効なままです。 その他のパラメーター(言語、フォントテーブル、ロシア語)は、rtfの有効性に影響します。
メッセージのrtf部分が空でない場合、メッセージに含まれることに注意してください。 メッセージの本文部分(本文)が示されている場合、Mail.Ru Agentのポップアップウィンドウにこのテキストが表示されます。
カンファレンス
別の連絡先とチャットを開始するためにメッセージを送信するだけで、会議での会話を開始するために数回スクワットする必要がある場合。
会議の作成
各会議には、5895986 @ chat.agentのような独自の一意の名前があり、このメッセージへの応答としてサーバーから受信します。
HEADER # 0x1019 UL(0x80), LPSW(""), LPSW(""), LPSW(chat_name), # , LPSW(""), LPSW(""), LPSW(""), LPSZ(LPSZ(LPSZ(packed_recipients))) #
このメッセージに応答して、ヘッダーとIDに同じ番号を持つメッセージがサーバーから届きます。 サーバーから応答を受信した後、会議にメッセージを送信できます。
会議へのメッセージの送信
会議にメッセージを送信するには、2つのパケットを送信する必要があります。 最初のパッケージにはセマンティックロードはありません。準備です。
HEADER # -- (0x1008) UL(0x200400), LPSA(chat_alias), # , LPSZ(" "), LPSZ("")
そして今、直接、メッセージ:
HEADER UL(0x80), LPSA(chat_alias), LPSW(body), LPSZ(rtf_part)
会議IDを含む通常のメッセージのように見えます。
会議を終了する
自動テストを実装するにはこれらの研究が必要でした。 すぐに問題に遭遇しました-アカウントは限られた数の会議に参加できます。 したがって、テストの最後に会議から退出する必要があります。
HEADER # , 0x101B UL(absolute_chat_number), # , . UL(0x0081), UL(0xF4244), LPSZ(chat_alias), # LPSW(chat_name), # LPSZ(""),
絶対的な会議番号を取得する方法を理解することはできませんでしたが、チャットの識別が行われないことが実験的に判明しました。 そのため、42などの適切な数を指定できます。
私の研究は完全とはほど遠いので、訂正や追加を喜んでいます。