Pull to refresh
VK
Building the Internet

Не только Аська в ICQ-клиентах

Reading time4 min
Views17K
Начнем с главного: зачем мы написали этот пост?

Уже больше года у нас реализована возможность общения с друзьями из Facebook, не покидая ICQ. Так сложилось, что ни один неофициальный ICQ-клиент до сих пор не добавил к себе нашу серверную поддержку Facebook — при том, что возможность вроде бы удобная, полезная и легкая в реализации. Возможно, ситуация изменится после публикации короткого и понятного HOWTO по теме. Скромно можем сказать, что аналогичный функционал в других IM-сетях отсутствует (да, естественно, любой клиент может сам установить два соединения к двум разным серверам и обрабатывать два разных протокола, но мы единственные делаем практически всю работу за автора клиента).

контакт-лист

Итак – вначале, естественно, пользователь должен «привязать» свой аккаунт на Facebook к своему номеру в ICQ.

К сожалению, это самая сложная часть процедуры, т. к. требует запуска браузера (к счастью, пользователь проходит через неё один раз в жизни). Проще всего открыть ссылку https://www.icq.com/login/ru?dest=http://lifestream.icq.com/settings/clientsettings?service=facebook&permission=xmpp в обычном браузере, но можно сделать это и в компоненте браузера внутри приложения — в меньшем окне страница, открывающаяся по ссылке, будет выглядеть красивее.

Если Facebook уже «привязан», то для того чтобы получать Facebook-контакты клиент должен на этапе логина к серверу отправить SNAC-пакет [snac-family=0x0003, snac-type=0x0002] с TLV {t=0x0008, l=1, v='\1' } внутри.

public static final int ICQ_FACEBOOK_SUPPORT = 0x0302;
private final BytesBuffer cs_FaceBook_create ( ) {
 return SNAC_Packet.newSnacPacket ( this, ICQ_FACEBOOK_SUPPORT, Garbage.getBytesBuffer ( ).putWord ( 8 ).putWord ( 1 ).writeByte ( 1 ) ); 
}

Контакты Facebook-сервер присылает в отдельном SNAC-пакете [snac-family=0x0013, snac-type=0x0008].
Клиент должен обработать этот пакет от сервера, отпарсить, добавить Facebook-контакты в локальный контакт-лист.

private final void sc_Roster_Add_received ( final BytesBuffer packet ) {  
  // Debug._trace ( "------sc 1308-------" );  
  // packet.dump ( );  
  try  {
  while ( packet.available ( ) > 0 )
  {
   String name = null;
   String proto = null;
   final String jid = packet.readPascalUTF8 ( ); // -1363121303@chat.facebook.com
   final int group = packet.getWord ( ); // 0001
   final int id = packet.getWord ( ); // 0003
   final int buddy = packet.getWord ( ); // 0000
   int len = packet.getWord ( ); // 0023
   while ( len > 0 )
    {
     final int t = packet.getWord ( ); 
     final int l = packet.checkWord ( );
     if ( t == 0x0131 )
      name = packet.readPascalUTF8 ( ); // e.g "Alexander Peregudov"
     else 
      if ( t == 0x0084 )
       proto = packet.readPascalUTF8 ( ); // "facebook" magic string
     else
     {
      Debug._trace ( "unknown tlv type=" + t + " len=" + l );
      packet.skip ( l + 2 );
     }
     len -= 4 + l;
    } 
   if ( buddy == 0 && StringCache.EqualsTo ( ASCII_CS_FACEBOOK_PROTO, proto ) )
   {
    // Debug._trace ( "got FACEBOOK contact name='" + name + "' proto='" + proto + "' jid='" + jid + "' group=" + group + " id=" + id + " buddy=" + buddy);
    final ICQ_Group igroup;
    if ( (igroup = findGroup ( group )) != null )
     igroup.add ( new ICQ_Contact ( this, id, group, jid, name, false ) );
    else
     Debug._trace ( "WARNING! no group for " + name + ". - skipped" );
   }
  }
 }
 catch ( final Throwable x )
 {
  x.printStackTrace ( );
 }
}

Дальнейшая работа с Facebook-контактами аналогична работе с обычными ICQ-контактами. Отправка сообщений и другие действия совершаются с помощью стандартных пакетов и дополнительного программирования не требуется.

Несколько слов о том, как Facebook реализовал jabber. Самое важное — статус в jabber синхронизован со статусом на сайте, если
  • пользователь находится под Facebook-аккаунтом в ICQ, то он будет online, как для других клиентов, которые реализуют Facebook-протокол, так и в чате на сайте Facebook.
  • входящие сообщения пользователь получает сразу во всех клиентах. Например, если пользователь находится на сайте Facebook и у него включена ICQ с Facebook, а также Агент с Facebook, то он получит сообщение трижды. Данная особенность находится на стороне Facebook.
Разумеется, как и положено протоколу XMPP, все сообщения идут централизованно через сервер Facebook, при этом история сообщений хранится в клиенте. Отправка сообщений происходит мгновенно, без каких-либо задержек.
Что касается антиспама, то он реализован на стороне Facebook и насколько мы можем судить, единственный используемый фильтр – только друзья могут отправлять сообщения друг другу.

Поскольку Facebook не поддерживает большинство операций по управлению контакт-листом, даем небольшой disclaimer относительно того, какие существуют ограничения:
  • Facebook-контакты нельзя переименовывать, как-либо изменять или удалять
  • их нельзя переносить в другую группу
  • группу Facebook-контактов нельзя как-либо модифицировать (удалять, переименовывать, переносить контакты в группу и из группы)
  • нельзя отправлять сообщения для Facebook-контактов находящихся offline
Полезные советы напоследок:
  • Facebook-контакты могут находиться в одном из трех состояний (онлайн, оффлайн и эвей), можно использовать для них отдельные иконки, можно ромашки
  • как такового числового 32-битного UIN у этих контактов нет; хотя в OSCAR-протоколе нет мест, где идентификатор передается именно как 32-битное число, вашу программу всё же стоит перепроверить

Как всегда, готовы ответить на дополнительные вопросы в комментариях.
Tags:
Hubs:
+21
Comments121

Articles

Information

Website
vk.com
Registered
Founded
Employees
5,001–10,000 employees
Location
Россия
Representative
Миша Берггрен