xref: /core/shell/source/cmdmail/cmdmailsuppl.cxx (revision 91ba9654)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <config_folders.h>
21 
22 #include <osl/thread.h>
23 
24 #include <rtl/bootstrap.hxx>
25 
26 #include <osl/file.hxx>
27 #include <rtl/strbuf.hxx>
28 #include "cmdmailsuppl.hxx"
29 #include "cmdmailmsg.hxx"
30 #include <com/sun/star/system/SimpleMailClientFlags.hpp>
31 #include <com/sun/star/container/XNameAccess.hpp>
32 #include <com/sun/star/configuration/theDefaultProvider.hpp>
33 #include <com/sun/star/beans/PropertyValue.hpp>
34 #include <com/sun/star/uno/XComponentContext.hpp>
35 #include <cppuhelper/supportsservice.hxx>
36 #include <comphelper/diagnose_ex.hxx>
37 
38 using com::sun::star::beans::PropertyValue;
39 using com::sun::star::system::XSimpleMailClientSupplier;
40 using com::sun::star::system::XSimpleMailClient;
41 using com::sun::star::system::XSimpleMailMessage;
42 using com::sun::star::system::XSimpleMailMessage2;
43 using com::sun::star::container::XNameAccess;
44 using osl::FileBase;
45 
46 using namespace cppu;
47 using namespace com::sun::star::system::SimpleMailClientFlags;
48 using namespace com::sun::star::uno;
49 using namespace com::sun::star::lang;
50 using namespace com::sun::star::configuration;
51 
52 CmdMailSuppl::CmdMailSuppl( const Reference< XComponentContext >& xContext )
53 {
54     m_xConfigurationProvider = theDefaultProvider::get(xContext);
55 }
56 
57 // XSimpleMailClientSupplier
58 
59 Reference< XSimpleMailClient > SAL_CALL CmdMailSuppl::querySimpleMailClient(  )
60 {
61     return static_cast < XSimpleMailClient * > (this);
62 }
63 
64 // XSimpleMailClient
65 
66 Reference< XSimpleMailMessage > SAL_CALL CmdMailSuppl::createSimpleMailMessage(  )
67 {
68     return Reference< XSimpleMailMessage >( new CmdMailMsg(  ) );
69 }
70 
71 namespace {
72 
73 void appendShellWord(OStringBuffer & buffer, OUString const & word, bool strict)
74 {
75     OString sys;
76     if (!word.convertToString(
77             &sys, osl_getThreadTextEncoding(),
78             (strict
79              ? (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
80                 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)
81              : OUSTRING_TO_OSTRING_CVTFLAGS)))
82     {
83         throw css::uno::Exception(
84             ("Could not convert \"" + word + "\" to encoding #"
85              + OUString::number(osl_getThreadTextEncoding())),
86             css::uno::Reference<css::uno::XInterface>());
87     }
88     buffer.append('\'');
89     for (sal_Int32 i = 0; i != sys.getLength(); ++i) {
90         char c = sys[i];
91         switch (c) {
92         case 0:
93             if (strict) {
94                 throw css::uno::Exception(
95                     "Could not convert word containing NUL, \"" + word + "\"",
96                     css::uno::Reference<css::uno::XInterface>());
97             }
98             break;
99         case '\'':
100             buffer.append("'\\''");
101             break;
102         default:
103             buffer.append(c);
104             break;
105         }
106     }
107     buffer.append('\'');
108 }
109 
110 }
111 
112 void SAL_CALL CmdMailSuppl::sendSimpleMailMessage( const Reference< XSimpleMailMessage >& xSimpleMailMessage, sal_Int32 /*aFlag*/ )
113 {
114     if ( ! xSimpleMailMessage.is() )
115     {
116         throw css::lang::IllegalArgumentException( "No message specified" ,
117             static_cast < XSimpleMailClient * > (this), 1 );
118     }
119 
120     if( ! m_xConfigurationProvider.is() )
121     {
122         throw css::uno::Exception( "Can not access configuration" ,
123             static_cast < XSimpleMailClient * > (this) );
124     }
125 
126 
127     OUString aProgramURL("$BRAND_BASE_DIR/" LIBO_LIBEXEC_FOLDER "/senddoc");
128     rtl::Bootstrap::expandMacros(aProgramURL);
129 
130     OUString aProgram;
131     if ( FileBase::E_None != FileBase::getSystemPathFromFileURL(aProgramURL, aProgram))
132     {
133         throw css::uno::Exception("Could not convert executable path",
134             static_cast < XSimpleMailClient * > (this));
135     }
136 
137     OStringBuffer aBuffer;
138     appendShellWord(aBuffer, aProgram, true);
139 
140     try
141     {
142         // Query XNameAccess interface of the org.openoffice.Office.Common/ExternalMailer
143         // configuration node to retrieve the users preferred email application. This may
144         // transparently by redirected to e.g. the corresponding GConf setting in GNOME.
145 
146         PropertyValue aProperty;
147         aProperty.Name = "nodepath";
148         aProperty.Value <<= OUString("org.openoffice.Office.Common/ExternalMailer");
149 
150         Sequence< Any > aArgumentList{ Any(aProperty) };
151 
152         Reference< XNameAccess > xNameAccess(
153                 m_xConfigurationProvider->createInstanceWithArguments(
154                     "com.sun.star.configuration.ConfigurationAccess",
155                     aArgumentList ),
156                 UNO_QUERY );
157 
158         if( xNameAccess.is() )
159         {
160             OUString aMailer;
161 
162             // Retrieve the value for "Program" node and append it feed senddoc with it
163             // using the (undocumented) --mailclient switch
164             xNameAccess->getByName("Program") >>= aMailer;
165 
166             if( !aMailer.isEmpty() )
167             {
168                 // make sure we have a system path
169                 FileBase::getSystemPathFromFileURL( aMailer, aMailer );
170 
171                 aBuffer.append(" --mailclient ");
172                 appendShellWord(aBuffer, aMailer, true);
173             }
174 #ifdef MACOSX
175             else
176                 aBuffer.append(" --mailclient Mail");
177 #endif
178         }
179 
180     }
181 
182     catch(const RuntimeException & )
183     {
184         TOOLS_WARN_EXCEPTION("shell", "RuntimeException caught accessing configuration provider" );
185         m_xConfigurationProvider.clear();
186         throw;
187     }
188 
189     Reference< XSimpleMailMessage2 > xMessage( xSimpleMailMessage, UNO_QUERY );
190     if ( xMessage.is() )
191     {
192         OUString sBody = xMessage->getBody();
193         if ( sBody.getLength() > 0 )
194         {
195             aBuffer.append(" --body ");
196             appendShellWord(aBuffer, sBody, false);
197         }
198     }
199 
200     // Convert from, to, etc. in a best-effort rather than a strict way to the
201     // system encoding, based on the assumption that the relevant address parts
202     // of those strings are ASCII anyway and any problematic characters are only
203     // in the human-readable, informational-only parts:
204 
205     // Append originator if set in the message
206     if ( !xSimpleMailMessage->getOriginator().isEmpty() )
207     {
208         aBuffer.append(" --from ");
209         appendShellWord(aBuffer, xSimpleMailMessage->getOriginator(), false);
210     }
211 
212     // Append recipient if set in the message
213     if ( !xSimpleMailMessage->getRecipient().isEmpty() )
214     {
215         aBuffer.append(" --to ");
216         appendShellWord(aBuffer, xSimpleMailMessage->getRecipient(), false);
217     }
218 
219     // Append carbon copy recipients set in the message
220     Sequence< OUString > aStringList = xSimpleMailMessage->getCcRecipient();
221     for ( const auto& rString : std::as_const(aStringList) )
222     {
223         aBuffer.append(" --cc ");
224         appendShellWord(aBuffer, rString, false);
225     }
226 
227     // Append blind carbon copy recipients set in the message
228     aStringList = xSimpleMailMessage->getBccRecipient();
229     for ( const auto& rString : std::as_const(aStringList) )
230     {
231         aBuffer.append(" --bcc ");
232         appendShellWord(aBuffer, rString, false);
233     }
234 
235     // Append subject if set in the message
236     if ( !xSimpleMailMessage->getSubject().isEmpty() )
237     {
238         aBuffer.append(" --subject ");
239         appendShellWord(aBuffer, xSimpleMailMessage->getSubject(), false);
240     }
241 
242     // Append attachments set in the message
243     aStringList = xSimpleMailMessage->getAttachement();
244     for ( const auto& rString : std::as_const(aStringList) )
245     {
246         OUString aSystemPath;
247         if ( FileBase::E_None == FileBase::getSystemPathFromFileURL(rString, aSystemPath) )
248         {
249             aBuffer.append(" --attach ");
250             appendShellWord(aBuffer, aSystemPath, true);
251         }
252     }
253 
254     OString cmd = aBuffer.makeStringAndClear();
255     FILE * f = popen(cmd.getStr(), "w");
256     if (f == nullptr || pclose(f) != 0)
257     {
258         throw css::uno::Exception("No mail client configured",
259             static_cast < XSimpleMailClient * > (this) );
260     }
261 }
262 
263 // XServiceInfo
264 
265 OUString SAL_CALL CmdMailSuppl::getImplementationName(  )
266 {
267     return "com.sun.star.comp.system.SimpleCommandMail";
268 }
269 
270 sal_Bool SAL_CALL CmdMailSuppl::supportsService( const OUString& ServiceName )
271 {
272     return cppu::supportsService(this, ServiceName);
273 }
274 
275 Sequence< OUString > SAL_CALL CmdMailSuppl::getSupportedServiceNames(    )
276 {
277     return { "com.sun.star.system.SimpleCommandMail" };
278 }
279 
280 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
281 shell_CmdMailSuppl_get_implementation(
282     css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
283 {
284     return cppu::acquire(new CmdMailSuppl(context));
285 }
286 
287 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
288