Описание протокола Mail.Ru агента

Web-разработка

Автор: Eugen

1 нояб. 2011 г., 09:00:53  5161


Приветствую!
Сегодня я расскажу про устройство MRIM протокола (протоколом Mail.Ru агента).
Сразу оговорюсь: есть официальное описание протокола, но оно устаревшее и практически не актуальное.
Найти его можно здесь: http://agent.mail.ru/ru/developers/protocol.html
Протокол исследовался мной с помощью снифера WireShark, официального агента версии 5.2 и QIP Infium версии 9024 (как не странно, у официального агента и у QIP поведение немного разное).
В статье будут фрагменты кода из моего класса MRIM.php (v3).

Итак, начнём.

MRIM (MMP) — бинарный протокол. Следовательно, при работе с сокетом необходимо использовать бинарно-безопасные функции fread и fwrite вместо текстовых fgets и fputs.
Рекомендованный сервер для подключения можно получить отсюда:
mrim.mail.ru:2042 — будет получен сервер с любым портом для подключения (обычно, 2041)
mrim.mail.ru:443 — будет получен сервер с портом для подключения 443. Полезно при работе через прокси-сервер.
Сервер будет получен в формате IP:PORT с символом конца строки после него.

Далее необходимо установить соединение с полученным сервером.

В протоколе используется несколько типов данных:

UL (Unsigned Long) — 4-х байтовое целое беззначное число.
На PHP это выглядит так:

$data = pack('L1',$int);

LPS (Long-Prefixed String) — строки с префиксированной длиной (в виде UL).
На PHP это выглядит так:
$data = pack('L1',strlen($string)).$string;

Z (Zero-endian) — сроки без префиксированной длины, с нулевым байтом в конце (\0).
В текущей версии протокола не используются, однако могут использоваться при обработке серверного списка контактов.

UIDL (Unique ID Listing) — строка длиной в 8 байт, состоящая из любых символов. Используется для идентификации сообщений.

Выражения:
Пустой LPS — LPS с пустой строкой. Т.е. UL, равный нулю.
string — строка без префиксированной длины (предполагается, что длина была указана раньше или заведомо известна)


От себя:
Не понимаю, зачем префиксировать длину строки, используя 4-х байтовое число. 2-х байтовое число (макс. 65535) было бы вполне достаточно (хотя, и это много).


Заголовок любого пакета при работе с MRIM сервером выглядит таким образом:
UL — «магический ключ», указывающий на то, что мы работаем именно с MRIM протоколом. Сейчас равен 0xDEADBEEF.
UL — версия протокола. Сейчас равен 0x010013.
UL — номер пакета (последовательность пакета). Нумерация начинается с нуля и с каждым отправляемым пакетом увеличивается на 1. Когда доходит до своего максимума — 0xFFFFFFFF, вновь сбрасывается в ноль.
UL — идентификатор команды.
UL — длина данных в пакете.
UL — IP в формате INET_ATON (можно передавать 0)
UL — порт (можно передавать 0)
ULx4 — 4 зарезервированных UL для дальнейшего расширения протокола. При отправке пакетов заполняются нулями.
string — данные пакета. Длина этой строки указана в 5-м UL.
 

Функция для генерации пакетов выглядит таким образом:

function make_packet($msg,$data = '')
{
    $dlen = ($data?strlen($data):0);
    $mrim_packet = pack('L*',$this->CS_MAGIC,$this->PROTO_VERSION,$this->mnumb,$msg,$dlen,0,0,0,0,0,0);
    if($data)
        $mrim_packet .= $data;
    if($this->mnumb == 0xFFFFFFFF)
        $this->mnumb = 0;
    else
        $this->mnumb++;
    return $mrim_packet;
}


Константы протокола:
 

