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 <tools/diagnose_ex.h>
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 
CmdMailSuppl(const Reference<XComponentContext> & xContext)52 CmdMailSuppl::CmdMailSuppl( const Reference< XComponentContext >& xContext ) :
53     WeakImplHelper< XSimpleMailClientSupplier, XSimpleMailClient, XServiceInfo >()
54 {
55     m_xConfigurationProvider = theDefaultProvider::get(xContext);
56 }
57 
58 // XSimpleMailClientSupplier
59 
querySimpleMailClient()60 Reference< XSimpleMailClient > SAL_CALL CmdMailSuppl::querySimpleMailClient(  )
61 {
62     return static_cast < XSimpleMailClient * > (this);
63 }
64 
65 // XSimpleMailClient
66 
createSimpleMailMessage()67 Reference< XSimpleMailMessage > SAL_CALL CmdMailSuppl::createSimpleMailMessage(  )
68 {
69     return Reference< XSimpleMailMessage >( new CmdMailMsg(  ) );
70 }
71 
72 namespace {
73 
appendShellWord(OStringBuffer & buffer,OUString const & word,bool strict)74 void appendShellWord(OStringBuffer & buffer, OUString const & word, bool strict)
75 {
76     OString sys;
77     if (!word.convertToString(
78             &sys, osl_getThreadTextEncoding(),
79             (strict
80              ? (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
81                 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)
82              : OUSTRING_TO_OSTRING_CVTFLAGS)))
83     {
84         throw css::uno::Exception(
85             ("Could not convert \"" + word + "\" to encoding #"
86              + OUString::number(osl_getThreadTextEncoding())),
87             css::uno::Reference<css::uno::XInterface>());
88     }
89     buffer.append('\'');
90     for (sal_Int32 i = 0; i != sys.getLength(); ++i) {
91         char c = sys[i];
92         switch (c) {
93         case 0:
94             if (strict) {
95                 throw css::uno::Exception(
96                     "Could not convert word containing NUL, \"" + word + "\"",
97                     css::uno::Reference<css::uno::XInterface>());
98             }
99             break;
100         case '\'':
101             buffer.append("'\\''");
102             break;
103         default:
104             buffer.append(c);
105             break;
106         }
107     }
108     buffer.append('\'');
109 }
110 
111 }
112 
sendSimpleMailMessage(const Reference<XSimpleMailMessage> & xSimpleMailMessage,sal_Int32)113 void SAL_CALL CmdMailSuppl::sendSimpleMailMessage( const Reference< XSimpleMailMessage >& xSimpleMailMessage, sal_Int32 /*aFlag*/ )
114 {
115     if ( ! xSimpleMailMessage.is() )
116     {
117         throw css::lang::IllegalArgumentException( "No message specified" ,
118             static_cast < XSimpleMailClient * > (this), 1 );
119     }
120 
121     if( ! m_xConfigurationProvider.is() )
122     {
123         throw css::uno::Exception( "Can not access configuration" ,
124             static_cast < XSimpleMailClient * > (this) );
125     }
126 
127 
128     OUString aProgramURL("$BRAND_BASE_DIR/" LIBO_LIBEXEC_FOLDER "/senddoc");
129     rtl::Bootstrap::expandMacros(aProgramURL);
130 
131     OUString aProgram;
132     if ( FileBase::E_None != FileBase::getSystemPathFromFileURL(aProgramURL, aProgram))
133     {
134         throw css::uno::Exception("Could not convert executable path",
135             static_cast < XSimpleMailClient * > (this));
136     }
137 
138     OStringBuffer aBuffer;
139     appendShellWord(aBuffer, aProgram, true);
140 
141     try
142     {
143         // Query XNameAccess interface of the org.openoffice.Office.Common/ExternalMailer
144         // configuration node to retrieve the users preferred email application. This may
145         // transparently by redirected to e.g. the corresponding GConf setting in GNOME.
146 
147         PropertyValue aProperty;
148         aProperty.Name = "nodepath";
149         aProperty.Value <<= OUString("org.openoffice.Office.Common/ExternalMailer");
150 
151         Sequence< Any > aArgumentList( 1 );
152         aArgumentList[0] <<= aProperty;
153 
154         Reference< XNameAccess > xNameAccess(
155                 m_xConfigurationProvider->createInstanceWithArguments(
156                     "com.sun.star.configuration.ConfigurationAccess",
157                     aArgumentList ),
158                 UNO_QUERY );
159 
160         if( xNameAccess.is() )
161         {
162             OUString aMailer;
163 
164             // Retrieve the value for "Program" node and append it feed senddoc with it
165             // using the (undocumented) --mailclient switch
166             xNameAccess->getByName("Program") >>= aMailer;
167 
168             if( !aMailer.isEmpty() )
169             {
170                 // make sure we have a system path
171                 FileBase::getSystemPathFromFileURL( aMailer, aMailer );
172 
173                 aBuffer.append(" --mailclient ");
174                 appendShellWord(aBuffer, aMailer, true);
175             }
176 #ifdef MACOSX
177             else
178                 aBuffer.append(" --mailclient Mail");
179 #endif
180         }
181 
182     }
183 
184     catch(const RuntimeException & )
185     {
186         TOOLS_WARN_EXCEPTION("shell", "RuntimeException caught accessing configuration provider" );
187         m_xConfigurationProvider.clear();
188         throw;
189     }
190 
191     Reference< XSimpleMailMessage2 > xMessage( xSimpleMailMessage, UNO_QUERY );
192     if ( xMessage.is() )
193     {
194         OUString sBody = xMessage->getBody();
195         if ( sBody.getLength() > 0 )
196         {
197             aBuffer.append(" --body ");
198             appendShellWord(aBuffer, sBody, false);
199         }
200     }
201 
202     // Convert from, to, etc. in a best-effort rather than a strict way to the
203     // system encoding, based on the assumption that the relevant address parts
204     // of those strings are ASCII anyway and any problematic characters are only
205     // in the human-readable, informational-only parts:
206 
207     // Append originator if set in the message
208     if ( !xSimpleMailMessage->getOriginator().isEmpty() )
209     {
210         aBuffer.append(" --from ");
211         appendShellWord(aBuffer, xSimpleMailMessage->getOriginator(), false);
212     }
213 
214     // Append recipient if set in the message
215     if ( !xSimpleMailMessage->getRecipient().isEmpty() )
216     {
217         aBuffer.append(" --to ");
218         appendShellWord(aBuffer, xSimpleMailMessage->getRecipient(), false);
219     }
220 
221     // Append carbon copy recipients set in the message
222     Sequence< OUString > aStringList = xSimpleMailMessage->getCcRecipient();
223     for ( const auto& rString : std::as_const(aStringList) )
224     {
225         aBuffer.append(" --cc ");
226         appendShellWord(aBuffer, rString, false);
227     }
228 
229     // Append blind carbon copy recipients set in the message
230     aStringList = xSimpleMailMessage->getBccRecipient();
231     for ( const auto& rString : std::as_const(aStringList) )
232     {
233         aBuffer.append(" --bcc ");
234         appendShellWord(aBuffer, rString, false);
235     }
236 
237     // Append subject if set in the message
238     if ( !xSimpleMailMessage->getSubject().isEmpty() )
239     {
240         aBuffer.append(" --subject ");
241         appendShellWord(aBuffer, xSimpleMailMessage->getSubject(), false);
242     }
243 
244     // Append attachments set in the message
245     aStringList = xSimpleMailMessage->getAttachement();
246     for ( const auto& rString : std::as_const(aStringList) )
247     {
248         OUString aSystemPath;
249         if ( FileBase::E_None == FileBase::getSystemPathFromFileURL(rString, aSystemPath) )
250         {
251             aBuffer.append(" --attach ");
252             appendShellWord(aBuffer, aSystemPath, true);
253         }
254     }
255 
256     OString cmd = aBuffer.makeStringAndClear();
257     FILE * f = popen(cmd.getStr(), "w");
258     if (f == nullptr || pclose(f) != 0)
259     {
260         throw css::uno::Exception("No mail client configured",
261             static_cast < XSimpleMailClient * > (this) );
262     }
263 }
264 
265 // XServiceInfo
266 
getImplementationName()267 OUString SAL_CALL CmdMailSuppl::getImplementationName(  )
268 {
269     return "com.sun.star.comp.system.SimpleCommandMail";
270 }
271 
supportsService(const OUString & ServiceName)272 sal_Bool SAL_CALL CmdMailSuppl::supportsService( const OUString& ServiceName )
273 {
274     return cppu::supportsService(this, ServiceName);
275 }
276 
getSupportedServiceNames()277 Sequence< OUString > SAL_CALL CmdMailSuppl::getSupportedServiceNames(    )
278 {
279     return { "com.sun.star.system.SimpleCommandMail" };
280 }
281 
282 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
shell_CmdMailSuppl_get_implementation(css::uno::XComponentContext * context,css::uno::Sequence<css::uno::Any> const &)283 shell_CmdMailSuppl_get_implementation(
284     css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
285 {
286     return cppu::acquire(new CmdMailSuppl(context));
287 }
288 
289 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
290