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