var $CS_MAGIC = 0xDEADBEEF;
var $PROTO_VERSION = 0x00010013;
var $CONTACT_FLAG_GROUP = 0x02;
var $CONTACT_FLAG_IGNORE = 0x10;
var $CONTACT_FLAG_INVISIBLE = 0x04;
var $CONTACT_FLAG_REMOVED = 0x01;
var $CONTACT_FLAG_SHADOW = 0x20;
var $CONTACT_FLAG_SMS = 0x100000;
var $CONTACT_FLAG_VISIBLE = 0x08;
var $CONTACT_INTFLAG_NOT_AUTHORIZED = 0x01;
var $CONTACT_OPER_ERROR = 0x01;
var $CONTACT_OPER_GROUP_LIMIT = 0x6;
var $CONTACT_OPER_INTERR = 0x02;
var $CONTACT_OPER_INVALID_INFO = 0x04;
var $CONTACT_OPER_NO_SUCH_USER = 0x03;
var $CONTACT_OPER_SUCCESS = 0x00;
var $CONTACT_OPER_USER_EXISTS = 0x05;
var $FILE_TRANSFER_MIRROR = 4;
var $FILE_TRANSFER_STATUS_DECLINE = 0;
var $FILE_TRANSFER_STATUS_ERROR = 2;
var $FILE_TRANSFER_STATUS_INCOMPATIBLE_VERS = 3;
var $FILE_TRANSFER_STATUS_OK = 1;
var $GET_CONTACTS_ERROR = 0x01;
var $GET_CONTACTS_INTERR = 0x02;
var $GET_CONTACTS_OK = 0x00;
var $LOGOUT_NO_RELOGIN_FLAG = 0x10;
var $MAX_CLIENT_DESCRIPTION = 256;
var $MESSAGE_DELIVERED = 0x00;
var $MESSAGE_FLAG_ALARM = 0x4000;
var $MESSAGE_FLAG_AUTHORIZE = 0x08;
var $MESSAGE_FLAG_CONTACT = 0x0200;
var $MESSAGE_FLAG_MULTICAST = 0x1000;
var $MESSAGE_FLAG_NORECV = 0x04;
var $MESSAGE_FLAG_NOTIFY = 0x0400;
var $MESSAGE_FLAG_OFFLINE = 0x01;
var $MESSAGE_FLAG_OLD = 0x200000;
var $MESSAGE_FLAG_RTF = 0x80;
var $MESSAGE_FLAG_SMS = 0x0800;
var $MESSAGE_FLAG_SMS_NOTIFY = 0x2000;
var $MESSAGE_FLAG_SPAM = 0x010000;
var $MESSAGE_FLAG_SYSTEM = 0x40;
var $MESSAGE_FLAG_UNI = 0x100000;
var $MESSAGE_REJECTED_DENY_OFFMSG = 0x8006;
var $MESSAGE_REJECTED_INTERR = 0x8003;
var $MESSAGE_REJECTED_LIMIT_EXCEEDED = 0x8004;
var $MESSAGE_REJECTED_NOUSER = 0x8001;
var $MESSAGE_REJECTED_TOO_LARGE = 0x8005;
var $MESSAGE_USERFLAGS_MASK = 0x36A8;
var $MRIM_ANKETA_INFO_STATUS_DBERR = 2;
var $MRIM_ANKETA_INFO_STATUS_NOUSER = 0;
var $MRIM_ANKETA_INFO_STATUS_OK = 1;
var $MRIM_ANKETA_INFO_STATUS_RATELIMERR = 3;
var $MRIM_CS_ADD_CONTACT = 0x1019;
var $MRIM_CS_ADD_CONTACT_ACK = 0x101A;
var $MRIM_CS_ANKETA_INFO = 0x1028;
var $MRIM_CS_AUTHORIZE = 0x1020;
var $MRIM_CS_AUTHORIZE_ACK = 0x1021;
var $MRIM_CS_CHANGE_STATUS = 0x1022;
var $MRIM_CS_CONNECTION_PARAMS = 0x1014;
var $MRIM_CS_CONTACT_LIST2 = 0x1037;
var $MRIM_CS_DELETE_OFFLINE_MESSAGE = 0x101E;
var $MRIM_CS_FILE_TRANSFER = 0x1026;
var $MRIM_CS_FILE_TRANSFER_ACK = 0x1027;
var $MRIM_CS_GET_MPOP_SESSION = 0x1024;
var $MRIM_CS_HELLO = 0x1001;
var $MRIM_CS_HELLO_ACK = 0x1002;
var $MRIM_CS_LOGIN_ACK = 0x1004;
var $MRIM_CS_LOGIN_REJ = 0x1005;
var $MRIM_CS_LOGIN2 = 0x1038;
var $MRIM_CS_LOGOUT = 0x1013;
var $MRIM_CS_MAILBOX_STATUS = 0x1033;
var $MRIM_CS_MESSAGE = 0x1008;
var $MRIM_CS_MESSAGE_ACK = 0x1009;
var $MRIM_CS_MESSAGE_RECV = 0x1011;
var $MRIM_CS_MESSAGE_STATUS = 0x1012;
var $MRIM_CS_MODIFY_CONTACT = 0x101B;
var $MRIM_CS_MODIFY_CONTACT_ACK = 0x101C;
var $MRIM_CS_MPOP_SESSION = 0x1025;
var $MRIM_CS_NEW_EMAIL = 0x1048;
var $MRIM_CS_OFFLINE_MESSAGE_ACK = 0x101D;
var $MRIM_CS_PING = 0x1006;
var $MRIM_CS_SMS = 0x1039;
var $MRIM_CS_SMS_ACK = 0x1040;
var $MRIM_CS_USER_INFO = 0x1015;
var $MRIM_CS_USER_STATUS = 0x100F;
var $MRIM_CS_WP_REQUEST = 0x1029;
var $MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY = 6;
var $MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY_DAY = 14;
var $MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY_MONTH = 13;
var $MRIM_CS_WP_REQUEST_PARAM_CITY_ID = 11;
var $MRIM_CS_WP_REQUEST_PARAM_COUNTRY_ID = 15;
var $MRIM_CS_WP_REQUEST_PARAM_DATE1 = 7;
var $MRIM_CS_WP_REQUEST_PARAM_DATE2 = 8;
var $MRIM_CS_WP_REQUEST_PARAM_DOMAIN = 1;
var $MRIM_CS_WP_REQUEST_PARAM_FIRSTNAME = 3;
var $MRIM_CS_WP_REQUEST_PARAM_LASTNAME = 4;
var $MRIM_CS_WP_REQUEST_PARAM_MAX = 16;
var $MRIM_CS_WP_REQUEST_PARAM_NICKNAME = 2;
var $MRIM_CS_WP_REQUEST_PARAM_ONLINE = 9;
var $MRIM_CS_WP_REQUEST_PARAM_SEX = 5;
var $MRIM_CS_WP_REQUEST_PARAM_STATUS = 10;
var $MRIM_CS_WP_REQUEST_PARAM_USER = 0;
var $MRIM_CS_WP_REQUEST_PARAM_ZODIAC = 12;
var $MRIM_GET_SESSION_FAIL = 0;
var $MRIM_GET_SESSION_SUCCESS = 1;
var $PARAM_VALUE_LENGTH_LIMIT = 64;
var $PARAMS_NUMBER_LIMIT = 50;
var $SMS_ACK_DELIVERY_STATUS_INVALID_PARAMS = 0x10000;
var $SMS_ACK_DELIVERY_STATUS_SUCCESS = 1;
var $SMS_ACK_SERVICE_UNAVAILABLE = 2;
var $STATUS_AWAY = 0x02;
var $STATUS_FLAG_INVISIBLE = 0x80000000;
var $STATUS_OFFLINE = 0x00;
var $STATUS_ONLINE = 0x01;
var $STATUS_OTHER = 0x04;
var $STATUS_UNDETERMINATED = 0x03;



