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