|  | /* | 
|  | * MAPISendMail implementation | 
|  | * | 
|  | * Copyright 2005 Hans Leidekker | 
|  | * Copyright 2009 Owen Rudge for CodeWeavers | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "wine/port.h" | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <stdarg.h> | 
|  |  | 
|  | #define COBJMACROS | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winerror.h" | 
|  | #include "mapi.h" | 
|  | #include "winreg.h" | 
|  | #include "shellapi.h" | 
|  | #include "shlwapi.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(winemapi); | 
|  |  | 
|  | /* Escapes a string for use in mailto: URL */ | 
|  | static char *escape_string(char *in, char *empty_string) | 
|  | { | 
|  | HRESULT res; | 
|  | DWORD size; | 
|  | char *escaped = NULL; | 
|  |  | 
|  | if (!in) | 
|  | return empty_string; | 
|  |  | 
|  | size = 1; | 
|  | res = UrlEscapeA(in, empty_string, &size, URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY); | 
|  |  | 
|  | if (res == E_POINTER) | 
|  | { | 
|  | escaped = HeapAlloc(GetProcessHeap(), 0, size); | 
|  |  | 
|  | if (!escaped) | 
|  | return in; | 
|  |  | 
|  | /* If for some reason UrlEscape fails, just send the original text */ | 
|  | if (UrlEscapeA(in, escaped, &size, URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY) != S_OK) | 
|  | { | 
|  | HeapFree(GetProcessHeap(), 0, escaped); | 
|  | escaped = in; | 
|  | } | 
|  | } | 
|  |  | 
|  | return escaped ? escaped : empty_string; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  MAPISendMail | 
|  | * | 
|  | * Send a message using a native mail client. | 
|  | * | 
|  | * PARAMS | 
|  | *  session  [I] Handle to a MAPI session. | 
|  | *  uiparam  [I] Parent window handle. | 
|  | *  message  [I] Pointer to a MAPIMessage structure. | 
|  | *  flags    [I] Flags. | 
|  | *  reserved [I] Reserved, pass 0. | 
|  | * | 
|  | * RETURNS | 
|  | *  Success: SUCCESS_SUCCESS | 
|  | *  Failure: MAPI_E_FAILURE | 
|  | * | 
|  | */ | 
|  | ULONG WINAPI MAPISendMail(LHANDLE session, ULONG_PTR uiparam, | 
|  | lpMapiMessage message, FLAGS flags, ULONG reserved) | 
|  | { | 
|  | ULONG ret = MAPI_E_FAILURE; | 
|  | unsigned int i, to_count = 0, cc_count = 0, bcc_count = 0; | 
|  | unsigned int to_size = 0, cc_size = 0, bcc_size = 0, subj_size, body_size; | 
|  |  | 
|  | char *to = NULL, *cc = NULL, *bcc = NULL, *subject = NULL, *body = NULL; | 
|  | const char *address; | 
|  | static const char format[] = | 
|  | "mailto:\"%s\"?subject=\"%s\"&cc=\"%s\"&bcc=\"%s\"&body=\"%s\""; | 
|  | static const char smtp[] = "smtp:"; | 
|  | char *mailto = NULL, *escape = NULL; | 
|  | char empty_string[] = ""; | 
|  | HRESULT res; | 
|  | DWORD size; | 
|  |  | 
|  | TRACE("(0x%08lx 0x%08lx %p 0x%08x 0x%08x)\n", session, uiparam, | 
|  | message, flags, reserved); | 
|  |  | 
|  | if (!message) | 
|  | return MAPI_E_FAILURE; | 
|  |  | 
|  | for (i = 0; i < message->nRecipCount; i++) | 
|  | { | 
|  | if (!message->lpRecips) | 
|  | { | 
|  | WARN("No recipients found\n"); | 
|  | return MAPI_E_FAILURE; | 
|  | } | 
|  |  | 
|  | address = message->lpRecips[i].lpszAddress; | 
|  |  | 
|  | if (address) | 
|  | { | 
|  | if (!strncasecmp(address, smtp, sizeof(smtp) - 1)) | 
|  | address += sizeof(smtp) - 1; | 
|  |  | 
|  | switch (message->lpRecips[i].ulRecipClass) | 
|  | { | 
|  | case MAPI_ORIG: | 
|  | TRACE("From: %s\n", debugstr_a(address)); | 
|  | break; | 
|  |  | 
|  | case MAPI_TO: | 
|  | TRACE("To: %s\n", debugstr_a(address)); | 
|  | to_size += lstrlenA(address) + 1; | 
|  | break; | 
|  |  | 
|  | case MAPI_CC: | 
|  | TRACE("Cc: %s\n", debugstr_a(address)); | 
|  | cc_size += lstrlenA(address) + 1; | 
|  | break; | 
|  |  | 
|  | case MAPI_BCC: | 
|  | TRACE("Bcc: %s\n", debugstr_a(address)); | 
|  | bcc_size += lstrlenA(address) + 1; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | TRACE("Unknown recipient class: %d\n", | 
|  | message->lpRecips[i].ulRecipClass); | 
|  | } | 
|  | } | 
|  | else | 
|  | FIXME("Name resolution and entry identifiers not supported\n"); | 
|  | } | 
|  |  | 
|  | if (message->nFileCount) | 
|  | FIXME("Ignoring attachments\n"); | 
|  |  | 
|  | /* Escape subject and body */ | 
|  | subject = escape_string(message->lpszSubject, empty_string); | 
|  | body = escape_string(message->lpszNoteText, empty_string); | 
|  |  | 
|  | TRACE("Subject: %s\n", debugstr_a(subject)); | 
|  | TRACE("Body: %s\n", debugstr_a(body)); | 
|  |  | 
|  | subj_size = lstrlenA(subject); | 
|  | body_size = lstrlenA(body); | 
|  |  | 
|  | ret = MAPI_E_INSUFFICIENT_MEMORY; | 
|  |  | 
|  | if (to_size) | 
|  | { | 
|  | to = HeapAlloc(GetProcessHeap(), 0, to_size); | 
|  |  | 
|  | if (!to) | 
|  | goto exit; | 
|  |  | 
|  | to[0] = 0; | 
|  | } | 
|  |  | 
|  | if (cc_size) | 
|  | { | 
|  | cc = HeapAlloc(GetProcessHeap(), 0, cc_size); | 
|  |  | 
|  | if (!cc) | 
|  | goto exit; | 
|  |  | 
|  | cc[0] = 0; | 
|  | } | 
|  |  | 
|  | if (bcc_size) | 
|  | { | 
|  | bcc = HeapAlloc(GetProcessHeap(), 0, bcc_size); | 
|  |  | 
|  | if (!bcc) | 
|  | goto exit; | 
|  |  | 
|  | bcc[0] = 0; | 
|  | } | 
|  |  | 
|  | if (message->lpOriginator) | 
|  | TRACE("From: %s\n", debugstr_a(message->lpOriginator->lpszAddress)); | 
|  |  | 
|  | for (i = 0; i < message->nRecipCount; i++) | 
|  | { | 
|  | address = message->lpRecips[i].lpszAddress; | 
|  |  | 
|  | if (address) | 
|  | { | 
|  | if (!strncasecmp(address, smtp, sizeof(smtp) - 1)) | 
|  | address += sizeof(smtp) - 1; | 
|  |  | 
|  | switch (message->lpRecips[i].ulRecipClass) | 
|  | { | 
|  | case MAPI_TO: | 
|  | if (to_count) | 
|  | lstrcatA(to, ","); | 
|  |  | 
|  | lstrcatA(to, address); | 
|  | to_count++; | 
|  | break; | 
|  |  | 
|  | case MAPI_CC: | 
|  | if (cc_count) | 
|  | lstrcatA(cc, ","); | 
|  |  | 
|  | lstrcatA(cc, address); | 
|  | cc_count++; | 
|  | break; | 
|  |  | 
|  | case MAPI_BCC: | 
|  | if (bcc_count) | 
|  | lstrcatA(bcc, ","); | 
|  |  | 
|  | lstrcatA(bcc, address); | 
|  | bcc_count++; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | ret = MAPI_E_FAILURE; | 
|  | size = sizeof(format) + to_size + cc_size + bcc_size + subj_size + body_size; | 
|  |  | 
|  | mailto = HeapAlloc(GetProcessHeap(), 0, size); | 
|  |  | 
|  | if (!mailto) | 
|  | goto exit; | 
|  |  | 
|  | sprintf(mailto, format, to ? to : "", subject, cc ? cc : "", bcc ? bcc : "", body); | 
|  |  | 
|  | size = 1; | 
|  | res = UrlEscapeA(mailto, empty_string, &size, URL_ESCAPE_SPACES_ONLY); | 
|  |  | 
|  | if (res != E_POINTER) | 
|  | goto exit; | 
|  |  | 
|  | escape = HeapAlloc(GetProcessHeap(), 0, size); | 
|  |  | 
|  | if (!escape) | 
|  | goto exit; | 
|  |  | 
|  | res = UrlEscapeA(mailto, escape, &size, URL_ESCAPE_SPACES_ONLY); | 
|  |  | 
|  | if (res != S_OK) | 
|  | goto exit; | 
|  |  | 
|  | TRACE("Executing winebrowser.exe with parameters '%s'\n", debugstr_a(escape)); | 
|  |  | 
|  | if ((UINT_PTR) ShellExecuteA(NULL, "open", "winebrowser.exe", escape, NULL, 0) > 32) | 
|  | ret = SUCCESS_SUCCESS; | 
|  |  | 
|  | exit: | 
|  | HeapFree(GetProcessHeap(), 0, to); | 
|  | HeapFree(GetProcessHeap(), 0, cc); | 
|  | HeapFree(GetProcessHeap(), 0, bcc); | 
|  | HeapFree(GetProcessHeap(), 0, mailto); | 
|  | HeapFree(GetProcessHeap(), 0, escape); | 
|  |  | 
|  | if (subject != empty_string) | 
|  | HeapFree(GetProcessHeap(), 0, subject); | 
|  |  | 
|  | if (body != empty_string) | 
|  | HeapFree(GetProcessHeap(), 0, body); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | ULONG WINAPI MAPISendDocuments(ULONG_PTR uiparam, LPSTR delim, LPSTR paths, | 
|  | LPSTR filenames, ULONG reserved) | 
|  | { | 
|  | return MAPI_E_NOT_SUPPORTED; | 
|  | } |