JabberClient::PresenceRequest::~PresenceRequest() { unsigned status = STATUS_UNKNOWN; if (m_type == "unavailable"){ status = STATUS_OFFLINE; }else if (m_type.length() == 0){ status = STATUS_ONLINE; if (m_show == "away"){ status = STATUS_AWAY; }else if (m_show == "xa"){ status = STATUS_NA; }else if (m_show == "dnd"){ status = STATUS_DND; } }else{ if (m_type == "subscribe"){ m_client->auth_request(m_from.c_str(), MessageAuthRequest, m_status.c_str(), true); }else if (m_type == "subscribed"){ m_client->auth_request(m_from.c_str(), MessageAuthGranted, m_status.c_str(), true); }else if (m_type == "unsubscribed"){ m_client->auth_request(m_from.c_str(), MessageRemoved, m_status.c_str(), true); }else{ log(L_DEBUG, "Unsupported presence type %s", m_type.c_str()); } } if (status != STATUS_UNKNOWN){ Contact *contact; JabberUserData *data = m_client->findContact(m_from.c_str(), NULL, NULL, false, contact); if (data){ bool bOnLine = false; bool bChanged = set_str(&data->AutoReply, m_status.c_str()); if (data->Status != status){ time_t now; time(&now); bChanged = true; if ((status == STATUS_ONLINE) && ((now - m_client->data.owner.OnlineTime > 60) || (data->Status != STATUS_OFFLINE))) bOnLine = true; if (data->Status == STATUS_OFFLINE) data->OnlineTime = now; data->Status = status; data->StatusTime = now; } if (bChanged){ StatusMessage m; m.setContact(contact->id()); m.setClient(m_client->dataName(data).c_str()); m.setFlags(MESSAGE_RECEIVED); m.setStatus(status); Event e(EventMessageReceived, &m); e.process(); } if (bOnLine){ Event e(EventContactOnline, contact); e.process(); } } } }
void YahooClient::processStatus(unsigned short service, const char *id, const char *_state, const char *_msg, const char *_away, const char *_idle) { Contact *contact; YahooUserData *data = findContact(id, NULL, contact); if (data == NULL) return; unsigned state = 0; unsigned away = 0; unsigned idle = 0; if (_state) state = atol(_state); if (_away) away = atol(_away); if (_idle) idle = atol(_idle); if (service == YAHOO_SERVICE_LOGOFF) state = YAHOO_STATUS_OFFLINE; if ((state != data->Status.value) || ((state == YAHOO_STATUS_CUSTOM) && (((away != 0) != data->bAway.bValue) || _cmp(_msg, data->AwayMessage.ptr)))) { unsigned long old_status = STATUS_UNKNOWN; unsigned style = 0; const char *statusIcon = NULL; contactInfo(data, old_status, style, statusIcon); time_t now; time(&now); now -= idle; if (data->Status.value == YAHOO_STATUS_OFFLINE) data->OnlineTime.value = now; data->Status.value = state; data->bAway.bValue = (away != 0); data->StatusTime.value = now; unsigned long new_status = STATUS_UNKNOWN; contactInfo(data, old_status, style, statusIcon); if (old_status != new_status) { StatusMessage m; m.setContact(contact->id()); m.setClient(dataName(data).c_str()); m.setFlags(MESSAGE_RECEIVED); m.setStatus(STATUS_OFFLINE); Event e(EventMessageReceived, &m); e.process(); if ((new_status == STATUS_ONLINE) && !contact->getIgnore()) { Event e(EventContactOnline, contact); e.process(); } } else { Event e(EventContactStatus, contact); e.process(); } } }
void JabberClient::setStatus(unsigned status, const char *ar) { if (status != m_status){ time_t now; time(&now); data.owner.StatusTime = now; if (m_status == STATUS_OFFLINE) data.owner.OnlineTime = now; m_status = status; m_socket->writeBuffer.packetStart(); const char *priority = "5"; const char *show = NULL; const char *type = NULL; if (getInvisible()){ type = "invisible"; }else{ switch (status){ case STATUS_AWAY: show = "away"; break; case STATUS_NA: show = "xa"; break; case STATUS_DND: show = "dnd"; break; case STATUS_FFC: show = "chat"; break; case STATUS_OFFLINE: priority = NULL; type = "unavailable"; break; } } m_socket->writeBuffer << "<presence"; if (type) m_socket->writeBuffer << " type=\"" << type << "\""; m_socket->writeBuffer << ">\n"; if (show && *show) m_socket->writeBuffer << "<show>" << show << "</show>\n"; if (ar && *ar){ m_socket->writeBuffer << "<status>" << ar << "</status>\n"; } if (priority) m_socket->writeBuffer << "<priority>" << priority << "</priority>\n"; m_socket->writeBuffer << "</presence>"; sendPacket(); Event e(EventClientChanged, static_cast<Client*>(this)); e.process(); } if (status == STATUS_OFFLINE){ if (m_socket){ m_socket->writeBuffer.packetStart(); m_socket->writeBuffer << "</stream:stream>\n"; sendPacket(); } Contact *contact; ContactList::ContactIterator it; time_t now; time(&now); data.owner.StatusTime = now; while ((contact = ++it) != NULL){ JabberUserData *data; ClientDataIterator it(contact->clientData, this); while ((data = (JabberUserData*)(++it)) != NULL){ if (data->Status == STATUS_OFFLINE) continue; data->StatusTime = now; setOffline(data); StatusMessage m; m.setContact(contact->id()); m.setClient(dataName(data).c_str()); m.setFlags(MESSAGE_RECEIVED); m.setStatus(STATUS_OFFLINE); Event e(EventMessageReceived, &m); e.process(); } } } }
void ICQClient::snac_buddy(unsigned short type, unsigned short) { string screen; Contact *contact; ICQUserData *data; switch (type){ case ICQ_SNACxBDY_RIGHTSxGRANTED: log(L_DEBUG, "Buddy rights granted"); break; case ICQ_SNACxBDY_USEROFFLINE: screen = m_socket->readBuffer.unpackScreen(); data = findContact(screen.c_str(), NULL, false, contact); if (data && (data->Status.value != ICQ_STATUS_OFFLINE)){ setOffline(data); StatusMessage m; m.setContact(contact->id()); m.setClient(dataName(data).c_str()); m.setStatus(STATUS_OFFLINE); m.setFlags(MESSAGE_RECEIVED); Event e(EventMessageReceived, &m); e.process(); } break; case ICQ_SNACxBDY_USERONLINE: screen = m_socket->readBuffer.unpackScreen(); data = findContact(screen.c_str(), NULL, false, contact); if (data){ time_t now; time(&now); bool bChanged = false; bool bAwayChanged = false; unsigned long prevStatus = data->Status.value; unsigned short level, len; m_socket->readBuffer >> level >> len; data->WarningLevel.value = level; TlvList tlv(m_socket->readBuffer); Tlv *tlvClass = tlv(0x0001); if (tlvClass){ unsigned short userClass = *tlvClass; if (userClass != data->Class.value){ if ((userClass & CLASS_AWAY) != (data->Class.value & CLASS_AWAY)){ data->StatusTime.value = (unsigned long)now; bAwayChanged = true; } data->Class.value = userClass; bChanged = true; } if (data->Uin.value == 0){ if (userClass & CLASS_AWAY){ fetchAwayMessage(data); }else{ set_str(&data->AutoReply.ptr, NULL); } } } // Status TLV Tlv *tlvStatus = tlv(0x0006); if (tlvStatus){ unsigned long status = *tlvStatus; if (status != data->Status.value){ data->Status.value = status; if ((status & 0xFF) == 0) set_str(&data->AutoReply.ptr, NULL); data->StatusTime.value = (unsigned long)now; } }else if (data->Status.value == ICQ_STATUS_OFFLINE){ data->Status.value = ICQ_STATUS_ONLINE; data->StatusTime.value = (unsigned long)now; } // Online time TLV Tlv *tlvOnlineTime = tlv(0x0003); if (tlvOnlineTime){ unsigned long OnlineTime = *tlvOnlineTime; if (OnlineTime != data->OnlineTime.value){ data->OnlineTime.value = OnlineTime; bChanged = true; } } Tlv *tlvNATime = tlv(0x0004); if (tlvNATime){ unsigned short na_time = *tlvNATime; unsigned long StatusTime = (unsigned long)now - na_time * 60; if (StatusTime != data->StatusTime.value){ data->StatusTime.value = StatusTime; bChanged = true; } } // IP TLV Tlv *tlvIP = tlv(0x000A); if (tlvIP) bChanged |= set_ip(&data->IP, htonl((unsigned long)(*tlvIP))); Tlv *tlvCapability = tlv(0x000D); if (tlvCapability){ data->Caps.value = 0; Buffer info(*tlvCapability); for (; info.readPos() < info.size(); ){ capability cap; info.unpack((char*)cap, sizeof(capability)); for (unsigned i = 0;; i++){ if (*capabilities[i] == 0) break; unsigned size = sizeof(capability); if (i == CAP_SIMOLD) size--; if ((i == CAP_MICQ) || (i == CAP_LICQ) || (i == CAP_SIM)) size -= 4; if (!memcmp(cap, capabilities[i], size)){ if (i == CAP_SIMOLD){ unsigned char build = cap[sizeof(capability)-1]; if (build && ((build == 0x92) || (build < (1 << 6)))) continue; data->Build.value = build; } if ((i == CAP_MICQ) || (i == CAP_LICQ) || (i == CAP_SIM)){ unsigned char *p = (unsigned char*)cap; p += 12; data->Build.value = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; } data->Caps.value |= (1 << i); break; } } } } unsigned long infoUpdateTime = 0; unsigned long pluginInfoTime = 0; unsigned long pluginStatusTime = 0; // Direct connection info Tlv *tlvDirect = tlv(0x000C); if (tlvDirect){ Buffer info(*tlvDirect); unsigned long realIP; unsigned short port; char mode, version, junk; info >> realIP; info.incReadPos(2); info >> port; if (realIP == 0x7F000001) realIP = 0; bChanged |= set_ip(&data->RealIP, htonl(realIP)); data->Port.value = port; unsigned long DCcookie; info >> mode >> junk >> version >> DCcookie; data->DCcookie.value = DCcookie; info.incReadPos(8); info >> infoUpdateTime >> pluginInfoTime >> pluginStatusTime; if (mode == MODE_DENIED) mode = MODE_INDIRECT; if ((mode != MODE_DIRECT) && (mode != MODE_INDIRECT)) mode = MODE_INDIRECT; data->Mode.value = mode; data->Version.value = version; } Tlv *tlvPlugin = tlv(0x0011); if (tlvPlugin && data->Uin.value){ Buffer info(*tlvPlugin); char type; unsigned long time; info >> type; info.unpack(time); plugin p; unsigned plugin_index; unsigned long plugin_status; switch (type){ case 1: addFullInfoRequest(data->Uin.value); break; case 2: info.incReadPos(6); info.unpack((char*)p, sizeof(p)); data->PluginInfoTime.value = time; for (plugin_index = 0; plugin_index < PLUGIN_NULL; plugin_index++) if (!memcmp(p, plugins[plugin_index], sizeof(p))) break; switch (plugin_index){ case PLUGIN_PHONEBOOK: log(L_DEBUG, "Updated phonebook"); addPluginInfoRequest(data->Uin.value, plugin_index); break; case PLUGIN_PICTURE: log(L_DEBUG, "Updated picture"); addPluginInfoRequest(data->Uin.value, plugin_index); break; case PLUGIN_QUERYxINFO: log(L_DEBUG, "Updated info plugin list"); addPluginInfoRequest(data->Uin.value, plugin_index); break; default: if (plugin_index >= PLUGIN_NULL) log(L_WARN, "Unknown plugin sign"); } break; case 3: info.incReadPos(6); info.unpack((char*)p, sizeof(p)); info.incReadPos(1); info.unpack(plugin_status); data->PluginStatusTime.value = time; for (plugin_index = 0; plugin_index < PLUGIN_NULL; plugin_index++) if (!memcmp(p, plugins[plugin_index], sizeof(p))) break; switch (plugin_index){ case PLUGIN_FOLLOWME: if (data->FollowMe.value == plugin_status) break; data->FollowMe.value = plugin_status; bChanged = true; break; case PLUGIN_FILESERVER: if ((data->SharedFiles.value != 0) == (plugin_status != 0)) break; data->SharedFiles.value = (plugin_status != 0); bChanged = true; break; case PLUGIN_ICQPHONE: if (data->ICQPhone.value == plugin_status) break; data->ICQPhone.value = plugin_status; bChanged = true; break; default: if (plugin_index >= PLUGIN_NULL) log(L_WARN, "Unknown plugin sign"); } break; } }else{ data->InfoUpdateTime.value = infoUpdateTime; data->PluginInfoTime.value = pluginInfoTime; data->PluginStatusTime.value = pluginStatusTime; if (getAutoUpdate()){ if (infoUpdateTime == 0) infoUpdateTime = 1; if (infoUpdateTime != data->InfoFetchTime.value) addFullInfoRequest(data->Uin.value); if ((data->PluginInfoTime.value != data->PluginInfoFetchTime.value)){ if (data->PluginInfoTime.value) addPluginInfoRequest(data->Uin.value, PLUGIN_QUERYxINFO); } if ((data->PluginInfoTime.value != data->PluginInfoFetchTime.value) || (data->PluginStatusTime.value != data->PluginStatusFetchTime.value)){ if (data->SharedFiles.bValue){ data->SharedFiles.bValue = false; bChanged = true; } if (data->FollowMe.value){ data->FollowMe.value = 0; bChanged = true; } if (data->ICQPhone.bValue){ data->ICQPhone.bValue = false; bChanged = true; } if (data->PluginStatusTime.value) addPluginInfoRequest(data->Uin.value, PLUGIN_QUERYxSTATUS); } } } if (data->bInvisible.bValue){ data->bInvisible.bValue = false; bChanged = true; } if (bChanged){ Event e(EventContactChanged, contact); e.process(); } if ((data->Status.value != prevStatus) || bAwayChanged){ unsigned status = STATUS_OFFLINE; if ((data->Status.value & 0xFFFF) != ICQ_STATUS_OFFLINE){ status = STATUS_ONLINE; if (data->Status.value & ICQ_STATUS_DND){ status = STATUS_DND; }else if (data->Status.value & ICQ_STATUS_OCCUPIED){ status = STATUS_OCCUPIED; }else if (data->Status.value & ICQ_STATUS_NA){ status = STATUS_NA; }else if (data->Status.value & ICQ_STATUS_AWAY){ status = STATUS_AWAY; }else if (data->Status.value & ICQ_STATUS_FFC){ status = STATUS_FFC; } } if ((status == STATUS_ONLINE) && (data->Class.value & CLASS_AWAY)) status = STATUS_AWAY; StatusMessage m; m.setContact(contact->id()); m.setClient(dataName(data).c_str()); m.setStatus(status); m.setFlags(MESSAGE_RECEIVED); Event e(EventMessageReceived, &m); e.process(); if (!contact->getIgnore() && ((data->Class.value & CLASS_AWAY) == 0) && (((data->Status.value & 0xFF) == ICQ_STATUS_ONLINE) && (((prevStatus & 0xFF) != ICQ_STATUS_ONLINE)) || bAwayChanged) && (((prevStatus & 0xFFFF) != ICQ_STATUS_OFFLINE) || (data->OnlineTime.value > this->data.owner.OnlineTime.value))){ Event e(EventContactOnline, contact); e.process(); } if (getAutoReplyUpdate() && ((data->Status.value & 0xFF) != ICQ_STATUS_ONLINE)){ if ((getInvisible() && data->VisibleId.value) || (!getInvisible() && (data->InvisibleId.value == 0))) addPluginInfoRequest(data->Uin.value, PLUGIN_AR); } } }
JabberClient::PresenceRequest::~PresenceRequest() { unsigned status = STATUS_UNKNOWN; /* m_type - flags after draft-ietf-xmpp-core-16 / 8.4.1 */ if (m_type == "unavailable") { status = STATUS_OFFLINE; } else if (m_type == "subscribe") { m_client->auth_request(m_from.c_str(), MessageAuthRequest, m_status.c_str(), true); } else if (m_type == "subscribed") { m_client->auth_request(m_from.c_str(), MessageAuthGranted, m_status.c_str(), true); } else if (m_type == "unsubscribe") { m_client->auth_request(m_from.c_str(), MessageRemoved, m_status.c_str(), true); } else if (m_type == "unsubscribed") { m_client->auth_request(m_from.c_str(), MessageAuthRefused, m_status.c_str(), true); } else if (m_type == "probe") { // server want to to know if we're living m_client->ping(); } else if (m_type == "error") { log(L_DEBUG, "An error has occurred regarding processing or delivery of a previously-sent presence stanza"); } else if (m_type.length() == 0) { // m_show - flags after draft-ietf-xmpp-im-15 / 4.2 status = STATUS_ONLINE; if (m_show == "away") { status = STATUS_AWAY; } else if (m_show == "chat") { status = STATUS_FFC; } else if (m_show == "xa") { status = STATUS_NA; } else if (m_show == "dnd") { status = STATUS_DND; } else if (m_show == "online") { status = STATUS_ONLINE; } else if (m_show.empty()) { status = STATUS_ONLINE; if (m_status == "Online") { status = STATUS_ONLINE; } else if (m_status == "Disconnected") { status = STATUS_OFFLINE; } else if (m_status == "Connected") { status = STATUS_ONLINE; } else if (!m_status.empty()) { log(L_DEBUG, "Unsupported status %s", m_status.c_str()); } } else { log(L_DEBUG, "Unsupported available status %s", m_show.c_str()); } } else { log(L_DEBUG, "Unsupported presence type %s", m_type.c_str()); } if (status != STATUS_UNKNOWN) { Contact *contact; JabberUserData *data = m_client->findContact(m_from.c_str(), NULL, false, contact); if (data) { bool bOnLine = false; bool bChanged = set_str(&data->AutoReply, m_status.c_str()); if (data->Status != status) { time_t now; time(&now); bChanged = true; if ((status == STATUS_ONLINE) && ((now - m_client->data.owner.OnlineTime > 60) || (data->Status != STATUS_OFFLINE))) bOnLine = true; if (data->Status == STATUS_OFFLINE) data->OnlineTime = now; data->Status = status; data->StatusTime = now; } if (bChanged) { StatusMessage m; m.setContact(contact->id()); m.setClient(m_client->dataName(data).c_str()); m.setFlags(MESSAGE_RECEIVED); m.setStatus(status); Event e(EventMessageReceived, &m); e.process(); } if (bOnLine && !contact->getIgnore() && !m_client->isAgent(data->ID)) { Event e(EventContactOnline, contact); e.process(); } } } }
bool SnacIcqBuddy::process(unsigned short subtype, ICQBuffer* buf, unsigned short seq) { switch (subtype) { case ICQ_SNACxBDY_RIGHTSxGRANTED: log(L_DEBUG, "Buddy rights granted"); break; case ICQ_SNACxBDY_USEROFFLINE: { Contact *contact; QString screen = buf->unpackScreen(); log(L_DEBUG, "Buddy offline: %s", qPrintable(screen)); ICQUserData *data = m_client->findContact(screen, NULL, false, contact); if(!data) break; if(data->getStatus() != ICQ_STATUS_OFFLINE) { m_client->setOffline(data); StatusMessage *m = new StatusMessage; m->setContact(contact->id()); m->setClient(m_client->dataName(data)); m->setStatus(STATUS_OFFLINE); m->setFlags(MESSAGE_RECEIVED); EventMessageReceived e(m); if(!e.process()) delete m; } else { // hack for trillian EventContact e(contact, EventContact::eOnline); e.process(); } break; } case ICQ_SNACxBDY_USERONLINE: { Contact *contact; QString screen = buf->unpackScreen(); log(L_DEBUG, "Buddy online: %s", qPrintable(screen)); ICQUserData *data = m_client->findContact(screen, NULL, false, contact); if(data) { bool bChanged = false; bool bAwayChanged = false; unsigned long prevStatus = data->getStatus(); unsigned short level, len; (*buf) >> level >> len; data->setWarningLevel(level); TlvList tlv((*buf)); Tlv* tlvClass = tlv(TLV_USER_CLASS); if(tlvClass) { unsigned short userClass = *tlvClass; if(userClass != data->getClass()) { if ((userClass & CLASS_AWAY) != (data->getClass() & CLASS_AWAY)) { data->setStatusTime((unsigned long)time(NULL)); bAwayChanged = true; } data->setClass(userClass); bChanged = true; } if(data->getUin() == 0) { if (userClass & CLASS_AWAY) { m_client->fetchAwayMessage(data); } else { data->setAutoReply(QString::null); } } } // Status TLV Tlv *tlvStatus = tlv(TLV_USER_STATUS); if(tlvStatus) { uint32_t status = *tlvStatus; if (status != data->getStatus()) { data->setStatus(status); if ((status & 0xFF) == 0) data->setAutoReply(QString::null); data->setStatusTime((unsigned long)time(NULL)); } } else if(data->getStatus() == ICQ_STATUS_OFFLINE) { data->setStatus(ICQ_STATUS_ONLINE); data->setStatusTime((unsigned long)time(NULL)); } // Online time TLV Tlv *tlvOnlineTime = tlv(TLV_USER_SIGNON_TIME); if(tlvOnlineTime) { uint32_t OnlineTime = *tlvOnlineTime; if(OnlineTime != data->getOnlineTime()) { data->setOnlineTime(OnlineTime); bChanged = true; } } Tlv *tlvNATime = tlv(0x0004); if(tlvNATime) { unsigned short na_time = *tlvNATime; unsigned long StatusTime = (unsigned long)time(NULL) - na_time * 60; if(StatusTime != data->getStatusTime()) { data->setStatusTime(StatusTime); bChanged = true; } } // IP TLV Tlv *tlvIP = tlv(TLV_USER_EXT_IP); unsigned long oldip = data->getIP(); data->setIP(htonl((uint32_t)(*tlvIP))); if(tlvIP) bChanged |= oldip != data->getIP(); // short caps tlv Tlv *tlvCapShort = tlv(TLV_USER_NEWCAPS); if(tlvCapShort) { data->setCaps(0); data->setCaps2(0); ICQBuffer info(*tlvCapShort); for (; info.readPos() < (unsigned)info.size(); ) { unsigned char shortcap[2]; info.unpack((char*)shortcap, sizeof(shortcap)); for (unsigned i = 0;; i++) { if (!memcmp(m_client->capabilities[i],"\x00\x00\x00\x00", 4)) { log(L_DEBUG, "%lu unknown cap %s", data->getUin(), makeCapStr(shortcap, sizeof(shortcap)).toLatin1().data()); break; } // we don't go through all caps, only the starting with 0x09 if (*m_client->capabilities[i] != '\x09') continue; if(!memcmp(&m_client->capabilities[i][2], shortcap, sizeof(shortcap))) { m_client->setCap(data, (cap_id_t)i); break; } } } } // normal cap tlv Tlv *tlvCapability = tlv(TLV_USER_CAPS); if (tlvCapability) { if(!tlvCapShort) { data->setCaps(0); data->setCaps2(0); } ICQBuffer info(*tlvCapability); for(; info.readPos() < (unsigned)info.size(); ) { capability cap; info.unpack((char*)cap, sizeof(capability)); for(unsigned i = 0;; i++) { unsigned size = sizeof(capability); if (i == CAP_SIMOLD) size--; if (!memcmp(m_client->capabilities[i], "\x00\x00\x00\x00", 4)) { log( L_DEBUG, "%lu unknown cap %s", data->getUin(), qPrintable(makeCapStr( cap, size )) ); break; } if (i == CAP_MICQ || i == CAP_LICQ || i == CAP_SIM || i == CAP_KOPETE || i == CAP_QIP2010) size -= 4; if (i == CAP_ANDRQ) size -= 7; if (i == CAP_MIRANDA) size -= 8; if ((i == CAP_JIMM)) size -= 11; if (i == CAP_ICQJP) size -= (16 - 4); if (!memcmp(cap, m_client->capabilities[i], size)) { if (i == CAP_SIMOLD) { unsigned char build = cap[sizeof(capability)-1]; if (build && (build == 0x92 || build < (1 << 6))) continue; data->setBuild(build); } if (i == CAP_MICQ || i == CAP_LICQ || i == CAP_SIM || i == CAP_KOPETE) { unsigned char *p = (unsigned char*)cap; p += 12; data->setBuild((p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]); } if (i == CAP_ANDRQ) { unsigned char *p = (unsigned char*)cap; p += 9; data->setBuild((p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]); } if (i == CAP_MIRANDA) { unsigned char *p = (unsigned char*)cap; p += 8; data->setBuild((p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]); } if (i == CAP_JIMM) { char *p = (char*)cap; p += 5; const QString str = QString::fromAscii(p, 10); const QStringList sl = str.split('.'); unsigned char maj = 0, min = 0; unsigned short rev = 0; if(sl.count() > 0) maj = sl[0].toUShort(); if(sl.count() > 1) min = sl[1].toUShort(); if(sl.count() > 2) rev = sl[2].toUShort(); data->setBuild((maj << 24) + (min << 16) + rev); } if (i == CAP_ICQJP) { log(L_DEBUG, "%lu ICQJP cap is set", data->getUin()); data->setBuild(cap[0x4] << 0x18 | cap[0x5] << 0x10 | cap[0x6] << 8 | cap[0x7]); } m_client->setCap(data, (cap_id_t)i); break; } } } } // buddy info Tlv *tlvBuddy = tlv(TLV_USER_BUDDYINFO); if (tlvBuddy) { QByteArray ba = data->getBuddyHash(); unsigned short iconID; unsigned char iconFlags, hashSize; ICQBuffer info(*tlvBuddy); QByteArray hash; QString fname = m_client->pictureFile(data); QFileInfo fi(fname); info >> iconID >> iconFlags >> hashSize; hash.resize(hashSize); info.unpack(hash.data(), hashSize); if(data->getBuddyID() != iconID || ba != hash || !fi.exists() || fi.size() == 0) { data->setBuddyID(iconID); data->setBuddyHash(hash); m_client->requestBuddy(data); } } unsigned long infoUpdateTime = 0; unsigned long pluginInfoTime = 0; unsigned long pluginStatusTime = 0; // Direct connection info Tlv *tlvDirect = tlv(TLV_USER_DC_INFO); if(tlvDirect) { ICQBuffer info(*tlvDirect); unsigned long realIP; unsigned short port; char mode, version, junk; info >> realIP; info.incReadPos(2); info >> port; if (realIP == 0x7F000001) realIP = 0; unsigned long oldip = data->getRealIP(); data->setRealIP(htonl(realIP)); bChanged |= oldip != data->getRealIP(); data->setPort(port); unsigned long DCcookie; info >> mode >> junk >> version >> DCcookie; data->setDCcookie(DCcookie); info.incReadPos(8); info >> infoUpdateTime >> pluginInfoTime >> pluginStatusTime; if (mode == MODE_DENIED || mode != MODE_DIRECT && mode != MODE_INDIRECT) mode = MODE_INDIRECT; data->setMode(mode); data->setVersion(version); } Tlv *tlvPlugin = tlv(0x0011); if(tlvPlugin && data->getUin()) { ICQBuffer info(*tlvPlugin); char type; unsigned long time; info >> type; info.unpack(time); plugin p; unsigned plugin_index; unsigned long plugin_status; switch (type){ case 1: m_client->addFullInfoRequest(data->getUin()); break; case 2: if (!m_client->getInvisible() && data->getInvisibleId() == 0 || m_client->getInvisible() && data->getVisibleId()){ info.incReadPos(6); info.unpack((char*)p, sizeof(p)); data->setPluginInfoTime(time); for (plugin_index = 0; plugin_index < PLUGIN_NULL; plugin_index++) if (!memcmp(p, m_client->plugins[plugin_index], sizeof(p))) break; switch (plugin_index) { case PLUGIN_PHONEBOOK: log(L_DEBUG, "Updated phonebook"); m_client->addPluginInfoRequest(data->getUin(), plugin_index); break; case PLUGIN_PICTURE: log(L_DEBUG, "Updated picture"); // when buddyID -> new avatar support, no need to ask for old picture plugin if(data->getBuddyID() == 0 || data->getBuddyHash().size() != 16) { data->setBuddyID(0); m_client->addPluginInfoRequest(data->getUin(), plugin_index); } break; case PLUGIN_QUERYxINFO: log(L_DEBUG, "Updated info plugin list"); m_client->addPluginInfoRequest(data->getUin(), plugin_index); break; default: if (plugin_index >= PLUGIN_NULL) log(L_WARN, "Unknown plugin sign (%04X %04X)", type, plugin_index); } } break; case 3: info.incReadPos(6); info.unpack((char*)p, sizeof(p)); info.incReadPos(1); info.unpack(plugin_status); data->setPluginStatusTime(time); for (plugin_index = 0; plugin_index < PLUGIN_NULL; plugin_index++) if (!memcmp(p, m_client->plugins[plugin_index], sizeof(p))) break; switch (plugin_index){ case PLUGIN_FOLLOWME: if (data->getFollowMe() == plugin_status) break; data->setFollowMe(plugin_status); bChanged = true; break; case PLUGIN_FILESERVER: if ((data->getSharedFiles() != 0) == (plugin_status != 0)) break; data->setSharedFiles(plugin_status != 0); bChanged = true; break; case PLUGIN_ICQPHONE: if (data->getICQPhone() == plugin_status) break; data->setICQPhone(plugin_status); bChanged = true; break; default: if (plugin_index >= PLUGIN_NULL) log(L_WARN, "Unknown plugin sign (%04X %04X)", type, plugin_index); } break; } } else { data->setInfoUpdateTime(infoUpdateTime); data->setPluginInfoTime(pluginInfoTime); data->setPluginStatusTime(pluginStatusTime); if ( !m_client->getDisableAutoUpdate() && (!m_client->getInvisible() || data->getVisibleId()) && (m_client->getInvisible() || data->getInvisibleId() == 0)) { if (infoUpdateTime == 0) infoUpdateTime = 1; if (infoUpdateTime != data->getInfoFetchTime()) m_client->addFullInfoRequest(data->getUin()); if ( data->getPluginInfoTime() != data->getPluginInfoFetchTime() && data->getPluginInfoTime()) m_client->addPluginInfoRequest(data->getUin(), PLUGIN_QUERYxINFO); if ( data->getPluginInfoTime() != data->getPluginInfoFetchTime() || data->getPluginStatusTime() != data->getPluginStatusFetchTime()){ if (data->getSharedFiles()) { data->setSharedFiles(false); bChanged = true; } if (data->getFollowMe()) { data->setFollowMe(0); bChanged = true; } if (data->getICQPhone()) { data->setICQPhone(0); bChanged = true; } if (data->getPluginStatusTime()) m_client->addPluginInfoRequest(data->getUin(), PLUGIN_QUERYxSTATUS); } } } if (data->getInvisible()) { data->setInvisible(false); bChanged = true; } if (bChanged) EventContact(contact, EventContact::eChanged).process(); if (data->getStatus() != prevStatus || bAwayChanged){ unsigned status = STATUS_OFFLINE; if ((data->getStatus() & 0xFFFF) != ICQ_STATUS_OFFLINE) { status = STATUS_ONLINE; if (data->getStatus() & ICQ_STATUS_DND) status = STATUS_DND; else if (data->getStatus() & ICQ_STATUS_OCCUPIED) status = STATUS_OCCUPIED; else if (data->getStatus() & ICQ_STATUS_NA) status = STATUS_NA; else if (data->getStatus() & ICQ_STATUS_AWAY) status = STATUS_AWAY; else if (data->getStatus() & ICQ_STATUS_FFC) status = STATUS_FFC; } if((status == STATUS_ONLINE) && (data->getClass() & CLASS_AWAY)) status = STATUS_AWAY; StatusMessage *m = new StatusMessage(); m->setContact(contact->id()); m->setClient(m_client->dataName(data)); m->setStatus(status); m->setFlags(MESSAGE_RECEIVED); EventMessageReceived e(m); if(!e.process()) delete m; if ( !contact->getIgnore() && (data->getClass() & CLASS_AWAY) == 0 && ((data->getStatus() & 0xFF) == ICQ_STATUS_ONLINE && (prevStatus & 0xFF) != ICQ_STATUS_ONLINE || bAwayChanged) && ((prevStatus & 0xFFFF) != ICQ_STATUS_OFFLINE || data->getOnlineTime() > m_client->data.owner.getOnlineTime()) ) { EventContact e(contact, EventContact::eOnline); e.process(); } if ( !m_client->getDisableAutoReplyUpdate() && (data->getStatus() & 0xFF) != ICQ_STATUS_ONLINE && (!m_client->getInvisible() || data->getVisibleId()) && (m_client->getInvisible() || data->getInvisibleId() == 0) ) m_client->addPluginInfoRequest(data->getUin(), PLUGIN_AR); } } break; }