/* Jabber Protocol Plugin for Miranda IM Copyright (C) 2002-04 Santithorn Bunchua Copyright (C) 2005-12 George Hazan Copyright (C) 2007 Maxim Mluhov Copyright (C) 2012-13 Miranda NG Project 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "jabber.h" #define TAG_MAX_LEN 128 #define ATTR_MAX_LEN 8192 #define T2UTF(A) A ///////////////////////////////////////////////////////////////////////////////////////// // XmlNodeIq class members XmlNodeIq::XmlNodeIq(const TCHAR *type, int id, LPCTSTR to) : XmlNode(_T("iq")) { if (type != NULL) *this << XATTR(_T("type"), type); if (to != NULL) *this << XATTR(_T("to"), to); if (id != -1 ) *this << XATTRID(id); } XmlNodeIq::XmlNodeIq(const TCHAR *type, LPCTSTR idStr, LPCTSTR to) : XmlNode(_T("iq")) { if (type != NULL) *this << XATTR(_T("type"), type ); if (to != NULL) *this << XATTR(_T("to"), to ); if (idStr != NULL) *this << XATTR(_T("id"), idStr); } XmlNodeIq::XmlNodeIq(const TCHAR *type, HXML node, LPCTSTR to) : XmlNode(_T("iq")) { if (type != NULL) *this << XATTR(_T("type"), type ); if (to != NULL) *this << XATTR(_T("to"), to ); if (node != NULL) { const TCHAR *iqId = xmlGetAttrValue(*this, _T("id")); if (iqId != NULL) *this << XATTR(_T("id"), iqId); } } XmlNodeIq::XmlNodeIq(CJabberIqInfo* pInfo) : XmlNode(_T("iq")) { if (pInfo) { if (pInfo->GetCharIqType() != NULL) *this << XATTR(_T("type"), _A2T(pInfo->GetCharIqType())); if (pInfo->GetReceiver() != NULL) *this << XATTR(_T("to"), pInfo->GetReceiver()); if (pInfo->GetIqId() != -1) *this << XATTRID(pInfo->GetIqId()); } } XmlNodeIq::XmlNodeIq(const TCHAR *type, CJabberIqInfo* pInfo) : XmlNode(_T("iq")) { if (type != NULL) *this << XATTR(_T("type"), type); if (pInfo) { if (pInfo->GetFrom() != NULL) *this << XATTR(_T("to"), pInfo->GetFrom()); if (pInfo->GetIdStr() != NULL) *this << XATTR(_T("id"), pInfo->GetIdStr()); } } ///////////////////////////////////////////////////////////////////////////////////////// // XmlNode class members XmlNode::XmlNode(LPCTSTR pszName) { m_hXml = xi.createNode(T2UTF(pszName), NULL, 0); } XmlNode::XmlNode(LPCTSTR pszName, LPCTSTR ptszText) { m_hXml = xi.createNode(T2UTF(pszName), ptszText, 0); } XmlNode::XmlNode(const XmlNode& n) { m_hXml = xi.copyNode(n); } XmlNode& XmlNode::operator =(const XmlNode& n) { if (m_hXml) xi.destroyNode(m_hXml); m_hXml = xi.copyNode(n); return *this; } XmlNode::~XmlNode() { if (m_hXml) { xi.destroyNode(m_hXml); m_hXml = NULL; } } ///////////////////////////////////////////////////////////////////////////////////////// HXML __fastcall operator<<(HXML node, const XCHILDNS& child) { HXML res = xmlAddChild(node, child.name); xmlAddAttr(res, _T("xmlns"), child.ns); return res; } HXML __fastcall operator<<(HXML node, const XQUERY& child) { HXML n = xmlAddChild(node, _T("query")); if (n) xmlAddAttr(n, _T("xmlns"), child.ns); return n; } ///////////////////////////////////////////////////////////////////////////////////////// void __fastcall xmlAddAttr(HXML hXml, LPCTSTR name, LPCTSTR value) { if (value) xi.addAttr(hXml, name, T2UTF(value)); } void __fastcall xmlAddAttr(HXML hXml, LPCTSTR pszName, int value) { xi.addAttrInt(hXml, T2UTF(pszName), value); } void __fastcall xmlAddAttr(HXML hXml, LPCTSTR pszName, unsigned __int64 value) { TCHAR buf[60]; _ui64tot(value, buf, 10); xi.addAttr(hXml, T2UTF(pszName), T2UTF(buf)); } void __fastcall xmlAddAttrID(HXML hXml, int id) { TCHAR text[ 100 ]; mir_sntprintf(text, SIZEOF(text), _T("mir_%d"), id); xmlAddAttr(hXml, _T("id"), text); } ///////////////////////////////////////////////////////////////////////////////////////// LPCTSTR __fastcall xmlGetAttr(HXML hXml, int n) { return xi.getAttr(hXml, n); } int __fastcall xmlGetAttrCount(HXML hXml) { return xi.getAttrCount(hXml); } LPCTSTR __fastcall xmlGetAttrName(HXML hXml, int n) { return xi.getAttrName(hXml, n); } ///////////////////////////////////////////////////////////////////////////////////////// void __fastcall xmlAddChild(HXML hXml, HXML n) { xi.addChild2(n, hXml); } HXML __fastcall xmlAddChild(HXML hXml, LPCTSTR name) { return xi.addChild(hXml, T2UTF(name), NULL); } HXML __fastcall xmlAddChild(HXML hXml, LPCTSTR name, LPCTSTR value) { return xi.addChild(hXml, T2UTF(name), T2UTF(value)); } HXML __fastcall xmlAddChild(HXML hXml, LPCTSTR name, int value) { TCHAR buf[40]; _itot(value, buf, 10); return xi.addChild(hXml, T2UTF(name), buf); } ///////////////////////////////////////////////////////////////////////////////////////// LPCTSTR __fastcall xmlGetAttrValue(HXML hXml, LPCTSTR key) { return xi.getAttrValue(hXml, key); } HXML __fastcall xmlGetChild(HXML hXml, int n) { return xi.getChild(hXml, n); } HXML __fastcall xmlGetChild(HXML hXml, LPCTSTR key) { return xi.getNthChild(hXml, key, 0); } HXML __fastcall xmlGetChild(HXML hXml, LPCSTR key) { LPTSTR wszKey = mir_a2t(key); HXML result = xi.getNthChild(hXml, wszKey, 0); mir_free(wszKey); return result; } HXML __fastcall xmlGetChildByTag(HXML hXml, LPCTSTR key, LPCTSTR attrName, LPCTSTR attrValue) { return xi.getChildByAttrValue(hXml, key, attrName, attrValue); } HXML __fastcall xmlGetChildByTag(HXML hXml, LPCSTR key, LPCSTR attrName, LPCTSTR attrValue) { LPTSTR wszKey = mir_a2t(key), wszName = mir_a2t(attrName); HXML result = xi.getChildByAttrValue(hXml, wszKey, wszName, attrValue); mir_free(wszKey), mir_free(wszName); return result; } int __fastcall xmlGetChildCount(HXML hXml) { return xi.getChildCount(hXml); } HXML __fastcall xmlGetNthChild(HXML hXml, LPCTSTR tag, int nth) { int i, num; if ( !hXml || tag == NULL || _tcslen(tag) <= 0 || nth < 1) return NULL; num = 1; for (i=0; ; i++) { HXML n = xi.getChild(hXml, i); if ( !n) break; if ( !lstrcmp(tag, xmlGetName(n))) { if (num == nth) return n; num++; } } return NULL; } LPCTSTR __fastcall xmlGetName(HXML xml) { return xi.getName(xml); } LPCTSTR __fastcall xmlGetText(HXML xml) { return (xml) ? xi.getText(xml) : NULL; } ///////////////////////////////////////////////////////////////////////////////////////// void XPath::ProcessPath(LookupInfo &info, bool bCreate) { if ( !info.nodeName) return; TCHAR *nodeName = (TCHAR *)alloca(sizeof(TCHAR) * (info.nodeName.length+1)); lstrcpyn(nodeName, info.nodeName.p, info.nodeName.length+1); if (info.attrName && info.attrValue) { TCHAR *attrName = (TCHAR *)alloca(sizeof(TCHAR) * (info.attrName.length+1)); lstrcpyn(attrName, info.attrName.p, info.attrName.length+1); TCHAR *attrValue = (TCHAR *)alloca(sizeof(TCHAR) * (info.attrValue.length+1)); lstrcpyn(attrValue, info.attrValue.p, info.attrValue.length+1); HXML hXml = xmlGetChildByTag(m_hXml, nodeName, attrName, attrValue); m_hXml = (hXml || !bCreate) ? hXml : (m_hXml << XCHILD(nodeName) << XATTR(attrName, attrValue)); } else if (info.nodeIndex) { int idx = _ttoi(info.nodeIndex.p); m_hXml = lstrcmp(nodeName, _T("*")) ? xmlGetNthChild(m_hXml, nodeName, idx) : xmlGetChild(m_hXml, idx-1); // no support for such creation mode } else { HXML hXml = xmlGetChild(m_hXml, nodeName); m_hXml = (hXml || !bCreate) ? hXml : (m_hXml << XCHILD(nodeName)); } info.Reset(); } XPath::PathType XPath::LookupImpl(bool bCreate) { LookupState state = S_START; LookupInfo info = {0}; for (LPCTSTR p = m_szPath; state < S_FINAL; ++p) { switch (state) { case S_START: { ProcessPath(info, bCreate); if ( !m_hXml) { state = S_FINAL_ERROR; break; } switch (*p) { case 0: state = S_FINAL_ERROR; break; case _T('@'): info.attrName.Begin(p+1); state = S_ATTR_STEP; break; case _T('/'): 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 _T('['): info.nodeName.End(p); state = S_NODE_OPENBRACKET; break; case _T('/'): 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 _T('@'): info.attrName.Begin(p+1); state = S_NODE_ATTRNAME; break; case _T('0'): case _T('1'): case _T('2'): case _T('3'): case _T('4'): case _T('5'): case _T('6'): case _T('7'): case _T('8'): case _T('9'): info.nodeIndex.Begin(p); state = S_NODE_INDEX; break; default: state = S_FINAL_ERROR; break; }; break; } case S_NODE_INDEX: { switch (*p) { case 0: state = S_FINAL_ERROR; break; case _T(']'): info.nodeIndex.End(p); state = S_NODE_CLOSEBRACKET; break; case _T('0'): case _T('1'): case _T('2'): case _T('3'): case _T('4'): case _T('5'): case _T('6'): case _T('7'): case _T('8'): case _T('9'): break; default: state = S_FINAL_ERROR; break; }; break; } case S_NODE_ATTRNAME: { switch (*p) { case 0: state = S_FINAL_ERROR; break; case _T('='): 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 _T('\''): 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 _T('\''): 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 _T(']'): 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 _T('/'): 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, bCreate); return T_NODE; case S_FINAL_NODESET: m_szParam = info.nodeName.p; return T_NODESET; } return T_ERROR; }