void ICQClient::snac_buddy(unsigned short type, unsigned short) { switch (type){ case ICQ_SNACxBDY_RIGHTSxGRANTED: log(L_DEBUG, "Buddy rights granted"); break; case ICQ_SNACxBDY_USEROFFLINE:{ unsigned long uin = readBuffer.unpackUin(); ICQUser *user = getUser(uin); if (user && (user->uStatus != ICQ_STATUS_OFFLINE)){ log(L_DEBUG, "User %lu [%s] offline", uin, user->Alias.c_str()); user->setOffline(); ICQEvent e(EVENT_STATUS_CHANGED, uin); process_event(&e); } break; } case ICQ_SNACxBDY_USERONLINE:{ unsigned long uin = readBuffer.unpackUin(); if (uin == Uin()) break; ICQUser *user = getUser(uin); if (user){ time_t now; time(&now); bool changed = false; unsigned long cookie1, cookie2, cookie3; cookie1 = cookie2 = cookie3 = 0; unsigned short level, len; readBuffer >> level >> len; TlvList tlv(readBuffer); // Status TLV Tlv *tlvStatus = tlv(0x0006); if (tlvStatus){ unsigned long status = *tlvStatus; log(L_DEBUG, "User %lu [%s] online [%08lX]", uin, user->Alias.c_str(), status); if (status != user->uStatus){ user->prevStatus = user->uStatus; user->uStatus = status; if (status & 0xFF){ addResponseRequest(uin); }else{ user->AutoReply = ""; } user->StatusTime = (unsigned long)now; changed = true; } } // Online time TLV Tlv *tlvOnlineTime = tlv(0x0003); if (tlvOnlineTime){ user->OnlineTime = (unsigned long)(*tlvOnlineTime); changed = true; } Tlv *tlvNATime = tlv(0x0004); if (tlvNATime){ user->StatusTime = (unsigned long)now - (unsigned short)(*tlvNATime) * 60L; changed = true; } // IP TLV Tlv *tlvIP = tlv(0x000A); if (tlvIP){ unsigned long ip = htonl((unsigned long)(*tlvIP)); if (user->IP() != ip) user->HostName = ""; user->IP = ip; changed = true; } // Direct connection info Tlv *tlvDirect = tlv(0x000C); if (tlvDirect){ user->ClientType = 0; Buffer info(*tlvDirect); unsigned long realIP; unsigned short port; char mode, version, junk; info >> realIP; info.incReadPos(2); info >> port; realIP = htonl(realIP); if (user->RealIP != realIP) user->RealHostName =""; user->RealIP = realIP; user->Port = port; info >> mode >> junk >> version >> user->DCcookie; info.incReadPos(8); info >> cookie1 >> cookie2 >> cookie3; if (cookie3 != user->PhoneBookTime()){ user->bPhoneChanged = true; user->PhoneBookTime = cookie3; } user->PhoneStatusTime = cookie2; user->TimeStamp = cookie1; if (mode == MODE_DENIED) mode = MODE_INDIRECT; if ((mode != MODE_DIRECT) && (mode != MODE_INDIRECT)) mode = MODE_INDIRECT; user->Mode = (unsigned short)mode; user->Version = (unsigned short)version; changed = true; if (user->DCcookie == 0) user->ClientType = 4; if ((user->DCcookie == cookie1) && (cookie1 == cookie2)) user->ClientType = 5; if (cookie1 == 0x279c6996) user->ClientType = 3; } Tlv *tlvCapability = tlv(0x000D); if (tlvCapability){ user->GetRTF = false; Buffer info(*tlvCapability); for (; info.readPos() < info.size(); ){ capability cap; info.unpack((char*)cap, sizeof(capability)); if (!memcmp(cap, capabilities[1], sizeof(capability))){ user->GetRTF = true; if (!user->CanPlugin){ if (user->bPhoneChanged) addPhoneRequest(uin); user->CanPlugin = true; } } if (!memcmp(cap, capabilities[3], sizeof(capability))) user->CanResponse = true; if (!memcmp(cap, capabilities[5], sizeof(capability))) user->ClientType = 2; if (!memcmp(cap, capabilities[4], sizeof(capability))) user->ClientType = 1; if (!memcmp(cap, capabilities[4], sizeof(capability)-1) && (cap[sizeof(capability)-1] > (1 << 6)) && (cap[sizeof(capability)-1] != 0x92)) user->ClientType = (char)(cap[sizeof(capability)-1]); } } Tlv *tlvPlugin = tlv(0x0011); if (tlvPlugin){ Buffer info(*tlvPlugin); char reqType; info >> reqType; info.incReadPos(10); capability cap; info.unpack((char*)cap, sizeof(capability)); if (user->CanPlugin && !memcmp(cap, PHONEBOOK_SIGN, sizeof(capability))){ if (reqType == 3){ info.incReadPos(3); info >> user->PhoneState; if (user->bPhoneChanged) addPhoneRequest(uin); }else if (reqType == 2) if (user->bPhoneChanged) addPhoneRequest(uin); } addInfoRequest(uin); changed = true; } if (changed){ ICQEvent e(EVENT_STATUS_CHANGED, uin); process_event(&e); user->prevStatus = user->uStatus; } } break; }
void ICQClient::snac_lists(unsigned short type, unsigned short seq) { bool bFull = false; switch (type){ case ICQ_SNACxLISTS_RIGHTS: log(L_DEBUG, "List rights"); break; case ICQ_SNACxLISTS_ROSTER:{ char c; unsigned short list_len; log(L_DEBUG,"Rosters"); if (m_bRosters){ log(L_DEBUG, "Rosters part 2"); break; } readBuffer >> c; if (c){ log(L_WARN, "Bad first roster byte %02X", c); break; } vector<ICQGroup*>::iterator it_grp; list<ICQUser*>::iterator it_usr; for (it_grp = contacts.groups.begin(); it_grp != contacts.groups.end(); it_grp++) (*it_grp)->bChecked = false; for (it_usr = contacts.users.begin(); it_usr != contacts.users.end(); it_usr++){ if ((*it_usr)->Type != USER_TYPE_ICQ) continue; (*it_usr)->Id = 0; (*it_usr)->GrpId = 0; (*it_usr)->inIgnore = false; (*it_usr)->inVisible = false; (*it_usr)->inInvisible = false; } readBuffer >> list_len; for (unsigned i = 0; i < list_len; i++){ string str; unsigned short id, grp_id, type, len; readBuffer.unpackStr(str); readBuffer >> grp_id >> id >> type >> len; TlvList *inf = NULL; if (len){ Buffer b(len); b.pack(readBuffer.Data(readBuffer.readPos()), len); readBuffer.incReadPos(len); inf = new TlvList(b); } switch (type){ case 0x0000: /* User */{ unsigned long uin = atol(str.c_str()); if (uin == 0){ log(L_WARN, "Bad uin record %s\n", str.c_str()); break; } Tlv *tlv_name = NULL; if (inf) tlv_name = (*inf)(0x0131); string alias = tlv_name ? (char*)(*tlv_name) : ""; fromUTF(alias); bool needAuth = false; if (inf && (*inf)(0x0066)) needAuth = true; ICQUser *user = getUser(uin, true); user->Id = id; user->GrpId = grp_id; user->Alias = alias; user->WaitAuth = needAuth; break; } case ICQ_GROUPS:{ if (str.size() == 0) break; fromUTF(str); ICQGroup *grp = getGroup(grp_id, true); if (grp == NULL){ grp = new ICQGroup(); contacts.groups.push_back(grp); } grp->Id = grp_id; grp->Name = str; grp->bChecked = true; break; } case ICQ_VISIBLE_LIST:{ unsigned long uin = atol(str.c_str()); if (uin) getUser(atol(str.c_str()), true)->inVisible = true; break; } case ICQ_INVISIBLE_LIST:{ unsigned long uin = atol(str.c_str()); if (uin) getUser(atol(str.c_str()), true)->inInvisible = true; break; } case ICQ_IGNORE_LIST:{ unsigned long uin = atol(str.c_str()); if (uin) getUser(atol(str.c_str()), true)->inIgnore = true; break; } case ICQ_INVISIBLE_STATE: contacts.Invisible = id; break; case 0x0009: break; default: log(L_WARN,"Unknown roster type %04X", type); } if (inf) delete inf; } unsigned long time; readBuffer >> time; contacts.Time = time; for (;;){ bool ok = true; for (it_grp = contacts.groups.begin(); it_grp != contacts.groups.end(); it_grp++){ if (!(*it_grp)->bChecked){ contacts.groups.erase(it_grp); ok = false; break; } } if (ok) break; } for (it_usr = contacts.users.begin(); it_usr != contacts.users.end(); it_usr++){ unsigned short grpId = (*it_usr)->GrpId(); bool ok = false; for (it_grp = contacts.groups.begin(); it_grp != contacts.groups.end(); it_grp++){ if ((*it_grp)->Id() == grpId){ ok = true; break; } } if (!ok) (*it_usr)->GrpId = 0; } ICQEvent e(EVENT_GROUP_CHANGED); process_event(&e); m_state = Logged; bFull = true; } case ICQ_SNACxLISTS_ROSTERxOK: // FALLTHROUGH { m_bRosters = true; log(L_DEBUG, "Rosters OK"); snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_UNKNOWN); sendPacket(); sendCapability(); sendICMB(); sendLogonStatus(); sendClientReady(); sendMessageRequest(); sendPhoneInit(); sendPhoneStatus(); if (bFull || (Nick.size() == 0)){ addInfoRequest(Uin); searchByUin(Uin); } list<ICQUser*>::iterator it; for (it = contacts.users.begin(); it != contacts.users.end(); it++){ if ((*it)->inIgnore()) continue; if (!bFull && (*it)->Nick.size()) continue; addInfoRequest((*it)->Uin); } if (contacts.groups.size() == 0){ m_state = Logged; createGroup("General"); } break; } case ICQ_SNACxLISTS_ADDED:{ readBuffer.incReadPos(8); unsigned long uin = readBuffer.unpackUin(); ICQAddedToList *m = new ICQAddedToList; m->Uin.push_back(uin); messageReceived(m); break; } case ICQ_SNACxLISTS_AUTHxREQUEST:{ readBuffer.incReadPos(8); unsigned long uin = readBuffer.unpackUin(); ICQUser *u = getUser(uin); string message; string charset; unsigned short have_charset; readBuffer.unpackStr(message); readBuffer >> have_charset; if (have_charset){ readBuffer.incReadPos(2); readBuffer.unpackStr(charset); } if (charset.size()){ translate(localCharset(u), charset.c_str(), message); }else{ fromServer(message, u); } log(L_DEBUG, "Auth request %lu", uin); ICQAuthRequest *m = new ICQAuthRequest; m->Uin.push_back(uin); m->Message = message; messageReceived(m); break; } case ICQ_SNACxLISTS_AUTH:{ readBuffer.incReadPos(8); unsigned long uin = readBuffer.unpackUin(); char auth_ok; readBuffer >> auth_ok; string message; string charset; unsigned short have_charset; readBuffer.unpackStr(message); readBuffer >> have_charset; if (have_charset){ readBuffer.incReadPos(2); readBuffer.unpackStr(charset); } ICQUser *u = getUser(uin); if (charset.size()){ translate(localCharset(u), charset.c_str(), message); }else{ fromServer(message, u); } log(L_DEBUG, "Auth %u %lu", auth_ok, uin); if (auth_ok){ ICQUser *user = getUser(uin); if (user){ user->WaitAuth = false; ICQEvent e(EVENT_INFO_CHANGED, uin); process_event(&e); } ICQAuthGranted *m = new ICQAuthGranted(); m->Uin.push_back(uin); messageReceived(m); }else{ ICQAuthRefused *m = new ICQAuthRefused(); m->Uin.push_back(uin); m->Message = message; messageReceived(m); } break; } case ICQ_SNACxLISTS_DONE:{ ICQEvent *e = findListEvent(seq); if (e == NULL) break; readBuffer.incReadPos(8); unsigned short res; readBuffer >> res; e->processAnswer(this, readBuffer, res); delete e; break; } default: log(L_WARN, "Unknown lists family type %04X", type); } }