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