Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygensendmail.c
Go to the documentation of this file.
00001 /* 00002 * MAPISendMail implementation 00003 * 00004 * Copyright 2005 Hans Leidekker 00005 * Copyright 2009 Owen Rudge for CodeWeavers 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 #include "config.h" 00023 #include "wine/port.h" 00024 00025 #include <stdio.h> 00026 #include <stdarg.h> 00027 00028 #define COBJMACROS 00029 00030 #include "windef.h" 00031 #include "winbase.h" 00032 #include "winerror.h" 00033 #include "winuser.h" 00034 #include "objbase.h" 00035 #include "objidl.h" 00036 #include "mapi.h" 00037 #include "mapix.h" 00038 #include "mapiutil.h" 00039 #include "mapidefs.h" 00040 #include "winreg.h" 00041 #include "shellapi.h" 00042 #include "shlwapi.h" 00043 #include "wine/debug.h" 00044 #include "util.h" 00045 #include "res.h" 00046 00047 WINE_DEFAULT_DEBUG_CHANNEL(mapi); 00048 00049 #define READ_BUF_SIZE 4096 00050 00051 /* 00052 Internal function to send a message via Extended MAPI. Wrapper around the Simple 00053 MAPI function MAPISendMail. 00054 */ 00055 static ULONG sendmail_extended_mapi(LHANDLE mapi_session, ULONG_PTR uiparam, lpMapiMessage message, 00056 FLAGS flags, ULONG reserved) 00057 { 00058 ULONG tags[] = {1, PR_IPM_DRAFTS_ENTRYID}; 00059 ULONG retval = MAPI_E_FAILURE; 00060 IMAPISession *session = NULL; 00061 IMAPITable* msg_table; 00062 LPSRowSet rows = NULL; 00063 IMsgStore* msg_store; 00064 IMAPIFolder* folder = NULL, *draft_folder = NULL; 00065 LPENTRYID entry_id; 00066 LPSPropValue props; 00067 ULONG entry_len; 00068 DWORD obj_type; 00069 IMessage* msg; 00070 ULONG values; 00071 HRESULT ret; 00072 00073 TRACE("Using Extended MAPI wrapper for MAPISendMail\n"); 00074 00075 /* Attempt to log on via Extended MAPI */ 00076 00077 ret = MAPILogonEx(0, NULL, NULL, MAPI_EXTENDED | MAPI_USE_DEFAULT | MAPI_NEW_SESSION, &session); 00078 TRACE("MAPILogonEx: %x\n", ret); 00079 00080 if (ret != S_OK) 00081 { 00082 retval = MAPI_E_LOGIN_FAILURE; 00083 goto cleanup; 00084 } 00085 00086 /* Open the default message store */ 00087 00088 if (IMAPISession_GetMsgStoresTable(session, 0, &msg_table) == S_OK) 00089 { 00090 /* We want the default store */ 00091 SizedSPropTagArray(2, columns) = {2, {PR_ENTRYID, PR_DEFAULT_STORE}}; 00092 00093 /* Set the columns we want */ 00094 if (IMAPITable_SetColumns(msg_table, (LPSPropTagArray) &columns, 0) == S_OK) 00095 { 00096 while (1) 00097 { 00098 if (IMAPITable_QueryRows(msg_table, 1, 0, &rows) != S_OK) 00099 { 00100 MAPIFreeBuffer(rows); 00101 rows = NULL; 00102 } 00103 else if (rows->cRows != 1) 00104 { 00105 FreeProws(rows); 00106 rows = NULL; 00107 } 00108 else 00109 { 00110 /* If it's not the default store, try the next row */ 00111 if (!rows->aRow[0].lpProps[1].Value.b) 00112 { 00113 FreeProws(rows); 00114 continue; 00115 } 00116 } 00117 00118 break; 00119 } 00120 } 00121 00122 IMAPITable_Release(msg_table); 00123 } 00124 00125 /* Did we manage to get the right store? */ 00126 if (!rows) 00127 goto logoff; 00128 00129 /* Open the message store */ 00130 IMAPISession_OpenMsgStore(session, 0, rows->aRow[0].lpProps[0].Value.bin.cb, 00131 (ENTRYID *) rows->aRow[0].lpProps[0].Value.bin.lpb, NULL, 00132 MDB_NO_DIALOG | MAPI_BEST_ACCESS, &msg_store); 00133 00134 /* We don't need this any more */ 00135 FreeProws(rows); 00136 00137 /* First open the inbox, from which the drafts folder can be opened */ 00138 if (IMsgStore_GetReceiveFolder(msg_store, NULL, 0, &entry_len, &entry_id, NULL) == S_OK) 00139 { 00140 IMsgStore_OpenEntry(msg_store, entry_len, entry_id, NULL, 0, &obj_type, (LPUNKNOWN*) &folder); 00141 MAPIFreeBuffer(entry_id); 00142 } 00143 00144 /* Open the drafts folder, or failing that, try asking the message store for the outbox */ 00145 if ((folder == NULL) || ((ret = IMAPIFolder_GetProps(folder, (LPSPropTagArray) tags, 0, &values, &props)) != S_OK)) 00146 { 00147 TRACE("Unable to open Drafts folder; opening Outbox instead\n"); 00148 tags[1] = PR_IPM_OUTBOX_ENTRYID; 00149 ret = IMsgStore_GetProps(msg_store, (LPSPropTagArray) tags, 0, &values, &props); 00150 } 00151 00152 if (ret != S_OK) 00153 goto logoff; 00154 00155 IMsgStore_OpenEntry(msg_store, props[0].Value.bin.cb, (LPENTRYID) props[0].Value.bin.lpb, 00156 NULL, MAPI_MODIFY, &obj_type, (LPUNKNOWN *) &draft_folder); 00157 00158 /* Create a new message */ 00159 if (IMAPIFolder_CreateMessage(draft_folder, NULL, 0, &msg) == S_OK) 00160 { 00161 ULONG token; 00162 SPropValue p; 00163 00164 /* Define message properties */ 00165 p.ulPropTag = PR_MESSAGE_FLAGS; 00166 p.Value.l = MSGFLAG_FROMME | MSGFLAG_UNSENT; 00167 00168 IMessage_SetProps(msg, 1, &p, NULL); 00169 00170 p.ulPropTag = PR_SENTMAIL_ENTRYID; 00171 p.Value.bin.cb = props[0].Value.bin.cb; 00172 p.Value.bin.lpb = props[0].Value.bin.lpb; 00173 IMessage_SetProps(msg, 1,&p, NULL); 00174 00175 /* Set message subject */ 00176 if (message->lpszSubject) 00177 { 00178 p.ulPropTag = PR_SUBJECT_A; 00179 p.Value.lpszA = message->lpszSubject; 00180 IMessage_SetProps(msg, 1, &p, NULL); 00181 } 00182 00183 /* Set message body */ 00184 if (message->lpszNoteText) 00185 { 00186 LPSTREAM stream = NULL; 00187 00188 if (IMessage_OpenProperty(msg, PR_BODY_A, &IID_IStream, 0, 00189 MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN*) &stream) == S_OK) 00190 { 00191 IStream_Write(stream, message->lpszNoteText, strlen(message->lpszNoteText)+1, NULL); 00192 IStream_Release(stream); 00193 } 00194 } 00195 00196 /* Add message attachments */ 00197 if (message->nFileCount > 0) 00198 { 00199 ULONG num_attach = 0; 00200 int i, j; 00201 00202 for (i = 0; i < message->nFileCount; i++) 00203 { 00204 IAttach* attachment = NULL; 00205 SPropValue prop[4]; 00206 LPCSTR filename; 00207 HANDLE file; 00208 00209 if (!message->lpFiles[i].lpszPathName) 00210 continue; 00211 00212 /* Open the attachment for reading */ 00213 file = CreateFileA(message->lpFiles[i].lpszPathName, GENERIC_READ, FILE_SHARE_READ, 00214 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 00215 00216 if (file == INVALID_HANDLE_VALUE) 00217 continue; 00218 00219 /* Check if a display filename has been given; if not, get one ourselves from path name */ 00220 filename = message->lpFiles[i].lpszFileName; 00221 00222 if (!filename) 00223 { 00224 filename = message->lpFiles[i].lpszPathName; 00225 00226 for (j = strlen(message->lpFiles[i].lpszPathName)-1; j >= 0; j--) 00227 { 00228 if (message->lpFiles[i].lpszPathName[i] == '\\' || 00229 message->lpFiles[i].lpszPathName[i] == '/') 00230 { 00231 filename = &message->lpFiles[i].lpszPathName[i+1]; 00232 break; 00233 } 00234 } 00235 } 00236 00237 TRACE("Attachment %d path: '%s'; filename: '%s'\n", i, debugstr_a(message->lpFiles[i].lpszPathName), 00238 debugstr_a(filename)); 00239 00240 /* Create the attachment */ 00241 if (IMessage_CreateAttach(msg, NULL, 0, &num_attach, &attachment) != S_OK) 00242 { 00243 TRACE("Unable to create attachment\n"); 00244 CloseHandle(file); 00245 continue; 00246 } 00247 00248 /* Set the attachment properties */ 00249 ZeroMemory(prop, sizeof(prop)); 00250 00251 prop[0].ulPropTag = PR_ATTACH_METHOD; 00252 prop[0].Value.ul = ATTACH_BY_VALUE; 00253 prop[1].ulPropTag = PR_ATTACH_LONG_FILENAME_A; 00254 prop[1].Value.lpszA = (LPSTR) filename; 00255 prop[2].ulPropTag = PR_ATTACH_FILENAME_A; 00256 prop[2].Value.lpszA = (LPSTR) filename; 00257 prop[3].ulPropTag = PR_RENDERING_POSITION; 00258 prop[3].Value.l = -1; 00259 00260 if (IAttach_SetProps(attachment, 4, prop, NULL) == S_OK) 00261 { 00262 LPSTREAM stream = NULL; 00263 00264 if (IAttach_OpenProperty(attachment, PR_ATTACH_DATA_BIN, &IID_IStream, 0, 00265 MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN*) &stream) == S_OK) 00266 { 00267 BYTE data[READ_BUF_SIZE]; 00268 DWORD size = 0, read, written; 00269 00270 while (ReadFile(file, data, READ_BUF_SIZE, &read, NULL) && (read != 0)) 00271 { 00272 IStream_Write(stream, data, read, &written); 00273 size += read; 00274 } 00275 00276 TRACE("%d bytes read, %d bytes written of attachment\n", read, written); 00277 00278 IStream_Commit(stream, STGC_DEFAULT); 00279 IStream_Release(stream); 00280 00281 prop[0].ulPropTag = PR_ATTACH_SIZE; 00282 prop[0].Value.ul = size; 00283 IAttach_SetProps(attachment, 1, prop, NULL); 00284 00285 IAttach_SaveChanges(attachment, KEEP_OPEN_READONLY); 00286 num_attach++; 00287 } 00288 } 00289 00290 CloseHandle(file); 00291 IAttach_Release(attachment); 00292 } 00293 } 00294 00295 IMessage_SaveChanges(msg, KEEP_OPEN_READWRITE); 00296 00297 /* Prepare the message form */ 00298 00299 if (IMAPISession_PrepareForm(session, NULL, msg, &token) == S_OK) 00300 { 00301 ULONG access = 0, status = 0, flags = 0, pc = 0; 00302 ULONG pT[2] = {1, PR_MSG_STATUS}; 00303 00304 /* Retrieve message status, flags, access rights and class */ 00305 00306 if (IMessage_GetProps(msg, (LPSPropTagArray) pT, 0, &pc, &props) == S_OK) 00307 { 00308 status = props->Value.ul; 00309 MAPIFreeBuffer(props); 00310 } 00311 00312 pT[1] = PR_MESSAGE_FLAGS; 00313 00314 if (IMessage_GetProps(msg, (LPSPropTagArray) pT, 0, &pc, &props) == S_OK) 00315 { 00316 flags = props->Value.ul; 00317 MAPIFreeBuffer(props); 00318 } 00319 00320 pT[1] = PR_ACCESS; 00321 00322 if (IMessage_GetProps(msg, (LPSPropTagArray) pT, 0, &pc, &props) == S_OK) 00323 { 00324 access = props->Value.ul; 00325 MAPIFreeBuffer(props); 00326 } 00327 00328 pT[1] = PR_MESSAGE_CLASS_A; 00329 00330 if (IMessage_GetProps(msg, (LPSPropTagArray) pT, 0, &pc, &props) == S_OK) 00331 { 00332 /* Show the message form (edit window) */ 00333 00334 ret = IMAPISession_ShowForm(session, 0, msg_store, draft_folder, NULL, 00335 token, NULL, 0, status, flags, access, 00336 props->Value.lpszA); 00337 00338 switch (ret) 00339 { 00340 case S_OK: 00341 retval = SUCCESS_SUCCESS; 00342 break; 00343 00344 case MAPI_E_USER_CANCEL: 00345 retval = MAPI_E_USER_ABORT; 00346 break; 00347 00348 default: 00349 TRACE("ShowForm failure: %x\n", ret); 00350 break; 00351 } 00352 } 00353 } 00354 00355 IMessage_Release(msg); 00356 } 00357 00358 /* Free up the resources we've used */ 00359 IMAPIFolder_Release(draft_folder); 00360 if (folder) IMAPIFolder_Release(folder); 00361 IMsgStore_Release(msg_store); 00362 00363 logoff: ; 00364 IMAPISession_Logoff(session, 0, 0, 0); 00365 IMAPISession_Release(session); 00366 00367 cleanup: ; 00368 MAPIUninitialize(); 00369 return retval; 00370 } 00371 00372 /************************************************************************** 00373 * MAPISendMail (MAPI32.211) 00374 * 00375 * Send a mail. 00376 * 00377 * PARAMS 00378 * session [I] Handle to a MAPI session. 00379 * uiparam [I] Parent window handle. 00380 * message [I] Pointer to a MAPIMessage structure. 00381 * flags [I] Flags. 00382 * reserved [I] Reserved, pass 0. 00383 * 00384 * RETURNS 00385 * Success: SUCCESS_SUCCESS 00386 * Failure: MAPI_E_FAILURE 00387 * 00388 */ 00389 ULONG WINAPI MAPISendMail( LHANDLE session, ULONG_PTR uiparam, 00390 lpMapiMessage message, FLAGS flags, ULONG reserved ) 00391 { 00392 WCHAR msg_title[READ_BUF_SIZE], error_msg[READ_BUF_SIZE]; 00393 00394 /* Check to see if we have a Simple MAPI provider loaded */ 00395 if (mapiFunctions.MAPISendMail) 00396 return mapiFunctions.MAPISendMail(session, uiparam, message, flags, reserved); 00397 00398 /* Check if we have an Extended MAPI provider - if so, use our wrapper */ 00399 if (MAPIInitialize(NULL) == S_OK) 00400 return sendmail_extended_mapi(session, uiparam, message, flags, reserved); 00401 00402 /* Display an error message since we apparently have no mail clients */ 00403 LoadStringW(hInstMAPI32, IDS_NO_MAPI_CLIENT, error_msg, sizeof(error_msg) / sizeof(WCHAR)); 00404 LoadStringW(hInstMAPI32, IDS_SEND_MAIL, msg_title, sizeof(msg_title) / sizeof(WCHAR)); 00405 00406 MessageBoxW((HWND) uiparam, error_msg, msg_title, MB_ICONEXCLAMATION); 00407 00408 return MAPI_E_NOT_SUPPORTED; 00409 } 00410 00411 ULONG WINAPI MAPISendDocuments(ULONG_PTR uiparam, LPSTR delim, LPSTR paths, 00412 LPSTR filenames, ULONG reserved) 00413 { 00414 if (mapiFunctions.MAPISendDocuments) 00415 return mapiFunctions.MAPISendDocuments(uiparam, delim, paths, filenames, reserved); 00416 00417 return MAPI_E_NOT_SUPPORTED; 00418 } Generated on Sun May 27 2012 04:24:38 for ReactOS by
1.7.6.1
|