ICQMessage *ICQClient::parseMessage(unsigned short type, unsigned long uin, string &p, Buffer &packet, unsigned short cookie1, unsigned short cookie2, unsigned long timestamp1, unsigned long timestamp2) { log(L_DEBUG, "Parse message [type=%u]", type); ICQUser *u = getUser(uin); switch (type){ case ICQ_MSGxMSG:{ if (uin < 1000){ log(L_WARN, "Strange UIN %lu in message", uin); return NULL; } if (*(p.c_str()) == 0) return NULL; ICQMsg *msg = new ICQMsg; msg->Uin.push_back(uin); parseMessageText(p.c_str(), msg->Message, u); unsigned long forecolor, backcolor; packet >> forecolor >> backcolor; if (forecolor != backcolor){ msg->ForeColor = forecolor >> 8; msg->BackColor = backcolor >> 8; } return msg; } case ICQ_MSGxURL:{ if (uin < 1000){ log(L_WARN, "Strange UIN %lu in URL message", uin); return NULL; } vector<string> l; if (!parseFE(p.c_str(), l, 2)){ log(L_WARN, "Parse error URL message"); return NULL; } ICQUrl *msg = new ICQUrl; msg->Uin.push_back(uin); parseMessageText(l[0].c_str(), msg->Message, u); msg->URL = l[1]; return msg; } case ICQ_MSGxAUTHxREQUEST:{ if (uin < 1000){ log(L_WARN, "Strange UIN %lu in auth request message", uin); return NULL; } vector<string> l; if (!parseFE(p.c_str(), l, 6)){ log(L_WARN, "Parse error auth request message"); return NULL; } ICQAuthRequest *msg = new ICQAuthRequest; msg->Uin.push_back(uin); parseMessageText(l[4].c_str(), msg->Message, u); return msg; } case ICQ_MSGxAUTHxGRANTED:{ if (uin < 1000){ log(L_WARN, "Strange UIN %lu in auth granted message", uin); return NULL; } ICQAuthGranted *msg = new ICQAuthGranted; msg->Uin.push_back(uin); return msg; } case ICQ_MSGxAUTHxREFUSED:{ if (uin < 1000){ log(L_WARN, "Strange UIN %lu in auth refused message", uin); return NULL; } ICQAuthRefused *msg = new ICQAuthRefused; msg->Uin.push_back(uin); parseMessageText(p.c_str(), msg->Message, u); return msg; } case ICQ_MSGxADDEDxTOxLIST:{ if (uin < 1000){ log(L_WARN, "Strange UIN %lu in added to list message", uin); return NULL; } ICQAddedToList *msg = new ICQAddedToList; msg->Uin.push_back(uin); return msg; } case ICQ_MSGxCONTACTxLIST:{ if (uin < 1000){ log(L_WARN, "Strange UIN %lu in contact message", uin); return NULL; } vector<string> l; if (!parseFE(p.c_str(), l, 2)){ log(L_WARN, "Parse error contacts message"); return NULL; } unsigned nContacts = atol(l[0].c_str()); if (nContacts == 0){ log(L_WARN, "No contacts found"); return NULL; } vector<string> c; if (!parseFE(l[1].c_str(), c, nContacts*2+1)){ log(L_WARN, "Parse error contacts message"); return NULL; } ICQContacts *msg = new ICQContacts; msg->Uin.push_back(uin); for (unsigned i = 0; i < nContacts; i++){ Contact *contact = new Contact; contact->Uin = atol(c[i*2].c_str()); fromServer(c[i*2+1], u); contact->Alias = c[i*2+1]; msg->Contacts.push_back(contact); } return msg; } case ICQ_MSGxCHAT:{ unsigned short port; unsigned short junk; string name; packet >> name >> port >> junk >> junk >> junk; fromServer(p, u); ICQChat *msg = new ICQChat(); msg->Uin.push_back(uin); msg->Reason = p; msg->id1 = port; msg->timestamp1 = timestamp1; return msg; } case ICQ_MSGxFILE:{ unsigned short port; unsigned short junk; unsigned long fileSize; string fileName; packet >> port >> junk >> fileName >> fileSize >> junk >> junk; fromServer(p, u); fromServer(fileName, u); const char *shortName = strrchr(fileName.c_str(), '\\'); if (shortName){ shortName++; }else{ shortName = fileName.c_str(); } ICQFile *msg = new ICQFile(); msg->Uin.push_back(uin); msg->Name = shortName; msg->Description = p; msg->Size = htonl(fileSize); msg->id1 = port; msg->timestamp1 = timestamp1; return msg; } case ICQ_MSGxSECURExOPEN:{ ICQSecureOn *msg = new ICQSecureOn; msg->Uin.push_back(uin); return msg; } case ICQ_MSGxSECURExCLOSE:{ ICQSecureOff *msg = new ICQSecureOff; msg->Uin.push_back(uin); return msg; } case ICQ_READxAWAYxMSG: case ICQ_READxOCCUPIEDxMSG: case ICQ_READxNAxMSG: case ICQ_READxDNDxMSG: case ICQ_READxFFCxMSG:{ ICQAutoResponse *msg = new ICQAutoResponse; msg->setType(type); return msg; } case ICQ_MSGxEXT:{ string header; packet >> header; Buffer h(header.size()); h.pack(header.c_str(), header.size()); h.incReadPos(16); unsigned short msg_type; h >> msg_type; string msgType; h.unpackStr32(msgType); string info; packet.unpackStr32(info); Buffer b(info.size()); b.pack(info.c_str(), info.size()); log(L_DEBUG, "Extended message %s [%04X] %u", msgType.c_str(), msg_type, info.size()); if (strstr(msgType.c_str(), "File")){ string fileDescr; b.unpackStr32(fileDescr); unsigned short id1, id2; b >> id1 >> id2; string fileName; b >> fileName; unsigned long fileSize; b >> fileSize; fileSize = htonl(fileSize); fromServer(fileDescr, u); fromServer(fileName, u); ICQFile *msg = new ICQFile(); msg->isExt = true; msg->Uin.push_back(uin); msg->Name = fileName; msg->Description = fileDescr; msg->Size = fileSize; msg->id1 = id1; msg->id2 = id2; msg->cookie1 = cookie1; msg->cookie2 = cookie2; msg->timestamp1 = timestamp1; msg->timestamp2 = timestamp2; return msg; } if (strstr(msgType.c_str(), "Web Page Address (URL)")){ string info; b.unpackStr32(info); vector<string> l; if (!parseFE(info.c_str(), l, 2)){ log(L_DEBUG, "Parse error extended URL message"); return NULL; } ICQUrl *msg = new ICQUrl(); msg->Uin.push_back(uin); parseMessageText(l[0].c_str(), msg->Message, u); msg->URL = l[1]; return msg; } if (!strcmp(msgType.c_str(), "Request For Contacts")){ string info; b.unpackStr32(info); ICQContactRequest *msg = new ICQContactRequest(); msg->Uin.push_back(uin); parseMessageText(info.c_str(), msg->Message, u); return msg; } if (!strcmp(msgType.c_str(), "Send / Start ICQ Chat")){ string reason; b.unpackStr32(reason); ICQChat *msg = new ICQChat; parseMessageText(reason.c_str(), msg->Reason, u); char flag; b >> flag; if (flag){ b.incReadPos(2); b >> msg->id1 >> msg->id2; } msg->Uin.push_back(uin); msg->cookie1 = cookie1; msg->cookie2 = cookie2; msg->timestamp1 = timestamp1; msg->timestamp2 = timestamp2; return msg; }
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); } }
void ICQClient::snac_message(unsigned short type, unsigned short) { switch (type){ case ICQ_SNACxMSG_RIGHTSxGRANTED: log(L_DEBUG, "Message rights granted"); break; case ICQ_SNACxMSG_ACK: log(L_DEBUG, "Ack message"); break; case ICQ_SNACxMSG_AUTOREPLY:{ unsigned long timestamp1, timestamp2; readBuffer >> timestamp1 >> timestamp2; readBuffer.incReadPos(2); unsigned long uin = readBuffer.unpackUin(); readBuffer.incReadPos(6); unsigned long t1, t2; readBuffer >> t1 >> t2; unsigned short seq; readBuffer.incReadPos(0x0F); readBuffer >> seq; if ((t1 == 0) && (t2 == 0)){ readBuffer.incReadPos(0x16); string answer; readBuffer >> answer; fromServer(answer); if (timestamp1 || timestamp2){ log(L_DEBUG, "Message declined %s", answer.c_str()); list<ICQEvent*>::iterator it; for (it = processQueue.begin(); it != processQueue.end(); ++it){ ICQEvent *e = *it; if (e->type() != EVENT_MESSAGE_SEND) continue; ICQMessage *msg = e->message(); if (msg == NULL) continue; if ((msg->Uin == uin) && (msg->timestamp1 == timestamp1) && (msg->timestamp2 == timestamp2)){ msg->DeclineReason = answer; cancelMessage(msg, false); break; } } if (it == processQueue.end()) log(L_WARN, "Decline file answer: message not found"); }else{ log(L_DEBUG, "[%X] Autoreply from %u %s", seq, uin, answer.c_str()); ICQUser *u = getUser(uin); if (u) u->AutoReply = answer; ICQEvent e(EVENT_STATUS_CHANGED, uin); process_event(&e); processResponseRequestQueue(seq); } } if ((t1 == 0xA0E93F37L) && (t2 == 0x4FE9D311L)){ ICQUser *u = getUser(uin); if (u == NULL){ log(L_WARN, "Request info no my user %lu", uin); return; } if (u->inIgnore()){ log(L_WARN, "Request info ignore user %lu", uin); return; } readBuffer.incReadPos(0x1D); unsigned long cookie; readBuffer >> cookie; readBuffer.incReadPos(4); readBuffer.unpack(t1); if (t1 == 3){ u->PhoneBookTime = (unsigned long)htonl(cookie); u->bPhoneChanged = false; log(L_DEBUG, "[%X] Phone book info %u", seq, uin); PhoneBook::iterator it; PhonePtrList myNumbers; for (it = u->Phones.begin(); it != u->Phones.end(); ++it){ PhoneInfo *phone = static_cast<PhoneInfo*>(*it); if (!phone->MyInfo()) continue; PhoneInfo *myPhone = new PhoneInfo; *myPhone = *phone; myNumbers.push_back(myPhone); } u->Phones.clear(); unsigned long nPhones; readBuffer.unpack(nPhones); for (unsigned i = 0; i < nPhones; i++){ PhoneInfo *phone = new PhoneInfo; u->Phones.push_back(phone); readBuffer.unpackStr32(phone->Name); readBuffer.unpackStr32(phone->AreaCode); readBuffer.unpackStr32(phone->Number); readBuffer.unpackStr32(phone->Extension); readBuffer.unpackStr32(phone->Country); unsigned long type; readBuffer.unpack(type); if (type) phone->Active = true; if (readBuffer.readPos() >= readBuffer.size()) break; } for (it = u->Phones.begin(); it != u->Phones.end(); it++){ PhoneInfo *phone = static_cast<PhoneInfo*>(*it); string prop; readBuffer.unpackStr32(prop); Buffer b; b.pack(prop.c_str(), prop.length()); b.unpack(phone->Type); b.unpackStr32(phone->Provider); if (readBuffer.readPos() >= readBuffer.size()) break; } for (;;){ for (it = u->Phones.begin(); it != u->Phones.end(); it++){ PhoneInfo *phone = static_cast<PhoneInfo*>(*it); bool bOK = (phone->getNumber().length() > 0); if (bOK && !*phone->Number.c_str()) bOK = false; if (bOK) for (const char *p = phone->Number.c_str(); *p; p++){ if ((*p >= '0') && (*p <= '9')) continue; if ((*p == ' ') || (*p == '-')) continue; bOK = false; break; } if (bOK) continue; u->Phones.remove(phone); break; } if (it == u->Phones.end()) break; } u->adjustPhones(); u->Phones.add(myNumbers); ICQEvent e(EVENT_INFO_CHANGED, uin); process_event(&e); processPhoneRequestQueue(seq); } } break; }
void ICQClient::fromServer(string &str, ICQUser *u) { fromServer(str, localCharset(u)); }