Release 1.5.29.
[wine] / dlls / winemapi / 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 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdio.h>
26 #include <stdarg.h>
27
28 #define COBJMACROS
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "mapi.h"
34 #include "winreg.h"
35 #include "shellapi.h"
36 #include "shlwapi.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(winemapi);
40
41 /* Escapes a string for use in mailto: URL */
42 static char *escape_string(char *in, char *empty_string)
43 {
44     HRESULT res;
45     DWORD size;
46     char *escaped = NULL;
47
48     if (!in)
49         return empty_string;
50
51     size = 1;
52     res = UrlEscapeA(in, empty_string, &size, URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY);
53
54     if (res == E_POINTER)
55     {
56         escaped = HeapAlloc(GetProcessHeap(), 0, size);
57
58         if (!escaped)
59             return in;
60
61         /* If for some reason UrlEscape fails, just send the original text */
62         if (UrlEscapeA(in, escaped, &size, URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY) != S_OK)
63         {
64             HeapFree(GetProcessHeap(), 0, escaped);
65             escaped = in;
66         }
67     }
68
69     return escaped ? escaped : empty_string;
70 }
71
72 /**************************************************************************
73  *  MAPISendMail
74  *
75  * Send a message using a native mail client.
76  *
77  * PARAMS
78  *  session  [I] Handle to a MAPI session.
79  *  uiparam  [I] Parent window handle.
80  *  message  [I] Pointer to a MAPIMessage structure.
81  *  flags    [I] Flags.
82  *  reserved [I] Reserved, pass 0.
83  *
84  * RETURNS
85  *  Success: SUCCESS_SUCCESS
86  *  Failure: MAPI_E_FAILURE
87  *
88  */
89 ULONG WINAPI MAPISendMail(LHANDLE session, ULONG_PTR uiparam,
90     lpMapiMessage message, FLAGS flags, ULONG reserved)
91 {
92     ULONG ret = MAPI_E_FAILURE;
93     unsigned int i, to_count = 0, cc_count = 0, bcc_count = 0;
94     unsigned int to_size = 0, cc_size = 0, bcc_size = 0, subj_size, body_size;
95
96     char *to = NULL, *cc = NULL, *bcc = NULL, *subject = NULL, *body = NULL;
97     const char *address;
98     static const char format[] =
99         "mailto:\"%s\"?subject=\"%s\"&cc=\"%s\"&bcc=\"%s\"&body=\"%s\"";
100     static const char smtp[] = "smtp:";
101     char *mailto = NULL, *escape = NULL;
102     char empty_string[] = "";
103     HRESULT res;
104     DWORD size;
105
106     TRACE("(0x%08lx 0x%08lx %p 0x%08x 0x%08x)\n", session, uiparam,
107            message, flags, reserved);
108
109     if (!message)
110         return MAPI_E_FAILURE;
111
112     for (i = 0; i < message->nRecipCount; i++)
113     {
114         if (!message->lpRecips)
115         {
116             WARN("No recipients found\n");
117             return MAPI_E_FAILURE;
118         }
119
120         address = message->lpRecips[i].lpszAddress;
121
122         if (address)
123         {
124             if (!strncasecmp(address, smtp, sizeof(smtp) - 1))
125                 address += sizeof(smtp) - 1;
126
127             switch (message->lpRecips[i].ulRecipClass)
128             {
129                 case MAPI_ORIG:
130                     TRACE("From: %s\n", debugstr_a(address));
131                     break;
132
133                 case MAPI_TO:
134                     TRACE("To: %s\n", debugstr_a(address));
135                     to_size += lstrlenA(address) + 1;
136                     break;
137
138                 case MAPI_CC:
139                     TRACE("Cc: %s\n", debugstr_a(address));
140                     cc_size += lstrlenA(address) + 1;
141                     break;
142
143                 case MAPI_BCC:
144                     TRACE("Bcc: %s\n", debugstr_a(address));
145                     bcc_size += lstrlenA(address) + 1;
146                     break;
147
148                 default:
149                     TRACE("Unknown recipient class: %d\n",
150                            message->lpRecips[i].ulRecipClass);
151             }
152         }
153         else
154             FIXME("Name resolution and entry identifiers not supported\n");
155     }
156
157     if (message->nFileCount)
158     {
159         FIXME("Ignoring %u attachments:\n", message->nFileCount);
160         for (i = 0; i < message->nFileCount; i++)
161             FIXME("\t%s (%s)\n", debugstr_a(message->lpFiles[i].lpszPathName),
162                   debugstr_a(message->lpFiles[i].lpszFileName));
163     }
164
165     /* Escape subject and body */
166     subject = escape_string(message->lpszSubject, empty_string);
167     body = escape_string(message->lpszNoteText, empty_string);
168
169     TRACE("Subject: %s\n", debugstr_a(subject));
170     TRACE("Body: %s\n", debugstr_a(body));
171
172     subj_size = lstrlenA(subject);
173     body_size = lstrlenA(body);
174
175     ret = MAPI_E_INSUFFICIENT_MEMORY;
176
177     if (to_size)
178     {
179         to = HeapAlloc(GetProcessHeap(), 0, to_size);
180
181         if (!to)
182             goto exit;
183
184         to[0] = 0;
185     }
186
187     if (cc_size)
188     {
189         cc = HeapAlloc(GetProcessHeap(), 0, cc_size);
190
191         if (!cc)
192             goto exit;
193
194         cc[0] = 0;
195     }
196
197     if (bcc_size)
198     {
199         bcc = HeapAlloc(GetProcessHeap(), 0, bcc_size);
200
201         if (!bcc)
202             goto exit;
203
204         bcc[0] = 0;
205     }
206
207     if (message->lpOriginator)
208         TRACE("From: %s\n", debugstr_a(message->lpOriginator->lpszAddress));
209
210     for (i = 0; i < message->nRecipCount; i++)
211     {
212         address = message->lpRecips[i].lpszAddress;
213
214         if (address)
215         {
216             if (!strncasecmp(address, smtp, sizeof(smtp) - 1))
217                 address += sizeof(smtp) - 1;
218
219             switch (message->lpRecips[i].ulRecipClass)
220             {
221                 case MAPI_TO:
222                     if (to_count)
223                         lstrcatA(to, ",");
224
225                     lstrcatA(to, address);
226                     to_count++;
227                     break;
228
229                 case MAPI_CC:
230                     if (cc_count)
231                         lstrcatA(cc, ",");
232
233                     lstrcatA(cc, address);
234                     cc_count++;
235                     break;
236
237                 case MAPI_BCC:
238                     if (bcc_count)
239                         lstrcatA(bcc, ",");
240
241                     lstrcatA(bcc, address);
242                     bcc_count++;
243                     break;
244             }
245         }
246     }
247     ret = MAPI_E_FAILURE;
248     size = sizeof(format) + to_size + cc_size + bcc_size + subj_size + body_size;
249
250     mailto = HeapAlloc(GetProcessHeap(), 0, size);
251
252     if (!mailto)
253         goto exit;
254
255     sprintf(mailto, format, to ? to : "", subject, cc ? cc : "", bcc ? bcc : "", body);
256
257     size = 1;
258     res = UrlEscapeA(mailto, empty_string, &size, URL_ESCAPE_SPACES_ONLY);
259
260     if (res != E_POINTER)
261         goto exit;
262
263     escape = HeapAlloc(GetProcessHeap(), 0, size);
264
265     if (!escape)
266         goto exit;
267
268     res = UrlEscapeA(mailto, escape, &size, URL_ESCAPE_SPACES_ONLY);
269
270     if (res != S_OK)
271         goto exit;
272
273     TRACE("Executing winebrowser.exe with parameters '%s'\n", debugstr_a(escape));
274
275     if ((UINT_PTR) ShellExecuteA(NULL, "open", "winebrowser.exe", escape, NULL, 0) > 32)
276         ret = SUCCESS_SUCCESS;
277
278 exit:
279     HeapFree(GetProcessHeap(), 0, to);
280     HeapFree(GetProcessHeap(), 0, cc);
281     HeapFree(GetProcessHeap(), 0, bcc);
282     HeapFree(GetProcessHeap(), 0, mailto);
283     HeapFree(GetProcessHeap(), 0, escape);
284
285     if (subject != empty_string)
286         HeapFree(GetProcessHeap(), 0, subject);
287
288     if (body != empty_string)
289         HeapFree(GetProcessHeap(), 0, body);
290
291     return ret;
292 }
293
294 ULONG WINAPI MAPISendDocuments(ULONG_PTR uiparam, LPSTR delim, LPSTR paths,
295     LPSTR filenames, ULONG reserved)
296 {
297     return MAPI_E_NOT_SUPPORTED;
298 }