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: smapi.cpp 35650 2005-09-23 12:56:45Z MR $ 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 40class WXDLLIMPEXP_NETUTILS wxMapiData 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(); 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 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 { 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 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 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 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)); 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 492long wxMapiSession::GetLastError() const 493{ 494 return m_data->m_nLastError; 495} 496 497#endif // __WXMSW__ 498