123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- /*
- * Copyright 2005 - 2016 Zarafa and its licensors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- #include <kopano/platform.h>
- #include <kopano/ECRestriction.h>
- #include <kopano/memory.hpp>
- #include "favoritesutil.h"
- #include <edkmdb.h>
- #include <kopano/mapiext.h>
- #include <kopano/CommonUtil.h>
- #include <kopano/charset/convstring.h>
- #include <string>
- #include <mapiutil.h>
- using namespace std;
- using namespace KCHL;
- namespace KC {
- static constexpr const SizedSPropTagArray(SHORTCUT_NUM, sPropsShortcuts) = {SHORTCUT_NUM, {
- PR_INSTANCE_KEY, PR_FAV_PUBLIC_SOURCE_KEY, PR_FAV_PARENT_SOURCE_KEY,
- PR_FAV_DISPLAY_NAME, PR_FAV_DISPLAY_ALIAS, PR_FAV_LEVEL_MASK,
- PR_FAV_CONTAINER_CLASS}};
- const SPropTagArray *GetShortCutTagArray(void)
- {
- return sPropsShortcuts;
- }
- /**
- * Get the shortcut folder from the users default store.
- * If the folder not exist it will create them
- *
- * @param lpSession Pointer to the current mapi session
- * @param lpszFolderName Pointer to a string containing the name for the shorcut folder. If NULL is passed, the folder has the default name 'Shortcut'.
- * @param lpszFolderComment Pointer to a string containing a comment associated with the shorcut folder. If NULL is passed, the folder has the default comment 'Shortcut folder'.
- * @param ulFlags MAPI_UNICODE unicode properties
- * MAPI_CREATE create shorcut folder if not exist
- * @param lppShortcutFolder Pointer to a pointer to the opened shortcut folder
- */
- HRESULT GetShortcutFolder(LPMAPISESSION lpSession, LPTSTR lpszFolderName, LPTSTR lpszFolderComment, ULONG ulFlags, LPMAPIFOLDER* lppShortcutFolder)
- {
- HRESULT hr = hrSuccess;
- memory_ptr<SPropValue> lpPropValue;
- object_ptr<IMsgStore> lpMsgStore;
- object_ptr<IMAPIFolder> lpFolder;
- ULONG ulObjType = 0;
- hr = HrOpenDefaultStore(lpSession, &~lpMsgStore);
- if(hr != hrSuccess)
- return hr;
- // Get shortcut entryid
- hr = HrGetOneProp(lpMsgStore, PR_IPM_FAVORITES_ENTRYID, &~lpPropValue);
- if(hr != hrSuccess) {
- if (hr == MAPI_E_NOT_FOUND && ulFlags & MAPI_CREATE)
- // Propety not found, re-create the shortcut folder
- return CreateShortcutFolder(lpMsgStore, lpszFolderName, lpszFolderComment, ulFlags & MAPI_UNICODE, lppShortcutFolder);
- return hr;
- }
- // Open Shortcut folder
- hr = lpMsgStore->OpenEntry(lpPropValue->Value.bin.cb, reinterpret_cast<ENTRYID *>(lpPropValue->Value.bin.lpb), &IID_IMAPIFolder, MAPI_BEST_ACCESS, &ulObjType, &~lpFolder);
- if (hr != hrSuccess) {
- if (hr == MAPI_E_NOT_FOUND && ulFlags & MAPI_CREATE)
- // Folder not found, re-create the shortcut folder
- return CreateShortcutFolder(lpMsgStore, lpszFolderName, lpszFolderComment, ulFlags & MAPI_UNICODE, lppShortcutFolder);
- return hr;
- }
- return lpFolder->QueryInterface(IID_IMAPIFolder, reinterpret_cast<void **>(lppShortcutFolder));
- }
- /**
- * Helper function to create a new shorcut folder and update the property
- * PR_IPM_FAVORITES_ENTRYID on the store object.
- * If the folder already exist, it will used and update only the property
- *
- * @param lpMsgStore Pointer to the private store
- * @param lpszFolderName Pointer to a string containing the name for the shorcut folder. If NULL is passed, the folder has the default name 'Shortcut'.
- * @param lpszFolderComment Pointer to a string containing a comment associated with the shorcut folder. If NULL is passed, the folder has the default comment 'Shortcut folder'.
- * @param ulFlags MAPI_UNICODE if the folder strings are in unicode format, otherwise 0.
- * @param lppShortcutFolder Pointer to a pointer to the opened shortcut folder
- */
- HRESULT CreateShortcutFolder(IMsgStore *lpMsgStore, LPTSTR lpszFolderName, LPTSTR lpszFolderComment, ULONG ulFlags, LPMAPIFOLDER* lppShortcutFolder)
- {
- HRESULT hr = hrSuccess;
- object_ptr<IMAPIFolder> lpFolder, lpNewFolder;
- ULONG ulObjType = 0;
- memory_ptr<SPropValue> lpProp;
- if (lpMsgStore == nullptr || lppShortcutFolder == nullptr)
- return MAPI_E_INVALID_PARAMETER;
- if (lpszFolderName == NULL) {
- if (ulFlags & MAPI_UNICODE)
- lpszFolderName = (LPTSTR)L"Shortcut";
- else
- lpszFolderName = (LPTSTR)"Shortcut";
- }
- if (lpszFolderComment == NULL) {
- if (ulFlags & MAPI_UNICODE)
- lpszFolderComment = (LPTSTR)L"Shortcut folder";
- else
- lpszFolderComment = (LPTSTR)"Shortcut folder";
- }
- // Open root folder
- hr = lpMsgStore->OpenEntry(0, nullptr, &IID_IMAPIFolder, MAPI_BEST_ACCESS, &ulObjType, &~lpFolder);
- if (hr != hrSuccess)
- return hr;
- hr = lpFolder->CreateFolder(FOLDER_GENERIC, lpszFolderName, lpszFolderComment, &IID_IMAPIFolder, ulFlags | OPEN_IF_EXISTS, &~lpNewFolder);
- if (hr != hrSuccess)
- return hr;
- hr = HrGetOneProp(lpNewFolder, PR_ENTRYID, &~lpProp);
- if (hr != hrSuccess)
- return hr;
- lpProp->ulPropTag = PR_IPM_FAVORITES_ENTRYID;
- hr = HrSetOneProp(lpMsgStore, lpProp);
- if (hr != hrSuccess)
- return hr;
- return lpNewFolder->QueryInterface(IID_IMAPIFolder, reinterpret_cast<void **>(lppShortcutFolder));
- }
- /**
- * Remove a favorite in the private store. also the sub favorites will be deleted
- *
- * @param lpShortcutFolder The shortcut folder in the private store.
- * @param lpPropSourceKey Pointer to the sourcekey of a favorite folder
- */
- HRESULT DelFavoriteFolder(IMAPIFolder *lpShortcutFolder, LPSPropValue lpPropSourceKey)
- {
- HRESULT hr = hrSuccess;
- object_ptr<IMAPITable> lpTable;
- rowset_ptr lpRows;
- memory_ptr<ENTRYLIST> lpsMsgList;
- static constexpr const SizedSPropTagArray(2, sPropDelFavo) =
- {2, {PR_ENTRYID, PR_FAV_PUBLIC_SOURCE_KEY}};
- std::list<string> listSourceKey;
- string strSourceKey;
- SPropValue sPropSourceKey;
- ULONG ulMaxRows = 0;
- if (lpShortcutFolder == nullptr || lpPropSourceKey == nullptr)
- return MAPI_E_INVALID_PARAMETER;
- hr = lpShortcutFolder->GetContentsTable(0, &~lpTable);
- if (hr != hrSuccess)
- return hr;
- hr = lpTable->GetRowCount(0, &ulMaxRows);
- if (hr != hrSuccess)
- return hr;
- hr = lpTable->SetColumns(sPropDelFavo, 0);
- if (hr != hrSuccess)
- return hr;
- // build restriction
- hr = ECPropertyRestriction(RELOP_EQ, PR_FAV_PUBLIC_SOURCE_KEY, lpPropSourceKey, ECRestriction::Cheap)
- .FindRowIn(lpTable, BOOKMARK_BEGINNING, 0);
- if (hr != hrSuccess)
- return hr; // Folder already removed (or memory problems)
- hr = lpTable->QueryRows (1, 0, &~lpRows);
- if (hr != hrSuccess)
- return hr;
- if (lpRows->cRows == 0)
- return hrSuccess; // Folder already removed
- hr = MAPIAllocateBuffer(sizeof(ENTRYLIST), &~lpsMsgList);
- if (hr != hrSuccess)
- return hr;
- hr = MAPIAllocateMore(sizeof(SBinary)*ulMaxRows, lpsMsgList, (void**)&lpsMsgList->lpbin);
- if (hr != hrSuccess)
- return hr;
- //FIXME: check the properties in the row!!!!
- lpsMsgList->cValues = 0;
- // add entryid
- lpsMsgList->lpbin[lpsMsgList->cValues].cb = lpRows->aRow[0].lpProps[0].Value.bin.cb;
- if ((hr = MAPIAllocateMore(lpsMsgList->lpbin[lpsMsgList->cValues].cb, lpsMsgList, (void **) &lpsMsgList->lpbin[lpsMsgList->cValues].lpb)) != hrSuccess)
- return hr;
- memcpy(lpsMsgList->lpbin[lpsMsgList->cValues].lpb, lpRows->aRow[0].lpProps[0].Value.bin.lpb, lpsMsgList->lpbin[lpsMsgList->cValues].cb);
- ++lpsMsgList->cValues;
- strSourceKey.assign((char*)lpRows->aRow[0].lpProps[1].Value.bin.lpb, lpRows->aRow[0].lpProps[1].Value.bin.cb);
- listSourceKey.push_back(strSourceKey);
- lpRows.reset();
- for (const auto &sk : listSourceKey) {
- sPropSourceKey.ulPropTag = PR_FAV_PUBLIC_SOURCE_KEY;
- sPropSourceKey.Value.bin.cb = sk.size();
- sPropSourceKey.Value.bin.lpb = const_cast<BYTE *>(reinterpret_cast<const BYTE *>(sk.c_str()));
- hr = ECPropertyRestriction(RELOP_EQ, PR_FAV_PARENT_SOURCE_KEY, &sPropSourceKey, ECRestriction::Cheap)
- .RestrictTable(lpTable);
- if (hr != hrSuccess)
- return hr;
- hr = lpTable->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
- if (hr != hrSuccess)
- return hr;
- while(true)
- {
- hr = lpTable->QueryRows(1, 0, &~lpRows);
- if (hr != hrSuccess)
- return hr;
- if (lpRows->cRows == 0)
- break; // no rows
- //FIXME: check the properties in the row!!!!
- // add entryid
- lpsMsgList->lpbin[lpsMsgList->cValues].cb = lpRows->aRow[0].lpProps[0].Value.bin.cb;
- if ((hr = MAPIAllocateMore(lpsMsgList->lpbin[lpsMsgList->cValues].cb, lpsMsgList, (void **) &lpsMsgList->lpbin[lpsMsgList->cValues].lpb)) != hrSuccess)
- return hr;
- memcpy(lpsMsgList->lpbin[lpsMsgList->cValues].lpb, lpRows->aRow[0].lpProps[0].Value.bin.lpb, lpsMsgList->lpbin[lpsMsgList->cValues].cb);
- ++lpsMsgList->cValues;
- // Add sourcekey into the list
- strSourceKey.assign((char*)lpRows->aRow[0].lpProps[1].Value.bin.lpb, lpRows->aRow[0].lpProps[1].Value.bin.cb);
- listSourceKey.push_back(strSourceKey);
- } //while(true)
- }
- return lpShortcutFolder->DeleteMessages(lpsMsgList, 0, nullptr, 0);
- }
- /**
- * Add a new favorite in the private store.
- *
- * @param[in] lpShortcutFolder The shortcut folder in the private store.
- * @param[in] ulLevel The depth of the folder, start from one.
- * @param[in] lpAliasName Alias name of the folder. Pass NULL to specify the standard foldername
- * @param[in] ulFlags possible MAPI_UNICODE for lpszAliasName
- * @param[in] cValues Count of property values pointed to by the lpPropArray parameter. The cValues parameter must not be zero.
- * @param[in] lpPropArray Pointer to an array of SPropValue structures holding property values to create the favorite.
- */
- HRESULT AddToFavorite(IMAPIFolder *lpShortcutFolder, ULONG ulLevel, LPCTSTR lpszAliasName, ULONG ulFlags, ULONG cValues, LPSPropValue lpPropArray)
- {
- HRESULT hr = hrSuccess;
- object_ptr<IMessage> lpMessage;
- object_ptr<IMAPITable> lpTable;
- memory_ptr<SPropValue> lpNewPropArray;
- ULONG cPropArray = 0;
- memory_ptr<SRestriction> lpRestriction;
- if (lpShortcutFolder == nullptr || lpPropArray == nullptr)
- return MAPI_E_INVALID_PARAMETER;
-
- auto lpPropSourceKey = PCpropFindProp(lpPropArray, cValues, PR_SOURCE_KEY);
- auto lpPropParentSourceKey = PCpropFindProp(lpPropArray, cValues, PR_PARENT_SOURCE_KEY);
- auto lpPropDisplayName = PCpropFindProp(lpPropArray, cValues, PR_DISPLAY_NAME);
- auto lpPropMessageClass = PCpropFindProp(lpPropArray, cValues, PR_CONTAINER_CLASS);
-
- if (lpPropSourceKey == NULL || lpPropParentSourceKey == NULL || lpPropDisplayName == NULL)
- return MAPI_E_CORRUPT_DATA;
- // Check for duplicates
- hr = lpShortcutFolder->GetContentsTable(0, &~lpTable);
- if (hr != hrSuccess)
- return hr;
- // build restriction
- hr = ECPropertyRestriction(RELOP_EQ, PR_FAV_PUBLIC_SOURCE_KEY, lpPropSourceKey, ECRestriction::Cheap)
- .CreateMAPIRestriction(&~lpRestriction, ECRestriction::Cheap);
- if (hr != hrSuccess)
- return hr;
- if (lpTable->FindRow(lpRestriction, BOOKMARK_BEGINNING , 0) == hrSuccess)
- return hrSuccess; /* Folder already included */
- // No duplicate, Start to add the favorite
- hr = lpShortcutFolder->CreateMessage(nullptr, 0, &~lpMessage);
- if (hr != hrSuccess)
- return hr;
- hr = MAPIAllocateBuffer(sizeof(SPropValue) * 6, &~lpNewPropArray);
- if (hr != hrSuccess)
- return hr;
- lpNewPropArray[cPropArray].ulPropTag = PR_FAV_LEVEL_MASK;
- lpNewPropArray[cPropArray++].Value.ul = ulLevel;
- lpNewPropArray[cPropArray].ulPropTag = PR_FAV_PUBLIC_SOURCE_KEY;
- lpNewPropArray[cPropArray++].Value = lpPropSourceKey->Value;
- lpNewPropArray[cPropArray].ulPropTag = PR_FAV_DISPLAY_NAME;
- lpNewPropArray[cPropArray++].Value = lpPropDisplayName->Value;
- if (lpPropMessageClass) {
- lpNewPropArray[cPropArray].ulPropTag = PR_FAV_CONTAINER_CLASS;
- lpNewPropArray[cPropArray++].Value = lpPropMessageClass->Value;
- }
- if (ulLevel > 1) {
- lpNewPropArray[cPropArray].ulPropTag = PR_FAV_PARENT_SOURCE_KEY;
- lpNewPropArray[cPropArray++].Value = lpPropParentSourceKey->Value;
- }
- if (lpszAliasName && lpszAliasName[0] != '\0') {
- tstring tDisplay(lpPropDisplayName->Value.LPSZ);
- convstring csAlias(lpszAliasName, ulFlags);
- if ((std::wstring)csAlias != tDisplay)
- {
- lpNewPropArray[cPropArray].ulPropTag = (ulFlags & MAPI_UNICODE) ? PR_FAV_DISPLAY_ALIAS_W : PR_FAV_DISPLAY_ALIAS_A;
- lpNewPropArray[cPropArray++].Value.lpszA = (LPSTR)lpszAliasName;
- }
- }
- hr = lpMessage->SetProps(cPropArray, lpNewPropArray, NULL);
- if (hr != hrSuccess)
- return hr;
- return lpMessage->SaveChanges(0);
- }
- /**
- * Add new folders to the favorites folder
- *
- * @param lpSession Pointer to the current mapi session
- * @param lpFolder Pointer to a folder in the public store, except a folder from the favorites folder
- * @param lpAliasName Pointer to a string containing another name for the folder
- * @param ulFlags Bitmask of flags that controls how the folder is added. The following flags can be set:
- * FAVO_FOLDER_LEVEL_BASE
- * Add only the folder itself
- * FAVO_FOLDER_LEVEL_ONE
- * Add the folder and the immediate subfolders only
- * FAVO_FOLDER_LEVEL_SUB
- * Add the folder and all subfolders
- * MAPI_UNICODE
- * lpAliasName parameter is in wide or multibyte format
- */
- HRESULT AddFavoriteFolder(LPMAPIFOLDER lpShortcutFolder, LPMAPIFOLDER lpFolder, LPCTSTR lpAliasName, ULONG ulFlags)
- {
- HRESULT hr = hrSuccess;
- object_ptr<IMAPITable> lpTable;
- memory_ptr<SPropValue> lpsPropArray;
- ULONG ulFolderFlags = 0;
- ULONG cValues = 0;
- static constexpr const SizedSPropTagArray(5, sPropsFolderInfo) =
- {5, {PR_DEPTH, PR_SOURCE_KEY, PR_PARENT_SOURCE_KEY,
- PR_DISPLAY_NAME, PR_CONTAINER_CLASS}};
- // FIXME: check vaiables
- // Add folders to the shorcut folder
- hr = lpFolder->GetProps(sPropsFolderInfo, 0, &cValues, &~lpsPropArray);
- if (FAILED(hr) != hrSuccess) //Gives always a warning
- return hr;
- hr = AddToFavorite(lpShortcutFolder, 1, lpAliasName, ulFlags, cValues, lpsPropArray);
- if (hr != hrSuccess)
- return hr;
- if (ulFlags == FAVO_FOLDER_LEVEL_SUB)
- ulFolderFlags = CONVENIENT_DEPTH;
- else if (ulFlags == FAVO_FOLDER_LEVEL_ONE)
- ulFolderFlags = 0;
- else
- return hrSuccess; // Done
- // Get subfolders
- hr = lpFolder->GetHierarchyTable(ulFolderFlags, &~lpTable);
- if (hr != hrSuccess)
- return hr;
- hr = lpTable->SetColumns(sPropsFolderInfo, 0);
- if (hr != hrSuccess)
- return hr;
- // Add the favorite recusive depended what the flags are
- while(true)
- {
- rowset_ptr lpRows;
- hr = lpTable->QueryRows (1, 0, &~lpRows);
- if (hr != hrSuccess)
- return hr;
- if (lpRows->cRows == 0)
- break;
- auto lpPropDepth = PCpropFindProp(lpRows->aRow[0].lpProps,lpRows->aRow[0].cValues, PR_DEPTH);
- if (lpPropDepth == nullptr)
- return MAPI_E_CORRUPT_DATA; // Break the action
- hr = AddToFavorite(lpShortcutFolder, lpPropDepth->Value.ul + 1, NULL, 0, lpRows->aRow[0].cValues, lpRows->aRow[0].lpProps);
- if (hr != hrSuccess)
- // Break the action
- return hr;
- } //while(true)
- return hrSuccess;
- }
- } /* namespace */
|