Меня уже несколько раз спрашивали, и уже надоело объяснять каждый раз заново. Поэтому ответ будет лежать тут, пока не понадобится мне в очередной раз.
Дано: люди, пишущие гигантской длины сообщения в IRC с кириллицей.
Проблема: люди видят крабозябры вместо обрезанного сообщения.
Как написано в
RFC 1459 на 8й странице,
а также в
RFC 2812 и
RFC 2813на 6й странице:
IRC messages are always lines of characters terminated with a CR-LF
(Carriage Return - Line Feed) pair, and these messages SHALL NOT
exceed 512 characters in length, counting all characters including
the trailing CR-LF. Thus, there are 510 characters maximum allowed
for the command and its parameters. There is no provision for
continuation of message lines.
Это ограничение довольно быстро достигается в случае длинных сообщений, кроме того перед непосредственно сообщением идёт также служебная информация протокола, которая тоже занимает место в этих 510 байтах. Например, в случае отправки сообщения в канал это выглядит как:
PRIVMSG #имяканала :имя сообщения\r\n
по двоеточию сервер догадывается, с какого места идёт собственно сообщение. Все лишние байты сервер попросту обрежет. Более того, при передаче другому клиенту сообщение ещё более сократится, чтобы вместить служебную информацию (кто сказал) и все равно уместиться в 510 байт.
логин!идент@маска PRIVMSG #имяканала :имя сообщения\r\n
Бороться с нехваткой байт под длинное сообщение можно по-разному. Большинство клиентов либо обрезает сообщение перед отправкой до 512 байт, либо отправляет как есть и тогда его обрезает уже сервер. Некоторые (например, XChat и некоторые скрипты к mIRC) разбивают сообщение на несколько и отправляют их подряд.
Ситуация усугубляется тем, что в UTF-8 кодировке символы кириллицы представляются двумя байтами. Если разрезать сообщение посреди символа, то такая последовательность байт уже не будет правильной unicode-последовательностью и у многих клиентов возникают проблемы с корректным отображением такой строки. И если WeNet и Rusnet используют однобайтовые кодировки, то на Freenode используется именно UTF-8 и пользователи нередко начинают выяснять отношения.
Для иллюстрации вышесказанного я нашел свой старый эксперимент по написанию IRC-бота, перенастроил его на FreeNode и дописал следующий код на команду "sayit":
if(order == "sayit")
{
// в этой строке 540 байт (UTF-8)
const char bigline[] = "КрабозябраПридиКрабозябраПридиКрабозябраПриди"
"КрабозябраПридиКрабозябраПридиКрабозябраПридиКрабозябраПридиКрабозябраПриди"
"КрабозябраПридиКрабозябраПридиКрабозябраПридиКрабозябраПридиКрабозябраПриди"
"КрабозябраПридиКрабозябраПридиКрабозябраПридиКрабозябраПридиКрабозябраПриди";
send_private_message(bigline, channel);
}
540 байт это явно больше 510. Моя реализация send_private_message не обрезает сообщения и посылает его как есть. Таким образом, в данном случае обрезание выполняется сервером, который рассылает это сообщение клиентам.
Для демонстрации я взял IRC-клиенты, находящиеся у меня под рукой:
KVIrc (версии 3.4.3 и 4 из svn), XChat (версия 2.8.6), Konversation (версия 1.2). Интересно было бы проверить ещё на mIRC, но у меня его нет.
Заведя бота и клиентов на уединённый канал, я несколько раз дал боту комманду "sayit", затем попытался отправить очень длинные строки из каждого клиента и проанализировал результаты.
KVIrc
Этот используемый мной клиент - лучший выбор когда нужно читать. В нём корректно отобразились все строки, посланные всеми клиентами (с учётом укорачивания, конечно). К сожалению, отправляемые строки сам клиент режет по 512 байт, ничуть не заботясь о границах символов. Надеюсь, это кто-нибудь исправит, или хотя бы напишет скрипт.
XChat
Этот клиент успешно делить длинные сообщения на несколько, что делает выбором тех, кто пишет. Сообщения от бота он тем не менее пережил нормально, видимо обрезалось удачным для алгоритма образом. А вот длинные сообщения от KVIrc и konversation он показал крабозябрами.
konversation
Этот клиент корректно показал сообщения от kvirc, но показал крабозябры от бота. Сам он умеет делить сообщения на несколько, но это совершенно не спасает от проблемы обрезания сообщения сервером после добавления имени и маски.
Вывод
Дело с клиентами IRC обстоит как всегда печально. Повтор одного и того же длинного сообщения несколько раз заставляет клиенты то показывает его правильно, то неправильно. Это видимо зависит от того, как трактует их алгоритм преобразования байт в символы. Если вы хотите избежать выяснения у кого клиент хуже, и что вы пишете-таки в UTF-8 - пишите сообщения покороче.