Merge branch 'bare-repo'
[TortoiseGit.git] / src / Utils / MailMsg.cpp
blob9f8894f86944b710b8ae1c8a255c5319579feaf4
1 /*************************************************************************************
2 This file is a part of CrashRpt library.
4 Copyright (c) 2003, Michael Carruth
5 All rights reserved.
7 Adjusted by Sven Strickroth <email@cs-ware.de>, 2011
8 * make it work with no attachments
9 * added flag to show mail compose dialog
10 * make it work with 32-64bit inconsistencies (http://msdn.microsoft.com/en-us/library/dd941355.aspx)
11 * auto extract filenames of attachments
12 * added AddCC
14 Redistribution and use in source and binary forms, with or without modification,
15 are permitted provided that the following conditions are met:
17 * Redistributions of source code must retain the above copyright notice, this
18 list of conditions and the following disclaimer.
20 * Redistributions in binary form must reproduce the above copyright notice,
21 this list of conditions and the following disclaimer in the documentation
22 and/or other materials provided with the distribution.
24 * Neither the name of the author nor the names of its contributors
25 may be used to endorse or promote products derived from this software without
26 specific prior written permission.
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
30 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
31 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
32 SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
34 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
37 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 ***************************************************************************************/
40 ///////////////////////////////////////////////////////////////////////////////
42 // Module: MailMsg.cpp
44 // Desc: See MailMsg.h
46 // Copyright (c) 2003 Michael Carruth
48 ///////////////////////////////////////////////////////////////////////////////
50 #include "stdafx.h"
51 #include "MailMsg.h"
52 #include "strconv.h"
54 CMailMsg::CMailMsg()
56 m_lpCmcLogon = NULL;
57 m_lpCmcSend = NULL;
58 m_lpCmcLogoff = NULL;
59 m_lpMapiSendMail = NULL;
60 m_bReady = FALSE;
61 m_bShowComposeDialog = FALSE;
64 CMailMsg::~CMailMsg()
66 if (m_bReady)
67 MAPIFinalize();
71 void CMailMsg::SetFrom(CString sAddress)
73 strconv_t strconv;
74 LPCSTR lpszAddress = strconv.t2a(sAddress.GetBuffer(0));
75 m_from = lpszAddress;
78 void CMailMsg::SetTo(CString sAddress)
80 strconv_t strconv;
81 LPCSTR lpszAddress = strconv.t2a(sAddress.GetBuffer(0));
82 m_to = lpszAddress;
85 void CMailMsg::SetSubject(CString sSubject)
87 strconv_t strconv;
88 LPCSTR lpszSubject = strconv.t2a(sSubject.GetBuffer(0));
89 m_sSubject = lpszSubject;
92 void CMailMsg::SetMessage(CString sMessage)
94 strconv_t strconv;
95 LPCSTR lpszMessage = strconv.t2a(sMessage.GetBuffer(0));
96 m_sMessage = lpszMessage;
99 void CMailMsg::SetShowComposeDialog(BOOL showComposeDialog)
101 m_bShowComposeDialog = showComposeDialog;
104 void CMailMsg::AddCC(CString sAddress)
106 strconv_t strconv;
107 LPCSTR lpszAddress = strconv.t2a(sAddress.GetBuffer(0));
108 m_cc.push_back(lpszAddress);
111 void CMailMsg::AddAttachment(CString sAttachment, CString sTitle)
113 strconv_t strconv;
114 LPCSTR lpszAttachment = strconv.t2a(sAttachment.GetBuffer(0));
115 if (sTitle.IsEmpty())
117 int position = sAttachment.ReverseFind(_T('\\'));
118 if(position >=0)
120 sTitle = sAttachment.Mid(position+1);
122 else
124 sTitle = sAttachment;
127 LPCSTR lpszTitle = strconv.t2a(sTitle.GetBuffer(0));
128 m_attachments[lpszAttachment] = lpszTitle;
131 BOOL CMailMsg::DetectMailClient(CString& sMailClientName)
133 CRegKey regKey;
134 TCHAR buf[1024] = _T("");
135 ULONG buf_size = 0;
136 LONG lResult;
138 lResult = regKey.Open(HKEY_CURRENT_USER, _T("SOFTWARE\\Clients\\Mail"), KEY_READ);
139 if(lResult!=ERROR_SUCCESS)
141 lResult = regKey.Open(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Clients\\Mail"), KEY_READ);
144 if(lResult==ERROR_SUCCESS)
146 buf_size = 1023;
147 #pragma warning(disable:4996)
148 LONG result = regKey.QueryValue(buf, _T(""), &buf_size);
149 #pragma warning(default:4996)
150 if(result==ERROR_SUCCESS)
152 sMailClientName = buf;
153 return TRUE;
155 regKey.Close();
157 else
159 sMailClientName = "Not Detected";
162 return FALSE;
165 BOOL CMailMsg::MAPIInitialize()
167 // Determine if there is default email program
169 CString sMailClientName;
170 if(!DetectMailClient(sMailClientName))
172 m_sErrorMsg = _T("Error detecting E-mail client");
173 return FALSE;
175 else
177 m_sErrorMsg = _T("Detected E-mail client ") + sMailClientName;
180 // Load MAPI.dll
182 m_hMapi = ::LoadLibrary(_T("mapi32.dll"));
183 if (!m_hMapi)
185 m_sErrorMsg = _T("Error loading mapi32.dll");
186 return FALSE;
189 m_lpCmcQueryConfiguration = (LPCMCQUERY)::GetProcAddress(m_hMapi, "cmc_query_configuration");
190 m_lpCmcLogon = (LPCMCLOGON)::GetProcAddress(m_hMapi, "cmc_logon");
191 m_lpCmcSend = (LPCMCSEND)::GetProcAddress(m_hMapi, "cmc_send");
192 m_lpCmcLogoff = (LPCMCLOGOFF)::GetProcAddress(m_hMapi, "cmc_logoff");
194 m_lpMapiSendMail = (LPMAPISENDMAIL)::GetProcAddress(m_hMapi, "MAPISendMail");
196 m_bReady = (m_lpCmcLogon && m_lpCmcSend && m_lpCmcLogoff) ||
197 (m_lpMapiSendMail);
199 if(!m_bReady)
201 m_sErrorMsg = _T("Not found required function entries in mapi32.dll");
204 return m_bReady;
207 void CMailMsg::MAPIFinalize()
209 ::FreeLibrary(m_hMapi);
212 CString CMailMsg::GetEmailClientName()
214 return m_sEmailClientName;
217 BOOL CMailMsg::Send()
219 if(MAPISend())
220 return TRUE;
222 if(CMCSend())
223 return TRUE;
225 return FALSE;
228 BOOL CMailMsg::MAPISend()
230 if(m_lpMapiSendMail==NULL)
231 return FALSE;
233 TStrStrMap::iterator p;
234 int nIndex = 0;
235 MapiRecipDesc* pRecipients = NULL;
236 int nAttachments = 0;
237 MapiFileDesc* pAttachments = NULL;
238 ULONG status = 0;
239 MapiMessage message;
241 if(!m_bReady && !MAPIInitialize())
242 return FALSE;
244 pRecipients = new MapiRecipDesc[2 + m_cc.size()];
245 if(!pRecipients)
247 m_sErrorMsg = _T("Error allocating memory");
248 return FALSE;
251 nAttachments = (int)m_attachments.size();
252 if (nAttachments)
254 pAttachments = new MapiFileDesc[nAttachments];
255 if(!pAttachments)
257 m_sErrorMsg = _T("Error allocating memory");
258 return FALSE;
262 // set from
263 pRecipients[0].ulReserved = 0;
264 pRecipients[0].ulRecipClass = MAPI_ORIG;
265 pRecipients[0].lpszAddress = (LPSTR)m_from.c_str();
266 pRecipients[0].lpszName = "";
267 pRecipients[0].ulEIDSize = 0;
268 pRecipients[0].lpEntryID = NULL;
270 // set to
271 pRecipients[1].ulReserved = 0;
272 pRecipients[1].ulRecipClass = MAPI_TO;
273 pRecipients[1].lpszAddress = (LPSTR)m_to.c_str();
274 pRecipients[1].lpszName = (LPSTR)m_to.c_str();
275 pRecipients[1].ulEIDSize = 0;
276 pRecipients[1].lpEntryID = NULL;
278 // add cc receipients
279 nIndex = 2;
280 for(int i=0; i < m_cc.size(); i++)
282 pRecipients[nIndex].ulReserved = 0;
283 pRecipients[nIndex].ulRecipClass = MAPI_CC;
284 pRecipients[nIndex].lpszAddress = (LPSTR)m_cc.at(i).c_str();
285 pRecipients[nIndex].lpszName = (LPSTR)m_cc.at(i).c_str();
286 pRecipients[nIndex].ulEIDSize = 0;
287 pRecipients[nIndex].lpEntryID = NULL;
288 nIndex++;
291 nIndex=0;
292 // add attachments
293 for (p = m_attachments.begin(), nIndex = 0;
294 p != m_attachments.end(); p++, nIndex++)
296 pAttachments[nIndex].ulReserved = 0;
297 pAttachments[nIndex].flFlags = 0;
298 pAttachments[nIndex].nPosition = 0xFFFFFFFF;
299 pAttachments[nIndex].lpszPathName = (LPSTR)p->first.c_str();
300 pAttachments[nIndex].lpszFileName = (LPSTR)p->second.c_str();
301 pAttachments[nIndex].lpFileType = NULL;
304 message.ulReserved = 0;
305 message.lpszSubject = (LPSTR)m_sSubject.c_str();
306 message.lpszNoteText = (LPSTR)m_sMessage.c_str();
307 message.lpszMessageType = NULL;
308 message.lpszDateReceived = NULL;
309 message.lpszConversationID = NULL;
310 message.flFlags = 0;
311 message.lpOriginator = pRecipients;
312 message.nRecipCount = 1 + m_cc.size();
313 message.lpRecips = &pRecipients[1];
314 message.nFileCount = nAttachments;
315 message.lpFiles = nAttachments ? pAttachments : NULL;
317 status = m_lpMapiSendMail(NULL, 0, &message, (m_bShowComposeDialog?MAPI_DIALOG:0)|MAPI_LOGON_UI, 0);
319 if(status!=SUCCESS_SUCCESS)
321 m_sErrorMsg.Format(_T("MAPISendMail has failed with code %X."), status);
324 if (pRecipients)
325 delete [] pRecipients;
327 if (nAttachments)
328 delete [] pAttachments;
330 return (SUCCESS_SUCCESS == status);
333 BOOL CMailMsg::CMCSend()
335 TStrStrMap::iterator p;
336 int nIndex = 0;
337 CMC_recipient* pRecipients;
338 CMC_attachment* pAttachments;
339 CMC_session_id session;
340 CMC_return_code status = 0;
341 CMC_message message;
342 CMC_boolean bAvailable = FALSE;
343 CMC_time t_now = {0};
345 if (!m_bReady && !MAPIInitialize())
346 return FALSE;
348 pRecipients = new CMC_recipient[2 + m_cc.size()];
349 pAttachments = new CMC_attachment[m_attachments.size()];
351 // set to
352 pRecipients[nIndex].name = (LPSTR)m_to.c_str();
353 pRecipients[nIndex].name_type = CMC_TYPE_INDIVIDUAL;
354 pRecipients[nIndex].address = (CMC_string)(LPCSTR)m_to.c_str();
355 pRecipients[nIndex].role = CMC_ROLE_TO;
356 pRecipients[nIndex].recip_flags = 0;
357 pRecipients[nIndex].recip_extensions = NULL;
359 // set from
360 pRecipients[nIndex+1].name = (LPSTR)m_from.c_str();
361 pRecipients[nIndex+1].name_type = CMC_TYPE_INDIVIDUAL;
362 pRecipients[nIndex+1].address = (CMC_string)(LPCSTR)m_from.c_str();
363 pRecipients[nIndex+1].role = CMC_ROLE_ORIGINATOR;
364 pRecipients[nIndex+1].recip_flags = 0;
365 pRecipients[nIndex+1].recip_extensions = NULL;
367 // add cc receipients
368 nIndex = 2;
369 for(int i=0; i < m_cc.size(); i++)
371 pRecipients[nIndex].name = (LPSTR)m_cc.at(i).c_str();
372 pRecipients[nIndex].name_type = CMC_TYPE_INDIVIDUAL;
373 pRecipients[nIndex].address = (CMC_string)(LPCSTR)m_cc.at(i).c_str();
374 pRecipients[nIndex].role = CMC_ROLE_CC;
375 pRecipients[nIndex].recip_flags = 0;
376 pRecipients[nIndex].recip_extensions = NULL;
377 nIndex++;
379 pRecipients[nIndex-1].recip_flags = CMC_RECIP_LAST_ELEMENT;
381 // add attachments
382 for (p = m_attachments.begin(), nIndex = 0;
383 p != m_attachments.end(); p++, nIndex++)
385 pAttachments[nIndex].attach_title = (LPSTR)p->second.c_str();
386 pAttachments[nIndex].attach_type = NULL;
387 pAttachments[nIndex].attach_filename = (CMC_string)(LPCSTR)p->first.c_str();
388 pAttachments[nIndex].attach_flags = 0;
389 pAttachments[nIndex].attach_extensions = NULL;
392 pAttachments[nIndex-1].attach_flags = CMC_ATT_LAST_ELEMENT;
394 message.message_reference = NULL;
395 message.message_type = NULL;
396 message.subject = (LPSTR)m_sSubject.c_str();
397 message.time_sent = t_now;
398 message.text_note = (LPSTR)m_sMessage.c_str();
399 message.recipients = pRecipients;
400 message.attachments = pAttachments;
401 message.message_flags = 0;
402 message.message_extensions = NULL;
404 status = m_lpCmcQueryConfiguration(
406 CMC_CONFIG_UI_AVAIL,
407 (void*)&bAvailable,
408 NULL
411 if (CMC_SUCCESS == status && bAvailable)
413 status = m_lpCmcLogon(
414 NULL,
415 NULL,
416 NULL,
417 NULL,
419 CMC_VERSION,
420 CMC_LOGON_UI_ALLOWED |
421 CMC_ERROR_UI_ALLOWED,
422 &session,
423 NULL
426 if (CMC_SUCCESS == status)
428 status = m_lpCmcSend(session, &message, 0, 0, NULL);
429 m_lpCmcLogoff(session, NULL, CMC_LOGON_UI_ALLOWED, NULL);
433 delete [] pRecipients;
434 delete [] pAttachments;
436 return ((CMC_SUCCESS == status) && bAvailable);