[Libreoffice-commits] core.git: include/sfx2 shell/Executable_senddoc.mk shell/Library_smplmail.mk shell/source

Mike Kaganski mike.kaganski at collabora.com
Wed Mar 7 03:30:38 UTC 2018


 include/sfx2/strings.hrc                         |    3 
 shell/Executable_senddoc.mk                      |    4 
 shell/Library_smplmail.mk                        |    3 
 shell/source/win32/simplemail/senddoc.cxx        |  170 +++++++++++++++++++++--
 shell/source/win32/simplemail/smplmailclient.cxx |  120 +++++++++++++++-
 shell/source/win32/simplemail/smplmailclient.hxx |    7 
 6 files changed, 287 insertions(+), 20 deletions(-)

New commits:
commit 2f061dad7f875f704e3744fc5780c1d145b22e9f
Author: Mike Kaganski <mike.kaganski at collabora.com>
Date:   Tue Feb 27 23:40:15 2018 +0300

    tdf#116074: Don't block on sending email interactively
    
    When sending e-mail using a MAPI mail client that doesn't recognize
    MAPI_DIALOG_MODELESS flag, and doesn't return from MAPISendMail until
    message compose dialog is closed (like MS Outlook 2010 and older),
    waiting for the senddoc process blocks UI, which is unexpected and
    prevents users from copying stuff from documents to the mail body.
    
    Waiting for senddoc process completion is used for two things:
    1. To serialize sending multiple mails (e.g., using mailmerge);
    2. To show error in case when it failed.
    
    This patch allows to avoid blocking the UI in case when compose UI is
    requested - i.e., user interaction with the mail client is expected,
    and serialization is not required. In this case, the senddoc process
    will show the error message itself -> no need for main application to
    wait for its return. The error message now includes actual error code.
    
    To avoid cases when closing main program would remove temporary
    attachment files before they were used by mail client, they are
    copied to base temporary directory (instead of default session
    temporary directory that gets deleted upon program shutdown).
    senddoc cleans up its temporaries itself.
    
    The temporary attachment files are copied to files with ASCII-only
    filenames, and their original filenames are passed to mail clients
    using MAPI. This allows to avoid cases when the filenames contain
    characters outside of current Windows codepage, and the mail client
    does not support Unicode MAPI, thus receiving wrong filename and
    erroring out from the send.
    
    Change-Id: I4a517bd7a797e76e4c0b7ea48bb1a7b652741a81
    Reviewed-on: https://gerrit.libreoffice.org/50826
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>

diff --git a/include/sfx2/strings.hrc b/include/sfx2/strings.hrc
index 4e8346b209a5..e5532815f63e 100644
--- a/include/sfx2/strings.hrc
+++ b/include/sfx2/strings.hrc
@@ -234,6 +234,9 @@
 #define STR_PRINT_NEWORISIZE                    NC_("STR_PRINT_NEWORISIZE", "The page size and orientation have been modified.\nWould you like to save the new settings in the\nactive document?")
 #define STR_CANT_CLOSE                          NC_("STR_CANT_CLOSE", "The document cannot be closed because a\n print job is being carried out.")
 #define STR_ERROR_SEND_MAIL                     NC_("STR_ERROR_SEND_MAIL", "An error occurred in sending the message. Possible errors could be a missing user account or a defective setup.\nPlease check the %PRODUCTNAME settings or your e-mail program settings.")
+// Error codes look like "MAPI_E_FAILURE" or "1234"
+#define STR_ERROR_SEND_MAIL_CODE                NC_("STR_ERROR_SEND_MAIL_CODE", "An error occurred in sending the message. Possible errors could be a missing user account or a defective setup.\n\nError code is $1")
+#define STR_ERROR_SEND_MAIL_HEADER              NC_("STR_ERROR_SEND_MAIL_HEADER", "Error sending mail")
 #define STR_QUERY_OPENASTEMPLATE                NC_("STR_QUERY_OPENASTEMPLATE", "This document cannot be edited, possibly due to missing access rights. Do you want to edit a copy of the document?")
 #define STR_QUERY_OPENASTEMPLATE_ALLOW_IGNORE   NC_("STR_QUERY_OPENASTEMPLATE_ALLOW_IGNORE", "This document cannot be edited, because it is locked in another session. Do you want to edit a copy of the document?\n\nYou can also try to ignore the lock and open the file for editing.")
 #define STR_QUERY_OPENASTEMPLATE_OPENCOPY_BTN   NC_("STR_QUERY_OPENASTEMPLATE_OPENCOPY_BTN", "Open ~Copy")
