TDE network applications
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

401 lines
12 KiB

  1. /*
  2. * kxmlrpcclient.cpp - (c) 2003 Frerich Raabe <raabe@kde.org>
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  15. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  16. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  17. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  18. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  21. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "xmlrpciface.h"
  26. #include <kdebug.h>
  27. #include <tdeio/job.h>
  28. #include <tdelocale.h>
  29. #include <kmdcodec.h>
  30. #include <tqdom.h>
  31. using namespace KXMLRPC;
  32. Query *Query::create( TQObject *parent, const char *name )
  33. {
  34. return new Query( parent, name );
  35. }
  36. void Query::call( const TQString &server, const TQString &method,
  37. const TQValueList<TQVariant> &args, const TQString &userAgent )
  38. {
  39. m_buffer.open( IO_ReadWrite );
  40. m_server = server;
  41. m_method = method;
  42. m_args = args;
  43. const TQString xmlMarkup = markupCall( method, args );
  44. TQByteArray postData;
  45. TQDataStream stream( postData, IO_WriteOnly );
  46. stream.writeRawBytes( xmlMarkup.utf8(), xmlMarkup.length() );
  47. TDEIO::TransferJob *job = TDEIO::http_post( KURL( server ), postData, false );
  48. job->addMetaData( "UserAgent", userAgent );
  49. job->addMetaData( "content-type", "Content-Type: text/xml; charset=utf-8" );
  50. connect( job, TQT_SIGNAL( infoMessage( TDEIO::Job *, const TQString & ) ),
  51. this, TQT_SLOT( slotInfoMessage( TDEIO::Job *, const TQString & ) ) );
  52. connect( job, TQT_SIGNAL( data( TDEIO::Job *, const TQByteArray & ) ),
  53. this, TQT_SLOT( slotData( TDEIO::Job *, const TQByteArray & ) ) );
  54. connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ),
  55. this, TQT_SLOT( slotResult( TDEIO::Job * ) ) );
  56. }
  57. void Query::slotInfoMessage( TDEIO::Job *, const TQString &msg )
  58. {
  59. emit infoMessage( msg );
  60. }
  61. void Query::slotData( TDEIO::Job *, const TQByteArray &data )
  62. {
  63. m_buffer.writeBlock( data );
  64. }
  65. void Query::slotResult( TDEIO::Job *job )
  66. {
  67. Result response;
  68. response.m_server = m_server;
  69. response.m_method = m_method;
  70. response.m_args = m_args;
  71. response.m_success = false;
  72. if ( job->error() != 0 ) {
  73. response.m_errorCode = job->error();
  74. response.m_errorString = job->errorString();
  75. emit finished( response );
  76. delete this;
  77. return;
  78. }
  79. TQDomDocument doc;
  80. if ( !doc.setContent( m_buffer.buffer() ) ) {
  81. response.m_errorCode = -1;
  82. response.m_errorString = i18n( "Received invalid XML markup" );
  83. emit finished( response );
  84. delete this;
  85. return;
  86. }
  87. m_buffer.close();
  88. if ( isMessageResponse( doc ) )
  89. response = parseMessageResponse( doc );
  90. else if ( isFaultResponse( doc ) )
  91. response = parseFaultResponse( doc );
  92. else {
  93. response.m_errorCode = 1;
  94. response.m_errorString = i18n( "Unknown type of XML markup received" );
  95. }
  96. // parserMessageResponse and parseFaultResponse overwrite these fields.
  97. response.m_server = m_server;
  98. response.m_method = m_method;
  99. response.m_args = m_args;
  100. emit finished( response );
  101. delete this;
  102. }
  103. bool Query::isMessageResponse( const TQDomDocument &doc ) const
  104. {
  105. return doc.documentElement().firstChild().toElement().tagName().lower() == "params";
  106. }
  107. Query::Result Query::parseMessageResponse( const TQDomDocument &doc ) const
  108. {
  109. Result response;
  110. response.m_success = true;
  111. TQDomNode paramNode = doc.documentElement().firstChild().firstChild();
  112. while ( !paramNode.isNull() ) {
  113. response.m_data << demarshal( paramNode.firstChild().toElement() );
  114. paramNode = paramNode.nextSibling();
  115. }
  116. return response;
  117. }
  118. bool Query::isFaultResponse( const TQDomDocument &doc ) const
  119. {
  120. return doc.documentElement().firstChild().toElement().tagName().lower() == "fault";
  121. }
  122. Query::Result Query::parseFaultResponse( const TQDomDocument &doc ) const
  123. {
  124. Result response;
  125. response.m_success = false;
  126. TQDomNode errorNode = doc.documentElement().firstChild().firstChild();
  127. const TQVariant errorVariant = demarshal( errorNode.toElement() );
  128. response.m_errorCode = errorVariant.toMap()[ "faultCode" ].toInt();
  129. response.m_errorString = errorVariant.toMap()[ "faultString" ].toString();
  130. return response;
  131. }
  132. TQString Query::markupCall( const TQString &cmd,
  133. const TQValueList<TQVariant> &args ) const
  134. {
  135. TQString markup = "<?xml version='1.0' ?><methodCall>";
  136. markup += "<methodName>" + cmd + "</methodName>";
  137. if ( !args.isEmpty() ) {
  138. markup += "<params>";
  139. TQValueList<TQVariant>::ConstIterator it = args.begin();
  140. TQValueList<TQVariant>::ConstIterator end = args.end();
  141. for ( ; it != end; ++it )
  142. markup += "<param>" + marshal( *it ) + "</param>";
  143. markup += "</params>";
  144. }
  145. markup += "</methodCall>";
  146. return markup;
  147. }
  148. TQString Query::marshal( const TQVariant &arg )
  149. {
  150. TQString s = "<value>";
  151. switch ( arg.type() ) {
  152. case TQVariant::String:
  153. case TQVariant::CString:
  154. s += "<string>" + arg.toString() + "</string>";
  155. break;
  156. case TQVariant::Int:
  157. s += "<int>" + TQString::number( arg.toInt() ) + "</int>";
  158. break;
  159. case TQVariant::Double:
  160. s += "<double>" + TQString::number( arg.toDouble() ) + "</double>";
  161. break;
  162. case TQVariant::Bool:
  163. s += "<boolean>";
  164. s += arg.toBool() ? "true" : "false";
  165. s += "</boolean>";
  166. break;
  167. case TQVariant::ByteArray:
  168. s += "<base64>" + KCodecs::base64Encode( arg.toByteArray() ) + "</base64>";
  169. break;
  170. case TQVariant::DateTime:
  171. s += "<datetime.iso8601>" + arg.toDateTime().toString( Qt::ISODate ) + "</datetime.iso8601>";
  172. break;
  173. case TQVariant::List: {
  174. s += "<array><data>";
  175. const TQValueList<TQVariant> args = arg.toList();
  176. TQValueList<TQVariant>::ConstIterator it = args.begin();
  177. TQValueList<TQVariant>::ConstIterator end = args.end();
  178. for ( ; it != end; ++it )
  179. s += marshal( *it );
  180. s += "</data></array>";
  181. break;
  182. }
  183. case TQVariant::Map: {
  184. s += "<struct>";
  185. TQStringVariantMap map = arg.toMap();
  186. TQStringVariantMap::ConstIterator it = map.begin();
  187. TQStringVariantMap::ConstIterator end = map.end();
  188. for ( ; it != end; ++it ) {
  189. s += "<member>";
  190. s += "<name>" + it.key() + "</name>";
  191. s += marshal( it.data() );
  192. s += "</member>";
  193. }
  194. s += "</struct>";
  195. break;
  196. }
  197. default:
  198. kdWarning() << "Failed to marshal unknown variant type: " << arg.type() << endl;
  199. return "<value/>";
  200. };
  201. return s + "</value>";
  202. }
  203. TQVariant Query::demarshal( const TQDomElement &elem )
  204. {
  205. Q_ASSERT( elem.tagName().lower() == "value" );
  206. if ( !elem.firstChild().isElement() )
  207. return TQVariant( elem.text() );
  208. const TQDomElement typeElement = elem.firstChild().toElement();
  209. const TQString typeName = typeElement.tagName().lower();
  210. if ( typeName == "string" )
  211. return TQVariant( typeElement.text() );
  212. else if ( typeName == "i4" || typeName == "int" )
  213. return TQVariant( typeElement.text().toInt() );
  214. else if ( typeName == "double" )
  215. return TQVariant( typeElement.text().toDouble() );
  216. else if ( typeName == "boolean" ) {
  217. if ( typeElement.text().lower() == "true" || typeElement.text() == "1" )
  218. return TQVariant( true );
  219. else
  220. return TQVariant( false );
  221. } else if ( typeName == "base64" )
  222. return TQVariant( KCodecs::base64Decode( TQCString(typeElement.text().latin1() )) );
  223. else if ( typeName == "datetime" || typeName == "datetime.iso8601" )
  224. return TQVariant( TQDateTime::fromString( typeElement.text(), Qt::ISODate ) );
  225. else if ( typeName == "array" ) {
  226. TQValueList<TQVariant> values;
  227. TQDomNode valueNode = typeElement.firstChild().firstChild();
  228. while ( !valueNode.isNull() ) {
  229. values << demarshal( valueNode.toElement() );
  230. valueNode = valueNode.nextSibling();
  231. }
  232. return TQVariant( values );
  233. } else if ( typeName == "struct" ) {
  234. TQStringVariantMap map;
  235. TQDomNode memberNode = typeElement.firstChild();
  236. while ( !memberNode.isNull() ) {
  237. const TQString key = memberNode.toElement().elementsByTagName( "name" ).item( 0 ).toElement().text();
  238. const TQVariant data = demarshal( memberNode.toElement().elementsByTagName( "value" ).item( 0 ).toElement() );
  239. map[ key ] = data;
  240. memberNode = memberNode.nextSibling();
  241. }
  242. return TQVariant( map );
  243. } else
  244. kdWarning() << "Cannot demarshal unknown type " << typeName << endl;
  245. return TQVariant();
  246. }
  247. Query::Query( TQObject *parent, const char *name ) : TQObject( parent, name )
  248. {
  249. }
  250. TQValueList<TQVariant> Server::toVariantList( const TQVariant &arg )
  251. {
  252. TQValueList<TQVariant> args;
  253. args << arg ;
  254. return args;
  255. }
  256. TQValueList<TQVariant> Server::toVariantList( int arg )
  257. {
  258. TQValueList<TQVariant> args;
  259. args << arg ;
  260. return args;
  261. }
  262. TQValueList<TQVariant> Server::toVariantList( bool arg )
  263. {
  264. TQValueList<TQVariant> args;
  265. args << arg ;
  266. return args;
  267. }
  268. TQValueList<TQVariant> Server::toVariantList( double arg )
  269. {
  270. TQValueList<TQVariant> args;
  271. args << arg ;
  272. return args;
  273. }
  274. TQValueList<TQVariant> Server::toVariantList( const TQString &arg )
  275. {
  276. TQValueList<TQVariant> args;
  277. args << arg ;
  278. return args;
  279. }
  280. TQValueList<TQVariant> Server::toVariantList( const TQCString &arg )
  281. {
  282. TQValueList<TQVariant> args;
  283. args << arg ;
  284. return args;
  285. }
  286. TQValueList<TQVariant> Server::toVariantList( const TQByteArray &arg )
  287. {
  288. TQValueList<TQVariant> args;
  289. args << arg ;
  290. return args;
  291. }
  292. TQValueList<TQVariant> Server::toVariantList( const TQDateTime &arg )
  293. {
  294. TQValueList<TQVariant> args;
  295. args << arg ;
  296. return args;
  297. }
  298. TQValueList<TQVariant> Server::toVariantList( const TQStringList &arg )
  299. {
  300. TQValueList<TQVariant> args;
  301. TQStringList::ConstIterator it = arg.begin();
  302. TQStringList::ConstIterator end = arg.end();
  303. for ( ; it != end; ++it )
  304. args << TQVariant( *it );
  305. return args;
  306. }
  307. Server::Server( const KURL &url, TQObject *parent, const char *name )
  308. : TQObject( parent, name )
  309. {
  310. if ( url.isValid() )
  311. m_url = url;
  312. }
  313. void Server::setUrl( const KURL &url )
  314. {
  315. m_url = url.isValid() ? url : KURL();
  316. }
  317. void Server::call( const TQString &method, const TQValueList<TQVariant> &args,
  318. TQObject *receiver, const char *slot )
  319. {
  320. if ( m_url.isEmpty() ) {
  321. kdWarning() << "Cannot execute call to " << method << ": empty server URL" << endl;
  322. return;
  323. }
  324. Query *query = Query::create( this );
  325. connect( query, TQT_SIGNAL( infoMessage( const TQString & ) ),
  326. this, TQT_SIGNAL( infoMessage( const TQString & ) ) );
  327. connect( query, TQT_SIGNAL( finished( const KXMLRPC::Query::Result & ) ),
  328. receiver, slot );
  329. query->call( m_url.url(), method, args, m_userAgent );
  330. }
  331. void Server::call( const TQString &method, const TQValueList<TQVariant> &args,
  332. TQObject *receiver, const char *slot,
  333. TQObject *infoObject, const char *infoSlot )
  334. {
  335. if ( m_url.isEmpty() ) {
  336. kdWarning() << "Cannot execute call to " << method << ": empty server URL" << endl;
  337. return;
  338. }
  339. Query *query = Query::create( this );
  340. connect( query, TQT_SIGNAL( infoMessage( const TQString &msg ) ),
  341. infoObject, infoSlot );
  342. connect( query, TQT_SIGNAL( finished( const KXMLRPC::Query::Result & ) ),
  343. receiver, slot );
  344. query->call( m_url.url(), method, args, m_userAgent );
  345. }
  346. #include "xmlrpciface.moc"