Logo Search packages:      
Sourcecode: kmess version File versions  Download package

offlineimservice.cpp

/***************************************************************************
                          offlineimservice.cpp -  description
                             -------------------
    begin                : Thu Sep 07 2006
    copyright            : (C) 2006 by Diederik van der Boor
    email                : "vdboor" --at-- "codingdomain.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "offlineimservice.h"

#include "../../kmessdebug.h"
#include "../../chat/chatmessage.h"
#include "../mimemessage.h"

#include <qdom.h>

#include <kmdcodec.h>
#include <krfcdate.h>

#ifdef KMESSDEBUG_OFFLINE_IM
#define KMESSDEBUG_OFFLINE_IM_GENERAL
#endif



/**
 * @brief  The constructor.
 *
 * Initializes the client for the Offline-IM webservice.
 *
 * @param  authT   The <code>t</code> value of the passport cookie.
 * @param  authP   The <code>p</code> value of the passport cookie.
 * @param  parent  The Qt parent object, when it's destroyed this class will be cleaned up automatically too.
 */
00044 OfflineImService::OfflineImService( const QString &authT, const QString &authP, QObject *parent )
  : HttpSoapConnection("https://rsi.hotmail.com/rsi/rsi.asmx", parent, "OfflineImService")
  , authT_(authT)
  , authP_(authP)
{
#ifdef KMESSDEBUG_OFFLINE_IM_GENERAL
  kdDebug() << "CREATED OfflineImService" << endl;
#endif

  // Initialize the header once. 
  passportCookieHeader_ =
      "    <PassportCookie xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">\n"
      "      <t>" + escapeString(authT) + "</t>\n"
      "      <p>" + escapeString(authP) + "</p>\n"
      "    </PassportCookie>";
}



/**
 * @brief  The destructor.
 */
00066 OfflineImService::~OfflineImService()
{
#ifdef KMESSDEBUG_OFFLINE_IM_GENERAL
  kdDebug() << "DESTROYED OfflineImService" << endl;
#endif
}



/**
 * @brief  SOAP call to delete messages from the remote storage.
 * @param  messageIds  List of messages to delete.
 */
00079 void OfflineImService::deleteMessages( const QStringList &messageIds )
{
#ifdef KMESSDEBUG_OFFLINE_IM_GENERAL
  kdDebug() << "OfflineImService: requesting deletion of messages: '" << messageIds.join("', '") << "'" << endl;
#endif
#ifdef KMESSTEST
  ASSERT( ! messageIds.isEmpty() );
#endif

  // Initialize request
  QString soapAction = "http://www.hotmail.msn.com/ws/2004/09/oim/rsi/DeleteMessages";
  QString soapBody =
      "    <DeleteMessages xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">\n"
      "      <messageIds>\n"
      "        <messageId>" + messageIds.join("</messageId>\n        <messageId>") + "</messageId>\n"
      "      </messageIds>\n"
      "    </DeleteMessages>";
  sendRequest( soapAction, soapBody, passportCookieHeader_ );
}



/**
 * @brief Internal function to extract the e-mail address from an RFC822 formatted string.
 *
 * For a value such as '<code>"Contactname" &lt;contact@hotmail.com&gt;</code>',
 * this method returns '<code>contact@hotmail.com</code>'.
 *
 * @param    address  The string with an e-mail address.
 * @returns  The e-mail address of the contact.
 */
00110 QString OfflineImService::extractRFC822Address( const QString &address )
{
  if( address.endsWith(">") )
  {
    int pos = address.findRev('<');
    if( pos != -1 )
    {
      return address.mid( pos + 1, address.length() - pos - 2 );
    }
  }

  return address;
}



/**
 * @brief SOAP call to download an offline message.
 *
 * The message ID can be extracted from
 * the following messages types received at the notification connection:
 * - <code>text/x-msmsgsoimnotification</code>
 * - <code>text/x-msmsgsinitialmdatanotification</code>
 *
 * The messageReceived() signal is fired when the webservice returns the message.
 *
 * @param  messageId  The ID of the message.
 * @param  markAsRead  Whether the message should be marked as read.
 */
00139 void OfflineImService::getMessage( const QString &messageId, bool markAsRead )
{
#ifdef KMESSDEBUG_OFFLINE_IM_GENERAL
  kdDebug() << "OfflineImService: requesting message '" << messageId << "'" << endl;
#endif

  // Initialize request
  QString soapAction = "http://www.hotmail.msn.com/ws/2004/09/oim/rsi/GetMessage";
  QString soapBody =
      "    <GetMessage xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">\n"
      "      <messageId>" + escapeString(messageId) + "</messageId>\n"
      "      <alsoMarkAsRead>" + (markAsRead ? "true" : "false") + "</alsoMarkAsRead>\n"
      "    </GetMessage>";
  sendRequest( soapAction, soapBody, passportCookieHeader_, messageId );
}



