mapi32: Open the Drafts folder in preparation for creating a message.
[wine.git] / dlls / mapi32 / sendmail.c
blobc7e0cfd01025812dcb821b56a065a5fc5914b43c
1 /*
2 * MAPISendMail implementation
4 * Copyright 2005 Hans Leidekker
5 * Copyright 2009 Owen Rudge for CodeWeavers
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.
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.
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
22 #include "config.h"
23 #include "wine/port.h"
25 #include <stdio.h>
26 #include <stdarg.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winerror.h"
31 #include "objbase.h"
32 #include "mapi.h"
33 #include "mapix.h"
34 #include "mapiutil.h"
35 #include "mapidefs.h"
36 #include "winreg.h"
37 #include "shellapi.h"
38 #include "shlwapi.h"
39 #include "wine/debug.h"
40 #include "util.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(mapi);
45 Internal function to send a message via Extended MAPI. Wrapper around the Simple
46 MAPI function MAPISendMail.
48 static ULONG sendmail_extended_mapi(LHANDLE mapi_session, ULONG_PTR uiparam, lpMapiMessage message,
49 FLAGS flags, ULONG reserved)
51 ULONG tags[] = {1, PR_IPM_DRAFTS_ENTRYID};
52 ULONG retval = MAPI_E_FAILURE;
53 IMAPISession *session = NULL;
54 IMAPITable* msg_table;
55 LPSRowSet rows = NULL;
56 IMsgStore* msg_store;
57 IMAPIFolder* folder;
58 LPENTRYID entry_id;
59 LPSPropValue props;
60 ULONG entry_len;
61 DWORD obj_type;
62 ULONG values;
63 HRESULT ret;
65 TRACE("Using Extended MAPI wrapper for MAPISendMail\n");
67 /* Attempt to log on via Extended MAPI */
69 ret = MAPILogonEx(0, NULL, NULL, MAPI_EXTENDED | MAPI_USE_DEFAULT | MAPI_NEW_SESSION, &session);
70 TRACE("MAPILogonEx: %x\n", ret);
72 if (ret != S_OK)
74 retval = MAPI_E_LOGIN_FAILURE;
75 goto cleanup;
78 /* Open the default message store */
80 if (IMAPISession_GetMsgStoresTable(session, 0, &msg_table) == S_OK)
82 /* We want the default store */
83 SizedSPropTagArray(2, columns) = {2, {PR_ENTRYID, PR_DEFAULT_STORE}};
85 /* Set the columns we want */
86 if (IMAPITable_SetColumns(msg_table, (LPSPropTagArray) &columns, 0) == S_OK)
88 while (1)
90 if (IMAPITable_QueryRows(msg_table, 1, 0, &rows) != S_OK)
92 MAPIFreeBuffer(rows);
93 rows = NULL;
95 else if (rows->cRows != 1)
97 FreeProws(rows);
98 rows = NULL;
100 else
102 /* If it's not the default store, try the next row */
103 if (!rows->aRow[0].lpProps[1].Value.b)
105 FreeProws(rows);
106 continue;
110 break;
114 IMAPITable_Release(msg_table);
117 /* Did we manage to get the right store? */
118 if (!rows)
119 goto logoff;
121 /* Open the message store */
122 IMAPISession_OpenMsgStore(session, 0, rows->aRow[0].lpProps[0].Value.bin.cb,
123 (ENTRYID *) rows->aRow[0].lpProps[0].Value.bin.lpb, NULL,
124 MDB_NO_DIALOG | MAPI_BEST_ACCESS, &msg_store);
126 /* We don't need this any more */
127 FreeProws(rows);
129 /* First open the inbox, from which the drafts folder can be opened */
130 if (IMsgStore_GetReceiveFolder(msg_store, NULL, 0, &entry_len, &entry_id, NULL) == S_OK)
132 IMsgStore_OpenEntry(msg_store, entry_len, entry_id, NULL, 0, &obj_type, (LPUNKNOWN*) &folder);
133 MAPIFreeBuffer(entry_id);
136 /* Open the drafts folder, or failing that, try asking the message store for the outbox */
137 if ((folder == NULL) || ((ret = IMAPIFolder_GetProps(folder, (LPSPropTagArray) tags, 0, &values, &props)) != S_OK))
139 TRACE("Unable to open Drafts folder; opening Outbox instead\n");
140 tags[1] = PR_IPM_OUTBOX_ENTRYID;
141 ret = IMsgStore_GetProps(msg_store, (LPSPropTagArray) tags, 0, &values, &props);
144 if (ret != S_OK)
145 goto logoff;
147 IMsgStore_OpenEntry(msg_store, props[0].Value.bin.cb, (LPENTRYID) props[0].Value.bin.lpb,
148 NULL, MAPI_MODIFY, &obj_type, (LPUNKNOWN *) &folder);
150 /* Free up the resources we've used */
151 IMAPIFolder_Release(folder);
152 IMsgStore_Release(msg_store);
154 logoff: ;
155 IMAPISession_Logoff(session, (ULONG) NULL, 0, 0);
156 IMAPISession_Release(session);
158 cleanup: ;
159 MAPIUninitialize();
160 return retval;
163 /**************************************************************************
164 * MAPISendMail (MAPI32.211)
166 * Send a mail.
168 * PARAMS
169 * session [I] Handle to a MAPI session.
170 * uiparam [I] Parent window handle.
171 * message [I] Pointer to a MAPIMessage structure.
172 * flags [I] Flags.
173 * reserved [I] Reserved, pass 0.
175 * RETURNS
176 * Success: SUCCESS_SUCCESS
177 * Failure: MAPI_E_FAILURE
179 * NOTES
180 * The fallback procedure is a temporary hack.
182 ULONG WINAPI MAPISendMail( LHANDLE session, ULONG_PTR uiparam,
183 lpMapiMessage message, FLAGS flags, ULONG reserved )
185 ULONG ret = MAPI_E_FAILURE;
186 unsigned int i, to_count = 0, cc_count = 0, bcc_count = 0;
187 unsigned int to_size = 0, cc_size = 0, bcc_size = 0, subj_size, body_size;
189 char *to = NULL, *cc = NULL, *bcc = NULL;
190 const char *address, *subject, *body;
191 static const char format[] =
192 "mailto:\"%s\"?subject=\"%s\"&cc=\"%s\"&bcc=\"%s\"&body=\"%s\"";
193 char *mailto = NULL, *escape = NULL;
194 char empty_string[] = "";
195 HRESULT res;
196 DWORD size;
198 TRACE( "(0x%08x 0x%08lx %p 0x%08x 0x%08x)\n", session, uiparam,
199 message, flags, reserved );
201 /* Check to see if we have a Simple MAPI provider loaded */
202 if (mapiFunctions.MAPISendMail)
203 return mapiFunctions.MAPISendMail(session, uiparam, message, flags, reserved);
205 /* Check if we have an Extended MAPI provider - if so, use our wrapper */
206 if (MAPIInitialize(NULL) == S_OK)
207 return sendmail_extended_mapi(session, uiparam, message, flags, reserved);
209 /* Fall back on our own implementation */
210 if (!message) return MAPI_E_FAILURE;
212 for (i = 0; i < message->nRecipCount; i++)
214 if (!message->lpRecips)
216 WARN("No recipients found\n");
217 return MAPI_E_FAILURE;
220 address = message->lpRecips[i].lpszAddress;
221 if (address)
223 switch (message->lpRecips[i].ulRecipClass)
225 case MAPI_ORIG:
226 TRACE( "From: %s\n", debugstr_a(address) );
227 break;
228 case MAPI_TO:
229 TRACE( "To: %s\n", debugstr_a(address) );
230 to_size += lstrlenA( address ) + 1;
231 break;
232 case MAPI_CC:
233 TRACE( "Cc: %s\n", debugstr_a(address) );
234 cc_size += lstrlenA( address ) + 1;
235 break;
236 case MAPI_BCC:
237 TRACE( "Bcc: %s\n", debugstr_a(address) );
238 bcc_size += lstrlenA( address ) + 1;
239 break;
240 default:
241 TRACE( "Unknown recipient class: %d\n",
242 message->lpRecips[i].ulRecipClass );
245 else
246 FIXME("Name resolution and entry identifiers not supported\n");
248 if (message->nFileCount) FIXME("Ignoring attachments\n");
250 subject = message->lpszSubject ? message->lpszSubject : "";
251 body = message->lpszNoteText ? message->lpszNoteText : "";
253 TRACE( "Subject: %s\n", debugstr_a(subject) );
254 TRACE( "Body: %s\n", debugstr_a(body) );
256 subj_size = lstrlenA( subject );
257 body_size = lstrlenA( body );
259 ret = MAPI_E_INSUFFICIENT_MEMORY;
260 if (to_size)
262 to = HeapAlloc( GetProcessHeap(), 0, to_size );
263 if (!to) goto exit;
264 to[0] = 0;
266 if (cc_size)
268 cc = HeapAlloc( GetProcessHeap(), 0, cc_size );
269 if (!cc) goto exit;
270 cc[0] = 0;
272 if (bcc_size)
274 bcc = HeapAlloc( GetProcessHeap(), 0, bcc_size );
275 if (!bcc) goto exit;
276 bcc[0] = 0;
279 if (message->lpOriginator)
280 TRACE( "From: %s\n", debugstr_a(message->lpOriginator->lpszAddress) );
282 for (i = 0; i < message->nRecipCount; i++)
284 address = message->lpRecips[i].lpszAddress;
285 if (address)
287 switch (message->lpRecips[i].ulRecipClass)
289 case MAPI_TO:
290 if (to_count) lstrcatA( to, "," );
291 lstrcatA( to, address );
292 to_count++;
293 break;
294 case MAPI_CC:
295 if (cc_count) lstrcatA( cc, "," );
296 lstrcatA( cc, address );
297 cc_count++;
298 break;
299 case MAPI_BCC:
300 if (bcc_count) lstrcatA( bcc, "," );
301 lstrcatA( bcc, address );
302 bcc_count++;
303 break;
307 ret = MAPI_E_FAILURE;
308 size = sizeof(format) + to_size + cc_size + bcc_size + subj_size + body_size;
310 mailto = HeapAlloc( GetProcessHeap(), 0, size );
311 if (!mailto) goto exit;
313 sprintf( mailto, format, to ? to : "", subject, cc ? cc : "", bcc ? bcc : "", body );
315 size = 1;
316 res = UrlEscapeA( mailto, empty_string, &size, URL_ESCAPE_SPACES_ONLY );
317 if (res != E_POINTER) goto exit;
319 escape = HeapAlloc( GetProcessHeap(), 0, size );
320 if (!escape) goto exit;
322 res = UrlEscapeA( mailto, escape, &size, URL_ESCAPE_SPACES_ONLY );
323 if (res != S_OK) goto exit;
325 if ((UINT_PTR)ShellExecuteA( NULL, "open", escape, NULL, NULL, 0 ) > 32)
326 ret = SUCCESS_SUCCESS;
328 exit:
329 HeapFree( GetProcessHeap(), 0, to );
330 HeapFree( GetProcessHeap(), 0, cc );
331 HeapFree( GetProcessHeap(), 0, bcc );
332 HeapFree( GetProcessHeap(), 0, mailto );
333 HeapFree( GetProcessHeap(), 0, escape );
335 return ret;
338 ULONG WINAPI MAPISendDocuments(ULONG_PTR uiparam, LPSTR delim, LPSTR paths,
339 LPSTR filenames, ULONG reserved)
341 if (mapiFunctions.MAPISendDocuments)
342 return mapiFunctions.MAPISendDocuments(uiparam, delim, paths, filenames, reserved);
344 return MAPI_E_NOT_SUPPORTED;