1 #ifdef _WIN32
2
3 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
4 //
5 // File: MAPIMessage.cpp
6 // Description: MAPI Message class wrapper
7 //
8 // Copyright (C) 2005-2011, Noel Dillabough
9 //
10 // This source code is free to use and modify provided this notice remains intact and that any enhancements
11 // or bug fixes are posted to the CodeProject page hosting this class for the community to benefit.
12 //
13 // Usage: see the CodeProject article at http://www.codeproject.com/internet/CMapiEx.asp
14 //
15 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
16
17 // Ported to U++ Framework by Koldo. See License.txt file
18
19 #include "MAPIEx.h"
20
21 const GUID CLSID_MailMessage = {0x00020D0B, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46};
22
23 #ifndef _WIN32_WCE
24 #define INITGUID
25 #define USES_IID_IMessage
26 #include <InitGuid.h>
27 #include <MAPIGuid.h>
28 #endif
29
30
31 /////////////////////////////////////////////////////////////
32 // MAPIMessage
33
MAPIMessage()34 MAPIMessage::MAPIMessage() {
35 m_pRecipients = NULL;
36 }
37
~MAPIMessage()38 MAPIMessage::~MAPIMessage() {
39 Close();
40 }
41
Open(MAPIEx * pMAPI,SBinary entryID)42 bool MAPIMessage::Open(MAPIEx* pMAPI, SBinary entryID) {
43 if(!MAPIObject::Open(pMAPI,entryID))
44 return false;
45
46 m_strSenderName = GetPropertyString(PR_SENDER_NAME);
47 FillSenderEmail();
48 m_strSubject = GetPropertyString(PR_SUBJECT);
49
50 return true;
51 }
52
Close()53 void MAPIMessage::Close() {
54 RELEASE(m_pRecipients);
55 MAPIObject::Close();
56 }
57
GetHeader()58 String MAPIMessage::GetHeader() {
59 return GetPropertyString(PR_TRANSPORT_MESSAGE_HEADERS);
60 }
61
FillSenderEmail()62 void MAPIMessage::FillSenderEmail() {
63 String strAddrType = GetPropertyString(PR_SENDER_ADDRTYPE);
64 m_strSenderEmail = GetPropertyString(PR_SENDER_EMAIL_ADDRESS);
65
66 // for Microsoft Exchange server internal mails we want to try to resolve the SMTP email address
67 if(strAddrType == "EX") {
68 LPSPropValue pProp;
69 if(GetProperty(PR_SENDER_ENTRYID, pProp)==S_OK) {
70 if(m_pMAPI)
71 m_pMAPI->GetExEmail(pProp->Value.bin, m_strSenderEmail);
72 MAPIFreeBuffer(pProp);
73 }
74 }
75 }
76
GetTime(ULONG property)77 Time MAPIMessage::GetTime(ULONG property) {
78 SYSTEMTIME st;
79 LPSPropValue pProp;
80 if(GetProperty(property, pProp) == S_OK) {
81 FILETIME tmLocal;
82 FileTimeToLocalFileTime(&pProp->Value.ft, &tmLocal);
83 FileTimeToSystemTime(&tmLocal, &st);
84 MAPIFreeBuffer(pProp);
85 return MAPIEx::GetSystemTime(st);
86 }
87 return Null;
88 }
89
GetTo()90 String MAPIMessage::GetTo() {
91 return GetPropertyString(PR_DISPLAY_TO);
92 }
93
GetCC()94 String MAPIMessage::GetCC() {
95 return GetPropertyString(PR_DISPLAY_CC);
96 }
97
GetBCC()98 String MAPIMessage::GetBCC() {
99 return GetPropertyString(PR_DISPLAY_BCC);
100 }
101
GetMessageStatus()102 int MAPIMessage::GetMessageStatus() {
103 return GetPropertyValue(PR_MSG_STATUS, 0);
104 }
105
GetPriority()106 int MAPIMessage::GetPriority() {
107 return GetPropertyValue(PR_PRIORITY, PRIO_NONURGENT);
108 }
109
GetSize()110 DWORD MAPIMessage::GetSize() {
111 return GetPropertyValue(PR_MESSAGE_SIZE, 0);
112 }
113
GetRecipients()114 bool MAPIMessage::GetRecipients() {
115 if(!Message())
116 return false;
117 RELEASE(m_pRecipients);
118
119 if(Message()->GetRecipientTable(MAPIEx::cm_nMAPICode, &m_pRecipients) != S_OK)
120 return false;
121
122 const int nProperties = RECIPIENT_COLS;
123 SizedSPropTagArray(nProperties, Columns)={nProperties,{PR_RECIPIENT_TYPE, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_ADDRTYPE, PR_ENTRYID }};
124 return (m_pRecipients->SetColumns((LPSPropTagArray)&Columns, 0) == S_OK);
125 }
126
GetNextRecipient(String & strName,String & strEmail,int & nType)127 bool MAPIMessage::GetNextRecipient(String& strName, String& strEmail, int &nType) {
128 if(!m_pRecipients)
129 return false;
130
131 LPSRowSet pRows = NULL;
132 bool bResult = false;
133 if(m_pRecipients->QueryRows(1, 0, &pRows) == S_OK) {
134 if(pRows->cRows) {
135 nType = pRows->aRow[0].lpProps[PROP_RECIPIENT_TYPE].Value.ul;
136 strName = MAPIEx::GetValidString(pRows->aRow[0].lpProps[PROP_RECIPIENT_NAME]);
137
138 // for Microsoft Exchange server internal mails we want to try to resolve the SMTP email address
139 String strAddrType = MAPIEx::GetValidString(pRows->aRow[0].lpProps[PROP_ADDR_TYPE]);
140 if(strAddrType == "EX") {
141 if(m_pMAPI)
142 m_pMAPI->GetExEmail(pRows->aRow[0].lpProps[PROP_ENTRYID].Value.bin, strEmail);
143 } else
144 strEmail = MAPIEx::GetValidString(pRows->aRow[0].lpProps[PROP_RECIPIENT_EMAIL]);
145 bResult = true;
146 }
147 MAPIEx::FreeProws(pRows);
148 }
149 return bResult;
150 }
151
GetReplyTo()152 String MAPIMessage::GetReplyTo() {
153 String strEmail;
154 bool bResult = false;
155 LPSPropValue prop;
156 if(GetProperty(PR_REPLY_RECIPIENT_ENTRIES, prop) == S_OK) {
157 LPFLATENTRYLIST pReplyEntryList = (LPFLATENTRYLIST)prop->Value.bin.lpb;
158 if(pReplyEntryList->cEntries > 0) {
159 LPFLATENTRY pReplyEntry = (LPFLATENTRY)pReplyEntryList->abEntries;
160
161 SBinary entryID;
162 entryID.cb = pReplyEntry->cb;
163 entryID.lpb = pReplyEntry->abEntry;
164 bResult = m_pMAPI->GetExEmail(entryID, strEmail);
165 }
166 MAPIFreeBuffer(prop);
167 }
168 if (bResult)
169 return strEmail;
170 else
171 return String();
172 }
173
174 // nPriority defaults to IMPORTANCE_NORMAL, IMPORTANCE_HIGH or IMPORTANCE_LOW also valid
Create(MAPIEx & mapi,MAPIFolder & folder,int nPriority,bool bSaveToSentFolder)175 bool MAPIMessage::Create(MAPIEx &mapi, MAPIFolder &folder, int nPriority, bool bSaveToSentFolder) {
176 if(!MAPIObject::Create(mapi, folder))
177 return false;
178
179 SPropValue prop;
180 SetMessageFlags(MSGFLAG_UNSENT | MSGFLAG_FROMME);
181
182 LPSPropValue pProp = NULL;
183 ULONG cValues = 0;
184 ULONG rgTags[] = { 1, PR_IPM_SENTMAIL_ENTRYID };
185
186 if(m_pMAPI->GetMessageStore()->GetProps((LPSPropTagArray) rgTags, MAPIEx::cm_nMAPICode, &cValues, &pProp)==S_OK) {
187 if(bSaveToSentFolder) {
188 prop.ulPropTag = PR_SENTMAIL_ENTRYID;
189 prop.Value.bin = pProp[0].Value.bin;
190 } else {
191 prop.ulPropTag = PR_DELETE_AFTER_SUBMIT;
192 prop.Value.b = true;
193 }
194 Message()->SetProps(1, &prop, NULL);
195 SetEntryID(&(pProp[0].Value.bin));
196 MAPIFreeBuffer(pProp);
197 }
198
199 if(nPriority != IMPORTANCE_NORMAL) {
200 prop.ulPropTag = PR_IMPORTANCE;
201 prop.Value.l = nPriority;
202 Message()->SetProps(1, &prop, NULL);
203 }
204 SetMessageClass("IPM.Note");
205
206 #ifdef _WIN32_WCE
207 prop.ulPropTag = PR_MSG_STATUS;
208 prop.Value.ul = MSGSTATUS_RECTYPE_SMTP;
209 Message()->SetProps(1, &prop, NULL);
210 #endif
211
212 return true;
213 }
214
IsUnread()215 bool MAPIMessage::IsUnread() {
216 return (!(GetMessageFlags()&MSGFLAG_READ));
217 }
218
MarkAsRead(bool bRead)219 bool MAPIMessage::MarkAsRead(bool bRead) {
220 #ifdef _WIN32_WCE
221 int ulMessageFlags = GetMessageFlags();
222 if(bRead) ulMessageFlags |= MSGFLAG_READ;
223 else ulMessageFlags &= ~MSGFLAG_READ;
224 return SetMessageFlags(ulMessageFlags);
225 #else
226 return (Message()->SetReadFlag(bRead ? MSGFLAG_READ : CLEAR_READ_FLAG)==S_OK);
227 #endif
228 }
229
AddRecipients(LPADRLIST pAddressList)230 bool MAPIMessage::AddRecipients(LPADRLIST pAddressList) {
231 HRESULT hr = E_INVALIDARG;
232 #ifdef _WIN32_WCE
233 hr = Message()->ModifyRecipients(MODRECIP_ADD, pAddressList);
234 #else
235 LPADRBOOK pAddressBook;
236 if(m_pMAPI->GetSession()->OpenAddressBook(0, NULL, AB_NO_DIALOG, &pAddressBook) != S_OK)
237 return false;
238
239 if(pAddressBook->ResolveName(0, MAPIEx::cm_nMAPICode, NULL, pAddressList) == S_OK)
240 hr = Message()->ModifyRecipients(MODRECIP_ADD, pAddressList);
241 RELEASE(pAddressBook);
242 #endif
243 return (hr == S_OK);
244 }
245
246 // AddrType only needed by Windows CE, use SMTP, or SMS etc, default NULL will not set PR_ADDRTYPE
AddRecipient(const String & email,int nType,const char * szAddrType)247 bool MAPIMessage::AddRecipient(const String &email, int nType, const char* szAddrType) {
248 if(!Message() || !m_pMAPI)
249 return false;
250
251 int nBufSize=CbNewADRLIST(1);
252 LPADRLIST pAddressList = NULL;
253 MAPIAllocateBuffer(nBufSize, (LPVOID FAR*)&pAddressList);
254 memset(pAddressList, 0, nBufSize);
255
256 int nProperties = 3;
257 if(szAddrType==NULL)
258 nProperties--;
259 pAddressList->cEntries=1;
260
261 pAddressList->aEntries[0].ulReserved1 = 0;
262 pAddressList->aEntries[0].cValues=nProperties;
263
264 MAPIAllocateBuffer(sizeof(SPropValue)*nProperties, (LPVOID FAR*)&pAddressList->aEntries[0].rgPropVals);
265 memset(pAddressList->aEntries[0].rgPropVals, 0, sizeof(SPropValue)*nProperties);
266
267 pAddressList->aEntries[0].rgPropVals[0].ulPropTag = PR_RECIPIENT_TYPE;
268 pAddressList->aEntries[0].rgPropVals[0].Value.ul = nType;
269
270 #ifdef _WIN32_WCE
271 pAddressList->aEntries[0].rgPropVals[1].ulPropTag = PR_EMAIL_ADDRESS;
272 pAddressList->aEntries[0].rgPropVals[1].Value.LPSZ = (TCHAR*)szEmail;
273 #else
274 pAddressList->aEntries[0].rgPropVals[1].ulPropTag = PR_DISPLAY_NAME;
275 pAddressList->aEntries[0].rgPropVals[1].Value.LPSZ = (TCHAR*)(email.Begin());
276 #endif
277
278 if(szAddrType != NULL) {
279 pAddressList->aEntries[0].rgPropVals[2].ulPropTag = PR_ADDRTYPE;
280 pAddressList->aEntries[0].rgPropVals[2].Value.LPSZ = (TCHAR*)szAddrType;
281 }
282
283 bool bResult = AddRecipients(pAddressList);
284 MAPIEx::ReleaseAddressList(pAddressList);
285 return bResult;
286 }
287
SetSubject(const String & subject)288 void MAPIMessage::SetSubject(const String &subject) {
289 m_strSubject = subject;
290 SetPropertyString(PR_SUBJECT, subject);
291 }
292
SetSender(const String & senderName,const String & senderEmail)293 void MAPIMessage::SetSender(const String &senderName, const String &senderEmail) {
294 m_strSenderName = senderName;
295 m_strSenderEmail = senderEmail;
296 LPTSTR szAddrType = (TCHAR*)"SMTP";
297 if(m_strSenderName.GetLength() && m_strSenderEmail.GetLength()) {
298 SetPropertyString(PR_SENDER_NAME, senderName);
299 SetPropertyString(PR_SENDER_EMAIL_ADDRESS, senderEmail);
300
301 #ifndef _WIN32_WCE
302 LPADRBOOK pAddressBook;
303 if(m_pMAPI->GetSession()->OpenAddressBook(0, NULL, AB_NO_DIALOG, &pAddressBook) == S_OK) {
304 SPropValue prop;
305 if(pAddressBook->CreateOneOff((LPTSTR)(senderName.Begin()), szAddrType,
306 (LPTSTR)(senderEmail.Begin()), 0, &prop.Value.bin.cb,
307 (LPENTRYID*)&prop.Value.bin.lpb) == S_OK) {
308 prop.ulPropTag=PR_SENT_REPRESENTING_ENTRYID;
309 Message()->SetProps(1, &prop, NULL);
310
311 SetPropertyString(PR_SENT_REPRESENTING_NAME, senderName);
312 SetPropertyString(PR_SENT_REPRESENTING_EMAIL_ADDRESS, senderEmail);
313 SetPropertyString(PR_SENT_REPRESENTING_ADDRTYPE, szAddrType);
314 }
315 }
316 RELEASE(pAddressBook);
317 #endif
318 }
319 }
320
SetReceivedTime(const Time & tm)321 bool MAPIMessage::SetReceivedTime(const Time &tm) {
322 SYSTEMTIME tmReceived;
323 MAPIEx::SetSystemTime(tmReceived, tm);
324
325 SPropValue prop;
326 prop.ulPropTag = PR_MESSAGE_DELIVERY_TIME;
327 #ifndef _WIN32_WCE
328 // if(bLocalTime) TzSpecificLocalTimeToSystemTime(NULL, &tmReceived, &tmReceived);
329 #endif
330 SystemTimeToFileTime(&tmReceived, &prop.Value.ft);
331 return (Message() && Message()->SetProps(1, &prop, NULL) == S_OK);
332 }
333
SetSubmitTime(const Time & tm)334 bool MAPIMessage::SetSubmitTime(const Time &tm) {
335 SYSTEMTIME tmSubmit;
336 MAPIEx::SetSystemTime(tmSubmit, tm);
337
338 SPropValue prop;
339 prop.ulPropTag = PR_CLIENT_SUBMIT_TIME;
340 #ifndef _WIN32_WCE
341 // if(bLocalTime) TzSpecificLocalTimeToSystemTime(NULL, &tmSubmit, &tmSubmit);
342 #endif
343 SystemTimeToFileTime(&tmSubmit, &prop.Value.ft);
344 return (Message() && Message()->SetProps(1, &prop, NULL) == S_OK);
345 }
346
347 // request a Read Receipt sent to szReceiverEmail
SetReadReceipt(bool bSet,String szReceiverEmail)348 bool MAPIMessage::SetReadReceipt(bool bSet, String szReceiverEmail) {
349 if(!Message())
350 return false;
351
352 SPropValue prop;
353 prop.ulPropTag = PR_READ_RECEIPT_REQUESTED;
354 prop.Value.b = (unsigned short)bSet;
355 if(Message()->SetProps(1, &prop, NULL) != S_OK)
356 return false;
357
358 if(bSet && !IsNull(szReceiverEmail) && szReceiverEmail.GetLength() > 0)
359 SetPropertyString(PR_READ_RECEIPT_REQUESTED, szReceiverEmail);
360 return true;
361 }
362
SetDeliveryReceipt(bool bSet)363 bool MAPIMessage::SetDeliveryReceipt(bool bSet) {
364 if(!Message())
365 return false;
366
367 SPropValue prop;
368 prop.ulPropTag = PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED;
369 prop.Value.b = (unsigned short)bSet;
370 return (Message()->SetProps(1, &prop, NULL) != S_OK);
371 }
372
373 // limited compare, compares entry IDs and subject to determine if two emails are equal
operator ==(MAPIMessage & message)374 bool MAPIMessage::operator==(MAPIMessage& message) {
375 if(!m_entryID.cb || !message.m_entryID.cb || m_entryID.cb!=message.m_entryID.cb)
376 return false;
377 if(memcmp(m_entryID.lpb,message.m_entryID.lpb, m_entryID.cb))
378 return false;
379 return (!m_strSubject.Compare(message.m_strSubject));
380 }
381
382 // Novell GroupWise customization by jcadmin
383 #ifndef GROUPWISE
MarkAsPrivate()384 bool MAPIMessage::MarkAsPrivate() { return false; }
385 #else
386 #include GWMAPI.h
387 //(from Novell Developer Kit)
388 #define SEND_OPTIONS_MARK_PRIVATE 0x00080000L
389
MarkAsPrivate()390 void MAPIMessage::MarkAsPrivate() {
391 SPropValue prop;
392 prop.ulPropTag = PR_NGW_SEND_OPTIONS;
393 prop.Value.l = NGW_SEND_OPTIONS_MARK_PRIVATE;
394 return (Message()->SetProps(1, &prop, NULL) == S_OK);
395 }
396 #endif
397
398 // In WinCE, use MSGSTATUS_RECTYPE_SMS for an SMS, MSGSTATUS_RECTYPE_SMTP for an email
SetMessageStatus(int nMessageStatus)399 bool MAPIMessage::SetMessageStatus(int nMessageStatus) {
400 SPropValue prop;
401 prop.ulPropTag = PR_MSG_STATUS;
402 prop.Value.ul = nMessageStatus;
403 return (Message()->SetProps(1, &prop, NULL) == S_OK);
404 }
405
406 // Shows the default MAPI form for IMessage, returns false on failure, IDOK on success or close existing messages
407 // and IDCANCEL on close new messages
ShowForm(MAPIEx * pMAPI,MAPIFolder & folder)408 int MAPIMessage::ShowForm(MAPIEx* pMAPI, MAPIFolder &folder) {
409 //MAPIFolder* pFolder=pMAPI->GetFolder();
410 IMAPISession* pSession = pMAPI->GetSession();
411 ULONG_PTR2 ulMessageToken;
412
413 if(folder.IsOpened() && pSession && pSession->PrepareForm(NULL, Message(), &ulMessageToken) == S_OK) {
414 ULONG ulMessageStatus=GetPropertyValue(PR_MSG_STATUS, 0);
415 ULONG ulMessageFlags=GetMessageFlags();
416 ULONG ulAccess=GetPropertyValue(PR_ACCESS, 0);
417
418 LPSPropValue pProp;
419 if(GetProperty(PR_MESSAGE_CLASS, pProp) == S_OK) {
420 char* szMessageClass = pProp->Value.LPSZ;
421 HRESULT hr = pSession->ShowForm(0, pMAPI->GetMessageStore(), folder.Folder(),
422 NULL, ulMessageToken, NULL, 0, ulMessageStatus,ulMessageFlags,
423 ulAccess, szMessageClass);
424 MAPIFreeBuffer(pProp);
425 if(hr == S_OK)
426 return IDOK;
427 if(hr == MAPI_E_USER_CANCEL)
428 return IDCANCEL;
429 }
430 }
431 return false;
432 }
433
Send()434 bool MAPIMessage::Send() {
435 if(Message()) {
436 HRESULT ret = Message()->SubmitMessage(0);
437 if (ret == S_OK) {
438 Close();
439 return true;
440 } else
441 return false;
442 }
443 return false;
444 }
445
SaveToFile(const String & fileName)446 bool MAPIMessage::SaveToFile(const String &fileName) {
447 if (!RealizePath(fileName))
448 return false;
449
450 #ifdef _WIN32_WCE
451 return false;
452 #else
453 LPSTORAGE pStorage;
454 DWORD dwFlags = STGM_READWRITE | STGM_TRANSACTED | STGM_CREATE;
455 if(StgCreateDocfile(fileName.ToWString(), dwFlags, 0, &pStorage) != S_OK)
456 return false;
457 LPMSGSESS pMsgSession;
458 LPMALLOC pMalloc = MF().MAPIGetDefaultMalloc();
459 if(MF().OpenIMsgSession(pMalloc, 0, &pMsgSession) == S_OK) {
460 LPMESSAGE pIMsg;
461 if(MF().OpenIMsgOnIStg(pMsgSession, MAPIAllocateBuffer, MAPIAllocateMore, MAPIFreeBuffer,
462 pMalloc, NULL, pStorage, NULL, 0, 0, &pIMsg) == S_OK) {
463 // client must support CLSID_MailMessage as the compound document
464 if(WriteClassStg(pStorage, CLSID_MailMessage) == S_OK) {
465 // exclude these properties from the copy operation to speed things up
466 SizedSPropTagArray (7, excludeTags);
467 excludeTags.cValues = 7;
468 excludeTags.aulPropTag[0] = PR_ACCESS;
469 excludeTags.aulPropTag[1] = PR_BODY;
470 excludeTags.aulPropTag[2] = PR_RTF_SYNC_BODY_COUNT;
471 excludeTags.aulPropTag[3] = PR_RTF_SYNC_BODY_CRC;
472 excludeTags.aulPropTag[4] = PR_RTF_SYNC_BODY_TAG;
473 excludeTags.aulPropTag[5] = PR_RTF_SYNC_PREFIX_COUNT;
474 excludeTags.aulPropTag[6] = PR_RTF_SYNC_TRAILING_COUNT;
475
476 if(Message()->CopyTo(0, NULL, (LPSPropTagArray)&excludeTags, 0, NULL,
477 (LPIID)&IID_IMessage, pIMsg, 0, NULL ) == S_OK) {
478 pIMsg->SaveChanges(KEEP_OPEN_READWRITE);
479 pStorage->Commit(STGC_DEFAULT);
480 }
481 }
482 RELEASE(pIMsg);
483 }
484 MF().CloseIMsgSession(pMsgSession);
485 }
486 RELEASE(pStorage);
487 return true;
488 #endif
489 }
490
491 #endif