При приёме пакета мы должны в начале прочитать 44 байта (т.е. заголовок пакета):
$answ = fread($this->sock,44);
Затем, парсим информацию из заголовка. Нас интересует длина данных в пакете.
list(,$magic,$proto,$seq,$msg,$dlen,$from,$fromport,$r1,$r2,$r3,$r4) = unpack('L*',$answ);
Проверяем, если $dlen больше нуля и читаем данные пакета (без проверки на ноль fread выдаст Warning, если в пакете нет данных. Нам оно нужно?):
$a = fread($this->sock,$dlen);
После подключения мы должны серверу отправить такой пакет:
Идентификатор команды равен MRIM_CS_HELLO.
В качестве ответа мы должны получить пакет, в данных которого один UL — время пинга. После этого мы должны посылать серверу пакет «PING» один раз в указанный здесь промежуток.

Пакет «PING»:
Идентификатор команды равен MRIM_CS_PING.
Данных в пакете нет.

Авторизация на сервере:
При авторизации логин и пароль передаются на сервер открытым текстом. Безопасный вход в протоколе пока не предусмотрен.
Пакет выглядит следующим образом:
Идентификатор команды равен MRIM_CS_LOGIN2.
LPS — логин (адрес почты)
LPS — пароль
UL — статус (при установке статуса «невидим» необходимо объединить флаги таким образом: $this->STATUS_ONLINE | $this->STATUS_FLAG_INVISIBLE при установке «нестандартного» статуса используется флаг STATUS_OTHER)
LPS — название статуса (STATUS_ONLINE, STATUS_INVISIBLE, STATUS_AWAY, status_*) (где * — идентификатор дополнительного статуса, т.е. любое число или слово)
LPS — заголовок икс-статуса в кодировке UTF-16LE
LPS — текст икс-статуса в кодировке UTF-16LE
UL — неизвестный мне параметр. Равен 0x03FF. (Предположительно, служит для скрытия/отображения названия/версии клиента. Второе значение, которое я встречал — это 0xFFFFFFFF.)
LPS — описание клиента в таком формате: client=«название» version=«версия» build=«сборка»
LPS — язык клиента (стандартно — ru)
LPS — строка с кратким описанием клиента (в произвольном формате)
В качестве ответа мы должны получить идентификатор команды (далее — MSG) равным MRIM_CS_LOGIN_ACK. В противном случае, вход невозможен (вероятно, неверный пароль или аккаунт временно заблокирован)



