Skip to content

Instantly share code, notes, and snippets.

@markx86
Last active March 16, 2025 22:28
Show Gist options
  • Select an option

  • Save markx86/350686b15d01c18a5507cc1532279f0a to your computer and use it in GitHub Desktop.

Select an option

Save markx86/350686b15d01c18a5507cc1532279f0a to your computer and use it in GitHub Desktop.
WINEMAPI Thunderbird patch
--- a/dlls/winemapi/sendmail.c 2025-03-07 22:15:56.000000000 +0100
+++ b/dlls/winemapi/sendmail.c 2025-03-16 23:26:02.574575702 +0100
@@ -406,6 +406,257 @@
return ret;
}
+static ULONG send_mail_thunderbird(lpMapiMessage message) {
+ 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, att_size = 0;
+ unsigned int subj_size, body_size, name_size;
+
+ char *to = NULL, *cc = NULL, *bcc = NULL, *subject = NULL, *body = NULL, *attachment = NULL;
+ const char *address;
+ static const char format[] =
+ "/c start %s -compose to='%s',subject='%s',cc='%s',bcc='%s',body='%s',attachment='%s'";
+ static const char smtp[] = "smtp:";
+ LPWSTR wthunderbird = NULL;
+ LPWSTR wname = NULL;
+ LPSTR file_path = NULL;
+ char *cmdstr = NULL;
+ char **unix_names = NULL;
+ char thunderbird[MAX_PATH];
+ DWORD size;
+
+ for (i = 0; i < message->nRecipCount; i++)
+ {
+ address = message->lpRecips[i].lpszAddress;
+
+ if (address)
+ {
+ if (!_strnicmp(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: %ld\n",
+ message->lpRecips[i].ulRecipClass);
+ }
+ }
+ else
+ FIXME("Name resolution and entry identifiers not supported\n");
+ }
+
+ if (message->nFileCount)
+ {
+ unix_names = HeapAlloc(GetProcessHeap(), 0, message->nFileCount * sizeof(*unix_names));
+ if (!unix_names)
+ {
+ WARN("Failed to allocate memory for file path translation\n");
+ goto end_file;
+ }
+
+ for (i = 0; i < message->nFileCount; i++)
+ {
+ file_path = message->lpFiles[i].lpszPathName;
+
+ TRACE("Translating %s to unix path\n", debugstr_a(file_path));
+
+ name_size = lstrlenA(file_path) + 1;
+ wname = HeapAlloc(GetProcessHeap(), 0, 2 * name_size);
+ if (!wname)
+ {
+ WARN("Failed to allocate memory for file path %s\n", debugstr_a(file_path));
+ goto end_file;
+ }
+ MultiByteToWideChar(CP_ACP, 0, file_path, name_size, wname, name_size);
+
+ unix_names[i] = wine_get_unix_file_name(wname);
+ HeapFree(GetProcessHeap(), 0, wname);
+
+ if (!unix_names[i])
+ {
+ TRACE(" -> FAILED!\n");
+ continue;
+ }
+ TRACE(" -> %s\n", unix_names[i]);
+ att_size += lstrlenA(unix_names[i]) + 1;
+ }
+
+ attachment = HeapAlloc(GetProcessHeap(), 0, att_size);
+ if (!attachment)
+ {
+ WARN("Could not allocate space for attachment\n");
+ goto end_file;
+ }
+
+ attachment[0] = '\0';
+end_file:
+ if (unix_names)
+ {
+ for (i = 0; i < message->nFileCount; ++i)
+ {
+ if (unix_names[i])
+ {
+ if (attachment[0] != '\0')
+ lstrcatA(attachment, ",");
+ lstrcatA(attachment, unix_names[i]);
+ HeapFree(GetProcessHeap(), 0, unix_names[i]);
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, unix_names);
+ unix_names = NULL;
+
+ TRACE("Attachments: %s\n", attachment);
+ }
+ }
+
+ /* Escape subject and body */
+ subject = message->lpszSubject;
+ body = message->lpszNoteText;
+
+ 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 (!_strnicmp(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;
+
+ wthunderbird = wine_get_dos_file_name("/usr/bin/thunderbird");
+ if (!wthunderbird)
+ {
+ WARN("Unable to convert '/usr/bin/thunderbird' to DOS path\n");
+ goto exit;
+ }
+
+ WideCharToMultiByte(CP_UNIXCP, 0, wthunderbird, -1, thunderbird, MAX_PATH, NULL, NULL);
+ HeapFree(GetProcessHeap(), 0, wthunderbird);
+
+ size = sizeof(format) + lstrlenA(thunderbird) + to_size + cc_size + bcc_size + subj_size + body_size + att_size;
+
+ cmdstr = HeapAlloc(GetProcessHeap(), 0, size);
+ if (!cmdstr)
+ {
+ WARN("Failed to allocate memory for command buffer\n");
+ goto exit;
+ }
+
+ sprintf(cmdstr, format,
+ thunderbird,
+ to ? to : "",
+ subject,
+ cc ? cc : "",
+ bcc ? bcc : "",
+ body,
+ attachment ? attachment : "");
+
+ size = 1;
+
+ TRACE("Executing thunderbird with parameters '%s'\n", debugstr_a(cmdstr));
+ /* FIXME: This is 99.999999% vulnerable to command injections */
+ if ((UINT_PTR) ShellExecuteA(NULL, "open", "cmd.exe", cmdstr, NULL, 0) > 32)
+ ret = SUCCESS_SUCCESS;
+
+exit:
+ HeapFree(GetProcessHeap(), 0, to);
+ HeapFree(GetProcessHeap(), 0, cc);
+ HeapFree(GetProcessHeap(), 0, bcc);
+ HeapFree(GetProcessHeap(), 0, attachment);
+ HeapFree(GetProcessHeap(), 0, cmdstr);
+
+ return ret;
+}
+
ULONG WINAPI MAPISendMail(LHANDLE session, ULONG_PTR uiparam,
lpMapiMessage message, FLAGS flags, ULONG reserved)
{
@@ -418,7 +669,10 @@
if (send_mail_xdg(message))
return SUCCESS_SUCCESS;
- return send_mail_winebrowser(message);
+ if (message->nFileCount)
+ return send_mail_thunderbird(message);
+ else
+ return send_mail_winebrowser(message);
}
ULONG WINAPI MAPISendDocuments(ULONG_PTR uiparam, LPSTR delim, LPSTR paths,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment