]>
Commit | Line | Data |
---|---|---|
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 | #ifndef WX_PRECOMP | |
24 | #include "wx/wx.h" | |
25 | #endif | |
26 | ||
27 | #include "wx/string.h" | |
28 | #include "wx/msw/private.h" | |
29 | ||
30 | #include <mapi.h> | |
31 | ||
32 | #include "wx/net/smapi.h" | |
33 | ||
34 | class wxMapiData | |
35 | { | |
36 | public: | |
37 | wxMapiData() | |
38 | { | |
39 | m_hSession = 0; | |
40 | m_nLastError = 0; | |
41 | m_hMapi = NULL; | |
42 | m_lpfnMAPILogon = NULL; | |
43 | m_lpfnMAPILogoff = NULL; | |
44 | m_lpfnMAPISendMail = NULL; | |
45 | m_lpfnMAPIResolveName = NULL; | |
46 | m_lpfnMAPIFreeBuffer = NULL; | |
47 | } | |
48 | ||
49 | //Data | |
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 | |
58 | }; | |
59 | ||
60 | ||
61 | ////////////////////////////////// Implementation ///////////////////////////// | |
62 | ||
63 | wxMapiSession::wxMapiSession() | |
64 | { | |
65 | m_data = new wxMapiData; | |
66 | ||
67 | Initialise(); | |
68 | } | |
69 | ||
70 | wxMapiSession::~wxMapiSession() | |
71 | { | |
72 | //Logoff if logged on | |
73 | Logoff(); | |
74 | ||
75 | //Unload the MAPI dll | |
76 | Deinitialise(); | |
77 | ||
78 | delete m_data; | |
79 | } | |
80 | ||
81 | void wxMapiSession::Initialise() | |
82 | { | |
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); | |
87 | ||
88 | if (bMapiInstalled) | |
89 | { | |
90 | //Load up the MAPI dll and get the function pointers we are interested in | |
91 | m_data->m_hMapi = ::LoadLibrary(_T("MAPI32.DLL")); | |
92 | if (m_data->m_hMapi) | |
93 | { | |
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"); | |
99 | ||
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) | |
106 | { | |
107 | wxLogDebug(_T("Failed to get one of the functions pointer in MAPI32.DLL\n")); | |
108 | Deinitialise(); | |
109 | } | |
110 | } | |
111 | } | |
112 | else | |
113 | wxLogDebug(_T("Mapi is not installed on this computer\n")); | |
114 | } | |
115 | ||
116 | void wxMapiSession::Deinitialise() | |
117 | { | |
118 | if (m_data->m_hMapi) | |
119 | { | |
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; | |
128 | } | |
129 | } | |
130 | ||
131 | bool wxMapiSession::Logon(const wxString& sProfileName, const wxString& sPassword, wxWindow* pParentWnd) | |
132 | { | |
133 | wxASSERT(MapiInstalled()); //MAPI must be installed | |
134 | wxASSERT(m_data->m_lpfnMAPILogon); //Function pointer must be valid | |
135 | ||
136 | //Initialise the function return value | |
137 | bool bSuccess = FALSE; | |
138 | ||
139 | //Just in case we are already logged in | |
140 | Logoff(); | |
141 | ||
142 | //Setup the ascii versions of the profile name and password | |
143 | int nProfileLength = sProfileName.Length(); | |
144 | int nPasswordLength = sPassword.Length(); | |
145 | ||
146 | LPSTR pszProfileName = NULL; | |
147 | LPSTR pszPassword = NULL; | |
148 | if (nProfileLength) | |
149 | { | |
150 | // pszProfileName = T2A((LPTSTR) (LPCTSTR) sProfileName); | |
151 | // pszPassword = T2A((LPTSTR) (LPCTSTR) sPassword); | |
152 | pszProfileName = (LPSTR) sProfileName.c_str(); | |
153 | pszPassword = (LPSTR) sPassword.c_str(); | |
154 | } | |
155 | ||
156 | //Setup the flags & UIParam parameters used in the MapiLogon call | |
157 | FLAGS flags = 0; | |
158 | ULONG nUIParam = 0; | |
159 | if (nProfileLength == 0) | |
160 | { | |
161 | //No profile name given, then we must interactively request a profile name | |
162 | if (pParentWnd) | |
163 | { | |
164 | nUIParam = (ULONG) (HWND) pParentWnd->GetHWND(); | |
165 | flags |= MAPI_LOGON_UI; | |
166 | } | |
167 | else | |
168 | { | |
169 | //No window given, just use the main window of the app as the parent window | |
170 | if (wxTheApp->GetTopWindow()) | |
171 | { | |
172 | nUIParam = (ULONG) (HWND) wxTheApp->GetTopWindow()->GetHWND(); | |
173 | flags |= MAPI_LOGON_UI; | |
174 | } | |
175 | } | |
176 | } | |
177 | ||
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) | |
181 | { | |
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) | |
186 | { | |
187 | m_data->m_nLastError = SUCCESS_SUCCESS; | |
188 | bSuccess = TRUE; | |
189 | } | |
190 | else | |
191 | { | |
192 | wxLogDebug(_T("Failed to logon to MAPI using a shared session, Error:%d\n"), nError); | |
193 | m_data->m_nLastError = nError; | |
194 | } | |
195 | } | |
196 | else if (nError == SUCCESS_SUCCESS) | |
197 | { | |
198 | m_data->m_nLastError = SUCCESS_SUCCESS; | |
199 | bSuccess = TRUE; | |
200 | } | |
201 | ||
202 | return bSuccess; | |
203 | } | |
204 | ||
205 | bool wxMapiSession::LoggedOn() const | |
206 | { | |
207 | return (m_data->m_hSession != 0); | |
208 | } | |
209 | ||
210 | bool wxMapiSession::MapiInstalled() const | |
211 | { | |
212 | return (m_data->m_hMapi != NULL); | |
213 | } | |
214 | ||
215 | bool wxMapiSession::Logoff() | |
216 | { | |
217 | wxASSERT(MapiInstalled()); //MAPI must be installed | |
218 | wxASSERT(m_data->m_lpfnMAPILogoff); //Function pointer must be valid | |
219 | ||
220 | //Initialise the function return value | |
221 | bool bSuccess = FALSE; | |
222 | ||
223 | if (m_data->m_hSession) | |
224 | { | |
225 | //Call the MAPILogoff function | |
226 | ULONG nError = m_data->m_lpfnMAPILogoff(m_data->m_hSession, 0, 0, 0); | |
227 | if (nError != SUCCESS_SUCCESS) | |
228 | { | |
229 | wxLogDebug(_T("Failed in call to MapiLogoff, Error:%d"), nError); | |
230 | m_data->m_nLastError = nError; | |
231 | bSuccess = TRUE; | |
232 | } | |
233 | else | |
234 | { | |
235 | m_data->m_nLastError = SUCCESS_SUCCESS; | |
236 | bSuccess = TRUE; | |
237 | } | |
238 | m_data->m_hSession = 0; | |
239 | } | |
240 | ||
241 | return bSuccess; | |
242 | } | |
243 | ||
244 | bool wxMapiSession::Resolve(const wxString& sName, void* lppRecip1) | |
245 | { | |
246 | lpMapiRecipDesc* lppRecip = (lpMapiRecipDesc*) lppRecip1; | |
247 | ||
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 | |
252 | ||
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) | |
258 | { | |
259 | wxLogDebug(_T("Failed to resolve the name: %s, Error:%d\n"), sName, nError); | |
260 | m_data->m_nLastError = nError; | |
261 | } | |
262 | ||
263 | return (nError == SUCCESS_SUCCESS); | |
264 | } | |
265 | ||
266 | bool wxMapiSession::Send(wxMailMessage& message) | |
267 | { | |
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 | |
273 | ||
274 | //Initialise the function return value | |
275 | bool bSuccess = FALSE; | |
276 | ||
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! | |
286 | ||
287 | //Allocate the recipients array | |
288 | mapiMessage.lpRecips = new MapiRecipDesc[mapiMessage.nRecipCount]; | |
289 | ||
290 | // If we have a 'From' field, use it | |
291 | if (!message.m_from.IsEmpty()) | |
292 | { | |
293 | mapiMessage.lpOriginator = new MapiRecipDesc; | |
294 | ZeroMemory(mapiMessage.lpOriginator, sizeof(MapiRecipDesc)); | |
295 | ||
296 | mapiMessage.lpOriginator->ulRecipClass = MAPI_ORIG; | |
297 | // TODO Do we have to call Resolve? | |
298 | mapiMessage.lpOriginator->lpszName = (LPSTR) message.m_from.c_str(); | |
299 | } | |
300 | ||
301 | //Setup the "To" recipients | |
302 | int nRecipIndex = 0; | |
303 | int nToSize = message.m_to.GetCount(); | |
304 | for (int i=0; i<nToSize; i++) | |
305 | { | |
306 | MapiRecipDesc& recip = mapiMessage.lpRecips[nRecipIndex]; | |
307 | ZeroMemory(&recip, sizeof(MapiRecipDesc)); | |
308 | recip.ulRecipClass = MAPI_TO; | |
309 | wxString& sName = message.m_to[i]; | |
310 | ||
311 | //Try to resolve the name | |
312 | lpMapiRecipDesc lpTempRecip; | |
313 | if (Resolve(sName, (void*) &lpTempRecip)) | |
314 | { | |
315 | //Resolve worked, put the resolved name back into the sName | |
316 | sName = lpTempRecip->lpszName; | |
317 | ||
318 | //Don't forget to free up the memory MAPI allocated for us | |
319 | m_data->m_lpfnMAPIFreeBuffer(lpTempRecip); | |
320 | } | |
321 | //recip.lpszName = T2A((LPTSTR) (LPCTSTR) sName); | |
322 | recip.lpszName = (LPSTR) sName.c_str(); | |
323 | ||
324 | ++nRecipIndex; | |
325 | } | |
326 | ||
327 | //Setup the "CC" recipients | |
328 | int nCCSize = message.m_cc.GetCount(); | |
329 | for (i=0; i<nCCSize; i++) | |
330 | { | |
331 | MapiRecipDesc& recip = mapiMessage.lpRecips[nRecipIndex]; | |
332 | ZeroMemory(&recip, sizeof(MapiRecipDesc)); | |
333 | recip.ulRecipClass = MAPI_CC; | |
334 | wxString& sName = message.m_cc[i]; | |
335 | ||
336 | //Try to resolve the name | |
337 | lpMapiRecipDesc lpTempRecip; | |
338 | if (Resolve(sName, (void*) &lpTempRecip)) | |
339 | { | |
340 | //Resolve worked, put the resolved name back into the sName | |
341 | sName = lpTempRecip->lpszName; | |
342 | ||
343 | //Don't forget to free up the memory MAPI allocated for us | |
344 | m_data->m_lpfnMAPIFreeBuffer(lpTempRecip); | |
345 | } | |
346 | //recip.lpszName = T2A((LPTSTR) (LPCTSTR) sName); | |
347 | recip.lpszName = (LPSTR) sName.c_str(); | |
348 | ||
349 | ++nRecipIndex; | |
350 | } | |
351 | ||
352 | //Setup the "BCC" recipients | |
353 | int nBCCSize = message.m_bcc.GetCount(); | |
354 | for (i=0; i<nBCCSize; i++) | |
355 | { | |
356 | MapiRecipDesc& recip = mapiMessage.lpRecips[nRecipIndex]; | |
357 | ZeroMemory(&recip, sizeof(MapiRecipDesc)); | |
358 | recip.ulRecipClass = MAPI_BCC; | |
359 | wxString& sName = message.m_bcc[i]; | |
360 | ||
361 | //Try to resolve the name | |
362 | lpMapiRecipDesc lpTempRecip; | |
363 | if (Resolve(sName, (void*) &lpTempRecip)) | |
364 | { | |
365 | //Resolve worked, put the resolved name back into the sName | |
366 | sName = lpTempRecip->lpszName; | |
367 | ||
368 | //Don't forget to free up the memory MAPI allocated for us | |
369 | m_data->m_lpfnMAPIFreeBuffer(lpTempRecip); | |
370 | } | |
371 | //recip.lpszName = T2A((LPTSTR) (LPCTSTR) sName); | |
372 | recip.lpszName = (LPSTR) sName.c_str(); | |
373 | ||
374 | ++nRecipIndex; | |
375 | } | |
376 | ||
377 | //Setup the attachments | |
378 | int nAttachmentSize = message.m_attachments.GetCount(); | |
379 | int nTitleSize = message.m_attachmentTitles.GetCount(); | |
380 | if (nTitleSize) | |
381 | { | |
382 | wxASSERT(nTitleSize == nAttachmentSize); //If you are going to set the attachment titles then you must set | |
383 | //the attachment title for each attachment | |
384 | } | |
385 | if (nAttachmentSize) | |
386 | { | |
387 | mapiMessage.nFileCount = nAttachmentSize; | |
388 | mapiMessage.lpFiles = new MapiFileDesc[nAttachmentSize]; | |
389 | for (i=0; i<nAttachmentSize; i++) | |
390 | { | |
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); | |
396 | ||
397 | file.lpszPathName = (LPSTR) sFilename.c_str(); | |
398 | //file.lpszFileName = file.lpszPathName; | |
399 | file.lpszFileName = NULL; | |
400 | ||
401 | if (nTitleSize && !message.m_attachmentTitles[i].IsEmpty()) | |
402 | { | |
403 | wxString& sTitle = message.m_attachmentTitles[i]; | |
404 | //file.lpszFileName = T2A((LPTSTR) (LPCTSTR) sTitle); | |
405 | file.lpszFileName = (LPSTR) sTitle.c_str(); | |
406 | } | |
407 | } | |
408 | } | |
409 | ||
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) | |
413 | { | |
414 | bSuccess = TRUE; | |
415 | m_data->m_nLastError = SUCCESS_SUCCESS; | |
416 | } | |
417 | else | |
418 | { | |
419 | wxLogDebug(_T("Failed to send mail message, Error:%d\n"), nError); | |
420 | m_data->m_nLastError = nError; | |
421 | } | |
422 | ||
423 | //Tidy up the Attachements | |
424 | if (nAttachmentSize) | |
425 | delete [] mapiMessage.lpFiles; | |
426 | ||
427 | //Free up the Recipients and Originator memory | |
428 | delete [] mapiMessage.lpRecips; | |
429 | delete mapiMessage.lpOriginator; | |
430 | ||
431 | return bSuccess; | |
432 | } | |
433 | ||
434 | long wxMapiSession::GetLastError() const | |
435 | { | |
436 | return m_data->m_nLastError; | |
437 | } | |
438 |