/* Jabber Protocol Plugin for Miranda IM Copyright ( C ) 2002-04 Santithorn Bunchua Copyright ( C ) 2005-12 George Hazan Copyright ( C ) 2007 Maxim Mluhov 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 xi.getText( xml ); } ///////////////////////////////////////////////////////////////////////////////////////// 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; }