]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/net/smapi.cpp
don't eat all events if m_maxLength is 0: this means no limit according to the docs...
[wxWidgets.git] / contrib / src / net / smapi.cpp
CommitLineData
decb3a6a
JS
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
decb3a6a
JS
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
5f109709
MB
19#ifdef __WXMSW__
20
decb3a6a
JS
21#ifndef WX_PRECOMP
22#include "wx/wx.h"
23#endif
24
25#include "wx/string.h"
26#include "wx/msw/private.h"
27
508c5a09
MW
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
decb3a6a 35#include <mapi.h>
508c5a09 36#endif
decb3a6a
JS
37
38#include "wx/net/smapi.h"
39
15e8daec 40class WXDLLIMPEXP_NETUTILS wxMapiData
decb3a6a
JS
41{
42public:
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
69wxMapiSession::wxMapiSession()
70{
71 m_data = new wxMapiData;
72
73 Initialise();
74}
75
76wxMapiSession::~wxMapiSession()
77{
78 //Logoff if logged on
79 Logoff();
80
81 //Unload the MAPI dll
82 Deinitialise();
83
84 delete m_data;
85}
86
87void 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
122void 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
137bool 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();
decb3a6a
JS
150
151 LPSTR pszProfileName = NULL;
152 LPSTR pszPassword = NULL;
5a618a14 153 wxCharBuffer cbProfile(1),cbPassword(1);
decb3a6a
JS
154 if (nProfileLength)
155 {
5a618a14 156#ifndef UNICODE
decb3a6a
JS
157 pszProfileName = (LPSTR) sProfileName.c_str();
158 pszPassword = (LPSTR) sPassword.c_str();
5a618a14
JS
159#else
160 cbProfile = sProfileName.mb_str();
161 cbPassword = sPassword.mb_str();
162 pszProfileName = cbProfile.data();
163 pszPassword = cbPassword.data();
164#endif
decb3a6a
JS
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 {
9409aa35 203 wxLogDebug(_T("Failed to logon to MAPI using a shared session, Error:%ld\n"), nError);
decb3a6a
JS
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
216bool wxMapiSession::LoggedOn() const
217{
218 return (m_data->m_hSession != 0);
219}
220
221bool wxMapiSession::MapiInstalled() const
222{
223 return (m_data->m_hMapi != NULL);
224}
225
226bool 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 {
9409aa35 240 wxLogDebug(_T("Failed in call to MapiLogoff, Error:%ld"), nError);
decb3a6a
JS
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
255bool 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
5a618a14 265#ifndef UNICODE
decb3a6a 266 LPSTR lpszAsciiName = (LPSTR) sName.c_str();
5a618a14
JS
267#else
268 wxCharBuffer cbName(1);
269 cbName = sName.mb_str();
270 LPSTR lpszAsciiName = cbName.data();
271#endif
decb3a6a
JS
272 ULONG nError = m_data->m_lpfnMAPIResolveName(m_data->m_hSession, 0, lpszAsciiName, 0, 0, lppRecip);
273 if (nError != SUCCESS_SUCCESS)
274 {
9409aa35
JS
275 wxLogDebug(_T("Failed to resolve the name: %s, Error:%ld\n"),
276 sName.c_str(), nError);
decb3a6a
JS
277 m_data->m_nLastError = nError;
278 }
279
280 return (nError == SUCCESS_SUCCESS);
281}
282
283bool 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));
5a618a14 297#ifndef UNICODE
decb3a6a
JS
298 mapiMessage.lpszSubject = (LPSTR) message.m_subject.c_str();
299 mapiMessage.lpszNoteText = (LPSTR) message.m_body.c_str();
5a618a14
JS
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
decb3a6a
JS
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];
a23c0047
JS
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?
5a618a14 321#ifndef UNICODE
a23c0047 322 mapiMessage.lpOriginator->lpszName = (LPSTR) message.m_from.c_str();
5a618a14
JS
323#else
324 cbOriginator = message.m_from.mb_str();
325 mapiMessage.lpOriginator->lpszName = cbOriginator.data();
326#endif
a23c0047 327 }
decb3a6a
JS
328
329 //Setup the "To" recipients
330 int nRecipIndex = 0;
331 int nToSize = message.m_to.GetCount();
cceb71da
MB
332 int i;
333 for (i=0; i<nToSize; i++)
decb3a6a
JS
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
9409aa35 345 sName = wxString(lpTempRecip->lpszName,*wxConvCurrent);
decb3a6a
JS
346
347 //Don't forget to free up the memory MAPI allocated for us
348 m_data->m_lpfnMAPIFreeBuffer(lpTempRecip);
349 }
5a618a14 350#ifndef UNICODE
decb3a6a 351 recip.lpszName = (LPSTR) sName.c_str();
5a618a14
JS
352#else
353 recip.lpszName = sName.mb_str().release();
354#endif
decb3a6a
JS
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
9409aa35 373 sName = wxString(lpTempRecip->lpszName,*wxConvCurrent);
decb3a6a
JS
374
375 //Don't forget to free up the memory MAPI allocated for us
376 m_data->m_lpfnMAPIFreeBuffer(lpTempRecip);
377 }
5a618a14 378#ifndef UNICODE
decb3a6a 379 recip.lpszName = (LPSTR) sName.c_str();
5a618a14
JS
380#else
381 recip.lpszName = sName.mb_str().release();
382#endif
decb3a6a
JS
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
5a618a14 401 sName = wxString(lpTempRecip->lpszName,wxConvCurrent);
decb3a6a
JS
402
403 //Don't forget to free up the memory MAPI allocated for us
404 m_data->m_lpfnMAPIFreeBuffer(lpTempRecip);
405 }
5a618a14 406#ifndef UNICODE
decb3a6a 407 recip.lpszName = (LPSTR) sName.c_str();
5a618a14
JS
408#else
409 recip.lpszName = sName.mb_str().release();
410#endif
decb3a6a
JS
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];
decb3a6a 433
5a618a14 434#ifndef UNICODE
decb3a6a 435 file.lpszPathName = (LPSTR) sFilename.c_str();
5a618a14
JS
436#else
437 file.lpszPathName = sFilename.mb_str().release();
438#endif
decb3a6a
JS
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];
5a618a14 445#ifndef UNICODE
decb3a6a 446 file.lpszFileName = (LPSTR) sTitle.c_str();
5a618a14
JS
447#else
448 file.lpszFileName = sTitle.mb_str().release();
449#endif
decb3a6a
JS
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 {
9409aa35 463 wxLogDebug(_T("Failed to send mail message, Error:%ld\n"), nError);
decb3a6a
JS
464 m_data->m_nLastError = nError;
465 }
466
467 //Tidy up the Attachements
468 if (nAttachmentSize)
5a618a14
JS
469 {
470#ifdef UNICODE
c59f3b2d 471 for (i = 0;i < nAttachmentSize;i++)
5a618a14
JS
472 {
473 free(mapiMessage.lpFiles[i].lpszPathName);
474 free(mapiMessage.lpFiles[i].lpszFileName);
475 }
476#endif
decb3a6a 477 delete [] mapiMessage.lpFiles;
5a618a14 478 }
decb3a6a 479
a23c0047 480 //Free up the Recipients and Originator memory
5a618a14 481#ifdef UNICODE
c59f3b2d 482 for (i = 0;i < nRecipIndex;i++)
5a618a14
JS
483 free(mapiMessage.lpRecips[i].lpszName);
484#endif
decb3a6a 485 delete [] mapiMessage.lpRecips;
5a618a14 486
a23c0047 487 delete mapiMessage.lpOriginator;
decb3a6a
JS
488
489 return bSuccess;
490}
491
492long wxMapiSession::GetLastError() const
493{
494 return m_data->m_nLastError;
495}
5f109709
MB
496
497#endif // __WXMSW__