]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/net/smapi.cpp
95b3287d62b1ee9ad2edc491ceef1396715924cf
[wxWidgets.git] / contrib / src / net / smapi.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: smapi.cpp
3 // Purpose: Simple MAPI classes
4 // Author: PJ Naughter <pjna@naughter.com>
5 // Modified by: Julian Smart
6 // Created: 2001-08-21
7 // RCS-ID: $Id$
8 // Copyright: (c) PJ Naughter
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "smapi.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifdef __WXMSW__
24
25 #ifndef WX_PRECOMP
26 #include "wx/wx.h"
27 #endif
28
29 #include "wx/string.h"
30 #include "wx/msw/private.h"
31
32 // mapi.h in Cygwin's include directory isn't a full implementation and is
33 // not sufficient for this lib. However recent versions of Cygwin also
34 // have another mapi.h in include/w32api which can be used.
35 //
36 #ifdef __CYGWIN__
37 #include <w32api/mapi.h>
38 #else
39 #include <mapi.h>
40 #endif
41
42 #include "wx/net/smapi.h"
43
44 class WXDLLIMPEXP_NETUTILS wxMapiData
45 {
46 public:
47 wxMapiData()
48 {
49 m_hSession = 0;
50 m_nLastError = 0;
51 m_hMapi = NULL;
52 m_lpfnMAPILogon = NULL;
53 m_lpfnMAPILogoff = NULL;
54 m_lpfnMAPISendMail = NULL;
55 m_lpfnMAPIResolveName = NULL;
56 m_lpfnMAPIFreeBuffer = NULL;
57 }
58
59 //Data
60 LHANDLE m_hSession; //Mapi Session handle
61 long m_nLastError; //Last Mapi error value
62 HINSTANCE m_hMapi; //Instance handle of the MAPI dll
63 LPMAPILOGON m_lpfnMAPILogon; //MAPILogon function pointer
64 LPMAPILOGOFF m_lpfnMAPILogoff; //MAPILogoff function pointer
65 LPMAPISENDMAIL m_lpfnMAPISendMail; //MAPISendMail function pointer
66 LPMAPIRESOLVENAME m_lpfnMAPIResolveName; //MAPIResolveName function pointer
67 LPMAPIFREEBUFFER m_lpfnMAPIFreeBuffer; //MAPIFreeBuffer function pointer
68 };
69
70
71 ////////////////////////////////// Implementation /////////////////////////////
72
73 wxMapiSession::wxMapiSession()
74 {
75 m_data = new wxMapiData;
76
77 Initialise();
78 }
79
80 wxMapiSession::~wxMapiSession()
81 {
82 //Logoff if logged on
83 Logoff();
84
85 //Unload the MAPI dll
86 Deinitialise();
87
88 delete m_data;
89 }
90
91 void wxMapiSession::Initialise()
92 {
93 //First make sure the "WIN.INI" entry for MAPI is present aswell
94 //as the MAPI32 dll being present on the system
95 bool bMapiInstalled = (GetProfileInt(_T("MAIL"), _T("MAPI"), 0) != 0) &&
96 (SearchPath(NULL, _T("MAPI32.DLL"), NULL, 0, NULL, NULL) != 0);
97
98 if (bMapiInstalled)
99 {
100 //Load up the MAPI dll and get the function pointers we are interested in
101 m_data->m_hMapi = ::LoadLibrary(_T("MAPI32.DLL"));
102 if (m_data->m_hMapi)
103 {
104 m_data->m_lpfnMAPILogon = (LPMAPILOGON) GetProcAddress(m_data->m_hMapi, "MAPILogon");
105 m_data->m_lpfnMAPILogoff = (LPMAPILOGOFF) GetProcAddress(m_data->m_hMapi, "MAPILogoff");
106 m_data->m_lpfnMAPISendMail = (LPMAPISENDMAIL) GetProcAddress(m_data->m_hMapi, "MAPISendMail");
107 m_data->m_lpfnMAPIResolveName = (LPMAPIRESOLVENAME) GetProcAddress(m_data->m_hMapi, "MAPIResolveName");
108 m_data->m_lpfnMAPIFreeBuffer = (LPMAPIFREEBUFFER) GetProcAddress(m_data->m_hMapi, "MAPIFreeBuffer");
109
110 //If any of the functions are not installed then fail the load
111 if (m_data->m_lpfnMAPILogon == NULL ||
112 m_data->m_lpfnMAPILogoff == NULL ||
113 m_data->m_lpfnMAPISendMail == NULL ||
114 m_data->m_lpfnMAPIResolveName == NULL ||
115 m_data->m_lpfnMAPIFreeBuffer == NULL)
116 {
117 wxLogDebug(_T("Failed to get one of the functions pointer in MAPI32.DLL\n"));
118 Deinitialise();
119 }
120 }
121 }
122 else
123 wxLogDebug(_T("Mapi is not installed on this computer\n"));
124 }
125
126 void wxMapiSession::Deinitialise()
127 {
128 if (m_data->m_hMapi)
129 {
130 //Unload the MAPI dll and reset the function pointers to NULL
131 FreeLibrary(m_data->m_hMapi);
132 m_data->m_hMapi = NULL;
133 m_data->m_lpfnMAPILogon = NULL;
134 m_data->m_lpfnMAPILogoff = NULL;
135 m_data->m_lpfnMAPISendMail = NULL;
136 m_data->m_lpfnMAPIResolveName = NULL;
137 m_data->m_lpfnMAPIFreeBuffer = NULL;
138 }
139 }
140
141 bool wxMapiSession::Logon(const wxString& sProfileName, const wxString& sPassword, wxWindow* pParentWnd)
142 {
143 wxASSERT(MapiInstalled()); //MAPI must be installed
144 wxASSERT(m_data->m_lpfnMAPILogon); //Function pointer must be valid
145
146 //Initialise the function return value
147 bool bSuccess = FALSE;
148
149 //Just in case we are already logged in
150 Logoff();
151
152 //Setup the ascii versions of the profile name and password
153 int nProfileLength = sProfileName.Length();
154
155 LPSTR pszProfileName = NULL;
156 LPSTR pszPassword = NULL;
157 wxCharBuffer cbProfile(1),cbPassword(1);
158 if (nProfileLength)
159 {
160 #ifndef UNICODE
161 pszProfileName = (LPSTR) sProfileName.c_str();
162 pszPassword = (LPSTR) sPassword.c_str();
163 #else
164 cbProfile = sProfileName.mb_str();
165 cbPassword = sPassword.mb_str();
166 pszProfileName = cbProfile.data();
167 pszPassword = cbPassword.data();
168 #endif
169 }
170
171 //Setup the flags & UIParam parameters used in the MapiLogon call
172 FLAGS flags = 0;
173 ULONG nUIParam = 0;
174 if (nProfileLength == 0)
175 {
176 //No profile name given, then we must interactively request a profile name
177 if (pParentWnd)
178 {
179 nUIParam = (ULONG) (HWND) pParentWnd->GetHWND();
180 flags |= MAPI_LOGON_UI;
181 }
182 else
183 {
184 //No window given, just use the main window of the app as the parent window
185 if (wxTheApp->GetTopWindow())
186 {
187 nUIParam = (ULONG) (HWND) wxTheApp->GetTopWindow()->GetHWND();
188 flags |= MAPI_LOGON_UI;
189 }
190 }
191 }
192
193 //First try to acquire a new MAPI session using the supplied settings using the MAPILogon functio
194 ULONG nError = m_data->m_lpfnMAPILogon(nUIParam, pszProfileName, pszPassword, flags | MAPI_NEW_SESSION, 0, &m_data->m_hSession);
195 if (nError != SUCCESS_SUCCESS && nError != MAPI_E_USER_ABORT)
196 {
197 //Failed to create a create mapi session, try to acquire a shared mapi session
198 wxLogDebug(_T("Failed to logon to MAPI using a new session, trying to acquire a shared one\n"));
199 nError = m_data->m_lpfnMAPILogon(nUIParam, NULL, NULL, 0, 0, &m_data->m_hSession);
200 if (nError == SUCCESS_SUCCESS)
201 {
202 m_data->m_nLastError = SUCCESS_SUCCESS;
203 bSuccess = TRUE;
204 }
205 else
206 {
207 wxLogDebug(_T("Failed to logon to MAPI using a shared session, Error:%ld\n"), nError);
208 m_data->m_nLastError = nError;
209 }
210 }
211 else if (nError == SUCCESS_SUCCESS)
212 {
213 m_data->m_nLastError = SUCCESS_SUCCESS;
214 bSuccess = TRUE;
215 }
216
217 return bSuccess;
218 }
219
220 bool wxMapiSession::LoggedOn() const
221 {
222 return (m_data->m_hSession != 0);
223 }
224
225 bool wxMapiSession::MapiInstalled() const
226 {
227 return (m_data->m_hMapi != NULL);
228 }
229
230 bool wxMapiSession::Logoff()
231 {
232 wxASSERT(MapiInstalled()); //MAPI must be installed
233 wxASSERT(m_data->m_lpfnMAPILogoff); //Function pointer must be valid
234
235 //Initialise the function return value
236 bool bSuccess = FALSE;
237
238 if (m_data->m_hSession)
239 {
240 //Call the MAPILogoff function
241 ULONG nError = m_data->m_lpfnMAPILogoff(m_data->m_hSession, 0, 0, 0);
242 if (nError != SUCCESS_SUCCESS)
243 {
244 wxLogDebug(_T("Failed in call to MapiLogoff, Error:%ld"), nError);
245 m_data->m_nLastError = nError;
246 bSuccess = TRUE;
247 }
248 else
249 {
250 m_data->m_nLastError = SUCCESS_SUCCESS;
251 bSuccess = TRUE;
252 }
253 m_data->m_hSession = 0;
254 }
255
256 return bSuccess;
257 }
258
259 bool wxMapiSession::Resolve(const wxString& sName, void* lppRecip1)
260 {
261 lpMapiRecipDesc* lppRecip = (lpMapiRecipDesc*) lppRecip1;
262
263 wxASSERT(MapiInstalled()); //MAPI must be installed
264 wxASSERT(m_data->m_lpfnMAPIResolveName); //Function pointer must be valid
265 wxASSERT(LoggedOn()); //Must be logged on to MAPI
266 wxASSERT(m_data->m_hSession); //MAPI session handle must be valid
267
268 //Call the MAPIResolveName function
269 #ifndef UNICODE
270 LPSTR lpszAsciiName = (LPSTR) sName.c_str();
271 #else
272 wxCharBuffer cbName(1);
273 cbName = sName.mb_str();
274 LPSTR lpszAsciiName = cbName.data();
275 #endif
276 ULONG nError = m_data->m_lpfnMAPIResolveName(m_data->m_hSession, 0, lpszAsciiName, 0, 0, lppRecip);
277 if (nError != SUCCESS_SUCCESS)
278 {
279 wxLogDebug(_T("Failed to resolve the name: %s, Error:%ld\n"),
280 sName.c_str(), nError);
281 m_data->m_nLastError = nError;
282 }
283
284 return (nError == SUCCESS_SUCCESS);
285 }
286
287 bool wxMapiSession::Send(wxMailMessage& message)
288 {
289 wxASSERT(MapiInstalled()); //MAPI must be installed
290 wxASSERT(m_data->m_lpfnMAPISendMail); //Function pointer must be valid
291 wxASSERT(m_data->m_lpfnMAPIFreeBuffer); //Function pointer must be valid
292 wxASSERT(LoggedOn()); //Must be logged on to MAPI
293 wxASSERT(m_data->m_hSession); //MAPI session handle must be valid
294
295 //Initialise the function return value
296 bool bSuccess = FALSE;
297
298 //Create the MapiMessage structure to match the message parameter send into us
299 MapiMessage mapiMessage;
300 ZeroMemory(&mapiMessage, sizeof(mapiMessage));
301 #ifndef UNICODE
302 mapiMessage.lpszSubject = (LPSTR) message.m_subject.c_str();
303 mapiMessage.lpszNoteText = (LPSTR) message.m_body.c_str();
304 #else
305 wxCharBuffer cbSubject(1),cbBody(1),cbOriginator(1);
306 cbSubject = message.m_subject.mb_str();
307 cbBody = message.m_body.mb_str();
308 mapiMessage.lpszSubject = cbSubject.data();
309 mapiMessage.lpszNoteText = cbBody.data();
310 #endif
311 mapiMessage.nRecipCount = message.m_to.GetCount() + message.m_cc.GetCount() + message.m_bcc.GetCount();
312 wxASSERT(mapiMessage.nRecipCount); //Must have at least 1 recipient!
313
314 //Allocate the recipients array
315 mapiMessage.lpRecips = new MapiRecipDesc[mapiMessage.nRecipCount];
316
317 // If we have a 'From' field, use it
318 if (!message.m_from.IsEmpty())
319 {
320 mapiMessage.lpOriginator = new MapiRecipDesc;
321 ZeroMemory(mapiMessage.lpOriginator, sizeof(MapiRecipDesc));
322
323 mapiMessage.lpOriginator->ulRecipClass = MAPI_ORIG;
324 // TODO Do we have to call Resolve?
325 #ifndef UNICODE
326 mapiMessage.lpOriginator->lpszName = (LPSTR) message.m_from.c_str();
327 #else
328 cbOriginator = message.m_from.mb_str();
329 mapiMessage.lpOriginator->lpszName = cbOriginator.data();
330 #endif
331 }
332
333 //Setup the "To" recipients
334 int nRecipIndex = 0;
335 int nToSize = message.m_to.GetCount();
336 int i;
337 for (i=0; i<nToSize; i++)
338 {
339 MapiRecipDesc& recip = mapiMessage.lpRecips[nRecipIndex];
340 ZeroMemory(&recip, sizeof(MapiRecipDesc));
341 recip.ulRecipClass = MAPI_TO;
342 wxString& sName = message.m_to[i];
343
344 //Try to resolve the name
345 lpMapiRecipDesc lpTempRecip;
346 if (Resolve(sName, (void*) &lpTempRecip))
347 {
348 //Resolve worked, put the resolved name back into the sName
349 sName = wxString(lpTempRecip->lpszName,*wxConvCurrent);
350
351 //Don't forget to free up the memory MAPI allocated for us
352 m_data->m_lpfnMAPIFreeBuffer(lpTempRecip);
353 }
354 #ifndef UNICODE
355 recip.lpszName = (LPSTR) sName.c_str();
356 #else
357 recip.lpszName = sName.mb_str().release();
358 #endif
359
360 ++nRecipIndex;
361 }
362
363 //Setup the "CC" recipients
364 int nCCSize = message.m_cc.GetCount();
365 for (i=0; i<nCCSize; i++)
366 {
367 MapiRecipDesc& recip = mapiMessage.lpRecips[nRecipIndex];
368 ZeroMemory(&recip, sizeof(MapiRecipDesc));
369 recip.ulRecipClass = MAPI_CC;
370 wxString& sName = message.m_cc[i];
371
372 //Try to resolve the name
373 lpMapiRecipDesc lpTempRecip;
374 if (Resolve(sName, (void*) &lpTempRecip))
375 {
376 //Resolve worked, put the resolved name back into the sName
377 sName = wxString(lpTempRecip->lpszName,*wxConvCurrent);
378
379 //Don't forget to free up the memory MAPI allocated for us
380 m_data->m_lpfnMAPIFreeBuffer(lpTempRecip);
381 }
382 #ifndef UNICODE
383 recip.lpszName = (LPSTR) sName.c_str();
384 #else
385 recip.lpszName = sName.mb_str().release();
386 #endif
387
388 ++nRecipIndex;
389 }
390
391 //Setup the "BCC" recipients
392 int nBCCSize = message.m_bcc.GetCount();
393 for (i=0; i<nBCCSize; i++)
394 {
395 MapiRecipDesc& recip = mapiMessage.lpRecips[nRecipIndex];
396 ZeroMemory(&recip, sizeof(MapiRecipDesc));
397 recip.ulRecipClass = MAPI_BCC;
398 wxString& sName = message.m_bcc[i];
399
400 //Try to resolve the name
401 lpMapiRecipDesc lpTempRecip;
402 if (Resolve(sName, (void*) &lpTempRecip))
403 {
404 //Resolve worked, put the resolved name back into the sName
405 sName = wxString(lpTempRecip->lpszName,wxConvCurrent);
406
407 //Don't forget to free up the memory MAPI allocated for us
408 m_data->m_lpfnMAPIFreeBuffer(lpTempRecip);
409 }
410 #ifndef UNICODE
411 recip.lpszName = (LPSTR) sName.c_str();
412 #else
413 recip.lpszName = sName.mb_str().release();
414 #endif
415
416 ++nRecipIndex;
417 }
418
419 //Setup the attachments
420 int nAttachmentSize = message.m_attachments.GetCount();
421 int nTitleSize = message.m_attachmentTitles.GetCount();
422 if (nTitleSize)
423 {
424 wxASSERT(nTitleSize == nAttachmentSize); //If you are going to set the attachment titles then you must set
425 //the attachment title for each attachment
426 }
427 if (nAttachmentSize)
428 {
429 mapiMessage.nFileCount = nAttachmentSize;
430 mapiMessage.lpFiles = new MapiFileDesc[nAttachmentSize];
431 for (i=0; i<nAttachmentSize; i++)
432 {
433 MapiFileDesc& file = mapiMessage.lpFiles[i];
434 ZeroMemory(&file, sizeof(MapiFileDesc));
435 file.nPosition = 0xFFFFFFFF;
436 wxString& sFilename = message.m_attachments[i];
437
438 #ifndef UNICODE
439 file.lpszPathName = (LPSTR) sFilename.c_str();
440 #else
441 file.lpszPathName = sFilename.mb_str().release();
442 #endif
443 //file.lpszFileName = file.lpszPathName;
444 file.lpszFileName = NULL;
445
446 if (nTitleSize && !message.m_attachmentTitles[i].IsEmpty())
447 {
448 wxString& sTitle = message.m_attachmentTitles[i];
449 #ifndef UNICODE
450 file.lpszFileName = (LPSTR) sTitle.c_str();
451 #else
452 file.lpszFileName = sTitle.mb_str().release();
453 #endif
454 }
455 }
456 }
457
458 //Do the actual send using MAPISendMail
459 ULONG nError = m_data->m_lpfnMAPISendMail(m_data->m_hSession, 0, &mapiMessage, MAPI_DIALOG, 0);
460 if (nError == SUCCESS_SUCCESS)
461 {
462 bSuccess = TRUE;
463 m_data->m_nLastError = SUCCESS_SUCCESS;
464 }
465 else
466 {
467 wxLogDebug(_T("Failed to send mail message, Error:%ld\n"), nError);
468 m_data->m_nLastError = nError;
469 }
470
471 //Tidy up the Attachements
472 if (nAttachmentSize)
473 {
474 #ifdef UNICODE
475 for (i = 0;i < nAttachmentSize;i++)
476 {
477 free(mapiMessage.lpFiles[i].lpszPathName);
478 free(mapiMessage.lpFiles[i].lpszFileName);
479 }
480 #endif
481 delete [] mapiMessage.lpFiles;
482 }
483
484 //Free up the Recipients and Originator memory
485 #ifdef UNICODE
486 for (i = 0;i < nRecipIndex;i++)
487 free(mapiMessage.lpRecips[i].lpszName);
488 #endif
489 delete [] mapiMessage.lpRecips;
490
491 delete mapiMessage.lpOriginator;
492
493 return bSuccess;
494 }
495
496 long wxMapiSession::GetLastError() const
497 {
498 return m_data->m_nLastError;
499 }
500
501 #endif // __WXMSW__