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 
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/task/DocumentMacroConfirmationRequest.hpp>
31 #include <com/sun/star/task/InteractionHandler.hpp>
32 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
33 #include <com/sun/star/ucb/InteractiveNetworkOffLineException.hpp>
34 
35 #include <com/sun/star/ucb/InteractiveIOException.hpp>
36 #include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
37 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
38 #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
39 
40 #include <com/sun/star/task/DocumentPasswordRequest2.hpp>
41 #include <com/sun/star/task/DocumentMSPasswordRequest2.hpp>
42 
43 #include <com/sun/star/document/FilterOptionsRequest.hpp>
44 
45 #include "../../inc/lib/init.hxx"
46 
47 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
48 #include <sfx2/lokhelper.hxx>
49 #include <sfx2/viewsh.hxx>
50 #include <vcl/svapp.hxx>
51 
52 #include <tools/json_writer.hxx>
53 
54 using namespace com::sun::star;
55 
57  const OString& rCommand,
58  desktop::LibLibreOffice_Impl *const pLOKit,
59  desktop::LibLODocument_Impl *const pLOKDocument)
60  : m_pLOKit(pLOKit)
61  , m_pLOKDocument(pLOKDocument)
62  , m_command(rCommand)
63  , m_usePassword(false)
64 {
65  assert(m_pLOKit);
66 }
67 
69 {
70 }
71 
73 {
74  return "com.sun.star.comp.uui.LOKInteractionHandler";
75 }
76 
77 sal_Bool SAL_CALL LOKInteractionHandler::supportsService(OUString const & rServiceName)
78 {
79  return cppu::supportsService(this, rServiceName);
80 }
81 
82 uno::Sequence< OUString > SAL_CALL LOKInteractionHandler::getSupportedServiceNames()
83 {
84  return { "com.sun.star.task.InteractionHandler",
85  // added to indicate support for configuration.backend.MergeRecoveryRequest
86  "com.sun.star.configuration.backend.InteractionHandler",
87  // for backwards compatibility
88  "com.sun.star.uui.InteractionHandler" };
89 }
90 
91 void SAL_CALL LOKInteractionHandler::initialize(uno::Sequence<uno::Any> const & /*rArguments*/)
92 {
93 }
94 
96  uno::Reference<task::XInteractionRequest> const & xRequest)
97 {
98  // just do the same thing in both cases
99  handleInteractionRequest(xRequest);
100 }
101 
102 void LOKInteractionHandler::postError(css::task::InteractionClassification classif, const char* kind, ErrCode code, const OUString &message)
103 {
104  std::string classification = "error";
105  switch (classif)
106  {
107  case task::InteractionClassification_ERROR: break;
108  case task::InteractionClassification_WARNING: classification = "warning"; break;
109  case task::InteractionClassification_INFO: classification = "info"; break;
110  case task::InteractionClassification_QUERY: classification = "query"; break;
111  default: assert(false); break;
112  }
113 
114  // create the JSON representation
115  tools::JsonWriter aJson;
116  aJson.put("classification", classification);
117  aJson.put("cmd", m_command.getStr());
118  aJson.put("kind", kind);
119  aJson.put("code", static_cast<sal_uInt32>(code));
120  aJson.put("message", message.toUtf8());
121 
122  std::size_t nView = SfxViewShell::Current() ? SfxLokHelper::getView() : 0;
124  m_pLOKDocument->mpCallbackFlushHandlers[nView]->queue(LOK_CALLBACK_ERROR, aJson.extractAsOString().getStr());
125  else if (m_pLOKit->mpCallback)
126  m_pLOKit->mpCallback(LOK_CALLBACK_ERROR, aJson.extractAsOString().getStr(), m_pLOKit->mpCallbackData);
127 }
128 
129 namespace {
130 
132 void selectApproved(uno::Sequence<uno::Reference<task::XInteractionContinuation>> const &rContinuations)
133 {
134  for (auto const & c : rContinuations)
135  {
136  uno::Reference<task::XInteractionApprove> xApprove(c, uno::UNO_QUERY);
137  if (xApprove.is())
138  xApprove->select();
139  }
140 }
141 
142 }
143 
144 bool LOKInteractionHandler::handleIOException(const css::uno::Sequence<css::uno::Reference<css::task::XInteractionContinuation>> &rContinuations, const css::uno::Any& rRequest)
145 {
146  ucb::InteractiveIOException aIoException;
147  if (!(rRequest >>= aIoException))
148  return false;
149 
150  static ErrCode const aErrorCode[int(ucb::IOErrorCode_WRONG_VERSION) + 1] =
151  {
188  };
189 
190  postError(aIoException.Classification, "io", aErrorCode[static_cast<int>(aIoException.Code)], "");
191  selectApproved(rContinuations);
192 
193  return true;
194 }
195 
196 bool LOKInteractionHandler::handleNetworkException(const uno::Sequence<uno::Reference<task::XInteractionContinuation>> &rContinuations, const uno::Any &rRequest)
197 {
198  ucb::InteractiveNetworkException aNetworkException;
199  if (!(rRequest >>= aNetworkException))
200  return false;
201 
202  ErrCode nErrorCode;
203  OUString aMessage;
204 
205  ucb::InteractiveNetworkOffLineException aOffLineException;
206  ucb::InteractiveNetworkResolveNameException aResolveNameException;
207  ucb::InteractiveNetworkConnectException aConnectException;
208  ucb::InteractiveNetworkReadException aReadException;
209  ucb::InteractiveNetworkWriteException aWriteException;
210  if (rRequest >>= aOffLineException)
211  {
212  nErrorCode = ERRCODE_INET_OFFLINE;
213  }
214  else if (rRequest >>= aResolveNameException)
215  {
216  nErrorCode = ERRCODE_INET_NAME_RESOLVE;
217  aMessage = aResolveNameException.Server;
218  }
219  else if (rRequest >>= aConnectException)
220  {
221  nErrorCode = ERRCODE_INET_CONNECT;
222  aMessage = aConnectException.Server;
223  }
224  else if (rRequest >>= aReadException)
225  {
226  nErrorCode = ERRCODE_INET_READ;
227  aMessage = aReadException.Diagnostic;
228  }
229  else if (rRequest >>= aWriteException)
230  {
231  nErrorCode = ERRCODE_INET_WRITE;
232  aMessage = aWriteException.Diagnostic;
233  }
234  else
235  {
236  nErrorCode = ERRCODE_INET_GENERAL;
237  }
238 
239  postError(aNetworkException.Classification, "network", nErrorCode, aMessage);
240  selectApproved(rContinuations);
241 
242  return true;
243 }
244 
245 bool LOKInteractionHandler::handlePasswordRequest(const uno::Sequence<uno::Reference<task::XInteractionContinuation>> &rContinuations, const uno::Any &rRequest)
246 {
247  bool bPasswordRequestFound = false;
248  bool bIsRequestPasswordToModify = false;
249 
250  OString sUrl;
251 
252  task::DocumentPasswordRequest passwordRequest;
253  if (rRequest >>= passwordRequest)
254  {
255  bIsRequestPasswordToModify = false;
256  sUrl = passwordRequest.Name.toUtf8();
257  bPasswordRequestFound = true;
258  }
259 
260  task::DocumentPasswordRequest2 passwordRequest2;
261  if (rRequest >>= passwordRequest2)
262  {
263  bIsRequestPasswordToModify = passwordRequest2.IsRequestPasswordToModify;
264  sUrl = passwordRequest2.Name.toUtf8();
265  bPasswordRequestFound = true;
266  }
267 
268  task::DocumentMSPasswordRequest2 passwordMSRequest;
269  if (rRequest >>= passwordMSRequest)
270  {
271  bIsRequestPasswordToModify = passwordMSRequest.IsRequestPasswordToModify;
272  sUrl = passwordMSRequest.Name.toUtf8();
273  bPasswordRequestFound = true;
274  }
275 
276  if (!bPasswordRequestFound)
277  return false;
278 
279  if (m_pLOKit->mpCallback &&
280  m_pLOKit->hasOptionalFeature(bIsRequestPasswordToModify ? LOK_FEATURE_DOCUMENT_PASSWORD_TO_MODIFY
281  : LOK_FEATURE_DOCUMENT_PASSWORD))
282  {
283  // release SolarMutex, so the callback handler, which may run in another thread,
284  // can acquire it in 'lo_setDocumentPassword'
285  SolarMutexReleaser aReleaser;
286  m_pLOKit->mpCallback(bIsRequestPasswordToModify ? LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY
287  : LOK_CALLBACK_DOCUMENT_PASSWORD,
288  sUrl.getStr(),
290 
291  // block until SetPassword is called
292  m_havePassword.wait();
293  m_havePassword.reset();
294  }
295 
296  for (auto const & cont : rContinuations)
297  {
298  if (m_usePassword)
299  {
300  if (bIsRequestPasswordToModify)
301  {
302  uno::Reference<task::XInteractionPassword2> const xIPW2(cont, uno::UNO_QUERY);
303  xIPW2->setPasswordToModify(m_Password);
304  xIPW2->select();
305  }
306  else
307  {
308  uno::Reference<task::XInteractionPassword> const xIPW(cont, uno::UNO_QUERY);
309  if (xIPW.is())
310  {
311  xIPW->setPassword(m_Password);
312  xIPW->select();
313  }
314  }
315  }
316  else
317  {
318  if (bIsRequestPasswordToModify)
319  {
320  uno::Reference<task::XInteractionPassword2> const xIPW2(cont, uno::UNO_QUERY);
321  xIPW2->setRecommendReadOnly(true);
322  xIPW2->select();
323  }
324  else
325  {
326  uno::Reference<task::XInteractionAbort> const xAbort(cont, uno::UNO_QUERY);
327  if (xAbort.is())
328  {
329  xAbort->select();
330  }
331  }
332  }
333  }
334  return true;
335 }
336 
337 bool LOKInteractionHandler::handleMacroConfirmationRequest(const uno::Reference<task::XInteractionRequest>& xRequest)
338 {
339  uno::Any const request(xRequest->getRequest());
340 
341  task::DocumentMacroConfirmationRequest aConfirmRequest;
342  if (request >>= aConfirmRequest)
343  {
344  auto xInteraction(task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), nullptr));
345 
346  if (xInteraction.is())
347  xInteraction->handleInteractionRequest(xRequest);
348 
349  return true;
350  }
351  return false;
352 }
353 
354 bool LOKInteractionHandler::handleFilterOptionsRequest(const uno::Reference<task::XInteractionRequest>& xRequest)
355 {
356  document::FilterOptionsRequest aFilterOptionsRequest;
357  uno::Any const request(xRequest->getRequest());
358  if (request >>= aFilterOptionsRequest)
359  {
360  uno::Reference< task::XInteractionHandler2 > xInteraction(
361  task::InteractionHandler::createWithParent(
363 
364  if (xInteraction.is())
365  xInteraction->handleInteractionRequest(xRequest);
366 
367  return true;
368  }
369  return false;
370 }
371 
373  const uno::Reference<task::XInteractionRequest>& xRequest)
374 {
375  uno::Sequence<uno::Reference<task::XInteractionContinuation>> const &rContinuations = xRequest->getContinuations();
376  uno::Any const request(xRequest->getRequest());
377 
378  if (handleIOException(rContinuations, request))
379  return true;
380 
381  if (handleNetworkException(rContinuations, request))
382  return true;
383 
384  if (handlePasswordRequest(rContinuations, request))
385  return true;
386 
387  if (handleFilterOptionsRequest(xRequest))
388  return true;
389 
390  if (handleMacroConfirmationRequest(xRequest))
391  return true;
392 
393  // TODO: perform more interactions 'for real' like the above
394  selectApproved(rContinuations);
395 
396  return true;
397 }
398 
399 void LOKInteractionHandler::SetPassword(char const*const pPassword)
400 {
401  if (pPassword)
402  {
403  m_Password = OUString(pPassword, strlen(pPassword), RTL_TEXTENCODING_UTF8);
404  m_usePassword = true;
405  }
406  else
407  {
408  m_usePassword = false;
409  }
410  m_havePassword.set();
411 }
412 
413 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OString extractAsOString()
#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
static bool handleFilterOptionsRequest(const ::com::sun::star::uno::Reference<::com::sun::star::task::XInteractionRequest > &Request)
#define ERRCODE_IO_GENERAL
std::map< size_t, std::shared_ptr< CallbackFlushHandler > > mpCallbackFlushHandlers
Definition: init.hxx:202
LibreOfficeKitCallback mpCallback
Definition: init.hxx:215
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
void put(const char *pPropName, const OUString &rPropValue)
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:223
#define ERRCODE_INET_NAME_RESOLVE
static int getView(const SfxViewShell *pViewShell=nullptr)
virtual void SAL_CALL initialize(com::sun::star::uno::Sequence< com::sun::star::uno::Any > const &rArguments) override
Reference< XComponentContext > getProcessComponentContext()
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
static bool handleMacroConfirmationRequest(const css::uno::Reference< css::task::XInteractionRequest > &xRequest)
#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