/*************************************************************************** icqlists.cpp - description ------------------- begin : Sun Mar 10 2002 copyright : (C) 2002 by Vladimir Shutoff email : vovan@shutoff.ru ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "icqclient.h" #include "icqmessage.h" #include "core.h" #ifndef WIN32 #include #else #include // htons #endif #include #include #include #include #include #include #include "log.h" using namespace std; using namespace SIM; const unsigned short ICQ_SNACxLISTS_ERROR = 0x0001; const unsigned short ICQ_SNACxLISTS_REQxRIGHTS = 0x0002; const unsigned short ICQ_SNACxLISTS_RIGHTS = 0x0003; const unsigned short ICQ_SNACxLISTS_REQxROSTER = 0x0005; const unsigned short ICQ_SNACxLISTS_ROSTER = 0x0006; const unsigned short ICQ_SNACxLISTS_ACTIVATE = 0x0007; const unsigned short ICQ_SNACxLISTS_CREATE = 0x0008; const unsigned short ICQ_SNACxLISTS_UPDATE = 0x0009; const unsigned short ICQ_SNACxLISTS_DELETE = 0x000A; const unsigned short ICQ_SNACxLISTS_DONE = 0x000E; const unsigned short ICQ_SNACxLISTS_ROSTERxOK = 0x000F; const unsigned short ICQ_SNACxLISTS_EDIT = 0x0011; const unsigned short ICQ_SNACxLISTS_SAVE = 0x0012; const unsigned short ICQ_SNACxLISTS_FUTURE_AUTH = 0x0014; const unsigned short ICQ_SNACxLISTS_FUTURE_GRANT = 0x0015; const unsigned short ICQ_SNACxLISTS_REQUEST_AUTH = 0x0018; const unsigned short ICQ_SNACxLISTS_AUTHxREQUEST = 0x0019; const unsigned short ICQ_SNACxLISTS_AUTHxSEND = 0x001A; const unsigned short ICQ_SNACxLISTS_AUTH = 0x001B; const unsigned short ICQ_SNACxLISTS_ADDED = 0x001C; const unsigned short ICQ_USER = 0x0000; const unsigned short ICQ_GROUPS = 0x0001; const unsigned short ICQ_VISIBLE_LIST = 0x0002; const unsigned short ICQ_INVISIBLE_LIST = 0x0003; const unsigned short ICQ_INVISIBLE_STATE = 0x0004; const unsigned short ICQ_PRESENCE_INFO = 0x0005; const unsigned short ICQ_SHORTCUT_BAR = 0x0009; const unsigned short ICQ_IGNORE_LIST = 0x000E; const unsigned short ICQ_LAST_UPDATE = 0x000F; const unsigned short ICQ_NON_IM = 0x0010; const unsigned short ICQ_UNKNOWN = 0x0011; const unsigned short ICQ_IMPORT_TIME = 0x0013; const unsigned short ICQ_BUDDY_CHECKSUM = 0x0014; const unsigned short ICQ_UNKNOWN2 = 0x0019; const unsigned short ICQ_UNKNOWN3 = 0x001A; const unsigned short ICQ_AWAITING_AUTH = 0x001B; const unsigned short TLV_WAIT_AUTH = 0x0066; const unsigned short TLV_UNKNOWN2 = 0x006d; const unsigned short TLV_UNKNOWN3 = 0x006e; const unsigned short TLV_SUBITEMS = 0x00C8; const unsigned short TLV_SHORTCUT_BAR = 0x00cd; const unsigned short TLV_TIME = 0x00D4; const unsigned short TLV_BUDDYHASH = 0x00D5; const unsigned short TLV_ALIAS = 0x0131; const unsigned short TLV_CELLULAR = 0x013A; const unsigned LIST_REQUEST_TIMEOUT = 50; class ListServerRequest { public: ListServerRequest(unsigned short seq) : m_seq(seq), m_time(time(NULL)) {} virtual ~ListServerRequest() {}; virtual void process(ICQClient *client, unsigned short res) { Q_UNUSED(res); client->snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_SAVE); client->sendPacket(true); } unsigned short seq() const { return m_seq; } time_t getTime() const { return m_time; } protected: unsigned short m_seq; time_t m_time; }; class GroupServerRequest : public ListServerRequest { public: GroupServerRequest(unsigned short seq, unsigned long id, unsigned short icq_id, const QString &name); virtual void process(ICQClient *client, unsigned short res); protected: unsigned long m_id; unsigned short m_icqId; QString m_name; }; class ContactServerRequest : public ListServerRequest { public: ContactServerRequest(unsigned short seq, const QString &screen, unsigned short icq_id, unsigned short grp_id, TlvList *tlv = NULL); ~ContactServerRequest(); virtual void process(ICQClient *client, unsigned short res); protected: QString m_screen; unsigned short m_icqId; unsigned short m_grpId; TlvList *m_tlv; }; class SetListRequest : public ListServerRequest { public: SetListRequest(unsigned short seq, const QString &screen, unsigned short icq_id, unsigned short type); virtual void process(ICQClient *client, unsigned short res); protected: QString m_screen; unsigned short m_icqId; unsigned short m_type; }; class SetBuddyRequest : public ListServerRequest { public: SetBuddyRequest(unsigned short seq, const ICQUserData *icqUserData); virtual void process(ICQClient *client, unsigned short res); protected: const ICQUserData *m_icqUserData; }; static char PLEASE_UPGRADE[] = "PleaseUpgrade"; void ICQClient::parseRosterItem(unsigned short type, const QString &str, unsigned short grp_id, unsigned short id, TlvList *inf, bool &bIgnoreTime) { int seq; switch (type){ case ICQ_USER: { if (str.length()){ if (str.startsWith(PLEASE_UPGRADE)){ log(L_DEBUG, "Upgrade warning"); return; } log(L_DEBUG, "User %s", str.latin1()); // check for own uin in contact list if (!m_bAIM && (str.toULong() == getUin())) { log(L_DEBUG, "Own UIN in contact list - removing!"); seq = sendRoster(ICQ_SNACxLISTS_DELETE, QString::null, grp_id, id); m_listRequest = new ContactServerRequest(seq, QString::number(id), 0, 0); break; } ListRequest *lr = findContactListRequest(str); if (lr){ log(L_DEBUG, "Request found"); lr->icq_id = id; lr->grp_id = grp_id; Contact *contact; ICQUserData *data = findContact(lr->screen, NULL, false, contact); if (data){ data->IcqID.asULong() = id; data->GrpId.asULong() = grp_id; } }else{ bool bChanged = false; QString alias; Tlv *tlv_name = inf ? (*inf)(TLV_ALIAS) : NULL; if (tlv_name) alias = QString::fromUtf8(*tlv_name); log(L_DEBUG, "User %s [%s] id %u - group %u", str.local8Bit().data(), alias.local8Bit().data(), id, grp_id); Contact *contact; Group *grp = NULL; ICQUserData *data = findGroup(grp_id, NULL, grp); data = findContact(str, &alias, true, contact, grp); if (inf && (*inf)(TLV_WAIT_AUTH)){ if (!data->WaitAuth.toBool()){ data->WaitAuth.asBool() = true; bChanged = true; } } else { /* if not TLV(WAIT_AUTH) we are authorized ... */ if (inf && !(*inf)(TLV_WAIT_AUTH)) { if (data->WaitAuth.toBool()){ data->WaitAuth.asBool() = false; bChanged = true; } } } data->IcqID.asULong() = id; data->GrpId.asULong() = grp_id; Tlv *tlv_phone = inf ? (*inf)(TLV_CELLULAR) : NULL; if (tlv_phone){ data->Cellular.str() = QString::fromUtf8(*tlv_phone); QString phone = trimPhone(data->Cellular.str()); QString phone_str = quoteChars(phone, ","); phone_str += ",Private Cellular,"; phone_str += QString::number(CELLULAR); bChanged |= contact->setPhones(phone_str, NULL); }else{ data->Cellular.clear(); } if (bChanged){ EventContact e(contact, EventContact::eChanged); e.process(); } if ((data->InfoFetchTime.toULong() == 0) && data->Uin.toULong()) addFullInfoRequest(data->Uin.toULong()); } }else{ bIgnoreTime = true; } break; } case ICQ_GROUPS:{ if (str.isEmpty()) break; log(L_DEBUG, "group %s %u", str.local8Bit().data(), grp_id); ListRequest *lr = findGroupListRequest(grp_id); if (lr) break; Group *grp; ICQUserData *data = findGroup(grp_id, &str, grp); if (data->IcqID.toULong()){ lr = findGroupListRequest((unsigned short)(data->IcqID.toULong())); if (lr) removeListRequest(lr); } data->IcqID.asULong() = grp_id; data->bChecked.asBool() = true; if (grp->getName() != str){ grp->setName(str); EventGroup e(grp, EventGroup::eChanged); e.process(); } break; } case ICQ_VISIBLE_LIST:{ if (str.length()){ log(L_DEBUG, "Visible %s", str.latin1()); ListRequest *lr = findContactListRequest(str); if (lr) lr->visible_id = id; if ((lr == NULL) || (lr->type != LIST_USER_DELETED)){ Contact *contact; ICQUserData *data = findContact(str, NULL, true, contact); data->ContactVisibleId.asULong() = id; if ((lr == NULL) && (data->VisibleId.toULong() != id)){ data->VisibleId.asULong() = id; EventContact e(contact, EventContact::eChanged); e.process(); } if ((data->InfoFetchTime.toULong() == 0) && data->Uin.toULong()) addFullInfoRequest(data->Uin.toULong()); } } break; } case ICQ_INVISIBLE_LIST:{ if (str.length()){ log(L_DEBUG, "Invisible %s", str.latin1()); ListRequest *lr = findContactListRequest(str); if (lr) lr->invisible_id = id; if ((lr == NULL) || (lr->type != LIST_USER_DELETED)){ Contact *contact; ICQUserData *data = findContact(str, NULL, true, contact); data->ContactInvisibleId.asULong() = id; if ((lr == NULL) && (data->InvisibleId.toULong() != id)){ data->InvisibleId.asULong() = id; EventContact e(contact, EventContact::eChanged); e.process(); } if ((data->InfoFetchTime.toULong() == 0) && data->Uin.toULong()) addFullInfoRequest(data->Uin.toULong()); } } break; } case ICQ_IGNORE_LIST:{ if (str.length()){ log(L_DEBUG, "Ignore %s", str.latin1()); ListRequest *lr = findContactListRequest(str); if (lr) lr->ignore_id = id; Contact *contact; ICQUserData *data = findContact(str, NULL, true, contact); if (data->IgnoreId.toULong() != id){ data->IgnoreId.asULong() = id; if (lr == NULL){ contact->setIgnore(true); EventContact e(contact, EventContact::eChanged); e.process(); } } } break; } case ICQ_INVISIBLE_STATE: setContactsInvisible(id); break; case ICQ_PRESENCE_INFO: break; case ICQ_BUDDY_CHECKSUM: { if (str.length()){ Tlv *tlv_buddyHash = inf ? (*inf)(TLV_BUDDYHASH) : NULL; if(tlv_buddyHash) { const QByteArray &ba = data.owner.buddyHash.toBinary(); unsigned char flag, size; QByteArray buddyHash; flag = tlv_buddyHash->Data()[0]; size = tlv_buddyHash->Data()[1]; buddyHash.resize(size); memcpy(buddyHash.data(), &tlv_buddyHash->Data()[2], size); if(ba != buddyHash) { data.owner.buddyHash.asBinary() = buddyHash; data.owner.buddyID.asULong() = flag; } data.owner.buddyRosterID.asULong() = id; } } break; } case ICQ_LAST_UPDATE: case ICQ_UNKNOWN: break; case ICQ_UNKNOWN3: if(inf) { Tlv *tlv_uk3 = NULL; tlv_uk3 = (*inf)(TLV_UNKNOWN3); } break; case ICQ_SHORTCUT_BAR: if(inf) { Tlv *tlv_sc = NULL; tlv_sc = (*inf)(TLV_SHORTCUT_BAR); } break; case ICQ_UNKNOWN2: if(inf) { Tlv *tlv_uk2 = NULL; tlv_uk2 = (*inf)(TLV_UNKNOWN2); } break; case ICQ_NON_IM: { Tlv *tlv_name = NULL; Tlv *tlv_phone = NULL; QString alias; QString phone; if (inf) { tlv_name = (*inf)(TLV_ALIAS); if (tlv_name) alias = (char*)(*tlv_name); tlv_phone = (*inf)(TLV_CELLULAR); if (tlv_phone){ phone = (char*)(*tlv_phone); } log (L_DEBUG,"External Contact: %s Phone: %s", alias.latin1(), phone.latin1()); } break; } case ICQ_IMPORT_TIME:{ Tlv *tlv_time = NULL; QDateTime qt_time; if (inf) { tlv_time = (*inf)(TLV_TIME); qt_time.setTime_t((uint32_t)(*tlv_time)); log (L_DEBUG, "Import Time %s",qt_time.toString().ascii()); } break; } case ICQ_AWAITING_AUTH: { Contact *contact; if (str.length()){ log(L_DEBUG, "%s is awaiting auth", str.latin1()); ICQUserData *data; if ((data = findContact(str, NULL, false, contact)) != NULL) { addFullInfoRequest(str.toULong()); data->WantAuth.asBool() = true; } else { log(L_DEBUG, "not in contact list, skipped"); } } break; } default: log(L_WARN,"Unknown roster type %04X", type); } } void ICQClient::snac_lists(unsigned short type, unsigned short seq) { switch (type){ case ICQ_SNACxLISTS_ERROR: break; case ICQ_SNACxLISTS_RIGHTS: log(L_DEBUG, "List rights"); break; case ICQ_SNACxLISTS_EDIT: { log(L_DEBUG, "Server begins SSI transaction"); break; } case ICQ_SNACxLISTS_SAVE: { log(L_DEBUG, "Server ends SSI transaction"); break; } case ICQ_SNACxLISTS_CREATE: { log(L_DEBUG, "Server adds new item"); break; } case ICQ_SNACxLISTS_UPDATE: { QString name; unsigned short id, grp_id, type, len; bool tmp; socket()->readBuffer().unpackStr(name); socket()->readBuffer() >> grp_id >> id >> type >> len; TlvList *inf = NULL; if (len){ ICQBuffer b(len); b.pack(socket()->readBuffer().data(socket()->readBuffer().readPos()), len); socket()->readBuffer().incReadPos(len); inf = new TlvList(b); } parseRosterItem(type,name,grp_id,id,inf,tmp); delete inf; break; } case ICQ_SNACxLISTS_DELETE: { log(L_DEBUG, "Server deletes item"); break; } case ICQ_SNACxLISTS_ROSTER:{ char c; unsigned short list_len; log(L_DEBUG,"Rosters"); socket()->readBuffer() >> c; if (c){ log(L_WARN, "Unknown SSI-Version 0x%02X", c); break; } bool bIgnoreTime = false; if (!m_bRosters){ m_bRosters = true; m_bJoin = false; setContactsInvisible(0); Group *grp; ContactList::GroupIterator it_g; while ((grp = ++it_g) != NULL){ ICQUserData *data; ClientDataIterator it(grp->clientData, this); while ((data = (ICQUserData*)(++it)) != NULL){ if (data->IcqID.toULong() == 0){ data->bChecked.asBool() = true; continue; } data->bChecked.asBool() = false; } } Contact *contact; ContactList::ContactIterator it_c; while ((contact = ++it_c) != NULL){ ICQUserData *data; ClientDataIterator it(contact->clientData, this); while ((data = (ICQUserData*)(++it)) != NULL){ data->bChecked.asBool() = false; data->GrpId.asULong() = 0; data->IgnoreId.asULong() = 0; data->VisibleId.asULong() = 0; data->InvisibleId.asULong() = 0; } } } socket()->readBuffer() >> list_len; for (unsigned i = 0; i < list_len; i++){ QString name; unsigned short id, grp_id, type, len; socket()->readBuffer().unpackStr(name); socket()->readBuffer() >> grp_id >> id >> type >> len; TlvList *inf = NULL; if (len){ ICQBuffer b(len); b.pack(socket()->readBuffer().data(socket()->readBuffer().readPos()), len); socket()->readBuffer().incReadPos(len); inf = new TlvList(b); } parseRosterItem(type, name, grp_id, id, inf, bIgnoreTime); delete inf; } unsigned long time; socket()->readBuffer() >> time; if ((time == 0) && list_len && !bIgnoreTime) break; setContactsTime(time); Group *grp; ContactList::GroupIterator it_g; list forRemove; while ((grp = ++it_g) != NULL){ ICQUserData *data = (ICQUserData*)(grp->clientData.getData(this)); QString n; if (grp->id()) n = grp->getName(); log(L_DEBUG, "Check %ld %s %p %u", grp->id(), n.latin1(), data, data ? data->bChecked.toBool() : 0); if ((data == NULL) || data->bChecked.toBool()) continue; ListRequest *lr = findGroupListRequest((unsigned short)(data->IcqID.toULong())); if (lr) continue; forRemove.push_back(grp); } for (list::iterator it = forRemove.begin(); it != forRemove.end(); ++it){ delete *it; } Contact *contact; ContactList::ContactIterator it_c; while ((contact = ++it_c) != NULL){ ICQUserData *data; ClientDataIterator it_d(contact->clientData); bool bOther = (contact->clientData.size() == 0); bool bMy = false; unsigned long newGroup = 0; while ((data = (ICQUserData*)(++it_d)) != NULL){ if (it_d.client() != this){ bOther = true; continue; } unsigned grpId = data->GrpId.toULong(); ContactList::GroupIterator it_g; while ((grp = ++it_g) != NULL){ ICQUserData *data = (ICQUserData*)(grp->clientData.getData(this)); if (data && (data->IcqID.toULong() == grpId)) break; } if (grp) newGroup = grp->id(); bMy = true; } if (newGroup != contact->getGroup()){ if ((newGroup == 0) && bOther){ if (bMy) addContactRequest(contact); }else{ contact->setGroup(newGroup); EventContact e(contact, EventContact::eChanged); e.process(); } } } } getContacts()->save(); if (m_bJoin){ EventJoinAlert(this).process(); m_bJoin = false; } case ICQ_SNACxLISTS_ROSTERxOK: // FALLTHROUGH { log(L_DEBUG, "Rosters OK"); QTimer::singleShot(PING_TIMEOUT * 1000, this, SLOT(ping())); setPreviousPassword(QString::null); if (m_bAIM){ Group *grp; ContactList::GroupIterator it; while ((grp = ++it) != NULL){ if (grp->id()) break; } if (grp == NULL){ grp = getContacts()->group(0, true); grp->setName("General"); EventGroup e(grp, EventGroup::eChanged); e.process(); } data.owner.OnlineTime.asULong() = time(NULL); if (m_logonStatus == STATUS_ONLINE){ m_status = STATUS_ONLINE; sendCapability(); sendICMB(1, 11); sendICMB(2, 3); sendICMB(4, 3); fetchProfiles(); }else{ m_status = STATUS_AWAY; ar_request req; req.bDirect = false; arRequests.push_back(req); ARRequest ar; ar.contact = NULL; ar.param = &arRequests.back(); ar.receiver = this; ar.status = m_logonStatus; EventARRequest(&ar).process(); } snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_ACTIVATE); sendPacket(true); sendClientReady(); setState(Connected); m_bReady = true; processSendQueue(); break; } sendCapability(); sendICMB(1, 11); sendICMB(2, 3); sendICMB(4, 3); sendLogonStatus(); sendClientReady(); snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_ACTIVATE); sendPacket(true); sendMessageRequest(); setState(Connected); fetchProfiles(); break; } case ICQ_SNACxLISTS_ADDED:{ QString screen = socket()->readBuffer().unpackScreen(); messageReceived(new AuthMessage(MessageAdded), screen); break; } case ICQ_SNACxLISTS_AUTHxREQUEST:{ QString screen = socket()->readBuffer().unpackScreen(); QCString message; QCString charset; unsigned short have_charset; socket()->readBuffer().unpackStr(message); socket()->readBuffer() >> have_charset; if (have_charset){ socket()->readBuffer().incReadPos(2); socket()->readBuffer().unpackStr(charset); } log(L_DEBUG, "Auth request %s", screen.latin1()); Message *m = NULL; if (charset.isEmpty()){ AuthMessage *msg = new AuthMessage(MessageAuthRequest); msg->setText(QString::fromUtf8(message)); m = msg; }else{ ICQAuthMessage *msg = new ICQAuthMessage(MessageICQAuthRequest, MessageAuthRequest); msg->setServerText(message); msg->setCharset(charset); m = msg; } messageReceived(m, screen); Contact *contact; ICQUserData *data = findContact(screen, NULL, false, contact); if (data) data->WantAuth.asBool() = true; break; } case ICQ_SNACxLISTS_FUTURE_GRANT:{ /* we treat future grant as normal grant but it isn't the same... http://iserverd1.khstu.ru/oscar/snac_13_15.html */ QString screen = socket()->readBuffer().unpackScreen(); QCString message; Message *m = NULL; socket()->readBuffer().unpackStr(message); AuthMessage *msg = new AuthMessage(MessageAuthGranted); msg->setText(QString::fromUtf8(message)); // toUnicode ?? m = msg; messageReceived(m, screen); Contact *contact; ICQUserData *data = findContact(screen, NULL, false, contact); if (data){ data->WaitAuth.asBool() = false; EventContact e(contact, EventContact::eChanged); e.process(); addPluginInfoRequest(data->Uin.toULong(), PLUGIN_QUERYxSTATUS); addPluginInfoRequest(data->Uin.toULong(), PLUGIN_QUERYxINFO); } } case ICQ_SNACxLISTS_AUTH:{ QString screen = socket()->readBuffer().unpackScreen(); char auth_ok; socket()->readBuffer() >> auth_ok; QCString message; QCString charset; unsigned short have_charset; socket()->readBuffer().unpackStr(message); socket()->readBuffer() >> have_charset; if (have_charset){ socket()->readBuffer().incReadPos(2); socket()->readBuffer().unpackStr(charset); } log(L_DEBUG, "Auth %u %s", auth_ok, screen.latin1()); Message *m = NULL; if (charset.isEmpty()){ AuthMessage *msg = new AuthMessage(auth_ok ? MessageAuthGranted : MessageAuthRefused); msg->setText(QString::fromUtf8(message)); m = msg; }else{ ICQAuthMessage *msg = new ICQAuthMessage(auth_ok ? MessageICQAuthGranted : MessageICQAuthRefused, auth_ok ? MessageAuthGranted : MessageAuthRefused); msg->setServerText(message); msg->setCharset(charset); m = msg; } messageReceived(m, screen); if (auth_ok){ Contact *contact; ICQUserData *data = findContact(screen, NULL, false, contact); if (data){ data->WaitAuth.asBool() = false; EventContact e(contact, EventContact::eChanged); e.process(); addPluginInfoRequest(data->Uin.toULong(), PLUGIN_QUERYxSTATUS); addPluginInfoRequest(data->Uin.toULong(), PLUGIN_QUERYxINFO); } } break; } case ICQ_SNACxLISTS_DONE: if (m_listRequest && m_listRequest->seq() == seq){ unsigned short res; const char *msg; socket()->readBuffer() >> res; switch (res) { case 0x00: msg = "No errors (success)"; break; case 0x02: msg = "Item you want to modify not found in list"; break; case 0x03: msg = "Item you want to add already exists"; break; case 0x0a: msg = "Error adding item (invalid id, already in list, invalid data)"; break; case 0x0c: msg = "Can't add item. Limit for this type of items exceeded"; break; case 0x0d: msg = "Trying to add ICQ contact to an AIM list"; break; case 0x0e: msg = "Can't add this contact because it requires authorization"; break; default: msg = NULL; } if (msg) log(L_DEBUG, "%s", msg); else log(L_DEBUG, "Unknown list request answer %u", res); m_listRequest->process(this, res); delete m_listRequest; m_listRequest = NULL; processSendQueue(); } break; default: log(L_WARN, "Unknown lists family type %04X", type); } } void ICQClient::listsRequest() { log(L_DEBUG, "lists request"); snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_REQxRIGHTS); sendPacket(true); snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_REQxROSTER); unsigned long contactsTime = getContactsTime(); unsigned short contactsLength = getContactsLength(); socket()->writeBuffer() << contactsTime << contactsLength; sendPacket(true); } void ICQClient::sendInvisible(bool bInvisible) { unsigned short cmd = ICQ_SNACxLISTS_UPDATE; if (getContactsInvisible() == 0){ cmd = ICQ_SNACxLISTS_CREATE; setContactsInvisible((unsigned short)(get_random() & 0x7FFF)); } char data = bInvisible ? 4 : 3; TlvList tlvs; tlvs += new Tlv(0xCA, 1, &data); sendRoster(cmd, NULL, 0, getContactsInvisible(), ICQ_INVISIBLE_STATE, &tlvs); } ListRequest *ICQClient::findContactListRequest(const QString &screen) { for (list::iterator it = listRequests.begin(); it != listRequests.end(); ++it){ if ((((*it).type == LIST_USER_CHANGED) || ((*it).type == LIST_USER_DELETED)) && ((*it).screen == screen)) return &(*it); } return NULL; } ListRequest *ICQClient::findGroupListRequest(unsigned short id) { for (list::iterator it = listRequests.begin(); it != listRequests.end(); ++it){ switch ((*it).type){ case LIST_GROUP_DELETED: case LIST_GROUP_CHANGED: if ((*it).icq_id == id) return &(*it); break; } } return NULL; } void ICQClient::removeListRequest(ListRequest *lr) { for (list::iterator it = listRequests.begin(); it != listRequests.end(); ++it){ if (&(*it) == lr){ listRequests.erase(it); return; } } } void ICQClient::clearListServerRequest() { if (m_listRequest){ delete m_listRequest; m_listRequest = NULL; } } //----------------------------------------------------------------------------- GroupServerRequest::GroupServerRequest(unsigned short seq, unsigned long id, unsigned short icq_id, const QString &name) : ListServerRequest(seq), m_id(id), m_icqId(icq_id), m_name(name) { } void GroupServerRequest::process(ICQClient *client, unsigned short res) { ListServerRequest::process(client, res); ListRequest *lr = client->findGroupListRequest(m_icqId); if (lr && (lr->type == LIST_GROUP_DELETED)){ lr->icq_id = 0; return; } Group *group = getContacts()->group(m_id); if (group == NULL) return; ICQUserData *data = (ICQUserData*)(group->clientData.getData(client)); if (data == NULL) data = (ICQUserData*)(group->clientData.createData(client)); data->IcqID.asULong() = m_icqId; data->Alias.str() = m_name; } //----------------------------------------------------------------------------- ContactServerRequest::ContactServerRequest(unsigned short seq, const QString &screen, unsigned short icq_id, unsigned short grp_id, TlvList *tlv) : ListServerRequest(seq), m_screen(screen), m_icqId(icq_id), m_grpId(grp_id), m_tlv(tlv) { } ContactServerRequest::~ContactServerRequest() { delete m_tlv; } void ContactServerRequest::process(ICQClient *client, unsigned short res) { ListServerRequest::process(client, res); ListRequest *lr = client->findContactListRequest(m_screen); if (lr && (lr->type == LIST_USER_DELETED)){ lr->screen = QString::null; lr->icq_id = 0; lr->grp_id = 0; return; } Contact *contact; ICQUserData *data = client->findContact(m_screen, NULL, true, contact); if ((res == 0x0E) && !data->WaitAuth.toBool()){ data->WaitAuth.asBool() = true; EventContact e(contact, EventContact::eChanged); e.process(); return; } data->IcqID.asULong() = m_icqId; data->GrpId.asULong() = m_grpId; if ((data->GrpId.toULong() == 0) && data->WaitAuth.toBool()){ data->WaitAuth.asBool() = false; EventContact e(contact, EventContact::eChanged); e.process(); } if (m_tlv){ Tlv *tlv_alias = (*m_tlv)(TLV_ALIAS); if (tlv_alias){ // ok here since Alias is utf8 and TLV_ALIAS too data->Alias.str() = QString::fromUtf8(*tlv_alias); }else{ data->Alias.clear(); } Tlv *tlv_cell = (*m_tlv)(TLV_CELLULAR); if (tlv_cell){ data->Cellular.str() = QString::fromUtf8(*tlv_cell); }else{ data->Cellular.clear(); } } } //----------------------------------------------------------------------------- SetListRequest::SetListRequest(unsigned short seq, const QString &screen, unsigned short icq_id, unsigned short type) : ListServerRequest(seq), m_screen(screen), m_icqId(icq_id), m_type(type) { } void SetListRequest::process(ICQClient *client, unsigned short res) { ListServerRequest::process(client, res); ListRequest *lr = client->findContactListRequest(m_screen); if (lr && (lr->type == LIST_USER_DELETED)){ switch (m_type){ case ICQ_VISIBLE_LIST: lr->visible_id = 0; break; case ICQ_INVISIBLE_LIST: lr->invisible_id = 0; break; case ICQ_IGNORE_LIST: lr->ignore_id = 0; break; } return; } Contact *contact; ICQUserData *data = client->findContact(m_screen, NULL, true, contact); switch (m_type){ case ICQ_VISIBLE_LIST: data->ContactVisibleId.asULong() = m_icqId; break; case ICQ_INVISIBLE_LIST: data->ContactInvisibleId.asULong() = m_icqId; break; case ICQ_IGNORE_LIST: data->IgnoreId.asULong() = m_icqId; break; } } //----------------------------------------------------------------------------- SetBuddyRequest::SetBuddyRequest(unsigned short seq, const ICQUserData *icqUserData) : ListServerRequest(seq), m_icqUserData(icqUserData) { } void SetBuddyRequest::process(ICQClient *client, unsigned short res) { ListServerRequest::process(client, res); client->listRequests.erase(client->listRequests.begin()); // item does not exist if(res == 2) { ListRequest lr; lr.type = LIST_BUDDY_CHECKSUM; lr.icq_id = m_icqUserData->buddyRosterID.toULong(); lr.icqUserData = m_icqUserData; client->listRequests.push_back(lr); client->processSendQueue(); } if(res != 0) return; } //----------------------------------------------------------------------------- unsigned short ICQClient::getListId() { unsigned short id; for (id = (unsigned short)(get_random() & 0x7FFF) ;; id++){ id &= 0x7FFF; if (id == 0) continue; Group *group; ContactList::GroupIterator it_grp; while ((group = ++it_grp) != NULL){ ICQUserData *data = (ICQUserData*)(group->clientData.getData(this)); if (data == NULL) continue; if (data->IcqID.toULong() == id) break; } if (group) continue; Contact *contact; ContactList::ContactIterator it_cnt; while ((contact = ++it_cnt) != NULL){ ClientDataIterator it(contact->clientData, this); ICQUserData *data; while ((data = (ICQUserData*)(++it)) != NULL){ if ((data->IcqID.toULong() == id) || (data->IgnoreId.toULong() == id) || (data->VisibleId.toULong() == id) || (data->InvisibleId.toULong() == id)) break; } if (data) break; } if (contact) continue; break; } return id; } TlvList *ICQClient::createListTlv(ICQUserData *data, Contact *contact) { TlvList *tlv = new TlvList; QCString name = contact->getName().utf8(); *tlv += new Tlv(TLV_ALIAS, (unsigned short)(name.length()), name); if (data->WaitAuth.toBool()) *tlv += new Tlv(TLV_WAIT_AUTH, 0, NULL); QString cell = getUserCellular(contact); if (cell.length()) *tlv += new Tlv(TLV_CELLULAR, (unsigned short)(cell.length()), cell.latin1()); return tlv; } void ICQClient::uploadBuddy(const ICQUserData *data) { ListRequest lr; lr.type = LIST_BUDDY_CHECKSUM; lr.icq_id = data->buddyRosterID.toULong(); lr.icqUserData = data; listRequests.push_back(lr); processSendQueue(); } unsigned short ICQClient::sendRoster(unsigned short cmd, const QString &name, unsigned short grp_id, unsigned short usr_id, unsigned short subCmd, TlvList *tlv) { // start edit SSI snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_EDIT); sendPacket(true); snac(ICQ_SNACxFAM_LISTS, cmd, true); QCString sName = name.utf8(); socket()->writeBuffer().pack(htons(sName.length())); socket()->writeBuffer().pack(sName.data(), sName.length()); socket()->writeBuffer() << grp_id << usr_id << subCmd; if (tlv){ socket()->writeBuffer() << *tlv; }else{ socket()->writeBuffer() << (unsigned short)0; } sendPacket(true); return m_nMsgSequence; } void ICQClient::sendRosterGrp(const QString &name, unsigned short grpId, unsigned short usrId) { QCString sName = name.utf8(); snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_UPDATE, true); socket()->writeBuffer().pack(sName.data(), sName.length()); socket()->writeBuffer() << grpId << (unsigned long) ICQ_GROUPS; if (usrId){ socket()->writeBuffer() << (unsigned short) 6 << (unsigned short) 0xC8 << (unsigned short) 2 << (unsigned short) usrId; }else{ socket()->writeBuffer() << (unsigned short) 4 << (unsigned short) 0xC8 << (unsigned short) 0; } sendPacket(true); } static QString userStr(Contact *contact, const ICQUserData *data) { QString name = contact ? contact->getName() : "unknown"; return QString::number(data->Uin.toULong()) + '[' + name + ']'; } unsigned ICQClient::processListRequest() { if (m_listRequest || (getState() != Connected) || !m_bReady) return false; for (;;){ if (listRequests.size() == 0) return 0; unsigned delay = delayTime(SNAC(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_CREATE)); if (delay) return delay; ListRequest &lr = listRequests.front(); unsigned short seq = 0; unsigned short icq_id; Group *group = NULL; Contact *contact; ICQUserData *data; unsigned grp_id = 0; switch (lr.type){ case LIST_USER_CHANGED: data = findContact(lr.screen, NULL, false, contact); if (data == NULL) break; if (data->VisibleId.toULong() != data->ContactVisibleId.toULong()){ if ((data->VisibleId.toULong() == 0) || (data->ContactVisibleId.toULong() == 0)){ if (data->VisibleId.toULong()){ log(L_DEBUG, "%s add to visible list", userStr(contact, data).local8Bit().data()); seq = sendRoster(ICQ_SNACxLISTS_CREATE, screen(data), 0, data->VisibleId.toULong(), ICQ_VISIBLE_LIST); }else{ log(L_DEBUG, "%s remove from visible list", userStr(contact, data).local8Bit().data()); seq = sendRoster(ICQ_SNACxLISTS_DELETE, screen(data), 0, data->ContactVisibleId.toULong(), ICQ_VISIBLE_LIST); } m_listRequest = new SetListRequest(seq, screen(data), data->VisibleId.toULong(), ICQ_VISIBLE_LIST); break; } data->VisibleId.asULong() = data->ContactVisibleId.toULong(); } if (data->InvisibleId.toULong() != data->ContactInvisibleId.toULong()){ if ((data->InvisibleId.toULong() == 0) || (data->ContactInvisibleId.toULong() == 0)){ if (data->InvisibleId.toULong()){ log(L_DEBUG, "%s add to invisible list", userStr(contact, data).local8Bit().data()); seq = sendRoster(ICQ_SNACxLISTS_CREATE, screen(data), 0, data->InvisibleId.toULong(), ICQ_INVISIBLE_LIST); }else{ log(L_DEBUG, "%s remove from invisible list", userStr(contact, data).local8Bit().data()); seq = sendRoster(ICQ_SNACxLISTS_DELETE, screen(data), 0, data->ContactInvisibleId.toULong(), ICQ_INVISIBLE_LIST); } m_listRequest = new SetListRequest(seq, screen(data), data->InvisibleId.toULong(), ICQ_INVISIBLE_LIST); break; } data->InvisibleId.asULong() = data->ContactInvisibleId.toULong(); } if (contact->getIgnore() != (data->IgnoreId.toULong() != 0)){ unsigned short ignore_id = 0; if (data->IgnoreId.toULong()){ log(L_DEBUG, "%s remove from ignore list", userStr(contact, data).local8Bit().data()); seq = sendRoster(ICQ_SNACxLISTS_DELETE, screen(data), 0, data->IgnoreId.toULong(), ICQ_IGNORE_LIST); }else{ ignore_id = getListId(); log(L_DEBUG, "%s add to ignore list", userStr(contact, data).local8Bit().data()); seq = sendRoster(ICQ_SNACxLISTS_CREATE, screen(data), 0, ignore_id, ICQ_IGNORE_LIST); } m_listRequest = new SetListRequest(seq, screen(data), ignore_id, ICQ_IGNORE_LIST); break; } if (contact->getGroup()){ group = getContacts()->group(contact->getGroup()); if (group){ ICQUserData *grp_data = (ICQUserData*)(group->clientData.getData(this)); if (grp_data) grp_id = grp_data->IcqID.toULong(); } } if (data->GrpId.toULong() != grp_id){ if (grp_id){ if (data->GrpId.toULong() == 0){ snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_FUTURE_AUTH); socket()->writeBuffer().packScreen(screen(data)); socket()->writeBuffer() << 0x00000000L; sendPacket(true); } if (data->IcqID.toULong() == 0) data->IcqID.asULong() = getListId(); TlvList *tlv = createListTlv(data, contact); if (data->GrpId.toULong()) seq = sendRoster(ICQ_SNACxLISTS_DELETE, QString::null, data->GrpId.toULong(), data->IcqID.toULong()); seq = sendRoster(ICQ_SNACxLISTS_CREATE, screen(data), grp_id, data->IcqID.toULong(), 0, tlv); sendRosterGrp(group->getName(), grp_id, data->IcqID.toULong()); log(L_DEBUG, "%s move to group %s", userStr(contact, data).local8Bit().data(), (const char*)group->getName().local8Bit()); m_listRequest = new ContactServerRequest(seq, screen(data), data->IcqID.toULong(), grp_id, tlv); }else{ log(L_DEBUG, "%s remove from contact list", userStr(contact, data).local8Bit().data()); seq = sendRoster(ICQ_SNACxLISTS_DELETE, QString::null, data->GrpId.toULong(), data->IcqID.toULong()); m_listRequest = new ContactServerRequest(seq, screen(data), 0, 0); } break; } if (data->IcqID.toULong() == 0) break; if (isContactRenamed(data, contact)){ log(L_DEBUG, "%s rename", userStr(contact, data).local8Bit().data()); TlvList *tlv = createListTlv(data, contact); seq = sendRoster(ICQ_SNACxLISTS_UPDATE, screen(data), data->GrpId.toULong(), data->IcqID.toULong(), 0, tlv); m_listRequest = new ContactServerRequest(seq, screen(data), data->IcqID.toULong(), data->GrpId.toULong(), tlv); break; } break; case LIST_USER_DELETED: if (lr.visible_id){ log(L_DEBUG, "%s remove from visible list", lr.screen.local8Bit().data()); seq = sendRoster(ICQ_SNACxLISTS_DELETE, lr.screen, 0, lr.visible_id, ICQ_VISIBLE_LIST); m_listRequest = new SetListRequest(seq, lr.screen, 0, ICQ_VISIBLE_LIST); break; } if (lr.invisible_id){ log(L_DEBUG, "%s remove from invisible list", lr.screen.local8Bit().data()); seq = sendRoster(ICQ_SNACxLISTS_DELETE, lr.screen, 0, lr.invisible_id, ICQ_INVISIBLE_LIST); m_listRequest = new SetListRequest(seq, lr.screen, 0, ICQ_INVISIBLE_LIST); break; } if (lr.ignore_id){ log(L_DEBUG, "%s remove from ignore list", lr.screen.local8Bit().data()); seq = sendRoster(ICQ_SNACxLISTS_DELETE, lr.screen, 0, lr.ignore_id, ICQ_IGNORE_LIST); m_listRequest = new SetListRequest(seq, lr.screen, 0, ICQ_IGNORE_LIST); break; } if (lr.screen.length() && lr.grp_id){ log(L_DEBUG, "%s remove from contact list", lr.screen.local8Bit().data()); seq = sendRoster(ICQ_SNACxLISTS_DELETE, QString::null, lr.grp_id, lr.icq_id); m_listRequest = new ContactServerRequest(seq, lr.screen, 0, 0); } break; case LIST_GROUP_CHANGED: group = getContacts()->group(lr.screen.toULong()); if (group){ QString name = group->getName(); data = (ICQUserData*)(group->clientData.getData(this)); if (data){ icq_id = (unsigned short)(data->IcqID.toULong()); QString alias = data->Alias.str(); if (alias != name){ log(L_DEBUG, "rename group %s", (const char*)group->getName().local8Bit()); seq = sendRoster(ICQ_SNACxLISTS_UPDATE, name, icq_id, 0, ICQ_GROUPS); } }else{ log(L_DEBUG, "create group %s", (const char*)group->getName().local8Bit()); icq_id = getListId(); seq = sendRoster(ICQ_SNACxLISTS_CREATE, name, icq_id, 0, ICQ_GROUPS); } if (seq) m_listRequest = new GroupServerRequest(seq, group->id(), icq_id, name); } break; case LIST_GROUP_DELETED: if (lr.icq_id){ log(L_DEBUG, "delete group"); seq = sendRoster(ICQ_SNACxLISTS_DELETE, QString::null, lr.icq_id, 0, ICQ_GROUPS); m_listRequest = new GroupServerRequest(seq, 0, lr.icq_id, QString::null); } break; case LIST_BUDDY_CHECKSUM: if (lr.icqUserData){ log(L_DEBUG, "Add/Modify buddy icon checksum"); QImage img(getPicture()); if(img.isNull()) break; QByteArray ba; QBuffer buf(ba); if(!buf.open(IO_WriteOnly)) { log(L_ERROR, "Can't open QByteArray for writing!"); break; } if(!img.save(&buf, "JPEG")) { log(L_ERROR, "Can't save QImage to QBuffer"); break; } buf.close(); QByteArray hash = md5(ba.data(), ba.size()); if(hash == this->data.owner.buddyHash.toBinary() && 1 == this->data.owner.buddyID.toULong()) { log(L_DEBUG, "No need to upload buddy"); break; } TlvList *tlvList = new TlvList; ba.resize(hash.size() + 2); ba.data()[0] = 0x01; ba.data()[1] = hash.size(); memcpy(&ba.data()[2], hash.data(), hash.size()); *tlvList += new Tlv(TLV_BUDDYHASH, ba.size(), ba.data()); *tlvList += new Tlv(TLV_ALIAS, 0, NULL); unsigned short seq = sendRoster(lr.icq_id ? ICQ_SNACxLISTS_UPDATE : ICQ_SNACxLISTS_CREATE, "1", lr.grp_id, lr.icq_id, ICQ_BUDDY_CHECKSUM, tlvList); m_listRequest = new SetBuddyRequest(seq, &this->data.owner); } break; } if (m_listRequest) break; listRequests.erase(listRequests.begin()); } return 0; } void ICQClient::checkListRequest() { if (m_listRequest == NULL) return; if (time(NULL) > (m_listRequest->getTime() + LIST_REQUEST_TIMEOUT)){ log(L_WARN, "List request timeout"); m_listRequest->process(this, (unsigned short)(-1)); delete m_listRequest; m_listRequest = NULL; processSendQueue(); } } void ICQClient::addGroupRequest(Group *group) { QString name; name = group->getName(); ICQUserData *data = (ICQUserData*)(group->clientData.getData(this)); if (data == NULL){ list::iterator it; for (it = listRequests.begin(); it != listRequests.end(); it++){ if ((*it).type != LIST_GROUP_CHANGED) continue; if ((*it).screen.toULong() == group->id()) return; } ListRequest lr; lr.type = LIST_GROUP_CHANGED; lr.screen = QString::number(group->id()); listRequests.push_back(lr); processSendQueue(); return; } list::iterator it; for (it = listRequests.begin(); it != listRequests.end(); it++){ if ((*it).type != LIST_GROUP_CHANGED) continue; if ((*it).icq_id == data->IcqID.toULong()) return; } QString alias = data->Alias.str(); if (alias == name) return; ListRequest lr; lr.type = LIST_GROUP_CHANGED; lr.icq_id = (unsigned short)(data->IcqID.toULong()); lr.screen = QString::number(group->id()); listRequests.push_back(lr); processSendQueue(); } void ICQClient::addContactRequest(Contact *contact) { ICQUserData *data; ClientDataIterator it(contact->clientData, this); while ((data = (ICQUserData*)(++it)) != NULL){ list::iterator it; for (it = listRequests.begin(); it != listRequests.end(); it++){ if ((*it).type != LIST_USER_CHANGED) continue; if ((*it).screen == screen(data)) return; } bool bChanged = false; if (data->VisibleId.toULong() != data->ContactVisibleId.toULong()){ if ((data->VisibleId.toULong() == 0) || (data->ContactVisibleId.toULong() == 0)){ bChanged = true; log(L_DEBUG, "%s change visible state", userStr(contact, data).local8Bit().data()); }else{ data->VisibleId.asULong() = data->ContactVisibleId.toULong(); } } if (data->InvisibleId.toULong() != data->ContactInvisibleId.toULong()){ if ((data->InvisibleId.toULong() == 0) || (data->ContactInvisibleId.toULong() == 0)){ bChanged = true; log(L_DEBUG, "%s change invisible state", userStr(contact, data).local8Bit().data()); }else{ data->InvisibleId.asULong() = data->ContactInvisibleId.toULong(); } } if (contact->getIgnore() != (data->IgnoreId.toULong() != 0)){ log(L_DEBUG, "%s change ignore state", userStr(contact, data).local8Bit().data()); bChanged = true; } if (!bChanged){ unsigned grp_id = 0; if (contact->getGroup()){ Group *group = getContacts()->group(contact->getGroup()); if (group){ ICQUserData *grp_data = (ICQUserData*)(group->clientData.getData(this)); if (grp_data){ grp_id = grp_data->IcqID.toULong(); }else{ addGroupRequest(group); } } } if (data->GrpId.toULong() != grp_id){ if (grp_id == 0) { // // fix for #5302 grp_id = 1; contact->setGroup(grp_id); unsigned oldGrpId = data->GrpId.toULong(); data->GrpId.asULong() = grp_id; log(L_WARN, "%s change group %u->%u, because otherewise the contact would be deleted", userStr(contact, data).local8Bit().data(), oldGrpId, grp_id); return; // } else { log(L_DEBUG, "%s change group %lu->%u", userStr(contact, data).local8Bit().data(), data->GrpId.toULong(), grp_id); bChanged = true; } } if (!bChanged && (data->IcqID.toULong() == 0)) return; if (!bChanged && !isContactRenamed(data, contact)) return; } ListRequest lr; lr.type = LIST_USER_CHANGED; lr.screen = screen(data); listRequests.push_back(lr); processSendQueue(); } } bool ICQClient::isContactRenamed(ICQUserData *data, Contact *contact) { QString alias = data->Alias.str(); if(alias.isEmpty()) alias.sprintf("%lu", data->Uin.toULong()); if (contact->getName() != alias){ log(L_DEBUG, "%lu renamed %s->%s", data->Uin.toULong(), alias.latin1(), contact->getName().latin1()); return true; } QString cell = getUserCellular(contact); QString phone = data->Cellular.str(); if (cell != phone){ log(L_DEBUG, "%s phone changed %s->%s", userStr(contact, data).latin1(), phone.latin1(), cell.latin1()); return true; } return false; } QString ICQClient::getUserCellular(Contact *contact) { QString phones = contact->getPhones(); while (phones.length()){ QString phoneItem = getToken(phones, ';', false); QString phone = getToken(phoneItem, '/', false); if (phoneItem != "-") continue; QString value = getToken(phone, ','); getToken(phone, ','); if (phone.toUInt() == CELLULAR){ return value; } } return QString(); } bool ICQClient::sendAuthRequest(Message *msg, void *_data) { if ((getState() != Connected) || (_data == NULL)) return false; ICQUserData *data = (ICQUserData*)_data; snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_REQUEST_AUTH); socket()->writeBuffer().packScreen(screen(data)); QCString message; QString charset; if (hasCap(data, CAP_RTF) || hasCap(data, CAP_UTF)){ message = msg->getPlainText().utf8(); charset = "utf-8"; }else{ message = getContacts()->fromUnicode(NULL, msg->getPlainText()); } socket()->writeBuffer() << (unsigned short)(message.length()) << message.data() << (char)0x00; if (charset.isEmpty()){ socket()->writeBuffer() << (char)0x00; }else{ socket()->writeBuffer() << (char)0x01 << (unsigned short)1 << (unsigned short)(charset.length()) << charset.latin1(); } sendPacket(true); msg->setClient(dataName(data)); EventSent(msg).process(); EventMessageSent(msg).process(); delete msg; return true; } bool ICQClient::sendAuthGranted(Message *msg, void *_data) { if ((getState() != Connected) || (_data == NULL)) return false; ICQUserData *data = (ICQUserData*)_data; data->WantAuth.asBool() = false; snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_AUTHxSEND); socket()->writeBuffer().packScreen(screen(data)); socket()->writeBuffer() << (char)0x01 << (unsigned long)0; sendPacket(true); msg->setClient(dataName(data)); EventSent(msg).process(); EventMessageSent(msg).process(); delete msg; return true; } bool ICQClient::sendAuthRefused(Message *msg, void *_data) { if ((getState() != Connected) || (_data == NULL)) return false; ICQUserData *data = (ICQUserData*)_data; data->WantAuth.asBool() = false; snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_AUTHxSEND); socket()->writeBuffer().packScreen(screen(data)); QCString message; QCString charset; if (hasCap(data, CAP_RTF) || hasCap(data, CAP_UTF)){ message = msg->getPlainText().utf8(); charset = "utf-8"; }else{ message = getContacts()->fromUnicode(NULL, msg->getPlainText()); } socket()->writeBuffer() << (char) 0 << (unsigned short)(message.length()) << message << (char)0x00; if (charset.isEmpty()){ socket()->writeBuffer() << (char)0x00; }else{ socket()->writeBuffer() << (char)0x01 << (unsigned short)1 << (unsigned short)(charset.length()) << charset; } sendPacket(true); msg->setClient(dataName(data)); EventSent(msg).process(); EventMessageSent(msg).process(); delete msg; return true; }