LibreOffice Module desktop (master)  1
lokinteractionhandler.cxx
Go to the documentation of this file.
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 
21 
22 #include <boost/property_tree/json_parser.hpp>
23 
24 #include <rtl/ref.hxx>
26 
27 #include <com/sun/star/task/XInteractionAbort.hpp>
28 #include <com/sun/star/task/XInteractionApprove.hpp>
29 #include <com/sun/star/task/XInteractionPassword2.hpp>
30 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
31 #include <com/sun/star/ucb/InteractiveNetworkOffLineException.hpp>
32 
33 #include <com/sun/star/ucb/InteractiveIOException.hpp>
34 #include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
35 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
36 #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
37 
38 #include <com/sun/star/task/DocumentPasswordRequest2.hpp>
39 #include <com/sun/star/task/DocumentMSPasswordRequest2.hpp>
40 
41 #include "../../inc/lib/init.hxx"
42 
43 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
44 #include <sfx2/lokhelper.hxx>
45 #include <sfx2/viewsh.hxx>
46 
47 using namespace com::sun::star;
48 
50  const OString& rCommand,
51  desktop::LibLibreOffice_Impl *const pLOKit,
52  desktop::LibLODocument_Impl *const pLOKDocument)
53  : m_pLOKit(pLOKit)
54  , m_pLOKDocument(pLOKDocument)
55  , m_command(rCommand)
56  , m_usePassword(false)
57 {
58  assert(m_pLOKit);
59 }
60 
62 {
63 }
64 
66 {
67  return "com.sun.star.comp.uui.LOKInteractionHandler";
68 }
69 
70 sal_Bool SAL_CALL LOKInteractionHandler::supportsService(OUString const & rServiceName)
71 {
72  return cppu::supportsService(this, rServiceName);
73 }
74 
75 uno::Sequence< OUString > SAL_CALL LOKInteractionHandler::getSupportedServiceNames()
76 {
77  return { "com.sun.star.task.InteractionHandler",
78  // added to indicate support for configuration.backend.MergeRecoveryRequest
79  "com.sun.star.configuration.backend.InteractionHandler",
80  // for backwards compatibility
81  "com.sun.star.uui.InteractionHandler" };
82 }
83 
84 void SAL_CALL LOKInteractionHandler::initialize(uno::Sequence<uno::Any> const & /*rArguments*/)
85 {
86 }
87 
89  uno::Reference<task::XInteractionRequest> const & xRequest)
90 {
91  // just do the same thing in both cases
92  handleInteractionRequest(xRequest);
93 }
94 
95 void LOKInteractionHandler::postError(css::task::InteractionClassification classif, const char* kind, ErrCode code, const OUString &message)
96 {
97  const char *classification = "error";
98  switch (classif)
99  {
100  case task::InteractionClassification_ERROR: break;
101  case task::InteractionClassification_WARNING: classification = "warning"; break;
102  case task::InteractionClassification_INFO: classification = "info"; break;
103  case task::InteractionClassification_QUERY: classification = "query"; break;
104  default: assert(false); break;
105  }
106 
107  // create the JSON representation
108  boost::property_tree::ptree aTree;
109  aTree.put("classification", classification);
110  aTree.put("cmd", m_command.getStr());
111  aTree.put("kind", kind);
112  aTree.put("code", code);
113  aTree.put("message", message.toUtf8());
114 
115  std::stringstream aStream;
116  boost::property_tree::write_json(aStream, aTree);
117 
118  std::size_t nView = SfxViewShell::Current() ? SfxLokHelper::getView() : 0;
120  m_pLOKDocument->mpCallbackFlushHandlers[nView]->queue(LOK_CALLBACK_ERROR, aStream.str().c_str());
121  else if (m_pLOKit->mpCallback)
122  m_pLOKit->mpCallback(LOK_CALLBACK_ERROR, aStream.str().c_str(), m_pLOKit->mpCallbackData);
123 }
124 
125 namespace {
126 
128 void selectApproved(uno::Sequence<uno::Reference<task::XInteractionContinuation>> const &rContinuations)
129 {
130  for (sal_Int32 i = 0; i < rContinuations.getLength(); ++i)
131  {
132  uno::Reference<task::XInteractionApprove> xApprove(rContinuations[i], uno::UNO_QUERY);
133  if (xApprove.is())
134  xApprove->select();
135  }
136 }
137 
138 }
139 
140 bool LOKInteractionHandler::handleIOException(const css::uno::Sequence<css::uno::Reference<css::task::XInteractionContinuation>> &rContinuations, const css::uno::Any& rRequest)
141 {
142  ucb::InteractiveIOException aIoException;
143  if (!(rRequest >>= aIoException))
144  return false;
145 
146  static ErrCode const aErrorCode[int(ucb::IOErrorCode_WRONG_VERSION) + 1] =
147  {
184  };
185 
186  postError(aIoException.Classification, "io", aErrorCode[static_cast<int>(aIoException.Code)], "");
187  selectApproved(rContinuations);
188 
189  return true;
190 }
191 
192 bool LOKInteractionHandler::handleNetworkException(const uno::Sequence<uno::Reference<task::XInteractionContinuation>> &rContinuations, const uno::Any &rRequest)
193 {
194  ucb::InteractiveNetworkException aNetworkException;
195  if (!(rRequest >>= aNetworkException))
196  return false;
197 
198  ErrCode nErrorCode;
199  OUString aMessage;
200 
201  ucb::InteractiveNetworkOffLineException aOffLineException;
202  ucb::InteractiveNetworkResolveNameException aResolveNameException;
203  ucb::InteractiveNetworkConnectException aConnectException;
204  ucb::InteractiveNetworkReadException aReadException;
205  ucb::InteractiveNetworkWriteException aWriteException;
206  if (rRequest >>= aOffLineException)
207  {
208  nErrorCode = ERRCODE_INET_OFFLINE;
209  }
210  else if (rRequest >>= aResolveNameException)
211  {
212  nErrorCode = ERRCODE_INET_NAME_RESOLVE;
213  aMessage = aResolveNameException.Server;
214  }
215  else if (rRequest >>= aConnectException)
216  {
217  nErrorCode = ERRCODE_INET_CONNECT;
218  aMessage = aConnectException.Server;
219  }
220  else if (rRequest >>= aReadException)
221  {
222  nErrorCode = ERRCODE_INET_READ;
223  aMessage = aReadException.Diagnostic;
224  }
225  else if (rRequest >>= aWriteException)
226  {
227  nErrorCode = ERRCODE_INET_WRITE;
228  aMessage = aWriteException.Diagnostic;
229  }
230  else
231  {
232  nErrorCode = ERRCODE_INET_GENERAL;
233  }
234 
235  postError(aNetworkException.Classification, "network", nErrorCode, aMessage);
236  selectApproved(rContinuations);
237 
238  return true;
239 }
240 
241 bool LOKInteractionHandler::handlePasswordRequest(const uno::Sequence<uno::Reference<task::XInteractionContinuation>> &rContinuations, const uno::Any &rRequest)
242 {
243  bool bPasswordRequestFound = false;
244  bool bIsRequestPasswordToModify = false;
245 
246  OString sUrl;
247 
248  task::DocumentPasswordRequest passwordRequest;
249  if (rRequest >>= passwordRequest)
250  {
251  bIsRequestPasswordToModify = false;
252  sUrl = passwordRequest.Name.toUtf8();
253  bPasswordRequestFound = true;
254  }
255 
256  task::DocumentPasswordRequest2 passwordRequest2;
257  if (rRequest >>= passwordRequest2)
258  {
259  bIsRequestPasswordToModify = passwordRequest2.IsRequestPasswordToModify;
260  sUrl = passwordRequest2.Name.toUtf8();
261  bPasswordRequestFound = true;
262  }
263 
264  task::DocumentMSPasswordRequest2 passwordMSRequest;
265  if (rRequest >>= passwordMSRequest)
266  {
267  bIsRequestPasswordToModify = passwordMSRequest.IsRequestPasswordToModify;
268  sUrl = passwordMSRequest.Name.toUtf8();
269  bPasswordRequestFound = true;
270  }
271 
272  if (!bPasswordRequestFound)
273  return false;
274 
275  if (m_pLOKit->mpCallback &&
276  m_pLOKit->hasOptionalFeature(bIsRequestPasswordToModify ? LOK_FEATURE_DOCUMENT_PASSWORD_TO_MODIFY
277  : LOK_FEATURE_DOCUMENT_PASSWORD))
278  {
279  m_pLOKit->mpCallback(bIsRequestPasswordToModify ? LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY
280  : LOK_CALLBACK_DOCUMENT_PASSWORD,
281  sUrl.getStr(),
283 
284  // block until SetPassword is called
285  m_havePassword.wait();
286  m_havePassword.reset();
287  }
288 
289  for (sal_Int32 i = 0; i < rContinuations.getLength(); ++i)
290  {
291  if (m_usePassword)
292  {
293  if (bIsRequestPasswordToModify)
294  {
295  uno::Reference<task::XInteractionPassword2> const xIPW2(rContinuations[i], uno::UNO_QUERY);
296  xIPW2->setPasswordToModify(m_Password);
297  xIPW2->select();
298  }
299  else
300  {
301  uno::Reference<task::XInteractionPassword> const xIPW(rContinuations[i], uno::UNO_QUERY);
302  if (xIPW.is())
303  {
304  xIPW->setPassword(m_Password);
305  xIPW->select();
306  }
307  }
308  }
309  else
310  {
311  if (bIsRequestPasswordToModify)
312  {
313  uno::Reference<task::XInteractionPassword2> const xIPW2(rContinuations[i], uno::UNO_QUERY);
314  xIPW2->setRecommendReadOnly(true);
315  xIPW2->select();
316  }
317  else
318  {
319  uno::Reference<task::XInteractionAbort> const xAbort(rContinuations[i], uno::UNO_QUERY);
320  if (xAbort.is())
321  {
322  xAbort->select();
323  }
324  }
325  }
326  }
327  return true;
328 }
329 
331  const uno::Reference<task::XInteractionRequest>& xRequest)
332 {
333  uno::Sequence<uno::Reference<task::XInteractionContinuation>> const &rContinuations = xRequest->getContinuations();
334  uno::Any const request(xRequest->getRequest());
335 
336  if (handleIOException(rContinuations, request))
337  return true;
338 
339  if (handleNetworkException(rContinuations, request))
340  return true;
341 
342  if (handlePasswordRequest(rContinuations, request))
343  return true;
344 
345  // TODO: perform more interactions 'for real' like the above
346  selectApproved(rContinuations);
347 
348  return true;
349 }
350 
351 void LOKInteractionHandler::SetPassword(char const*const pPassword)
352 {
353  if (pPassword)
354  {
355  m_Password = OUString(pPassword, strlen(pPassword), RTL_TEXTENCODING_UTF8);
356  m_usePassword = true;
357  }
358  else
359  {
360  m_usePassword = false;
361  }
362  m_havePassword.set();
363 }
364 
365 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define ERRCODE_IO_NAMETOOLONG
#define ERRCODE_IO_INVALIDPARAMETER
#define ERRCODE_IO_ABORT
virtual sal_Bool SAL_CALL handleInteractionRequest(const ::com::sun::star::uno::Reference<::com::sun::star::task::XInteractionRequest > &Request) override
#define ERRCODE_IO_UNKNOWN
#define ERRCODE_IO_WRITEPROTECTED
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
#define ERRCODE_IO_ACCESSDENIED
#define ERRCODE_IO_CANTTELL
#define ERRCODE_INET_GENERAL
#define ERRCODE_IO_NOTAFILE
#define ERRCODE_IO_WRONGFORMAT
virtual void SAL_CALL handle(com::sun::star::uno::Reference< com::sun::star::task::XInteractionRequest > const &rRequest) override
#define ERRCODE_IO_CANTSEEK
#define ERRCODE_IO_INVALIDDEVICE
#define ERRCODE_IO_NOTEXISTSPATH
#define ERRCODE_IO_NOTSAMEDEVICE
bool handlePasswordRequest(const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation >> &rContinuations, const css::uno::Any &rRequest)
#define ERRCODE_IO_OUTOFSPACE
#define ERRCODE_IO_INVALIDACCESS
desktop::LibLODocument_Impl * m_pLOKDocument
#define ERRCODE_IO_BADCRC
#define ERRCODE_INET_WRITE
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
static SfxViewShell * Current()
#define ERRCODE_IO_CANTWRITE
bool handleNetworkException(const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation >> &rContinuations, const css::uno::Any &rRequest)
#define ERRCODE_IO_NOTSUPPORTED
#define ERRCODE_IO_NOTADIRECTORY
#define ERRCODE_IO_RECURSIVE
#define ERRCODE_IO_CANTCREATE
#define ERRCODE_IO_GENERAL
std::map< size_t, std::shared_ptr< CallbackFlushHandler > > mpCallbackFlushHandlers
Definition: init.hxx:152
static int getView(SfxViewShell *pViewShell=nullptr)
int i
LibreOfficeKitCallback mpCallback
Definition: init.hxx:163
unsigned char sal_Bool
#define ERRCODE_IO_LOCKVIOLATION
#define ERRCODE_IO_WRONGVERSION
virtual OUString SAL_CALL getImplementationName() override
#define ERRCODE_IO_MISPLACEDCHAR
virtual ~LOKInteractionHandler() override
OString m_command
Command for which we use this interaction handler (like "load", "save", "saveas", ...
desktop::LibLibreOffice_Impl * m_pLOKit
#define ERRCODE_IO_NOTEXISTS
#define ERRCODE_INET_READ
#define ERRCODE_IO_DEVICENOTREADY
#define ERRCODE_IO_CURRENTDIR
#define ERRCODE_INET_OFFLINE
void SetPassword(char const *pPassword)
#define ERRCODE_IO_OUTOFMEMORY
bool hasOptionalFeature(LibreOfficeKitOptionalFeatures const feature)
Definition: init.hxx:171
#define ERRCODE_INET_NAME_RESOLVE
virtual void SAL_CALL initialize(com::sun::star::uno::Sequence< com::sun::star::uno::Any > const &rArguments) override
bool handleIOException(const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation >> &rContinuations, const css::uno::Any &rRequest)
LOKInteractionHandler(const LOKInteractionHandler &)=delete
#define ERRCODE_INET_CONNECT
#define ERRCODE_IO_ISWILDCARD
void postError(css::task::InteractionClassification classif, const char *kind, ErrCode code, const OUString &message)
Call the LOK_CALLBACK_ERROR on the LOK document (if available) or LOK lib.
virtual sal_Bool SAL_CALL supportsService(OUString const &rServiceName) override
#define ERRCODE_IO_PENDING
#define ERRCODE_IO_TOOMANYOPENFILES
#define ERRCODE_IO_ALREADYEXISTS
#define ERRCODE_IO_INVALIDCHAR
#define ERRCODE_IO_CANTREAD
#define ERRCODE_IO_INVALIDLENGTH
virtual com::sun::star::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override