43d68ce140e4bd3975ddd22cbdeaeb535f953690
[reactos.git] / reactos / dll / win32 / mapi32 / sendmail.c
1 /*
2 * MAPISendMail implementation
3 *
4 * Copyright 2005 Hans Leidekker
5 * Copyright 2009 Owen Rudge for CodeWeavers
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #define WIN32_NO_STATUS
23 #define _INC_WINDOWS
24 #define COM_NO_WINDOWS_H
25
26 #include <config.h>
27 //#include "wine/port.h"
28
29 //#include <stdio.h>
30 #include <stdarg.h>
31
32 #define COBJMACROS
33
34 #include <windef.h>
35 #include <winbase.h>
36 //#include "winerror.h"
37 #include <winuser.h>
38 //#include "objbase.h"
39 //#include "objidl.h"
40 //#include "mapi.h"
41 //#include "mapix.h"
42 #include <mapiutil.h>
43 //#include "mapidefs.h"
44 //#include "winreg.h"
45 //#include "shellapi.h"
46 //#include "shlwapi.h"
47 #include <wine/debug.h>
48 #include <wine/unicode.h>
49 #include "util.h"
50 #include "res.h"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(mapi);
53
54 #define READ_BUF_SIZE 4096
55
56 #define STORE_UNICODE_OK 0x00040000
57
58 static LPSTR convert_from_unicode(LPCWSTR wstr)
59 {
60 LPSTR str;
61 DWORD len;
62
63 if (!wstr)
64 return NULL;
65
66 len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
67 str = HeapAlloc(GetProcessHeap(), 0, len);
68 WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);
69
70 return str;
71 }
72
73 static LPWSTR convert_to_unicode(LPSTR str)
74 {
75 LPWSTR wstr;
76 DWORD len;
77
78 if (!str)
79 return NULL;
80
81 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
82 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
83 MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, len);
84
85 return wstr;
86 }
87
88 /*
89 Internal function to send a message via Extended MAPI. Wrapper around the Simple
90 MAPI function MAPISendMail.
91 */
92 static ULONG sendmail_extended_mapi(LHANDLE mapi_session, ULONG_PTR uiparam, lpMapiMessageW message,
93 FLAGS flags)
94 {
95 ULONG tags[] = {1, 0};
96 char *subjectA = NULL, *bodyA = NULL;
97 ULONG retval = MAPI_E_FAILURE;
98 IMAPISession *session = NULL;
99 BOOL unicode_aware = FALSE;
100 IMAPITable* msg_table;
101 LPSRowSet rows = NULL;
102 IMsgStore* msg_store;
103 IMAPIFolder* folder = NULL, *draft_folder = NULL;
104 LPENTRYID entry_id;
105 LPSPropValue props;
106 ULONG entry_len;
107 DWORD obj_type;
108 IMessage* msg;
109 ULONG values;
110 HRESULT ret;
111
112 TRACE("Using Extended MAPI wrapper for MAPISendMail\n");
113
114 /* Attempt to log on via Extended MAPI */
115
116 ret = MAPILogonEx(0, NULL, NULL, MAPI_EXTENDED | MAPI_USE_DEFAULT | MAPI_NEW_SESSION, &session);
117 TRACE("MAPILogonEx: %x\n", ret);
118
119 if (ret != S_OK)
120 {
121 retval = MAPI_E_LOGIN_FAILURE;
122 goto cleanup;
123 }
124
125 /* Open the default message store */
126
127 if (IMAPISession_GetMsgStoresTable(session, 0, &msg_table) == S_OK)
128 {
129 /* We want the default store */
130 SizedSPropTagArray(2, columns) = {2, {PR_ENTRYID, PR_DEFAULT_STORE}};
131
132 /* Set the columns we want */
133 if (IMAPITable_SetColumns(msg_table, (LPSPropTagArray) &columns, 0) == S_OK)
134 {
135 while (1)
136 {
137 if (IMAPITable_QueryRows(msg_table, 1, 0, &rows) != S_OK)
138 {
139 MAPIFreeBuffer(rows);
140 rows = NULL;
141 }
142 else if (rows->cRows != 1)
143 {
144 FreeProws(rows);
145 rows = NULL;
146 }
147 else
148 {
149 /* If it's not the default store, try the next row */
150 if (!rows->aRow[0].lpProps[1].Value.b)
151 {
152 FreeProws(rows);
153 continue;
154 }
155 }
156
157 break;
158 }
159 }
160
161 IMAPITable_Release(msg_table);
162 }
163
164 /* Did we manage to get the right store? */
165 if (!rows)
166 goto logoff;
167
168 /* Open the message store */
169 IMAPISession_OpenMsgStore(session, 0, rows->aRow[0].lpProps[0].Value.bin.cb,
170 (ENTRYID *) rows->aRow[0].lpProps[0].Value.bin.lpb, NULL,
171 MDB_NO_DIALOG | MAPI_BEST_ACCESS, &msg_store);
172
173 /* We don't need this any more */
174 FreeProws(rows);
175
176 /* Check if the message store supports Unicode */
177 tags[1] = PR_STORE_SUPPORT_MASK;
178 ret = IMsgStore_GetProps(msg_store, (LPSPropTagArray) tags, 0, &values, &props);
179
180 if ((ret == S_OK) && (props[0].Value.l & STORE_UNICODE_OK))
181 unicode_aware = TRUE;
182 else
183 {
184 /* Don't convert to ANSI */
185 if (flags & MAPI_FORCE_UNICODE)
186 {
187 WARN("No Unicode-capable mail client, and MAPI_FORCE_UNICODE is specified. MAPISendMail failed.\n");
188 retval = MAPI_E_UNICODE_NOT_SUPPORTED;
189 IMsgStore_Release(msg_store);
190 goto logoff;
191 }
192 }
193
194 /* First open the inbox, from which the drafts folder can be opened */
195 if (IMsgStore_GetReceiveFolder(msg_store, NULL, 0, &entry_len, &entry_id, NULL) == S_OK)
196 {
197 IMsgStore_OpenEntry(msg_store, entry_len, entry_id, NULL, 0, &obj_type, (LPUNKNOWN*) &folder);
198 MAPIFreeBuffer(entry_id);
199 }
200
201 tags[1] = PR_IPM_DRAFTS_ENTRYID;
202
203 /* Open the drafts folder, or failing that, try asking the message store for the outbox */
204 if ((folder == NULL) || ((ret = IMAPIFolder_GetProps(folder, (LPSPropTagArray) tags, 0, &values, &props)) != S_OK))
205 {
206 TRACE("Unable to open Drafts folder; opening Outbox instead\n");
207 tags[1] = PR_IPM_OUTBOX_ENTRYID;
208 ret = IMsgStore_GetProps(msg_store, (LPSPropTagArray) tags, 0, &values, &props);
209 }
210
211 if (ret != S_OK)
212 goto logoff;
213
214 IMsgStore_OpenEntry(msg_store, props[0].Value.bin.cb, (LPENTRYID) props[0].Value.bin.lpb,
215 NULL, MAPI_MODIFY, &obj_type, (LPUNKNOWN *) &draft_folder);
216
217 /* Create a new message */
218 if (IMAPIFolder_CreateMessage(draft_folder, NULL, 0, &msg) == S_OK)
219 {
220 ULONG token;
221 SPropValue p;
222
223 /* Define message properties */
224 p.ulPropTag = PR_MESSAGE_FLAGS;
225 p.Value.l = MSGFLAG_FROMME | MSGFLAG_UNSENT;
226
227 IMessage_SetProps(msg, 1, &p, NULL);
228
229 p.ulPropTag = PR_SENTMAIL_ENTRYID;
230 p.Value.bin.cb = props[0].Value.bin.cb;
231 p.Value.bin.lpb = props[0].Value.bin.lpb;
232 IMessage_SetProps(msg, 1,&p, NULL);
233
234 /* Set message subject */
235 if (message->lpszSubject)
236 {
237 if (unicode_aware)
238 {
239 p.ulPropTag = PR_SUBJECT_W;
240 p.Value.lpszW = message->lpszSubject;
241 }
242 else
243 {
244 subjectA = convert_from_unicode(message->lpszSubject);
245
246 p.ulPropTag = PR_SUBJECT_A;
247 p.Value.lpszA = subjectA;
248 }
249
250 IMessage_SetProps(msg, 1, &p, NULL);
251 }
252
253 /* Set message body */
254 if (message->lpszNoteText)
255 {
256 LPSTREAM stream = NULL;
257
258 if (IMessage_OpenProperty(msg, unicode_aware ? PR_BODY_W : PR_BODY_A, &IID_IStream, 0,
259 MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN*) &stream) == S_OK)
260 {
261 if (unicode_aware)
262 IStream_Write(stream, message->lpszNoteText, (lstrlenW(message->lpszNoteText)+1) * sizeof(WCHAR), NULL);
263 else
264 {
265 bodyA = convert_from_unicode(message->lpszNoteText);
266 IStream_Write(stream, bodyA, strlen(bodyA)+1, NULL);
267 }
268
269 IStream_Release(stream);
270 }
271 }
272
273 /* Add message attachments */
274 if (message->nFileCount > 0)
275 {
276 ULONG num_attach = 0;
277 unsigned int i;
278
279 for (i = 0; i < message->nFileCount; i++)
280 {
281 IAttach* attachment = NULL;
282 char *filenameA = NULL;
283 SPropValue prop[4];
284 LPCWSTR filename;
285 HANDLE file;
286
287 if (!message->lpFiles[i].lpszPathName)
288 continue;
289
290 /* Open the attachment for reading */
291 file = CreateFileW(message->lpFiles[i].lpszPathName, GENERIC_READ, FILE_SHARE_READ,
292 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
293
294 if (file == INVALID_HANDLE_VALUE)
295 continue;
296
297 /* Check if a display filename has been given; if not, get one ourselves from path name */
298 filename = message->lpFiles[i].lpszFileName;
299
300 if (!filename)
301 {
302 int j;
303
304 filename = message->lpFiles[i].lpszPathName;
305
306 for (j = lstrlenW(message->lpFiles[i].lpszPathName)-1; j >= 0; j--)
307 {
308 if (message->lpFiles[i].lpszPathName[i] == '\\' ||
309 message->lpFiles[i].lpszPathName[i] == '/')
310 {
311 filename = &message->lpFiles[i].lpszPathName[i+1];
312 break;
313 }
314 }
315 }
316
317 TRACE("Attachment %u path: '%s'; filename: '%s'\n", i, debugstr_w(message->lpFiles[i].lpszPathName),
318 debugstr_w(filename));
319
320 /* Create the attachment */
321 if (IMessage_CreateAttach(msg, NULL, 0, &num_attach, &attachment) != S_OK)
322 {
323 TRACE("Unable to create attachment\n");
324 CloseHandle(file);
325 continue;
326 }
327
328 /* Set the attachment properties */
329 ZeroMemory(prop, sizeof(prop));
330
331 prop[0].ulPropTag = PR_ATTACH_METHOD;
332 prop[0].Value.ul = ATTACH_BY_VALUE;
333
334 if (unicode_aware)
335 {
336 prop[1].ulPropTag = PR_ATTACH_LONG_FILENAME_W;
337 prop[1].Value.lpszW = (LPWSTR) filename;
338 prop[2].ulPropTag = PR_ATTACH_FILENAME_W;
339 prop[2].Value.lpszW = (LPWSTR) filename;
340 }
341 else
342 {
343 filenameA = convert_from_unicode(filename);
344
345 prop[1].ulPropTag = PR_ATTACH_LONG_FILENAME_A;
346 prop[1].Value.lpszA = (LPSTR) filenameA;
347 prop[2].ulPropTag = PR_ATTACH_FILENAME_A;
348 prop[2].Value.lpszA = (LPSTR) filenameA;
349
350 }
351
352 prop[3].ulPropTag = PR_RENDERING_POSITION;
353 prop[3].Value.l = -1;
354
355 if (IAttach_SetProps(attachment, 4, prop, NULL) == S_OK)
356 {
357 LPSTREAM stream = NULL;
358
359 if (IAttach_OpenProperty(attachment, PR_ATTACH_DATA_BIN, &IID_IStream, 0,
360 MAPI_MODIFY | MAPI_CREATE, (LPUNKNOWN*) &stream) == S_OK)
361 {
362 BYTE data[READ_BUF_SIZE];
363 DWORD size = 0, read, written;
364
365 while (ReadFile(file, data, READ_BUF_SIZE, &read, NULL) && (read != 0))
366 {
367 IStream_Write(stream, data, read, &written);
368 size += read;
369 }
370
371 TRACE("%d bytes written of attachment\n", size);
372
373 IStream_Commit(stream, STGC_DEFAULT);
374 IStream_Release(stream);
375
376 prop[0].ulPropTag = PR_ATTACH_SIZE;
377 prop[0].Value.ul = size;
378 IAttach_SetProps(attachment, 1, prop, NULL);
379
380 IAttach_SaveChanges(attachment, KEEP_OPEN_READONLY);
381 num_attach++;
382 }
383 }
384
385 CloseHandle(file);
386 IAttach_Release(attachment);
387
388 HeapFree(GetProcessHeap(), 0, filenameA);
389 }
390 }
391
392 IMessage_SaveChanges(msg, KEEP_OPEN_READWRITE);
393
394 /* Prepare the message form */
395
396 if (IMAPISession_PrepareForm(session, NULL, msg, &token) == S_OK)
397 {
398 ULONG access = 0, status = 0, message_flags = 0, pc = 0;
399 ULONG pT[2] = {1, PR_MSG_STATUS};
400
401 /* Retrieve message status, flags, access rights and class */
402
403 if (IMessage_GetProps(msg, (LPSPropTagArray) pT, 0, &pc, &props) == S_OK)
404 {
405 status = props->Value.ul;
406 MAPIFreeBuffer(props);
407 }
408
409 pT[1] = PR_MESSAGE_FLAGS;
410
411 if (IMessage_GetProps(msg, (LPSPropTagArray) pT, 0, &pc, &props) == S_OK)
412 {
413 message_flags = props->Value.ul;
414 MAPIFreeBuffer(props);
415 }
416
417 pT[1] = PR_ACCESS;
418
419 if (IMessage_GetProps(msg, (LPSPropTagArray) pT, 0, &pc, &props) == S_OK)
420 {
421 access = props->Value.ul;
422 MAPIFreeBuffer(props);
423 }
424
425 pT[1] = PR_MESSAGE_CLASS_A;
426
427 if (IMessage_GetProps(msg, (LPSPropTagArray) pT, 0, &pc, &props) == S_OK)
428 {
429 /* Show the message form (edit window) */
430
431 ret = IMAPISession_ShowForm(session, 0, msg_store, draft_folder, NULL,
432 token, NULL, 0, status, message_flags, access,
433 props->Value.lpszA);
434
435 switch (ret)
436 {
437 case S_OK:
438 retval = SUCCESS_SUCCESS;
439 break;
440
441 case MAPI_E_USER_CANCEL:
442 retval = MAPI_E_USER_ABORT;
443 break;
444
445 default:
446 TRACE("ShowForm failure: %x\n", ret);
447 break;
448 }
449 }
450 }
451
452 IMessage_Release(msg);
453 }
454
455 /* Free up the resources we've used */
456 IMAPIFolder_Release(draft_folder);
457 if (folder) IMAPIFolder_Release(folder);
458 IMsgStore_Release(msg_store);
459
460 HeapFree(GetProcessHeap(), 0, subjectA);
461 HeapFree(GetProcessHeap(), 0, bodyA);
462
463 logoff: ;
464 IMAPISession_Logoff(session, 0, 0, 0);
465 IMAPISession_Release(session);
466
467 cleanup: ;
468 MAPIUninitialize();
469 return retval;
470 }
471
472 /**************************************************************************
473 * MAPISendMail (MAPI32.211)
474 *
475 * Send a mail.
476 *
477 * PARAMS
478 * session [I] Handle to a MAPI session.
479 * uiparam [I] Parent window handle.
480 * message [I] Pointer to a MAPIMessage structure.
481 * flags [I] Flags.
482 * reserved [I] Reserved, pass 0.
483 *
484 * RETURNS
485 * Success: SUCCESS_SUCCESS
486 * Failure: MAPI_E_FAILURE
487 *
488 */
489 ULONG WINAPI MAPISendMail( LHANDLE session, ULONG_PTR uiparam,
490 lpMapiMessage message, FLAGS flags, ULONG reserved )
491 {
492 WCHAR msg_title[READ_BUF_SIZE], error_msg[READ_BUF_SIZE];
493
494 /* Check to see if we have a Simple MAPI provider loaded */
495 if (mapiFunctions.MAPISendMail)
496 return mapiFunctions.MAPISendMail(session, uiparam, message, flags, reserved);
497
498 /* Check if we have an Extended MAPI provider - if so, use our wrapper */
499 if (MAPIInitialize(NULL) == S_OK)
500 {
501 MapiMessageW messageW;
502 ULONG ret;
503
504 ZeroMemory(&messageW, sizeof(MapiMessageW));
505
506 /* Convert the entries we need to Unicode */
507 messageW.lpszSubject = convert_to_unicode(message->lpszSubject);
508 messageW.lpszNoteText = convert_to_unicode(message->lpszNoteText);
509 messageW.nFileCount = message->nFileCount;
510
511 if (message->nFileCount && message->lpFiles)
512 {
513 lpMapiFileDescW filesW;
514 unsigned int i;
515
516 filesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MapiFileDescW) * message->nFileCount);
517
518 for (i = 0; i < message->nFileCount; i++)
519 {
520 filesW[i].lpszPathName = convert_to_unicode(message->lpFiles[i].lpszPathName);
521 filesW[i].lpszFileName = convert_to_unicode(message->lpFiles[i].lpszFileName);
522 }
523
524 messageW.lpFiles = filesW;
525 }
526
527 ret = sendmail_extended_mapi(session, uiparam, &messageW, flags);
528
529 /* Now free everything we allocated */
530 if (message->nFileCount && message->lpFiles)
531 {
532 unsigned int i;
533
534 for (i = 0; i < message->nFileCount; i++)
535 {
536 HeapFree(GetProcessHeap(), 0, messageW.lpFiles[i].lpszPathName);
537 HeapFree(GetProcessHeap(), 0, messageW.lpFiles[i].lpszFileName);
538 }
539
540 HeapFree(GetProcessHeap(), 0, messageW.lpFiles);
541 }
542
543 HeapFree(GetProcessHeap(), 0, messageW.lpszSubject);
544 HeapFree(GetProcessHeap(), 0, messageW.lpszNoteText);
545
546 return ret;
547 }
548
549 /* Display an error message since we apparently have no mail clients */
550 LoadStringW(hInstMAPI32, IDS_NO_MAPI_CLIENT, error_msg, sizeof(error_msg) / sizeof(WCHAR));
551 LoadStringW(hInstMAPI32, IDS_SEND_MAIL, msg_title, sizeof(msg_title) / sizeof(WCHAR));
552
553 MessageBoxW((HWND) uiparam, error_msg, msg_title, MB_ICONEXCLAMATION);
554
555 return MAPI_E_NOT_SUPPORTED;
556 }
557
558 static lpMapiRecipDesc convert_recipient_from_unicode(lpMapiRecipDescW recipW, lpMapiRecipDesc dest)
559 {
560 lpMapiRecipDesc ret;
561
562 if (!recipW)
563 return NULL;
564
565 if (dest)
566 ret = dest;
567 else
568 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MapiRecipDesc));
569
570 ret->ulRecipClass = recipW->ulRecipClass;
571 ret->lpszName = convert_from_unicode(recipW->lpszName);
572 ret->lpszAddress = convert_from_unicode(recipW->lpszAddress);
573 ret->ulEIDSize = recipW->ulEIDSize;
574 ret->lpEntryID = recipW->lpEntryID;
575
576 return ret;
577 }
578
579 /**************************************************************************
580 * MAPISendMailW (MAPI32.256)
581 *
582 * Send a mail.
583 *
584 * PARAMS
585 * session [I] Handle to a MAPI session.
586 * uiparam [I] Parent window handle.
587 * message [I] Pointer to a MAPIMessageW structure.
588 * flags [I] Flags.
589 * reserved [I] Reserved, pass 0.
590 *
591 * RETURNS
592 * Success: SUCCESS_SUCCESS
593 * Failure: MAPI_E_FAILURE
594 *
595 */
596 ULONG WINAPI MAPISendMailW(LHANDLE session, ULONG_PTR uiparam,
597 lpMapiMessageW message, FLAGS flags, ULONG reserved)
598 {
599 WCHAR msg_title[READ_BUF_SIZE], error_msg[READ_BUF_SIZE];
600
601 /* Check to see if we have a Simple MAPI provider loaded */
602 if (mapiFunctions.MAPISendMailW)
603 return mapiFunctions.MAPISendMailW(session, uiparam, message, flags, reserved);
604
605 /* Check if we have an Extended MAPI provider - if so, use our wrapper */
606 if (MAPIInitialize(NULL) == S_OK)
607 return sendmail_extended_mapi(session, uiparam, message, flags);
608
609 if (mapiFunctions.MAPISendMail)
610 {
611 MapiMessage messageA;
612 ULONG ret;
613
614 if (flags & MAPI_FORCE_UNICODE)
615 return MAPI_E_UNICODE_NOT_SUPPORTED;
616
617 /* Convert to ANSI and send to MAPISendMail */
618 ZeroMemory(&messageA, sizeof(MapiMessage));
619
620 messageA.lpszSubject = convert_from_unicode(message->lpszSubject);
621 messageA.lpszNoteText = convert_from_unicode(message->lpszNoteText);
622 messageA.lpszMessageType = convert_from_unicode(message->lpszMessageType);
623 messageA.lpszDateReceived = convert_from_unicode(message->lpszDateReceived);
624 messageA.lpszConversationID = convert_from_unicode(message->lpszConversationID);
625 messageA.flFlags = message->flFlags;
626 messageA.lpOriginator = convert_recipient_from_unicode(message->lpOriginator, NULL);
627 messageA.nRecipCount = message->nRecipCount;
628 messageA.nFileCount = message->nFileCount;
629
630 if (message->nRecipCount && message->lpRecips)
631 {
632 lpMapiRecipDesc recipsA;
633 unsigned int i;
634
635 recipsA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MapiRecipDesc) * message->nRecipCount);
636
637 for (i = 0; i < message->nRecipCount; i++)
638 {
639 convert_recipient_from_unicode(&message->lpRecips[i], &recipsA[i]);
640 }
641
642 messageA.lpRecips = recipsA;
643 }
644
645 if (message->nFileCount && message->lpFiles)
646 {
647 lpMapiFileDesc filesA;
648 unsigned int i;
649
650 filesA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MapiFileDesc) * message->nFileCount);
651
652 for (i = 0; i < message->nFileCount; i++)
653 {
654 filesA[i].flFlags = message->lpFiles[i].flFlags;
655 filesA[i].nPosition = message->lpFiles[i].nPosition;
656 filesA[i].lpszPathName = convert_from_unicode(message->lpFiles[i].lpszPathName);
657 filesA[i].lpszFileName = convert_from_unicode(message->lpFiles[i].lpszFileName);
658 filesA[i].lpFileType = message->lpFiles[i].lpFileType;
659 }
660
661 messageA.lpFiles = filesA;
662 }
663
664 ret = mapiFunctions.MAPISendMail(session, uiparam, &messageA, flags, reserved);
665
666 /* Now free everything we allocated */
667 if (message->lpOriginator)
668 {
669 HeapFree(GetProcessHeap(), 0, messageA.lpOriginator->lpszName);
670 HeapFree(GetProcessHeap(), 0, messageA.lpOriginator->lpszAddress);
671 HeapFree(GetProcessHeap(), 0, messageA.lpOriginator);
672 }
673
674 if (message->nRecipCount && message->lpRecips)
675 {
676 unsigned int i;
677
678 for (i = 0; i < message->nRecipCount; i++)
679 {
680 HeapFree(GetProcessHeap(), 0, messageA.lpRecips[i].lpszName);
681 HeapFree(GetProcessHeap(), 0, messageA.lpRecips[i].lpszAddress);
682 }
683
684 HeapFree(GetProcessHeap(), 0, messageA.lpRecips);
685 }
686
687 if (message->nFileCount && message->lpFiles)
688 {
689 unsigned int i;
690
691 for (i = 0; i < message->nFileCount; i++)
692 {
693 HeapFree(GetProcessHeap(), 0, messageA.lpFiles[i].lpszPathName);
694 HeapFree(GetProcessHeap(), 0, messageA.lpFiles[i].lpszFileName);
695 }
696
697 HeapFree(GetProcessHeap(), 0, messageA.lpFiles);
698 }
699
700 HeapFree(GetProcessHeap(), 0, messageA.lpszSubject);
701 HeapFree(GetProcessHeap(), 0, messageA.lpszNoteText);
702 HeapFree(GetProcessHeap(), 0, messageA.lpszDateReceived);
703 HeapFree(GetProcessHeap(), 0, messageA.lpszConversationID);
704
705 return ret;
706 }
707
708 /* Display an error message since we apparently have no mail clients */
709 LoadStringW(hInstMAPI32, IDS_NO_MAPI_CLIENT, error_msg, sizeof(error_msg) / sizeof(WCHAR));
710 LoadStringW(hInstMAPI32, IDS_SEND_MAIL, msg_title, sizeof(msg_title) / sizeof(WCHAR));
711
712 MessageBoxW((HWND) uiparam, error_msg, msg_title, MB_ICONEXCLAMATION);
713
714 return MAPI_E_NOT_SUPPORTED;
715 }
716
717 ULONG WINAPI MAPISendDocuments(ULONG_PTR uiparam, LPSTR delim, LPSTR paths,
718 LPSTR filenames, ULONG reserved)
719 {
720 if (mapiFunctions.MAPISendDocuments)
721 return mapiFunctions.MAPISendDocuments(uiparam, delim, paths, filenames, reserved);
722
723 return MAPI_E_NOT_SUPPORTED;
724 }