From 899e841aea8e54721ce9771780b05a07de05ce71 Mon Sep 17 00:00:00 2001 From: George Hazan <ghazan@miranda.im> Date: Mon, 25 Feb 2019 15:16:23 +0300 Subject: Jabber: - obsolete class Xpath removed, its functionality replaced with helpers & iterators; - JABBER_FEAT_BIND added to enchance code reading & understanding; - unused function CNoteItem::AddNote removed; - fix for improper jabber:x:last behavior --- protocols/JabberG/src/jabber_caps.cpp | 41 ++++--- protocols/JabberG/src/jabber_caps.h | 1 + protocols/JabberG/src/jabber_iqid.cpp | 75 ++++++------ protocols/JabberG/src/jabber_notes.cpp | 14 +-- protocols/JabberG/src/jabber_notes.h | 1 - protocols/JabberG/src/jabber_strm_mgmt.cpp | 2 +- protocols/JabberG/src/jabber_thread.cpp | 10 +- protocols/JabberG/src/jabber_xml.cpp | 188 ----------------------------- protocols/JabberG/src/jabber_xml.h | 133 -------------------- protocols/JabberG/src/jabber_xstatus.cpp | 2 +- 10 files changed, 74 insertions(+), 393 deletions(-) (limited to 'protocols/JabberG') diff --git a/protocols/JabberG/src/jabber_caps.cpp b/protocols/JabberG/src/jabber_caps.cpp index 305cf845eb..94e949cbbf 100755 --- a/protocols/JabberG/src/jabber_caps.cpp +++ b/protocols/JabberG/src/jabber_caps.cpp @@ -161,25 +161,30 @@ void CJabberProto::OnIqResultCapsDiscoInfo(const TiXmlElement*, CJabberIqInfo *p } for (auto *xform : TiXmlFilter(query, "x")) { - const char *szFormTypeValue = XPath(xform, "field[@var='FORM_TYPE']/value"); - if (!mir_strcmp(szFormTypeValue, "urn:xmpp:dataforms:softwareinfo")) { - JSONNode root; - if (pCaps->m_szOs = mir_strdup(XPath(xform, "field[@var='os']/value"))) - root.push_back(JSONNode("o", pCaps->m_szOs.get())); - if (pCaps->m_szOsVer = mir_strdup(XPath(xform, "field[@var='os_version']/value"))) - root.push_back(JSONNode("ov", pCaps->m_szOsVer.get())); - if (pCaps->m_szSoft = mir_strdup(XPath(xform, "field[@var='software']/value"))) - root.push_back(JSONNode("s", pCaps->m_szSoft.get())); - if (pCaps->m_szSoftVer = mir_strdup(XPath(xform, "field[@var='software_version']/value"))) - root.push_back(JSONNode("sv", pCaps->m_szSoftVer.get())); - if (pCaps->m_szSoftMir = mir_strdup(XPath(xform, "field[@var='x-miranda-core-version']/value"))) - root.push_back(JSONNode("sm", pCaps->m_szSoftMir.get())); - root.push_back(JSONNode("c", CMStringA(FORMAT, "%lld", jcbCaps))); - - CMStringA szName(FORMAT, "%s#%s", pCaps->GetNode(), pCaps->GetHash()); - json_string szValue = root.write(); - db_set_s(0, "JabberCaps", szName, szValue.c_str()); + // check that this is a form of required type + auto *formType = XmlGetChildText(XmlGetChildByTag(xform, "field", "var", "FORM_TYPE"), "value"); + if (!formType || mir_strcmp(formType, "urn:xmpp:dataforms:softwareinfo")) + continue; + + JSONNode root; + for (auto *field : TiXmlFilter(xform, "field")) { + const char *fieldName = field->Attribute("var"), *fieldValue = XmlGetChildText(field, "value"); + if (!mir_strcmp(fieldName, "os")) + root.push_back(JSONNode("o", pCaps->m_szOs = mir_strdup(fieldValue))); + else if (!mir_strcmp(fieldName, "os_version")) + root.push_back(JSONNode("ov", pCaps->m_szOsVer = mir_strdup(fieldValue))); + else if (!mir_strcmp(fieldName, "software")) + root.push_back(JSONNode("s", pCaps->m_szSoft = mir_strdup(fieldValue))); + else if (!mir_strcmp(fieldName, "software_version")) + root.push_back(JSONNode("sv", pCaps->m_szSoftVer = mir_strdup(fieldValue))); + else if (!mir_strcmp(fieldName, "x-miranda-core-version")) + root.push_back(JSONNode("sm", pCaps->m_szSoftMir = mir_strdup(fieldValue))); } + root.push_back(JSONNode("c", CMStringA(FORMAT, "%lld", jcbCaps))); + + CMStringA szName(FORMAT, "%s#%s", pCaps->GetNode(), pCaps->GetHash()); + json_string szValue = root.write(); + db_set_s(0, "JabberCaps", szName, szValue.c_str()); } pCaps->SetCaps(jcbCaps, pInfo->GetIqId()); diff --git a/protocols/JabberG/src/jabber_caps.h b/protocols/JabberG/src/jabber_caps.h index 4c8e985990..683b44b897 100755 --- a/protocols/JabberG/src/jabber_caps.h +++ b/protocols/JabberG/src/jabber_caps.h @@ -132,6 +132,7 @@ typedef unsigned __int64 JabberCapsBits; #define JABBER_CAPS_ARCHIVE_MANAGE ((JabberCapsBits)1<<35) #define JABBER_FEAT_CAPTCHA "urn:xmpp:captcha" +#define JABBER_FEAT_BIND "urn:ietf:params:xml:ns:xmpp-bind" #define JABBER_FEAT_ATTENTION "urn:xmpp:attention:0" #define JABBER_CAPS_ATTENTION ((JabberCapsBits)1<<36) diff --git a/protocols/JabberG/src/jabber_iqid.cpp b/protocols/JabberG/src/jabber_iqid.cpp index 627f404a8a..ad5b04c556 100755 --- a/protocols/JabberG/src/jabber_iqid.cpp +++ b/protocols/JabberG/src/jabber_iqid.cpp @@ -82,14 +82,14 @@ void CJabberProto::OnIqResultServerDiscoInfo(const TiXmlElement *iqNode, CJabber void CJabberProto::OnIqResultNestedRosterGroups(const TiXmlElement *iqNode, CJabberIqInfo *pInfo) { - const char *szGroupDelimeter = nullptr; + const char *szGroupDelimiter = nullptr; bool bPrivateStorageSupport = false; if (iqNode && pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT) { bPrivateStorageSupport = true; - szGroupDelimeter = XPathFmt(iqNode, "query[@xmlns='%s']/roster[@xmlns='%s']", JABBER_FEAT_PRIVATE_STORAGE, JABBER_FEAT_NESTED_ROSTER_GROUPS); - if (szGroupDelimeter && !szGroupDelimeter[0]) - szGroupDelimeter = nullptr; // "" as roster delimeter is not supported :) + auto *xmlDelimiter = XmlGetChildByTag(XmlGetChildByTag(iqNode, "query", "xmlns", JABBER_FEAT_PRIVATE_STORAGE), "roster", "xmlns", JABBER_FEAT_NESTED_ROSTER_GROUPS); + if (xmlDelimiter) + szGroupDelimiter = xmlDelimiter->GetText(); } // global fuckup @@ -97,13 +97,13 @@ void CJabberProto::OnIqResultNestedRosterGroups(const TiXmlElement *iqNode, CJab return; // is our default delimiter? - if ((!szGroupDelimeter && bPrivateStorageSupport) || (szGroupDelimeter && mir_strcmp(szGroupDelimeter, "\\"))) + if ((!szGroupDelimiter && bPrivateStorageSupport) || (szGroupDelimiter && mir_strcmp(szGroupDelimiter, "\\"))) m_ThreadInfo->send( XmlNodeIq("set", SerialNext()) << XQUERY(JABBER_FEAT_PRIVATE_STORAGE) << XCHILD("roster", "\\") << XATTR("xmlns", JABBER_FEAT_NESTED_ROSTER_GROUPS)); // roster request - char *szUserData = mir_strdup(szGroupDelimeter ? szGroupDelimeter : "\\"); + char *szUserData = mir_strdup(szGroupDelimiter ? szGroupDelimiter : "\\"); m_ThreadInfo->send( XmlNodeIq(AddIQ(&CJabberProto::OnIqResultGetRoster, JABBER_IQ_TYPE_GET, nullptr, 0, -1, (void*)szUserData)) << XCHILDNS("query", JABBER_FEAT_IQ_ROSTER)); @@ -293,7 +293,7 @@ void CJabberProto::OnIqResultBind(const TiXmlElement *iqNode, CJabberIqInfo *pIn if (!m_ThreadInfo || !iqNode) return; if (pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT) { - const char *szJid = XPath(iqNode, "bind[@xmlns='urn:ietf:params:xml:ns:xmpp-bind']/jid"); + const char *szJid = XmlGetChildText(XmlGetChildByTag(iqNode, "bind", "xmlns", JABBER_FEAT_BIND), "jid"); if (szJid) { if (!strncmp(m_ThreadInfo->fullJID, szJid, _countof(m_ThreadInfo->fullJID))) debugLogA("Result Bind: %s confirmed ", m_ThreadInfo->fullJID); @@ -351,7 +351,7 @@ void CJabberProto::GroupchatJoinByHContact(MCONTACT hContact, bool autojoin) void CJabberProto::OnIqResultGetRoster(const TiXmlElement *iqNode, CJabberIqInfo *pInfo) { debugLogA("<iq/> iqIdGetRoster"); - ptrA szGroupDelimeter((char *)pInfo->GetUserData()); + ptrA szGroupDelimiter((char *)pInfo->GetUserData()); if (pInfo->GetIqType() != JABBER_IQ_TYPE_RESULT) return; @@ -362,8 +362,8 @@ void CJabberProto::OnIqResultGetRoster(const TiXmlElement *iqNode, CJabberIqInfo if (mir_strcmp(queryNode->Attribute("xmlns"), JABBER_FEAT_IQ_ROSTER)) return; - if (!mir_strcmp(szGroupDelimeter, "\\")) - szGroupDelimeter = nullptr; + if (!mir_strcmp(szGroupDelimiter, "\\")) + szGroupDelimiter = nullptr; LIST<void> chatRooms(10); OBJLIST<JABBER_HTTP_AVATARS> *httpavatars = new OBJLIST<JABBER_HTTP_AVATARS>(20, JABBER_HTTP_AVATARS::compare); @@ -402,10 +402,10 @@ void CJabberProto::OnIqResultGetRoster(const TiXmlElement *iqNode, CJabberIqInfo replaceStr(item->group, XmlGetChildText(itemNode, "group")); // check group delimiters - if (item->group && szGroupDelimeter) { - while (char *szPos = strstr(item->group, szGroupDelimeter)) { + if (item->group && szGroupDelimiter) { + while (char *szPos = strstr(item->group, szGroupDelimiter)) { *szPos = 0; - szPos += mir_strlen(szGroupDelimeter); + szPos += mir_strlen(szGroupDelimiter); CMStringA szNewGroup(FORMAT, "%s\\%s", item->group, szPos); replaceStr(item->group, szNewGroup.Detach()); } @@ -491,8 +491,8 @@ void CJabberProto::OnIqResultGetRoster(const TiXmlElement *iqNode, CJabberIqInfo UI_SAFE_NOTIFY(m_pDlgServiceDiscovery, WM_JABBER_TRANSPORT_REFRESH); - if (szGroupDelimeter) - mir_free(szGroupDelimeter); + if (szGroupDelimiter) + mir_free(szGroupDelimiter); OnProcessLoginRq(m_ThreadInfo, JABBER_LOGIN_ROSTER); RebuildInfoFrame(); @@ -1424,8 +1424,8 @@ void CJabberProto::OnIqResultDiscoBookmarks(const TiXmlElement *iqNode, CJabberI item->name = mir_utf8decodeW(itemNode->Attribute("name")); item->type = mir_strdup("conference"); item->bUseResource = true; - item->nick = mir_strdup(XPath(itemNode, "nick")); - item->password = mir_strdup(XPath(itemNode, "password")); + item->nick = mir_strdup(XmlGetChildText(itemNode, "nick")); + item->password = mir_strdup(XmlGetChildText(itemNode, "password")); const char *autoJ = itemNode->Attribute("autojoin"); if (autoJ != nullptr) @@ -1515,7 +1515,7 @@ void CJabberProto::OnIqResultLastActivity(const TiXmlElement *iqNode, CJabberIqI time_t lastActivity = -1; if (pInfo->m_nIqType == JABBER_IQ_TYPE_RESULT) { if (auto *xmlLast = XmlGetChildByTag(iqNode, "query", "xmlns", JABBER_FEAT_LAST_ACTIVITY)) { - int nSeconds = XmlGetChildInt(xmlLast, "seconds"); + int nSeconds = xmlLast->IntAttribute("seconds"); if (nSeconds > 0) lastActivity = time(0) - nSeconds; @@ -1536,24 +1536,27 @@ void CJabberProto::OnIqResultEntityTime(const TiXmlElement *pIqNode, CJabberIqIn return; if (pInfo->m_nIqType == JABBER_IQ_TYPE_RESULT) { - const char *szTzo = XPathFmt(pIqNode, "time[@xmlns='%s']/tzo", JABBER_FEAT_ENTITY_TIME); - if (szTzo && szTzo[0]) { - const char *szMin = strchr(szTzo, ':'); - int nTz = atoi(szTzo) * -2; - nTz += (nTz < 0 ? -1 : 1) * (szMin ? atoi(szMin + 1) / 30 : 0); - - TIME_ZONE_INFORMATION tzinfo; - if (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT) - nTz -= tzinfo.DaylightBias / 30; - - setByte(pInfo->m_hContact, "Timezone", (signed char)nTz); - - const char *szTz = XPathFmt(pIqNode, "time[@xmlns='%s']/tz", JABBER_FEAT_ENTITY_TIME); - if (szTz) - setUString(pInfo->m_hContact, "TzName", szTz); - else - delSetting(pInfo->m_hContact, "TzName"); - return; + auto *xmlTime = XmlGetChildByTag(pIqNode, "time", "xmlns", JABBER_FEAT_ENTITY_TIME); + if (xmlTime) { + const char *szTzo = XmlGetChildText(xmlTime, "tzo"); + if (szTzo && szTzo[0]) { + const char *szMin = strchr(szTzo, ':'); + int nTz = atoi(szTzo) * -2; + nTz += (nTz < 0 ? -1 : 1) * (szMin ? atoi(szMin + 1) / 30 : 0); + + TIME_ZONE_INFORMATION tzinfo; + if (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT) + nTz -= tzinfo.DaylightBias / 30; + + setByte(pInfo->m_hContact, "Timezone", (signed char)nTz); + + const char *szTz = XmlGetChildText(xmlTime, "tz"); + if (szTz) + setUString(pInfo->m_hContact, "TzName", szTz); + else + delSetting(pInfo->m_hContact, "TzName"); + return; + } } } else if (pInfo->m_nIqType == JABBER_IQ_TYPE_ERROR) { diff --git a/protocols/JabberG/src/jabber_notes.cpp b/protocols/JabberG/src/jabber_notes.cpp index 67678f107c..3b346ff64c 100644 --- a/protocols/JabberG/src/jabber_notes.cpp +++ b/protocols/JabberG/src/jabber_notes.cpp @@ -38,10 +38,10 @@ CNoteItem::CNoteItem() CNoteItem::CNoteItem(const TiXmlElement *hXml, const char *szFrom) { SetData( - XPath(hXml, "title"), - szFrom ? szFrom : XPath(hXml, "@from"), - Utf2T(XPath(hXml, "text")), - XPath(hXml, "@tags")); + XmlGetChildText(hXml, "title"), + szFrom ? szFrom : hXml->Attribute("from"), + Utf2T(XmlGetChildText(hXml, "text")), + hXml->Attribute("tags")); } CNoteItem::~CNoteItem() @@ -107,12 +107,6 @@ int CNoteItem::cmp(const CNoteItem *p1, const CNoteItem *p2) return 0; } -void CNoteList::AddNote(TiXmlElement *hXml, const char *szFrom) -{ - m_bIsModified = true; - insert(new CNoteItem(hXml, szFrom)); -} - void CNoteList::LoadXml(const TiXmlElement *hXml) { destroy(); diff --git a/protocols/JabberG/src/jabber_notes.h b/protocols/JabberG/src/jabber_notes.h index c2867970b3..3f0613a044 100644 --- a/protocols/JabberG/src/jabber_notes.h +++ b/protocols/JabberG/src/jabber_notes.h @@ -77,7 +77,6 @@ public: OBJLIST<CNoteItem>::remove(p); } - void AddNote(TiXmlElement *hXml, const char *szFrom = nullptr); void LoadXml(const TiXmlElement *hXml); void SaveXml(TiXmlElement *hXmlParent); diff --git a/protocols/JabberG/src/jabber_strm_mgmt.cpp b/protocols/JabberG/src/jabber_strm_mgmt.cpp index 9a61f66c63..b7682364aa 100755 --- a/protocols/JabberG/src/jabber_strm_mgmt.cpp +++ b/protocols/JabberG/src/jabber_strm_mgmt.cpp @@ -272,7 +272,7 @@ void strm_mgmt::FinishLoginProcess(ThreadData *info) if (info->auth) { //We are already logged-in info->send( XmlNodeIq(proto->AddIQ(&CJabberProto::OnIqResultBind, JABBER_IQ_TYPE_SET)) - << XCHILDNS("bind", "urn:ietf:params:xml:ns:xmpp-bind") + << XCHILDNS("bind", JABBER_FEAT_BIND) << XCHILD("resource", info->resource)); if (proto->m_AuthMechs.isSessionAvailable) diff --git a/protocols/JabberG/src/jabber_thread.cpp b/protocols/JabberG/src/jabber_thread.cpp index 439ed33d69..fa9ea84c14 100755 --- a/protocols/JabberG/src/jabber_thread.cpp +++ b/protocols/JabberG/src/jabber_thread.cpp @@ -760,7 +760,7 @@ void CJabberProto::OnProcessFeatures(const TiXmlElement *node, ThreadData *info) if (info->auth) { //We are already logged-in info->send( XmlNodeIq(AddIQ(&CJabberProto::OnIqResultBind, JABBER_IQ_TYPE_SET)) - << XCHILDNS("bind", "urn:ietf:params:xml:ns:xmpp-bind") + << XCHILDNS("bind", JABBER_FEAT_BIND) << XCHILD("resource", info->resource)); if (m_AuthMechs.isSessionAvailable) @@ -989,10 +989,10 @@ void CJabberProto::OnProcessPubsubEvent(const TiXmlElement *node) if (!tuneNode) return; - const char *szArtist = XPath(tuneNode, "artist"); - const char *szSource = XPath(tuneNode, "source"); - const char *szTitle = XPath(tuneNode, "title"); - const char *szTrack = XPath(tuneNode, "track"); + const char *szArtist = XmlGetChildText(tuneNode, "artist"); + const char *szSource = XmlGetChildText(tuneNode, "source"); + const char *szTitle = XmlGetChildText(tuneNode, "title"); + const char *szTrack = XmlGetChildText(tuneNode, "track"); wchar_t szLengthInTime[20]; int nLength = XmlGetChildInt(tuneNode, "length"); diff --git a/protocols/JabberG/src/jabber_xml.cpp b/protocols/JabberG/src/jabber_xml.cpp index bd0fbe08eb..f2336123c7 100644 --- a/protocols/JabberG/src/jabber_xml.cpp +++ b/protocols/JabberG/src/jabber_xml.cpp @@ -199,191 +199,3 @@ int XmlGetChildCount(const TiXmlElement *hXml) } return iCount; } - -///////////////////////////////////////////////////////////////////////////////////////// - -void XPath::ProcessPath(LookupInfo &info) -{ - if (!info.nodeName) return; - - char *nodeName = (char *)alloca(sizeof(char) * (info.nodeName.length+1)); - mir_strncpy(nodeName, info.nodeName.p, info.nodeName.length+1); - - if (info.attrName && info.attrValue) { - char *attrName = (char *)alloca(sizeof(char)* (info.attrName.length + 1)); - mir_strncpy(attrName, info.attrName.p, info.attrName.length + 1); - char *attrValue = (char *)alloca(sizeof(char)* (info.attrValue.length + 1)); - mir_strncpy(attrValue, info.attrValue.p, info.attrValue.length + 1); - m_hXml = XmlGetChildByTag(m_hXml, nodeName, attrName, attrValue); - } - else m_hXml = m_hXml->FirstChildElement(nodeName); - - info.Reset(); -} - -XPath::PathType XPath::LookupImpl() -{ - LookupState state = S_START; - LookupInfo info = {}; - - for (const char *p = m_szPath; state < S_FINAL; ++p) { - switch (state) { - case S_START: - ProcessPath(info); - if (!m_hXml) { - state = S_FINAL_ERROR; - break; - } - - switch (*p) { - case 0: - state = S_FINAL_ERROR; - break; - case '@': - info.attrName.Begin(p + 1); - state = S_ATTR_STEP; - break; - case '/': - break; - default: - info.nodeName.Begin(p); - state = S_NODE_NAME; - break; - }; - break; - - case S_ATTR_STEP: - switch (*p) { - case 0: - info.attrName.End(p); - state = S_FINAL_ATTR; - break; - default: - break; - }; - break; - - case S_NODE_NAME: - switch (*p) { - case 0: - info.nodeName.End(p); - state = S_FINAL_NODESET; - break; - case '[': - info.nodeName.End(p); - state = S_NODE_OPENBRACKET; - break; - case '/': - info.nodeName.End(p); - state = S_START; - break; - default: - break; - }; - break; - - case S_NODE_OPENBRACKET: - switch (*p) { - case 0: - state = S_FINAL_ERROR; - break; - case '@': - info.attrName.Begin(p + 1); - state = S_NODE_ATTRNAME; - break; - default: - state = S_FINAL_ERROR; - break; - }; - break; - - case S_NODE_ATTRNAME: - switch (*p) { - case 0: - state = S_FINAL_ERROR; - break; - case '=': - info.attrName.End(p); - state = S_NODE_ATTREQUALS; - break; - default: - break; - }; - break; - - case S_NODE_ATTREQUALS: - switch (*p) { - case 0: - state = S_FINAL_ERROR; - break; - case '\'': - info.attrValue.Begin(p + 1); - state = S_NODE_ATTRVALUE; - break; - default: - state = S_FINAL_ERROR; - break; - }; - break; - - case S_NODE_ATTRVALUE: - switch (*p) { - case 0: - state = S_FINAL_ERROR; - break; - case '\'': - info.attrValue.End(p); - state = S_NODE_ATTRCLOSEVALUE; - break; - default: - break; - }; - break; - - case S_NODE_ATTRCLOSEVALUE: - switch (*p) { - case 0: - state = S_FINAL_ERROR; - break; - case ']': - state = S_NODE_CLOSEBRACKET; - break; - default: - state = S_FINAL_ERROR; - break; - }; - break; - - case S_NODE_CLOSEBRACKET: - switch (*p) { - case 0: - state = S_FINAL_NODE; - break; - case '/': - state = S_START; - break; - default: - state = S_FINAL_ERROR; - break; - }; - break; - } - - if (!*p && (state < S_FINAL)) - state = S_FINAL_ERROR; - } - - switch (state) { - case S_FINAL_ATTR: - m_szParam = info.attrName.p; - return T_ATTRIBUTE; - case S_FINAL_NODE: - ProcessPath(info); - return T_NODE; - case S_FINAL_NODESET: - m_szParam = info.nodeName.p; - return T_NODESET; - } - - return T_ERROR; -} diff --git a/protocols/JabberG/src/jabber_xml.h b/protocols/JabberG/src/jabber_xml.h index 84be255ba5..098e8ae346 100644 --- a/protocols/JabberG/src/jabber_xml.h +++ b/protocols/JabberG/src/jabber_xml.h @@ -188,137 +188,4 @@ struct XQUERY TiXmlElement* __fastcall operator<<(TiXmlElement *node, const XQUERY& child); -///////////////////////////////////////////////////////////////////////////////////////// -// Limited XPath support -// path should look like: "node-spec/node-spec/.../result-spec" -// where "node-spec" can be "node-name", "node-name[@attr-name='attr-value']" or "node-name[node-index]" -// result may be either "node-spec", or "@attr-name" -// -// Samples: -// const char *s = XPath(node, "child/subchild[@attr='value']"); // get node text -// XPath(node, "child/subchild[@name='test']/@attr") = L"Hello"; // create path if needed and set attribute value -// -// XPath(node, "child/subchild[@name='test']") = L"Hello"; // TODO: create path if needed and set node text - -class XPath -{ -public: - __forceinline XPath(const TiXmlElement *hXml, char *path): - m_type(T_UNKNOWN), - m_szPath(path), - m_hXml(hXml), - m_szParam(nullptr) - {} - - // Read data - operator const TiXmlElement*() - { - switch (Lookup()) - { - case T_NODE: return m_hXml; - case T_NODESET: return m_hXml->FirstChildElement(m_szParam); - } - return nullptr; - } - operator LPCSTR() - { - switch (Lookup()) - { - case T_ATTRIBUTE: return m_hXml->Attribute(m_szParam); - case T_NODE: return m_hXml->GetText(); - case T_NODESET: return (m_hXml->FirstChildElement()) ? m_hXml->FirstChildElement()->GetText() : 0; - } - return nullptr; - } - __forceinline bool operator== (char *str) - { - return !mir_strcmp(*this, str); - } - __forceinline bool operator!= (char *str) - { - return mir_strcmp(*this, str) ? true : false; - } - -private: - enum PathType - { - T_UNKNOWN, - T_ERROR, - T_NODE, - T_ATTRIBUTE, - T_NODESET - }; - - __forceinline PathType Lookup() - { - return (m_type == T_UNKNOWN) ? LookupImpl() : m_type; - } - - enum LookupState - { - S_START, - S_ATTR_STEP, - S_NODE_NAME, - S_NODE_OPENBRACKET, - S_NODE_ATTRNAME, - S_NODE_ATTREQUALS, - S_NODE_ATTRVALUE, - S_NODE_ATTRCLOSEVALUE, - S_NODE_CLOSEBRACKET, - - S_FINAL, - S_FINAL_ERROR, - S_FINAL_ATTR, - S_FINAL_NODESET, - S_FINAL_NODE - }; - - struct LookupString - { - void Begin(const char *p_) { p = p_; } - void End(const char *p_) { length = p_ - p; } - operator bool() { return p ? true : false; } - - const char *p; - int length; - - }; - - struct LookupInfo - { - void Reset() { memset(this, 0, sizeof(*this)); } - LookupString nodeName; - LookupString attrName; - LookupString attrValue; - }; - - void ProcessPath(LookupInfo &info); - PathType LookupImpl(); - - PathType m_type; - const TiXmlElement *m_hXml; - const char *m_szPath; - const char *m_szParam; -}; - -class XPathFmt: public XPath -{ -public: - enum { BUFSIZE = 512 }; - XPathFmt(const TiXmlElement *hXml, char *path, ...): XPath(hXml, m_buf) - { - *m_buf = 0; - char buf[BUFSIZE]; - - va_list args; - va_start(args, path); - mir_vsnprintf(buf, BUFSIZE, path, args); - buf[BUFSIZE-1] = 0; - va_end(args); - } - -private: - char m_buf[BUFSIZE]; -}; - #endif diff --git a/protocols/JabberG/src/jabber_xstatus.cpp b/protocols/JabberG/src/jabber_xstatus.cpp index 70fad9c365..7909374f13 100644 --- a/protocols/JabberG/src/jabber_xstatus.cpp +++ b/protocols/JabberG/src/jabber_xstatus.cpp @@ -1003,7 +1003,7 @@ void CPepActivity::ProcessItems(const char *from, const TiXmlElement *itemsNode) if (!actNode) return; - const char *szText = XPath(actNode, "text"); + const char *szText = XmlGetChildText(actNode, "text"); const char *szFirstNode = nullptr, *szSecondNode = nullptr; for (auto *n : TiXmlFilter(actNode, "text")) { -- cgit v1.2.3