diff --git a/shell/Executable_senddoc.mk b/shell/Executable_senddoc.mk
index f51c8441aada..4b8c5e3d18bb 100644
--- a/shell/Executable_senddoc.mk
+++ b/shell/Executable_senddoc.mk
@@ -13,8 +13,12 @@ $(eval $(call gb_Executable_use_system_win32_libs,senddoc,\
 	kernel32 \
 ))
 
+$(eval $(call gb_Executable_use_sdk_api,senddoc))
+
 $(eval $(call gb_Executable_use_libraries,senddoc,\
+	i18nlangtag \
 	sal \
+	utl \
 ))
 
 $(eval $(call gb_Executable_add_exception_objects,senddoc,\
diff --git a/shell/Library_smplmail.mk b/shell/Library_smplmail.mk
index d68f0a65e8ec..fa8c222943ed 100644
--- a/shell/Library_smplmail.mk
+++ b/shell/Library_smplmail.mk
@@ -18,7 +18,10 @@ $(eval $(call gb_Library_use_system_win32_libs,smplmail,\
 $(eval $(call gb_Library_use_libraries,smplmail,\
 	cppu \
 	cppuhelper \
+	i18nlangtag \
 	sal \
+	tl \
+	utl \
 ))
 
 $(eval $(call gb_Library_set_componentfile,smplmail,shell/source/win32/simplemail/smplmail))
diff --git a/shell/source/win32/simplemail/senddoc.cxx b/shell/source/win32/simplemail/senddoc.cxx
index d972bad5f71e..636a0d862f4e 100644
--- a/shell/source/win32/simplemail/senddoc.cxx
+++ b/shell/source/win32/simplemail/senddoc.cxx
@@ -20,6 +20,11 @@
 #include <osl/diagnose.h>
 #include <sal/macros.h>
 
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <rtl/bootstrap.hxx>
+#include <sfx2/strings.hrc>
+#include <unotools/resmgr.hxx>
+
 #include <wchar.h>
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
@@ -38,7 +43,6 @@
 #endif
 
 typedef std::vector<std::wstring> StringList_t;
-typedef StringList_t::const_iterator StringListIterator_t;
 typedef std::vector<MapiRecipDescW> MapiRecipientList_t;
 typedef std::vector<MapiFileDescW> MapiAttachmentList_t;
 
@@ -46,13 +50,16 @@ const int LEN_SMTP_PREFIX = 5; // "SMTP:"
 
 namespace /* private */
 {
+    OUString gLangTag;
+    OUString gBootstrap;
     std::wstring gFrom;
     std::wstring gSubject;
     std::wstring gBody;
     StringList_t gTo;
     StringList_t gCc;
     StringList_t gBcc;
-    StringList_t gAttachments;
+    // Keep temp filepath and displayed name
+    std::vector<std::pair<std::wstring, std::wstring>> gAttachments;
     int gMapiFlags = 0;
 }
 
@@ -118,10 +125,16 @@ void initAttachmentList(MapiAttachmentList_t* pMapiAttachmentList)
     {
         MapiFileDescW mfd;
         ZeroMemory(&mfd, sizeof(mfd));
-        mfd.lpszPathName = const_cast<wchar_t*>(attachment.c_str());
-        // This is required for Outlook 2013 - otherwise using MAPI_DIALOG_MODELESS results in MAPI_E_FAILURE
+        mfd.lpszPathName = const_cast<wchar_t*>(attachment.first.c_str());
+        // MapiFileDesc documentation (https://msdn.microsoft.com/en-us/library/hh707272)
+        // allows using here either nullptr, or a pointer to empty string. However,
+        // for Outlook 2013, we cannot use nullptr here, and must point to a (possibly
+        // empty) string: otherwise using MAPI_DIALOG_MODELESS results in MAPI_E_FAILURE.
         // See http://peach.ease.lsoft.com/scripts/wa-PEACH.exe?A2=MAPI-L;d2bf3060.1604
-        mfd.lpszFileName = L"";
+        // Since C++11, c_str() must return a pointer to single null character when the
+        // string is empty, so we are OK here in case when there's no explicit file name
+        // passed
+        mfd.lpszFileName = const_cast<wchar_t*>(attachment.second.c_str());
         mfd.nPosition = sal::static_int_cast<ULONG>(-1);
         pMapiAttachmentList->push_back(mfd);
     }
@@ -151,11 +164,12 @@ void initMapiMessage(
     pMapiMessage->lpOriginator = aMapiOriginator;
     pMapiMessage->lpRecips = aMapiRecipientList.size() ? &aMapiRecipientList[0] : nullptr;
     pMapiMessage->nRecipCount = aMapiRecipientList.size();
-    pMapiMessage->lpFiles = &aMapiAttachmentList[0];
+    if (!aMapiAttachmentList.empty())
+        pMapiMessage->lpFiles = &aMapiAttachmentList[0];
     pMapiMessage->nFileCount = aMapiAttachmentList.size();
 }
 
-const wchar_t* const KnownParameter[] =
+const wchar_t* const KnownParameters[] =
 {
     L"--to",
     L"--cc",
@@ -165,16 +179,16 @@ const wchar_t* const KnownParameter[] =
     L"--body",
     L"--attach",
     L"--mapi-dialog",
-    L"--mapi-logon-ui"
+    L"--mapi-logon-ui",
+    L"--langtag",
+    L"--bootstrap",
 };
 
-const size_t nKnownParameter = SAL_N_ELEMENTS(KnownParameter);
-
 /** @internal */
 bool isKnownParameter(const wchar_t* aParameterName)
 {
-    for (size_t i = 0; i < nKnownParameter; i++)
-        if (_wcsicmp(aParameterName, KnownParameter[i]) == 0)
+    for (const wchar_t* KnownParameter : KnownParameters)
+        if (_wcsicmp(aParameterName, KnownParameter) == 0)
             return true;
 
     return false;
@@ -215,13 +229,122 @@ void initParameter(int argc, wchar_t* argv[])
             else if (_wcsicmp(argv[i], L"--body") == 0)
                 gBody = argv[i+1];
             else if (_wcsicmp(argv[i], L"--attach") == 0)
-                gAttachments.push_back(argv[i+1]);
+            {
+                std::wstring sPath(argv[i + 1]);
+                // An attachment may optionally be immediately followed by --attach-name and user-visible name
+                std::wstring sName;
+                if ((i + 3) < argc && _wcsicmp(argv[i+2], L"--attach-name") == 0)
+                {
+                    sName = argv[i+3];
+                    i += 2;
+                }
+                gAttachments.emplace_back(sPath, sName);
+            }
+            else if (_wcsicmp(argv[i], L"--langtag") == 0)
+                gLangTag = o3tl::toU(argv[i+1]);
+            else if (_wcsicmp(argv[i], L"--bootstrap") == 0)
+                gBootstrap = o3tl::toU(argv[i+1]);
 
             i++;
         }
     }
 }
 
+void ShowError(ULONG nMAPIResult)
+{
+    if (!gBootstrap.isEmpty())
+        rtl::Bootstrap::setIniFilename(gBootstrap);
+    LanguageTag aLangTag(gLangTag);
+    std::locale aLocale = Translate::Create("sfx", aLangTag);
+    OUString sMessage = Translate::get(STR_ERROR_SEND_MAIL_CODE, aLocale);
+    OUString sErrorId;
+    switch (nMAPIResult)
+    {
+    case MAPI_E_FAILURE:
+        sErrorId = "MAPI_E_FAILURE";
+        break;
+    case MAPI_E_LOGON_FAILURE:
+        sErrorId = "MAPI_E_LOGON_FAILURE";
+        break;
+    case MAPI_E_DISK_FULL:
+        sErrorId = "MAPI_E_DISK_FULL";
+        break;
+    case MAPI_E_INSUFFICIENT_MEMORY:
+        sErrorId = "MAPI_E_INSUFFICIENT_MEMORY";
+        break;
+    case MAPI_E_ACCESS_DENIED:
+        sErrorId = "MAPI_E_ACCESS_DENIED";
+        break;
+    case MAPI_E_TOO_MANY_SESSIONS:
+        sErrorId = "MAPI_E_ACCESS_DENIED";
+        break;
+    case MAPI_E_TOO_MANY_FILES:
+        sErrorId = "MAPI_E_TOO_MANY_FILES";
+        break;
+    case MAPI_E_TOO_MANY_RECIPIENTS:
+        sErrorId = "MAPI_E_TOO_MANY_RECIPIENTS";
+        break;
+    case MAPI_E_ATTACHMENT_NOT_FOUND:
+        sErrorId = "MAPI_E_ATTACHMENT_NOT_FOUND";
+        break;
+    case MAPI_E_ATTACHMENT_OPEN_FAILURE:
+        sErrorId = "MAPI_E_ATTACHMENT_OPEN_FAILURE";
+        break;
+    case MAPI_E_ATTACHMENT_WRITE_FAILURE:
+        sErrorId = "MAPI_E_ATTACHMENT_WRITE_FAILURE";
+        break;
+    case MAPI_E_UNKNOWN_RECIPIENT:
+        sErrorId = "MAPI_E_UNKNOWN_RECIPIENT";
+        break;
+    case MAPI_E_BAD_RECIPTYPE:
+        sErrorId = "MAPI_E_BAD_RECIPTYPE";
+        break;
+    case MAPI_E_NO_MESSAGES:
+        sErrorId = "MAPI_E_NO_MESSAGES";
+        break;
+    case MAPI_E_INVALID_MESSAGE:
+        sErrorId = "MAPI_E_INVALID_MESSAGE";
+        break;
+    case MAPI_E_TEXT_TOO_LARGE:
+        sErrorId = "MAPI_E_TEXT_TOO_LARGE";
+        break;
+    case MAPI_E_INVALID_SESSION:
+        sErrorId = "MAPI_E_INVALID_SESSION";
+        break;
+    case MAPI_E_TYPE_NOT_SUPPORTED:
+        sErrorId = "MAPI_E_TYPE_NOT_SUPPORTED";
+        break;
+    case MAPI_E_AMBIGUOUS_RECIPIENT:
+        sErrorId = "MAPI_E_AMBIGUOUS_RECIPIENT";
+        break;
+    case MAPI_E_MESSAGE_IN_USE:
+        sErrorId = "MAPI_E_MESSAGE_IN_USE";
+        break;
+    case MAPI_E_NETWORK_FAILURE:
+        sErrorId = "MAPI_E_NETWORK_FAILURE";
+        break;
+    case MAPI_E_INVALID_EDITFIELDS:
+        sErrorId = "MAPI_E_INVALID_EDITFIELDS";
+        break;
+    case MAPI_E_INVALID_RECIPS:
+        sErrorId = "MAPI_E_INVALID_RECIPS";
+        break;
+    case MAPI_E_NOT_SUPPORTED:
+        sErrorId = "MAPI_E_NOT_SUPPORTED";
+        break;
+    case MAPI_E_UNICODE_NOT_SUPPORTED:
+        sErrorId = "MAPI_E_UNICODE_NOT_SUPPORTED";
+        break;
+    default:
+        sErrorId = OUString::number(nMAPIResult);
+    }
+    sMessage = sMessage.replaceAll("$1", sErrorId);
+    OUString sTitle(Translate::get(STR_ERROR_SEND_MAIL_HEADER, aLocale));
+
+    MessageBoxW(nullptr, o3tl::toW(sMessage.getStr()), o3tl::toW(sTitle.getStr()),
+        MB_OK | MB_ICONINFORMATION);
+}
+
 /**
     Main.
     NOTE: Because this is program only serves implementation
@@ -275,6 +398,15 @@ int wmain(int argc, wchar_t* argv[])
     {
         OSL_FAIL(ex.what());
     }
+
+    // Now cleanup the temporary attachment files
+    for (const auto& rAttachment : gAttachments)
+        DeleteFileW(rAttachment.first.c_str());
+
+    // Only show the error message if UI was requested
+    if ((ulRet != SUCCESS_SUCCESS) && (gMapiFlags & (MAPI_DIALOG | MAPI_LOGON_UI)))
+        ShowError(ulRet);
+
     return ulRet;
 }
 
@@ -302,7 +434,11 @@ int wmain(int argc, wchar_t* argv[])
             oss << "--bcc " << address << std::endl;
 
         for (const auto& attachment : gAttachments)
-            oss << "--attach " << attachment << std::endl;
+        {
+            oss << "--attach " << attachment.first << std::endl;
+            if (!attachment.second.empty())
+                oss << "--attach-name " << attachment.second << std::endl;
+        }
 
         if (gMapiFlags & MAPI_DIALOG)
             oss << "--mapi-dialog" << std::endl;
@@ -310,6 +446,12 @@ int wmain(int argc, wchar_t* argv[])
         if (gMapiFlags & MAPI_LOGON_UI)
             oss << "--mapi-logon-ui" << std::endl;
 
+        if (!gLangTag.isEmpty())
+            oss << "--langtag " << gLangTag << std::endl;
+
+        if (!gBootstrap.isEmpty())
+            oss << "--bootstrap " << gBootstrap << std::endl;
+
         MessageBoxW(nullptr, oss.str().c_str(), L"Arguments", MB_OK | MB_ICONINFORMATION);
     }
 #endif
diff --git a/shell/source/win32/simplemail/smplmailclient.cxx b/shell/source/win32/simplemail/smplmailclient.cxx
index f83932902e7b..3a659548bbd1 100644
--- a/shell/source/win32/simplemail/smplmailclient.cxx
+++ b/shell/source/win32/simplemail/smplmailclient.cxx
@@ -28,10 +28,17 @@
 #include <com/sun/star/system/XSimpleMailMessage2.hpp>
 #include <osl/file.hxx>
 #include <o3tl/char16_t2wchar_t.hxx>
+#include <o3tl/make_unique.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/pathoptions.hxx>
+#include <unotools/syslocale.hxx>
 
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <mapi.h>
+#if defined GetTempPath
+#undef GetTempPath
+#endif
 
 #include <process.h>
 #include <vector>
@@ -56,8 +63,11 @@ const OUString FROM("--from");
 const OUString SUBJECT("--subject");
 const OUString BODY("--body");
 const OUString ATTACH("--attach");
+const OUString ATTACH_NAME("--attach-name");
 const OUString FLAG_MAPI_DIALOG("--mapi-dialog");
 const OUString FLAG_MAPI_LOGON_UI("--mapi-logon-ui");
+const OUString FLAG_LANGTAG("--langtag");
+const OUString FLAG_BOOTSTRAP("--bootstrap");
 
 namespace /* private */
 {
@@ -111,12 +121,14 @@ namespace /* private */
         @returns
         <TRUE/> on success.
     */
-    bool executeSenddoc(const std::vector<OUString>& rCommandArgs)
+    bool executeSenddoc(const std::vector<OUString>& rCommandArgs, bool bWait)
     {
         OUString senddocUrl = getSenddocUrl();
         if (senddocUrl.getLength() == 0)
             return false;
 
+        oslProcessOption nProcOption = osl_Process_DETACHED | (bWait ? osl_Process_WAIT : 0);
+
         oslProcess proc;
 
         /* for efficiency reasons we are using a 'bad' cast here
@@ -126,7 +138,7 @@ namespace /* private */
             senddocUrl.pData,
             const_cast<rtl_uString**>(reinterpret_cast<rtl_uString * const *>(&rCommandArgs[0])),
             rCommandArgs.size(),
-            osl_Process_WAIT | osl_Process_DETACHED,
+            nProcOption,
             nullptr,
             nullptr,
             nullptr,
@@ -136,6 +148,9 @@ namespace /* private */
         if (err != osl_Process_E_None)
             return false;
 
+        if (!bWait)
+            return true;
+
         oslProcessInfo procInfo;
         procInfo.Size = sizeof(oslProcessInfo);
         osl_getProcessInfo(proc, osl_Process_EXITCODE, &procInfo);
@@ -149,6 +164,76 @@ Reference<XSimpleMailMessage> SAL_CALL CSmplMailClient::createSimpleMailMessage(
     return Reference<XSimpleMailMessage>(new CSmplMailMsg());
 }
 
+namespace {
+// We cannot use the session-local temporary directory for the attachment,
+// because it will get removed upon program exit; and it must be alive for
+// senddoc process lifetime. So we use base temppath for the attachments,
+// and let the senddoc to do the cleanup if it was started successfully.
+// This function works like Desktop::CreateTemporaryDirectory()
+OUString&& InitBaseTempDirURL()
+{
+    // No need to intercept an exception here, since
+    // Desktop::CreateTemporaryDirectory() has ensured that path manager is available
+    SvtPathOptions aOpt;
+    OUString aRetURL = aOpt.GetTempPath();
+    if (aRetURL.isEmpty())
+    {
+        osl::File::getTempDirURL(aRetURL);
+    }
+    if (aRetURL.endsWith("/"))
+        aRetURL = aRetURL.copy(0, aRetURL.getLength() - 1);
+
+    return std::move(aRetURL);
+}
+
+const OUString& GetBaseTempDirURL()
+{
+    static const OUString aRetURL(InitBaseTempDirURL());
+    return aRetURL;
+}
+}
+
+OUString CSmplMailClient::CopyAttachment(const OUString& sOrigAttachURL, OUString& sUserVisibleName)
+{
+    // We do two things here:
+    // 1. Make the attachment temporary filename to not contain any fancy characters possible in
+    // original filename, that could confuse mailer, and extract the original filename to explicitly
+    // define it;
+    // 2. Allow the copied files be outside of the session's temporary directory, and thus not be
+    // removed in Desktop::RemoveTemporaryDirectory() if soffice process gets closed before the
+    // mailer finishes using them.
+
+    maAttachmentFiles.emplace_back(o3tl::make_unique<utl::TempFile>(&GetBaseTempDirURL()));
+    maAttachmentFiles.back()->EnableKillingFile();
+    INetURLObject aFilePathObj(maAttachmentFiles.back()->GetURL());
+    OUString sNewAttachmentURL = aFilePathObj.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+    if (osl::File::copy(sOrigAttachURL, sNewAttachmentURL) == osl::FileBase::RC::E_None)
+    {
+        INetURLObject url(sOrigAttachURL, INetURLObject::EncodeMechanism::WasEncoded);
+        sUserVisibleName = url.getName(INetURLObject::LAST_SEGMENT, true,
+            INetURLObject::DecodeMechanism::WithCharset);
+    }
+    else
+    {
+        // Failed to copy original; the best effort is to use original file. It is possible that
+        // the file gets deleted before used in spawned process; but let's hope... the worst thing
+        // is the absent attachment file anyway.
+        sNewAttachmentURL = sOrigAttachURL;
+        maAttachmentFiles.pop_back();
+    }
+    return sNewAttachmentURL;
+}
+
+void CSmplMailClient::ReleaseAttachments()
+{
+    for (auto& pTempFile : maAttachmentFiles)
+    {
+        if (pTempFile)
+            pTempFile->EnableKillingFile(false);
+    }
+    maAttachmentFiles.clear();
+}
+
 /**
     Assemble a command line for SendDoc.exe out of the members
     of the supplied SimpleMailMessage.
@@ -218,11 +303,12 @@ void CSmplMailClient::assembleCommandLine(
         rCommandArgs.push_back(subject);
     }
 
-    Sequence<OUString> attachments = xSimpleMailMessage->getAttachement();
-    for (int i = 0; i < attachments.getLength(); i++)
+    for (const auto& attachment : xSimpleMailMessage->getAttachement())
     {
+        OUString sDisplayName;
+        OUString sTempFileURL(CopyAttachment(attachment, sDisplayName));
         OUString sysPath;
-        osl::FileBase::RC err = osl::FileBase::getSystemPathFromFileURL(attachments[i], sysPath);
+        osl::FileBase::RC err = osl::FileBase::getSystemPathFromFileURL(sTempFileURL, sysPath);
         if (err != osl::FileBase::E_None)
             throw IllegalArgumentException(
                 "Invalid attachment file URL",
@@ -231,6 +317,11 @@ void CSmplMailClient::assembleCommandLine(
 
         rCommandArgs.push_back(ATTACH);
         rCommandArgs.push_back(sysPath);
+        if (!sDisplayName.isEmpty())
+        {
+            rCommandArgs.push_back(ATTACH_NAME);
+            rCommandArgs.push_back(sDisplayName);
+        }
     }
 
     if (!(aFlag & NO_USER_INTERFACE))
@@ -238,6 +329,19 @@ void CSmplMailClient::assembleCommandLine(
 
     if (!(aFlag & NO_LOGON_DIALOG))
         rCommandArgs.push_back(FLAG_MAPI_LOGON_UI);
+
+    rCommandArgs.push_back(FLAG_LANGTAG);
+    rCommandArgs.push_back(SvtSysLocale().GetUILanguageTag().getBcp47());
+
+    rtl::Bootstrap aBootstrap;
+    OUString sBootstrapPath;
+    aBootstrap.getIniName(sBootstrapPath);
+    if (!sBootstrapPath.isEmpty())
+    {
+        rCommandArgs.push_back(FLAG_BOOTSTRAP);
+        rCommandArgs.push_back(sBootstrapPath);
+    }
+
 }
 
 void SAL_CALL CSmplMailClient::sendSimpleMailMessage(
@@ -248,10 +352,14 @@ void SAL_CALL CSmplMailClient::sendSimpleMailMessage(
     std::vector<OUString> senddocParams;
     assembleCommandLine(xSimpleMailMessage, aFlag, senddocParams);
 
-    if (!executeSenddoc(senddocParams))
+    const bool bWait = aFlag & NO_USER_INTERFACE;
+    if (!executeSenddoc(senddocParams, bWait))
         throw Exception(
             "Send email failed",
             static_cast<XSimpleMailClient*>(this));
+    // Let the launched senddoc to cleanup the attachments temporary files
+    if (!bWait)
+        ReleaseAttachments();
 }
 
 void CSmplMailClient::validateParameter(
diff --git a/shell/source/win32/simplemail/smplmailclient.hxx b/shell/source/win32/simplemail/smplmailclient.hxx
index 4a744c289eec..5844e99147e5 100644
--- a/shell/source/win32/simplemail/smplmailclient.hxx
+++ b/shell/source/win32/simplemail/smplmailclient.hxx
@@ -24,7 +24,9 @@
 #include <com/sun/star/lang/XServiceInfo.hpp>
 
 #include <com/sun/star/system/XSimpleMailClient.hpp>
+#include <unotools/tempfile.hxx>
 #include <vector>
+#include <memory>
 
 class CSmplMailClient : public cppu::WeakImplHelper<css::system::XSimpleMailClient>
 {
@@ -36,6 +38,11 @@ public:
 private:
     void validateParameter(const css::uno::Reference<css::system::XSimpleMailMessage>& xSimpleMailMessage, sal_Int32 aFlag);
     void assembleCommandLine(const css::uno::Reference<css::system::XSimpleMailMessage>& xSimpleMailMessage, sal_Int32 aFlag, std::vector<OUString>& rCommandArgs);
+    OUString CopyAttachment(const OUString& sOrigAttachURL, OUString& sUserVisibleName);
+    // Don't try to delete the copied attachment files; let the spawned process cleanup them
+    void ReleaseAttachments();
+
+    std::vector< std::unique_ptr<utl::TempFile> > maAttachmentFiles;
 };
 
 #endif


More information about the Libreoffice-commits mailing list