Пакеты, отправляемые на сервер:


Отправка сообщения:
Возможна отправка сообщений нескольких типов. Все тексты сообщений в кодировке UTF-16LE. Пакет при этом выглядит таким образом:
MSG равен MRIM_CS_MESSAGE.
UL — флаги (тип) сообщения.
LPS — адрес, кому адресовано сообщение.
LPS — текстовая версия сообщения.
LPS — RTF версия сообщения в таком формате: base64_encode(gzcompress(UL — количество LPS (2), LPS — RTF текст со всеми заголовками, LPS — цвет фона в виде UL (т.е. UL внутри LPS, такой вот маразм)))
При отправке простых сообщений RTF версию можно не передавать. (флаг равен 0, MESSAGE_FLAG_OFFLINE или MESSAGE_FLAG_RTF при наличии RTF версии сообщения)
При отправке запроса авторизации текст должен указываться в таком формате: base64_encode(UL — количество LPS (2), LPS — мой ник в кодировке UTF-16LE, LPS — текст запроса авторизации), RTF версия может быть пустой. Флаг равен MESSAGE_FLAG_AUTHORIZE.
При отправке уведомления «вам печатают» текст и весь LPS с RTF версией должны состоять из одного пробела. Флаг равен MESSAGE_FLAG_NOTIFY.
При отправке «будильника» должны быть указаны и текстовая, и RTF версии сообщения (альтернатива, которую увидит собеседник, если его клиент не поддерживает «будильник»). Флаг равен паре MESSAGE_FLAG_ALARM и MESSAGE_FLAG_RTF ($this->MESSAGE_FLAG_ALARM | $this->MESSAGE_FLAG_RTF).
При отправке списка контактов, текстовая версия предоставляется в формате имя1; адрес1; имя2; адрес2;..., а LPS RTF версии должен состоять из одного пробела. Всё тело текстовой версии передаётся в UTF-16LE. Флаг равен MESSAGE_FLAG_CONTACT)


От себя:
Брррр. Ну и намутили они с RTF версией сообщения.

Отправка SMS сообщений:
MSG равен MRIM_CS_SMS.
UL — неизвестный параметр. Равен нулю.
LPS — номер телефона в международном формате, на который должно быть доставлено сообщение.
LPS — текст сообщения в кодировке UTF-16LE.


Примечание: контакт с этим номером телефона должен быть в списке (как обычный или как SMS контакт).


Одобрение авторизации:
MSG равен MRIM_CS_AUTHORIZE.
LPS — адрес запросившего авторизацию.

Установка нового статуса:
MSG равен MRIM_CS_CHANGE_STATUS.
UL — статус (при установке статуса «невидим» необходимо объединить флаги таким образом: $this->STATUS_ONLINE | $this->STATUS_FLAG_INVISIBLE при установке «нестандартного» статуса используется флаг STATUS_OTHER)
LPS — название статуса (STATUS_ONLINE, STATUS_INVISIBLE, STATUS_AWAY, status_*) (где * — идентификатор дополнительного статуса, т.е. любое число или слово)
LPS — заголовок икс-статуса в кодировке UTF-16LE
LPS — текст икс-статуса в кодировке UTF-16LE
UL — неизвестный мне параметр. Равен 0x03FF. (Предположительно, служит для скрытия/отображения названия/версии клиента. Второе значение, которое я встречал — это 0xFFFFFFFF.)

Добавление нового контакта в список:
MSG равен MRIM_CS_ADD_CONTACT.
UL — флаги.
UL — номер (ID) группы (можно получить из списка контактов)
LPS — адрес добавляемого контакта.
LPS — имя (ник) добавляемого контакта в кодировке UTF-16LE.
LPS — номер телефона добавляемого контакта в международном формате.
LPS — текстовая версия запроса авторизации в формате: base64_encode(UL — количество LPS (2), LPS — мой ник в кодировке UTF-16LE, LPS — текст запроса авторизации в кодировке UTF-16LE)
LPS — предположительно, RTF версия запроса авторизации. Отправляется пустой LPS.
Флаги:
CONTACT_FLAG_INVISIBLE — Контакт должен попасть в список «Я всегда невидим для»
CONTACT_FLAG_VISIBLE — Контакт должен попасть в список «Я всегда видим для»
CONTACT_FLAG_IGNORE — Контакт должен попасть в список игнорируемых
CONTACT_FLAG_SHADOW — Контакт не должен попасть в основной контакт-лист (применяется в паре с одним из трех предыдущих)
CONTACT_FLAG_REMOVED — Контакт удален
CONTACT_FLAG_SMS — Добавляется SMS контакт. При этом адрес равен строке «phone», а ID группы равен 0x67.

Добавление новой группы в список контактов:
MSG равен MRIM_CS_ADD_CONTACT.
UL — флаги (равен CONTACT_FLAG_GROUP).
UL — равен 0.
LPS — пустой LPS.
LPS — имя добавляемой группы в кодировке UTF-16LE.
LPS — текстовая версия запроса авторизации в формате: base64_encode(UL — количество LPS (2), LPS — мой ник в кодировке UTF-16LE, LPS — текст запроса авторизации в кодировке UTF-16LE)
LPS — предположительно, RTF версия запроса авторизации. Отправляется пустой LPS.


От себя:
Не понятно, зачем нужно передавать текст запроса авторизации при добавлении группы? Предполагаю, что два последних LPS могут быть пустыми.


Изменение контакта в списке:
MSG равен MRIM_CS_MODIFY_CONTACT.
UL — ID контакта (можно получить из списка контактов)
UL — флаги.
UL — номер (ID) группы (можно получить из списка контактов), используется для перемещения контакта в другую группу.
LPS — адрес контакта.
LPS — имя (ник) контакта в кодировке UTF-16LE.
LPS — номер телефона контакта в международном формате.
Флаги:
CONTACT_FLAG_INVISIBLE — Контакт должен попасть в список «Я всегда невидим для»
CONTACT_FLAG_VISIBLE — Контакт должен попасть в список «Я всегда видим для»
CONTACT_FLAG_IGNORE — Контакт должен попасть в список игнорируемых
CONTACT_FLAG_SHADOW — Контакт не должен попасть в основной контакт-лист (применяется в паре с одним из трех предыдущих)
CONTACT_FLAG_REMOVED — Контакт удален
CONTACT_FLAG_SMS — SMS контакт. При этом адрес равен строке «phone», а ID группы равен 0x67.

Изменение группы в списке:
MSG равен MRIM_CS_MODIFY_CONTACT.
UL — ID группы (можно получить из списка контактов)
UL — флаги.
UL — равен 0.
LPS — пустой LPS.
LPS — имя группы в кодировке UTF-16LE.
LPS — пустой LPS.
Флаги:
Используется CONTACT_FLAG_GROUP вместе со следующими флагами:
CONTACT_FLAG_SHADOW — Группа не должна попасть в основной контакт-лист
CONTACT_FLAG_REMOVED — Группа удалена

Поиск контакта в базе Mail.Ru:
MSG равен MRIM_CS_WP_REQUEST.
string — данные запроса, состоящие из блоков. Длина не префиксируется.
Каждый блок выглядит следующим образом:
UL — параметр поиска.
LPS — значение параметра.
Допустимые параметры со значениями:
Ник, имя и фамилия указываются в кодировке UTF-16LE.
MRIM_CS_WP_REQUEST_PARAM_USER — логин (без домена), обязан комбинироваться с доменом
MRIM_CS_WP_REQUEST_PARAM_DOMAIN — почтовый домен
MRIM_CS_WP_REQUEST_PARAM_NICKNAME — ник
MRIM_CS_WP_REQUEST_PARAM_FIRSTNAME — имя 
MRIM_CS_WP_REQUEST_PARAM_LASTNAME — фамилия, * в конце ника/имени/фамилии указывает на возможность любого продолжения имени
MRIM_CS_WP_REQUEST_PARAM_SEX — пол. 1 — мужской, 2 — женский
MRIM_CS_WP_REQUEST_PARAM_DATE1 — минимальный возраст (в годах)
MRIM_CS_WP_REQUEST_PARAM_DATE2 — максимальный возраст (в годах)
MRIM_CS_WP_REQUEST_PARAM_CITY_ID — ID региона проживания 
MRIM_CS_WP_REQUEST_PARAM_ZODIAC — Знак зодиака (Овен — 1, ..., Рыбы — 12)
MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY_MONTH — Месяц рождения (Январь — 1, ..., Декабрь — 12)
MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY_DAY — День рождения (обязан комбинироваться с месяцем рождения)
MRIM_CS_WP_REQUEST_PARAM_COUNTRY_ID — ID страны проживания
MRIM_CS_WP_REQUEST_PARAM_ONLINE — ищем ли мы только подключенных в данный момент пользователей (1 — единственное возможное значение)
Параметры могут использоваться в любых комбинациях (кроме случаев, когда один параметр обязан комбинироваться с другим), в любом порядке и должны соединяться в общую строку string.



Требование ключа для web-авторизации:

MSG равен MRIM_CS_GET_MPOP_SESSION.
Данных в пакете нет.
Используется для входа в почтовый ящик Mail.Ru без дополнительной авторизации и не передавая свой пароль в GET-запросе.
 

Пакеты, принимаемые от сервера:


Информация о пользователе (собственная информация):
MSG равен MRIM_CS_USER_INFO.
string — данные без префиксированной длины.
Данные передаются в виде последовательности LPS. Причём, нечётные LPS — названия параметров, а соотв. чётные — значения параметров.
Основные параметры:
MESSAGES.TOTAL — количество писем в ящике
MESSAGES.UNREAD — количество непрочитанных писем в ящике
MRIM.NICKNAME — ник пользователя
client.endpoint — до конца не ясный параметр. В нём указывается наш IP (с которого мы подключились к серверу) и порт.



Статус пользователя:


Используется сервером для сообщения нам нового статуса одного из наших контактов.
MSG равен MRIM_CS_USER_STATUS.
UL — статус.
LPS — название статуса (STATUS_ONLINE, STATUS_INVISIBLE, STATUS_AWAY, status_*) (где * — идентификатор дополнительного статуса, т.е. любое число или слово)
LPS — заголовок икс-статуса в кодировке UTF-16LE
LPS — текст икс-статуса в кодировке UTF-16LE
LPS — адрес контакта.
UL — неизвестный мне параметр. Равен 0x03FF. (Предположительно, служит для скрытия/отображения названия/версии клиента. Второе значение, которое я встречал — это 0xFFFFFFFF.)
 

Ключ для WEB авторизации:

MSG равен MRIM_CS_MPOP_SESSION.
UL — статус.
LPS — ключ.
Если статус равен MRIM_GET_SESSION_SUCCESS, в последующем LPS будет содержаться ключ, который можно использовать для входа в почтовый ящик.
Для входа в ящик можно использовать URL:win.mail.ru/cgi-bin/auth?Login=адрес&∓agent=ключ
 

Количество писем в почтовом ящике:

MSG равен MRIM_CS_MAILBOX_STATUS.
UL — количество непрочитанных писем в ящике.
Используется сервером для уведомления об изменении количества непрочитанных писем в ящике (приход новой почты или удаление/прочтение писем).
 

