/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Mobility Components. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QMESSAGEWINHELPERPRIVATE_H #define QMESSAGEWINHELPERPRIVATE_H #include #include #include #include #include #include #include #include #include #include #include QTM_BEGIN_NAMESPACE QTM_END_NAMESPACE #ifndef _WIN32_WCE #define USES_IID_IMAPIForm #define USES_IID_IMAPIMessageSite #define USES_IID_IPersistMessage #include #include #include #endif // As per http://support.microsoft.com/kb/816477 #ifndef PR_MSG_EDITOR_FORMAT #define PR_MSG_EDITOR_FORMAT PROP_TAG( PT_LONG, 0x5909 ) #define EDITOR_FORMAT_DONTKNOW ((ULONG)0) #define EDITOR_FORMAT_PLAINTEXT ((ULONG)1) #define EDITOR_FORMAT_HTML ((ULONG)2) #ifndef _WIN32_WCE #define EDITOR_FORMAT_RTF ((ULONG)3) #else // Not a real definition, but useful for us: #define EDITOR_FORMAT_MIME ((ULONG)3) #endif #endif #ifndef PR_ATTACH_CONTENT_ID // This is not available in my SDK version... #define PR_ATTACH_CONTENT_ID PROP_TAG( PT_UNICODE, 0x3712 ) #endif #ifndef PR_BODY_HTML #define PR_BODY_HTML PROP_TAG( PT_TSTRING, 0x1013 ) #endif #define mapiRelease(a) if(a){a->Release();a=0;} QTM_BEGIN_NAMESPACE class MapiEntryId : public QByteArray { public: MapiEntryId():QByteArray(){} MapiEntryId(LPENTRYID mapiEntryId, ULONG entryIdLength) : QByteArray(reinterpret_cast(mapiEntryId),entryIdLength){} MapiEntryId(LPBYTE mapiEntryId, ULONG entryIdLength) : QByteArray(reinterpret_cast(mapiEntryId),entryIdLength){} }; class MapiRecordKey : public QByteArray { public: MapiRecordKey():QByteArray(){} MapiRecordKey(LPENTRYID mapiRecordKey, ULONG entryIdLength) : QByteArray(reinterpret_cast(mapiRecordKey),entryIdLength){} MapiRecordKey(LPBYTE mapiRecordKey, ULONG entryIdLength) : QByteArray(reinterpret_cast(mapiRecordKey),entryIdLength){} }; class MapiFolder; class MapiStore; class MapiSession; typedef QSharedPointer MapiFolderPtr; typedef QSharedPointer MapiStorePtr; typedef QSharedPointer MapiSessionPtr; namespace WinHelpers { enum SavePropertyOption { DontSavePropertyChanges = 0, SavePropertyChanges }; QString QStringFromLpctstr(LPCTSTR lpszValue); void LptstrFromQString(const QString &value, LPTSTR *lpsz); typedef QPair AttachmentLocator; QMessageContentContainer fromLocator(const WinHelpers::AttachmentLocator &l); ULONG createNamedProperty(IMAPIProp *object, const QString &name); ULONG getNamedPropertyTag(IMAPIProp *object, const QString &name); bool setNamedProperty(IMAPIProp *object, ULONG tag, const QString &value); QString getNamedProperty(IMAPIProp *object, ULONG tag); QByteArray contentTypeFromExtension(const QString &extension); class Lptstr : public QVector { public: Lptstr():QVector(){} Lptstr(int length) : QVector(length){} operator TCHAR* (){ return QVector::data(); } }; Lptstr LptstrFromQString(const QString &src); class MapiInitializer; typedef QSharedPointer MapiInitializationToken; MapiInitializationToken initializeMapi(); class MapiInitializer { friend MapiInitializationToken WinHelpers::initializeMapi(); private: MapiInitializer(); MapiInitializer &operator=(const MapiInitializer &); public: ~MapiInitializer(); bool _initialized; }; bool getMapiProperty(IMAPIProp *object, ULONG tag, ULONG *value); bool getMapiProperty(IMAPIProp *object, ULONG tag, LONG *value); bool getMapiProperty(IMAPIProp *object, ULONG tag, QByteArray *value); bool getMapiProperty(IMAPIProp *object, ULONG tag, QString value); bool setMapiProperty(IMAPIProp *object, ULONG tag, const QString &value); bool setMapiProperty(IMAPIProp *object, ULONG tag, LONG value); bool setMapiProperty(IMAPIProp *object, ULONG tag, ULONG value); bool setMapiProperty(IMAPIProp *object, ULONG tag, bool value); bool setMapiProperty(IMAPIProp *object, ULONG tag, FILETIME value); bool setMapiProperty(IMAPIProp *object, ULONG tag, MapiEntryId value); } /* Note on links: - Session must close at exit for correct cleanup Session must be a singleton Stores must have weak ref to session - Stores must remain open after opening to enable notifications Session holds strong ref to stores - Folders should not remain open Store holds weak ref to folders Folder can have strong ref to store * Session keeps stores open * Folders keep store open */ class MapiFolder { public: static MapiFolderPtr createFolder(QMessageManager::Error *error, const MapiStorePtr &store, IMAPIFolder *folder, const MapiRecordKey &recordKey, const QString &name, const MapiEntryId &entryId, bool hasSubFolders, uint messageCount); ~MapiFolder(); MapiFolderPtr nextSubFolder(QMessageManager::Error *error); LPMAPITABLE queryBegin(QMessageManager::Error *error, const QMessageFilter &filter, const QMessageSortOrder &sortOrder); QMessageIdList queryNext(QMessageManager::Error *error, LPMAPITABLE messagesTable, const QMessageFilter &filter); void queryEnd(LPMAPITABLE messagesTable); uint countMessages(QMessageManager::Error *error, const QMessageFilter &filter = QMessageFilter()) const; void removeMessages(QMessageManager::Error *error, const QMessageIdList &ids); MapiEntryId messageEntryId(QMessageManager::Error *error, const MapiRecordKey &messagekey); QMessageFolderId id() const; QMessageAccountId accountId() const; QMessageFolderId parentId() const; QList ancestorIds() const; bool isValid() const { return _valid; } IMAPIFolder* folder() const { return _folder; } MapiRecordKey recordKey() const { return _key; } MapiRecordKey storeKey() const; #ifdef _WIN32_WCE MapiEntryId storeEntryId() const; #endif QString name() const { return _name; } MapiEntryId entryId() const { return _entryId; } bool hasSubFolders() const { return _hasSubFolders; } uint messageCount() const { return _messageCount; } IMessage *createMessage(QMessageManager::Error* error); IMessage *createMessage(QMessageManager::Error* error, const QMessage& source, const MapiSessionPtr &session, WinHelpers::SavePropertyOption saveOption = WinHelpers::SavePropertyChanges ); IMessage *openMessage(QMessageManager::Error *error, const MapiEntryId &entryId); QMessageFolder folder(QMessageManager::Error *error, const QMessageFolderId& id) const; QMessage message(QMessageManager::Error *error, const QMessageId& id) const; QMessage::StandardFolder standardFolder() const; private: MapiFolder(); MapiFolder(const MapiStorePtr &store, IMAPIFolder *folder, const MapiRecordKey &recordKey, const QString &name, const MapiEntryId &entryId, bool hasSubFolders, uint messageCount); void findSubFolders(QMessageManager::Error *error); friend class MapiStore; QWeakPointer _self; MapiStorePtr _store; bool _valid; IMAPIFolder* _folder; MapiRecordKey _key; QString _name; MapiEntryId _entryId; bool _hasSubFolders; uint _messageCount; bool _init; QList _subFolders; }; class MapiStore { public: static MapiStorePtr createStore(QMessageManager::Error *error, const MapiSessionPtr &session, IMsgStore *store, const MapiRecordKey &key, const MapiEntryId &entryId, const QString &name, bool cachedMode); ~MapiStore(); MapiFolderPtr findFolder(QMessageManager::Error *error, QMessage::StandardFolder sf); QMessageFolderIdList folderIds(QMessageManager::Error *error) const; QMessageFolder folderFromId(QMessageManager::Error *error, const QMessageFolderId &folderId); QList filterFolders(QMessageManager::Error *error, const QMessageFolderFilter &filter) const; MapiEntryId messageEntryId(QMessageManager::Error *error, const MapiRecordKey &folderKey, const MapiRecordKey &messageKey); MapiFolderPtr openFolder(QMessageManager::Error *error, const MapiEntryId& id) const; MapiFolderPtr openFolderWithKey(QMessageManager::Error *error, const MapiRecordKey& key) const; bool supports(ULONG featureFlag) const; bool isValid() const { return _valid; } QMessageAccountId id() const; MapiEntryId entryId() const { return _entryId; } QString name() const { return _name; } IMsgStore* store() const { return _store; } MapiRecordKey recordKey() const { return _key; } QMessage::TypeFlags types() const; QMessageAddress address() const; MapiSessionPtr session() const; MapiFolderPtr rootFolder(QMessageManager::Error *error) const; MapiFolderPtr receiveFolder(QMessageManager::Error *error) const; IMessage *openMessage(QMessageManager::Error *error, const MapiEntryId &entryId); QMessageFolder folder(QMessageManager::Error *error, const QMessageFolderId& id) const; QMessage message(QMessageManager::Error *error, const QMessageId& id) const; QMessage::StandardFolder standardFolder(const MapiEntryId &entryId) const; void notifyEvents(ULONG mask); #ifdef _WIN32_WCE QString transportName() const; #endif private: MapiStore(); MapiStore(const MapiSessionPtr &session, IMsgStore *store, const MapiRecordKey &key, const MapiEntryId &entryId, const QString &name, bool cachedMode); MapiEntryId standardFolderId(QMessageManager::Error *error, QMessage::StandardFolder sf) const; MapiEntryId rootFolderId(QMessageManager::Error *error) const; MapiEntryId receiveFolderId(QMessageManager::Error *error) const; IMAPIFolder *openMapiFolder(QMessageManager::Error *error, const MapiEntryId &entryId) const; bool setAdviseSink(ULONG mask, IMAPIAdviseSink *sink); class AdviseSink : public IMAPIAdviseSink { MapiStore *_store; LONG _refCount; public: AdviseSink(MapiStore *store) : _store(store), _refCount(0) {} STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj); STDMETHOD_(ULONG, AddRef)(); STDMETHOD_(ULONG, Release)(); STDMETHOD_(ULONG, OnNotify)(ULONG cNotification, LPNOTIFICATION lpNotifications); }; QWeakPointer _self; QWeakPointer _session; bool _valid; IMsgStore* _store; MapiRecordKey _key; MapiEntryId _entryId; QString _name; bool _cachedMode; ULONG _adviseConnection; QMap _standardFolderId; mutable QHash > _folderMap; }; class MapiSession : public QObject { Q_OBJECT public: enum NotifyType { Added = 1, Removed, Updated }; class NotifyEvent : public QEvent { public: static QEvent::Type eventType(); NotifyEvent(MapiStore *store, const QMessageId &id, MapiSession::NotifyType type); virtual Type type(); MapiStore *_store; QMessageId _id; NotifyType _notifyType; }; static MapiSessionPtr createSession(QMessageManager::Error *error); ~MapiSession(); bool isValid() const { return (_mapiSession != 0); } MapiStorePtr findStore(QMessageManager::Error *error, const QMessageAccountId &id = QMessageAccountId(), bool cachedMode = true) const; MapiStorePtr defaultStore(QMessageManager::Error *error, bool cachedMode = true) const { return findStore(error,QMessageAccountId(),cachedMode); } QList filterStores(QMessageManager::Error *error, const QMessageAccountFilter &filter, const QMessageAccountSortOrder &sortOrder = QMessageAccountSortOrder(), uint limit = 0, uint offset = 0, bool cachedMode = true) const; QList allStores(QMessageManager::Error *error, bool cachedMode = true) const; QList filterFolders(QMessageManager::Error *error, const QMessageFolderFilter &filter, const QMessageFolderSortOrder &sortOrder = QMessageFolderSortOrder(), uint limit = 0, uint offset = 0, bool cachedMode = true) const; MapiStorePtr openStore(QMessageManager::Error *error, const MapiEntryId& id, bool cachedMode = true) const; MapiStorePtr openStoreWithKey(QMessageManager::Error *error, const MapiRecordKey& key, bool cachedMode = true) const; QMessageAccountId defaultAccountId(QMessageManager::Error *error, QMessage::Type type) const; MapiEntryId messageEntryId(QMessageManager::Error *error, const MapiRecordKey &storeKey, const MapiRecordKey &folderKey, const MapiRecordKey &messageKey); MapiRecordKey messageRecordKey(QMessageManager::Error *error, const QMessageId &id); MapiRecordKey folderRecordKey(QMessageManager::Error *error, const QMessageId &id); #ifdef _WIN32_WCE MapiEntryId folderEntryId(QMessageManager::Error *error, const QMessageId &id); #endif bool equal(const MapiEntryId &lhs, const MapiEntryId &rhs) const; QMessageFolder folder(QMessageManager::Error *error, const QMessageFolderId& id) const; QMessage message(QMessageManager::Error *error, const QMessageId& id) const; bool updateMessageProperties(QMessageManager::Error *error, QMessage *msg) const; bool updateMessageRecipients(QMessageManager::Error *error, QMessage *msg) const; bool updateMessageBody(QMessageManager::Error *error, QMessage *msg) const; bool updateMessageAttachments(QMessageManager::Error *error, QMessage *msg) const; bool haveAttachmentData(QMessageManager::Error* error, const QMessageId& id, ULONG number) const; QByteArray attachmentData(QMessageManager::Error *error, const QMessageId& id, ULONG number) const; QMessageIdList queryMessages(QMessageManager::Error *error, const QMessageFilter &filter, const QMessageSortOrder &sortOrder = QMessageSortOrder(), uint limit = 0, uint offset = 0, const QString &body = QString(), QMessageDataComparator::MatchFlags matchFlags = 0) const; void updateMessage(QMessageManager::Error* error, const QMessage& source); void removeMessages(QMessageManager::Error *error, const QMessageIdList &ids); IMAPISession* session() const { return _mapiSession; } QMessageManager::NotificationFilterId registerNotificationFilter(QMessageManager::Error *error, const QMessageFilter &filter); void unregisterNotificationFilter(QMessageManager::Error *error, QMessageManager::NotificationFilterId filterId); static QMessagePrivate *messageImpl(const QMessage &message); static QMessageContentContainerPrivate *containerImpl(const QMessageContentContainer &); void addToNotifyQueue(const NotifyEvent& e); void flushNotifyQueue(); signals: void messageAdded(const QMessageId &id, const QMessageManager::NotificationFilterIdSet &matchingFilterIds); void messageRemoved(const QMessageId &id, const QMessageManager::NotificationFilterIdSet &matchingFilterIds); void messageUpdated(const QMessageId &id, const QMessageManager::NotificationFilterIdSet &matchingFilterIds); public slots: void dispatchNotifications(); void processNotifyQueue(); private: MapiSession(); MapiSession(QMessageManager::Error *error); IMsgStore *openMapiStore(QMessageManager::Error *error, const MapiEntryId &entryId, bool cachedMode = true) const; IMessage *openMapiMessage(QMessageManager::Error *error, const QMessageId &id, MapiStorePtr *storePtr = 0) const; void addRecipients(LPMESSAGE message, const QMessageAddressList& addressList, unsigned long mapiAddressType); void addAttachment(LPMESSAGE message, const QMessageContentContainer& attachmentContainer); bool event(QEvent *e); void notify(MapiStore *store, const QMessageId &id, NotifyType notifyType); template QList filterStores(QMessageManager::Error *error, Predicate predicate, Ordering sortOrder, uint limit, uint offset, bool cachedMode) const; private: friend class SessionManager; QWeakPointer _self; WinHelpers::MapiInitializationToken _token; IMAPISession* _mapiSession; QMessageManager::NotificationFilterId _filterId; QMap _filters; bool _registered; QQueue _notifyEventQueue; mutable QHash _storeMap; }; #ifndef _WIN32_WCE class MapiForm : public IMAPIMessageSite { public: MapiForm(IMsgStore* mapiStore, IMAPISession* mapiSession, IMAPIFolder* mapiFolder, IMessage* mapiMessage); virtual ~MapiForm(); // IUnknown interface STDMETHODIMP QueryInterface (REFIID riid, void** ppvObj); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); STDMETHODIMP GetLastError(HRESULT hResult, ulong flags, LPMAPIERROR FAR * lppMAPIError); // IMAPIMessageSite interface STDMETHODIMP GetSession(IMAPISession* FAR * mapiSession); STDMETHODIMP GetStore(IMsgStore* FAR * mapiStore); STDMETHODIMP GetFolder(IMAPIFolder* FAR * mapiFolder); STDMETHODIMP GetMessage(IMessage* FAR * mapiMessage); STDMETHODIMP GetFormManager(IMAPIFormMgr* FAR * ppFormMgr); STDMETHODIMP NewMessage(ULONG fComposeInFolder, IMAPIFolder* mapiFolder, IPersistMessage* pPersistMessage, IMessage* FAR * mapiMessage, IMAPIMessageSite* FAR * ppMessageSite, LPMAPIVIEWCONTEXT FAR * ppViewContext); STDMETHODIMP CopyMessage(IMAPIFolder* pFolderDestination); STDMETHODIMP MoveMessage(IMAPIFolder* pFolderDestination, LPMAPIVIEWCONTEXT pViewContext, LPCRECT prcPosRect); STDMETHODIMP DeleteMessage(LPMAPIVIEWCONTEXT pViewContext, LPCRECT prcPosRect); STDMETHODIMP SaveMessage(); STDMETHODIMP SubmitMessage(ulong flags); STDMETHODIMP GetSiteStatus(ulong* status); bool show(); private: HRESULT setPersistMessage(LPMAPIFORM lpForm, IPersistMessage* mapiPersistMessage); void releasePersistMessage(); void releaseAll(); private: long m_referenceCount; IMAPIFolder* m_mapiFolder; IMessage* m_mapiMessage; IMsgStore* m_mapiStore; IMAPISession* m_mapiSession; IPersistMessage* m_mapiPersistMessage; }; #endif QTM_END_NAMESPACE #endif