qtmobility/src/messaging/qmessageservice_win.cpp
changeset 1 2b40d63a9c3d
child 4 90517678cc4f
equal deleted inserted replaced
0:cfcbf08528c4 1:2b40d63a9c3d
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qmessageservice.h"
       
    43 #include "winhelpers_p.h"
       
    44 #include "qmessagemanager.h"
       
    45 #include "qmessageid_p.h"
       
    46 #include "qmessagefolderid_p.h"
       
    47 #include "qmessageaccountid_p.h"
       
    48 #include "qmessage_p.h"
       
    49 #include "qmessagestore_p.h"
       
    50 #include "qmessagecontentcontainer_p.h"
       
    51 #include "qmessagecontentcontainerid_p.h"
       
    52 #include <QDebug>
       
    53 #include <QThread>
       
    54 #include <QTimer>
       
    55 #include <mapix.h>
       
    56 #include <objbase.h>
       
    57 #include <mapiutil.h>
       
    58 #include <qmobilityglobal.h>
       
    59 #ifdef _WIN32_WCE
       
    60 #include <cemapi.h>
       
    61 #endif
       
    62 
       
    63 using namespace QtMobility::WinHelpers;
       
    64 
       
    65 QTM_BEGIN_NAMESPACE
       
    66 
       
    67 static const unsigned long SmsCharLimit = 160;
       
    68 
       
    69 class QMessageServicePrivate : public QObject
       
    70 {
       
    71     Q_OBJECT
       
    72 
       
    73     Q_DECLARE_PUBLIC(QMessageService)
       
    74 
       
    75 public:
       
    76     QMessageServicePrivate(QMessageService* parent);
       
    77     ~QMessageServicePrivate();
       
    78 
       
    79     bool send(const QMessage& message, bool showComposer = false);
       
    80     bool show(const QMessageId& id);
       
    81 #ifdef _WIN32_WCE
       
    82     bool isPartiallyDownloaded(const QMessageId& id, bool considerAttachments = false);
       
    83     bool markForDownload(const QMessageId& id, bool includeAttachments = false);
       
    84     bool synchronize(const QMessageAccountId& id);
       
    85     bool registerUpdates(const QMessageId& id);
       
    86     void unregisterUpdates();
       
    87     bool retrieveBody(const QMessage& partialMessage);
       
    88 #endif
       
    89 
       
    90     void setFinished(bool successful);
       
    91 
       
    92 public slots:
       
    93     void completed();
       
    94     void reportMatchingIds();
       
    95     void reportMessagesCounted();
       
    96 
       
    97 #ifdef _WIN32_WCE
       
    98     void messageUpdated(const QMessageId& id);
       
    99 #endif
       
   100 
       
   101 signals:
       
   102     void stateChanged(QMessageService::State);
       
   103     void messagesFound(const QMessageIdList&);
       
   104     void messagesCounted(int);
       
   105     void progressChanged(uint, uint);
       
   106 
       
   107 public:
       
   108     QMessageService* q_ptr;
       
   109     QMessageManager _manager;
       
   110     bool _active;
       
   111     QMessageManager::Error _error;
       
   112     QMessageIdList _candidateIds;
       
   113     int _count;
       
   114     QMessageService::State _state;
       
   115     QMessageId m_bodyDownloadTarget;
       
   116     QMessageManager::NotificationFilterId m_bodyDownloadFilterId;
       
   117     bool m_registeredUpdates;
       
   118     QThread *m_queryThread;
       
   119     QList<QThread*> m_obsoleteThreads;
       
   120 };
       
   121 
       
   122 namespace {
       
   123 
       
   124 class QueryThread : public QThread
       
   125 {
       
   126     Q_OBJECT
       
   127 
       
   128     QMessageServicePrivate *_parent;
       
   129     QMessageFilter _filter;
       
   130     QString _body;
       
   131     QMessageDataComparator::MatchFlags _matchFlags;
       
   132     QMessageSortOrder _ordering;
       
   133     uint _limit;
       
   134     uint _offset;
       
   135 
       
   136     // Ensure that the main thread has instantiated the store before we access it from another thread:
       
   137     QMessageManager _manager;
       
   138 
       
   139 public:
       
   140     QueryThread(QMessageServicePrivate *parent, const QMessageFilter &filter, const QString &body, QMessageDataComparator::MatchFlags matchFlags, const QMessageSortOrder &sortOrder, uint limit, uint offset);
       
   141     void run();
       
   142 
       
   143 signals:
       
   144     void completed();
       
   145 };
       
   146 
       
   147 QueryThread::QueryThread(QMessageServicePrivate *parent, const QMessageFilter &filter, const QString &body, QMessageDataComparator::MatchFlags matchFlags, const QMessageSortOrder &sortOrder, uint limit, uint offset)
       
   148 : QThread(),
       
   149     _parent(parent),
       
   150     _filter(filter),
       
   151     _body(body),
       
   152     _matchFlags(matchFlags),
       
   153     _ordering(sortOrder),
       
   154     _limit(limit),
       
   155     _offset(offset)
       
   156 {
       
   157 }
       
   158 
       
   159 void QueryThread::run()
       
   160 {
       
   161     // Ensure that this thread has initialized MAPI
       
   162     WinHelpers::MapiInitializationToken token(WinHelpers::initializeMapi());
       
   163 
       
   164     _parent->_candidateIds = _manager.queryMessages(_filter, _body, _matchFlags, _ordering, _limit, _offset);
       
   165     _parent->_error = _manager.error();
       
   166     emit completed();
       
   167 }
       
   168 
       
   169 }
       
   170 
       
   171 void QMessageServicePrivate::completed()
       
   172 {
       
   173     _active = false;
       
   174     _state = QMessageService::FinishedState;
       
   175     emit stateChanged(_state);
       
   176 }
       
   177 
       
   178 void QMessageServicePrivate::reportMatchingIds()
       
   179 {
       
   180     if (_error == QMessageManager::NoError) {
       
   181         emit messagesFound(_candidateIds);
       
   182     }
       
   183 
       
   184     completed();
       
   185 }
       
   186 
       
   187 void QMessageServicePrivate::reportMessagesCounted()
       
   188 {
       
   189     if (_error == QMessageManager::NoError) {
       
   190         emit messagesCounted(_candidateIds.count());
       
   191     }
       
   192     completed();
       
   193 }
       
   194 
       
   195 #ifdef _WIN32_WCE
       
   196 void QMessageServicePrivate::messageUpdated(const QMessageId& id)
       
   197 {
       
   198     if (id == m_bodyDownloadTarget) {
       
   199         bool isBodyDownloaded = !isPartiallyDownloaded(id);
       
   200         if (isBodyDownloaded) {
       
   201             unregisterUpdates();
       
   202 
       
   203             completed();
       
   204         }
       
   205     }
       
   206 }
       
   207 
       
   208 #endif
       
   209 
       
   210 QMessageServicePrivate::QMessageServicePrivate(QMessageService* parent)
       
   211     :q_ptr(parent),
       
   212      _active(false),
       
   213      _state(QMessageService::InactiveState),
       
   214      m_registeredUpdates(false),
       
   215      m_queryThread(0)
       
   216 {
       
   217 }
       
   218 
       
   219 QMessageServicePrivate::~QMessageServicePrivate()
       
   220 {
       
   221     qDeleteAll(m_obsoleteThreads);
       
   222     delete m_queryThread;
       
   223     _manager.unregisterNotificationFilter(m_bodyDownloadFilterId);
       
   224 }
       
   225 
       
   226 static Lptstr createMCFRecipients(QMessageAddress::Type filterAddressType, const QMessageAddressList& addressList)
       
   227 {
       
   228     QStringList temp;
       
   229 
       
   230     foreach(const QMessageAddress& a, addressList)
       
   231     {
       
   232         if(a.type() == filterAddressType)
       
   233             temp.append(a.recipient());
       
   234     }
       
   235 
       
   236     return temp.isEmpty() ? Lptstr(0) : LptstrFromQString(temp.join(";"));
       
   237 }
       
   238 
       
   239 bool QMessageServicePrivate::send(const QMessage& message, bool showComposer)
       
   240 {
       
   241     //check message type
       
   242 
       
   243     if(message.type() == QMessage::AnyType || message.type() == QMessage::NoType)
       
   244     {
       
   245         qWarning() << "Unsupported message type for sending/composition";
       
   246         _error = QMessageManager::ConstraintFailure;
       
   247         return false;
       
   248     }
       
   249 
       
   250     //check account
       
   251 
       
   252     QMessageAccountId accountId = message.parentAccountId();
       
   253 
       
   254     if(!accountId.isValid())
       
   255     {
       
   256         accountId = QMessageAccount::defaultAccount(message.type());
       
   257         if(!accountId.isValid())
       
   258         {
       
   259             qWarning() << "Invalid account for sending/composition";
       
   260             _error = QMessageManager::InvalidId;
       
   261             return false;
       
   262         }
       
   263     }
       
   264 
       
   265     //check account/message type compatibility
       
   266 
       
   267     QMessageAccount account(accountId);
       
   268     if(!(account.messageTypes() & message.type()))
       
   269     {
       
   270         qWarning() << "Message type unsupported by account";
       
   271         _error = QMessageManager::ConstraintFailure;
       
   272         return false;
       
   273     }
       
   274 
       
   275 #ifdef _WIN32_WCE
       
   276     if(showComposer)
       
   277     {
       
   278         MAILCOMPOSEFIELDS mcf;
       
   279         memset(&mcf,0,sizeof(mcf));
       
   280 
       
   281         Lptstr accountName = LptstrFromQString(QMessageAccount(accountId).name());
       
   282         Lptstr to;
       
   283         Lptstr cc;
       
   284         Lptstr bcc;
       
   285         Lptstr subject;
       
   286         Lptstr attachments;
       
   287         Lptstr bodyText;
       
   288 
       
   289         //account
       
   290 
       
   291         mcf.pszAccount = accountName;
       
   292         mcf.dwFlags = MCF_ACCOUNT_IS_NAME;
       
   293 
       
   294         if(message.type() == QMessage::Email)
       
   295         {
       
   296             //recipients
       
   297 
       
   298             to = createMCFRecipients(QMessageAddress::Email, message.to());
       
   299             cc = createMCFRecipients(QMessageAddress::Email, message.cc());
       
   300             bcc = createMCFRecipients(QMessageAddress::Email, message.bcc());
       
   301             mcf.pszTo = to;
       
   302             mcf.pszCc = cc;
       
   303             mcf.pszBcc = bcc;
       
   304 
       
   305             //subject
       
   306 
       
   307             subject = LptstrFromQString(message.subject());
       
   308             mcf.pszSubject = subject;
       
   309 
       
   310             //body
       
   311 
       
   312             QMessageContentContainerId bodyId = message.bodyId();
       
   313             if(bodyId.isValid())
       
   314             {
       
   315                 const QMessageContentContainer& bodyContainer = message.find(bodyId);
       
   316                 bodyText = LptstrFromQString(bodyContainer.textContent());
       
   317                 mcf.pszBody = bodyText;
       
   318             }
       
   319 
       
   320             //attachments
       
   321 
       
   322             if(message.status() & QMessage::HasAttachments)
       
   323             {
       
   324                 QStringList attachmentList;
       
   325 
       
   326                 foreach(const QMessageContentContainerId& id, message.attachmentIds())
       
   327                 {
       
   328                     const QMessageContentContainer& attachmentContainer = message.find(id);
       
   329                     attachmentList.append(QMessageContentContainerPrivate::attachmentFilename(attachmentContainer));
       
   330                 }
       
   331 
       
   332                 mcf.cAttachments = attachmentList.count();
       
   333                 QChar nullChar(0);
       
   334                 attachments = LptstrFromQString(attachmentList.join(nullChar));
       
   335                 mcf.pszAttachments = attachments;
       
   336             }
       
   337         }
       
   338         else if(message.type() == QMessage::Sms)
       
   339         {
       
   340             //recipients
       
   341 
       
   342             to = createMCFRecipients(QMessageAddress::Phone, message.to());
       
   343             mcf.pszTo = to;
       
   344 
       
   345             //body
       
   346 
       
   347             QMessageContentContainerId bodyId = message.bodyId();
       
   348             if(bodyId.isValid())
       
   349             {
       
   350                 const QMessageContentContainer& bodyContainer = message.find(bodyId);
       
   351                 QString textContent = bodyContainer.textContent();
       
   352                 if(textContent.length() > SmsCharLimit)
       
   353                 {
       
   354                     textContent.truncate(SmsCharLimit);
       
   355                     qWarning() << "SMS messages may not exceed " << SmsCharLimit << " characters. Body trucated.";
       
   356                 }
       
   357                 bodyText = LptstrFromQString(textContent);
       
   358                 mcf.pszBody = bodyText;
       
   359             }
       
   360         }
       
   361 
       
   362        mcf.cbSize = sizeof(mcf);
       
   363 
       
   364        if(FAILED(MailComposeMessage(&mcf)))
       
   365        {
       
   366            _error = QMessageManager::FrameworkFault;
       
   367            qWarning() << "MailComposeMessage failed";
       
   368            return false;
       
   369        }
       
   370     }
       
   371     else
       
   372     {
       
   373 #endif
       
   374 
       
   375     //check recipients
       
   376     QMessageAddressList recipients = message.to() + message.bcc() + message.cc();
       
   377     if(recipients.isEmpty() && !showComposer)
       
   378     {
       
   379         qWarning() << "Message must have recipients for sending";
       
   380         _error = QMessageManager::ConstraintFailure;
       
   381         return false;
       
   382     }
       
   383 
       
   384     MapiSessionPtr mapiSession(MapiSession::createSession(&_error));
       
   385     if (_error != QMessageManager::NoError)
       
   386     {
       
   387         qWarning() << "Could not create MAPI session for sending";
       
   388         return false;
       
   389     }
       
   390 
       
   391     QMessage outgoing(message);
       
   392 
       
   393     //ensure the message is marked read otherwise MapiForm displays the message as incomming
       
   394     outgoing.setStatus(QMessage::Read,true);
       
   395 
       
   396     //set default account if unset
       
   397     if(!outgoing.parentAccountId().isValid())
       
   398         outgoing.setParentAccountId(accountId);
       
   399 
       
   400     MapiStorePtr mapiStore = mapiSession->findStore(&_error, outgoing.parentAccountId(),false);
       
   401 
       
   402     if(mapiStore.isNull() || _error != QMessageManager::NoError)
       
   403     {
       
   404         qWarning() << "Unable to retrieve MAPI store for account";
       
   405         return false;
       
   406     }
       
   407 
       
   408     //try first to create message in outbox for store, failing that attempt draft
       
   409 
       
   410     MapiFolderPtr mapiFolder = mapiStore->findFolder(&_error,QMessage::OutboxFolder);
       
   411 
       
   412     if( mapiFolder.isNull() || _error != QMessageManager::NoError ) {
       
   413         qWarning() << "Unable to retrieve outbox MAPI folder for sending, attempting drafts...";
       
   414         mapiFolder = mapiStore->findFolder(&_error,QMessage::DraftsFolder);
       
   415         if(mapiFolder.isNull() || _error != QMessageManager::NoError) {
       
   416             qWarning() << "Unable to retrieve drafts MAPI folder for sending";
       
   417             return false;
       
   418         }
       
   419     }
       
   420 
       
   421     IMessage* mapiMessage = mapiFolder->createMessage(&_error, outgoing, mapiSession, DontSavePropertyChanges);
       
   422 
       
   423     if(!mapiMessage || _error != QMessageManager::NoError)
       
   424     {
       
   425         qWarning() << "Unable to create MAPI message from source";
       
   426         mapiRelease(mapiMessage);
       
   427         return false;
       
   428     }
       
   429 
       
   430 #ifndef _WIN32_WCE
       
   431     if(showComposer)
       
   432     {
       
   433         MapiForm* mapiForm = new MapiForm(mapiStore->store(),mapiSession->session(),mapiFolder->folder(),mapiMessage);
       
   434         bool result = mapiForm->show();
       
   435         mapiRelease(mapiForm);
       
   436 
       
   437         if(!result)
       
   438         {
       
   439             qWarning() << "MapiForm::Show failed";
       
   440             _error = QMessageManager::FrameworkFault;
       
   441             return false;
       
   442         }
       
   443     }
       
   444     else
       
   445 #endif
       
   446     {
       
   447         if(FAILED(mapiMessage->SubmitMessage(0)))
       
   448         {
       
   449             qWarning() << "MAPI SubmitMessage failed.";
       
   450             _error = QMessageManager::FrameworkFault;
       
   451             mapiRelease(mapiMessage);
       
   452             return false;
       
   453         }
       
   454     }
       
   455 
       
   456 #ifdef _WIN32_WCE
       
   457     }
       
   458 #endif
       
   459 
       
   460     return true;
       
   461 }
       
   462 
       
   463 bool QMessageServicePrivate::show(const QMessageId& messageId)
       
   464 {
       
   465     if(!messageId.isValid())
       
   466     {
       
   467         _error = QMessageManager::InvalidId;
       
   468         qWarning() << "Invalid QMessageId";
       
   469         return false;
       
   470     }
       
   471 
       
   472 #ifdef _WIN32_WCE
       
   473     MapiEntryId entryId = QMessageIdPrivate::entryId(messageId);
       
   474     LPENTRYID entryIdPtr(reinterpret_cast<LPENTRYID>(const_cast<char*>(entryId.data())));
       
   475     if(FAILED(MailDisplayMessage(entryIdPtr,entryId.length())))
       
   476     {
       
   477         qWarning() << "MailDisplayMessage failed";
       
   478         _error = QMessageManager::FrameworkFault;
       
   479         return false;
       
   480     }
       
   481     return true;
       
   482 
       
   483 #else
       
   484 
       
   485     MapiSessionPtr mapiSession(MapiSession::createSession(&_error));
       
   486     if (_error != QMessageManager::NoError)
       
   487     {
       
   488         qWarning() << "Could not create MAPI seesion";
       
   489         return false;
       
   490     }
       
   491 
       
   492     MapiEntryId entryId = QMessageIdPrivate::entryId(messageId);
       
   493     MapiRecordKey folderRecordKey = QMessageIdPrivate::folderRecordKey(messageId);
       
   494     MapiRecordKey storeRecordKey = QMessageIdPrivate::storeRecordKey(messageId);
       
   495 
       
   496     MapiStorePtr mapiStore = mapiSession->findStore(&_error,QMessageAccountIdPrivate::from(storeRecordKey));
       
   497 
       
   498     if(mapiStore.isNull() || _error != QMessageManager::NoError)
       
   499     {
       
   500         qWarning() << "Unable to retrieve MAPI store for account";
       
   501         return false;
       
   502     }
       
   503 
       
   504     MapiFolderPtr mapiFolder = mapiStore->openFolderWithKey(&_error,folderRecordKey);
       
   505 
       
   506     if( mapiFolder.isNull() || _error != QMessageManager::NoError ) {
       
   507         qWarning() << "Unable to retrieve MAPI folder for message";
       
   508         return false;
       
   509     }
       
   510 
       
   511     IMessage* mapiMessage = mapiFolder->openMessage(&_error,entryId);
       
   512 
       
   513     if(!mapiMessage || _error != QMessageManager::NoError)
       
   514     {
       
   515         qWarning() << "Unable to retrieve MAPI message";
       
   516         mapiRelease(mapiMessage);
       
   517         return false;
       
   518     }
       
   519 
       
   520     MapiForm* mapiForm = new MapiForm(mapiStore->store(),mapiSession->session(),mapiFolder->folder(),mapiMessage);
       
   521     bool result = mapiForm->show();
       
   522     mapiRelease(mapiForm);
       
   523 
       
   524     if(!result)
       
   525     {
       
   526         qWarning() << "MapiForm::show failed.";
       
   527         _error = QMessageManager::FrameworkFault;
       
   528         return false;
       
   529     }
       
   530 
       
   531     mapiRelease(mapiMessage);
       
   532 
       
   533     return result;
       
   534 
       
   535 #endif
       
   536 }
       
   537 
       
   538 #ifdef _WIN32_WCE
       
   539 
       
   540 bool QMessageServicePrivate::isPartiallyDownloaded(const QMessageId& id, bool considerAttachments)
       
   541 {
       
   542     if(!id.isValid())
       
   543     {
       
   544         _error = QMessageManager::InvalidId;
       
   545         qWarning() << "Invalid QMessageId";
       
   546         return false;
       
   547     }
       
   548 
       
   549     MapiSessionPtr mapiSession(MapiSession::createSession(&_error));
       
   550 
       
   551     if (_error != QMessageManager::NoError)
       
   552     {
       
   553         qWarning() << "Could not create MAPI session";
       
   554         return false;
       
   555     }
       
   556 
       
   557     MapiStorePtr mapiStore = mapiSession->openStore(&_error,QMessageIdPrivate::storeRecordKey(id));
       
   558 
       
   559     if(mapiStore.isNull() || _error != QMessageManager::NoError) {
       
   560         qWarning() << "Unable to retrieve MAPI store for account";
       
   561         return false;
       
   562     }
       
   563 
       
   564     IMessage* message = mapiStore->openMessage(&_error,QMessageIdPrivate::entryId(id));
       
   565 
       
   566     ULONG status = 0;
       
   567     if(!getMapiProperty(message,PR_MSG_STATUS,&status)) {
       
   568         qWarning() << "Unable to get MAPI message status flags";
       
   569         _error = QMessageManager::FrameworkFault;
       
   570         return false;
       
   571     }
       
   572     else
       
   573     {
       
   574         mapiRelease(message);
       
   575         bool bodyNotDownloaded = (status & MSGSTATUS_HEADERONLY) || (status & MSGSTATUS_PARTIAL);
       
   576         bool attachmentsNotDownloaded = (status & MSGSTATUS_PENDING_ATTACHMENTS);
       
   577         return considerAttachments ? bodyNotDownloaded && attachmentsNotDownloaded : bodyNotDownloaded;
       
   578     }
       
   579 }
       
   580 
       
   581 bool QMessageServicePrivate::markForDownload(const QMessageId& id, bool includeAttachments)
       
   582 {
       
   583     if(!id.isValid())
       
   584     {
       
   585         _error = QMessageManager::InvalidId;
       
   586         qWarning() << "Invalid QMessageId";
       
   587         return false;
       
   588     }
       
   589 
       
   590     MapiSessionPtr mapiSession(MapiSession::createSession(&_error));
       
   591 
       
   592     if (_error != QMessageManager::NoError)
       
   593     {
       
   594         qWarning() << "Could not create MAPI session";
       
   595         return false;
       
   596     }
       
   597 
       
   598     MapiStorePtr mapiStore = mapiSession->openStore(&_error,QMessageIdPrivate::storeRecordKey(id));
       
   599 
       
   600     if(mapiStore.isNull() || _error != QMessageManager::NoError)
       
   601     {
       
   602         qWarning() << "Unable to retrieve MAPI store for message account";
       
   603         return false;
       
   604     }
       
   605 
       
   606     IMessage* message = mapiStore->openMessage(&_error,QMessageIdPrivate::entryId(id));
       
   607 
       
   608     ULONG status = 0;
       
   609 
       
   610     if(!getMapiProperty(message,PR_MSG_STATUS,&status))
       
   611     {
       
   612         qWarning() << "Unable to get MAPI message status flags";
       
   613         _error = QMessageManager::FrameworkFault;
       
   614         return false;
       
   615     }
       
   616     else
       
   617     {
       
   618         //mark the message to download on the next sync
       
   619 
       
   620         status |= MSGSTATUS_REMOTE_DOWNLOAD;
       
   621         if(includeAttachments)
       
   622             status |= MSGSTATUS_REMOTE_DOWNLOAD_ATTACH;
       
   623 
       
   624         if(!setMapiProperty(message, PR_MSG_STATUS, status))
       
   625         {
       
   626             qWarning() << "Could not mark the MAPI message for download!";
       
   627             _error = QMessageManager::FrameworkFault;
       
   628             return false;
       
   629         }
       
   630 
       
   631         mapiRelease(message);
       
   632 
       
   633         //TODO investigate possiblity of interacting with mapi transport directly
       
   634         /*
       
   635         QString transportName = mapiStore->transportName();
       
   636         if(transportName.isEmpty())
       
   637         {
       
   638             qWarning() << "Could not get transport name for mapi store";
       
   639             return false;
       
   640         }
       
   641         */
       
   642     }
       
   643     return true;
       
   644 }
       
   645 
       
   646 bool QMessageServicePrivate::synchronize(const QMessageAccountId& id)
       
   647 {
       
   648     if(!id.isValid())
       
   649     {
       
   650         qWarning() << "Cannot synchronize invalid QMessageAccountId";
       
   651         _error = QMessageManager::InvalidId;
       
   652         return false;
       
   653     }
       
   654 
       
   655     QMessageAccount account(id);
       
   656     if(FAILED(MailSyncMessages(LptstrFromQString(account.name()),MCF_ACCOUNT_IS_NAME | MCF_RUN_IN_BACKGROUND)))
       
   657     {
       
   658         qWarning() << "MailSyncMessages failed for account: " << account.name();
       
   659         _error = QMessageManager::FrameworkFault;
       
   660         return false;
       
   661     }
       
   662     return true;
       
   663 }
       
   664 
       
   665 bool QMessageServicePrivate::registerUpdates(const QMessageId& id)
       
   666 {
       
   667     if(!id.isValid())
       
   668     {
       
   669         qWarning() << "Cannot register for update notifications on invalid QMessageId";
       
   670         _error = QMessageManager::InvalidId;
       
   671         return false;
       
   672     }
       
   673 
       
   674     if(!m_registeredUpdates)
       
   675     {
       
   676         connect(&_manager, SIGNAL(messageUpdated(const QMessageId&, const QMessageManager::NotificationFilterIdSet&)),this,SLOT(messageUpdated(const QMessageId&)));
       
   677         m_bodyDownloadFilterId = _manager.registerNotificationFilter(QMessageFilter::byId(id));
       
   678         m_bodyDownloadTarget = id;
       
   679         m_registeredUpdates = true;
       
   680     }
       
   681     return m_registeredUpdates;
       
   682 }
       
   683 
       
   684 void QMessageServicePrivate::unregisterUpdates()
       
   685 {
       
   686     disconnect(&_manager, SIGNAL(messageUpdated(const QMessageId&, const QMessageManager::NotificationFilterIdSet&)),this,SLOT(messageUpdated(const QMessageId&)));
       
   687     _manager.unregisterNotificationFilter(m_bodyDownloadFilterId);
       
   688     m_bodyDownloadFilterId = 0;
       
   689     m_registeredUpdates = false;
       
   690 }
       
   691 
       
   692 bool QMessageServicePrivate::retrieveBody(const QMessage& partialMessage)
       
   693 {
       
   694     if(partialMessage.type() != QMessage::Email)
       
   695     {
       
   696         qWarning() << "Cannot retrieve body for non-email message type";
       
   697         _error = QMessageManager::ConstraintFailure;
       
   698         return false;
       
   699     }
       
   700 
       
   701     if(isPartiallyDownloaded(partialMessage.id()))
       
   702     {
       
   703         //only valid for Email
       
   704         if(markForDownload(partialMessage.id(),true))
       
   705             if(registerUpdates(partialMessage.id()))
       
   706                 if(!synchronize(partialMessage.parentAccountId()))
       
   707                     unregisterUpdates();
       
   708     }
       
   709     else QTimer::singleShot(0,this,SLOT(completed()));
       
   710 
       
   711     return (_error == QMessageManager::NoError);
       
   712 }
       
   713 
       
   714 #endif
       
   715 
       
   716 void QMessageServicePrivate::setFinished(bool successful)
       
   717 {
       
   718     if (!successful && (_error == QMessageManager::NoError)) {
       
   719         _error = QMessageManager::RequestIncomplete;
       
   720     }
       
   721 
       
   722     completed();
       
   723 }
       
   724 
       
   725 QMessageService::QMessageService(QObject *parent)
       
   726     : QObject(parent),
       
   727     d_ptr(new QMessageServicePrivate(this))
       
   728 {
       
   729     connect(d_ptr, SIGNAL(stateChanged(QMessageService::State)),
       
   730         this, SIGNAL(stateChanged(QMessageService::State)));
       
   731     connect(d_ptr, SIGNAL(messagesFound(const QMessageIdList&)),
       
   732         this, SIGNAL(messagesFound(const QMessageIdList&)));
       
   733     connect(d_ptr, SIGNAL(messagesCounted(int)),
       
   734         this, SIGNAL(messagesCounted(int)));
       
   735     connect(d_ptr, SIGNAL(progressChanged(uint, uint)),
       
   736         this, SIGNAL(progressChanged(uint, uint)));
       
   737 }
       
   738 
       
   739 QMessageService::~QMessageService()
       
   740 {
       
   741     delete d_ptr;
       
   742     d_ptr = 0;
       
   743 }
       
   744 
       
   745 bool QMessageService::queryMessages(const QMessageFilter &filter, const QMessageSortOrder &sortOrder, uint limit, uint offset)
       
   746 {
       
   747     return queryMessages(filter, QString(), QMessageDataComparator::MatchFlags(), sortOrder, limit, offset);
       
   748 }
       
   749 
       
   750 bool QMessageService::queryMessages(const QMessageFilter &filter, const QString &body, QMessageDataComparator::MatchFlags matchFlags, const QMessageSortOrder &sortOrder, uint limit, uint offset)
       
   751 {
       
   752     if (d_ptr->_active) {
       
   753         qWarning() << "Service is currently busy";
       
   754         return false;
       
   755     }
       
   756 
       
   757 
       
   758     d_ptr->_active = true;
       
   759     d_ptr->_error = QMessageManager::NoError;
       
   760     d_ptr->_state = QMessageService::ActiveState;
       
   761     emit stateChanged(d_ptr->_state);
       
   762 
       
   763 #if 0
       
   764     d_ptr->_candidateIds = d_ptr->_manager.queryMessages(filter, body, matchFlags, sortOrder, limit, offset);
       
   765     d_ptr->_error = d_ptr->_manager.error();
       
   766     QTimer::singleShot(0,d_ptr,SLOT(reportMatchingIds()));
       
   767 #else
       
   768     // Perform the query in another thread to keep the UI thread free
       
   769     QueryThread *query = new QueryThread(d_ptr, filter, body, matchFlags, sortOrder, limit, offset);
       
   770     connect(query, SIGNAL(completed()), d_ptr, SLOT(reportMatchingIds()), Qt::QueuedConnection);
       
   771     query->start();
       
   772 
       
   773     if (d_ptr->m_queryThread) {
       
   774         // Don't delete the previous thread object immediately
       
   775         if (!d_ptr->m_obsoleteThreads.isEmpty()) {
       
   776             qDeleteAll(d_ptr->m_obsoleteThreads);
       
   777             d_ptr->m_obsoleteThreads.clear();
       
   778         }
       
   779         d_ptr->m_obsoleteThreads.append(d_ptr->m_queryThread);
       
   780     }
       
   781     d_ptr->m_queryThread = query;
       
   782 #endif
       
   783     return true;
       
   784 }
       
   785 
       
   786 bool QMessageService::countMessages(const QMessageFilter &filter)
       
   787 {
       
   788     if (d_ptr->_active) {
       
   789         qWarning() << "Service is currently busy";
       
   790         return false;
       
   791     }
       
   792     d_ptr->_active = true;
       
   793     d_ptr->_error = QMessageManager::NoError;
       
   794     d_ptr->_state = QMessageService::ActiveState;
       
   795     emit stateChanged(d_ptr->_state);
       
   796 
       
   797     // Perform the query in another thread to keep the UI thread free
       
   798     QueryThread *query = new QueryThread(d_ptr, filter, QString(), QMessageDataComparator::MatchFlags(), QMessageSortOrder(), 0, 0);
       
   799     connect(query, SIGNAL(completed()), d_ptr, SLOT(reportMessagesCounted()), Qt::QueuedConnection);
       
   800     query->start();
       
   801 
       
   802     if (d_ptr->m_queryThread) {
       
   803         // Don't delete the previous thread object immediately
       
   804         if (!d_ptr->m_obsoleteThreads.isEmpty()) {
       
   805             qDeleteAll(d_ptr->m_obsoleteThreads);
       
   806         }
       
   807         d_ptr->m_obsoleteThreads.append(d_ptr->m_queryThread);
       
   808     }
       
   809     d_ptr->m_queryThread = query;
       
   810 
       
   811     return true;
       
   812 }
       
   813 
       
   814 bool QMessageService::send(QMessage &message)
       
   815 {
       
   816     if(d_ptr->_active) {
       
   817         qWarning() << "Service is currently busy";
       
   818         return false;
       
   819     }
       
   820 
       
   821     d_ptr->_active = true;
       
   822     d_ptr->_state = QMessageService::ActiveState;
       
   823     d_ptr->_error = QMessageManager::NoError;
       
   824     emit stateChanged(d_ptr->_state);
       
   825 
       
   826     bool result = d_ptr->send(message);
       
   827     d_ptr->setFinished(result);
       
   828 
       
   829     return result;
       
   830 }
       
   831 
       
   832 bool QMessageService::compose(const QMessage &message)
       
   833 {
       
   834     if(d_ptr->_active) {
       
   835         qWarning() << "Service is currently busy";
       
   836         return false;
       
   837     }
       
   838 
       
   839     d_ptr->_active = true;
       
   840     d_ptr->_state = QMessageService::ActiveState;
       
   841     d_ptr->_error = QMessageManager::NoError;
       
   842     emit stateChanged(d_ptr->_state);
       
   843 
       
   844     bool result = d_ptr->send(message,true);
       
   845     d_ptr->setFinished(result);
       
   846 
       
   847     return result;
       
   848 }
       
   849 
       
   850 bool QMessageService::retrieveHeader(const QMessageId& id)
       
   851 {
       
   852     Q_UNUSED(id);
       
   853 
       
   854     if(d_ptr->_active) {
       
   855         qWarning() << "Service is currently busy";
       
   856         return false;
       
   857     }
       
   858 
       
   859     d_ptr->_error = QMessageManager::NoError;
       
   860     d_ptr->setFinished(true);
       
   861 
       
   862     return true;
       
   863 }
       
   864 
       
   865 bool QMessageService::retrieveBody(const QMessageId& id)
       
   866 {
       
   867 
       
   868     if(d_ptr->_active) {
       
   869         qWarning() << "Service is currently busy";
       
   870         return false;
       
   871     }
       
   872 
       
   873 #ifdef _WIN32_WCE
       
   874 
       
   875     d_ptr->_active = true;
       
   876     d_ptr->_state = ActiveState;
       
   877     d_ptr->_error = QMessageManager::NoError;
       
   878     emit stateChanged(d_ptr->_state);
       
   879 
       
   880     if(!id.isValid())
       
   881     {
       
   882         qWarning() << "Invalid QMessageId";
       
   883         d_ptr->_error = QMessageManager::InvalidId;
       
   884     }
       
   885 
       
   886     QMessage message;
       
   887 
       
   888     if(d_ptr->_error == QMessageManager::NoError)
       
   889     {
       
   890         message = QMessage(id);
       
   891         d_ptr->_error = QMessageManager().error();
       
   892     }
       
   893 
       
   894 
       
   895     if(d_ptr->_error == QMessageManager::NoError)
       
   896         d_ptr->retrieveBody(message);
       
   897 
       
   898     //emit failure immediately
       
   899     if (d_ptr->_error != QMessageManager::NoError) {
       
   900         d_ptr->setFinished(false);
       
   901         return false;
       
   902     }
       
   903 
       
   904     return true;
       
   905 
       
   906 #else
       
   907     Q_UNUSED(id);
       
   908 
       
   909     d_ptr->_error = QMessageManager::NotYetImplemented;
       
   910     d_ptr->setFinished(false);
       
   911     return false;
       
   912 #endif
       
   913 }
       
   914 
       
   915 bool QMessageService::retrieve(const QMessageId& messageId, const QMessageContentContainerId& id)
       
   916 {
       
   917 
       
   918     if(d_ptr->_active) {
       
   919         qWarning() << "Service is currently busy";
       
   920         return false;
       
   921     }
       
   922 
       
   923 #ifdef _WIN32_WCE
       
   924 
       
   925     d_ptr->_active = true;
       
   926     d_ptr->_state = ActiveState;
       
   927     d_ptr->_error = QMessageManager::NoError;
       
   928     emit stateChanged(d_ptr->_state);
       
   929 
       
   930     if(!messageId.isValid())
       
   931     {
       
   932         qWarning() << "Invalid QMessageId";
       
   933         d_ptr->_error = QMessageManager::InvalidId;
       
   934     }
       
   935 
       
   936     QMessage message;
       
   937 
       
   938     if(d_ptr->_error == QMessageManager::NoError)
       
   939     {
       
   940         message = QMessage(messageId);
       
   941         d_ptr->_error = d_ptr->_manager.error();
       
   942     }
       
   943 
       
   944     if(d_ptr->_error == QMessageManager::NoError)
       
   945     {
       
   946         bool isBodyContainer = message.bodyId() == id;
       
   947         if(isBodyContainer)
       
   948             d_ptr->retrieveBody(message);
       
   949         //TODO downloading attachment programatically possible?
       
   950     }
       
   951 
       
   952     //emit failure immediately
       
   953     if (d_ptr->_error != QMessageManager::NoError) {
       
   954         d_ptr->setFinished(false);
       
   955         return false;
       
   956     }
       
   957 
       
   958     return true;
       
   959 
       
   960 #else
       
   961     Q_UNUSED(messageId)
       
   962     Q_UNUSED(id)
       
   963 
       
   964     d_ptr->_error = QMessageManager::NotYetImplemented;
       
   965     d_ptr->setFinished(false);
       
   966 #endif
       
   967 
       
   968     return false;
       
   969 }
       
   970 
       
   971 bool QMessageService::show(const QMessageId& id)
       
   972 {
       
   973     if(d_ptr->_active) {
       
   974         qWarning() << "Service is currently busy";
       
   975         return false;
       
   976     }
       
   977 
       
   978     d_ptr->_active = true;
       
   979     d_ptr->_state = ActiveState;
       
   980     d_ptr->_error = QMessageManager::NoError;
       
   981     emit stateChanged(d_ptr->_state);
       
   982 
       
   983     bool result = d_ptr->show(id);
       
   984     d_ptr->setFinished(result);
       
   985 
       
   986     return result;
       
   987 }
       
   988 
       
   989 bool QMessageService::exportUpdates(const QMessageAccountId &id)
       
   990 {
       
   991     Q_UNUSED(id);
       
   992 
       
   993     if(d_ptr->_active) {
       
   994         qWarning() << "Service is currently busy";
       
   995         return false;
       
   996     }
       
   997 
       
   998     d_ptr->_error = QMessageManager::NotYetImplemented;
       
   999     d_ptr->setFinished(false);
       
  1000 
       
  1001     return false;
       
  1002 }
       
  1003 
       
  1004 QMessageService::State QMessageService::state() const
       
  1005 {
       
  1006     return d_ptr->_state;
       
  1007 }
       
  1008 
       
  1009 void QMessageService::cancel()
       
  1010 {
       
  1011 #ifdef _WIN32_WCE
       
  1012     if(d_ptr->_active)
       
  1013     {
       
  1014         bool awaitingBodyRetrieval(d_ptr->m_bodyDownloadFilterId != 0);
       
  1015 
       
  1016         if(awaitingBodyRetrieval)
       
  1017         {
       
  1018             d_ptr->unregisterUpdates();
       
  1019             d_ptr->_error = QMessageManager::NoError;
       
  1020             d_ptr->_state = QMessageService::InactiveState;
       
  1021             d_ptr->_active = false;
       
  1022             emit stateChanged(d_ptr->_state);
       
  1023         }
       
  1024     }
       
  1025 #else
       
  1026     //NOOP
       
  1027 #endif
       
  1028 }
       
  1029 
       
  1030 QMessageManager::Error QMessageService::error() const
       
  1031 {
       
  1032     return d_ptr->_error;
       
  1033 }
       
  1034 
       
  1035 #include <qmessageservice_win.moc>
       
  1036 
       
  1037 QTM_END_NAMESPACE