1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "lokinteractionhandler.hxx"
22 #include <comphelper/processfactory.hxx>
23 #include <cppuhelper/supportsservice.hxx>
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>
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>
38 #include <com/sun/star/task/DocumentPasswordRequest2.hpp>
39 #include <com/sun/star/task/DocumentMSPasswordRequest2.hpp>
41 #include <com/sun/star/document/FilterOptionsRequest.hpp>
43 #include "../../inc/lib/init.hxx"
45 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
46 #include <sfx2/lokhelper.hxx>
47 #include <sfx2/viewsh.hxx>
49 #include <vcl/svapp.hxx>
51 #include <tools/json_writer.hxx>
53 using namespace com::sun::star
;
55 LOKInteractionHandler::LOKInteractionHandler(
57 desktop::LibLibreOffice_Impl
*const pLOKit
,
58 desktop::LibLODocument_Impl
*const pLOKDocument
)
60 , m_pLOKDocument(pLOKDocument
)
61 , m_command(std::move(command
))
62 , m_usePassword(false)
67 LOKInteractionHandler::~LOKInteractionHandler()
71 OUString SAL_CALL
LOKInteractionHandler::getImplementationName()
73 return "com.sun.star.comp.uui.LOKInteractionHandler";
76 sal_Bool SAL_CALL
LOKInteractionHandler::supportsService(OUString
const & rServiceName
)
78 return cppu::supportsService(this, rServiceName
);
81 uno::Sequence
< OUString
> SAL_CALL
LOKInteractionHandler::getSupportedServiceNames()
83 return { "com.sun.star.task.InteractionHandler",
84 // added to indicate support for configuration.backend.MergeRecoveryRequest
85 "com.sun.star.configuration.backend.InteractionHandler",
86 // for backwards compatibility
87 "com.sun.star.uui.InteractionHandler" };
90 void SAL_CALL
LOKInteractionHandler::initialize(uno::Sequence
<uno::Any
> const & /*rArguments*/)
94 void SAL_CALL
LOKInteractionHandler::handle(
95 uno::Reference
<task::XInteractionRequest
> const & xRequest
)
97 // just do the same thing in both cases
98 handleInteractionRequest(xRequest
);
101 void LOKInteractionHandler::postError(css::task::InteractionClassification classif
, const char* kind
, ErrCode code
, const OUString
&message
)
103 std::string classification
= "error";
106 case task::InteractionClassification_ERROR
: break;
107 case task::InteractionClassification_WARNING
: classification
= "warning"; break;
108 case task::InteractionClassification_INFO
: classification
= "info"; break;
109 case task::InteractionClassification_QUERY
: classification
= "query"; break;
110 default: assert(false); break;
113 // create the JSON representation
114 tools::JsonWriter aJson
;
115 aJson
.put("classification", classification
);
116 aJson
.put("cmd", m_command
.getStr());
117 aJson
.put("kind", kind
);
118 aJson
.put("code", static_cast<sal_uInt32
>(code
));
119 aJson
.put("message", message
.toUtf8());
121 std::size_t nView
= SfxViewShell::Current() ? SfxLokHelper::getView() : 0;
122 if (m_pLOKDocument
&& m_pLOKDocument
->mpCallbackFlushHandlers
.count(nView
))
123 m_pLOKDocument
->mpCallbackFlushHandlers
[nView
]->queue(LOK_CALLBACK_ERROR
, aJson
.finishAndGetAsOString());
124 else if (m_pLOKit
->mpCallback
)
125 m_pLOKit
->mpCallback(LOK_CALLBACK_ERROR
, aJson
.finishAndGetAsOString().getStr(), m_pLOKit
->mpCallbackData
);
130 /// Just approve the interaction.
131 void selectApproved(uno::Sequence
<uno::Reference
<task::XInteractionContinuation
>> const &rContinuations
)
133 for (auto const & c
: rContinuations
)
135 uno::Reference
<task::XInteractionApprove
> xApprove(c
, uno::UNO_QUERY
);
143 bool LOKInteractionHandler::handleIOException(const css::uno::Sequence
<css::uno::Reference
<css::task::XInteractionContinuation
>> &rContinuations
, const css::uno::Any
& rRequest
)
145 ucb::InteractiveIOException aIoException
;
146 if (!(rRequest
>>= aIoException
))
149 static ErrCode
const aErrorCode
[int(ucb::IOErrorCode_WRONG_VERSION
) + 1] =
152 ERRCODE_IO_ACCESSDENIED
,
153 ERRCODE_IO_ALREADYEXISTS
,
155 ERRCODE_IO_CANTCREATE
,
159 ERRCODE_IO_CANTWRITE
,
160 ERRCODE_IO_CURRENTDIR
,
161 ERRCODE_IO_DEVICENOTREADY
,
162 ERRCODE_IO_NOTSAMEDEVICE
,
164 ERRCODE_IO_INVALIDACCESS
,
165 ERRCODE_IO_INVALIDCHAR
,
166 ERRCODE_IO_INVALIDDEVICE
,
167 ERRCODE_IO_INVALIDLENGTH
,
168 ERRCODE_IO_INVALIDPARAMETER
,
169 ERRCODE_IO_ISWILDCARD
,
170 ERRCODE_IO_LOCKVIOLATION
,
171 ERRCODE_IO_MISPLACEDCHAR
,
172 ERRCODE_IO_NAMETOOLONG
,
173 ERRCODE_IO_NOTEXISTS
,
174 ERRCODE_IO_NOTEXISTSPATH
,
175 ERRCODE_IO_NOTSUPPORTED
,
176 ERRCODE_IO_NOTADIRECTORY
,
178 ERRCODE_IO_OUTOFSPACE
,
179 ERRCODE_IO_TOOMANYOPENFILES
,
180 ERRCODE_IO_OUTOFMEMORY
,
182 ERRCODE_IO_RECURSIVE
,
184 ERRCODE_IO_WRITEPROTECTED
,
185 ERRCODE_IO_WRONGFORMAT
,
186 ERRCODE_IO_WRONGVERSION
,
189 postError(aIoException
.Classification
, "io", aErrorCode
[static_cast<int>(aIoException
.Code
)], "");
190 selectApproved(rContinuations
);
195 bool LOKInteractionHandler::handleNetworkException(const uno::Sequence
<uno::Reference
<task::XInteractionContinuation
>> &rContinuations
, const uno::Any
&rRequest
)
197 ucb::InteractiveNetworkException aNetworkException
;
198 if (!(rRequest
>>= aNetworkException
))
204 ucb::InteractiveNetworkOffLineException aOffLineException
;
205 ucb::InteractiveNetworkResolveNameException aResolveNameException
;
206 ucb::InteractiveNetworkConnectException aConnectException
;
207 ucb::InteractiveNetworkReadException aReadException
;
208 ucb::InteractiveNetworkWriteException aWriteException
;
209 if (rRequest
>>= aOffLineException
)
211 nErrorCode
= ERRCODE_INET_OFFLINE
;
213 else if (rRequest
>>= aResolveNameException
)
215 nErrorCode
= ERRCODE_INET_NAME_RESOLVE
;
216 aMessage
= aResolveNameException
.Server
;
218 else if (rRequest
>>= aConnectException
)
220 nErrorCode
= ERRCODE_INET_CONNECT
;
221 aMessage
= aConnectException
.Server
;
223 else if (rRequest
>>= aReadException
)
225 nErrorCode
= ERRCODE_INET_READ
;
226 aMessage
= aReadException
.Diagnostic
;
228 else if (rRequest
>>= aWriteException
)
230 nErrorCode
= ERRCODE_INET_WRITE
;
231 aMessage
= aWriteException
.Diagnostic
;
235 nErrorCode
= ERRCODE_INET_GENERAL
;
238 postError(aNetworkException
.Classification
, "network", nErrorCode
, aMessage
);
239 selectApproved(rContinuations
);
244 bool LOKInteractionHandler::handlePasswordRequest(const uno::Sequence
<uno::Reference
<task::XInteractionContinuation
>> &rContinuations
, const uno::Any
&rRequest
)
246 bool bPasswordRequestFound
= false;
247 bool bIsRequestPasswordToModify
= false;
251 task::DocumentPasswordRequest passwordRequest
;
252 if (rRequest
>>= passwordRequest
)
254 bIsRequestPasswordToModify
= false;
255 sUrl
= passwordRequest
.Name
.toUtf8();
256 bPasswordRequestFound
= true;
259 task::DocumentPasswordRequest2 passwordRequest2
;
260 if (rRequest
>>= passwordRequest2
)
262 bIsRequestPasswordToModify
= passwordRequest2
.IsRequestPasswordToModify
;
263 sUrl
= passwordRequest2
.Name
.toUtf8();
264 bPasswordRequestFound
= true;
267 task::DocumentMSPasswordRequest2 passwordMSRequest
;
268 if (rRequest
>>= passwordMSRequest
)
270 bIsRequestPasswordToModify
= passwordMSRequest
.IsRequestPasswordToModify
;
271 sUrl
= passwordMSRequest
.Name
.toUtf8();
272 bPasswordRequestFound
= true;
275 if (!bPasswordRequestFound
)
278 if (m_pLOKit
->mpCallback
&&
279 m_pLOKit
->hasOptionalFeature(bIsRequestPasswordToModify
? LOK_FEATURE_DOCUMENT_PASSWORD_TO_MODIFY
280 : LOK_FEATURE_DOCUMENT_PASSWORD
))
282 // release SolarMutex, so the callback handler, which may run in another thread,
283 // can acquire it in 'lo_setDocumentPassword'
284 SolarMutexReleaser aReleaser
;
285 m_pLOKit
->mpCallback(bIsRequestPasswordToModify
? LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY
286 : LOK_CALLBACK_DOCUMENT_PASSWORD
,
288 m_pLOKit
->mpCallbackData
);
290 // block until SetPassword is called
291 m_havePassword
.wait();
292 m_havePassword
.reset();
295 for (auto const & cont
: rContinuations
)
299 if (bIsRequestPasswordToModify
)
301 uno::Reference
<task::XInteractionPassword2
> const xIPW2(cont
, uno::UNO_QUERY
);
302 xIPW2
->setPasswordToModify(m_Password
);
307 uno::Reference
<task::XInteractionPassword
> const xIPW(cont
, uno::UNO_QUERY
);
310 xIPW
->setPassword(m_Password
);
317 if (bIsRequestPasswordToModify
)
319 uno::Reference
<task::XInteractionPassword2
> const xIPW2(cont
, uno::UNO_QUERY
);
320 xIPW2
->setRecommendReadOnly(true);
325 uno::Reference
<task::XInteractionAbort
> const xAbort(cont
, uno::UNO_QUERY
);
336 bool LOKInteractionHandler::handleMacroConfirmationRequest(const uno::Reference
<task::XInteractionRequest
>& xRequest
)
338 uno::Any
const request(xRequest
->getRequest());
340 task::DocumentMacroConfirmationRequest aConfirmRequest
;
341 if (request
>>= aConfirmRequest
)
343 auto xInteraction(task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), nullptr));
345 if (xInteraction
.is())
346 xInteraction
->handleInteractionRequest(xRequest
);
353 bool LOKInteractionHandler::handleFilterOptionsRequest(const uno::Reference
<task::XInteractionRequest
>& xRequest
)
355 document::FilterOptionsRequest aFilterOptionsRequest
;
356 uno::Any
const request(xRequest
->getRequest());
357 if (request
>>= aFilterOptionsRequest
)
359 uno::Reference
< task::XInteractionHandler2
> xInteraction(
360 task::InteractionHandler::createWithParent(
361 ::comphelper::getProcessComponentContext(), nullptr));
363 if (xInteraction
.is())
364 xInteraction
->handleInteractionRequest(xRequest
);
371 sal_Bool SAL_CALL
LOKInteractionHandler::handleInteractionRequest(
372 const uno::Reference
<task::XInteractionRequest
>& xRequest
)
374 uno::Sequence
<uno::Reference
<task::XInteractionContinuation
>> const &rContinuations
= xRequest
->getContinuations();
375 uno::Any
const request(xRequest
->getRequest());
377 if (handleIOException(rContinuations
, request
))
380 if (handleNetworkException(rContinuations
, request
))
383 if (handlePasswordRequest(rContinuations
, request
))
386 if (handleFilterOptionsRequest(xRequest
))
389 if (handleMacroConfirmationRequest(xRequest
))
392 // TODO: perform more interactions 'for real' like the above
393 selectApproved(rContinuations
);
398 void LOKInteractionHandler::SetPassword(char const*const pPassword
)
402 m_Password
= OUString(pPassword
, strlen(pPassword
), RTL_TEXTENCODING_UTF8
);
403 m_usePassword
= true;
407 m_usePassword
= false;
409 m_havePassword
.set();
412 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */