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