Уведомление о приходе нового письма:

MSG равен MRIM_CS_NEW_EMAIL.
UL — количество непрочитанных писем в ящике.
LPS — адрес, от кого получено письмо (в RFC формате в кодировке UTF-16LE)
LPS — тема письма в кодировке UTF-16LE.
 

Входящее сообщение:


MSG равен MRIM_CS_MESSAGE_ACK.
UL — sequence (последовательность) этого сообщения для отправителя.
UL — флаги сообщения.
LPS — адрес отправителя сообщения.
LPS — текстовая версия сообщения.
LPS — RTF версия сообщения.
Форматы и флаги аналогичны используемым при отправке сообщений, однако при наличии флага MESSAGE_FLAG_OLD, текст сообщения передаётся в кодировке Windows-1251.
При приёме сообщения необходимо послать пакет с MSG равным MRIM_CS_MESSAGE_RECV и данными следующего вида:
LPS — адрес, от кого получено сообщение.
UL — sequence сообщения.
Естественно, НЕ НУЖНО отправлять этот пакет, если у нас статус «невидим». В противном случае будет возможна такая проверка на невидимость.
 

Изменение параметров соединения:

MSG равен MRIM_CS_CONNECTION_PARAMS.
UL — новый интервал для отправки пакетов «PING».
При этом ближайший PING должен отправляться уже с учётом нового интервала.
 

Сообщение о разрыве соединения:

MSG равен MRIM_CS_LOGOUT.
UL — причина разрыва.
Если в причине указан флаг LOGOUT_NO_RELOGIN_FLAG, это значит, что агент с данной учётной записью был открыт на другом компьютере.
 

Уведомление об одобрении авторизации:

MSG равен MRIM_CS_AUTHORIZE_ACK.
LPS — адрес одобрившего авторизацию.
 

Входящее оффлайн сообщение:

MSG равен MRIM_CS_OFFLINE_MESSAGE_ACK.
UIDL — ID сообщения.
LPS — текст сообщения со всеми заголовками в RFC-822 формате.
При этом заголовок From содержит адрес отправитела, Date — дату отправки сообщения, X-Mrim-Flags — флаги сообщения (в шестнадцатеричном виде).
Boundary для разделения текстовой и RTF частей может содержаться в заголовке Boundary (хоть это и противоречит RFC) либо в Content-Type.
Флаги сообщения такие же, как при приёме обычного сообщения. Content-Type равный application/x-mrim-auth-req явно указывает на то, что сообщение является запросом авторизации.
Content-Type начинающийся с multipart/ указывает на то, что сообщение содержит RTF часть.
Кодировка сообщения может явно указываться в Content-Type, а может и не указываться.
В таком случае необходимо проверить флаги на наличие MESSAGE_FLAG_OLD и при его наличии рассматривать сообщение в кодировке Windows-1251. В противном случае — кодировка сообщения UTF-16LE.
Content-Transfer-Encoding указывает на метод кодирования сообщения (base64, quoted-printable и т.п.)
Сообщение было отправлено, пока мы находились не в сети.

От себя:
Да уж… Перемудрили с RFC здесь. Гораздо разумнее было бы использовать UL/LPS для передачи сообщения...


Список контактов:

MSG равен MRIM_CS_CONTACT_LIST2.
Типы данных в масках:
u — UL
s — LPS
z — Z (сейчас не используется)
Данные пакета:
UL — статус получения списка контактов (GET_CONTACTS_OK — ОК, GET_CONTACTS_ERROR — ошибка базы данных на сервере, GET_CONTACTS_INTERR — внутренняя ошибка)
UL — количество групп в списке.
LPS — описание маски списка групп (каждый символ указывает на определённый тип данных)
LPS — определение маски списка контактов (каждый символ указывает на определённый тип данных)
string — список групп (количество групп и маска описания указаны во втором и третьем параметре)
string — список контактов.
Порядок нумерации ID групп начинается с нуля.
Порядок нумерации ID контактов начинается с 20.
Описание групп сейчас состоит из двух параметров (us):
UL — флаги группы.
LPS — имя группы в кодировке UTF-16LE.
При наличии других параметров, данные должны быть прочитаны и проигнорированы.
Описание контактов сейчас состоит из 12 параметров (uussuussssus):
UL — флаги контакта.
UL — ID группы.
LPS — адрес контакта.
LPS — имя (ник) контакта в кодировке UTF-16LE.
UL — серверные флаги (CONTACT_INTFLAG_NOT_AUTHORIZED — контакт не авторизован)
UL — статус.
LPS — номер телефона в международном формате.
LPS — название статуса.
LPS — заголовок икс-статуса в кодировке UTF-16LE.
LPS — текст икс-статуса в кодировке UTF-16LE.
UL — неизвестный мне параметр. Равен 0x03FF. (Предположительно, служит для скрытия/отображения названия/версии клиента. Второе значение, которое я встречал — это 0xFFFFFFFF.)
LPS — описание клиента в таком формате: client=«название» version=«версия» build=«сборка»
При обновлении протокола могут добавляться новые параметры, но порядок старых не будет меняться (во всяком случае, так заявлено на mail.ru)
 

