/*************************************************************************** icqlocation.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 #ifdef Q_OS_WIN32 # include #else # include #endif #include "log.h" using namespace SIM; const unsigned short ICQ_SNACxLOC_ERROR = 0x0001; const unsigned short ICQ_SNACxLOC_REQUESTxRIGHTS = 0x0002; const unsigned short ICQ_SNAXxLOC_RIGHTSxGRANTED = 0x0003; const unsigned short ICQ_SNACxLOC_SETxUSERxINFO = 0x0004; const unsigned short ICQ_SNACxLOC_REQUESTxUSERxINFO = 0x0005; const unsigned short ICQ_SNACxLOC_LOCATIONxINFO = 0x0006; const unsigned short ICQ_SNACxLOC_SETxDIRxINFO = 0x0009; const unsigned short ICQ_SNACxLOC_RESPONSExSETxINFO = 0x000A; const unsigned short ICQ_SNACxLOC_REQUESTxDIRxINFO = 0x000B; const unsigned short ICQ_SNACxLOC_DIRxINFO = 0x000C; static bool extractInfo(TlvList &tlvs, unsigned short id, SIM::Data &data, Contact *c = NULL) { const char *info = NULL; Tlv *tlv = tlvs(id); if (tlv) info = *tlv; return data.setStr(getContacts()->toUnicode(c, info)); } QString ICQClient::convert(Tlv *tlvInfo, TlvList &tlvs, unsigned n) { if (tlvInfo == NULL) return QString::null; return convert(*tlvInfo, tlvInfo->Size(), tlvs, n); } QString ICQClient::convert(const char *text, unsigned size, TlvList &tlvs, unsigned n) { QCString charset = "us-ascii"; Tlv *tlvCharset = NULL; for (unsigned i = 0; i < tlvs.count(); i++){ Tlv *tlv = tlvs[i]; if (tlv->Num() != n) continue; if (tlvCharset && (tlv->Size() < tlvCharset->Size())) continue; tlvCharset = tlv; } if (tlvCharset){ int idx1 = charset.find('\"'); if (idx1 != -1){ idx1++; int idx2 = charset.find('\"', idx1); if(idx2 != -1) charset = charset.mid(idx1, idx2 - idx1); else charset = charset.mid(idx1); } } QString res; if (charset.contains("us-ascii") || charset.contains("utf")){ res = QString::fromUtf8(text, size); }else if (charset.contains("unicode")){ unsigned short *p = (unsigned short*)text; for (unsigned i = 0; i < size - 1; i += 2, p++) res += QChar((unsigned short)htons(*p)); }else{ QTextCodec *codec = QTextCodec::codecForName(charset); if (codec){ res = codec->toUnicode(text, size); }else{ res = QString::fromUtf8(text, size); log(L_WARN, "Unknown encoding %s", charset.data()); } } return res; } void ICQClient::snac_location(unsigned short type, unsigned short seq) { Contact *contact = NULL; ICQUserData *data; QString screen; switch (type){ case ICQ_SNAXxLOC_RIGHTSxGRANTED: log(L_DEBUG, "Location rights granted"); break; case ICQ_SNACxLOC_ERROR: break; case ICQ_SNACxLOC_LOCATIONxINFO: screen = socket()->readBuffer().unpackScreen(); if (isOwnData(screen)){ data = &this->data.owner; }else{ data = findContact(screen, NULL, false, contact); } if (data){ socket()->readBuffer().incReadPos(4); TlvList tlvs(socket()->readBuffer()); Tlv *tlvInfo = tlvs(0x02); if (tlvInfo){ QString info = convert(tlvInfo, tlvs, 0x01); if (info.startsWith("", false)) info = info.mid(6); if (info.endsWith("", false)) info = info.left(info.length() - 7); if (data->About.setStr(info)){ data->ProfileFetch.asBool() = true; if (contact){ EventContact(contact, EventContact::eChanged).process(); }else{ EventClientChanged(this).process(); } } break; /* Because we won't find tlv(0x03) which is "since online" instead of encoding... */ } Tlv *tlvAway = tlvs(0x04); if (tlvAway){ QString info = convert(tlvAway, tlvs, 0x03); data->AutoReply.str() = info; EventClientChanged(this).process(); } } break; case ICQ_SNACxLOC_DIRxINFO: if (isOwnData(screen)){ data = &this->data.owner; }else{ data = findInfoRequest(seq, contact); } if (data){ bool bChanged = false; unsigned country = 0; socket()->readBuffer().incReadPos(4); TlvList tlvs(socket()->readBuffer()); Contact *c = getContact(data); bChanged |= extractInfo(tlvs, 0x01, data->FirstName, c); bChanged |= extractInfo(tlvs, 0x02, data->LastName, c); bChanged |= extractInfo(tlvs, 0x03, data->MiddleName, c); bChanged |= extractInfo(tlvs, 0x04, data->Maiden, c); bChanged |= extractInfo(tlvs, 0x07, data->State, c); bChanged |= extractInfo(tlvs, 0x08, data->City, c); bChanged |= extractInfo(tlvs, 0x0C, data->Nick, c); bChanged |= extractInfo(tlvs, 0x0D, data->Zip, c); bChanged |= extractInfo(tlvs, 0x21, data->Address, c); Tlv *tlvCountry = tlvs(0x06); if (tlvCountry){ const char *code = *tlvCountry; for (const ext_info *c = getCountryCodes(); c->nCode; c++){ QString name(c->szName); if (name.upper() == code){ country = c->nCode; break; } } } if (country != data->Country.toULong()){ data->Country.asULong() = country; bChanged = true; } data->ProfileFetch.asBool() = true; if (bChanged){ if (contact){ EventContact e(contact, EventContact::eChanged); e.process(); }else{ EventClientChanged(this).process(); } } } break; case ICQ_SNACxLOC_RESPONSExSETxINFO: break; default: log(L_WARN, "Unknown location family type %04X", type); } } void ICQClient::locationRequest() { snac(ICQ_SNACxFAM_LOCATION, ICQ_SNACxLOC_REQUESTxRIGHTS); sendPacket(true); } #define cap_id 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 #define cap_none 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define cap_str 0xbc, 0xd2, 0x00, 0x04, 0xac, 0x96, 0xdd, 0x96 #define cap_mid 0x4c, 0x7f, 0x11, 0xd1 #define cap_mstr 0x4f, 0xe9, 0xd3, 0x11 #define cap_aim 0x09, 0x46 // must be synced with cap_id_t enum in icqclient.h // const capability arrCapabilities[] = { // CAP_AIM_SHORTCAPS { cap_aim, 0x00, 0x00, cap_mid, cap_id }, // CAP_AIM_VOICE { cap_aim, 0x13, 0x41, cap_mid, cap_id }, // CAP_AIM_SENDFILE { cap_aim, 0x13, 0x43, cap_mid, cap_id }, // CAP_DIRECT { cap_aim, 0x13, 0x44, cap_mid, cap_id }, // CAP_AIM_IMIMAGE { cap_aim, 0x13, 0x45, cap_mid, cap_id }, // CAP_AIM_BUDDYCON { cap_aim, 0x13, 0x46, cap_mid, cap_id }, // CAP_AIM_STOCKS { cap_aim, 0x13, 0x47, cap_mid, cap_id }, // CAP_AIM_GETFILE { cap_aim, 0x13, 0x48, cap_mid, cap_id }, // CAP_SRV_RELAY { cap_aim, 0x13, 0x49, cap_mid, cap_id }, // CAP_AIM_GAMES { cap_aim, 0x13, 0x4a, cap_mid, cap_id }, // CAP_AIM_BUDDYLIST { cap_aim, 0x13, 0x4b, cap_mid, cap_id }, // CAP_AVATAR { cap_aim, 0x13, 0x4c, cap_mid, cap_id }, // CAP_AIM_SUPPORT { cap_aim, 0x13, 0x4d, cap_mid, cap_id }, // CAP_UTF { cap_aim, 0x13, 0x4e, cap_mid, cap_id }, // CAP_RTF { 0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x92 }, // CAP_TYPING { 0x56, 0x3f, 0xc8, 0x09, 0x0b, 0x6f, 0x41, 0xbd, 0x9f, 0x79, 0x42, 0x26, 0x09, 0xdf, 0xa2, 0xf3 }, // CAP_SIM { 'S', 'I', 'M', ' ', 'c', 'l', 'i', 'e', 'n', 't', ' ', ' ', 0, 0, 0, 0 }, // CAP_STR_2001 { 0xa0, 0xe9, 0x3f, 0x37, cap_mstr, cap_str }, // CAP_STR_2002 { 0x10, 0xcf, 0x40, 0xd1, cap_mstr, cap_str }, // CAP_IS_2001 { 0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf, 0x4d, 0xc8, 0x88, 0x6f, 0xea, 0x35, 0x95, 0xfd, 0xb6, 0xdf }, // CAP_TRILLIAN { 0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x09 }, // CAP_TRIL_CRYPT { 0xf2, 0xe7, 0xc7, 0xf4, 0xfe, 0xad, 0x4d, 0xfb, 0xb2, 0x35, 0x36, 0x79, 0x8b, 0xdf, 0x00, 0x00 }, // CAP_MACICQ { 0xdd, 0x16, 0xf2, 0x02, 0x84, 0xe6, 0x11, 0xd4, 0x90, 0xdb, 0x00, 0x10, 0x4b, 0x9b, 0x4b, 0x7d }, // CAP_AIM_CHAT { 0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1, cap_id }, // CAP_MICQ { 'm', 'I', 'C', 'Q', ' ', (unsigned char)'©', 'R', '.', 'K', ' ', '.', ' ', 0, 0, 0, 0 }, // CAP_LICQ { 'L', 'i', 'c', 'q', ' ', 'c', 'l', 'i', 'e', 'n', 't', ' ', 0, 0, 0, 0 }, // CAP_SIMOLD { 0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x00 }, // CAP_KOPETE { 'K', 'o', 'p', 'e', 't', 'e', ' ', 'I', 'C', 'Q', ' ', ' ', 0, 0, 0, 0 }, // CAP_XTRAZ { 0x1A, 0x09, 0x3C, 0x6C, 0xD7, 0xFD, 0x4E, 0xC5, 0x9D, 0x51, 0xA6, 0x47, 0x4E, 0x34, 0xF5, 0xA0 }, // CAP_IS_2002 { 0x10, 0xcf, 0x40, 0xd1, cap_mid, cap_id }, // CAP_MIRANDA { 'M', 'i', 'r', 'a', 'n', 'd', 'a', 'M', cap_none }, // CAP_ANDRQ { '&', 'R', 'Q', 'i', 'n', 's', 'i', 'd', 'e', 0, 0, 0, 0, 0, 0, 0 }, // CAP_QIP { 0x56, 0x3f, 0xc8, 0x09, 0x0b, 0x6f, 0x41, 'Q', 'I', 'P', ' ', '2', '0', '0', '5', 'a' }, // CAP_IMSECURE { 'I', 'M', 's', 'e', 'c', 'u', 'r', 'e', 'C', 'p', 'h', 'r', 0, 0, 0, 0 }, // CAP_KXICQ { 0x09, 0x49, 0x13, 0x44, cap_mid, cap_id }, // CAP_ICQ5_1 { 0xe3, 0x62, 0xc1, 0xe9, 0x12, 0x1a, 0x4b, 0x94, 0xa6, 0x26, 0x7a, 0x74, 0xde, 0x24, 0x27, 0x0d }, // CAP_UNKNOWN - used by Trillian and some ICQ 5 clients { 0x17, 0x8c, 0x2d, 0x9b, 0xda, 0xa5, 0x45, 0xbb, 0x8d, 0xdb, 0xf3, 0xbd, 0xbd, 0x53, 0xa1, 0x0a }, // CAP_ICQ5_3 { 0x67, 0x36, 0x15, 0x15, 0x61, 0x2d, 0x4c, 0x07, 0x8f, 0x3d, 0xbd, 0xe6, 0x40, 0x8e, 0xa0, 0x41 }, // CAP_ICQ5_4 { 0xb9, 0x97, 0x08, 0xb5, 0x3a, 0x92, 0x42, 0x02, 0xb0, 0x69, 0xf1, 0xe7, 0x57, 0xbb, 0x2e, 0x17 }, // CAP_ICQ51 { 0xb2, 0xec, 0x8f, 0x16, 0x7c, 0x6f, 0x45, 0x1b, 0xbd, 0x79, 0xdc, 0x58, 0x49, 0x78, 0x88, 0xb9 }, // CAP_JIMM { 'J', 'i', 'm', 'm', ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, //CAP_ICQJP {'i', 'c', 'q', 'p', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /*/* // from Gaim: // CAP_AIM_HIPTOP { cap_aim, 0x13, 0x23, cap_mid, cap_id }, // CAP_AIM_SECUREIM { cap_aim, 0x00, 0x01, cap_mid, cap_id }, // CAP_AIM_VIDEO { cap_aim, 0x01, 0x00, cap_mid, cap_id }, // CAP_AIM_LIVEVIDEO { cap_aim, 0x01, 0x01, cap_mid, cap_id }, // CAP_AIM_CAMERA { cap_aim, 0x01, 0x02, cap_mid, cap_id }, // CAP_AIM_ICHATAV { cap_aim, 0x01, 0x05, cap_mid, cap_id }, // CAP_AIM_SMS { cap_aim, 0x01, 0xff, cap_mid, cap_id }, // unknown { cap_aim, 0xf0, 0x03, cap_mid, cap_id }, { cap_aim, 0xf0, 0x05, cap_mid, cap_id }, // from http://community.livejournal.com/oscardoc/12366.html: // HasMicrophone { cap_aim, 0x01, 0x03, cap_mid, cap_id }, // RtcAudio { cap_aim, 0x01, 0x04, cap_mid, cap_id }, // Aca { cap_aim, 0x01, 0x06, cap_mid, cap_id }, // MultiAudio { cap_aim, 0x01, 0x07, cap_mid, cap_id }, // MultiVideo { cap_aim, 0x01, 0x08, cap_mid, cap_id }, // Viceroy { cap_aim, 0xf0, 0x04, cap_mid, cap_id }, // unknown QIP caps: { 0xd3, 0xd4, 0x53, 0x19, 0x8b, 0x32, 0x40, 0x3b, 0xac, 0xc7, 0xd1, 0xa9, 0xe2, 0xb5, 0x81, 0x3e }, { 0x78, 0x5e, 0x8c, 0x48, 0x40, 0xd3, 0x4c, 0x65, 0x88, 0x6f, 0x04, 0xcf, 0x3f, 0x3f, 0x43, 0xdf }, { 0xe6, 0x01, 0xe4, 0x1c, 0x33, 0x73, 0x4b, 0xd1, 0xbc, 0x06, 0x81, 0x1d, 0x6c, 0x32, 0x3d, 0x81 }, { 0x61, 0xbe, 0xe0, 0xdd, 0x8b, 0xdd, 0x47, 0x5d, 0x8d, 0xee, 0x5f, 0x4b, 0xaa, 0xcf, 0x19, 0xa7 }, // from mICQ: { 0x17, 0x8c, 0x2d, 0x9b, 0xda, 0xa5, 0x45, 0xbb, 0x8d, 0xdb, 0xf3, 0xbd, 0xbd, 0x53, 0xa1, 0x0a }, { 0x67, 0x36, 0x15, 0x15, 0x61, 0x2d, 0x4c, 0x07, 0x8f, 0x3d, 0xbd, 0xe6, 0x40, 0x8e, 0xa0, 0x41 }, { 0xe3, 0x62, 0xc1, 0xe9, 0x12, 0x1a, 0x4b, 0x94, 0xa6, 0x26, 0x7a, 0x74, 0xde, 0x24, 0x27, 0x0d }, { 0xb9, 0x97, 0x08, 0xb5, 0x3a, 0x92, 0x42, 0x02, 0xb0, 0x69, 0xf1, 0xe7, 0x57, 0xbb, 0x2e, 0x17 }, { 0xb6, 0x07, 0x43, 0x78, 0xf5, 0x0c, 0x4a, 0xc7, 0x90, 0x92, 0x59, 0x38, 0x50, 0x2d, 0x05, 0x91 }, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x19, 0x04, 0x4a, 0x16, 0xed, 0x79, 0x2c, 0xb1, 0x71, 0x01 }, { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0xb3, 0xf8, 0x53, 0x44, 0x7f, 0x0d, 0x2d, 0x83, 0xbd, 0x76 }, */ // CAP_NULL { cap_none, cap_none }, }; const capability *ICQClient::capabilities = arrCapabilities; #ifndef VERSION #define VERSION "0.1" #endif static unsigned char get_ver(const char *&v) { if (v == NULL) return 0; char c = (char)atol(v); v = strchr(v, '.'); if (v) v++; return c; } static bool isWide(const QString &str) { for (int i = 0; i < (int)(str.length()); i++) if (str[i].unicode() > 0x7F) return true; return true; } static inline bool isWide(const SIM::Data &data) { return isWide(data.str()); } void ICQClient::encodeString(const QString &str, unsigned short nTlv, bool bWide) { if (str.isEmpty()){ socket()->writeBuffer().tlv(nTlv, QString::null); return; } QString m = str; if (bWide){ unsigned short *unicode = new unsigned short[m.length()]; unsigned short *t = unicode; for (int i = 0; i < (int)(m.length()); i++) *(t++) = htons(m[i].unicode()); socket()->writeBuffer().tlv(nTlv, (char*)unicode, (unsigned short)(m.length() * sizeof(unsigned short))); delete[] unicode; }else{ socket()->writeBuffer().tlv(nTlv, m.latin1()); } } void ICQClient::encodeString(const QString &m, const QString &type, unsigned short charsetTlv, unsigned short infoTlv) { bool bWide = isWide(m); QString content_type = type + "; charset=\""; if (bWide){ unsigned short *unicode = new unsigned short[m.length()]; unsigned short *t = unicode; for (int i = 0; i < (int)(m.length()); i++) *(t++) = htons(m[i].unicode()); content_type += "unicode-2\""; socket()->writeBuffer().tlv(charsetTlv, content_type); socket()->writeBuffer().tlv(infoTlv, (char*)unicode, (unsigned short)(m.length() * sizeof(unsigned short))); delete[] unicode; }else{ content_type += "us-ascii\""; socket()->writeBuffer().tlv(charsetTlv, content_type); socket()->writeBuffer().tlv(infoTlv, m.latin1()); } } void ICQClient::addCapability(ICQBuffer &cap, cap_id_t id) { cap.pack((char*)capabilities[id], sizeof(capability)); } void ICQClient::sendCapability(const QString &away_msg) { ICQBuffer cap; capability c; memcpy(c, capabilities[CAP_SIM], sizeof(c)); const char *ver = VERSION; unsigned char *pack_ver = c + sizeof(capability) - 4; *(pack_ver++) = get_ver(ver); *(pack_ver++) = get_ver(ver); *(pack_ver++) = get_ver(ver); unsigned char os_ver; #ifdef WIN32 os_ver = 0x80; #else #ifdef QT_MACOSX_VERSION os_ver = 0x40; #else os_ver = 0; #endif #endif *(pack_ver++) = os_ver | get_ver(ver); addCapability(cap, CAP_AIM_SHORTCAPS); addCapability(cap, CAP_AIM_SUPPORT); addCapability(cap, CAP_AVATAR); if (m_bAIM){ addCapability(cap, CAP_AIM_CHAT); addCapability(cap, CAP_AIM_BUDDYCON); addCapability(cap, CAP_AIM_IMIMAGE); addCapability(cap, CAP_AIM_SENDFILE); addCapability(cap, CAP_AIM_BUDDYLIST); }else{ addCapability(cap, CAP_DIRECT); addCapability(cap, CAP_SRV_RELAY); addCapability(cap, CAP_XTRAZ); if (getSendFormat() <= 1) addCapability(cap, CAP_UTF); if (getSendFormat() == 0) addCapability(cap, CAP_RTF); } if (!getDisableTypingNotification()) cap.pack((char*)capabilities[CAP_TYPING], sizeof(capability)); cap.pack((char*)c, sizeof(c)); snac(ICQ_SNACxFAM_LOCATION, ICQ_SNACxLOC_SETxUSERxINFO); if (m_bAIM){ if (data.owner.ProfileFetch.toBool()){ QString profile; profile = QString("") + data.owner.About.str() + ""; encodeString(profile, "text/aolrtf", 1, 2); } if (!away_msg.isNull()) encodeString(away_msg, "text/plain", 3, 4); } socket()->writeBuffer().tlv(0x0005, cap); if (m_bAIM) socket()->writeBuffer().tlv(0x0006, "\x00\x04\x00\x02\x00\x02", 6); sendPacket(true); } void ICQClient::setAwayMessage(const QString &msg) { snac(ICQ_SNACxFAM_LOCATION, ICQ_SNACxLOC_SETxUSERxINFO); if (!msg.isNull()){ encodeString(msg, "text/plain", 3, 4); }else{ socket()->writeBuffer().tlv(0x0004); } sendPacket(true); } void ICQClient::fetchProfile(ICQUserData *data) { snac(ICQ_SNACxFAM_LOCATION, ICQ_SNACxLOC_REQUESTxUSERxINFO, true); socket()->writeBuffer() << (unsigned short)0x0001; socket()->writeBuffer().packScreen(screen(data)); sendPacket(false); snac(ICQ_SNACxFAM_LOCATION, ICQ_SNACxLOC_REQUESTxDIRxINFO, true); socket()->writeBuffer().packScreen(screen(data)); sendPacket(false); m_info_req.insert(INFO_REQ_MAP::value_type(m_nMsgSequence, screen(data))); data->ProfileFetch.setBool(true); } void ICQClient::fetchProfiles() { if (!data.owner.ProfileFetch.toBool()) fetchProfile(&data.owner); Contact *contact; ContactList::ContactIterator itc; while ((contact = ++itc) != NULL){ ICQUserData *data; ClientDataIterator itd(contact->clientData, this); while ((data = (ICQUserData*)(++itd)) != NULL){ if (data->Uin.toULong() || data->ProfileFetch.toBool()) continue; fetchProfile(data); } } } ICQUserData *ICQClient::findInfoRequest(unsigned short seq, Contact *&contact) { INFO_REQ_MAP::iterator it = m_info_req.find(seq); if (it == m_info_req.end()){ log(L_WARN, "Info req %u not found", seq); return NULL; } QString screen = (*it).second; m_info_req.erase(it); return findContact(screen, NULL, false, contact); } void ICQClient::setAIMInfo(ICQUserData *data) { if (getState() != Connected) return; bool bWide = isWide(data->FirstName) || isWide(data->LastName) || isWide(data->MiddleName) || isWide(data->Maiden) || isWide(data->Nick) || isWide(data->Zip) || isWide(data->Address) || isWide(data->City); QString country; for (const ext_info *e = getCountryCodes(); e->szName; e++){ if (e->nCode == data->Country.toULong()){ country = e->szName; break; } } snac(ICQ_SNACxFAM_LOCATION, ICQ_SNACxLOC_SETxDIRxINFO); QString encoding = bWide ? "unicode-2-0" : "us-ascii"; socket()->writeBuffer().tlv(0x1C, encoding); socket()->writeBuffer().tlv(0x0A, (unsigned short)0x01); encodeString(data->FirstName.str(), 0x01, bWide); encodeString(data->LastName.str(), 0x02, bWide); encodeString(data->MiddleName.str(), 0x03, bWide); encodeString(data->Maiden.str(), 0x04, bWide); encodeString(country, 0x06, bWide); encodeString(data->Address.str(), 0x07, bWide); encodeString(data->City.str(), 0x08, bWide); encodeString(data->Nick.str(), 0x0C, bWide); encodeString(data->Zip.str(), 0x0D, bWide); encodeString(data->State.str(), 0x21, bWide); sendPacket(false); ICQUserData *ownerData = &this->data.owner; ownerData->FirstName.str() = data->FirstName.str(); ownerData->LastName.str() = data->LastName.str(); ownerData->MiddleName.str() = data->MiddleName.str(); ownerData->Maiden.str() = data->Maiden.str(); ownerData->Address.str() = data->Address.str(); ownerData->City.str() = data->City.str(); ownerData->Nick.str() = data->Nick.str(); ownerData->Zip.str() = data->Zip.str(); ownerData->State.str() = data->State.str(); ownerData->Country.asULong() = data->Country.toULong(); } void ICQClient::setProfile(ICQUserData *data) { snac(ICQ_SNACxFAM_LOCATION, ICQ_SNACxLOC_SETxUSERxINFO); QString profile; profile = QString("") + data->About.str() + ""; encodeString(profile, "text/aolrtf", 1, 2); sendPacket(false); }