/*************************************************************************** jabber_rosters.cpp - description ------------------- begin : Sun Mar 17 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 "jabberclient.h" #include "jabber.h" #include "jabbermessage.h" #include "html.h" #include "core.h" #include #ifdef WIN32 #include #else #include #include #include #include #include #endif #include #include class RostersRequest : public JabberClient::ServerRequest { public: RostersRequest(JabberClient *client); ~RostersRequest(); protected: virtual void element_start(const char *el, const char **attr); virtual void element_end(const char *el); virtual void char_data(const char *str, int len); string m_jid; string m_name; string m_grp; string m_subscription; unsigned m_subscribe; unsigned m_bSubscription; string *m_data; }; RostersRequest::RostersRequest(JabberClient *client) : JabberClient::ServerRequest(client, _GET, NULL, NULL) { m_data = NULL; ContactList::ContactIterator itc; Contact *contact; while ((contact = ++itc) != NULL){ ClientDataIterator it(contact->clientData, client); JabberUserData *data; while ((data = (JabberUserData*)(++it)) != NULL) data->bChecked.bValue = false; } client->m_bJoin = false; } RostersRequest::~RostersRequest() { ContactList::ContactIterator itc; Contact *contact; list contactRemoved; while ((contact = ++itc) != NULL){ ClientDataIterator it(contact->clientData, m_client); JabberUserData *data; list dataRemoved; while ((data = (JabberUserData*)(++it)) != NULL){ if (!data->bChecked.bValue){ string jid; jid = data->ID.ptr; JabberListRequest *lr = m_client->findRequest(jid.c_str(), false); if (lr && lr->bDelete) m_client->findRequest(jid.c_str(), true); dataRemoved.push_back(data); } } if (dataRemoved.empty()) continue; for (list::iterator itr = dataRemoved.begin(); itr != dataRemoved.end(); ++itr) contact->clientData.freeData(*itr); if (contact->clientData.size() == 0) contactRemoved.push_back(contact); } for (list::iterator itr = contactRemoved.begin(); itr != contactRemoved.end(); ++itr) delete *itr; m_client->processList(); if (m_client->m_bJoin){ Event e(EventJoinAlert, m_client); e.process(); } } void RostersRequest::element_start(const char *el, const char **attr) { if (strcmp(el, "item") == 0){ m_subscribe = SUBSCRIBE_NONE; m_grp = ""; m_jid = JabberClient::get_attr("jid", attr); if (m_jid.length() == 0) return; m_name = JabberClient::get_attr("name", attr); m_subscription = ""; m_bSubscription = false; string subscribe = JabberClient::get_attr("subscription", attr); if (subscribe == "none"){ m_subscribe = SUBSCRIBE_NONE; }else if (subscribe == "from"){ m_subscribe = SUBSCRIBE_FROM; }else if (subscribe == "to"){ m_subscribe = SUBSCRIBE_TO; }else if (subscribe == "both"){ m_subscribe = SUBSCRIBE_BOTH; }else{ log(L_WARN, "Unknown attr subscribe=%s", subscribe.c_str()); } return; } if (strcmp(el, "group") == 0){ m_grp = ""; m_data = &m_grp; return; } if (strcmp(el, "subscription") == 0){ m_bSubscription = true; m_subscription = ""; m_data = &m_subscription; return; } } void RostersRequest::element_end(const char *el) { if (strcmp(el, "group") == 0){ m_data = NULL; return; } if (strcmp(el, "item") == 0){ bool bChanged = false; JabberListRequest *lr = m_client->findRequest(m_jid.c_str(), false); Contact *contact; string resource; JabberUserData *data = m_client->findContact(m_jid.c_str(), m_name.c_str(), false, contact, resource); if (data == NULL){ if (lr && lr->bDelete){ m_client->findRequest(m_jid.c_str(), true); }else{ bChanged = true; string resource; data = m_client->findContact(m_jid.c_str(), m_name.c_str(), true, contact, resource); if (m_bSubscription){ contact->setFlags(CONTACT_TEMP); Event eContact(EventContactChanged, contact); eContact.process(); m_client->auth_request(m_jid.c_str(), MessageAuthRequest, m_subscription.c_str(), true); data = m_client->findContact(m_jid.c_str(), m_name.c_str(), false, contact, resource); } } } if (data == NULL) return; if (data->Subscribe.value != m_subscribe){ bChanged = true; data->Subscribe.value = m_subscribe; } set_str(&data->Group.ptr, m_grp.c_str()); data->bChecked.bValue = true; if (lr == NULL){ unsigned grp = 0; if (!m_grp.empty()){ Group *group = NULL; ContactList::GroupIterator it; while ((group = ++it) != NULL){ if (m_grp == (const char*)(group->getName().utf8())){ grp = group->id(); break; } } if (group == NULL){ group = getContacts()->group(0, true); group->setName(QString::fromUtf8(m_grp.c_str())); grp = group->id(); Event e(EventGroupChanged, group); e.process(); } } if (contact->getGroup() != grp){ if (grp == 0){ void *d = NULL; ClientDataIterator it_d(contact->clientData); while ((d = ++it_d) != NULL){ if (d != data) break; } if (d){ grp = contact->getGroup(); Group *group = getContacts()->group(grp); if (group) m_client->listRequest(data, contact->getName().utf8(), group->getName().utf8(), false); } } contact->setGroup(grp); bChanged = true; } } if (bChanged){ Event e(EventContactChanged, contact); e.process(); } } } void RostersRequest::char_data(const char *str, int len) { if (m_data == NULL) return; m_data->append(str, len); } void JabberClient::rosters_request() { RostersRequest *req = new RostersRequest(this); req->start_element("query"); req->add_attribute("xmlns", "jabber:iq:roster"); req->send(); m_requests.push_back(req); } class InfoRequest : public JabberClient::ServerRequest { public: InfoRequest(JabberClient *client, JabberUserData *data, bool bVCard); ~InfoRequest(); protected: virtual void element_start(const char *el, const char **attr); virtual void element_end(const char *el); virtual void char_data(const char *str, int len); string m_jid; string m_node; string m_host; bool m_bStarted; string m_firstName; string m_nick; string m_desc; string m_email; string m_bday; string m_url; string m_orgName; string m_orgUnit; string m_title; string m_role; string m_phone; string m_street; string m_ext; string m_city; string m_region; string m_pcode; string m_country; string *m_data; Buffer m_photo; Buffer m_logo; Buffer *m_cdata; bool m_bPhoto; bool m_bLogo; bool m_bVCard; }; extern DataDef jabberUserData[]; InfoRequest::InfoRequest(JabberClient *client, JabberUserData *data, bool bVCard) : JabberClient::ServerRequest(client, _GET, NULL, client->buildId(data).c_str()) { m_jid = data->ID.ptr; if (data->Node.ptr) m_node = data->Node.ptr; m_bStarted = false; m_data = NULL; m_cdata = NULL; m_bPhoto = false; m_bLogo = false; m_bVCard = bVCard; } InfoRequest::~InfoRequest() { if (m_bStarted){ Contact *contact = NULL; JabberUserData *data; JabberUserData u_data; if (m_bVCard){ load_data(jabberUserData, &u_data, NULL); data = &u_data; set_str(&data->ID.ptr, m_jid.c_str()); set_str(&data->Node.ptr, m_node.c_str()); }else{ if (m_jid == m_client->data.owner.ID.ptr){ data = &m_client->data.owner; }else{ string jid = m_jid; if (strchr(jid.c_str(), '@') == NULL){ jid += "@"; jid += m_host; } string resource; data = m_client->findContact(m_jid.c_str(), NULL, false, contact, resource); if (data == NULL) return; } } bool bChanged = false; bChanged |= set_str(&data->FirstName.ptr, m_firstName.c_str()); bChanged |= set_str(&data->Nick.ptr, m_nick.c_str()); bChanged |= set_str(&data->Desc.ptr, m_desc.c_str()); bChanged |= set_str(&data->Bday.ptr, m_bday.c_str()); bChanged |= set_str(&data->Url.ptr, m_url.c_str()); bChanged |= set_str(&data->OrgName.ptr, m_orgName.c_str()); bChanged |= set_str(&data->OrgUnit.ptr, m_orgUnit.c_str()); bChanged |= set_str(&data->Title.ptr, m_title.c_str()); bChanged |= set_str(&data->Role.ptr, m_role.c_str()); bChanged |= set_str(&data->Street.ptr, m_street.c_str()); bChanged |= set_str(&data->ExtAddr.ptr, m_ext.c_str()); bChanged |= set_str(&data->City.ptr, m_city.c_str()); bChanged |= set_str(&data->Region.ptr, m_region.c_str()); bChanged |= set_str(&data->PCode.ptr, m_pcode.c_str()); bChanged |= set_str(&data->Country.ptr, m_country.c_str()); bChanged |= set_str(&data->EMail.ptr, m_email.c_str()); bChanged |= set_str(&data->Phone.ptr, m_phone.c_str()); if (m_bVCard){ Event e(EventVCard, data); e.process(); free_data(jabberUserData, &u_data); return; } QImage photo; if (m_photo.size()){ Buffer unpack; unpack.fromBase64(m_photo); QString fName = m_client->photoFile(data); QFile f(fName); if (f.open(IO_WriteOnly | IO_Truncate)){ f.writeBlock(unpack.data(), unpack.size()); f.close(); photo.load(fName); }else{ log(L_ERROR, "Can't create %s", (const char*)fName.local8Bit()); } } if (photo.width() && photo.height()){ if ((photo.width() != (int)(data->PhotoWidth.value)) || (photo.height() != (int)(data->PhotoHeight.value))) bChanged = true; data->PhotoWidth.value = photo.width(); data->PhotoHeight.value = photo.height(); if (m_jid == m_client->data.owner.ID.ptr) m_client->setPhoto(m_client->photoFile(data)); }else{ if (data->PhotoWidth.value || data->PhotoHeight.value) bChanged = true; data->PhotoWidth.value = 0; data->PhotoHeight.value = 0; } QImage logo; if (m_logo.size()){ Buffer unpack; unpack.fromBase64(m_logo); QString fName = m_client->logoFile(data); QFile f(fName); if (f.open(IO_WriteOnly | IO_Truncate)){ f.writeBlock(unpack.data(), unpack.size()); f.close(); logo.load(fName); }else{ log(L_ERROR, "Can't create %s", (const char*)fName.local8Bit()); } } if (logo.width() && logo.height()){ if ((logo.width() != (int)(data->LogoWidth.value)) || (logo.height() != (int)(data->LogoHeight.value))) bChanged = true; data->LogoWidth.value = logo.width(); data->LogoHeight.value = logo.height(); if (m_jid == m_client->data.owner.ID.ptr) m_client->setLogo(m_client->logoFile(data)); }else{ if (data->LogoWidth.value || data->LogoHeight.value) bChanged = true; data->LogoWidth.value = 0; data->LogoHeight.value = 0; } if (bChanged){ if (contact){ m_client->setupContact(contact, data); Event e(EventContactChanged, (Client*)contact); e.process(); }else{ Event e(EventClientChanged, (Client*)m_client); e.process(); } } } } void JabberClient::setupContact(Contact *contact, void *_data) { JabberUserData *data = (JabberUserData*)_data; QString mail; if (data->EMail.ptr && *data->EMail.ptr) mail = QString::fromUtf8(data->EMail.ptr); contact->setEMails(mail, name().c_str()); QString phones; if (data->Phone.ptr && *data->Phone.ptr){ phones = QString::fromUtf8(data->Phone.ptr); phones += ",Home Phone,"; phones += number(PHONE).c_str(); } contact->setPhones(phones, name().c_str()); if (contact->getFirstName().isEmpty() && data->FirstName.ptr && *data->FirstName.ptr) contact->setFirstName(QString::fromUtf8(data->FirstName.ptr), name().c_str()); if (contact->getName().isEmpty()) contact->setName(QString::fromUtf8(data->ID.ptr)); } void InfoRequest::element_start(const char *el, const char**) { m_data = NULL; if (!strcmp(el, "vcard")){ m_bStarted = true; return; } if (!strcmp(el, "nickname")){ m_data = &m_nick; return; } if (!strcmp(el, "fn")){ m_data = &m_firstName; return; } if (!strcmp(el, "desc")){ m_data = &m_desc; return; } if (!strcmp(el, "email")){ m_data = &m_email; return; } if (!strcmp(el, "bday")){ m_data = &m_bday; return; } if (!strcmp(el, "url")){ m_data = &m_url; return; } if (!strcmp(el, "orgname")){ m_data = &m_orgName; return; } if (!strcmp(el, "orgunit")){ m_data = &m_orgUnit; return; } if (!strcmp(el, "title")){ m_data = &m_title; return; } if (!strcmp(el, "role")){ m_data = &m_role; return; } if (!strcmp(el, "voice")){ m_data = &m_phone; return; } if (!strcmp(el, "street")){ m_data = &m_street; return; } if (!strcmp(el, "extadd")){ m_data = &m_ext; return; } if (!strcmp(el, "city")){ m_data = &m_city; return; } if (!strcmp(el, "region")){ m_data = &m_region; return; } if (!strcmp(el, "pcode")){ m_data = &m_pcode; return; } if (!strcmp(el, "country")){ m_data = &m_country; return; } if (!strcmp(el, "photo")){ m_bPhoto = true; return; } if (!strcmp(el, "logo")){ m_bLogo = true; return; } if (!strcmp(el, "binval")){ if (m_bPhoto) m_cdata = &m_photo; if (m_bLogo) m_cdata = &m_logo; } } void InfoRequest::element_end(const char *el) { m_data = NULL; m_cdata = NULL; if (!strcmp(el, "photo")){ m_bPhoto = false; return; } if (!strcmp(el, "logo")){ m_bLogo = false; return; } } void InfoRequest::char_data(const char *str, int len) { if (m_cdata){ m_cdata->pack(str, len); return; } if (m_data) m_data->append(str, len); } void JabberClient::info_request(JabberUserData *user_data, bool bVCard) { if (getState() != Connected) return; if (user_data == NULL) user_data = &data.owner; InfoRequest *req = new InfoRequest(this, user_data, bVCard); req->start_element("vCard"); req->add_attribute("prodid", "-//HandGen//NONSGML vGen v1.0//EN"); req->add_attribute("xmlns", "vcard-temp"); req->add_attribute("version", "2.0"); if (user_data->Node.ptr && *user_data->Node.ptr) req->add_attribute("node", user_data->Node.ptr); req->send(); m_requests.push_back(req); } class SetInfoRequest : public JabberClient::ServerRequest { public: SetInfoRequest(JabberClient *client, JabberUserData *data); protected: virtual void element_start(const char *el, const char **attr); }; SetInfoRequest::SetInfoRequest(JabberClient *client, JabberUserData *data) : JabberClient::ServerRequest(client, _SET, NULL, client->buildId(data).c_str()) { } void SetInfoRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "iq")){ string type = JabberClient::get_attr("type", attr); if (type == "result") m_client->setInfoUpdated(false); } } void JabberClient::setClientInfo(void *_data) { JabberUserData *data = (JabberUserData*)_data; if (data != &this->data.owner){ set_str(&this->data.owner.FirstName.ptr, data->FirstName.ptr); set_str(&this->data.owner.Nick.ptr, data->Nick.ptr); set_str(&this->data.owner.Desc.ptr, data->Desc.ptr); set_str(&this->data.owner.Bday.ptr, data->Bday.ptr); set_str(&this->data.owner.Url.ptr, data->Url.ptr); set_str(&this->data.owner.OrgName.ptr, data->OrgName.ptr); set_str(&this->data.owner.OrgUnit.ptr, data->OrgUnit.ptr); set_str(&this->data.owner.Title.ptr, data->Title.ptr); set_str(&this->data.owner.Role.ptr, data->Role.ptr); set_str(&this->data.owner.Street.ptr, data->Street.ptr); set_str(&this->data.owner.ExtAddr.ptr, data->ExtAddr.ptr); set_str(&this->data.owner.City.ptr, data->City.ptr); set_str(&this->data.owner.Region.ptr, data->Region.ptr); set_str(&this->data.owner.PCode.ptr, data->PCode.ptr); set_str(&this->data.owner.Country.ptr, data->Country.ptr); } setInfoUpdated(true); if (getState() != Connected) return; SetInfoRequest *req = new SetInfoRequest(this, &this->data.owner); req->start_element("vCard"); req->add_attribute("prodid", "-//HandGen//NONSGML vGen v1.0//EN"); req->add_attribute("xmlns", "vcard-temp"); req->add_attribute("version", "2.0"); if (data->Node.ptr && *data->Node.ptr) req->add_attribute("node", data->Node.ptr); req->text_tag("FN", data->FirstName.ptr); req->text_tag("NICKNAME", data->Nick.ptr); req->text_tag("DESC", data->Desc.ptr); QString mails = getContacts()->owner()->getEMails(); while (mails.length()){ QString mailItem = getToken(mails, ';', false); QString mail = getToken(mailItem, '/'); if (mailItem.length()) continue; req->text_tag("EMAIL", mail.utf8()); break; } req->text_tag("BDAY", data->Bday.ptr); req->text_tag("URL", data->Url.ptr); req->start_element("ORG"); req->text_tag("ORGNAME", data->OrgName.ptr); req->text_tag("ORGUNIT", data->OrgUnit.ptr); req->end_element(); req->text_tag("TITLE", data->Title.ptr); req->text_tag("ROLE", data->Role.ptr); QString phone; QString phones = getContacts()->owner()->getPhones(); while (phones.length()){ QString phoneItem = getToken(phones, ';', false); QString phoneValue = getToken(phoneItem, '/', false); if (phoneItem.length()) continue; QString number = getToken(phoneValue, ','); QString type = getToken(phoneValue, ','); if (type == "Hone Phone"){ phone = number; break; } } if (phone.length()){ req->start_element("TEL"); req->start_element("HOME"); req->end_element(); req->text_tag("VOICE", phone); req->end_element(); } req->start_element("ADDR"); req->start_element("HOME"); req->end_element(); req->text_tag("STREET", data->Street.ptr); req->text_tag("EXTADD", data->ExtAddr.ptr); req->text_tag("LOCALITY", data->City.ptr); req->text_tag("REGION", data->Region.ptr); req->text_tag("PCODE", data->PCode.ptr); req->text_tag("COUNTRY", data->Country.ptr); req->end_element(); if (!getPhoto().isEmpty()){ QFile img(getPhoto()); if (img.open(IO_ReadOnly)){ Buffer b; b.init(img.size()); img.readBlock(b.data(), b.size()); Buffer packed; packed.toBase64(b); packed << (char)0; req->start_element("PHOTO"); req->text_tag("BINVAL", packed.data()); req->end_element(); } } if (!getLogo().isEmpty()){ QFile img(getLogo()); if (img.open(IO_ReadOnly)){ Buffer b; b.init(img.size()); img.readBlock(b.data(), b.size()); Buffer packed; packed.toBase64(b); packed << (char)0; req->start_element("LOGO"); req->text_tag("BINVAL", packed.data()); req->end_element(); } } req->send(); m_requests.push_back(req); } class AddRequest : public JabberClient::ServerRequest { public: AddRequest(JabberClient *client, const char *jid, unsigned grp); protected: virtual void element_start(const char *el, const char **attr); string m_jid; unsigned m_grp; }; AddRequest::AddRequest(JabberClient *client, const char *jid, unsigned grp) : JabberClient::ServerRequest(client, _SET, NULL, NULL) { m_jid = jid; m_grp = grp; } void AddRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "iq")){ string type = JabberClient::get_attr("type", attr); if (type == "result"){ Contact *contact; string resource; JabberUserData *data = m_client->findContact(m_jid.c_str(), NULL, true, contact, resource); if (data && (contact->getGroup() != m_grp)){ contact->setGroup(m_grp); Event e(EventContactChanged, contact); e.process(); } } } } bool JabberClient::add_contact(const char *jid, unsigned grp) { Contact *contact; string resource; if (findContact(jid, NULL, false, contact, resource)){ Event e(EventContactChanged, contact); e.process(); return false; } AddRequest *req = new AddRequest(this, jid, grp); req->start_element("query"); req->add_attribute("xmlns", "jabber:iq:roster"); req->start_element("item"); req->add_attribute("jid", jid); Group *g = NULL; if (grp) g = getContacts()->group(grp); if (g) req->text_tag("group", g->getName().utf8()); req->send(); m_requests.push_back(req); return true; } JabberClient::PresenceRequest::PresenceRequest(JabberClient *client) : ServerRequest(client, NULL, NULL, NULL) { } static unsigned get_number(string &s, unsigned digits) { if (s.length() < digits){ s = ""; return 0; } string p = s.substr(0, digits); s = s.substr(digits); return atol(p.c_str()); } static time_t fromDelay(const char *t) { string s = t; time_t now; time(&now); struct tm _tm = *localtime(&now); _tm.tm_year = get_number(s, 4) - 1900; _tm.tm_mon = get_number(s, 2) - 1; _tm.tm_mday = get_number(s, 2); get_number(s, 1); _tm.tm_hour = get_number(s, 2); get_number(s, 1); _tm.tm_min = get_number(s, 2); get_number(s, 1); _tm.tm_sec = get_number(s, 2); return mktime(&_tm); } JabberClient::PresenceRequest::~PresenceRequest() { unsigned status = STATUS_UNKNOWN; bool bInvisible = false; // RFC 3921 "XMPP IM": 2.2.1. Types of Presence 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){ // RFC 3921 "XMPP IM": 2.2.2.1. Show 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()){ // RFC 3921 "XMPP IM": 2.2.2.2. Status 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 == "Invisible"){ status = STATUS_ONLINE; bInvisible = true; }else if (!m_status.empty()){ status = STATUS_ONLINE; } }else{ log(L_DEBUG, "Unsupported available status %s", m_show.c_str()); } }else{ log(L_DEBUG, "Unsupported presence type %s", m_type.c_str()); } time_t now; time(&now); time_t time1 = now; time_t time2 = 0; if (!m_stamp1.empty()) time1 = fromDelay(m_stamp1.c_str()); if (!m_stamp2.empty()){ time2 = fromDelay(m_stamp2.c_str()); if (time2 > time1){ time_t t = time1; time1 = time2; time2 = t; } } if (status != STATUS_UNKNOWN){ Contact *contact; string resource; JabberUserData *data = m_client->findContact(m_from.c_str(), NULL, false, contact, resource); if (data){ unsigned i; for (i = 1; i <= data->nResources.value; i++){ if (resource == get_str(data->Resources, i)) break; } bool bChanged = false; if (status == STATUS_OFFLINE){ if (i <= data->nResources.value){ bChanged = true; vector resources; vector resourceReply; vector resourceStatus; vector resourceStatusTime; vector resourceOnlineTime; vector resourceClientName; vector resourceClientVersion; vector resourceClientOS; for (unsigned n = 1; n <= data->nResources.value; n++){ if (i == n) continue; resources.push_back(get_str(data->Resources, n)); resourceReply.push_back(get_str(data->ResourceReply, n)); resourceStatus.push_back(get_str(data->ResourceStatus, n)); resourceStatusTime.push_back(get_str(data->ResourceStatusTime, n)); resourceOnlineTime.push_back(get_str(data->ResourceOnlineTime, n)); resourceClientName.push_back(get_str(data->ResourceClientName, n)); resourceClientVersion.push_back(get_str(data->ResourceClientVersion, n)); resourceClientOS.push_back(get_str(data->ResourceClientOS, n)); } clear_list(&data->Resources); clear_list(&data->ResourceReply); clear_list(&data->ResourceStatus); clear_list(&data->ResourceStatusTime); clear_list(&data->ResourceOnlineTime); clear_list(&data->ResourceClientName); clear_list(&data->ResourceClientVersion); clear_list(&data->ResourceClientOS); for (i = 0; i < resources.size(); i++){ set_str(&data->Resources, i + 1, resources[i].c_str()); set_str(&data->ResourceReply, i + 1, resourceReply[i].c_str()); set_str(&data->ResourceStatus, i + 1, resourceStatus[i].c_str()); set_str(&data->ResourceStatusTime, i + 1, resourceStatusTime[i].c_str()); set_str(&data->ResourceOnlineTime, i + 1, resourceOnlineTime[i].c_str()); set_str(&data->ResourceClientName, i + 1, resourceClientName[i].c_str()); set_str(&data->ResourceClientVersion, i + 1, resourceClientVersion[i].c_str()); set_str(&data->ResourceClientOS, i + 1, resourceClientOS[i].c_str()); } data->nResources.value = resources.size(); } if (data->nResources.value == 0) set_str(&data->AutoReply.ptr, m_status.c_str()); }else{ if (i > data->nResources.value){ bChanged = true; data->nResources.value = i; set_str(&data->Resources, i, resource.c_str()); set_str(&data->ResourceOnlineTime, i, number(time2 ? time2 : time1).c_str()); if (m_client->getUseVersion()) m_client->versionInfo(m_from.c_str()); } if (number(status) != get_str(data->ResourceStatus, i)){ bChanged = true; set_str(&data->ResourceStatus, i, number(status).c_str()); set_str(&data->ResourceStatusTime, i, number(time1).c_str()); } if (m_status != get_str(data->ResourceReply, i)){ bChanged = true; set_str(&data->ResourceReply, i, m_status.c_str()); } } bool bOnLine = false; status = STATUS_OFFLINE; for (i = 1; i <= data->nResources.value; i++){ unsigned rStatus = atol(get_str(data->ResourceStatus, i)); if (rStatus > status) status = rStatus; } if (data->Status.value != status){ bChanged = true; if ((status == STATUS_ONLINE) && (((int)(time1 - m_client->data.owner.OnlineTime.value) > 60) || (data->Status.value != STATUS_OFFLINE))) bOnLine = true; if (data->Status.value == STATUS_OFFLINE){ data->OnlineTime.value = time1; data->richText.bValue = true; } if (status == STATUS_OFFLINE && data->IsTyping.bValue){ data->IsTyping.bValue = false; Event e(EventContactStatus, contact); e.process(); } data->Status.value = status; data->StatusTime.value = time1; } if (data->invisible.bValue != bInvisible){ data->invisible.bValue = bInvisible; bChanged = true; } 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.ptr)){ Event e(EventContactOnline, contact); e.process(); } } } } void JabberClient::PresenceRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "presence")){ m_from = JabberClient::get_attr("from", attr); m_type = JabberClient::get_attr("type", attr); } if (!strcmp(el, "x")){ if (JabberClient::get_attr("xmlns", attr) == "jabber:x:delay"){ string stamp = JabberClient::get_attr("stamp", attr); if (!stamp.empty()){ if (m_stamp1.empty()){ m_stamp1 = stamp; }else if (m_stamp2.empty()){ m_stamp2 = stamp; } } } } m_data = ""; } void JabberClient::PresenceRequest::element_end(const char *el) { if (!strcmp(el, "show")){ m_show = m_data; }else if (!strcmp(el, "status")){ m_status = m_data; } } void JabberClient::PresenceRequest::char_data(const char *str, int len) { m_data.append(str, len); } JabberClient::IqRequest::IqRequest(JabberClient *client) : ServerRequest(client, NULL, NULL, NULL) { m_data = NULL; m_file_size = 0; } JabberClient::IqRequest::~IqRequest() { JabberFileMessage *msg = NULL; if (m_query == "jabber:iq:oob"){ string proto = m_url.substr(0, 7); if (proto != "http://"){ log(L_WARN, "Unknown protocol"); return; } m_url = m_url.substr(7); int n = m_url.find(':'); if (n < 0){ log(L_WARN, "Port not found"); return; } string host = m_url.substr(0, n); unsigned short port = (unsigned short)atol(m_url.c_str() + n + 1); n = m_url.find('/'); if (n < 0){ log(L_WARN, "File not found"); return; } string file = m_url.substr(n + 1); msg = new JabberFileMessage; msg->setDescription(QString::fromUtf8(file.c_str())); msg->setText(QString::fromUtf8(m_descr.c_str())); msg->setHost(host.c_str()); msg->setPort(port); }else if (!m_file_name.empty()){ msg = new JabberFileMessage; msg->setDescription(QString::fromUtf8(m_file_name.c_str())); msg->setSize(m_file_size); } if (msg){ Contact *contact; string resource; JabberUserData *data = m_client->findContact(m_from.c_str(), NULL, false, contact, resource); if (data == NULL){ string resource; data = m_client->findContact(m_from.c_str(), NULL, true, contact, resource); if (data == NULL) return; contact->setFlags(CONTACT_TEMP); } msg->setFrom(m_from.c_str()); msg->setID(m_id.c_str()); msg->setFlags(MESSAGE_RECEIVED | MESSAGE_TEMP); msg->setClient(m_client->dataName(data).c_str()); msg->setContact(contact->id()); m_client->m_ackMsg.push_back(msg); Event e(EventMessageReceived, msg); if (e.process()){ for (list::iterator it = m_client->m_ackMsg.begin(); it != m_client->m_ackMsg.end(); ++it){ if ((*it) == msg){ m_client->m_ackMsg.erase(it); break; } } } } } void JabberClient::IqRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "iq")){ m_from = JabberClient::get_attr("from", attr); m_id = JabberClient::get_attr("id", attr); m_type = JabberClient::get_attr("type", attr); return; } if (!strcmp(el, "query")){ m_query = JabberClient::get_attr("xmlns", attr); if (m_query == "jabber:iq:roster"){ if (!strcmp(el, "item")){ string jid = JabberClient::get_attr("jid", attr); string subscription = JabberClient::get_attr("subscription", attr); string name = JabberClient::get_attr("name", attr); if (!subscription.empty()){ unsigned subscribe = SUBSCRIBE_NONE; if (subscription == "none"){ subscribe = SUBSCRIBE_NONE; }else if (subscription == "to"){ subscribe = SUBSCRIBE_TO; }else if (subscription == "from"){ subscribe = SUBSCRIBE_FROM; }else if (subscription == "both"){ subscribe = SUBSCRIBE_BOTH; }else if (subscription == "remove"){ }else{ log(L_DEBUG, "Unknown value subscription=%s", subscription.c_str()); } Contact *contact; string resource; JabberUserData *data = m_client->findContact(jid.c_str(), name.c_str(), false, contact, resource); if ((data == NULL) && (subscribe != SUBSCRIBE_NONE)){ string resource; data = m_client->findContact(jid.c_str(), name.c_str(), true, contact, resource); } if (data && (data->Subscribe.value != subscribe)){ data->Subscribe.value = subscribe; Event e(EventContactChanged, contact); e.process(); if (m_client->getAutoSubscribe() && ((subscribe & SUBSCRIBE_FROM) == 0)){ AuthMessage *msg = new AuthMessage(MessageAuthRequest); msg->setContact(contact->id()); msg->setFlags(MESSAGE_NOHISTORY); m_client->send(msg, data); } } } } // XEP-0092: Software Version }else if (m_query == "jabber:iq:version"){ if (m_type == "get" && m_client->getUseVersion()){ // send our version JabberClient::ServerRequest *req = new JabberClient::ServerRequest(m_client, JabberClient::ServerRequest::_RESULT, NULL, m_from.c_str(), m_id.c_str()); req->start_element("query"); req->add_attribute("xmlns", "jabber:iq:version"); req->text_tag("name", PACKAGE); req->text_tag("version", VERSION); QString version = get_os_version(); req->text_tag("os", version); req->send(); m_client->m_requests.push_back(req); } } } if (!strcmp(el, "url")) m_data = &m_url; if (!strcmp(el, "desc")) m_data = &m_descr; if (!strcmp(el, "file")){ m_file_name = JabberClient::get_attr("name", attr); m_file_size = atol(JabberClient::get_attr("size", attr).c_str()); } } void JabberClient::IqRequest::element_end(const char*) { m_data = NULL; } void JabberClient::IqRequest::char_data(const char *data, int len) { if (m_data) m_data->append(data, len); } class JabberBgParser : public HTMLParser { public: JabberBgParser(); QString parse(const QString &text); unsigned bgColor; protected: virtual void text(const QString &text); virtual void tag_start(const QString &tag, const list &attrs); virtual void tag_end(const QString &tag); QString res; }; JabberBgParser::JabberBgParser() { bgColor = 0xFFFFFF; } QString JabberBgParser::parse(const QString &text) { res = ""; HTMLParser::parse(text); return res; } void JabberBgParser::text(const QString &text) { res += quoteString(text); } void JabberBgParser::tag_start(const QString &tag, const list &attrs) { if (tag == "body"){ for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ QString name = *it; ++it; QString value = *it; if (name.lower() == "bgcolor"){ QColor c(value); bgColor = c.rgb(); } } return; } res += "<"; res += tag; for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ QString name = *it; ++it; QString value = *it; res += " "; res += name; if (name == "style"){ list styles = parseStyle(value); for (list::iterator it = styles.begin(); it != styles.end(); ++it){ QString name = *it; ++it; QString value = *it; if (name == "background-color"){ QColor c; c.setNamedColor(value); bgColor = c.rgb() & 0xFFFFFF; } } } if (!value.isEmpty()){ res += "=\'"; res += quoteString(value); res += "\'"; } } res += ">"; } void JabberBgParser::tag_end(const QString &tag) { if (tag == "body"){ return; } res += ""; } JabberClient::MessageRequest::MessageRequest(JabberClient *client) : ServerRequest(client, NULL, NULL, NULL) { m_data = NULL; m_errorCode = 0; m_bBody = false; m_bCompose = false; m_bEvent = false; m_bRichText = false; m_bRosters = false; m_bError = false; } JabberClient::MessageRequest::~MessageRequest() { if (m_from.empty()) return; Contact *contact; string resource; JabberUserData *data = m_client->findContact(m_from.c_str(), NULL, false, contact, resource); if (data == NULL){ data = m_client->findContact(m_from.c_str(), NULL, true, contact, resource); if (data == NULL) return; contact->setFlags(CONTACT_TEMP); } Message *msg = NULL; if (!m_bError){ // JEP-0022 composing event handling if (m_bBody){ // Msg contains normal message. // here means "send me composing events, please", so we should do it. // But if that tag is absent, we must not send them. data->SendTypingEvents.bValue = m_bCompose; set_str(&data->TypingId.ptr, (m_bCompose ? m_id.c_str() : NULL)); // also, incoming message implicitly means that user has stopped typing if (data->IsTyping.bValue){ data->IsTyping.bValue = false; Event e(EventContactStatus, contact); e.process(); } } else{ // Msg has no body ==> it is event message. // Presence of here means "I'm typing", absence - "I'm not typing anymore". data->IsTyping.bValue = m_bCompose; Event e(EventContactStatus, contact); e.process(); } } if (m_errorCode || !m_error.empty()){ if (!m_bEvent){ JabberMessageError *m = new JabberMessageError; m->setError(QString::fromUtf8(m_error.c_str())); m->setCode(m_errorCode); msg = m; } }else if (m_bBody){ if (!m_contacts.empty()){ msg = new ContactsMessage; static_cast(msg)->setContacts(QString::fromUtf8(m_contacts.c_str())); }else if (m_subj.empty()){ msg = new Message(MessageGeneric); }else{ JabberMessage *m = new JabberMessage; m->setSubject(QString::fromUtf8(m_subj.c_str())); msg = m; } } if (msg == NULL) return; if (m_bBody && m_contacts.empty()){ if (m_richText.empty()){ data->richText.bValue = false; msg->setText(QString::fromUtf8(m_body.c_str())); }else{ JabberBgParser p; msg->setText(p.parse(QString::fromUtf8(m_richText.c_str()))); msg->setFlags(MESSAGE_RICHTEXT); msg->setBackground(p.bgColor); } if (m_targets.size()){ if ((msg->getFlags() & MESSAGE_RICHTEXT) == 0){ msg->setText(quoteString(msg->getText())); msg->setFlags(MESSAGE_RICHTEXT); } QString text = msg->getText(); for (unsigned i = 0; i < m_targets.size(); i++){ text += "
"; text += quoteString(QString::fromUtf8(m_descs[i].c_str())); text += ""; } } }else{ msg->setText(QString::fromUtf8(m_body.c_str())); } msg->setFlags(msg->getFlags() | MESSAGE_RECEIVED); msg->setClient(m_client->dataName(data).c_str()); msg->setContact(contact->id()); Event e(EventMessageReceived, msg); if (!e.process()) delete msg; } void JabberClient::MessageRequest::element_start(const char *el, const char **attr) { if (m_bRichText){ *m_data += "<"; *m_data += el; if (attr){ for (const char **p = attr; *p; ){ const char *key = *(p++); const char *val = *(p++); *m_data += " "; *m_data += key; *m_data += "=\'"; *m_data += val; *m_data += "\'"; } } *m_data += ">"; return; } m_data = NULL; if (!strcmp(el, "message")){ m_from = JabberClient::get_attr("from", attr); m_id = JabberClient::get_attr("id", attr); if (JabberClient::get_attr("type", attr) == "error") m_bError = true; return; } if (!strcmp(el, "body")){ m_data = &m_body; m_bBody = true; return; } if (!strcmp(el, "subject")){ m_data = &m_subj; return; } if (!strcmp(el, "error")){ m_errorCode = atol(JabberClient::get_attr("code", attr).c_str()); m_data = &m_error; return; } if (m_bEvent){ // Parsing tag, which contains JEP-0022 event info if (!strcmp(el, "composing")) m_bCompose = true; return; } if (!strcmp(el, "url-data")){ m_target = JabberClient::get_attr("target", attr); m_desc = ""; } if (!strcmp(el, "desc")){ m_data = &m_desc; return; } if (m_bRosters && !strcmp(el, "item")){ string jid = JabberClient::get_attr("jid", attr); string name = JabberClient::get_attr("name", attr); if (!jid.empty()){ if (!m_contacts.empty()) m_contacts += ";"; m_contacts += "jabber:"; m_contacts += jid; if (name.empty()){ int n = jid.find('@'); if (n >= 0){ name = jid.substr(0, n); }else{ name = jid; } } m_contacts += "/"; m_contacts += name; m_contacts += ","; m_contacts += name; m_contacts += " ("; m_contacts += jid; m_contacts += ")"; } } if (!strcmp(el, "x")){ if (JabberClient::get_attr("xmlns", attr) == "jabber:x:event") m_bEvent = true; if (JabberClient::get_attr("xmlns", attr) == "jabber:x:roster") m_bRosters = true; } if (!strcmp(el, "html")){ string xmlns = JabberClient::get_attr("xmlns", attr); if (xmlns == "http://jabber.org/protocol/xhtml-im"){ m_bRichText = true; m_data = &m_richText; } } } void JabberClient::MessageRequest::element_end(const char *el) { if (m_bRichText){ if (!strcmp(el, "html")){ m_bRichText = false; m_data = NULL; return; } *m_data += ""; return; } if (!strcmp(el, "x")) m_bRosters = false; if (!strcmp(el, "url-data")){ if (!m_target.empty()){ if (m_desc.empty()) m_desc = m_target; m_targets.push_back(m_target); m_descs.push_back(m_desc); } m_target = ""; m_desc = ""; } m_data = NULL; } void JabberClient::MessageRequest::char_data(const char *str, int len) { if (m_data) m_data->append(str, len); } class AgentRequest : public JabberClient::ServerRequest { public: AgentRequest(JabberClient *client, const char *jid); ~AgentRequest(); protected: JabberAgentsInfo data; string m_data; string m_jid; bool m_bError; virtual void element_start(const char *el, const char **attr); virtual void element_end(const char *el); virtual void char_data(const char *el, int len); }; class AgentsDiscoRequest : public JabberClient::ServerRequest { public: AgentsDiscoRequest(JabberClient *client); protected: virtual void element_start(const char *el, const char **attr); }; class AgentDiscoRequest : public JabberClient::ServerRequest { public: AgentDiscoRequest(JabberClient *client, const char *jid); ~AgentDiscoRequest(); protected: JabberAgentsInfo data; virtual void element_start(const char *el, const char **attr); bool m_bError; }; /* typedef struct JabberAgentsInfo { char *VHost; char *ID; char *Name; unsigned Search; unsigned Register; } JabberAgentsInfo; */ static DataDef jabberAgentsInfo[] = { { "", DATA_STRING, 1, 0 }, { "", DATA_STRING, 1, 0 }, { "", DATA_STRING, 1, 0 }, { "", DATA_BOOL, 1, 0 }, { "", DATA_BOOL, 1, 0 }, { "", DATA_ULONG, 1, 0 }, { NULL, 0, 0, 0 } }; AgentDiscoRequest::AgentDiscoRequest(JabberClient *client, const char *jid) : ServerRequest(client, _GET, NULL, jid) { load_data(jabberAgentsInfo, &data, NULL); set_str(&data.ID.ptr, jid); m_bError = false; } AgentDiscoRequest::~AgentDiscoRequest() { if (data.Name.ptr == NULL){ string jid = data.ID.ptr; int n = jid.find('.'); if (n > 0){ jid = jid.substr(0, n); set_str(&data.Name.ptr, jid.c_str()); } } if (m_bError){ data.Register.bValue = true; data.Search.bValue = true; } if (data.Name.ptr){ set_str(&data.VHost.ptr, m_client->VHost().c_str()); data.Client = m_client; Event e(EventAgentFound, &data); e.process(); } free_data(jabberAgentsInfo, &data); } void AgentDiscoRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "error")){ m_bError = true; return; } if (!strcmp(el, "identity")){ set_str(&data.Name.ptr, JabberClient::get_attr("name", attr).c_str()); return; } if (!strcmp(el, "feature")){ string s = JabberClient::get_attr("var", attr); if (s == "jabber:iq:register") data.Register.bValue = true; if (s == "jabber:iq:search") data.Search.bValue = true; } } AgentsDiscoRequest::AgentsDiscoRequest(JabberClient *client) : ServerRequest(client, _GET, NULL, client->VHost().c_str()) { } void AgentsDiscoRequest::element_start(const char *el, const char **attr) { if (strcmp(el, "item")) return; string jid = JabberClient::get_attr("jid", attr); if (!jid.empty()){ AgentDiscoRequest *req = new AgentDiscoRequest(m_client, jid.c_str()); req->start_element("query"); req->add_attribute("xmlns", "http://jabber.org/protocol/disco#info"); req->send(); m_client->m_requests.push_back(req); } } AgentRequest::AgentRequest(JabberClient *client, const char *jid) : ServerRequest(client, _GET, NULL, jid) { load_data(jabberAgentsInfo, &data, NULL); m_bError = false; m_jid = jid; } AgentRequest::~AgentRequest() { free_data(jabberAgentsInfo, &data); if (m_bError){ AgentsDiscoRequest *req = new AgentsDiscoRequest(m_client); req->start_element("query"); req->add_attribute("xmlns", "http://jabber.org/protocol/disco#items"); req->send(); m_client->m_requests.push_back(req); } } void AgentRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "agent")){ free_data(jabberAgentsInfo, &data); load_data(jabberAgentsInfo, &data, NULL); m_data = JabberClient::get_attr("jid", attr); set_str(&data.ID.ptr, m_data.c_str()); }else if (!strcmp(el, "search")){ data.Search.bValue = true; }else if (!strcmp(el, "register")){ data.Register.bValue = true; }else if (!strcmp(el, "error")){ m_bError = true; } m_data = ""; } void AgentRequest::element_end(const char *el) { if (!strcmp(el, "agent")){ if (data.ID.ptr && *data.ID.ptr){ set_str(&data.VHost.ptr, m_client->VHost().c_str()); data.Client = m_client; Event e(EventAgentFound, &data); e.process(); } }else if (!strcmp(el, "name")){ set_str(&data.Name.ptr, m_data.c_str()); } } void AgentRequest::char_data(const char *el, int len) { m_data.append(el, len); } string JabberClient::get_agents(const char *jid) { AgentRequest *req = new AgentRequest(this, jid); req->start_element("query"); req->add_attribute("xmlns", "jabber:iq:agents"); addLang(req); req->send(); m_requests.push_back(req); return req->m_id; } class AgentInfoRequest : public JabberClient::ServerRequest { public: AgentInfoRequest(JabberClient *client, const char *jid); ~AgentInfoRequest(); protected: JabberAgentInfo data; bool m_bOption; string m_data; string m_jid; string m_error; bool m_bError; unsigned m_error_code; virtual void element_start(const char *el, const char **attr); virtual void element_end(const char *el); virtual void char_data(const char *el, int len); }; /* typedef struct JabberAgentInfo { char *VHost; char *ID; char *Field; char *Type; char *Label; char *Value; void *Options; void *OptionLabels; unsigned nOptions; } JabberAgentInfo; */ static DataDef jabberAgentInfo[] = { { "", DATA_STRING, 1, 0 }, { "", DATA_STRING, 1, 0 }, { "", DATA_STRING, 1, 0 }, { "", DATA_STRING, 1, 0 }, { "", DATA_STRING, 1, 0 }, { "", DATA_STRING, 1, 0 }, { "", DATA_STRING, 1, 0 }, { "", DATA_STRING, 1, 0 }, { "", DATA_STRLIST, 1, 0 }, { "", DATA_STRLIST, 1, 0 }, { "", DATA_ULONG, 1, 0 }, { "", DATA_BOOL, 1, 0 }, { NULL, 0, 0, 0 } }; AgentInfoRequest::AgentInfoRequest(JabberClient *client, const char *jid) : ServerRequest(client, _GET, NULL, jid) { m_jid = jid; m_bOption = false; m_error_code = 0; m_bError = false; load_data(jabberAgentInfo, &data, NULL); } AgentInfoRequest::~AgentInfoRequest() { free_data(jabberAgentInfo, &data); load_data(jabberAgentInfo, &data, NULL); set_str(&data.ID.ptr, m_jid.c_str()); set_str(&data.ReqID.ptr, m_id.c_str()); data.nOptions.value = m_error_code; set_str(&data.Label.ptr, m_error.c_str()); Event e(EventAgentInfo, &data); e.process(); free_data(jabberAgentInfo, &data); } void AgentInfoRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "error")){ m_bError = true; m_error_code = atol(JabberClient::get_attr("code", attr).c_str()); } if (m_bError) return; if (!strcmp(el, "field")){ free_data(jabberAgentInfo, &data); load_data(jabberAgentInfo, &data, NULL); set_str(&data.ID.ptr, m_jid.c_str()); m_data = JabberClient::get_attr("var", attr); set_str(&data.Field.ptr, m_data.c_str()); m_data = JabberClient::get_attr("type", attr); set_str(&data.Type.ptr, m_data.c_str()); m_data = JabberClient::get_attr("label", attr); set_str(&data.Label.ptr, m_data.c_str()); } if (!strcmp(el, "option")){ m_bOption = true; m_data = JabberClient::get_attr("label", attr); set_str(&data.OptionLabels, data.nOptions.value, m_data.c_str()); } if (!strcmp(el, "x")){ set_str(&data.VHost.ptr, m_client->VHost().c_str()); set_str(&data.Type.ptr, "x"); set_str(&data.ReqID.ptr, m_id.c_str()); set_str(&data.ID.ptr, m_jid.c_str()); Event e(EventAgentInfo, &data); e.process(); free_data(jabberAgentInfo, &data); load_data(jabberAgentInfo, &data, NULL); } m_data = ""; } void AgentInfoRequest::element_end(const char *el) { if (!strcmp(el, "error")){ m_error = m_data; m_data = ""; m_bError = false; return; } if (m_bError) return; if (!strcmp(el, "desc")){ set_str(&data.Desc.ptr, m_data.c_str()); return; } if (!strcmp(el, "field")){ if (data.Field.ptr && *data.Field.ptr){ set_str(&data.VHost.ptr, m_client->VHost().c_str()); set_str(&data.ReqID.ptr, m_id.c_str()); set_str(&data.ID.ptr, m_jid.c_str()); Event e(EventAgentInfo, &data); e.process(); free_data(jabberAgentInfo, &data); load_data(jabberAgentInfo, &data, NULL); } }else if (!strcmp(el, "option")){ m_bOption = false; const char *str = get_str(data.Options, data.nOptions.value); if (str && *str) data.nOptions.value++; }else if (!strcmp(el, "value")){ if (m_bOption){ set_str(&data.Options, data.nOptions.value, m_data.c_str()); }else{ set_str(&data.Value.ptr, m_data.c_str()); } }else if (!strcmp(el, "required")){ data.bRequired.bValue = true; }else if (!strcmp(el, "key") || !strcmp(el, "instructions")){ set_str(&data.Value.ptr, m_data.c_str()); set_str(&data.ID.ptr, m_jid.c_str()); set_str(&data.ReqID.ptr, m_id.c_str()); set_str(&data.Type.ptr, el); Event e(EventAgentInfo, &data); e.process(); free_data(jabberAgentInfo, &data); load_data(jabberAgentInfo, &data, NULL); }else if (strcmp(el, "error") && strcmp(el, "iq") && strcmp(el, "query") && strcmp(el, "x")){ set_str(&data.Value.ptr, m_data.c_str()); set_str(&data.ID.ptr, m_jid.c_str()); set_str(&data.ReqID.ptr, m_id.c_str()); set_str(&data.Type.ptr, el); Event e(EventAgentInfo, &data); e.process(); free_data(jabberAgentInfo, &data); load_data(jabberAgentInfo, &data, NULL); } } void AgentInfoRequest::char_data(const char *el, int len) { m_data.append(el, len); } string JabberClient::get_agent_info(const char *jid, const char *node, const char *type) { AgentInfoRequest *req = new AgentInfoRequest(this, jid); req->start_element("query"); string xmlns = "jabber:iq:"; xmlns += type; req->add_attribute("xmlns", xmlns.c_str()); if (node && *node) req->add_attribute("node", node); addLang(req); req->send(); m_requests.push_back(req); return req->m_id; } typedef map VALUE_MAP; class SearchRequest : public JabberClient::ServerRequest { public: SearchRequest(JabberClient *client, const char *jid); ~SearchRequest(); protected: JabberSearchData data; string m_data; string m_attr; list m_fields; VALUE_MAP m_values; bool m_bReported; virtual void element_start(const char *el, const char **attr); virtual void element_end(const char *el); virtual void char_data(const char *el, int len); }; /* typedef struct JabberSearchData { char *ID; char *JID; char *First; char *Last; char *Nick; char *EMail; } JabberSearchData; */ static DataDef jabberSearchData[] = { { "", DATA_STRING, 1, 0 }, { "", DATA_STRING, 1, 0 }, { "", DATA_STRING, 1, 0 }, { "", DATA_STRING, 1, 0 }, { "", DATA_STRING, 1, 0 }, { "", DATA_STRING, 1, 0 }, { "", DATA_STRING, 1, 0 }, { "", DATA_STRLIST, 1, 0 }, { "", DATA_ULONG, 1, 0 }, { NULL, 0, 0, 0 } }; SearchRequest::SearchRequest(JabberClient *client, const char *jid) : ServerRequest(client, _SET, NULL, jid) { load_data(jabberSearchData, &data, NULL); m_bReported = false; } SearchRequest::~SearchRequest() { Event e(EventSearchDone, (void*)m_id.c_str()); e.process(); free_data(jabberSearchData, &data); } void SearchRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "reported")){ m_bReported = true; }else if (!strcmp(el, "item")){ free_data(jabberSearchData, &data); load_data(jabberSearchData, &data, NULL); m_data = JabberClient::get_attr("jid", attr); set_str(&data.JID.ptr, m_data.c_str()); }else if (!strcmp(el, "field")){ string var = JabberClient::get_attr("var", attr); if (m_bReported){ if (!var.empty() && (var != "jid")){ string label = JabberClient::get_attr("label", attr); if (label.empty()) label = var; m_values.insert(VALUE_MAP::value_type(var.c_str(), label)); m_fields.push_back(var); } }else{ m_attr = var; } } m_data = ""; } void SearchRequest::element_end(const char *el) { if (!strcmp(el, "reported")){ m_bReported = false; free_data(jabberSearchData, &data); load_data(jabberSearchData, &data, NULL); for (list::iterator it = m_fields.begin(); it != m_fields.end(); ++it){ string value; VALUE_MAP::iterator itv = m_values.find((*it).c_str()); if (itv != m_values.end()) value = (*itv).second; set_str(&data.Fields, data.nFields.value * 2, value.c_str()); set_str(&data.Fields, data.nFields.value * 2 + 1, value.c_str()); data.nFields.value++; } set_str(&data.ID.ptr, m_id.c_str()); Event e(EventSearch, &data); e.process(); m_values.clear(); }else if (!strcmp(el, "item")){ if (data.JID.ptr && *data.JID.ptr){ for (list::iterator it = m_fields.begin(); it != m_fields.end(); ++it){ VALUE_MAP::iterator itv = m_values.find((*it).c_str()); if (itv != m_values.end()){ string val = (*itv).second.c_str(); set_str(&data.Fields, data.nFields.value, val.c_str()); } data.nFields.value++; } set_str(&data.ID.ptr, m_id.c_str()); Event e(EventSearch, &data); e.process(); m_values.clear(); } }else if (!strcmp(el, "value") || !strcmp(el, "field")){ if (!m_attr.empty() && !m_data.empty()){ if (m_attr == "jid"){ set_str(&data.JID.ptr, m_data.c_str()); }else{ m_values.insert(VALUE_MAP::value_type(m_attr.c_str(), m_data)); } } m_attr = ""; }else if (!strcmp(el, "first")){ set_str(&data.First.ptr, m_data.c_str()); }else if (!strcmp(el, "last")){ set_str(&data.Last.ptr, m_data.c_str()); }else if (!strcmp(el, "nick")){ set_str(&data.Nick.ptr, m_data.c_str()); }else if (!strcmp(el, "email")){ set_str(&data.EMail.ptr, m_data.c_str()); }else if (!strcmp(el, "status")){ set_str(&data.Status.ptr, m_data.c_str()); } } void SearchRequest::char_data(const char *el, int len) { m_data.append(el, len); } string JabberClient::search(const char *jid, const char *node, const char *condition) { SearchRequest *req = new SearchRequest(this, jid); req->start_element("query"); req->add_attribute("xmlns", "jabber:iq:search"); if (node && *node) req->add_attribute("node", node); req->add_condition(condition, false); req->send(); m_requests.push_back(req); return req->m_id; } #if 0 I18N_NOOP("Password does not match"); I18N_NOOP("Low level network error"); #endif class RegisterRequest : public JabberClient::ServerRequest { public: RegisterRequest(JabberClient *client, const char *jid); ~RegisterRequest(); protected: string m_error; string *m_data; unsigned m_error_code; virtual void element_start(const char *el, const char **attr); virtual void element_end(const char *el); virtual void char_data(const char *el, int len); }; RegisterRequest::RegisterRequest(JabberClient *client, const char *jid) : ServerRequest(client, _SET, NULL, jid) { m_data = NULL; m_error_code = (unsigned)(-1); } RegisterRequest::~RegisterRequest() { agentRegisterInfo ai; ai.id = m_id.c_str(); ai.err_code = m_error_code; ai.error = m_error.c_str(); Event e(EventAgentRegister, &ai); e.process(); } void RegisterRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "error")){ m_error_code = atol(JabberClient::get_attr("code", attr).c_str()); if (m_error_code == 0) m_error_code = (unsigned)(-1); m_data = &m_error; return; } if (!strcmp(el, "iq")){ string type = JabberClient::get_attr("type", attr); if (type == "result") m_error_code = 0; } } void RegisterRequest::element_end(const char*) { m_data = NULL; } void RegisterRequest::char_data(const char *el, int len) { if (m_data == NULL) return; m_data->append(el, len); } string JabberClient::process(const char *jid, const char *node, const char *condition, const char *type) { RegisterRequest *req = new RegisterRequest(this, jid); req->start_element("query"); string xmlns = "jabber:iq:"; xmlns += type; req->add_attribute("xmlns", xmlns.c_str()); bool bData = (strcmp(type, "data") == 0); if (bData) req->add_attribute("type", "submit"); if (node && *node) req->add_attribute("node", node); req->add_condition(condition, bData); req->send(); m_requests.push_back(req); return req->m_id; } void JabberClient::processList() { if (getState() != Connected) return; for (list::iterator it = m_listRequests.begin(); it != m_listRequests.end(); ++it){ JabberListRequest &r = (*it); JabberClient::ServerRequest *req = new JabberClient::ServerRequest(this, JabberClient::ServerRequest::_SET, NULL, NULL); req->start_element("query"); req->add_attribute("xmlns", "jabber:iq:roster"); req->start_element("item"); req->add_attribute("jid", r.jid.c_str()); if ((*it).bDelete) req->add_attribute("subscription", "remove"); if (!(*it).name.empty()) req->add_attribute("name", r.name.c_str()); if (!(*it).bDelete) req->text_tag("group", r.grp.c_str()); req->send(); m_requests.push_back(req); } m_listRequests.clear(); } #if 0 class SendFileRequest : public JabberClient::ServerRequest { public: SendFileRequest(JabberClient *client, const char *jid, FileMessage *msg); ~SendFileRequest(); protected: virtual void element_start(const char *el, const char **attr); virtual void element_end(const char *el); virtual void char_data(const char *str, int len); string *m_data; string m_error; bool m_bError; FileMessage *m_msg; }; SendFileRequest::SendFileRequest(JabberClient *client, const char *jid, FileMessage *msg) : JabberClient::ServerRequest(client, _SET, NULL, jid) { m_msg = msg; m_data = NULL; m_bError = false; } SendFileRequest::~SendFileRequest() { if (m_msg && m_bError){ if (m_error.empty()) m_error = I18N_NOOP("File transfer declined"); m_msg->setError(m_error.c_str()); Event e(EventMessageSent, m_msg); e.process(); delete m_msg; } } void SendFileRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "iq")){ string type = JabberClient::get_attr("type", attr); if (type == "error") m_bError = true; } if (!strcmp(el, "error")) m_data = &m_error; } void SendFileRequest::element_end(const char*) { m_data = NULL; } void SendFileRequest::char_data(const char *str, int len) { if (m_data) m_data->append(str, len); } #endif class SendFileRequest : public JabberClient::ServerRequest { public: SendFileRequest(JabberClient *client, const char *jid, FileMessage *msg); ~SendFileRequest(); protected: virtual void element_start(const char *el, const char **attr); virtual void element_end(const char *el); virtual void char_data(const char *str, int len); FileMessage *m_msg; }; SendFileRequest::SendFileRequest(JabberClient *client, const char *jid, FileMessage *msg) : JabberClient::ServerRequest(client, _SET, NULL, jid) { m_msg = msg; } SendFileRequest::~SendFileRequest() { } void SendFileRequest::element_start(const char*, const char**) { } void SendFileRequest::element_end(const char*) { } void SendFileRequest::char_data(const char*, int) { } void JabberClient::sendFileRequest(FileMessage *msg, unsigned short, JabberUserData *data, const char *fname, unsigned size) { string jid = data->ID.ptr; string resource; if (msg->getResource().isEmpty()){ if (data->Resource.ptr){ jid += "/"; jid += data->Resource.ptr; } }else{ jid += "/"; jid += msg->getResource().utf8(); } SendFileRequest *req = new SendFileRequest(this, jid.c_str(), msg); req->start_element("si"); req->add_attribute("xmlns", "http://jabber.org/protocol/si"); req->add_attribute("profile", "http://jabber.org/protocol/si/profile/file-transfer"); req->add_attribute("id", get_unique_id().c_str()); req->start_element("file"); req->add_attribute("xmns", "http://jabber.org/protocol/si/profile/file-transfer"); req->add_attribute("size", number(size).c_str()); req->add_attribute("name", fname); req->start_element("range"); req->end_element(); req->end_element(); req->start_element("feature"); req->add_attribute("xmlns", "http://jabber.org/protocol/feature-neg"); req->start_element("x"); req->add_attribute("xmlns", "jabber:x:data"); req->add_attribute("type", "form"); req->start_element("field"); req->add_attribute("type", "list-single"); req->add_attribute("var", "stream-method"); req->start_element("option"); req->text_tag("value", "http://jabber.org/protocol/bytestreams"); #if 0 req->start_element("query"); req->add_attribute("xmlns", "jabber:iq:oob"); string url = "http://"; struct in_addr addr; addr.s_addr = m_socket->localHost(); url += inet_ntoa(addr); url += ":"; url += number(port); url += "/"; url += fname; string desc; desc = msg->getText().utf8(); req->text_tag("url", url.c_str()); req->text_tag("desc", desc.c_str()); #endif req->send(); m_requests.push_back(req); } void JabberClient::sendFileAccept(FileMessage *msg, JabberUserData *data) { JabberFileMessage *m = static_cast(msg); string jid = data->ID.ptr; string resource; if (msg->getResource().isEmpty()){ if (data->Resource.ptr){ jid += "/"; jid += data->Resource.ptr; } }else{ jid += "/"; jid += msg->getResource().utf8(); } ServerRequest req(this, ServerRequest::_RESULT, NULL, jid.c_str(), m->getID()); req.start_element("si"); req.add_attribute("xmlns", "http://jabber.org/protocol/si"); req.start_element("feature"); req.add_attribute("xmlns", "http://jabber.org/protocol/feature-neg"); req.start_element("x"); req.add_attribute("xmlns", "jabber:x:data"); req.add_attribute("type", "submit"); req.start_element("field"); req.add_attribute("var", "stream-method"); req.text_tag("value", "http://jabber.org/protocol/bytestreams"); req.send(); } class DiscoItemsRequest : public JabberClient::ServerRequest { public: DiscoItemsRequest(JabberClient *client, const char *jid); ~DiscoItemsRequest(); protected: virtual void element_start(const char *el, const char **attr); virtual void element_end(const char *el); virtual void char_data(const char *str, int len); string *m_data; string m_error; unsigned m_code; }; DiscoItemsRequest::DiscoItemsRequest(JabberClient *client, const char *jid) : JabberClient::ServerRequest(client, _GET, NULL, jid) { m_data = NULL; m_code = 0; } DiscoItemsRequest::~DiscoItemsRequest() { DiscoItem item; item.id = m_id; if (m_code){ item.name = m_error; item.node = number(m_code); } Event e(EventDiscoItem, &item); e.process(); } void DiscoItemsRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "item")){ DiscoItem item; item.id = m_id; item.jid = JabberClient::get_attr("jid", attr); item.name = JabberClient::get_attr("name", attr); item.node = JabberClient::get_attr("node", attr); if (!item.jid.empty()){ Event e(EventDiscoItem, &item); e.process(); } } if (!strcmp(el, "error")){ m_code = atol(JabberClient::get_attr("code", attr).c_str()); m_data = &m_error; } } void DiscoItemsRequest::element_end(const char *el) { if (!strcmp(el, "error")) m_data = NULL; } void DiscoItemsRequest::char_data(const char *buf, int len) { if (m_data) m_data->append(buf, len); } string JabberClient::discoItems(const char *jid, const char *node) { if (getState() != Connected) return ""; DiscoItemsRequest *req = new DiscoItemsRequest(this, jid); req->start_element("query"); req->add_attribute("xmlns", "http://jabber.org/protocol/disco#items"); if (node && *node) req->add_attribute("node", node); addLang(req); req->send(); m_requests.push_back(req); return req->m_id; } class DiscoInfoRequest : public JabberClient::ServerRequest { public: DiscoInfoRequest(JabberClient *client, const char *jid); ~DiscoInfoRequest(); protected: virtual void element_start(const char *el, const char **attr); virtual void element_end(const char *el); virtual void char_data(const char *str, int len); string *m_data; string m_error; string m_features; string m_name; string m_type; string m_category; unsigned m_code; }; DiscoInfoRequest::DiscoInfoRequest(JabberClient *client, const char *jid) : JabberClient::ServerRequest(client, _GET, NULL, jid) { m_data = NULL; m_code = 0; } DiscoInfoRequest::~DiscoInfoRequest() { if (m_code == 0){ DiscoItem item; item.id = m_id; item.jid = "info"; item.name = m_name; item.category = m_category; item.type = m_type; item.features = m_features; Event e(EventDiscoItem, &item); e.process(); } DiscoItem item; item.id = m_id; if (m_code){ item.name = m_error; item.node = number(m_code); } Event e(EventDiscoItem, &item); e.process(); } void DiscoInfoRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "identity")){ m_category = JabberClient::get_attr("category", attr); m_name = JabberClient::get_attr("name", attr); m_type = JabberClient::get_attr("type", attr); } if (!strcmp(el, "feature")){ string feature = JabberClient::get_attr("var", attr); if (!feature.empty()){ if (!m_features.empty()) m_features += "\n"; m_features += feature; } } if (!strcmp(el, "error")){ m_code = atol(JabberClient::get_attr("code", attr).c_str()); m_data = &m_error; } } void DiscoInfoRequest::element_end(const char *el) { if (!strcmp(el, "error")) m_data = NULL; } void DiscoInfoRequest::char_data(const char *buf, int len) { if (m_data) m_data->append(buf, len); } string JabberClient::discoInfo(const char *jid, const char *node) { if (getState() != Connected) return ""; DiscoInfoRequest *req = new DiscoInfoRequest(this, jid); req->start_element("query"); req->add_attribute("xmlns", "http://jabber.org/protocol/disco#info"); if (node && *node) req->add_attribute("node", node); req->send(); m_requests.push_back(req); return req->m_id; } class BrowseRequest : public JabberClient::ServerRequest { public: BrowseRequest(JabberClient *client, const char *jid); ~BrowseRequest(); protected: virtual void element_start(const char *el, const char **attr); virtual void element_end(const char *el); virtual void char_data(const char *str, int len); string *m_data; string m_jid; string m_error; string m_name; string m_type; string m_category; string m_features; string m_ns; unsigned m_code; }; BrowseRequest::BrowseRequest(JabberClient *client, const char *jid) : JabberClient::ServerRequest(client, _GET, NULL, jid) { m_data = NULL; m_code = 0; m_jid = jid; } BrowseRequest::~BrowseRequest() { if (!m_jid.empty() && !m_name.empty() && (m_code == 0)){ DiscoItem item; item.id = m_id; item.jid = m_jid; item.name = m_name; item.type = m_type; item.category = m_category; item.features = m_features; Event e(EventDiscoItem, &item); e.process(); } DiscoItem item; item.id = m_id; if (m_code){ item.name = m_error; item.node = number(m_code); } Event e(EventDiscoItem, &item); e.process(); } void BrowseRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "error")){ m_code = atol(JabberClient::get_attr("code", attr).c_str()); m_data = &m_error; } if (!strcmp(el, "item") || !strcmp(el, "service") || !strcmp(el, "agent") || !strcmp(el, "headline")){ if (!m_jid.empty() && !m_name.empty()){ DiscoItem item; item.id = m_id; item.jid = m_jid; item.name = m_name; item.type = m_type; item.category = m_category; item.features = m_features; Event e(EventDiscoItem, &item); e.process(); } m_jid = JabberClient::get_attr("jid", attr).c_str(); m_name = JabberClient::get_attr("name", attr).c_str(); m_type = JabberClient::get_attr("type", attr).c_str(); m_category = JabberClient::get_attr("category", attr).c_str(); if (!strcmp(el, "headline")) m_category = "headline"; m_features = ""; } if (!strcmp(el, "query")){ m_name = JabberClient::get_attr("name", attr).c_str(); m_type = JabberClient::get_attr("type", attr).c_str(); m_category = JabberClient::get_attr("category", attr).c_str(); } if (!strcmp(el, "ns")) m_data = &m_ns; } void BrowseRequest::element_end(const char *el) { if (!strcmp(el, "error")) m_data = NULL; if (!strcmp(el, "ns") && !m_ns.empty()){ if (!m_features.empty()) m_features += "\n"; m_features += m_ns; m_ns = ""; m_data = NULL; } if ((!strcmp(el, "item") || !strcmp(el, "service") || !strcmp(el, "agent") || !strcmp(el, "headline")) && !m_jid.empty()){ DiscoItem item; item.id = m_id; item.jid = m_jid; item.name = m_name; item.type = m_type; item.category = m_category; item.features = m_features; Event e(EventDiscoItem, &item); e.process(); m_jid = ""; } } void BrowseRequest::char_data(const char *buf, int len) { if (m_data) m_data->append(buf, len); } string JabberClient::browse(const char *jid) { if (getState() != Connected) return ""; BrowseRequest *req = new BrowseRequest(this, jid); req->start_element("query"); req->add_attribute("xmlns", "jabber:iq:browse"); req->send(); m_requests.push_back(req); return req->m_id; } class VersionInfoRequest : public JabberClient::ServerRequest { public: VersionInfoRequest(JabberClient *client, const char *jid, const char *node); ~VersionInfoRequest(); protected: virtual void element_start(const char *el, const char **attr); virtual void element_end(const char *el); virtual void char_data(const char *str, int len); string *m_data; string m_jid; string m_node; string m_name; string m_version; string m_os; }; VersionInfoRequest::VersionInfoRequest(JabberClient *client, const char *jid, const char *node) : JabberClient::ServerRequest(client, _GET, NULL, jid) { m_data = NULL; m_jid = jid; m_node = node; } VersionInfoRequest::~VersionInfoRequest() { ClientVersionInfo info; info.jid = m_jid; info.node = m_node; info.name = m_name; info.version = m_version; info.os = m_os; Event e(EventClientVersion, &info); e.process(); } void VersionInfoRequest::element_start(const char *el, const char**) { if (!strcmp(el, "name")) m_data = &m_name; if (!strcmp(el, "version")) m_data = &m_version; if (!strcmp(el, "os")) m_data = &m_os; } void VersionInfoRequest::element_end(const char*) { m_data = NULL; } void VersionInfoRequest::char_data(const char *buf, int len) { if (m_data) m_data->append(buf, len); } string JabberClient::versionInfo(const char *jid, const char *node) { if (getState() != Connected) return ""; VersionInfoRequest *req = new VersionInfoRequest(this, jid, node); req->start_element("query"); req->add_attribute("xmlns", "jabber:iq:version"); if (node && *node) req->add_attribute("node", node); req->send(); m_requests.push_back(req); return req->m_id; } class TimeInfoRequest : public JabberClient::ServerRequest { public: TimeInfoRequest(JabberClient *client, const char *jid); ~TimeInfoRequest(); protected: virtual void element_start(const char *el, const char **attr); virtual void element_end(const char *el); virtual void char_data(const char *str, int len); string *m_data; string m_time; }; TimeInfoRequest::TimeInfoRequest(JabberClient *client, const char *jid) : JabberClient::ServerRequest(client, _GET, NULL, jid) { m_data = NULL; } TimeInfoRequest::~TimeInfoRequest() { DiscoItem item; item.id = m_id; item.jid = m_time; Event e(EventDiscoItem, &item); e.process(); } void TimeInfoRequest::element_start(const char *el, const char**) { if (!strcmp(el, "utc")) m_data = &m_time; } void TimeInfoRequest::element_end(const char*) { m_data = NULL; } void TimeInfoRequest::char_data(const char *buf, int len) { if (m_data) m_data->append(buf, len); } string JabberClient::timeInfo(const char *jid, const char *node) { if (getState() != Connected) return ""; TimeInfoRequest *req = new TimeInfoRequest(this, jid); req->start_element("query"); req->add_attribute("xmlns", "jabber:iq:time"); if (node && *node) req->add_attribute("node", node); req->send(); m_requests.push_back(req); return req->m_id; } class LastInfoRequest : public JabberClient::ServerRequest { public: LastInfoRequest(JabberClient *client, const char *jid); protected: virtual void element_start(const char *el, const char **attr); }; LastInfoRequest::LastInfoRequest(JabberClient *client, const char *jid) : JabberClient::ServerRequest(client, _GET, NULL, jid) { } void LastInfoRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "query")){ DiscoItem item; item.id = m_id; item.jid = JabberClient::get_attr("seconds", attr); Event e(EventDiscoItem, &item); e.process(); } } string JabberClient::lastInfo(const char *jid, const char *node) { if (getState() != Connected) return ""; LastInfoRequest *req = new LastInfoRequest(this, jid); req->start_element("query"); req->add_attribute("xmlns", "jabber:iq:last"); if (node && *node) req->add_attribute("node", node); req->send(); m_requests.push_back(req); return req->m_id; } class StatRequest : public JabberClient::ServerRequest { public: StatRequest(JabberClient *client, const char *jid, const char *id); ~StatRequest(); protected: virtual void element_start(const char *el, const char **attr); string m_id; }; StatRequest::StatRequest(JabberClient *client, const char *jid, const char *id) : JabberClient::ServerRequest(client, _GET, NULL, jid) { m_id = id; } StatRequest::~StatRequest() { DiscoItem item; item.id = m_id; item.jid = ""; Event e(EventDiscoItem, &item); e.process(); } void StatRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "stat")){ DiscoItem item; item.id = m_id; item.jid = JabberClient::get_attr("name", attr);; item.name = JabberClient::get_attr("units", attr);; item.node = JabberClient::get_attr("value", attr);; Event e(EventDiscoItem, &item); e.process(); } } class StatItemsRequest : public JabberClient::ServerRequest { public: StatItemsRequest(JabberClient *client, const char *jid, const char *node); ~StatItemsRequest(); protected: virtual void element_start(const char *el, const char **attr); list m_stats; string m_jid; string m_node; }; StatItemsRequest::StatItemsRequest(JabberClient *client, const char *jid, const char *node) : JabberClient::ServerRequest(client, _GET, NULL, jid) { m_jid = jid; if (node) m_node = node; } StatItemsRequest::~StatItemsRequest() { if (m_stats.empty()){ DiscoItem item; item.id = m_id; item.jid = ""; Event e(EventDiscoItem, &item); e.process(); return; } StatRequest *req = new StatRequest(m_client, m_jid.c_str(), m_id.c_str()); req->start_element("query"); req->add_attribute("xmlns", "http://jabber.org/protocol/stats"); if (!m_node.empty()) req->add_attribute("node", m_node.c_str()); m_client->addLang(req); for (list::iterator it = m_stats.begin(); it != m_stats.end(); ++it){ req->start_element("stat"); req->add_attribute("name", (*it).c_str()); req->end_element(); } req->send(); m_client->m_requests.push_back(req); } void StatItemsRequest::element_start(const char *el, const char **attr) { if (!strcmp(el, "stat")){ string name = JabberClient::get_attr("name", attr); if (!name.empty()) m_stats.push_back(name); } } string JabberClient::statInfo(const char *jid, const char *node) { if (getState() != Connected) return ""; StatItemsRequest *req = new StatItemsRequest(this, jid, node); req->start_element("query"); req->add_attribute("xmlns", "http://jabber.org/protocol/stats"); if (node && *node) req->add_attribute("node", node); addLang(req); req->send(); m_requests.push_back(req); return req->m_id; } static char XmlLang[] = I18N_NOOP("Please translate this to short language name (ru, de)"); void JabberClient::addLang(ServerRequest *req) { QString s = i18n(XmlLang); if (s == XmlLang) return; req->add_attribute("xml:lang", s.utf8()); } class ChangePasswordRequest : public JabberClient::ServerRequest { public: ChangePasswordRequest(JabberClient *client, const char *password); ~ChangePasswordRequest(); protected: string m_password; }; ChangePasswordRequest::ChangePasswordRequest(JabberClient *client, const char *password) : JabberClient::ServerRequest(client, _SET, NULL, NULL) { m_password = password; } ChangePasswordRequest::~ChangePasswordRequest() { m_client->setPassword(m_password.c_str()); } void JabberClient::changePassword(const char *password) { if (getState() != Connected) return; ChangePasswordRequest *req = new ChangePasswordRequest(this, password); req->start_element("query"); req->add_attribute("xmlns", "jabber:iq:register"); req->text_tag("username", data.owner.ID.ptr); req->text_tag("password", password); m_requests.push_back(req); req->send(); }