/**
 * @brief SOAP call to download the value of the Mail-Data field.
 *
 * The value of the <code>Mail-Data</code> field is normally received by the notification server.
 * If there are many offline-IM messages, the value of this field is literally <code>too-large</code>.
 * In that case, the message data can be downloaded using this method.
 *
 * The metaDataReceived() signal is fired when the webservice returns the data.
 */
00166 void OfflineImService::getMetaData()
{
#ifdef KMESSDEBUG_OFFLINE_IM_GENERAL
  kdDebug() << "OfflineImService: requesting Mail-Data field" << endl;
#endif

  QString soapAction = "http://www.hotmail.msn.com/ws/2004/09/oim/rsi/GetMetadata";
  QString soapBody   = "    <GetMetadata xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\" />";
  sendRequest( soapAction, soapBody, passportCookieHeader_ );
}



/**
 * @brief  Internal function to process the response of the webservice.
 *
 * This handles the following response nodes:
 * - <code>GetMessageResult</code> is handled by processGetMessageResult().
 * - <code>GetMetadataResponse</code> is sent with the metaDataReceived() signal.
 * - <code>DeleteMessagesResponse</code> is ignored because it's always empty.
 *
 * Other unrecognized response types result in a warning message at the console.
 *
 * @param  resultRoot  The result root of the SOAP response.
 */
00191 void OfflineImService::parseSoapResult( const QDomElement &resultRoot, const QDomElement &/*headerNode*/ )
{
#ifdef KMESSDEBUG_OFFLINE_IM_GENERAL
  kdDebug() << "OfflineImService: parsing SOAP response." << endl;
#endif

  QString resultName = resultRoot.nodeName();
  if( resultName == "GetMessageResult" )
  {
    processGetMessageResult( resultRoot );
  }
  else if( resultName == "GetMetadataResponse" )
  {
    emit metaDataReceived( resultRoot.namedItem("MD").toElement() );
  }
  else if( resultName == "DeleteMessagesResponse" )
  {
    // do nothing
  }
  else
  {
    kdWarning() << "OfflineImService::slotRequestFinished: Unknown response type received "
                << "(rootnode=" << resultName << " endpoint=" << getEndpoint() << ")" << endl;
  }
}



/**
 * @brief  Internal function to process the response of the getMessage() call.
 *
 * This method parses the XML data, extracts the relevant fields,
 * and fires the messageReceived() signal with the results.
 *
 * @param  resultRoot  The <code>GetMessageResult</code> node of the response.
 */
00227 void OfflineImService::processGetMessageResult( const QDomElement &resultRoot )
{
#ifdef KMESSDEBUG_OFFLINE_IM_GENERAL
  kdDebug() << "OfflineImService: parsing downloaded Offline-IM message." << endl;
#endif

  // Parse as MIME message.
  MimeMessage message( resultRoot.text() );

  // Extract the fields
  QString from        = message.decodeRFC2047String( message.getValue("From").data() );
  QString to          = message.decodeRFC2047String( message.getValue("To").data() );
  QString dateString  = message.getValue("Date");
  QString runId       = message.getValue("X-OIM-Run-Id");
  int     sequenceNum = message.getValue("X-OIM-Sequence-Num").toInt();

  // Convert the 'From' and 'To' lines, it's something like "Contactname <contact@hotmail.com>"
  from = extractRFC822Address( from );
  to   = extractRFC822Address( to );

  // Convert the date, is something like "15 Nov 2005 14:24:27 -0800"
  QDateTime date;
  date.setTime_t( KRFCDate::parseDate( dateString ) );

  // Validate content type
  QString contentType = message.getValue("Content-Type");
  if( contentType.lower() != "text/plain; charset=utf-8" )
  {
    kdWarning() << "OfflineImService: received unexpected content type: " << contentType << endl;
  }

  // Validate transfer encoding
  QString transferEncoding = message.getValue("Content-Transfer-Encoding");
  if( transferEncoding != "base64" )
  {
    kdWarning() << "OfflineImService: received unexpected transfer encoding: " << transferEncoding << endl;
  }

  // Validate message type
  QString messageType  = message.getValue("X-OIM-Message-Type");
  if( messageType != "OfflineMessage" )
  {
    kdWarning() << "OfflineImService: received unexpected message type: " << messageType << endl;
  }

  // Process the body
  QCString decodedBody = KCodecs::base64Decode( message.getBody().utf8() );
  QString body = QString::fromUtf8( decodedBody.data(), decodedBody.length() );

  // Return to caller
  // The MessageID was stored in the "RequestId" field of the sendRawRequest() method
  emit messageReceived( getRequestId(), from, to, date, body, runId, sequenceNum );
}


#include "offlineimservice.moc"

Generated by  Doxygen 1.6.0   Back to index