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"
27 #include "wx/string.h"
28 #include "wx/msw/private.h"
32 #include "wx/net/smapi.h"
42 m_lpfnMAPILogon
= NULL
;
43 m_lpfnMAPILogoff
= NULL
;
44 m_lpfnMAPISendMail
= NULL
;
45 m_lpfnMAPIResolveName
= NULL
;
46 m_lpfnMAPIFreeBuffer
= NULL
;
50 LHANDLE m_hSession
; //Mapi Session handle
51 long m_nLastError
; //Last Mapi error value
52 HINSTANCE m_hMapi
; //Instance handle of the MAPI dll
53 LPMAPILOGON m_lpfnMAPILogon
; //MAPILogon function pointer
54 LPMAPILOGOFF m_lpfnMAPILogoff
; //MAPILogoff function pointer
55 LPMAPISENDMAIL m_lpfnMAPISendMail
; //MAPISendMail function pointer
56 LPMAPIRESOLVENAME m_lpfnMAPIResolveName
; //MAPIResolveName function pointer
57 LPMAPIFREEBUFFER m_lpfnMAPIFreeBuffer
; //MAPIFreeBuffer function pointer
61 ////////////////////////////////// Implementation /////////////////////////////
63 wxMapiSession::wxMapiSession()
65 m_data
= new wxMapiData
;
70 wxMapiSession::~wxMapiSession()
81 void wxMapiSession::Initialise()
83 //First make sure the "WIN.INI" entry for MAPI is present aswell
84 //as the MAPI32 dll being present on the system
85 bool bMapiInstalled
= (GetProfileInt(_T("MAIL"), _T("MAPI"), 0) != 0) &&
86 (SearchPath(NULL
, _T("MAPI32.DLL"), NULL
, 0, NULL
, NULL
) != 0);
90 //Load up the MAPI dll and get the function pointers we are interested in
91 m_data
->m_hMapi
= ::LoadLibrary(_T("MAPI32.DLL"));
94 m_data
->m_lpfnMAPILogon
= (LPMAPILOGON
) GetProcAddress(m_data
->m_hMapi
, "MAPILogon");
95 m_data
->m_lpfnMAPILogoff
= (LPMAPILOGOFF
) GetProcAddress(m_data
->m_hMapi
, "MAPILogoff");
96 m_data
->m_lpfnMAPISendMail
= (LPMAPISENDMAIL
) GetProcAddress(m_data
->m_hMapi
, "MAPISendMail");
97 m_data
->m_lpfnMAPIResolveName
= (LPMAPIRESOLVENAME
) GetProcAddress(m_data
->m_hMapi
, "MAPIResolveName");
98 m_data
->m_lpfnMAPIFreeBuffer
= (LPMAPIFREEBUFFER
) GetProcAddress(m_data
->m_hMapi
, "MAPIFreeBuffer");
100 //If any of the functions are not installed then fail the load
101 if (m_data
->m_lpfnMAPILogon
== NULL
||
102 m_data
->m_lpfnMAPILogoff
== NULL
||
103 m_data
->m_lpfnMAPISendMail
== NULL
||
104 m_data
->m_lpfnMAPIResolveName
== NULL
||
105 m_data
->m_lpfnMAPIFreeBuffer
== NULL
)
107 wxLogDebug(_T("Failed to get one of the functions pointer in MAPI32.DLL\n"));
113 wxLogDebug(_T("Mapi is not installed on this computer\n"));
116 void wxMapiSession::Deinitialise()
120 //Unload the MAPI dll and reset the function pointers to NULL
121 FreeLibrary(m_data
->m_hMapi
);
122 m_data
->m_hMapi
= NULL
;
123 m_data
->m_lpfnMAPILogon
= NULL
;
124 m_data
->m_lpfnMAPILogoff
= NULL
;
125 m_data
->m_lpfnMAPISendMail
= NULL
;
126 m_data
->m_lpfnMAPIResolveName
= NULL
;
127 m_data
->m_lpfnMAPIFreeBuffer
= NULL
;
131 bool wxMapiSession::Logon(const wxString
& sProfileName
, const wxString
& sPassword
, wxWindow
* pParentWnd
)
133 wxASSERT(MapiInstalled()); //MAPI must be installed
134 wxASSERT(m_data
->m_lpfnMAPILogon
); //Function pointer must be valid
136 //Initialise the function return value
137 bool bSuccess
= FALSE
;
139 //Just in case we are already logged in
142 //Setup the ascii versions of the profile name and password
143 int nProfileLength
= sProfileName
.Length();
144 int nPasswordLength
= sPassword
.Length();
146 LPSTR pszProfileName
= NULL
;
147 LPSTR pszPassword
= NULL
;
150 // pszProfileName = T2A((LPTSTR) (LPCTSTR) sProfileName);
151 // pszPassword = T2A((LPTSTR) (LPCTSTR) sPassword);
152 pszProfileName
= (LPSTR
) sProfileName
.c_str();
153 pszPassword
= (LPSTR
) sPassword
.c_str();
156 //Setup the flags & UIParam parameters used in the MapiLogon call
159 if (nProfileLength
== 0)
161 //No profile name given, then we must interactively request a profile name
164 nUIParam
= (ULONG
) (HWND
) pParentWnd
->GetHWND();
165 flags
|= MAPI_LOGON_UI
;
169 //No window given, just use the main window of the app as the parent window
170 if (wxTheApp
->GetTopWindow())
172 nUIParam
= (ULONG
) (HWND
) wxTheApp
->GetTopWindow()->GetHWND();
173 flags
|= MAPI_LOGON_UI
;
178 //First try to acquire a new MAPI session using the supplied settings using the MAPILogon functio
179 ULONG nError
= m_data
->m_lpfnMAPILogon(nUIParam
, pszProfileName
, pszPassword
, flags
| MAPI_NEW_SESSION
, 0, &m_data
->m_hSession
);
180 if (nError
!= SUCCESS_SUCCESS
&& nError
!= MAPI_E_USER_ABORT
)
182 //Failed to create a create mapi session, try to acquire a shared mapi session
183 wxLogDebug(_T("Failed to logon to MAPI using a new session, trying to acquire a shared one\n"));
184 nError
= m_data
->m_lpfnMAPILogon(nUIParam
, NULL
, NULL
, 0, 0, &m_data
->m_hSession
);
185 if (nError
== SUCCESS_SUCCESS
)
187 m_data
->m_nLastError
= SUCCESS_SUCCESS
;
192 wxLogDebug(_T("Failed to logon to MAPI using a shared session, Error:%d\n"), nError
);
193 m_data
->m_nLastError
= nError
;
196 else if (nError
== SUCCESS_SUCCESS
)
198 m_data
->m_nLastError
= SUCCESS_SUCCESS
;
205 bool wxMapiSession::LoggedOn() const
207 return (m_data
->m_hSession
!= 0);
210 bool wxMapiSession::MapiInstalled() const
212 return (m_data
->m_hMapi
!= NULL
);
215 bool wxMapiSession::Logoff()
217 wxASSERT(MapiInstalled()); //MAPI must be installed
218 wxASSERT(m_data
->m_lpfnMAPILogoff
); //Function pointer must be valid
220 //Initialise the function return value
221 bool bSuccess
= FALSE
;
223 if (m_data
->m_hSession
)
225 //Call the MAPILogoff function
226 ULONG nError
= m_data
->m_lpfnMAPILogoff(m_data
->m_hSession
, 0, 0, 0);
227 if (nError
!= SUCCESS_SUCCESS
)
229 wxLogDebug(_T("Failed in call to MapiLogoff, Error:%d"), nError
);
230 m_data
->m_nLastError
= nError
;
235 m_data
->m_nLastError
= SUCCESS_SUCCESS
;
238 m_data
->m_hSession
= 0;
244 bool wxMapiSession::Resolve(const wxString
& sName
, void* lppRecip1
)
246 lpMapiRecipDesc
* lppRecip
= (lpMapiRecipDesc
*) lppRecip1
;
248 wxASSERT(MapiInstalled()); //MAPI must be installed
249 wxASSERT(m_data
->m_lpfnMAPIResolveName
); //Function pointer must be valid
250 wxASSERT(LoggedOn()); //Must be logged on to MAPI
251 wxASSERT(m_data
->m_hSession
); //MAPI session handle must be valid
253 //Call the MAPIResolveName function
254 // LPSTR lpszAsciiName = T2A((LPTSTR) (LPCTSTR) sName);
255 LPSTR lpszAsciiName
= (LPSTR
) sName
.c_str();
256 ULONG nError
= m_data
->m_lpfnMAPIResolveName(m_data
->m_hSession
, 0, lpszAsciiName
, 0, 0, lppRecip
);
257 if (nError
!= SUCCESS_SUCCESS
)
259 wxLogDebug(_T("Failed to resolve the name: %s, Error:%d\n"), sName
, nError
);
260 m_data
->m_nLastError
= nError
;
263 return (nError
== SUCCESS_SUCCESS
);
266 bool wxMapiSession::Send(wxMailMessage
& message
)
268 wxASSERT(MapiInstalled()); //MAPI must be installed
269 wxASSERT(m_data
->m_lpfnMAPISendMail
); //Function pointer must be valid
270 wxASSERT(m_data
->m_lpfnMAPIFreeBuffer
); //Function pointer must be valid
271 wxASSERT(LoggedOn()); //Must be logged on to MAPI
272 wxASSERT(m_data
->m_hSession
); //MAPI session handle must be valid
274 //Initialise the function return value
275 bool bSuccess
= FALSE
;
277 //Create the MapiMessage structure to match the message parameter send into us
278 MapiMessage mapiMessage
;
279 ZeroMemory(&mapiMessage
, sizeof(mapiMessage
));
280 mapiMessage
.lpszSubject
= (LPSTR
) message
.m_subject
.c_str();
281 mapiMessage
.lpszNoteText
= (LPSTR
) message
.m_body
.c_str();
282 // mapiMessage.lpszSubject = T2A((LPTSTR) (LPCTSTR) message.m_subject);
283 // mapiMessage.lpszNoteText = T2A((LPTSTR) (LPCTSTR) message.m_body);
284 mapiMessage
.nRecipCount
= message
.m_to
.GetCount() + message
.m_cc
.GetCount() + message
.m_bcc
.GetCount();
285 wxASSERT(mapiMessage
.nRecipCount
); //Must have at least 1 recipient!
287 //Allocate the recipients array
288 mapiMessage
.lpRecips
= new MapiRecipDesc
[mapiMessage
.nRecipCount
];
290 // If we have a 'From' field, use it
291 if (!message
.m_from
.IsEmpty())
293 mapiMessage
.lpOriginator
= new MapiRecipDesc
;
294 ZeroMemory(mapiMessage
.lpOriginator
, sizeof(MapiRecipDesc
));
296 mapiMessage
.lpOriginator
->ulRecipClass
= MAPI_ORIG
;
297 // TODO Do we have to call Resolve?
298 mapiMessage
.lpOriginator
->lpszName
= (LPSTR
) message
.m_from
.c_str();
301 //Setup the "To" recipients
303 int nToSize
= message
.m_to
.GetCount();
304 for (int i
=0; i
<nToSize
; i
++)
306 MapiRecipDesc
& recip
= mapiMessage
.lpRecips
[nRecipIndex
];
307 ZeroMemory(&recip
, sizeof(MapiRecipDesc
));
308 recip
.ulRecipClass
= MAPI_TO
;
309 wxString
& sName
= message
.m_to
[i
];
311 //Try to resolve the name
312 lpMapiRecipDesc lpTempRecip
;
313 if (Resolve(sName
, (void*) &lpTempRecip
))
315 //Resolve worked, put the resolved name back into the sName
316 sName
= lpTempRecip
->lpszName
;
318 //Don't forget to free up the memory MAPI allocated for us
319 m_data
->m_lpfnMAPIFreeBuffer(lpTempRecip
);
321 //recip.lpszName = T2A((LPTSTR) (LPCTSTR) sName);
322 recip
.lpszName
= (LPSTR
) sName
.c_str();
327 //Setup the "CC" recipients
328 int nCCSize
= message
.m_cc
.GetCount();
329 for (i
=0; i
<nCCSize
; i
++)
331 MapiRecipDesc
& recip
= mapiMessage
.lpRecips
[nRecipIndex
];
332 ZeroMemory(&recip
, sizeof(MapiRecipDesc
));
333 recip
.ulRecipClass
= MAPI_CC
;
334 wxString
& sName
= message
.m_cc
[i
];
336 //Try to resolve the name
337 lpMapiRecipDesc lpTempRecip
;
338 if (Resolve(sName
, (void*) &lpTempRecip
))
340 //Resolve worked, put the resolved name back into the sName
341 sName
= lpTempRecip
->lpszName
;
343 //Don't forget to free up the memory MAPI allocated for us
344 m_data
->m_lpfnMAPIFreeBuffer(lpTempRecip
);
346 //recip.lpszName = T2A((LPTSTR) (LPCTSTR) sName);
347 recip
.lpszName
= (LPSTR
) sName
.c_str();
352 //Setup the "BCC" recipients
353 int nBCCSize
= message
.m_bcc
.GetCount();
354 for (i
=0; i
<nBCCSize
; i
++)
356 MapiRecipDesc
& recip
= mapiMessage
.lpRecips
[nRecipIndex
];
357 ZeroMemory(&recip
, sizeof(MapiRecipDesc
));
358 recip
.ulRecipClass
= MAPI_BCC
;
359 wxString
& sName
= message
.m_bcc
[i
];
361 //Try to resolve the name
362 lpMapiRecipDesc lpTempRecip
;
363 if (Resolve(sName
, (void*) &lpTempRecip
))
365 //Resolve worked, put the resolved name back into the sName
366 sName
= lpTempRecip
->lpszName
;
368 //Don't forget to free up the memory MAPI allocated for us
369 m_data
->m_lpfnMAPIFreeBuffer(lpTempRecip
);
371 //recip.lpszName = T2A((LPTSTR) (LPCTSTR) sName);
372 recip
.lpszName
= (LPSTR
) sName
.c_str();
377 //Setup the attachments
378 int nAttachmentSize
= message
.m_attachments
.GetCount();
379 int nTitleSize
= message
.m_attachmentTitles
.GetCount();
382 wxASSERT(nTitleSize
== nAttachmentSize
); //If you are going to set the attachment titles then you must set
383 //the attachment title for each attachment
387 mapiMessage
.nFileCount
= nAttachmentSize
;
388 mapiMessage
.lpFiles
= new MapiFileDesc
[nAttachmentSize
];
389 for (i
=0; i
<nAttachmentSize
; i
++)
391 MapiFileDesc
& file
= mapiMessage
.lpFiles
[i
];
392 ZeroMemory(&file
, sizeof(MapiFileDesc
));
393 file
.nPosition
= 0xFFFFFFFF;
394 wxString
& sFilename
= message
.m_attachments
[i
];
395 //file.lpszPathName = T2A((LPTSTR) (LPCTSTR) sFilename);
397 file
.lpszPathName
= (LPSTR
) sFilename
.c_str();
398 //file.lpszFileName = file.lpszPathName;
399 file
.lpszFileName
= NULL
;
401 if (nTitleSize
&& !message
.m_attachmentTitles
[i
].IsEmpty())
403 wxString
& sTitle
= message
.m_attachmentTitles
[i
];
404 //file.lpszFileName = T2A((LPTSTR) (LPCTSTR) sTitle);
405 file
.lpszFileName
= (LPSTR
) sTitle
.c_str();
410 //Do the actual send using MAPISendMail
411 ULONG nError
= m_data
->m_lpfnMAPISendMail(m_data
->m_hSession
, 0, &mapiMessage
, MAPI_DIALOG
, 0);
412 if (nError
== SUCCESS_SUCCESS
)
415 m_data
->m_nLastError
= SUCCESS_SUCCESS
;
419 wxLogDebug(_T("Failed to send mail message, Error:%d\n"), nError
);
420 m_data
->m_nLastError
= nError
;
423 //Tidy up the Attachements
425 delete [] mapiMessage
.lpFiles
;
427 //Free up the Recipients and Originator memory
428 delete [] mapiMessage
.lpRecips
;
429 delete mapiMessage
.lpOriginator
;
434 long wxMapiSession::GetLastError() const
436 return m_data
->m_nLastError
;