Результат добавления контакта (группы):


MSG равен MRIM_CS_ADD_CONTACT_ACK.
UL — результат операции.
UL — присвоенный новому контакту номер (ID)
Возможные результаты:
CONTACT_OPER_SUCCESS — добавление произведено успешно
CONTACT_OPER_ERROR — переданные данные были некорректны
CONTACT_OPER_INTERR — при обработке запроса произошла внутренняя ошибка
CONTACT_OPER_NO_SUCH_USER — добавляемого пользователя не существует в системе
CONTACT_OPER_INVALID_INFO — некорректное имя пользователя
CONTACT_OPER_USER_EXISTS — пользователь уже есть в контакт-листе
CONTACT_OPER_GROUP_LIMIT — превышено максимально допустимое количество групп (20)
 

Результат изменения контакта:


MSG равен MRIM_CS_MODIFY_CONTACT_ACK.
UL — результат операции (может принимать те же значения, что и при получении результата добавления контакта.

Отчёт о доставке SMS сообщения:
MSG равен MRIM_CS_SMS_ACK.
UL — статус доставки.
Статусы:
SMS_ACK_DELIVERY_STATUS_INVALID_PARAMS — неверные параметры запроса на отправку.
SMS_ACK_SERVICE_UNAVAILABLE — сервис недоступен.
SMS_ACK_DELIVERY_STATUS_SUCCESS — сообщение отправлено.
 

Список найденных пользователей:


MSG равен MRIM_CS_ANKETA_INFO.
UL — результат операции.
UL — количество полей в анкете каждого пользователя (N).
UL — текущее ограничение на количество результатов поиска (может быть больше, чем количество строк в данном ответе) (при следующем∓ запросе на поиск с такими же параметрами будет показана следующая страница)
UL — текущее серверное время (timestamp).
LPSxN — N LPS с названиями полей.
Далее идут LPS со значениями полей анкеты для каждого найденного по запросу пользователя в том же порядке, что в списке полей, по N штук на каждого.
Возможные результаты:
MRIM_ANKETA_INFO_STATUS_OK — поиск успешно завершен
MRIM_ANKETA_INFO_STATUS_NOUSER — не найдено ни одной подходящей записи
MRIM_ANKETA_INFO_STATUS_RATELIMERR — слишком много запросов, поиск временно запрещен
 

Формирование ссылок на проекты Мой Мир, Фото, Видео, Блоги:


Для проекта «Мой Мир»: r.mail.ru/cln3587/my.mail.ru/домен/логин/
Для проекта «Фото»: r.mail.ru/cln3565/foto.mail.ru/домен/логин/
Для проекта «Видео»: r.mail.ru/cln3567/video.mail.ru/домен/логин/
Для проекта «Блоги»: r.mail.ru/cln3566/blogs.mail.ru/домен/логин/
 

Загрузка фотографий (аватар):


Малое фото: obraz.foto.mail.ru/домен/логин/_mrimavatarsmall
Большое фото: obraz.foto.mail.ru/домен/логин/_mrimavatar
В качестве домена указывается часть до первого вхождения точки. То есть:
mail.ru => mail
bk.ru => bk
list.ru => list
inbox.ru => inbox
corp.mail.ru => corp

Автор статьи Eugen.
Любое (полное или частичное) копирование материалов не приветствуется.