qtmobility/tests/auto/support/support_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 "support.h"
       
    43 #include <qmessageaccountid.h>
       
    44 #include <qmessagefolderid.h>
       
    45 #include <qmessageid.h>
       
    46 #include <qmessage_p.h>
       
    47 #include <qmessagemanager.h>
       
    48 #include <QDataStream>
       
    49 #include <QFile>
       
    50 #include <QVector>
       
    51 #include <QDebug>
       
    52 
       
    53 #include <mapix.h>
       
    54 #include <Mapidefs.h>
       
    55 #include <Mapitags.h>
       
    56 #include <MAPIUtil.h>
       
    57 #ifdef _WIN32_WCE
       
    58 #include <cemapi.h>
       
    59 #endif
       
    60 
       
    61 // Missing definitions
       
    62 #ifndef PR_PST_CONFIG_FLAGS
       
    63 #define PR_PST_CONFIG_FLAGS PROP_TAG( PT_LONG, 0x6770 )
       
    64 #endif
       
    65 #ifndef PST_CONFIG_UNICODE
       
    66 #define PST_CONFIG_UNICODE 0x80000000
       
    67 #endif
       
    68 #ifndef PR_PST_PATH_A
       
    69 #define PR_PST_PATH_A PROP_TAG( PT_STRING8, 0x6700 )
       
    70 #endif
       
    71 
       
    72 namespace {
       
    73 
       
    74 class Lptstr : public QVector<TCHAR>
       
    75 {
       
    76 public:
       
    77     Lptstr(int length) : QVector<TCHAR>(length){}
       
    78     operator TCHAR* (){ return QVector<TCHAR>::data(); }
       
    79 };
       
    80 
       
    81 Lptstr LptstrFromQString(const QString &src)
       
    82 {
       
    83     uint length(src.length());
       
    84     Lptstr dst(length+1);
       
    85 
       
    86     const quint16 *data = src.utf16();
       
    87     const quint16 *it = data, *end = data + length;
       
    88     TCHAR *oit = dst;
       
    89     for ( ; it != end; ++it, ++oit) {
       
    90         *oit = static_cast<TCHAR>(*it);
       
    91     }
       
    92     *oit = TCHAR('\0');
       
    93     return dst;
       
    94 }
       
    95 
       
    96 QString QStringFromLptstr(LPCTSTR data)
       
    97 {
       
    98     if (!data)
       
    99         return QString();
       
   100 
       
   101     return QString::fromUtf16(reinterpret_cast<const quint16*>(data));
       
   102 }
       
   103 
       
   104 class QueryAllRows
       
   105 {
       
   106     static const int BatchSize = 20;
       
   107 public:
       
   108     QueryAllRows(LPMAPITABLE ptable,
       
   109                  LPSPropTagArray ptaga,
       
   110                  LPSRestriction pres,
       
   111                  LPSSortOrderSet psos,
       
   112                  bool setPosition = true);
       
   113     ~QueryAllRows();
       
   114 
       
   115     bool query();
       
   116     LPSRowSet rows() const;
       
   117     QMessageManager::Error error() const;
       
   118 
       
   119 private:
       
   120     LPMAPITABLE m_table;
       
   121     LPSPropTagArray m_tagArray;
       
   122     LPSRestriction m_restriction;
       
   123     LPSSortOrderSet m_sortOrderSet;
       
   124     LPSRowSet m_rows;
       
   125     QMessageManager::Error m_error;
       
   126 };
       
   127 
       
   128 QueryAllRows::QueryAllRows(LPMAPITABLE ptable,
       
   129                                LPSPropTagArray ptaga,
       
   130                                LPSRestriction pres,
       
   131                                LPSSortOrderSet psos,
       
   132                                bool setPosition)
       
   133     :
       
   134         m_table(ptable),
       
   135         m_tagArray(ptaga),
       
   136         m_restriction(pres),
       
   137         m_sortOrderSet(psos),
       
   138         m_rows(0),
       
   139         m_error(QMessageManager::NoError)
       
   140 {
       
   141 #ifndef _WIN32_WCE
       
   142     const ULONG options(TBL_BATCH);
       
   143 #else
       
   144     const ULONG options(0);
       
   145 #endif
       
   146 
       
   147     bool initFailed = false;
       
   148 
       
   149     initFailed |= FAILED(m_table->SetColumns(m_tagArray, options));
       
   150 
       
   151     if(m_restriction)
       
   152         initFailed |= FAILED(m_table->Restrict(m_restriction, options));
       
   153 
       
   154     if(m_sortOrderSet)
       
   155         initFailed |= FAILED(m_table->SortTable(m_sortOrderSet, options));
       
   156 
       
   157     if(setPosition)
       
   158         initFailed |= FAILED(m_table->SeekRow(BOOKMARK_BEGINNING, 0, NULL));
       
   159 
       
   160     if(initFailed) m_error = QMessageManager::ContentInaccessible;
       
   161 }
       
   162 
       
   163 QueryAllRows::~QueryAllRows()
       
   164 {
       
   165     FreeProws(m_rows);
       
   166     m_rows = 0;
       
   167 }
       
   168 
       
   169 bool QueryAllRows::query()
       
   170 {
       
   171     if(m_error != QMessageManager::NoError)
       
   172         return false;
       
   173 
       
   174     FreeProws(m_rows);
       
   175     m_rows = 0;
       
   176     m_error = QMessageManager::NoError;
       
   177 
       
   178     bool failed = FAILED(m_table->QueryRows( QueryAllRows::BatchSize, NULL, &m_rows));
       
   179 
       
   180     if(failed)
       
   181         m_error = QMessageManager::ContentInaccessible;
       
   182 
       
   183     if(failed || m_rows && !m_rows->cRows) return false;
       
   184 
       
   185     return true;
       
   186 }
       
   187 
       
   188 LPSRowSet QueryAllRows::rows() const
       
   189 {
       
   190     return m_rows;
       
   191 }
       
   192 
       
   193 QMessageManager::Error QueryAllRows::error() const
       
   194 {
       
   195     return m_error;
       
   196 }
       
   197 
       
   198 #ifndef _WIN32_WCE
       
   199 GUID GuidPublicStrings = { 0x00020329, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
       
   200 #else
       
   201 GUID GuidPSMAPI = { 0x00020328, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
       
   202 #endif
       
   203 
       
   204 void doInit()
       
   205 {
       
   206     static QMessageManager manager;
       
   207     Q_UNUSED(manager)
       
   208 }
       
   209 
       
   210 QByteArray binaryResult(const SPropValue &prop)
       
   211 {
       
   212     return QByteArray(reinterpret_cast<const char*>(prop.Value.bin.lpb), prop.Value.bin.cb);
       
   213 }
       
   214 
       
   215 #ifndef _WIN32_WCE
       
   216 IProfAdmin *openProfileAdmin()
       
   217 {
       
   218     IProfAdmin *profAdmin(0);
       
   219     HRESULT rv = MAPIAdminProfiles(0, &profAdmin);
       
   220     if (HR_FAILED(rv)) {
       
   221         qWarning() << "openProfileAdmin: MAPIAdminProfiles failed";
       
   222     }
       
   223 
       
   224     return profAdmin;
       
   225 }
       
   226 
       
   227 IMsgServiceAdmin *openServiceAdmin(const QByteArray &profileName, IProfAdmin *profAdmin)
       
   228 {
       
   229     IMsgServiceAdmin *svcAdmin(0);
       
   230 
       
   231     HRESULT rv = profAdmin->AdminServices(reinterpret_cast<LPTSTR>(const_cast<char*>(profileName.data())), 0, 0, 0, &svcAdmin);
       
   232     if (HR_FAILED(rv)) {
       
   233         qWarning() << "openServiceAdmin: AdminServices failed";
       
   234     }
       
   235 
       
   236     return svcAdmin;
       
   237 }
       
   238 
       
   239 typedef QPair<QByteArray, bool> ProfileDetail;
       
   240 
       
   241 QList<ProfileDetail> profileDetails(LPPROFADMIN profAdmin)
       
   242 {
       
   243     QList<ProfileDetail> result;
       
   244 
       
   245     LPMAPITABLE profileTable(0);
       
   246     HRESULT rv = profAdmin->GetProfileTable(0, &profileTable);
       
   247     if (HR_SUCCEEDED(rv)) {
       
   248 
       
   249         SizedSPropTagArray(2, cols) = {2, {PR_DISPLAY_NAME_A, PR_DEFAULT_PROFILE}};
       
   250 
       
   251         QueryAllRows qar(profileTable, reinterpret_cast<LPSPropTagArray>(&cols), NULL, NULL);
       
   252         while(qar.query()) {
       
   253             for (uint n = 0; n < qar.rows()->cRows; ++n) {
       
   254                 if (qar.rows()->aRow[n].lpProps[0].ulPropTag == PR_DISPLAY_NAME_A) {
       
   255                     QByteArray profileName(qar.rows()->aRow[n].lpProps[0].Value.lpszA);
       
   256                     bool defaultProfile(qar.rows()->aRow[n].lpProps[1].Value.b);
       
   257                     result.append(qMakePair(profileName, defaultProfile));
       
   258                 }
       
   259             }
       
   260         }
       
   261 
       
   262         if(qar.error() != QMessageManager::NoError)
       
   263             qWarning() << "profileNames: QueryAllRows failed";
       
   264 
       
   265         profileTable->Release();
       
   266 
       
   267     } else {
       
   268         qWarning() << "profileNames: GetProfileTable failed";
       
   269     }
       
   270 
       
   271     return result;
       
   272 }
       
   273 
       
   274 QByteArray findDefaultProfileName(IProfAdmin *profAdmin)
       
   275 {
       
   276     QByteArray defaultProfileName;
       
   277 
       
   278     foreach (const ProfileDetail &profile, profileDetails(profAdmin)) {
       
   279         if (profile.second) {
       
   280             defaultProfileName = profile.first;
       
   281             break;
       
   282         }
       
   283     }
       
   284 
       
   285     if (defaultProfileName.isEmpty()) {
       
   286         qWarning() << "findDefaultProfileName: no default profile!";
       
   287     }
       
   288 
       
   289     return defaultProfileName;
       
   290 }
       
   291 
       
   292 typedef QPair<QPair<QByteArray, QByteArray>, MAPIUID> ServiceDetail;
       
   293 
       
   294 QList<ServiceDetail> serviceDetails(LPSERVICEADMIN svcAdmin)
       
   295 {
       
   296     QList<ServiceDetail> result;
       
   297 
       
   298     IMAPITable *svcTable(0);
       
   299     HRESULT rv = svcAdmin->GetMsgServiceTable(0, &svcTable);
       
   300     if (HR_SUCCEEDED(rv)) {
       
   301 
       
   302         SizedSPropTagArray(3, cols) = {3, {PR_SERVICE_NAME_A, PR_DISPLAY_NAME_A, PR_SERVICE_UID}};
       
   303 
       
   304         QueryAllRows qar(svcTable, reinterpret_cast<LPSPropTagArray>(&cols), 0, 0);
       
   305         while(qar.query()) {
       
   306             for (uint n = 0; n < qar.rows()->cRows; ++n) {
       
   307                 if (qar.rows()->aRow[n].lpProps[0].ulPropTag == PR_SERVICE_NAME_A) {
       
   308                     QByteArray svcName(qar.rows()->aRow[n].lpProps[0].Value.lpszA);
       
   309                     QByteArray displayName;
       
   310                     if (qar.rows()->aRow[n].lpProps[1].ulPropTag == PR_DISPLAY_NAME_A) {
       
   311                         displayName = QByteArray(qar.rows()->aRow[n].lpProps[1].Value.lpszA);
       
   312                     }
       
   313                     MAPIUID svcUid(*(reinterpret_cast<MAPIUID*>(qar.rows()->aRow[n].lpProps[2].Value.bin.lpb)));
       
   314                     result.append(qMakePair(qMakePair(svcName, displayName), svcUid));
       
   315                 }
       
   316             }
       
   317         }
       
   318 
       
   319         if(qar.error() != QMessageManager::NoError)
       
   320             qWarning() << "serviceDetails: QueryAllRows failed";
       
   321 
       
   322         svcTable->Release();
       
   323 
       
   324     } else {
       
   325         qWarning() << "serviceDetails: GetMsgServiceTable failed";
       
   326     }
       
   327 
       
   328     return result;
       
   329 }
       
   330 #endif
       
   331 
       
   332 #ifndef _WIN32_WCE
       
   333 typedef QPair<QByteArray, QPair<QByteArray, QByteArray> > StoreDetail;
       
   334 #else
       
   335 typedef QPair<QString, QByteArray> StoreDetail;
       
   336 #endif
       
   337 
       
   338 QList<StoreDetail> storeDetails(LPMAPISESSION session)
       
   339 {
       
   340     QList<StoreDetail> result;
       
   341 
       
   342     IMAPITable *storesTable(0);
       
   343     HRESULT rv = session->GetMsgStoresTable(0, &storesTable);
       
   344     if (HR_SUCCEEDED(rv)) {
       
   345 #ifndef _WIN32_WCE
       
   346         SizedSPropTagArray(3, cols) = {3, {PR_DISPLAY_NAME_A, PR_RECORD_KEY, PR_ENTRYID}};
       
   347 #else
       
   348         SizedSPropTagArray(2, cols) = {2, {PR_DISPLAY_NAME, PR_ENTRYID}};
       
   349 #endif
       
   350 
       
   351         QueryAllRows qar(storesTable, reinterpret_cast<LPSPropTagArray>(&cols), 0, 0, false);
       
   352         while(qar.query()) {
       
   353             for (uint n = 0; n < qar.rows()->cRows; ++n) {
       
   354                 SPropValue *props(qar.rows()->aRow[n].lpProps);
       
   355                 if (props[0].ulPropTag == cols.aulPropTag[0]) {
       
   356 #ifndef _WIN32_WCE
       
   357                     QByteArray storeName(props[0].Value.lpszA);
       
   358                     QByteArray recordKey(binaryResult(props[1]));
       
   359                     QByteArray entryId(binaryResult(props[2]));
       
   360                     result.append(qMakePair(storeName, qMakePair(recordKey, entryId)));
       
   361 #else
       
   362                     QString storeName(QStringFromLptstr(props[0].Value.lpszW));
       
   363                     QByteArray entryId(binaryResult(props[1]));
       
   364                     result.append(qMakePair(storeName, entryId));
       
   365 #endif
       
   366                 }
       
   367             }
       
   368         }
       
   369 
       
   370         if(qar.error() != QMessageManager::NoError)
       
   371             qWarning() << "storeDetails: QueryAllRows failed";
       
   372 
       
   373         storesTable->Release();
       
   374     } else {
       
   375         qWarning() << "storeDetails: GetMsgStoresTable failed";
       
   376     }
       
   377 
       
   378     return result;
       
   379 }
       
   380 
       
   381 QMessageAccountId accountIdFromRecordKey(const QByteArray &recordKey)
       
   382 {
       
   383     QByteArray encodedId;
       
   384     {
       
   385         QDataStream encodedIdStream(&encodedId, QIODevice::WriteOnly);
       
   386         encodedIdStream << recordKey;
       
   387     }
       
   388 
       
   389     return QMessageAccountId(encodedId.toBase64());
       
   390 }
       
   391 
       
   392 QMessageFolderId folderIdFromProperties(const QByteArray &recordKey, const QByteArray &entryId, const QByteArray &storeKey)
       
   393 {
       
   394     QByteArray encodedId;
       
   395     {
       
   396         QDataStream encodedIdStream(&encodedId, QIODevice::WriteOnly);
       
   397 #ifndef _WIN32_WCE
       
   398         encodedIdStream << recordKey << storeKey;
       
   399         if (!entryId.isEmpty()) {
       
   400             encodedIdStream << entryId;
       
   401         }
       
   402 #else
       
   403         encodedIdStream << entryId << storeKey;
       
   404         if (!recordKey.isEmpty()) {
       
   405             encodedIdStream << recordKey;
       
   406         }
       
   407 #endif
       
   408     }
       
   409 
       
   410     return QMessageFolderId(encodedId.toBase64());
       
   411 }
       
   412 
       
   413 QByteArray objectProperty(IMAPIProp *object, ULONG tag)
       
   414 {
       
   415     QByteArray result;
       
   416 
       
   417     if (object) {
       
   418         SPropValue *prop(0);
       
   419         HRESULT rv = HrGetOneProp(object, tag, &prop);
       
   420         if (HR_SUCCEEDED(rv)) {
       
   421             result = binaryResult(*prop);
       
   422 
       
   423             MAPIFreeBuffer(prop);
       
   424         } else {
       
   425             qWarning() << "objectProperty: HrGetOneProp failed";
       
   426         }
       
   427     }
       
   428 
       
   429     return result;
       
   430 }
       
   431 
       
   432 QString stringProperty(IMAPIProp *object, ULONG tag)
       
   433 {
       
   434     QString result;
       
   435 
       
   436     if (object) {
       
   437         SPropValue *prop(0);
       
   438         HRESULT rv = HrGetOneProp(object, tag, &prop);
       
   439         if (HR_SUCCEEDED(rv)) {
       
   440             result = QString::fromUtf16(reinterpret_cast<quint16*>(prop->Value.LPSZ));
       
   441 
       
   442             MAPIFreeBuffer(prop);
       
   443         } else if (rv != MAPI_E_NOT_FOUND) {
       
   444             qWarning() << "stringProperty: HrGetOneProp failed";
       
   445         }
       
   446     }
       
   447 
       
   448     return result;
       
   449 }
       
   450 
       
   451 ULONG createNamedProperty(IMAPIProp *object, const QString &name)
       
   452 {
       
   453     ULONG result = 0;
       
   454 
       
   455     if (!name.isEmpty()) {
       
   456         Lptstr nameBuffer = LptstrFromQString(name);
       
   457 
       
   458         MAPINAMEID propName = { 0 };
       
   459 #ifndef _WIN32_WCE
       
   460         propName.lpguid = &GuidPublicStrings;
       
   461 #else
       
   462         propName.lpguid = &GuidPSMAPI;
       
   463 #endif
       
   464         propName.ulKind = MNID_STRING;
       
   465         propName.Kind.lpwstrName = nameBuffer;
       
   466 
       
   467         LPMAPINAMEID propNames = &propName;
       
   468 
       
   469         SPropTagArray *props;
       
   470         HRESULT rv = object->GetIDsFromNames(1, &propNames, MAPI_CREATE, &props);
       
   471         if (HR_SUCCEEDED(rv)) {
       
   472             result = props->aulPropTag[0] | PT_UNICODE;
       
   473 
       
   474             MAPIFreeBuffer(props);
       
   475         } else {
       
   476             qWarning() << "createNamedProperty: GetIDsFromNames failed";
       
   477         }
       
   478     }
       
   479 
       
   480     return result;
       
   481 }
       
   482 
       
   483 ULONG getNamedPropertyTag(IMAPIProp *object, const QString &name)
       
   484 {
       
   485     ULONG result = 0;
       
   486 
       
   487     if (!name.isEmpty()) {
       
   488         Lptstr nameBuffer = LptstrFromQString(name);
       
   489 
       
   490         MAPINAMEID propName = { 0 };
       
   491 #ifndef _WIN32_WCE
       
   492         propName.lpguid = &GuidPublicStrings;
       
   493 #else
       
   494         propName.lpguid = &GuidPSMAPI;
       
   495 #endif
       
   496         propName.ulKind = MNID_STRING;
       
   497         propName.Kind.lpwstrName = nameBuffer;
       
   498 
       
   499         LPMAPINAMEID propNames = &propName;
       
   500 
       
   501         SPropTagArray *props;
       
   502         HRESULT rv = object->GetIDsFromNames(1, &propNames, 0, &props);
       
   503         if (HR_SUCCEEDED(rv)) {
       
   504             if (props->aulPropTag[0] != PT_ERROR) {
       
   505                 result = props->aulPropTag[0] | PT_UNICODE;
       
   506             }
       
   507 
       
   508             MAPIFreeBuffer(props);
       
   509         } else {
       
   510             qWarning() << "getNamedPropertyTag: GetIDsFromNames failed";
       
   511         }
       
   512     }
       
   513 
       
   514     return result;
       
   515 }
       
   516 
       
   517 bool setNamedProperty(IMAPIProp *object, ULONG tag, const QString &value)
       
   518 {
       
   519     if (object && tag && !value.isEmpty()) {
       
   520         SPropValue prop = { 0 };
       
   521         prop.ulPropTag = tag;
       
   522         prop.Value.LPSZ = reinterpret_cast<LPTSTR>(const_cast<quint16*>(value.utf16()));
       
   523 
       
   524         HRESULT rv = object->SetProps(1, &prop, 0);
       
   525         if (HR_SUCCEEDED(rv)) {
       
   526             return true;
       
   527         } else {
       
   528             qWarning() << "setNamedProperty: SetProps failed";
       
   529         }
       
   530     }
       
   531 
       
   532     return false;
       
   533 }
       
   534 
       
   535 QString getNamedProperty(IMAPIProp *object, ULONG tag)
       
   536 {
       
   537     QString result;
       
   538 
       
   539     if (object && tag) {
       
   540         SPropValue *prop(0);
       
   541         HRESULT rv = HrGetOneProp(object, tag, &prop);
       
   542         if (HR_SUCCEEDED(rv)) {
       
   543             result = QString::fromUtf16(reinterpret_cast<quint16*>(prop->Value.LPSZ));
       
   544 
       
   545             MAPIFreeBuffer(prop);
       
   546         } else if (rv != MAPI_E_NOT_FOUND) {
       
   547             qWarning() << "getNamedProperty: HrGetOneProp failed";
       
   548         }
       
   549     }
       
   550 
       
   551     return result;
       
   552 }
       
   553 
       
   554 #ifndef _WIN32_WCE
       
   555 IProviderAdmin *serviceProvider(const MAPIUID &svcUid, LPSERVICEADMIN svcAdmin)
       
   556 {
       
   557     IProviderAdmin *provider(0);
       
   558 
       
   559     if (svcAdmin) {
       
   560         HRESULT rv = svcAdmin->AdminProviders(const_cast<MAPIUID*>(&svcUid), 0, &provider);
       
   561         if (HR_FAILED(rv)) {
       
   562             provider = 0;
       
   563             qWarning() << "serviceProvider: AdminProviders failed";
       
   564         }
       
   565     }
       
   566 
       
   567     return provider;
       
   568 }
       
   569 
       
   570 MAPIUID findProviderUid(const QByteArray &name, IProviderAdmin *providerAdmin)
       
   571 {
       
   572     MAPIUID result = { 0 };
       
   573     IMAPITable *providerTable(0);
       
   574     HRESULT rv = providerAdmin->GetProviderTable(0, &providerTable);
       
   575     if (HR_SUCCEEDED(rv)) {
       
   576 
       
   577         SizedSPropTagArray(2, cols) = {2, {PR_SERVICE_NAME_A, PR_PROVIDER_UID}};
       
   578 
       
   579         QueryAllRows qar(providerTable, reinterpret_cast<LPSPropTagArray>(&cols), 0, 0);
       
   580         while(qar.query()) {
       
   581             for (uint n = 0; n < qar.rows()->cRows; ++n) {
       
   582                 SPropValue *props(qar.rows()->aRow[n].lpProps);
       
   583                 if (props[0].ulPropTag == PR_SERVICE_NAME_A) {
       
   584                     QByteArray serviceName(props[0].Value.lpszA);
       
   585                     if (name.isEmpty() || (serviceName.toLower() == name.toLower())) {
       
   586                         result = *(reinterpret_cast<MAPIUID*>(props[1].Value.bin.lpb));
       
   587                         break;
       
   588                     }
       
   589                 }
       
   590             }
       
   591         }
       
   592 
       
   593         if(qar.error() != QMessageManager::NoError)
       
   594             qWarning() << "findProviderUid: QueryAllRows failed";
       
   595 
       
   596         providerTable->Release();
       
   597     } else {
       
   598         qWarning() << "findProviderUid: GetProviderTable failed";
       
   599     }
       
   600 
       
   601     return result;
       
   602 }
       
   603 
       
   604 IProfSect *openProfileSection(const MAPIUID &providerUid, IProviderAdmin *providerAdmin)
       
   605 {
       
   606     IProfSect *profileSection(0);
       
   607 
       
   608     // Bypass the MAPI_E_NO_ACCESS_ERROR, as described at http://support.microsoft.com/kb/822977
       
   609     const ULONG MAPI_FORCE_ACCESS = 0x00080000;
       
   610 
       
   611     HRESULT rv = providerAdmin->OpenProfileSection(const_cast<MAPIUID*>(&providerUid), 0, MAPI_FORCE_ACCESS, &profileSection);
       
   612     if (HR_FAILED(rv)) {
       
   613         qWarning() << "openProfileSection: OpenProfileSection failed";
       
   614         profileSection = 0;
       
   615     }
       
   616 
       
   617     return profileSection;
       
   618 }
       
   619 
       
   620 template<typename T>
       
   621 bool isEmpty(const T &v)
       
   622 {
       
   623     const char empty[sizeof(T)] = { 0 };
       
   624     return (memcmp(empty, &v, sizeof(T)) == 0);
       
   625 }
       
   626 
       
   627 bool deleteExistingService(const MAPIUID &svcUid, LPSERVICEADMIN svcAdmin)
       
   628 {
       
   629     if (svcAdmin) {
       
   630         QByteArray storePath;
       
   631 
       
   632         // Find the Provider for this service
       
   633         IProviderAdmin *provider = serviceProvider(svcUid, svcAdmin);
       
   634         if (provider) {
       
   635             MAPIUID providerUid = findProviderUid("MSUPST MS", provider);
       
   636             if (!isEmpty(providerUid)) {
       
   637                 IProfSect *profileSection = openProfileSection(providerUid, provider);
       
   638                 if (profileSection) {
       
   639                     SPropValue *prop(0);
       
   640                     HRESULT rv = HrGetOneProp(profileSection, PR_PST_PATH_A, &prop);
       
   641                     if (HR_SUCCEEDED(rv)) {
       
   642                         storePath = QByteArray(prop->Value.lpszA);
       
   643 
       
   644                         MAPIFreeBuffer(prop);
       
   645                     } else {
       
   646                         qWarning() << "deleteExistingService: HrGetOneProp failed";
       
   647                     }
       
   648 
       
   649                     profileSection->Release();
       
   650                 }
       
   651             }
       
   652 
       
   653             provider->Release();
       
   654         }
       
   655 
       
   656         if (!storePath.isEmpty()) {
       
   657             // Delete the existing service
       
   658             HRESULT rv = svcAdmin->DeleteMsgService(const_cast<MAPIUID*>(&svcUid));
       
   659             if (HR_SUCCEEDED(rv)) {
       
   660                 // Delete the storage file
       
   661                 if (QFile::exists(storePath)) {
       
   662                     if (!QFile::remove(storePath)) {
       
   663                         qWarning() << "deleteExistingService: Unable to remove PST file at:" << storePath;
       
   664                     }
       
   665                 }
       
   666                 return true;
       
   667             } else {
       
   668                 qWarning() << "deleteExistingService: DeleteMsgService failed";
       
   669             }
       
   670         }
       
   671     }
       
   672 
       
   673     return false;
       
   674 }
       
   675 
       
   676 QByteArray defaultProfile()
       
   677 {
       
   678     QByteArray result;
       
   679 
       
   680     LPPROFADMIN profAdmin(0);
       
   681     HRESULT rv = MAPIAdminProfiles(0, &profAdmin);
       
   682     if (HR_SUCCEEDED(rv)) {
       
   683         // Find the default profile
       
   684         foreach (const ProfileDetail &profile, profileDetails(profAdmin)) {
       
   685             if (profile.second) {
       
   686                 result = profile.first;
       
   687                 break;
       
   688             }
       
   689         }
       
   690     } else {
       
   691         qWarning() << "defaultProfile: MAPIAdminProfiles failed";
       
   692     }
       
   693     return result;
       
   694 }
       
   695 
       
   696 IMAPISession *profileSession(const QByteArray &profileName)
       
   697 {
       
   698     IMAPISession *session(0);
       
   699 
       
   700     if (!profileName.isEmpty()) {
       
   701         // Open a session on the profile
       
   702         QByteArray name(profileName);
       
   703         HRESULT rv = MAPILogonEx(0, reinterpret_cast<LPTSTR>(name.data()), 0, MAPI_EXTENDED | MAPI_NEW_SESSION | MAPI_NO_MAIL, &session);
       
   704         if (HR_FAILED(rv)) {
       
   705             session = 0;
       
   706             qWarning() << "profileSession: MAPILogonEx failed";
       
   707         }
       
   708     }
       
   709 
       
   710     return session;
       
   711 }
       
   712 #endif
       
   713 
       
   714 #ifndef _WIN32_WCE
       
   715 IMAPISession *defaultSession() { return profileSession(defaultProfile()); }
       
   716 #else
       
   717 ICEMAPISession *defaultSession()
       
   718 {
       
   719     ICEMAPISession *session(0);
       
   720 
       
   721     // Open a session on the profile
       
   722     HRESULT rv = MAPILogonEx(0, 0, 0, 0, reinterpret_cast<LPMAPISESSION*>(&session));
       
   723     if (HR_FAILED(rv)) {
       
   724         session = 0;
       
   725         qWarning() << "defaultSession: MAPILogonEx failed";
       
   726     }
       
   727 
       
   728     return session;
       
   729 }
       
   730 #endif
       
   731 
       
   732 #ifdef _WIN32_WCE
       
   733 bool deleteExistingStore(const QByteArray &entryId, ICEMAPISession *session)
       
   734 {
       
   735     if (session) {
       
   736         HRESULT rv = session->DeleteMsgStore(entryId.count(), reinterpret_cast<LPENTRYID>(const_cast<char*>(entryId.data())));
       
   737         if (HR_SUCCEEDED(rv)) {
       
   738             return true;
       
   739         } else {
       
   740             qWarning() << "deleteExistingStore: DeleteMsgStore failed";
       
   741         }
       
   742     }
       
   743 
       
   744     return false;
       
   745 }
       
   746 #endif
       
   747 
       
   748 IMsgStore *openStore(const QByteArray &entryId, IMAPISession* session)
       
   749 {
       
   750     IMsgStore *store(0);
       
   751 
       
   752     if (session && !entryId.isEmpty()) {
       
   753         HRESULT rv = session->OpenMsgStore(0, entryId.length(), reinterpret_cast<LPENTRYID>(const_cast<char*>(entryId.data())), 0, MDB_NO_MAIL | MDB_WRITE, reinterpret_cast<LPMDB*>(&store));
       
   754         if (HR_FAILED(rv)) {
       
   755             store = 0;
       
   756             qWarning() << "openStore: OpenMsgStore failed";
       
   757         }
       
   758     }
       
   759 
       
   760     return store;
       
   761 }
       
   762 
       
   763 #ifndef _WIN32_WCE
       
   764 IMsgStore *openStoreByName(const QByteArray &storeName, IMAPISession* session)
       
   765 #else
       
   766 IMsgStore *openStoreByName(const QString &storeName, IMAPISession* session)
       
   767 #endif
       
   768 {
       
   769     IMsgStore *store(0);
       
   770 
       
   771     if (session && !storeName.isEmpty()) {
       
   772         QByteArray entryId;
       
   773 
       
   774         // Find the store with the specified name
       
   775         IMAPITable *storesTable(0);
       
   776         HRESULT rv = session->GetMsgStoresTable(0, &storesTable);
       
   777         if (HR_SUCCEEDED(rv)) {
       
   778 #ifndef _WIN32_WCE
       
   779             SizedSPropTagArray(2, cols) = {2, {PR_DISPLAY_NAME_A, PR_ENTRYID}};
       
   780 #else
       
   781             SizedSPropTagArray(2, cols) = {2, {PR_DISPLAY_NAME, PR_ENTRYID}};
       
   782 #endif
       
   783 
       
   784             QueryAllRows qar(storesTable, reinterpret_cast<LPSPropTagArray>(&cols), 0, 0, false);
       
   785             while(qar.query()) {
       
   786                 for (uint n = 0; n < qar.rows()->cRows; ++n) {
       
   787                     if (qar.rows()->aRow[n].lpProps[0].ulPropTag == cols.aulPropTag[0]) {
       
   788 #ifndef _WIN32_WCE
       
   789                         QByteArray name(qar.rows()->aRow[n].lpProps[0].Value.lpszA);
       
   790 #else
       
   791                         QString name(QStringFromLptstr(qar.rows()->aRow[n].lpProps[0].Value.lpszW));
       
   792 #endif
       
   793                         if (name.toLower() == storeName.toLower()) {
       
   794                             entryId = binaryResult(qar.rows()->aRow[n].lpProps[1]);
       
   795                             break;
       
   796                         }
       
   797                     }
       
   798                 }
       
   799             }
       
   800 
       
   801             if(qar.error() != QMessageManager::NoError)
       
   802                 qWarning() << "openStoreByName: QueryAllRows failed";
       
   803 
       
   804             storesTable->Release();
       
   805         } else {
       
   806             qWarning() << "openStoreByName: GetMsgStoresTable failed";
       
   807         }
       
   808 
       
   809         if (!entryId.isEmpty()) {
       
   810             store = openStore(entryId, session);
       
   811         }
       
   812     }
       
   813 
       
   814     return store;
       
   815 }
       
   816 
       
   817 QByteArray rootFolderEntryId(IMsgStore *store)
       
   818 {
       
   819     return objectProperty(store, PR_IPM_SUBTREE_ENTRYID);
       
   820 }
       
   821 
       
   822 IMAPIFolder *openFolder(const QByteArray &entryId, IMsgStore *store)
       
   823 {
       
   824     IMAPIFolder *folder(0);
       
   825 
       
   826     if (store && !entryId.isEmpty()) {
       
   827         ULONG type(0);
       
   828         QByteArray entry(entryId);
       
   829         HRESULT rv = store->OpenEntry(entry.length(), reinterpret_cast<LPENTRYID>(entry.data()), 0, MAPI_MODIFY, &type, reinterpret_cast<LPUNKNOWN*>(&folder));
       
   830         if (HR_FAILED(rv)) {
       
   831             folder = 0;
       
   832             qWarning() << "openFolder: OpenEntry failed";
       
   833         }
       
   834     }
       
   835 
       
   836     return folder;
       
   837 }
       
   838 
       
   839 IMAPIFolder *openFolder(const QByteArray &entryId, IMAPIFolder *container)
       
   840 {
       
   841     IMAPIFolder *folder(0);
       
   842 
       
   843     if (container && !entryId.isEmpty()) {
       
   844         ULONG type(0);
       
   845         QByteArray entry(entryId);
       
   846         HRESULT rv = container->OpenEntry(entry.length(), reinterpret_cast<LPENTRYID>(entry.data()), 0, MAPI_MODIFY, &type, reinterpret_cast<LPUNKNOWN*>(&folder));
       
   847         if (HR_FAILED(rv)) {
       
   848             folder = 0;
       
   849             qWarning() << "openFolder: OpenEntry failed";
       
   850         }
       
   851     }
       
   852 
       
   853     return folder;
       
   854 }
       
   855 
       
   856 QList<QByteArray> subFolderEntryIds(IMAPIFolder *folder)
       
   857 {
       
   858     QList<QByteArray> result;
       
   859 
       
   860     if (folder) {
       
   861         IMAPITable *hierarchyTable(0);
       
   862         HRESULT rv = folder->GetHierarchyTable(MAPI_UNICODE, &hierarchyTable);
       
   863         if (HR_SUCCEEDED(rv)) {
       
   864 #ifndef _WIN32_WCE
       
   865             SizedSPropTagArray(2, cols) = {2, {PR_OBJECT_TYPE, PR_ENTRYID}};
       
   866 #else
       
   867             SizedSPropTagArray(1, cols) = {1, {PR_ENTRYID}};
       
   868 #endif
       
   869 
       
   870             QueryAllRows qar(hierarchyTable, reinterpret_cast<LPSPropTagArray>(&cols), NULL, NULL, false);
       
   871             while(qar.query()) {
       
   872                 for (uint n = 0; n < qar.rows()->cRows; ++n) {
       
   873 #ifndef _WIN32_WCE
       
   874                     if ((qar.rows()->aRow[n].lpProps[0].ulPropTag == PR_OBJECT_TYPE) &&
       
   875                         (qar.rows()->aRow[n].lpProps[0].Value.l == MAPI_FOLDER)) {
       
   876                         result.append(binaryResult(qar.rows()->aRow[n].lpProps[1]));
       
   877                     }
       
   878 #else
       
   879                     if (qar.rows()->aRow[n].lpProps[0].ulPropTag == PR_ENTRYID) {
       
   880                         result.append(binaryResult(qar.rows()->aRow[n].lpProps[0]));
       
   881                     }
       
   882 #endif
       
   883                 }
       
   884             }
       
   885 
       
   886             if(qar.error() != QMessageManager::NoError)
       
   887                 qWarning() << "subFolderEntryIds: QueryAllRows failed";
       
   888 
       
   889             hierarchyTable->Release();
       
   890         }
       
   891     }
       
   892 
       
   893     return result;
       
   894 }
       
   895 
       
   896 IMAPIFolder *subFolder(const QString &path, IMAPIFolder *folder, const QString &rootPath)
       
   897 {
       
   898     IMAPIFolder *result(0);
       
   899 
       
   900     if (folder && !path.isEmpty()) {
       
   901         // Find all folders in the current folder
       
   902         foreach (const QByteArray &entryId, subFolderEntryIds(folder)) {
       
   903             IMAPIFolder *childFolder = openFolder(entryId, folder);
       
   904             if (childFolder) {
       
   905                 QString childPath;
       
   906 
       
   907 #ifndef _WIN32_WCE
       
   908                 ULONG tag = getNamedPropertyTag(childFolder, "path");
       
   909                 if (tag) {
       
   910                     childPath = getNamedProperty(childFolder, tag);
       
   911                 }
       
   912 #else
       
   913                 // Folders do not support named properties on CE...
       
   914                 if (!rootPath.isEmpty()) {
       
   915                     childPath = rootPath + '/';
       
   916                 }
       
   917                 childPath += stringProperty(childFolder, PR_DISPLAY_NAME);
       
   918 #endif
       
   919 
       
   920                 if (childPath == path) {
       
   921                     // This is the folder we're looking for
       
   922                     result = childFolder;
       
   923                 } else if (path.startsWith(childPath)) {
       
   924                     // This must be a parent of the folder we're looking for
       
   925                     result = subFolder(path, childFolder, childPath);
       
   926                 }
       
   927 
       
   928                 if (childFolder != result) {
       
   929                     childFolder->Release();
       
   930                 }
       
   931             }
       
   932 
       
   933             if (result) {
       
   934                 break;
       
   935             }
       
   936         }
       
   937     }
       
   938 
       
   939     return result;
       
   940 
       
   941 #ifndef _WIN32_WCE
       
   942     Q_UNUSED(rootPath)
       
   943 #endif
       
   944 }
       
   945 
       
   946 IMAPIFolder *createFolder(const QString &name, IMAPIFolder *folder)
       
   947 {
       
   948     IMAPIFolder *newFolder(0);
       
   949 
       
   950     if (folder && !name.isEmpty()) {
       
   951         HRESULT rv = folder->CreateFolder(FOLDER_GENERIC, reinterpret_cast<LPTSTR>(const_cast<quint16*>(name.utf16())), 0, 0, MAPI_UNICODE, &newFolder);
       
   952         if (HR_FAILED(rv)) {
       
   953             newFolder = 0;
       
   954             qWarning() << "createFolder: CreateFolder failed";
       
   955         }
       
   956     }
       
   957 
       
   958     return newFolder;
       
   959 }
       
   960 
       
   961 QByteArray folderRecordKey(IMAPIFolder *folder)
       
   962 {
       
   963     return objectProperty(folder, PR_RECORD_KEY);
       
   964 }
       
   965 
       
   966 QByteArray folderEntryId(IMAPIFolder *folder)
       
   967 {
       
   968     return objectProperty(folder, PR_ENTRYID);
       
   969 }
       
   970 
       
   971 QByteArray storeRecordKey(IMsgStore *store)
       
   972 {
       
   973 #ifndef _WIN32_WCE
       
   974     return objectProperty(store, PR_RECORD_KEY);
       
   975 #else
       
   976     return objectProperty(store, PR_ENTRYID);
       
   977 #endif
       
   978 }
       
   979 
       
   980 }
       
   981 
       
   982 namespace Support {
       
   983 
       
   984 void clearMessageStore()
       
   985 {
       
   986     // Ensure the store is instantiated
       
   987     doInit();
       
   988 
       
   989     // Remove any existing stores that we added previously
       
   990 #ifndef _WIN32_WCE
       
   991     IProfAdmin *profAdmin = openProfileAdmin();
       
   992     if (profAdmin) {
       
   993         QByteArray defaultProfileName = findDefaultProfileName(profAdmin);
       
   994         if (!defaultProfileName.isEmpty()) {
       
   995             IMAPISession *session = profileSession(defaultProfileName);
       
   996             if (session) {
       
   997                 IMsgServiceAdmin *svcAdmin = openServiceAdmin(defaultProfileName, profAdmin);
       
   998                 if (svcAdmin) {
       
   999                     char *providerName = "MSUPST MS";
       
  1000                     QList<MAPIUID> obsoleteUids;
       
  1001 
       
  1002                     foreach (const ServiceDetail &svc, serviceDetails(svcAdmin)) {
       
  1003                         // Find all services that have our provider
       
  1004                         if (svc.first.first.toLower() == QByteArray(providerName).toLower()) {
       
  1005                             IMsgStore *store = openStoreByName(svc.first.second, session);
       
  1006                             if (store) {
       
  1007                                 // Did we create this store
       
  1008                                 ULONG tag = getNamedPropertyTag(store, "origin");
       
  1009                                 if (tag) {
       
  1010                                     if (getNamedProperty(store, tag) == "QMF") {
       
  1011                                         // This is an existing service we need to remove
       
  1012                                         obsoleteUids.append(svc.second);
       
  1013                                     }
       
  1014                                 }
       
  1015 
       
  1016                                 store->Release();
       
  1017                             }
       
  1018                         }
       
  1019                     }
       
  1020 
       
  1021                     foreach (const MAPIUID &uid, obsoleteUids) {
       
  1022                         deleteExistingService(uid, svcAdmin);
       
  1023                     }
       
  1024 
       
  1025                     svcAdmin->Release();
       
  1026                 }
       
  1027 
       
  1028                 session->Release();
       
  1029             }
       
  1030         }
       
  1031 
       
  1032         profAdmin->Release();
       
  1033     }
       
  1034 #else
       
  1035     ICEMAPISession *session = defaultSession();
       
  1036     if (session) {
       
  1037         QList<QByteArray> obsoleteEntryIds;
       
  1038 
       
  1039         foreach (const StoreDetail &detail, storeDetails(session)) {
       
  1040             IMsgStore *store = openStore(detail.second, session);
       
  1041             if (store) {
       
  1042                 // Did we create this store?
       
  1043                 ULONG tag = getNamedPropertyTag(store, "origin");
       
  1044                 if (tag) {
       
  1045                     if (getNamedProperty(store, tag) == "QMF") {
       
  1046                         // This is an existing store we need to remove
       
  1047                         obsoleteEntryIds.append(detail.second);
       
  1048                     }
       
  1049                 }
       
  1050 
       
  1051                 store->Release();
       
  1052             }
       
  1053         }
       
  1054 
       
  1055         foreach (const QByteArray &entryId, obsoleteEntryIds) {
       
  1056             deleteExistingStore(entryId, session);
       
  1057         }
       
  1058 
       
  1059         session->Release();
       
  1060     }
       
  1061 #endif
       
  1062 }
       
  1063 
       
  1064 QMessageAccountId addAccount(const Parameters &params)
       
  1065 {
       
  1066     QMessageAccountId result;
       
  1067 
       
  1068     doInit();
       
  1069 
       
  1070     QString accountName(params["name"]);
       
  1071     QString fromAddress(params["fromAddress"]);
       
  1072 
       
  1073     if (!accountName.isEmpty()) {
       
  1074         // Profile name must be ASCII
       
  1075         QByteArray name(accountName.toAscii());
       
  1076 
       
  1077 #ifndef _WIN32_WCE
       
  1078         // See if a profile exists with the given name
       
  1079         IProfAdmin *profAdmin = openProfileAdmin();
       
  1080         if (profAdmin) {
       
  1081             QByteArray defaultProfileName = findDefaultProfileName(profAdmin);
       
  1082             if (!defaultProfileName.isEmpty()) {
       
  1083                 IMAPISession *session = profileSession(defaultProfileName);
       
  1084                 if (session) {
       
  1085                     IMsgServiceAdmin *svcAdmin = openServiceAdmin(defaultProfileName, profAdmin);
       
  1086                     if (svcAdmin) {
       
  1087                         char *providerName = "MSUPST MS";
       
  1088                         QList<QByteArray> existingServices;
       
  1089 
       
  1090                         foreach (const ServiceDetail &svc, serviceDetails(svcAdmin)) {
       
  1091                             // Find all services that have our provider
       
  1092                             if (svc.first.first.toLower() == QByteArray(providerName).toLower()) {
       
  1093                                 existingServices.append(QByteArray(reinterpret_cast<const char*>(&svc.second), sizeof(MAPIUID)));
       
  1094                             }
       
  1095                         }
       
  1096 
       
  1097                         // Create a message service for this profile using the standard provider
       
  1098                         HRESULT rv = svcAdmin->CreateMsgService(reinterpret_cast<LPTSTR>(providerName), 0, 0, 0);
       
  1099                         if (HR_SUCCEEDED(rv)) {
       
  1100                             // Find which of the now-extant services was not in the previous set
       
  1101                             foreach (const ServiceDetail &svc, serviceDetails(svcAdmin)) {
       
  1102                                 QByteArray uidData(reinterpret_cast<const char*>(&svc.second), sizeof(MAPIUID));
       
  1103                                 if ((svc.first.first.toLower() == QByteArray(providerName).toLower()) &&
       
  1104                                     !existingServices.contains(uidData)) {
       
  1105                                     // Create a .PST message store for this service
       
  1106                                     QByteArray path(QString("%1.pst").arg(name.constData()).toAscii());
       
  1107 
       
  1108                                     SPropValue props[3] = { 0 };
       
  1109                                     props[0].ulPropTag = PR_DISPLAY_NAME_A;
       
  1110                                     props[0].Value.lpszA = name.data();
       
  1111                                     props[1].ulPropTag = PR_PST_PATH_A;
       
  1112                                     props[1].Value.lpszA = path.data();
       
  1113                                     props[2].ulPropTag = PR_PST_CONFIG_FLAGS;
       
  1114                                     props[2].Value.l = PST_CONFIG_UNICODE;
       
  1115 
       
  1116                                     MAPIUID svcUid = svc.second;
       
  1117                                     rv = svcAdmin->ConfigureMsgService(&svcUid, 0, 0, 3, props);
       
  1118                                     if (HR_SUCCEEDED(rv)) {
       
  1119                                         foreach (const StoreDetail &store, storeDetails(session)) {
       
  1120                                             if (store.first.toLower() == name.toLower()) {
       
  1121                                                 result = accountIdFromRecordKey(store.second.first);
       
  1122 
       
  1123                                                 IMsgStore *newStore = openStore(store.second.second, session);
       
  1124                                                 if (newStore) {
       
  1125                                                     // Add an origin tag to this store
       
  1126                                                     ULONG originTag = createNamedProperty(newStore, "origin");
       
  1127                                                     if (originTag) {
       
  1128                                                         setNamedProperty(newStore, originTag, "QMF");
       
  1129                                                     }
       
  1130 
       
  1131                                                     if (!fromAddress.isEmpty()) {
       
  1132                                                         // Try to set the address for this service, as a property of the store
       
  1133                                                         ULONG addressTag = createNamedProperty(newStore, "fromAddress");
       
  1134                                                         if (addressTag) {
       
  1135                                                             setNamedProperty(newStore, addressTag, fromAddress);
       
  1136                                                         }
       
  1137                                                     }
       
  1138 
       
  1139                                                     newStore->Release();
       
  1140                                                 }
       
  1141                                                 break;
       
  1142                                             }
       
  1143                                         }
       
  1144                                     } else {
       
  1145                                         qWarning() << "ConfigureMsgService failed";
       
  1146                                     }
       
  1147                                     break;
       
  1148                                 }
       
  1149                             }
       
  1150                         } else {
       
  1151                             qWarning() << "CreateMsgService failed";
       
  1152                         }
       
  1153 
       
  1154                         svcAdmin->Release();
       
  1155                     }
       
  1156 
       
  1157                     session->Release();
       
  1158                 }
       
  1159             }
       
  1160 
       
  1161             profAdmin->Release();
       
  1162         }
       
  1163 #else
       
  1164         ICEMAPISession *session(defaultSession());
       
  1165         if (session) {
       
  1166             QSet<QString> existingStoreNames;
       
  1167             foreach (const StoreDetail &detail, storeDetails(session)) {
       
  1168                 existingStoreNames.insert(detail.first);
       
  1169             }
       
  1170 
       
  1171             if (existingStoreNames.contains(accountName)) {
       
  1172                 qWarning() << "Store name already in use:" << accountName;
       
  1173             } else {
       
  1174                 IMsgStore *newStore(0);
       
  1175                 HRESULT rv = session->CreateMsgStore(reinterpret_cast<LPCWSTR>(accountName.constData()), &newStore);
       
  1176                 if (HR_SUCCEEDED(rv)) {
       
  1177                     // Add an origin tag to this store
       
  1178                     ULONG originTag = createNamedProperty(newStore, "origin");
       
  1179                     if (originTag) {
       
  1180                         setNamedProperty(newStore, originTag, "QMF");
       
  1181                     }
       
  1182 
       
  1183                     if (!fromAddress.isEmpty()) {
       
  1184                         // Try to set the address for this service, as a property of the store
       
  1185                         ULONG addressTag = createNamedProperty(newStore, "fromAddress");
       
  1186                         if (addressTag) {
       
  1187                             setNamedProperty(newStore, addressTag, fromAddress);
       
  1188                         }
       
  1189                     }
       
  1190 
       
  1191                     // Create an ID from the record key - actually, the entry ID for CE...
       
  1192                     result = accountIdFromRecordKey(objectProperty(newStore, PR_ENTRYID));
       
  1193 
       
  1194                     newStore->Release();
       
  1195                 } else {
       
  1196                     qWarning() << "Unable to create new store:" << name;
       
  1197                     qDebug() << "rv:" << hex << (ULONG) rv;
       
  1198                 }
       
  1199             }
       
  1200 
       
  1201             session->Release();
       
  1202         }
       
  1203 #endif
       
  1204     }
       
  1205 
       
  1206     return result;
       
  1207 }
       
  1208 
       
  1209 QMessageFolderId addFolder(const Parameters &params)
       
  1210 {
       
  1211     QMessageFolderId result;
       
  1212 
       
  1213     doInit();
       
  1214 
       
  1215     QString folderPath(params["path"]);
       
  1216     QString folderName(params["name"]);
       
  1217     QString parentPath(params["parentFolderPath"]);
       
  1218     QByteArray accountName(params["parentAccountName"].toAscii());
       
  1219 
       
  1220     if (folderName.isEmpty()) {
       
  1221         int index = folderPath.lastIndexOf('/');
       
  1222         folderName = folderPath.mid(index + 1);
       
  1223     }
       
  1224 
       
  1225     if (!folderName.isEmpty() && !folderPath.isEmpty() && !accountName.isEmpty()) {
       
  1226         // Open a session on the default profile
       
  1227         IMAPISession *session(defaultSession());
       
  1228         if (session) {
       
  1229             // Open the store for modification
       
  1230             IMsgStore *store = openStoreByName(accountName, session);
       
  1231             if (store) {
       
  1232                 // Open the root folder for modification
       
  1233                 IMAPIFolder *folder = openFolder(rootFolderEntryId(store), store);
       
  1234                 if (folder) {
       
  1235                     // Find the parent folder for the new folder
       
  1236                     if (!parentPath.isEmpty()) {
       
  1237                         IMAPIFolder *parentFolder = subFolder(parentPath, folder, QString());
       
  1238                         folder->Release();
       
  1239                         folder = parentFolder;
       
  1240                     }
       
  1241 
       
  1242                     if (folder) {
       
  1243                         IMAPIFolder *newFolder = createFolder(folderName, folder);
       
  1244                         if (newFolder) {
       
  1245 #ifndef _WIN32_WCE
       
  1246                             // Named properties not supported by folders on CE...
       
  1247                             ULONG tag = createNamedProperty(newFolder, "path");
       
  1248                             if (tag) {
       
  1249                                 setNamedProperty(newFolder, tag, folderPath);
       
  1250                             }
       
  1251 #endif
       
  1252 
       
  1253 #ifndef _WIN32_WCE
       
  1254                             QByteArray recordKey = folderRecordKey(newFolder);
       
  1255 #else
       
  1256                             QByteArray recordKey;
       
  1257 #endif
       
  1258                             QByteArray entryId = folderEntryId(newFolder);
       
  1259                             QByteArray storeKey = storeRecordKey(store);
       
  1260                             result = folderIdFromProperties(recordKey, entryId, storeKey);
       
  1261 
       
  1262                             newFolder->Release();
       
  1263                         }
       
  1264 
       
  1265                         folder->Release();
       
  1266                     } else {
       
  1267                         qWarning() << "Unable to locate parent folder for addition";
       
  1268                     }
       
  1269                 } else {
       
  1270                     qWarning() << "Unable to open root folder for addition";
       
  1271                 }
       
  1272 
       
  1273                 store->Release();
       
  1274             }
       
  1275 
       
  1276             session->Release();
       
  1277         }
       
  1278     }
       
  1279 
       
  1280     return result;
       
  1281 }
       
  1282 
       
  1283 }
       
  1284 
       
  1285 QTM_BEGIN_NAMESPACE
       
  1286 
       
  1287 // The class 'MapiSession' is a friend of QMessageContentContainer - hijack it here
       
  1288 class QTM_PREPEND_NAMESPACE(MapiSession)
       
  1289 {
       
  1290 public:
       
  1291     static QMessageId addMessage(const Support::Parameters &params)
       
  1292     {
       
  1293         QString parentAccountName(params["parentAccountName"]);
       
  1294         QString parentFolderPath(params["parentFolderPath"]);
       
  1295         QString to(params["to"]);
       
  1296         QString cc(params["cc"]);
       
  1297         QString from(params["from"]);
       
  1298         QString date(params["date"]);
       
  1299         QString receivedDate(params["receivedDate"]);
       
  1300         QString subject(params["subject"]);
       
  1301         QString text(params["text"]);
       
  1302         QString mimeType(params["mimeType"]);
       
  1303         QString attachments(params["attachments"]);
       
  1304         QString priority(params["priority"]);
       
  1305         QString size(params["size"]);
       
  1306         QString type(params["type"]);
       
  1307         QString read(params["status-read"]);
       
  1308         QString hasAttachments(params["status-hasAttachments"]);
       
  1309 
       
  1310         QMessageManager manager;
       
  1311 
       
  1312         if (!to.isEmpty() && !from.isEmpty() && !date.isEmpty() && !subject.isEmpty() &&
       
  1313             !parentAccountName.isEmpty() && !parentFolderPath.isEmpty()) {
       
  1314             // Find the named account
       
  1315             QMessageAccountIdList accountIds(manager.queryAccounts(QMessageAccountFilter::byName(parentAccountName)));
       
  1316             if (accountIds.count() == 1) {
       
  1317                 // Find the specified folder
       
  1318                 QMessageFolderFilter filter(QMessageFolderFilter::byPath(parentFolderPath, QMessageDataComparator::Equal) & QMessageFolderFilter::byParentAccountId(accountIds.first()));
       
  1319                 QMessageFolderIdList folderIds(manager.queryFolders(filter));
       
  1320                 if (folderIds.count() == 1) {
       
  1321                     QMessage message;
       
  1322 
       
  1323                     message.setParentAccountId(accountIds.first());
       
  1324                     message.d_ptr->_parentFolderId = folderIds.first();
       
  1325 
       
  1326                     QList<QMessageAddress> toList;
       
  1327                     foreach (const QString &addr, to.split(",", QString::SkipEmptyParts)) {
       
  1328                         toList.append(QMessageAddress(QMessageAddress::Email, addr.trimmed()));
       
  1329                     }
       
  1330                     message.setTo(toList);
       
  1331 
       
  1332                     QList<QMessageAddress> ccList;
       
  1333                     foreach (const QString &addr, cc.split(",", QString::SkipEmptyParts)) {
       
  1334                         ccList.append(QMessageAddress(QMessageAddress::Email, addr.trimmed()));
       
  1335                     }
       
  1336                     if (!ccList.isEmpty()) {
       
  1337                         message.setCc(ccList);
       
  1338                     }
       
  1339 
       
  1340                     message.setFrom(QMessageAddress(QMessageAddress::Email, from));
       
  1341                     message.setSubject(subject);
       
  1342 
       
  1343                     QDateTime dt(QDateTime::fromString(date, Qt::ISODate));
       
  1344                     dt.setTimeSpec(Qt::UTC);
       
  1345                     message.setDate(dt);
       
  1346 
       
  1347                     if (type.isEmpty()) {
       
  1348                         message.setType(QMessage::Email);
       
  1349                     } else {
       
  1350                         if (type.toLower() == "mms") {
       
  1351                             message.setType(QMessage::Mms);
       
  1352                         } else if (type.toLower() == "sms") {
       
  1353                             message.setType(QMessage::Sms);
       
  1354                         } else if (type.toLower() == "xmpp") {
       
  1355                             message.setType(QMessage::Xmpp);
       
  1356                         } else {
       
  1357                             message.setType(QMessage::Email);
       
  1358                         }
       
  1359                     }
       
  1360 
       
  1361                     if (!receivedDate.isEmpty()) {
       
  1362                         QDateTime dt(QDateTime::fromString(receivedDate, Qt::ISODate));
       
  1363                         dt.setTimeSpec(Qt::UTC);
       
  1364                         message.setReceivedDate(dt);
       
  1365                     }
       
  1366 
       
  1367                     if (!priority.isEmpty()) {
       
  1368                         if (priority.toLower() == "high") {
       
  1369                             message.setPriority(QMessage::HighPriority);
       
  1370                         } else if (priority.toLower() == "low") {
       
  1371                             message.setPriority(QMessage::LowPriority);
       
  1372                         }
       
  1373                     }
       
  1374 
       
  1375                     if (!size.isEmpty()) {
       
  1376                         message.d_ptr->_size = size.toUInt();
       
  1377                     }
       
  1378 
       
  1379                     if (!text.isEmpty()) {
       
  1380                         message.setBody(text, mimeType.toAscii());
       
  1381                     }
       
  1382 
       
  1383                     if (!attachments.isEmpty()) {
       
  1384                         message.appendAttachments(attachments.split("\n"));
       
  1385                     }
       
  1386 
       
  1387                     QMessage::StatusFlags flags(0);
       
  1388                     if (read.toLower() == "true") {
       
  1389                         flags |= QMessage::Read;
       
  1390                     }
       
  1391                     if (hasAttachments.toLower() == "true") {
       
  1392                         flags |= QMessage::HasAttachments;
       
  1393                     }
       
  1394                     message.setStatus(flags);
       
  1395 
       
  1396                     if (!manager.addMessage(&message)) {
       
  1397                         qWarning() << "Unable to addMessage:" << to << from << date << subject;
       
  1398                     } else {
       
  1399                         return message.id();
       
  1400                     }
       
  1401                 } else {
       
  1402                     qWarning() << "Unable to locate parent folder:" << parentFolderPath;
       
  1403                 }
       
  1404             } else {
       
  1405                 qWarning() << "Unable to locate parent account:" << parentAccountName;
       
  1406             }
       
  1407         } else {
       
  1408             qWarning() << "Necessary information missing";
       
  1409         }
       
  1410 
       
  1411         return QMessageId();
       
  1412     }
       
  1413 };
       
  1414 
       
  1415 QTM_END_NAMESPACE
       
  1416 
       
  1417 namespace Support {
       
  1418 
       
  1419 QMessageId addMessage(const Parameters &params)
       
  1420 {
       
  1421     return MapiSession::addMessage(params);
       
  1422 }
       
  1423 
       
  1424 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
       
  1425 /*
       
  1426  * Returns true if a MAPI subsystem is available, as per the
       
  1427  * information at
       
  1428  * http://msdn.microsoft.com/en-us/library/cc815368.aspx
       
  1429  *
       
  1430  * Returns false if a MAPI subsystem could not be found.
       
  1431  */
       
  1432 bool mapiAvailable()
       
  1433 {
       
  1434     bool mapix = false;
       
  1435     LONG res = -1;
       
  1436     HKEY key;
       
  1437     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
       
  1438                         L"SOFTWARE\\Microsoft\\Windows Messaging Subsystem",
       
  1439                         0,
       
  1440                         KEY_READ,
       
  1441                         &key);
       
  1442 
       
  1443     if (res == ERROR_SUCCESS) {
       
  1444         unsigned long type = REG_SZ;
       
  1445         unsigned long size = 512;
       
  1446         char ret[512] = "";
       
  1447         res = RegQueryValueExW(key,
       
  1448                                L"MAPIX",
       
  1449                                0,
       
  1450                                &type,
       
  1451                                (LPBYTE)&ret[0],
       
  1452                                &size);
       
  1453 
       
  1454         if (res == ERROR_SUCCESS && (QString::fromUtf16((const ushort*)ret).toInt() == 1))
       
  1455             mapix = true;
       
  1456     }
       
  1457 
       
  1458     RegCloseKey(key);
       
  1459 
       
  1460     return mapix;
       
  1461 }
       
  1462 #endif
       
  1463 
       
  1464 }