1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "MapiDbgLog.h"
7 #include "MapiApi.h"
8
9 #include <sstream>
10 #include "rtfMailDecoder.h"
11
12 #include "prprf.h"
13 #include "nsMemory.h"
14 #include "nsMsgUtils.h"
15 #include "nsUnicharUtils.h"
16 #include "nsNativeCharsetUtils.h"
17
18 int CMapiApi::m_clients = 0;
19 BOOL CMapiApi::m_initialized = false;
20 nsTArray<CMsgStore*>* CMapiApi::m_pStores = NULL;
21 LPMAPISESSION CMapiApi::m_lpSession = NULL;
22 LPMDB CMapiApi::m_lpMdb = NULL;
23 HRESULT CMapiApi::m_lastError;
24 /*
25 Type: 1, name: Calendar, class: IPF.Appointment
26 Type: 1, name: Contacts, class: IPF.Contact
27 Type: 1, name: Journal, class: IPF.Journal
28 Type: 1, name: Notes, class: IPF.StickyNote
29 Type: 1, name: Tasks, class: IPF.Task
30 Type: 1, name: Drafts, class: IPF.Note
31 */
32
33 HINSTANCE CMapiApi::m_hMapi32 = NULL;
34
35 LPMAPIUNINITIALIZE gpMapiUninitialize = NULL;
36 LPMAPIINITIALIZE gpMapiInitialize = NULL;
37 LPMAPIALLOCATEBUFFER gpMapiAllocateBuffer = NULL;
38 LPMAPIFREEBUFFER gpMapiFreeBuffer = NULL;
39 LPMAPILOGONEX gpMapiLogonEx = NULL;
40 LPOPENSTREAMONFILE gpMapiOpenStreamOnFile = NULL;
41
42 typedef HRESULT(STDMETHODCALLTYPE WRAPCOMPRESSEDRTFSTREAM)(
43 LPSTREAM lpCompressedRTFStream, ULONG ulFlags,
44 LPSTREAM FAR* lpUncompressedRTFStream);
45 typedef WRAPCOMPRESSEDRTFSTREAM* LPWRAPCOMPRESSEDRTFSTREAM;
46 LPWRAPCOMPRESSEDRTFSTREAM gpWrapCompressedRTFStream = NULL;
47
48 // WrapCompressedRTFStreamEx related stuff - see
49 // http://support.microsoft.com/kb/839560
50 typedef struct {
51 ULONG size;
52 ULONG ulFlags;
53 ULONG ulInCodePage;
54 ULONG ulOutCodePage;
55 } RTF_WCSINFO;
56 typedef struct {
57 ULONG size;
58 ULONG ulStreamFlags;
59 } RTF_WCSRETINFO;
60
61 typedef HRESULT(STDMETHODCALLTYPE WRAPCOMPRESSEDRTFSTREAMEX)(
62 LPSTREAM lpCompressedRTFStream, CONST RTF_WCSINFO* pWCSInfo,
63 LPSTREAM* lppUncompressedRTFStream, RTF_WCSRETINFO* pRetInfo);
64 typedef WRAPCOMPRESSEDRTFSTREAMEX* LPWRAPCOMPRESSEDRTFSTREAMEX;
65 LPWRAPCOMPRESSEDRTFSTREAMEX gpWrapCompressedRTFStreamEx = NULL;
66
LoadMapiEntryPoints(void)67 BOOL CMapiApi::LoadMapiEntryPoints(void) {
68 if (!(gpMapiUninitialize =
69 (LPMAPIUNINITIALIZE)GetProcAddress(m_hMapi32, "MAPIUninitialize")))
70 return FALSE;
71 if (!(gpMapiInitialize =
72 (LPMAPIINITIALIZE)GetProcAddress(m_hMapi32, "MAPIInitialize")))
73 return FALSE;
74 if (!(gpMapiAllocateBuffer = (LPMAPIALLOCATEBUFFER)GetProcAddress(
75 m_hMapi32, "MAPIAllocateBuffer")))
76 return FALSE;
77 if (!(gpMapiFreeBuffer =
78 (LPMAPIFREEBUFFER)GetProcAddress(m_hMapi32, "MAPIFreeBuffer")))
79 return FALSE;
80 if (!(gpMapiLogonEx =
81 (LPMAPILOGONEX)GetProcAddress(m_hMapi32, "MAPILogonEx")))
82 return FALSE;
83 if (!(gpMapiOpenStreamOnFile =
84 (LPOPENSTREAMONFILE)GetProcAddress(m_hMapi32, "OpenStreamOnFile")))
85 return FALSE;
86
87 // Available from the Outlook 2002 post-SP3 hotfix
88 // (http://support.microsoft.com/kb/883924/) Exported by msmapi32.dll; so it's
89 // unavailable to us using mapi32.dll
90 gpWrapCompressedRTFStreamEx = (LPWRAPCOMPRESSEDRTFSTREAMEX)GetProcAddress(
91 m_hMapi32, "WrapCompressedRTFStreamEx");
92 // Available always
93 gpWrapCompressedRTFStream = (LPWRAPCOMPRESSEDRTFSTREAM)GetProcAddress(
94 m_hMapi32, "WrapCompressedRTFStream");
95
96 return TRUE;
97 }
98
99 // Gets the PR_RTF_COMPRESSED tag property
100 // Codepage is used only if the WrapCompressedRTFStreamEx is available
GetRTFPropertyDecodedAsUTF16(LPMAPIPROP pProp,nsString & val,unsigned long & nativeBodyType,unsigned long codepage)101 BOOL CMapiApi::GetRTFPropertyDecodedAsUTF16(LPMAPIPROP pProp, nsString& val,
102 unsigned long& nativeBodyType,
103 unsigned long codepage) {
104 if (!m_hMapi32 || !(gpWrapCompressedRTFStreamEx || gpWrapCompressedRTFStream))
105 return FALSE; // Fallback to the default processing
106
107 LPSTREAM icstream = 0; // for the compressed stream
108 LPSTREAM iunstream = 0; // for the uncompressed stream
109 HRESULT hr =
110 pProp->OpenProperty(PR_RTF_COMPRESSED, &IID_IStream,
111 STGM_READ | STGM_DIRECT, 0, (LPUNKNOWN*)&icstream);
112 if (HR_FAILED(hr)) return FALSE;
113
114 if (gpWrapCompressedRTFStreamEx) { // Impossible - we use mapi32.dll!
115 RTF_WCSINFO wcsinfo = {0};
116 RTF_WCSRETINFO retinfo = {0};
117
118 retinfo.size = sizeof(RTF_WCSRETINFO);
119
120 wcsinfo.size = sizeof(RTF_WCSINFO);
121 wcsinfo.ulFlags = MAPI_NATIVE_BODY;
122 wcsinfo.ulInCodePage = codepage;
123 wcsinfo.ulOutCodePage = CP_UTF8;
124
125 if (HR_SUCCEEDED(hr = gpWrapCompressedRTFStreamEx(icstream, &wcsinfo,
126 &iunstream, &retinfo)))
127 nativeBodyType = retinfo.ulStreamFlags;
128 } else { // mapi32.dll
129 gpWrapCompressedRTFStream(icstream, 0, &iunstream);
130 }
131 icstream->Release();
132
133 if (iunstream) { // Succeeded
134 std::string streamData;
135 // Stream.Stat doesn't work for this stream!
136 bool done = false;
137 while (!done) {
138 // I think 10K is a good guess to minimize the number of reads while
139 // keeping memory usage low
140 const int bufsize = 10240;
141 char buf[bufsize];
142 ULONG read;
143 hr = iunstream->Read(buf, bufsize, &read);
144 done = (read < bufsize) || (hr != S_OK);
145 if (read) streamData.append(buf, read);
146 }
147 iunstream->Release();
148 // if rtf -> convert to plain text.
149 if (!gpWrapCompressedRTFStreamEx ||
150 (nativeBodyType == MAPI_NATIVE_BODY_TYPE_RTF)) {
151 std::stringstream s(streamData);
152 CRTFMailDecoder decoder;
153 DecodeRTF(s, decoder);
154 if (decoder.mode() == CRTFMailDecoder::mHTML)
155 nativeBodyType = MAPI_NATIVE_BODY_TYPE_HTML;
156 else if (decoder.mode() == CRTFMailDecoder::mText)
157 nativeBodyType = MAPI_NATIVE_BODY_TYPE_PLAINTEXT;
158 else
159 nativeBodyType = MAPI_NATIVE_BODY_TYPE_RTF;
160 val.Assign(decoder.text(), decoder.textSize());
161 } else { // WrapCompressedRTFStreamEx available and original type is not
162 // rtf
163 CopyUTF8toUTF16(nsDependentCString(streamData.c_str()), val);
164 }
165 return TRUE;
166 }
167 return FALSE;
168 }
169
MAPIUninitialize(void)170 void CMapiApi::MAPIUninitialize(void) {
171 if (m_hMapi32 && gpMapiUninitialize) (*gpMapiUninitialize)();
172 }
173
MAPIInitialize(LPVOID lpInit)174 HRESULT CMapiApi::MAPIInitialize(LPVOID lpInit) {
175 return (m_hMapi32 && gpMapiInitialize) ? (*gpMapiInitialize)(lpInit)
176 : MAPI_E_NOT_INITIALIZED;
177 }
178
MAPIAllocateBuffer(ULONG cbSize,LPVOID FAR * lppBuffer)179 SCODE CMapiApi::MAPIAllocateBuffer(ULONG cbSize, LPVOID FAR* lppBuffer) {
180 return (m_hMapi32 && gpMapiAllocateBuffer)
181 ? (*gpMapiAllocateBuffer)(cbSize, lppBuffer)
182 : MAPI_E_NOT_INITIALIZED;
183 }
184
MAPIFreeBuffer(LPVOID lpBuff)185 ULONG CMapiApi::MAPIFreeBuffer(LPVOID lpBuff) {
186 return (m_hMapi32 && gpMapiFreeBuffer) ? (*gpMapiFreeBuffer)(lpBuff)
187 : MAPI_E_NOT_INITIALIZED;
188 }
189
MAPILogonEx(ULONG ulUIParam,LPTSTR lpszProfileName,LPTSTR lpszPassword,FLAGS flFlags,LPMAPISESSION FAR * lppSession)190 HRESULT CMapiApi::MAPILogonEx(ULONG ulUIParam, LPTSTR lpszProfileName,
191 LPTSTR lpszPassword, FLAGS flFlags,
192 LPMAPISESSION FAR* lppSession) {
193 return (m_hMapi32 && gpMapiLogonEx)
194 ? (*gpMapiLogonEx)(ulUIParam, lpszProfileName, lpszPassword,
195 flFlags, lppSession)
196 : MAPI_E_NOT_INITIALIZED;
197 }
198
OpenStreamOnFile(LPALLOCATEBUFFER lpAllocateBuffer,LPFREEBUFFER lpFreeBuffer,ULONG ulFlags,LPCTSTR lpszFileName,LPTSTR lpszPrefix,LPSTREAM FAR * lppStream)199 HRESULT CMapiApi::OpenStreamOnFile(LPALLOCATEBUFFER lpAllocateBuffer,
200 LPFREEBUFFER lpFreeBuffer, ULONG ulFlags,
201 LPCTSTR lpszFileName, LPTSTR lpszPrefix,
202 LPSTREAM FAR* lppStream) {
203 return (m_hMapi32 && gpMapiOpenStreamOnFile)
204 ? (*gpMapiOpenStreamOnFile)(lpAllocateBuffer, lpFreeBuffer,
205 ulFlags, lpszFileName, lpszPrefix,
206 lppStream)
207 : MAPI_E_NOT_INITIALIZED;
208 }
209
FreeProws(LPSRowSet prows)210 void CMapiApi::FreeProws(LPSRowSet prows) {
211 ULONG irow;
212 if (!prows) return;
213 for (irow = 0; irow < prows->cRows; ++irow)
214 MAPIFreeBuffer(prows->aRow[irow].lpProps);
215 MAPIFreeBuffer(prows);
216 }
217
LoadMapi(void)218 BOOL CMapiApi::LoadMapi(void) {
219 if (m_hMapi32) return TRUE;
220
221 HINSTANCE hInst = ::LoadLibraryW(L"MAPI32.DLL");
222 if (!hInst) return FALSE;
223 FARPROC pProc = GetProcAddress(hInst, "MAPIGetNetscapeVersion");
224 if (pProc) {
225 ::FreeLibrary(hInst);
226 hInst = ::LoadLibraryW(L"MAPI32BAK.DLL");
227 if (!hInst) return FALSE;
228 }
229
230 m_hMapi32 = hInst;
231 return LoadMapiEntryPoints();
232 }
233
UnloadMapi(void)234 void CMapiApi::UnloadMapi(void) {
235 if (m_hMapi32) ::FreeLibrary(m_hMapi32);
236 m_hMapi32 = NULL;
237 }
238
CMapiApi()239 CMapiApi::CMapiApi() {
240 m_clients++;
241 LoadMapi();
242 if (!m_pStores) m_pStores = new nsTArray<CMsgStore*>();
243 }
244
~CMapiApi()245 CMapiApi::~CMapiApi() {
246 m_clients--;
247 if (!m_clients) {
248 HRESULT hr;
249
250 ClearMessageStores();
251 delete m_pStores;
252 m_pStores = NULL;
253
254 m_lpMdb = NULL;
255
256 if (m_lpSession) {
257 hr = m_lpSession->Logoff(NULL, 0, 0);
258 if (FAILED(hr)) {
259 MAPI_TRACE2("Logoff failed: 0x%lx, %d\n", (long)hr, (int)hr);
260 }
261 m_lpSession->Release();
262 m_lpSession = NULL;
263 }
264
265 if (m_initialized) {
266 MAPIUninitialize();
267 m_initialized = FALSE;
268 }
269
270 UnloadMapi();
271 }
272 }
273
CStrToUnicode(const char * pStr,nsString & result)274 void CMapiApi::CStrToUnicode(const char* pStr, nsString& result) {
275 NS_CopyNativeToUnicode(nsDependentCString(pStr), result);
276 }
277
Initialize(void)278 BOOL CMapiApi::Initialize(void) {
279 if (m_initialized) return TRUE;
280
281 HRESULT hr;
282
283 hr = MAPIInitialize(NULL);
284
285 if (FAILED(hr)) {
286 MAPI_TRACE2("MAPI Initialize failed: 0x%lx, %d\n", (long)hr, (int)hr);
287 return FALSE;
288 }
289
290 m_initialized = TRUE;
291 MAPI_TRACE0("MAPI Initialized\n");
292
293 return TRUE;
294 }
295
LogOn(void)296 BOOL CMapiApi::LogOn(void) {
297 if (!m_initialized) {
298 MAPI_TRACE0("Tried to LogOn before initializing MAPI\n");
299 return FALSE;
300 }
301
302 if (m_lpSession) return TRUE;
303
304 HRESULT hr;
305
306 hr = MAPILogonEx(
307 0, // might need to be passed in HWND
308 NULL, // profile name, 64 char max (LPTSTR)
309 NULL, // profile password, 64 char max (LPTSTR)
310 // MAPI_NEW_SESSION | MAPI_NO_MAIL | MAPI_LOGON_UI |
311 // MAPI_EXPLICIT_PROFILE, MAPI_NEW_SESSION | MAPI_NO_MAIL | MAPI_LOGON_UI,
312 // MAPI_NO_MAIL | MAPI_LOGON_UI,
313 MAPI_NO_MAIL | MAPI_USE_DEFAULT | MAPI_EXTENDED | MAPI_NEW_SESSION,
314 &m_lpSession);
315
316 if (FAILED(hr)) {
317 m_lpSession = NULL;
318 MAPI_TRACE2("LogOn failed: 0x%lx, %d\n", (long)hr, (int)hr);
319 return FALSE;
320 }
321
322 MAPI_TRACE0("MAPI Logged on\n");
323 return TRUE;
324 }
325
326 class CGetStoreFoldersIter : public CMapiHierarchyIter {
327 public:
328 CGetStoreFoldersIter(CMapiApi* pApi, CMapiFolderList& folders, int depth,
329 BOOL isMail = TRUE);
330
331 virtual BOOL HandleHierarchyItem(ULONG oType, ULONG cb, LPENTRYID pEntry);
332
333 protected:
334 BOOL ExcludeFolderClass(const char16_t* pName);
335
336 BOOL m_isMail;
337 CMapiApi* m_pApi;
338 CMapiFolderList* m_pList;
339 int m_depth;
340 };
341
CGetStoreFoldersIter(CMapiApi * pApi,CMapiFolderList & folders,int depth,BOOL isMail)342 CGetStoreFoldersIter::CGetStoreFoldersIter(CMapiApi* pApi,
343 CMapiFolderList& folders, int depth,
344 BOOL isMail) {
345 m_pApi = pApi;
346 m_pList = &folders;
347 m_depth = depth;
348 m_isMail = isMail;
349 }
350
ExcludeFolderClass(const char16_t * pName)351 BOOL CGetStoreFoldersIter::ExcludeFolderClass(const char16_t* pName) {
352 BOOL bResult;
353 nsDependentString pNameStr(pName);
354 if (m_isMail) {
355 bResult = FALSE;
356 if (pNameStr.EqualsLiteral("IPF.Appointment"))
357 bResult = TRUE;
358 else if (pNameStr.EqualsLiteral("IPF.Contact"))
359 bResult = TRUE;
360 else if (pNameStr.EqualsLiteral("IPF.Journal"))
361 bResult = TRUE;
362 else if (pNameStr.EqualsLiteral("IPF.StickyNote"))
363 bResult = TRUE;
364 else if (pNameStr.EqualsLiteral("IPF.Task"))
365 bResult = TRUE;
366 // Skip IMAP folders
367 else if (pNameStr.EqualsLiteral("IPF.Imap"))
368 bResult = TRUE;
369 // else if (!stricmp(pName, "IPF.Note"))
370 // bResult = TRUE;
371 } else {
372 bResult = TRUE;
373 if (pNameStr.EqualsLiteral("IPF.Contact")) bResult = FALSE;
374 }
375
376 return bResult;
377 }
378
HandleHierarchyItem(ULONG oType,ULONG cb,LPENTRYID pEntry)379 BOOL CGetStoreFoldersIter::HandleHierarchyItem(ULONG oType, ULONG cb,
380 LPENTRYID pEntry) {
381 if (oType == MAPI_FOLDER) {
382 LPMAPIFOLDER pFolder;
383 if (m_pApi->OpenEntry(cb, pEntry, (LPUNKNOWN*)&pFolder)) {
384 LPSPropValue pVal;
385 nsString name;
386
387 pVal = m_pApi->GetMapiProperty(pFolder, PR_CONTAINER_CLASS);
388 if (pVal)
389 m_pApi->GetStringFromProp(pVal, name);
390 else
391 name.Truncate();
392
393 if ((name.IsEmpty() && m_isMail) || (!ExcludeFolderClass(name.get()))) {
394 pVal = m_pApi->GetMapiProperty(pFolder, PR_DISPLAY_NAME);
395 m_pApi->GetStringFromProp(pVal, name);
396 CMapiFolder* pNewFolder =
397 new CMapiFolder(name.get(), cb, pEntry, m_depth);
398 m_pList->AddItem(pNewFolder);
399
400 pVal = m_pApi->GetMapiProperty(pFolder, PR_FOLDER_TYPE);
401 MAPI_TRACE2("Type: %d, name: %s\n", m_pApi->GetLongFromProp(pVal),
402 name.get());
403 // m_pApi->ListProperties(pFolder);
404
405 CGetStoreFoldersIter nextIter(m_pApi, *m_pList, m_depth + 1, m_isMail);
406 m_pApi->IterateHierarchy(&nextIter, pFolder);
407 }
408 pFolder->Release();
409 } else {
410 MAPI_TRACE0(
411 "GetStoreFolders - HandleHierarchyItem: Error opening folder "
412 "entry.\n");
413 return FALSE;
414 }
415 } else
416 MAPI_TRACE1(
417 "GetStoreFolders - HandleHierarchyItem: Unhandled ObjectType: %ld\n",
418 oType);
419 return TRUE;
420 }
421
GetStoreFolders(ULONG cbEid,LPENTRYID lpEid,CMapiFolderList & folders,int startDepth)422 BOOL CMapiApi::GetStoreFolders(ULONG cbEid, LPENTRYID lpEid,
423 CMapiFolderList& folders, int startDepth) {
424 // Fill in the array with the folders in the given store
425 if (!m_initialized || !m_lpSession) {
426 MAPI_TRACE0("MAPI not initialized for GetStoreFolders\n");
427 return FALSE;
428 }
429
430 m_lpMdb = NULL;
431
432 CMsgStore* pStore = FindMessageStore(cbEid, lpEid);
433 BOOL bResult = FALSE;
434 LPSPropValue pVal;
435
436 if (pStore && pStore->Open(m_lpSession, &m_lpMdb)) {
437 // Successful open, do the iteration of the store
438 pVal = GetMapiProperty(m_lpMdb, PR_IPM_SUBTREE_ENTRYID);
439 if (pVal) {
440 ULONG cbEntry;
441 LPENTRYID pEntry;
442 LPMAPIFOLDER lpSubTree = NULL;
443
444 if (GetEntryIdFromProp(pVal, cbEntry, pEntry)) {
445 // Open up the folder!
446 bResult = OpenEntry(cbEntry, pEntry, (LPUNKNOWN*)&lpSubTree);
447 MAPIFreeBuffer(pEntry);
448 if (bResult && lpSubTree) {
449 // Iterate the subtree with the results going into the folder list
450 CGetStoreFoldersIter iterHandler(this, folders, startDepth);
451 bResult = IterateHierarchy(&iterHandler, lpSubTree);
452 lpSubTree->Release();
453 } else {
454 MAPI_TRACE0("GetStoreFolders: Error opening sub tree.\n");
455 }
456 } else {
457 MAPI_TRACE0(
458 "GetStoreFolders: Error getting entryID from sub tree property "
459 "val.\n");
460 }
461 } else {
462 MAPI_TRACE0("GetStoreFolders: Error getting sub tree property.\n");
463 }
464 } else {
465 MAPI_TRACE0("GetStoreFolders: Error opening message store.\n");
466 }
467
468 return bResult;
469 }
470
GetStoreAddressFolders(ULONG cbEid,LPENTRYID lpEid,CMapiFolderList & folders)471 BOOL CMapiApi::GetStoreAddressFolders(ULONG cbEid, LPENTRYID lpEid,
472 CMapiFolderList& folders) {
473 // Fill in the array with the folders in the given store
474 if (!m_initialized || !m_lpSession) {
475 MAPI_TRACE0("MAPI not initialized for GetStoreAddressFolders\n");
476 return FALSE;
477 }
478
479 m_lpMdb = NULL;
480
481 CMsgStore* pStore = FindMessageStore(cbEid, lpEid);
482 BOOL bResult = FALSE;
483 LPSPropValue pVal;
484
485 if (pStore && pStore->Open(m_lpSession, &m_lpMdb)) {
486 // Successful open, do the iteration of the store
487 pVal = GetMapiProperty(m_lpMdb, PR_IPM_SUBTREE_ENTRYID);
488 if (pVal) {
489 ULONG cbEntry;
490 LPENTRYID pEntry;
491 LPMAPIFOLDER lpSubTree = NULL;
492
493 if (GetEntryIdFromProp(pVal, cbEntry, pEntry)) {
494 // Open up the folder!
495 bResult = OpenEntry(cbEntry, pEntry, (LPUNKNOWN*)&lpSubTree);
496 MAPIFreeBuffer(pEntry);
497 if (bResult && lpSubTree) {
498 // Iterate the subtree with the results going into the folder list
499 CGetStoreFoldersIter iterHandler(this, folders, 1, FALSE);
500 bResult = IterateHierarchy(&iterHandler, lpSubTree);
501 lpSubTree->Release();
502 } else {
503 MAPI_TRACE0("GetStoreAddressFolders: Error opening sub tree.\n");
504 }
505 } else {
506 MAPI_TRACE0(
507 "GetStoreAddressFolders: Error getting entryID from sub tree "
508 "property val.\n");
509 }
510 } else {
511 MAPI_TRACE0("GetStoreAddressFolders: Error getting sub tree property.\n");
512 }
513 } else
514 MAPI_TRACE0("GetStoreAddressFolders: Error opening message store.\n");
515
516 return bResult;
517 }
518
OpenStore(ULONG cbEid,LPENTRYID lpEid,LPMDB * ppMdb)519 BOOL CMapiApi::OpenStore(ULONG cbEid, LPENTRYID lpEid, LPMDB* ppMdb) {
520 if (!m_lpSession) {
521 MAPI_TRACE0("OpenStore called before a session was opened\n");
522 return FALSE;
523 }
524
525 CMsgStore* pStore = FindMessageStore(cbEid, lpEid);
526 if (pStore && pStore->Open(m_lpSession, ppMdb)) return TRUE;
527 return FALSE;
528 }
529
OpenEntry(ULONG cbEntry,LPENTRYID pEntryId,LPUNKNOWN * ppOpen)530 BOOL CMapiApi::OpenEntry(ULONG cbEntry, LPENTRYID pEntryId, LPUNKNOWN* ppOpen) {
531 if (!m_lpMdb) {
532 MAPI_TRACE0("OpenEntry called before the message store is open\n");
533 return FALSE;
534 }
535
536 return OpenMdbEntry(m_lpMdb, cbEntry, pEntryId, ppOpen);
537 }
538
OpenMdbEntry(LPMDB lpMdb,ULONG cbEntry,LPENTRYID pEntryId,LPUNKNOWN * ppOpen)539 BOOL CMapiApi::OpenMdbEntry(LPMDB lpMdb, ULONG cbEntry, LPENTRYID pEntryId,
540 LPUNKNOWN* ppOpen) {
541 ULONG ulObjType;
542 HRESULT hr;
543 hr = m_lpSession->OpenEntry(cbEntry, pEntryId, NULL, 0, &ulObjType,
544 (LPUNKNOWN*)ppOpen);
545 if (FAILED(hr)) {
546 MAPI_TRACE2("OpenMdbEntry failed: 0x%lx, %d\n", (long)hr, (int)hr);
547 return FALSE;
548 }
549 return TRUE;
550 }
551
552 enum { ieidPR_ENTRYID = 0, ieidPR_OBJECT_TYPE, ieidMax };
553
554 static const SizedSPropTagArray(ieidMax, ptaEid) = {ieidMax,
555 {
556 PR_ENTRYID,
557 PR_OBJECT_TYPE,
558 }};
559
IterateContents(CMapiContentIter * pIter,LPMAPIFOLDER pFolder,ULONG flags)560 BOOL CMapiApi::IterateContents(CMapiContentIter* pIter, LPMAPIFOLDER pFolder,
561 ULONG flags) {
562 // flags can be 0 or MAPI_ASSOCIATED
563 // MAPI_ASSOCIATED is usually used for forms and views
564
565 HRESULT hr;
566 LPMAPITABLE lpTable;
567 hr = pFolder->GetContentsTable(flags, &lpTable);
568 if (FAILED(hr)) {
569 MAPI_TRACE2("GetContentsTable failed: 0x%lx, %d\n", (long)hr, (int)hr);
570 return FALSE;
571 }
572
573 ULONG rowCount;
574 hr = lpTable->GetRowCount(0, &rowCount);
575 if (!rowCount) {
576 MAPI_TRACE0(" Empty Table\n");
577 }
578
579 hr = lpTable->SetColumns((LPSPropTagArray)&ptaEid, 0);
580 if (FAILED(hr)) {
581 lpTable->Release();
582 MAPI_TRACE2("SetColumns failed: 0x%lx, %d\n", (long)hr, (int)hr);
583 return FALSE;
584 }
585
586 hr = lpTable->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
587 if (FAILED(hr)) {
588 lpTable->Release();
589 MAPI_TRACE2("SeekRow failed: 0x%lx, %d\n", (long)hr, (int)hr);
590 return FALSE;
591 }
592
593 int cNumRows = 0;
594 LPSRowSet lpRow;
595 BOOL keepGoing = TRUE;
596 BOOL bResult = TRUE;
597 do {
598 lpRow = NULL;
599 hr = lpTable->QueryRows(1, 0, &lpRow);
600 if (HR_FAILED(hr)) {
601 MAPI_TRACE2("QueryRows failed: 0x%lx, %d\n", (long)hr, (int)hr);
602 bResult = FALSE;
603 break;
604 }
605
606 if (lpRow) {
607 cNumRows = lpRow->cRows;
608 if (cNumRows) {
609 LPENTRYID lpEID =
610 (LPENTRYID)lpRow->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
611 ULONG cbEID = lpRow->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb;
612 ULONG oType = lpRow->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.ul;
613 keepGoing = HandleContentsItem(oType, cbEID, lpEID);
614 MAPI_TRACE1(" ObjectType: %ld\n", oType);
615 }
616 FreeProws(lpRow);
617 }
618
619 } while (SUCCEEDED(hr) && cNumRows && lpRow && keepGoing);
620
621 lpTable->Release();
622 return bResult;
623 }
624
HandleContentsItem(ULONG oType,ULONG cb,LPENTRYID pEntry)625 BOOL CMapiApi::HandleContentsItem(ULONG oType, ULONG cb, LPENTRYID pEntry) {
626 if (oType == MAPI_MESSAGE) {
627 LPMESSAGE pMsg;
628 if (OpenEntry(cb, pEntry, (LPUNKNOWN*)&pMsg)) {
629 LPSPropValue pVal;
630 pVal = GetMapiProperty(pMsg, PR_SUBJECT);
631 ReportStringProp("PR_SUBJECT:", pVal);
632 pVal = GetMapiProperty(pMsg, PR_DISPLAY_BCC);
633 ReportStringProp("PR_DISPLAY_BCC:", pVal);
634 pVal = GetMapiProperty(pMsg, PR_DISPLAY_CC);
635 ReportStringProp("PR_DISPLAY_CC:", pVal);
636 pVal = GetMapiProperty(pMsg, PR_DISPLAY_TO);
637 ReportStringProp("PR_DISPLAY_TO:", pVal);
638 pVal = GetMapiProperty(pMsg, PR_MESSAGE_CLASS);
639 ReportStringProp("PR_MESSAGE_CLASS:", pVal);
640 ListProperties(pMsg);
641 pMsg->Release();
642 } else {
643 MAPI_TRACE0(" Folder type - error opening\n");
644 }
645 } else
646 MAPI_TRACE1(" ObjectType: %ld\n", oType);
647
648 return TRUE;
649 }
650
ListProperties(LPMAPIPROP lpProp,BOOL getValues)651 void CMapiApi::ListProperties(LPMAPIPROP lpProp, BOOL getValues) {
652 LPSPropTagArray pArray;
653 HRESULT hr = lpProp->GetPropList(0, &pArray);
654 if (FAILED(hr)) {
655 MAPI_TRACE0(" Unable to retrieve property list\n");
656 return;
657 }
658 ULONG count = 0;
659 LPMAPINAMEID FAR* lppPropNames;
660 SPropTagArray tagArray;
661 LPSPropTagArray lpTagArray = &tagArray;
662 tagArray.cValues = (ULONG)1;
663 nsCString desc;
664 for (ULONG i = 0; i < pArray->cValues; i++) {
665 GetPropTagName(pArray->aulPropTag[i], desc);
666 if (getValues) {
667 tagArray.aulPropTag[0] = pArray->aulPropTag[i];
668 hr = lpProp->GetNamesFromIDs(&lpTagArray, nullptr, 0, &count,
669 &lppPropNames);
670 if (hr == S_OK) MAPIFreeBuffer(lppPropNames);
671
672 LPSPropValue pVal = GetMapiProperty(lpProp, pArray->aulPropTag[i]);
673 if (pVal) {
674 desc += ", ";
675 ListPropertyValue(pVal, desc);
676 MAPIFreeBuffer(pVal);
677 }
678 }
679 MAPI_TRACE2(" Tag #%d: %s\n", (int)i, desc.get());
680 }
681
682 MAPIFreeBuffer(pArray);
683 }
684
GetEmailPropertyTag(LPMAPIPROP lpProp,LONG nameID)685 ULONG CMapiApi::GetEmailPropertyTag(LPMAPIPROP lpProp, LONG nameID) {
686 static GUID emailGUID = {0x00062004,
687 0x0000,
688 0x0000,
689 {0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
690
691 MAPINAMEID mapiNameID;
692 mapiNameID.lpguid = &emailGUID;
693 mapiNameID.ulKind = MNID_ID;
694 mapiNameID.Kind.lID = nameID;
695
696 LPMAPINAMEID lpMapiNames = &mapiNameID;
697 LPSPropTagArray lpMailTagArray = nullptr;
698
699 HRESULT result =
700 lpProp->GetIDsFromNames(1L, &lpMapiNames, 0, &lpMailTagArray);
701 if (result == S_OK) {
702 ULONG lTag = lpMailTagArray->aulPropTag[0];
703 MAPIFreeBuffer(lpMailTagArray);
704 return lTag;
705 } else
706 return 0L;
707 }
708
HandleHierarchyItem(ULONG oType,ULONG cb,LPENTRYID pEntry)709 BOOL CMapiApi::HandleHierarchyItem(ULONG oType, ULONG cb, LPENTRYID pEntry) {
710 if (oType == MAPI_FOLDER) {
711 LPMAPIFOLDER pFolder;
712 if (OpenEntry(cb, pEntry, (LPUNKNOWN*)&pFolder)) {
713 LPSPropValue pVal;
714 pVal = GetMapiProperty(pFolder, PR_DISPLAY_NAME);
715 ReportStringProp("Folder name:", pVal);
716 IterateContents(NULL, pFolder);
717 IterateHierarchy(NULL, pFolder);
718 pFolder->Release();
719 } else {
720 MAPI_TRACE0(" Folder type - error opening\n");
721 }
722 } else
723 MAPI_TRACE1(" ObjectType: %ld\n", oType);
724
725 return TRUE;
726 }
727
IterateHierarchy(CMapiHierarchyIter * pIter,LPMAPIFOLDER pFolder,ULONG flags)728 BOOL CMapiApi::IterateHierarchy(CMapiHierarchyIter* pIter, LPMAPIFOLDER pFolder,
729 ULONG flags) {
730 // flags can be CONVENIENT_DEPTH or 0
731 // CONVENIENT_DEPTH will return all depths I believe instead
732 // of just children
733 HRESULT hr;
734 LPMAPITABLE lpTable;
735 hr = pFolder->GetHierarchyTable(flags, &lpTable);
736 if (HR_FAILED(hr)) {
737 m_lastError = hr;
738 MAPI_TRACE2("IterateHierarchy: GetContentsTable failed: 0x%lx, %d\n",
739 (long)hr, (int)hr);
740 return FALSE;
741 }
742
743 ULONG rowCount;
744 hr = lpTable->GetRowCount(0, &rowCount);
745 if (!rowCount) {
746 lpTable->Release();
747 return TRUE;
748 }
749
750 hr = lpTable->SetColumns((LPSPropTagArray)&ptaEid, 0);
751 if (HR_FAILED(hr)) {
752 m_lastError = hr;
753 lpTable->Release();
754 MAPI_TRACE2("IterateHierarchy: SetColumns failed: 0x%lx, %d\n", (long)hr,
755 (int)hr);
756 return FALSE;
757 }
758
759 hr = lpTable->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
760 if (HR_FAILED(hr)) {
761 m_lastError = hr;
762 lpTable->Release();
763 MAPI_TRACE2("IterateHierarchy: SeekRow failed: 0x%lx, %d\n", (long)hr,
764 (int)hr);
765 return FALSE;
766 }
767
768 int cNumRows = 0;
769 LPSRowSet lpRow;
770 BOOL keepGoing = TRUE;
771 BOOL bResult = TRUE;
772 do {
773 lpRow = NULL;
774 hr = lpTable->QueryRows(1, 0, &lpRow);
775
776 if (HR_FAILED(hr)) {
777 MAPI_TRACE2("QueryRows failed: 0x%lx, %d\n", (long)hr, (int)hr);
778 m_lastError = hr;
779 bResult = FALSE;
780 break;
781 }
782
783 if (lpRow) {
784 cNumRows = lpRow->cRows;
785
786 if (cNumRows) {
787 LPENTRYID lpEntry =
788 (LPENTRYID)lpRow->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
789 ULONG cb = lpRow->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb;
790 ULONG oType = lpRow->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.ul;
791
792 if (pIter)
793 keepGoing = pIter->HandleHierarchyItem(oType, cb, lpEntry);
794 else
795 keepGoing = HandleHierarchyItem(oType, cb, lpEntry);
796 }
797 FreeProws(lpRow);
798 }
799 } while (SUCCEEDED(hr) && cNumRows && lpRow && keepGoing);
800
801 lpTable->Release();
802
803 if (bResult && !keepGoing) bResult = FALSE;
804
805 return bResult;
806 }
807
808 enum { itblPR_DISPLAY_NAME, itblPR_ENTRYID, itblMax };
809
810 static const SizedSPropTagArray(itblMax, ptaTbl) = {itblMax,
811 {
812 PR_DISPLAY_NAME,
813 PR_ENTRYID,
814 }};
815
IterateStores(CMapiFolderList & stores)816 BOOL CMapiApi::IterateStores(CMapiFolderList& stores) {
817 stores.ClearAll();
818
819 if (!m_lpSession) {
820 MAPI_TRACE0("IterateStores called before session is open\n");
821 m_lastError = E_UNEXPECTED;
822 return FALSE;
823 }
824
825 HRESULT hr;
826
827 /* -- Some Microsoft sample code just to see if things are working --- */ /*
828
829 ULONG cbEIDStore;
830 LPENTRYID lpEIDStore;
831
832 hr = HrMAPIFindDefaultMsgStore(m_lpSession, &cbEIDStore, &lpEIDStore);
833 if (HR_FAILED(hr)) {
834 MAPI_TRACE0("Default message store not found\n");
835 // MessageBoxW(NULL, L"Message Store Not Found", NULL, MB_OK);
836 }
837 else {
838 LPMDB lpStore;
839 MAPI_TRACE0("Default Message store FOUND\n");
840 hr = m_lpSession->OpenMsgStore(NULL, cbEIDStore,
841 lpEIDStore, NULL,
842 MDB_NO_MAIL | MDB_NO_DIALOG, &lpStore);
843 if (HR_FAILED(hr)) {
844 MAPI_TRACE1("Unable to open default message store: 0x%lx\n", hr);
845 }
846 else {
847 MAPI_TRACE0("Default message store OPENED\n");
848 lpStore->Release();
849 }
850 }
851 */
852
853 LPMAPITABLE lpTable;
854
855 hr = m_lpSession->GetMsgStoresTable(0, &lpTable);
856 if (FAILED(hr)) {
857 MAPI_TRACE0("GetMsgStoresTable failed\n");
858 m_lastError = hr;
859 return FALSE;
860 }
861
862 ULONG rowCount;
863 hr = lpTable->GetRowCount(0, &rowCount);
864 MAPI_TRACE1("MsgStores Table rowCount: %ld\n", rowCount);
865
866 hr = lpTable->SetColumns((LPSPropTagArray)&ptaTbl, 0);
867 if (FAILED(hr)) {
868 lpTable->Release();
869 MAPI_TRACE2("SetColumns failed: 0x%lx, %d\n", (long)hr, (int)hr);
870 m_lastError = hr;
871 return FALSE;
872 }
873
874 hr = lpTable->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
875 if (FAILED(hr)) {
876 lpTable->Release();
877 MAPI_TRACE2("SeekRow failed: 0x%lx, %d\n", (long)hr, (int)hr);
878 m_lastError = hr;
879 return FALSE;
880 }
881
882 int cNumRows = 0;
883 LPSRowSet lpRow;
884 BOOL keepGoing = TRUE;
885 BOOL bResult = TRUE;
886 do {
887 lpRow = NULL;
888 hr = lpTable->QueryRows(1, 0, &lpRow);
889
890 if (HR_FAILED(hr)) {
891 MAPI_TRACE2("QueryRows failed: 0x%lx, %d\n", (long)hr, (int)hr);
892 bResult = FALSE;
893 m_lastError = hr;
894 break;
895 }
896
897 if (lpRow) {
898 cNumRows = lpRow->cRows;
899
900 if (cNumRows) {
901 LPCTSTR lpStr =
902 (LPCTSTR)lpRow->aRow[0].lpProps[itblPR_DISPLAY_NAME].Value.LPSZ;
903 LPENTRYID lpEID =
904 (LPENTRYID)lpRow->aRow[0].lpProps[itblPR_ENTRYID].Value.bin.lpb;
905 ULONG cbEID = lpRow->aRow[0].lpProps[itblPR_ENTRYID].Value.bin.cb;
906
907 // In the future, GetStoreInfo needs to somehow return
908 // whether or not the store is from an IMAP server.
909 // Currently, GetStoreInfo opens the store and attempts
910 // to get the hierarchy tree. If the tree is empty or
911 // does not exist, then szContents will be zero. We'll
912 // assume that any store that doesn't have anything in
913 // it's hierarchy tree is not a store we want to import -
914 // there would be nothing to import from anyway!
915 // Currently, this does exclude IMAP server accounts
916 // which is the desired behaviour.
917
918 int strLen = strlen(lpStr);
919 char16_t* pwszStr =
920 (char16_t*)moz_xmalloc((strLen + 1) * sizeof(WCHAR));
921 if (!pwszStr) {
922 // out of memory
923 FreeProws(lpRow);
924 lpTable->Release();
925 return FALSE;
926 }
927 ::MultiByteToWideChar(CP_ACP, 0, lpStr, strlen(lpStr) + 1,
928 reinterpret_cast<wchar_t*>(pwszStr),
929 (strLen + 1) * sizeof(WCHAR));
930 CMapiFolder* pFolder =
931 new CMapiFolder(pwszStr, cbEID, lpEID, 0, MAPI_STORE);
932 free(pwszStr);
933
934 long szContents = 1;
935 GetStoreInfo(pFolder, &szContents);
936
937 MAPI_TRACE1(" DisplayName: %s\n", lpStr);
938 if (szContents)
939 stores.AddItem(pFolder);
940 else {
941 delete pFolder;
942 MAPI_TRACE0(" ^^^^^ Not added to store list\n");
943 }
944
945 keepGoing = TRUE;
946 }
947 FreeProws(lpRow);
948 }
949 } while (SUCCEEDED(hr) && cNumRows && lpRow && keepGoing);
950
951 lpTable->Release();
952
953 return bResult;
954 }
955
GetStoreInfo(CMapiFolder * pFolder,long * pSzContents)956 void CMapiApi::GetStoreInfo(CMapiFolder* pFolder, long* pSzContents) {
957 HRESULT hr;
958 LPMDB lpMdb;
959
960 if (pSzContents) *pSzContents = 0;
961
962 if (!OpenStore(pFolder->GetCBEntryID(), pFolder->GetEntryID(), &lpMdb))
963 return;
964
965 LPSPropValue pVal;
966 /*
967 pVal = GetMapiProperty(lpMdb, PR_DISPLAY_NAME);
968 ReportStringProp(" Message store name:", pVal);
969 pVal = GetMapiProperty(lpMdb, PR_MDB_PROVIDER);
970 ReportUIDProp(" Message store provider:", pVal);
971 pVal = GetMapiProperty(lpMdb, PR_COMMENT);
972 ReportStringProp(" Message comment:", pVal);
973 pVal = GetMapiProperty(lpMdb, PR_ACCESS_LEVEL);
974 ReportLongProp(" Message store Access Level:", pVal);
975 pVal = GetMapiProperty(lpMdb, PR_STORE_SUPPORT_MASK);
976 ReportLongProp(" Message store support mask:", pVal);
977 pVal = GetMapiProperty(lpMdb, PR_STORE_STATE);
978 ReportLongProp(" Message store state:", pVal);
979 pVal = GetMapiProperty(lpMdb, PR_OBJECT_TYPE);
980 ReportLongProp(" Message store object type:", pVal);
981 pVal = GetMapiProperty(lpMdb, PR_VALID_FOLDER_MASK);
982 ReportLongProp(" Message store valid folder mask:", pVal);
983
984 pVal = GetMapiProperty(lpMdb, 0x8001001e);
985 ReportStringProp(" Message prop 0x8001001e:", pVal);
986
987 // This key appears to be the OMI Account Manager account that corresponds
988 // to this message store. This is important for IMAP accounts
989 // since we may not want to import messages from an IMAP store!
990 // Seems silly if you ask me!
991 // In order to test this, we'll need the registry key to look under to
992 determine
993 // if it contains the "IMAP Server" value, if it does then we are an
994 // IMAP store, if not, then we are a non-IMAP store - which may always mean
995 // a regular store that should be imported.
996
997 pVal = GetMapiProperty(lpMdb, 0x80000003);
998 ReportLongProp(" Message prop 0x80000003:", pVal);
999
1000 // ListProperties(lpMdb);
1001 */
1002
1003 pVal = GetMapiProperty(lpMdb, PR_IPM_SUBTREE_ENTRYID);
1004 if (pVal) {
1005 ULONG cbEntry;
1006 LPENTRYID pEntry;
1007 LPMAPIFOLDER lpSubTree = NULL;
1008
1009 if (GetEntryIdFromProp(pVal, cbEntry, pEntry)) {
1010 // Open up the folder!
1011 ULONG ulObjType;
1012 hr = lpMdb->OpenEntry(cbEntry, pEntry, NULL, 0, &ulObjType,
1013 (LPUNKNOWN*)&lpSubTree);
1014 MAPIFreeBuffer(pEntry);
1015 if (SUCCEEDED(hr) && lpSubTree) {
1016 // Find out if there are any contents in the
1017 // tree.
1018 LPMAPITABLE lpTable;
1019 hr = lpSubTree->GetHierarchyTable(0, &lpTable);
1020 if (HR_FAILED(hr)) {
1021 MAPI_TRACE2("GetStoreInfo: GetHierarchyTable failed: 0x%lx, %d\n",
1022 (long)hr, (int)hr);
1023 } else {
1024 ULONG rowCount;
1025 hr = lpTable->GetRowCount(0, &rowCount);
1026 lpTable->Release();
1027 if (SUCCEEDED(hr) && pSzContents) *pSzContents = (long)rowCount;
1028 }
1029
1030 lpSubTree->Release();
1031 }
1032 }
1033 }
1034 }
1035
ClearMessageStores(void)1036 void CMapiApi::ClearMessageStores(void) {
1037 if (m_pStores) {
1038 CMsgStore* pStore;
1039 for (size_t i = 0; i < m_pStores->Length(); i++) {
1040 pStore = m_pStores->ElementAt(i);
1041 delete pStore;
1042 }
1043 m_pStores->Clear();
1044 }
1045 }
1046
AddMessageStore(CMsgStore * pStore)1047 void CMapiApi::AddMessageStore(CMsgStore* pStore) {
1048 if (m_pStores) m_pStores->AppendElement(pStore);
1049 }
1050
FindMessageStore(ULONG cbEid,LPENTRYID lpEid)1051 CMsgStore* CMapiApi::FindMessageStore(ULONG cbEid, LPENTRYID lpEid) {
1052 if (!m_lpSession) {
1053 MAPI_TRACE0("FindMessageStore called before session is open\n");
1054 m_lastError = E_UNEXPECTED;
1055 return NULL;
1056 }
1057
1058 ULONG result;
1059 HRESULT hr;
1060 CMsgStore* pStore;
1061 for (size_t i = 0; i < m_pStores->Length(); i++) {
1062 pStore = m_pStores->ElementAt(i);
1063 hr = m_lpSession->CompareEntryIDs(cbEid, lpEid, pStore->GetCBEntryID(),
1064 pStore->GetLPEntryID(), 0, &result);
1065 if (HR_FAILED(hr)) {
1066 MAPI_TRACE2("CompareEntryIDs failed: 0x%lx, %d\n", (long)hr, (int)hr);
1067 m_lastError = hr;
1068 return NULL;
1069 }
1070 if (result) {
1071 return pStore;
1072 }
1073 }
1074
1075 pStore = new CMsgStore(cbEid, lpEid);
1076 AddMessageStore(pStore);
1077 return pStore;
1078 }
1079
1080 // --------------------------------------------------------------------
1081 // Utility stuff
1082 // --------------------------------------------------------------------
1083
GetMapiProperty(LPMAPIPROP pProp,ULONG tag)1084 LPSPropValue CMapiApi::GetMapiProperty(LPMAPIPROP pProp, ULONG tag) {
1085 if (!pProp) return NULL;
1086
1087 int sz = CbNewSPropTagArray(1);
1088 SPropTagArray* pTag = (SPropTagArray*)new char[sz];
1089 pTag->cValues = 1;
1090 pTag->aulPropTag[0] = tag;
1091 LPSPropValue lpProp = NULL;
1092 ULONG cValues = 0;
1093 HRESULT hr = pProp->GetProps(pTag, 0, &cValues, &lpProp);
1094 delete[] pTag;
1095 if (HR_FAILED(hr) || (cValues != 1)) {
1096 if (lpProp) MAPIFreeBuffer(lpProp);
1097 return NULL;
1098 } else {
1099 if (PROP_TYPE(lpProp->ulPropTag) == PT_ERROR) {
1100 if (lpProp->Value.l == MAPI_E_NOT_FOUND) {
1101 MAPIFreeBuffer(lpProp);
1102 lpProp = NULL;
1103 }
1104 }
1105 }
1106
1107 return lpProp;
1108 }
1109
IsLargeProperty(LPSPropValue pVal)1110 BOOL CMapiApi::IsLargeProperty(LPSPropValue pVal) {
1111 return ((PROP_TYPE(pVal->ulPropTag) == PT_ERROR) &&
1112 (pVal->Value.l == E_OUTOFMEMORY));
1113 }
1114
1115 // The output buffer (result) must be freed with operator delete[]
GetLargeProperty(LPMAPIPROP pProp,ULONG tag,void ** result)1116 BOOL CMapiApi::GetLargeProperty(LPMAPIPROP pProp, ULONG tag, void** result) {
1117 LPSTREAM lpStream;
1118 HRESULT hr =
1119 pProp->OpenProperty(tag, &IID_IStream, 0, 0, (LPUNKNOWN*)&lpStream);
1120 if (HR_FAILED(hr)) return FALSE;
1121 STATSTG st;
1122 BOOL bResult = TRUE;
1123 hr = lpStream->Stat(&st, STATFLAG_NONAME);
1124 if (HR_FAILED(hr))
1125 bResult = FALSE;
1126 else {
1127 if (!st.cbSize.QuadPart) st.cbSize.QuadPart = 1;
1128 char* pVal = new char[(int)st.cbSize.QuadPart + 2];
1129 if (pVal) {
1130 ULONG sz;
1131 hr = lpStream->Read(pVal, (ULONG)st.cbSize.QuadPart, &sz);
1132 if (HR_FAILED(hr)) {
1133 bResult = FALSE;
1134 delete[] pVal;
1135 } else {
1136 // Just in case it's a UTF16 string
1137 pVal[(int)st.cbSize.QuadPart] = pVal[(int)st.cbSize.QuadPart + 1] = 0;
1138 *result = pVal;
1139 }
1140 } else
1141 bResult = FALSE;
1142 }
1143
1144 lpStream->Release();
1145
1146 return bResult;
1147 }
1148
GetLargeStringProperty(LPMAPIPROP pProp,ULONG tag,nsCString & val)1149 BOOL CMapiApi::GetLargeStringProperty(LPMAPIPROP pProp, ULONG tag,
1150 nsCString& val) {
1151 void* result;
1152 if (!GetLargeProperty(pProp, tag, &result)) return FALSE;
1153 if (PROP_TYPE(tag) == PT_UNICODE) // unicode string
1154 LossyCopyUTF16toASCII(nsDependentString(static_cast<wchar_t*>(result)),
1155 val);
1156 else // either PT_STRING8 or some other binary - use as is
1157 val.Assign(static_cast<char*>(result));
1158 // Despite being used as wchar_t*, result it allocated as "new char[]" in
1159 // GetLargeProperty().
1160 delete[] static_cast<char*>(result);
1161 return TRUE;
1162 }
1163
GetLargeStringProperty(LPMAPIPROP pProp,ULONG tag,nsString & val)1164 BOOL CMapiApi::GetLargeStringProperty(LPMAPIPROP pProp, ULONG tag,
1165 nsString& val) {
1166 void* result;
1167 if (!GetLargeProperty(pProp, tag, &result)) return FALSE;
1168 if (PROP_TYPE(tag) == PT_UNICODE) // We already get the unicode string
1169 val.Assign(static_cast<wchar_t*>(result));
1170 else // either PT_STRING8 or some other binary
1171 CStrToUnicode(static_cast<char*>(result), val);
1172 // Despite being used as wchar_t*, result it allocated as "new char[]" in
1173 // GetLargeProperty().
1174 delete[] static_cast<char*>(result);
1175 return TRUE;
1176 }
1177 // If the value is a string, get it...
GetEntryIdFromProp(LPSPropValue pVal,ULONG & cbEntryId,LPENTRYID & lpEntryId,BOOL delVal)1178 BOOL CMapiApi::GetEntryIdFromProp(LPSPropValue pVal, ULONG& cbEntryId,
1179 LPENTRYID& lpEntryId, BOOL delVal) {
1180 if (!pVal) return FALSE;
1181
1182 BOOL bResult = TRUE;
1183 switch (PROP_TYPE(pVal->ulPropTag)) {
1184 case PT_BINARY:
1185 cbEntryId = pVal->Value.bin.cb;
1186 MAPIAllocateBuffer(cbEntryId, (LPVOID*)&lpEntryId);
1187 memcpy(lpEntryId, pVal->Value.bin.lpb, cbEntryId);
1188 break;
1189
1190 default:
1191 MAPI_TRACE0("EntryId not in BINARY prop value\n");
1192 bResult = FALSE;
1193 break;
1194 }
1195
1196 if (pVal && delVal) MAPIFreeBuffer(pVal);
1197
1198 return bResult;
1199 }
1200
GetStringFromProp(LPSPropValue pVal,nsCString & val,BOOL delVal)1201 BOOL CMapiApi::GetStringFromProp(LPSPropValue pVal, nsCString& val,
1202 BOOL delVal) {
1203 BOOL bResult = TRUE;
1204 if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_STRING8))
1205 val = pVal->Value.lpszA;
1206 else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_UNICODE))
1207 LossyCopyUTF16toASCII(nsDependentString(pVal->Value.lpszW), val);
1208 else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_NULL))
1209 val.Truncate();
1210 else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_ERROR)) {
1211 val.Truncate();
1212 bResult = FALSE;
1213 } else {
1214 if (pVal) {
1215 MAPI_TRACE1("GetStringFromProp: invalid value, expecting string - %d\n",
1216 (int)PROP_TYPE(pVal->ulPropTag));
1217 } else {
1218 MAPI_TRACE0(
1219 "GetStringFromProp: invalid value, expecting string, got null "
1220 "pointer\n");
1221 }
1222 val.Truncate();
1223 bResult = FALSE;
1224 }
1225 if (pVal && delVal) MAPIFreeBuffer(pVal);
1226
1227 return bResult;
1228 }
1229
GetStringFromProp(LPSPropValue pVal,nsString & val,BOOL delVal)1230 BOOL CMapiApi::GetStringFromProp(LPSPropValue pVal, nsString& val,
1231 BOOL delVal) {
1232 BOOL bResult = TRUE;
1233 if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_STRING8)) {
1234 CStrToUnicode((const char*)pVal->Value.lpszA, val);
1235 } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_UNICODE)) {
1236 val = (char16_t*)pVal->Value.lpszW;
1237 } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_NULL)) {
1238 val.Truncate();
1239 } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_ERROR)) {
1240 val.Truncate();
1241 bResult = FALSE;
1242 } else {
1243 if (pVal) {
1244 MAPI_TRACE1("GetStringFromProp: invalid value, expecting string - %d\n",
1245 (int)PROP_TYPE(pVal->ulPropTag));
1246 } else {
1247 MAPI_TRACE0(
1248 "GetStringFromProp: invalid value, expecting string, got null "
1249 "pointer\n");
1250 }
1251 val.Truncate();
1252 bResult = FALSE;
1253 }
1254 if (pVal && delVal) MAPIFreeBuffer(pVal);
1255
1256 return bResult;
1257 }
1258
GetLongFromProp(LPSPropValue pVal,BOOL delVal)1259 LONG CMapiApi::GetLongFromProp(LPSPropValue pVal, BOOL delVal) {
1260 LONG val = 0;
1261 if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_LONG)) {
1262 val = pVal->Value.l;
1263 } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_NULL)) {
1264 val = 0;
1265 } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_ERROR)) {
1266 val = 0;
1267 MAPI_TRACE0("GetLongFromProp: Error retrieving property\n");
1268 } else {
1269 MAPI_TRACE0("GetLongFromProp: invalid value, expecting long\n");
1270 }
1271 if (pVal && delVal) MAPIFreeBuffer(pVal);
1272
1273 return val;
1274 }
1275
ReportUIDProp(const char * pTag,LPSPropValue pVal)1276 void CMapiApi::ReportUIDProp(const char* pTag, LPSPropValue pVal) {
1277 if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_BINARY)) {
1278 if (pVal->Value.bin.cb != 16) {
1279 MAPI_TRACE1("%s - INVALID, expecting 16 bytes of binary data for UID\n",
1280 pTag);
1281 } else {
1282 nsIID uid;
1283 memcpy(&uid, pVal->Value.bin.lpb, 16);
1284 char* pStr = uid.ToString();
1285 if (pStr) {
1286 MAPI_TRACE2("%s %s\n", pTag, (const char*)pStr);
1287 free(pStr);
1288 }
1289 }
1290 } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_NULL)) {
1291 MAPI_TRACE1("%s {NULL}\n", pTag);
1292 } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_ERROR)) {
1293 MAPI_TRACE1("%s {Error retrieving property}\n", pTag);
1294 } else {
1295 MAPI_TRACE1("%s invalid value, expecting binary\n", pTag);
1296 }
1297 if (pVal) MAPIFreeBuffer(pVal);
1298 }
1299
ReportLongProp(const char * pTag,LPSPropValue pVal)1300 void CMapiApi::ReportLongProp(const char* pTag, LPSPropValue pVal) {
1301 if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_LONG)) {
1302 nsCString num;
1303 nsCString num2;
1304
1305 num.AppendInt((int32_t)pVal->Value.l);
1306 num2.AppendInt((int32_t)pVal->Value.l, 16);
1307 MAPI_TRACE3("%s %s, 0x%s\n", pTag, num, num2);
1308 } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_NULL)) {
1309 MAPI_TRACE1("%s {NULL}\n", pTag);
1310 } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_ERROR)) {
1311 MAPI_TRACE1("%s {Error retrieving property}\n", pTag);
1312 } else {
1313 MAPI_TRACE1("%s invalid value, expecting long\n", pTag);
1314 }
1315 if (pVal) MAPIFreeBuffer(pVal);
1316 }
1317
ReportStringProp(const char * pTag,LPSPropValue pVal)1318 void CMapiApi::ReportStringProp(const char* pTag, LPSPropValue pVal) {
1319 if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_TSTRING)) {
1320 nsCString val((LPCTSTR)(pVal->Value.LPSZ));
1321 MAPI_TRACE2("%s %s\n", pTag, val.get());
1322 } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_NULL)) {
1323 MAPI_TRACE1("%s {NULL}\n", pTag);
1324 } else if (pVal && (PROP_TYPE(pVal->ulPropTag) == PT_ERROR)) {
1325 MAPI_TRACE1("%s {Error retrieving property}\n", pTag);
1326 } else {
1327 MAPI_TRACE1("%s invalid value, expecting string\n", pTag);
1328 }
1329 if (pVal) MAPIFreeBuffer(pVal);
1330 }
1331
GetPropTagName(ULONG tag,nsCString & s)1332 void CMapiApi::GetPropTagName(ULONG tag, nsCString& s) {
1333 char numStr[256];
1334 PR_snprintf(numStr, 256, "0x%lx, %ld", tag, tag);
1335 s = numStr;
1336 switch (tag) {
1337 #include "MapiTagStrs.cpp"
1338 }
1339 s += ", data: ";
1340 switch (PROP_TYPE(tag)) {
1341 case PT_UNSPECIFIED:
1342 s += "PT_UNSPECIFIED";
1343 break;
1344 case PT_NULL:
1345 s += "PT_NULL";
1346 break;
1347 case PT_I2:
1348 s += "PT_I2";
1349 break;
1350 case PT_LONG:
1351 s += "PT_LONG";
1352 break;
1353 case PT_R4:
1354 s += "PT_R4";
1355 break;
1356 case PT_DOUBLE:
1357 s += "PT_DOUBLE";
1358 break;
1359 case PT_CURRENCY:
1360 s += "PT_CURRENCY";
1361 break;
1362 case PT_APPTIME:
1363 s += "PT_APPTIME";
1364 break;
1365 case PT_ERROR:
1366 s += "PT_ERROR";
1367 break;
1368 case PT_BOOLEAN:
1369 s += "PT_BOOLEAN";
1370 break;
1371 case PT_OBJECT:
1372 s += "PT_OBJECT";
1373 break;
1374 case PT_I8:
1375 s += "PT_I8";
1376 break;
1377 case PT_STRING8:
1378 s += "PT_STRING8";
1379 break;
1380 case PT_UNICODE:
1381 s += "PT_UNICODE";
1382 break;
1383 case PT_SYSTIME:
1384 s += "PT_SYSTIME";
1385 break;
1386 case PT_CLSID:
1387 s += "PT_CLSID";
1388 break;
1389 case PT_BINARY:
1390 s += "PT_BINARY";
1391 break;
1392 case PT_MV_I2:
1393 s += "PT_MV_I2";
1394 break;
1395 case PT_MV_LONG:
1396 s += "PT_MV_LONG";
1397 break;
1398 case PT_MV_R4:
1399 s += "PT_MV_R4";
1400 break;
1401 case PT_MV_DOUBLE:
1402 s += "PT_MV_DOUBLE";
1403 break;
1404 case PT_MV_CURRENCY:
1405 s += "PT_MV_CURRENCY";
1406 break;
1407 case PT_MV_APPTIME:
1408 s += "PT_MV_APPTIME";
1409 break;
1410 case PT_MV_SYSTIME:
1411 s += "PT_MV_SYSTIME";
1412 break;
1413 case PT_MV_STRING8:
1414 s += "PT_MV_STRING8";
1415 break;
1416 case PT_MV_BINARY:
1417 s += "PT_MV_BINARY";
1418 break;
1419 case PT_MV_UNICODE:
1420 s += "PT_MV_UNICODE";
1421 break;
1422 case PT_MV_CLSID:
1423 s += "PT_MV_CLSID";
1424 break;
1425 case PT_MV_I8:
1426 s += "PT_MV_I8";
1427 break;
1428 default:
1429 s += "Unknown";
1430 }
1431 }
1432
ListPropertyValue(LPSPropValue pVal,nsCString & s)1433 void CMapiApi::ListPropertyValue(LPSPropValue pVal, nsCString& s) {
1434 nsCString strVal;
1435 char nBuff[64];
1436
1437 s += "value: ";
1438 switch (PROP_TYPE(pVal->ulPropTag)) {
1439 case PT_STRING8:
1440 GetStringFromProp(pVal, strVal, FALSE);
1441 if (strVal.Length() > 60) {
1442 strVal.SetLength(60);
1443 strVal += "...";
1444 }
1445 strVal.ReplaceSubstring("\r", "\\r");
1446 strVal.ReplaceSubstring("\n", "\\n");
1447 s += strVal;
1448 break;
1449 case PT_LONG:
1450 s.AppendInt((int32_t)pVal->Value.l);
1451 s += ", 0x";
1452 s.AppendInt((int32_t)pVal->Value.l, 16);
1453 s += nBuff;
1454 break;
1455 case PT_BOOLEAN:
1456 if (pVal->Value.b)
1457 s += "True";
1458 else
1459 s += "False";
1460 break;
1461 case PT_NULL:
1462 s += "--NULL--";
1463 break;
1464 case PT_SYSTIME: {
1465 /*
1466 COleDateTime tm(pVal->Value.ft);
1467 s += tm.Format();
1468 */
1469 s += "-- Figure out how to format time in mozilla, PT_SYSTIME --";
1470 } break;
1471 default:
1472 s += "?";
1473 }
1474 }
1475
1476 // -------------------------------------------------------------------
1477 // Folder list stuff
1478 // -------------------------------------------------------------------
CMapiFolderList()1479 CMapiFolderList::CMapiFolderList() {}
1480
~CMapiFolderList()1481 CMapiFolderList::~CMapiFolderList() { ClearAll(); }
1482
AddItem(CMapiFolder * pFolder)1483 void CMapiFolderList::AddItem(CMapiFolder* pFolder) {
1484 EnsureUniqueName(pFolder);
1485 GenerateFilePath(pFolder);
1486 m_array.AppendElement(pFolder);
1487 }
1488
ChangeName(nsString & name)1489 void CMapiFolderList::ChangeName(nsString& name) {
1490 if (name.IsEmpty()) {
1491 name.Assign('1');
1492 return;
1493 }
1494 char16_t lastC = name.Last();
1495 if ((lastC >= '0') && (lastC <= '9')) {
1496 lastC++;
1497 if (lastC > '9') {
1498 lastC = '1';
1499 name.SetCharAt(lastC, name.Length() - 1);
1500 name.Append('0');
1501 } else {
1502 name.SetCharAt(lastC, name.Length() - 1);
1503 }
1504 } else {
1505 name.AppendLiteral(" 2");
1506 }
1507 }
1508
EnsureUniqueName(CMapiFolder * pFolder)1509 void CMapiFolderList::EnsureUniqueName(CMapiFolder* pFolder) {
1510 // For everybody in the array before me with the SAME
1511 // depth, my name must be unique
1512 CMapiFolder* pCurrent;
1513 int i;
1514 BOOL done;
1515 nsString name;
1516 nsString cName;
1517
1518 pFolder->GetDisplayName(name);
1519 do {
1520 done = TRUE;
1521 i = m_array.Length() - 1;
1522 while (i >= 0) {
1523 pCurrent = GetAt(i);
1524 if (pCurrent->GetDepth() == pFolder->GetDepth()) {
1525 pCurrent->GetDisplayName(cName);
1526 if (cName.Equals(name, nsCaseInsensitiveStringComparator)) {
1527 ChangeName(name);
1528 pFolder->SetDisplayName(name.get());
1529 done = FALSE;
1530 break;
1531 }
1532 } else if (pCurrent->GetDepth() < pFolder->GetDepth())
1533 break;
1534 i--;
1535 }
1536 } while (!done);
1537 }
1538
GenerateFilePath(CMapiFolder * pFolder)1539 void CMapiFolderList::GenerateFilePath(CMapiFolder* pFolder) {
1540 // A file path, includes all of my parent's path, plus mine
1541 nsString name;
1542 nsString path;
1543 if (!pFolder->GetDepth()) {
1544 pFolder->GetDisplayName(name);
1545 pFolder->SetFilePath(name.get());
1546 return;
1547 }
1548
1549 CMapiFolder* pCurrent;
1550 int i = m_array.Length() - 1;
1551 while (i >= 0) {
1552 pCurrent = GetAt(i);
1553 if (pCurrent->GetDepth() == (pFolder->GetDepth() - 1)) {
1554 pCurrent->GetFilePath(path);
1555 path.AppendLiteral(".sbd\\");
1556 pFolder->GetDisplayName(name);
1557 path += name;
1558 pFolder->SetFilePath(path.get());
1559 return;
1560 }
1561 i--;
1562 }
1563 pFolder->GetDisplayName(name);
1564 pFolder->SetFilePath(name.get());
1565 }
1566
ClearAll(void)1567 void CMapiFolderList::ClearAll(void) {
1568 CMapiFolder* pFolder;
1569 for (size_t i = 0; i < m_array.Length(); i++) {
1570 pFolder = GetAt(i);
1571 delete pFolder;
1572 }
1573 m_array.Clear();
1574 }
1575
DumpList(void)1576 void CMapiFolderList::DumpList(void) {
1577 CMapiFolder* pFolder;
1578 nsString str;
1579 int depth;
1580 char prefix[256];
1581
1582 MAPI_TRACE0("Folder List ---------------------------------\n");
1583 for (size_t i = 0; i < m_array.Length(); i++) {
1584 pFolder = GetAt(i);
1585 depth = pFolder->GetDepth();
1586 pFolder->GetDisplayName(str);
1587 depth *= 2;
1588 if (depth > 255) depth = 255;
1589 memset(prefix, ' ', depth);
1590 prefix[depth] = 0;
1591 #ifdef MAPI_DEBUG
1592 char* ansiStr = ToNewCString(str);
1593 MAPI_TRACE2("%s%s: ", prefix, ansiStr);
1594 free(ansiStr);
1595 #endif
1596 pFolder->GetFilePath(str);
1597 #ifdef MAPI_DEBUG
1598 ansiStr = ToNewCString(str);
1599 MAPI_TRACE2("depth=%d, filePath=%s\n", pFolder->GetDepth(), ansiStr);
1600 free(ansiStr);
1601 #endif
1602 }
1603 MAPI_TRACE0("---------------------------------------------\n");
1604 }
1605
CMapiFolder()1606 CMapiFolder::CMapiFolder() {
1607 m_objectType = MAPI_FOLDER;
1608 m_cbEid = 0;
1609 m_lpEid = NULL;
1610 m_depth = 0;
1611 m_doImport = TRUE;
1612 }
1613
CMapiFolder(const char16_t * pDisplayName,ULONG cbEid,LPENTRYID lpEid,int depth,LONG oType)1614 CMapiFolder::CMapiFolder(const char16_t* pDisplayName, ULONG cbEid,
1615 LPENTRYID lpEid, int depth, LONG oType) {
1616 m_cbEid = 0;
1617 m_lpEid = NULL;
1618 SetDisplayName(pDisplayName);
1619 SetEntryID(cbEid, lpEid);
1620 SetDepth(depth);
1621 SetObjectType(oType);
1622 SetDoImport(TRUE);
1623 }
1624
CMapiFolder(const CMapiFolder * pCopyFrom)1625 CMapiFolder::CMapiFolder(const CMapiFolder* pCopyFrom) {
1626 m_lpEid = NULL;
1627 m_cbEid = 0;
1628 SetDoImport(pCopyFrom->GetDoImport());
1629 SetDisplayName(pCopyFrom->m_displayName.get());
1630 SetObjectType(pCopyFrom->GetObjectType());
1631 SetEntryID(pCopyFrom->GetCBEntryID(), pCopyFrom->GetEntryID());
1632 SetDepth(pCopyFrom->GetDepth());
1633 SetFilePath(pCopyFrom->m_mailFilePath.get());
1634 }
1635
~CMapiFolder()1636 CMapiFolder::~CMapiFolder() {
1637 if (m_lpEid) delete m_lpEid;
1638 }
1639
SetEntryID(ULONG cbEid,LPENTRYID lpEid)1640 void CMapiFolder::SetEntryID(ULONG cbEid, LPENTRYID lpEid) {
1641 if (m_lpEid) delete m_lpEid;
1642 m_lpEid = NULL;
1643 m_cbEid = cbEid;
1644 if (cbEid) {
1645 m_lpEid = new BYTE[cbEid];
1646 memcpy(m_lpEid, lpEid, cbEid);
1647 }
1648 }
1649
1650 // ---------------------------------------------------------------------
1651 // Message store stuff
1652 // ---------------------------------------------------------------------
1653
CMsgStore(ULONG cbEid,LPENTRYID lpEid)1654 CMsgStore::CMsgStore(ULONG cbEid, LPENTRYID lpEid) {
1655 m_lpEid = NULL;
1656 m_lpMdb = NULL;
1657 SetEntryID(cbEid, lpEid);
1658 }
1659
~CMsgStore()1660 CMsgStore::~CMsgStore() {
1661 if (m_lpEid) delete m_lpEid;
1662
1663 if (m_lpMdb) {
1664 ULONG flags = LOGOFF_NO_WAIT;
1665 m_lpMdb->StoreLogoff(&flags);
1666 m_lpMdb->Release();
1667 m_lpMdb = NULL;
1668 }
1669 }
1670
SetEntryID(ULONG cbEid,LPENTRYID lpEid)1671 void CMsgStore::SetEntryID(ULONG cbEid, LPENTRYID lpEid) {
1672 if (m_lpEid) delete m_lpEid;
1673
1674 m_lpEid = NULL;
1675 if (cbEid) {
1676 m_lpEid = new BYTE[cbEid];
1677 memcpy(m_lpEid, lpEid, cbEid);
1678 }
1679 m_cbEid = cbEid;
1680
1681 if (m_lpMdb) {
1682 ULONG flags = LOGOFF_NO_WAIT;
1683 m_lpMdb->StoreLogoff(&flags);
1684 m_lpMdb->Release();
1685 m_lpMdb = NULL;
1686 }
1687 }
1688
Open(LPMAPISESSION pSession,LPMDB * ppMdb)1689 BOOL CMsgStore::Open(LPMAPISESSION pSession, LPMDB* ppMdb) {
1690 if (m_lpMdb) {
1691 if (ppMdb) *ppMdb = m_lpMdb;
1692 return TRUE;
1693 }
1694
1695 BOOL bResult = TRUE;
1696 HRESULT hr = pSession->OpenMsgStore(NULL, m_cbEid, (LPENTRYID)m_lpEid, NULL,
1697 MDB_NO_MAIL, &m_lpMdb); // MDB pointer
1698 if (HR_FAILED(hr)) {
1699 m_lpMdb = NULL;
1700 MAPI_TRACE2("OpenMsgStore failed: 0x%lx, %d\n", (long)hr, (int)hr);
1701 bResult = FALSE;
1702 }
1703
1704 if (ppMdb) *ppMdb = m_lpMdb;
1705 return bResult;
1706 }
1707
1708 // ------------------------------------------------------------
1709 // Contents Iterator
1710 // -----------------------------------------------------------
1711
CMapiFolderContents(LPMDB lpMdb,ULONG cbEid,LPENTRYID lpEid)1712 CMapiFolderContents::CMapiFolderContents(LPMDB lpMdb, ULONG cbEid,
1713 LPENTRYID lpEid) {
1714 m_lpMdb = lpMdb;
1715 m_fCbEid = cbEid;
1716 m_fLpEid = new BYTE[cbEid];
1717 memcpy(m_fLpEid, lpEid, cbEid);
1718 m_count = 0;
1719 m_iterCount = 0;
1720 m_failure = FALSE;
1721 m_lastError = 0;
1722 m_lpFolder = NULL;
1723 m_lpTable = NULL;
1724 m_lastLpEid = NULL;
1725 m_lastCbEid = 0;
1726 }
1727
~CMapiFolderContents()1728 CMapiFolderContents::~CMapiFolderContents() {
1729 if (m_lastLpEid) delete m_lastLpEid;
1730 delete m_fLpEid;
1731 if (m_lpTable) m_lpTable->Release();
1732 if (m_lpFolder) m_lpFolder->Release();
1733 }
1734
SetUpIter(void)1735 BOOL CMapiFolderContents::SetUpIter(void) {
1736 // First, open up the MAPIFOLDER object
1737 ULONG ulObjType;
1738 HRESULT hr;
1739 hr = m_lpMdb->OpenEntry(m_fCbEid, (LPENTRYID)m_fLpEid, NULL, 0, &ulObjType,
1740 (LPUNKNOWN*)&m_lpFolder);
1741
1742 if (FAILED(hr) || !m_lpFolder) {
1743 m_lpFolder = NULL;
1744 m_lastError = hr;
1745 MAPI_TRACE2("CMapiFolderContents OpenEntry failed: 0x%lx, %d\n", (long)hr,
1746 (int)hr);
1747 return FALSE;
1748 }
1749
1750 if (ulObjType != MAPI_FOLDER) {
1751 m_lastError = E_UNEXPECTED;
1752 MAPI_TRACE0("CMapiFolderContents - bad object type, not a folder.\n");
1753 return FALSE;
1754 }
1755
1756 hr = m_lpFolder->GetContentsTable(0, &m_lpTable);
1757 if (FAILED(hr) || !m_lpTable) {
1758 m_lastError = hr;
1759 m_lpTable = NULL;
1760 MAPI_TRACE2("CMapiFolderContents - GetContentsTable failed: 0x%lx, %d\n",
1761 (long)hr, (int)hr);
1762 return FALSE;
1763 }
1764
1765 hr = m_lpTable->GetRowCount(0, &m_count);
1766 if (FAILED(hr)) {
1767 m_lastError = hr;
1768 MAPI_TRACE0("CMapiFolderContents - GetRowCount failed\n");
1769 return FALSE;
1770 }
1771
1772 hr = m_lpTable->SetColumns((LPSPropTagArray)&ptaEid, 0);
1773 if (FAILED(hr)) {
1774 m_lastError = hr;
1775 MAPI_TRACE2("CMapiFolderContents - SetColumns failed: 0x%lx, %d\n",
1776 (long)hr, (int)hr);
1777 return FALSE;
1778 }
1779
1780 hr = m_lpTable->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
1781 if (FAILED(hr)) {
1782 m_lastError = hr;
1783 MAPI_TRACE2("CMapiFolderContents - SeekRow failed: 0x%lx, %d\n", (long)hr,
1784 (int)hr);
1785 return FALSE;
1786 }
1787
1788 return TRUE;
1789 }
1790
GetNext(ULONG * pcbEid,LPENTRYID * ppEid,ULONG * poType,BOOL * pDone)1791 BOOL CMapiFolderContents::GetNext(ULONG* pcbEid, LPENTRYID* ppEid,
1792 ULONG* poType, BOOL* pDone) {
1793 *pDone = FALSE;
1794 if (m_failure) return FALSE;
1795 if (!m_lpFolder) {
1796 if (!SetUpIter()) {
1797 m_failure = TRUE;
1798 return FALSE;
1799 }
1800 if (!m_count) {
1801 *pDone = TRUE;
1802 return TRUE;
1803 }
1804 }
1805
1806 int cNumRows = 0;
1807 LPSRowSet lpRow = NULL;
1808 HRESULT hr = m_lpTable->QueryRows(1, 0, &lpRow);
1809
1810 if (HR_FAILED(hr)) {
1811 m_lastError = hr;
1812 m_failure = TRUE;
1813 MAPI_TRACE2("CMapiFolderContents - QueryRows failed: 0x%lx, %d\n", (long)hr,
1814 (int)hr);
1815 return FALSE;
1816 }
1817
1818 if (lpRow) {
1819 cNumRows = lpRow->cRows;
1820 if (cNumRows) {
1821 LPENTRYID lpEID =
1822 (LPENTRYID)lpRow->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
1823 ULONG cbEID = lpRow->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb;
1824 ULONG oType = lpRow->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.ul;
1825
1826 if (m_lastCbEid != cbEID) {
1827 if (m_lastLpEid) delete m_lastLpEid;
1828 m_lastLpEid = new BYTE[cbEID];
1829 m_lastCbEid = cbEID;
1830 }
1831 memcpy(m_lastLpEid, lpEID, cbEID);
1832
1833 *ppEid = (LPENTRYID)m_lastLpEid;
1834 *pcbEid = cbEID;
1835 *poType = oType;
1836 } else
1837 *pDone = TRUE;
1838 CMapiApi::FreeProws(lpRow);
1839 } else
1840 *pDone = TRUE;
1841
1842 return TRUE;
1843 }
1844