1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Simple MAPI classes
4 // Author: PJ Naughter <pjna@naughter.com>
5 // Modified by: Julian Smart
8 // Copyright: (c) PJ Naughter
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "smapi.h"
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
29 #include "wx/string.h"
30 #include "wx/msw/private.h"
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.
37 #include <w32api/mapi.h>
42 #include "wx/net/smapi.h"
44 class WXDLLIMPEXP_NETUTILS wxMapiData
52 m_lpfnMAPILogon
= NULL
;
53 m_lpfnMAPILogoff
= NULL
;
54 m_lpfnMAPISendMail
= NULL
;
55 m_lpfnMAPIResolveName
= NULL
;
56 m_lpfnMAPIFreeBuffer
= NULL
;
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
71 ////////////////////////////////// Implementation /////////////////////////////
73 wxMapiSession::wxMapiSession()
75 m_data
= new wxMapiData
;
80 wxMapiSession::~wxMapiSession()
91 void wxMapiSession::Initialise()
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);
100 //Load up the MAPI dll and get the function pointers we are interested in
101 m_data
->m_hMapi
= ::LoadLibrary(_T("MAPI32.DLL"));
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");
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
)
117 wxLogDebug(_T("Failed to get one of the functions pointer in MAPI32.DLL\n"));
123 wxLogDebug(_T("Mapi is not installed on this computer\n"));
126 void wxMapiSession::Deinitialise()
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
;
141 bool wxMapiSession::Logon(const wxString
& sProfileName
, const wxString
& sPassword
, wxWindow
* pParentWnd
)
143 wxASSERT(MapiInstalled()); //MAPI must be installed
144 wxASSERT(m_data
->m_lpfnMAPILogon
); //Function pointer must be valid
146 //Initialise the function return value
147 bool bSuccess
= FALSE
;
149 //Just in case we are already logged in
152 //Setup the ascii versions of the profile name and password
153 int nProfileLength
= sProfileName
.Length();
155 LPSTR pszProfileName
= NULL
;
156 LPSTR pszPassword
= NULL
;
157 wxCharBuffer
cbProfile(1),cbPassword(1);
161 pszProfileName
= (LPSTR
) sProfileName
.c_str();
162 pszPassword
= (LPSTR
) sPassword
.c_str();
164 cbProfile
= sProfileName
.mb_str();
165 cbPassword
= sPassword
.mb_str();
166 pszProfileName
= cbProfile
.data();
167 pszPassword
= cbPassword
.data();
171 //Setup the flags & UIParam parameters used in the MapiLogon call
174 if (nProfileLength
== 0)
176 //No profile name given, then we must interactively request a profile name
179 nUIParam
= (ULONG
) (HWND
) pParentWnd
->GetHWND();
180 flags
|= MAPI_LOGON_UI
;
184 //No window given, just use the main window of the app as the parent window
185 if (wxTheApp
->GetTopWindow())
187 nUIParam
= (ULONG
) (HWND
) wxTheApp
->GetTopWindow()->GetHWND();
188 flags
|= MAPI_LOGON_UI
;
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
)
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
)
202 m_data
->m_nLastError
= SUCCESS_SUCCESS
;
207 wxLogDebug(_T("Failed to logon to MAPI using a shared session, Error:%ld\n"), nError
);
208 m_data
->m_nLastError
= nError
;
211 else if (nError
== SUCCESS_SUCCESS
)
213 m_data
->m_nLastError
= SUCCESS_SUCCESS
;
220 bool wxMapiSession::LoggedOn() const
222 return (m_data
->m_hSession
!= 0);
225 bool wxMapiSession::MapiInstalled() const
227 return (m_data
->m_hMapi
!= NULL
);
230 bool wxMapiSession::Logoff()
232 wxASSERT(MapiInstalled()); //MAPI must be installed
233 wxASSERT(m_data
->m_lpfnMAPILogoff
); //Function pointer must be valid
235 //Initialise the function return value
236 bool bSuccess
= FALSE
;
238 if (m_data
->m_hSession
)
240 //Call the MAPILogoff function
241 ULONG nError
= m_data
->m_lpfnMAPILogoff(m_data
->m_hSession
, 0, 0, 0);
242 if (nError
!= SUCCESS_SUCCESS
)
244 wxLogDebug(_T("Failed in call to MapiLogoff, Error:%ld"), nError
);
245 m_data
->m_nLastError
= nError
;
250 m_data
->m_nLastError
= SUCCESS_SUCCESS
;
253 m_data
->m_hSession
= 0;
259 bool wxMapiSession::Resolve(const wxString
& sName
, void* lppRecip1
)
261 lpMapiRecipDesc
* lppRecip
= (lpMapiRecipDesc
*) lppRecip1
;
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
268 //Call the MAPIResolveName function
270 LPSTR lpszAsciiName
= (LPSTR
) sName
.c_str();
272 wxCharBuffer
cbName(1);
273 cbName
= sName
.mb_str();
274 LPSTR lpszAsciiName
= cbName
.data();
276 ULONG nError
= m_data
->m_lpfnMAPIResolveName(m_data
->m_hSession
, 0, lpszAsciiName
, 0, 0, lppRecip
);
277 if (nError
!= SUCCESS_SUCCESS
)
279 wxLogDebug(_T("Failed to resolve the name: %s, Error:%ld\n"),
280 sName
.c_str(), nError
);
281 m_data
->m_nLastError
= nError
;
284 return (nError
== SUCCESS_SUCCESS
);
287 bool wxMapiSession::Send(wxMailMessage
& message
)
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
295 //Initialise the function return value
296 bool bSuccess
= FALSE
;
298 //Create the MapiMessage structure to match the message parameter send into us
299 MapiMessage mapiMessage
;
300 ZeroMemory(&mapiMessage
, sizeof(mapiMessage
));
302 mapiMessage
.lpszSubject
= (LPSTR
) message
.m_subject
.c_str();
303 mapiMessage
.lpszNoteText
= (LPSTR
) message
.m_body
.c_str();
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();
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!
314 //Allocate the recipients array
315 mapiMessage
.lpRecips
= new MapiRecipDesc
[mapiMessage
.nRecipCount
];
317 // If we have a 'From' field, use it
318 if (!message
.m_from
.IsEmpty())
320 mapiMessage
.lpOriginator
= new MapiRecipDesc
;
321 ZeroMemory(mapiMessage
.lpOriginator
, sizeof(MapiRecipDesc
));
323 mapiMessage
.lpOriginator
->ulRecipClass
= MAPI_ORIG
;
324 // TODO Do we have to call Resolve?
326 mapiMessage
.lpOriginator
->lpszName
= (LPSTR
) message
.m_from
.c_str();
328 cbOriginator
= message
.m_from
.mb_str();
329 mapiMessage
.lpOriginator
->lpszName
= cbOriginator
.data();
333 //Setup the "To" recipients
335 int nToSize
= message
.m_to
.GetCount();
337 for (i
=0; i
<nToSize
; i
++)
339 MapiRecipDesc
& recip
= mapiMessage
.lpRecips
[nRecipIndex
];
340 ZeroMemory(&recip
, sizeof(MapiRecipDesc
));
341 recip
.ulRecipClass
= MAPI_TO
;
342 wxString
& sName
= message
.m_to
[i
];
344 //Try to resolve the name
345 lpMapiRecipDesc lpTempRecip
;
346 if (Resolve(sName
, (void*) &lpTempRecip
))
348 //Resolve worked, put the resolved name back into the sName
349 sName
= wxString(lpTempRecip
->lpszName
,*wxConvCurrent
);
351 //Don't forget to free up the memory MAPI allocated for us
352 m_data
->m_lpfnMAPIFreeBuffer(lpTempRecip
);
355 recip
.lpszName
= (LPSTR
) sName
.c_str();
357 recip
.lpszName
= sName
.mb_str().release();
363 //Setup the "CC" recipients
364 int nCCSize
= message
.m_cc
.GetCount();
365 for (i
=0; i
<nCCSize
; i
++)
367 MapiRecipDesc
& recip
= mapiMessage
.lpRecips
[nRecipIndex
];
368 ZeroMemory(&recip
, sizeof(MapiRecipDesc
));
369 recip
.ulRecipClass
= MAPI_CC
;
370 wxString
& sName
= message
.m_cc
[i
];
372 //Try to resolve the name
373 lpMapiRecipDesc lpTempRecip
;
374 if (Resolve(sName
, (void*) &lpTempRecip
))
376 //Resolve worked, put the resolved name back into the sName
377 sName
= wxString(lpTempRecip
->lpszName
,*wxConvCurrent
);
379 //Don't forget to free up the memory MAPI allocated for us
380 m_data
->m_lpfnMAPIFreeBuffer(lpTempRecip
);
383 recip
.lpszName
= (LPSTR
) sName
.c_str();
385 recip
.lpszName
= sName
.mb_str().release();
391 //Setup the "BCC" recipients
392 int nBCCSize
= message
.m_bcc
.GetCount();
393 for (i
=0; i
<nBCCSize
; i
++)
395 MapiRecipDesc
& recip
= mapiMessage
.lpRecips
[nRecipIndex
];
396 ZeroMemory(&recip
, sizeof(MapiRecipDesc
));
397 recip
.ulRecipClass
= MAPI_BCC
;
398 wxString
& sName
= message
.m_bcc
[i
];
400 //Try to resolve the name
401 lpMapiRecipDesc lpTempRecip
;
402 if (Resolve(sName
, (void*) &lpTempRecip
))
404 //Resolve worked, put the resolved name back into the sName
405 sName
= wxString(lpTempRecip
->lpszName
,wxConvCurrent
);
407 //Don't forget to free up the memory MAPI allocated for us
408 m_data
->m_lpfnMAPIFreeBuffer(lpTempRecip
);
411 recip
.lpszName
= (LPSTR
) sName
.c_str();
413 recip
.lpszName
= sName
.mb_str().release();
419 //Setup the attachments
420 int nAttachmentSize
= message
.m_attachments
.GetCount();
421 int nTitleSize
= message
.m_attachmentTitles
.GetCount();
424 wxASSERT(nTitleSize
== nAttachmentSize
); //If you are going to set the attachment titles then you must set
425 //the attachment title for each attachment
429 mapiMessage
.nFileCount
= nAttachmentSize
;
430 mapiMessage
.lpFiles
= new MapiFileDesc
[nAttachmentSize
];
431 for (i
=0; i
<nAttachmentSize
; i
++)
433 MapiFileDesc
& file
= mapiMessage
.lpFiles
[i
];
434 ZeroMemory(&file
, sizeof(MapiFileDesc
));
435 file
.nPosition
= 0xFFFFFFFF;
436 wxString
& sFilename
= message
.m_attachments
[i
];
439 file
.lpszPathName
= (LPSTR
) sFilename
.c_str();
441 file
.lpszPathName
= sFilename
.mb_str().release();
443 //file.lpszFileName = file.lpszPathName;
444 file
.lpszFileName
= NULL
;
446 if (nTitleSize
&& !message
.m_attachmentTitles
[i
].IsEmpty())
448 wxString
& sTitle
= message
.m_attachmentTitles
[i
];
450 file
.lpszFileName
= (LPSTR
) sTitle
.c_str();
452 file
.lpszFileName
= sTitle
.mb_str().release();
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
)
463 m_data
->m_nLastError
= SUCCESS_SUCCESS
;
467 wxLogDebug(_T("Failed to send mail message, Error:%ld\n"), nError
);
468 m_data
->m_nLastError
= nError
;
471 //Tidy up the Attachements
475 for (i
= 0;i
< nAttachmentSize
;i
++)
477 free(mapiMessage
.lpFiles
[i
].lpszPathName
);
478 free(mapiMessage
.lpFiles
[i
].lpszFileName
);
481 delete [] mapiMessage
.lpFiles
;
484 //Free up the Recipients and Originator memory
486 for (i
= 0;i
< nRecipIndex
;i
++)
487 free(mapiMessage
.lpRecips
[i
].lpszName
);
489 delete [] mapiMessage
.lpRecips
;
491 delete mapiMessage
.lpOriginator
;
496 long wxMapiSession::GetLastError() const
498 return m_data
->m_nLastError
;