summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Holesovsky <kendy@collabora.com>2016-02-02 22:59:34 +0100
committerJan Holesovsky <kendy@collabora.com>2016-02-03 10:39:35 +0100
commit64c1690fa31937bb4adfe0eb7beb42f105841c3b (patch)
tree849661bb232e1a63054460a36bc6d96d5f42193c
parent0fa0bc66e2010d01947671022926c3ae920fbf11 (diff)
lok interaction handler: Add handling of io and network errors.
Change-Id: If7c84a7b24f2072439718fb0c473b73243f2ecc1
-rw-r--r--desktop/source/lib/init.cxx39
-rw-r--r--desktop/source/lib/lokinteractionhandler.cxx194
-rw-r--r--desktop/source/lib/lokinteractionhandler.hxx32
-rw-r--r--include/LibreOfficeKit/LibreOfficeKitEnums.h14
-rw-r--r--libreofficekit/source/gtk/lokdocview.cxx21
5 files changed, 267 insertions, 33 deletions
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 0fbece04b7f1..c4d445091e00 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -271,7 +271,7 @@ static OUString getAbsoluteURL(const char* pURL)
return OUString();
}
-static void jsonToPropertyValues(const char* pJSON, uno::Sequence<beans::PropertyValue>& rPropertyValues)
+static std::vector<beans::PropertyValue> jsonToPropertyValuesVector(const char* pJSON)
{
std::vector<beans::PropertyValue> aArguments;
if (pJSON)
@@ -298,11 +298,11 @@ static void jsonToPropertyValues(const char* pJSON, uno::Sequence<beans::Propert
else if (rType == "unsigned short")
aValue.Value <<= static_cast<sal_uInt16>(OString(rValue.c_str()).toUInt32());
else
- SAL_WARN("desktop.lib", "jsonToPropertyValues: unhandled type '"<<rType<<"'");
+ SAL_WARN("desktop.lib", "jsonToPropertyValuesVector: unhandled type '"<<rType<<"'");
aArguments.push_back(aValue);
}
}
- rPropertyValues = comphelper::containerToSequence(aArguments);
+ return aArguments;
}
extern "C"
@@ -549,7 +549,7 @@ static LibreOfficeKitDocument* lo_documentLoadWithOptions(LibreOfficeKit* pThis,
beans::PropertyState_DIRECT_VALUE);
rtl::Reference<LOKInteractionHandler> const pInteraction(
- new LOKInteractionHandler(::comphelper::getProcessComponentContext(), pLib));
+ new LOKInteractionHandler(::comphelper::getProcessComponentContext(), "load", pLib));
auto const pair(pLib->mInteractionMap.insert(std::make_pair(aURL.toUtf8(), pInteraction)));
uno::Reference<task::XInteractionHandler2> const xInteraction(pInteraction.get());
aFilterOptions[1].Name = "InteractionHandler";
@@ -1034,9 +1034,9 @@ static void doc_initializeForRendering(LibreOfficeKitDocument* pThis,
if (pDoc)
{
doc_iniUnoCommands();
- uno::Sequence<beans::PropertyValue> aPropertyValues;
- jsonToPropertyValues(pArguments, aPropertyValues);
- pDoc->initializeForTiledRendering(aPropertyValues);
+
+ pDoc->initializeForTiledRendering(
+ comphelper::containerToSequence(jsonToPropertyValuesVector(pArguments)));
}
}
@@ -1126,20 +1126,33 @@ public:
static void doc_postUnoCommand(LibreOfficeKitDocument* pThis, const char* pCommand, const char* pArguments, bool bNotifyWhenFinished)
{
OUString aCommand(pCommand, strlen(pCommand), RTL_TEXTENCODING_UTF8);
+ LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
- uno::Sequence<beans::PropertyValue> aPropertyValues;
- jsonToPropertyValues(pArguments, aPropertyValues);
- bool bResult = false;
+ std::vector<beans::PropertyValue> aPropertyValuesVector(jsonToPropertyValuesVector(pArguments));
- LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
+ // handle potential interaction
+ if (aCommand == ".uno:Save")
+ {
+ rtl::Reference<LOKInteractionHandler> const pInteraction(
+ new LOKInteractionHandler(::comphelper::getProcessComponentContext(), "save", gImpl, pDocument));
+ uno::Reference<task::XInteractionHandler2> const xInteraction(pInteraction.get());
+
+ beans::PropertyValue aValue;
+ aValue.Name = "InteractionHandler";
+ aValue.Value <<= xInteraction;
+
+ aPropertyValuesVector.push_back(aValue);
+ }
+
+ bool bResult = false;
if (bNotifyWhenFinished && pDocument->mpCallback)
{
- bResult = comphelper::dispatchCommand(aCommand, aPropertyValues,
+ bResult = comphelper::dispatchCommand(aCommand, comphelper::containerToSequence(aPropertyValuesVector),
new DispatchResultListener(pCommand, pDocument->mpCallback, pDocument->mpCallbackData));
}
else
- bResult = comphelper::dispatchCommand(aCommand, aPropertyValues);
+ bResult = comphelper::dispatchCommand(aCommand, comphelper::containerToSequence(aPropertyValuesVector));
if (!bResult)
{
diff --git a/desktop/source/lib/lokinteractionhandler.cxx b/desktop/source/lib/lokinteractionhandler.cxx
index 86f521ee3367..a4a60c20bc82 100644
--- a/desktop/source/lib/lokinteractionhandler.cxx
+++ b/desktop/source/lib/lokinteractionhandler.cxx
@@ -19,12 +19,21 @@
#include "lokinteractionhandler.hxx"
+#include <boost/property_tree/json_parser.hpp>
+
#include <rtl/ref.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <com/sun/star/task/XInteractionAbort.hpp>
#include <com/sun/star/task/XInteractionApprove.hpp>
#include <com/sun/star/task/XInteractionPassword2.hpp>
+#include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
+#include <com/sun/star/ucb/InteractiveNetworkOffLineException.hpp>
+
+#include <com/sun/star/ucb/InteractiveIOException.hpp>
+#include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
+#include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
+#include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
#define LOK_USE_UNSTABLE_API
#include <../../inc/lib/init.hxx>
@@ -35,8 +44,12 @@ using namespace com::sun::star;
LOKInteractionHandler::LOKInteractionHandler(
uno::Reference<uno::XComponentContext> const & /*rxContext*/,
- desktop::LibLibreOffice_Impl *const pLOKit)
+ const OString& rCommand,
+ desktop::LibLibreOffice_Impl *const pLOKit,
+ desktop::LibLODocument_Impl *const pLOKDocument)
: m_pLOKit(pLOKit)
+ , m_pLOKDocument(pLOKDocument)
+ , m_command(rCommand)
, m_usePassword(false)
{
assert(m_pLOKit);
@@ -79,8 +92,157 @@ throw (uno::RuntimeException, std::exception)
handleInteractionRequest(xRequest);
}
-sal_Bool LOKInteractionHandler::handlePasswordRequest(const uno::Sequence<uno::Reference<task::XInteractionContinuation>> &rContinuations, const task::DocumentPasswordRequest2& passwordRequest)
+void LOKInteractionHandler::postError(css::task::InteractionClassification classif, const char* kind, ErrCode code, const OUString &message)
{
+ const char *classification = "error";
+ switch (classif)
+ {
+ case task::InteractionClassification_ERROR: break;
+ case task::InteractionClassification_WARNING: classification = "warning"; break;
+ case task::InteractionClassification_INFO: classification = "info"; break;
+ case task::InteractionClassification_QUERY: classification = "query"; break;
+ default: assert(false); break;
+ }
+
+ // create the JSON representation
+ boost::property_tree::ptree aTree;
+ aTree.put("classification", classification);
+ aTree.put("cmd", m_command.getStr());
+ aTree.put("kind", kind);
+ aTree.put("code", code);
+ aTree.put("message", message.toUtf8());
+
+ std::stringstream aStream;
+ boost::property_tree::write_json(aStream, aTree);
+
+ if (m_pLOKDocument)
+ m_pLOKDocument->mpCallback(LOK_CALLBACK_ERROR, aStream.str().c_str(), m_pLOKDocument->mpCallbackData);
+ else
+ m_pLOKit->mpCallback(LOK_CALLBACK_ERROR, aStream.str().c_str(), m_pLOKit->mpCallbackData);
+}
+
+namespace {
+
+/// Just approve the interaction.
+void selectApproved(uno::Sequence<uno::Reference<task::XInteractionContinuation>> const &rContinuations)
+{
+ for (sal_Int32 i = 0; i < rContinuations.getLength(); ++i)
+ {
+ uno::Reference<task::XInteractionApprove> xApprove(rContinuations[i], uno::UNO_QUERY);
+ if (xApprove.is())
+ xApprove->select();
+ }
+}
+
+}
+
+bool LOKInteractionHandler::handleIOException(const css::uno::Sequence<css::uno::Reference<css::task::XInteractionContinuation>> &rContinuations, const css::uno::Any& rRequest)
+{
+ ucb::InteractiveIOException aIoException;
+ if (!(rRequest >>= aIoException))
+ return false;
+
+ static ErrCode const aErrorCode[ucb::IOErrorCode_WRONG_VERSION + 1] =
+ {
+ ERRCODE_IO_ABORT,
+ ERRCODE_IO_ACCESSDENIED,
+ ERRCODE_IO_ALREADYEXISTS,
+ ERRCODE_IO_BADCRC,
+ ERRCODE_IO_CANTCREATE,
+ ERRCODE_IO_CANTREAD,
+ ERRCODE_IO_CANTSEEK,
+ ERRCODE_IO_CANTTELL,
+ ERRCODE_IO_CANTWRITE,
+ ERRCODE_IO_CURRENTDIR,
+ ERRCODE_IO_DEVICENOTREADY,
+ ERRCODE_IO_NOTSAMEDEVICE,
+ ERRCODE_IO_GENERAL,
+ ERRCODE_IO_INVALIDACCESS,
+ ERRCODE_IO_INVALIDCHAR,
+ ERRCODE_IO_INVALIDDEVICE,
+ ERRCODE_IO_INVALIDLENGTH,
+ ERRCODE_IO_INVALIDPARAMETER,
+ ERRCODE_IO_ISWILDCARD,
+ ERRCODE_IO_LOCKVIOLATION,
+ ERRCODE_IO_MISPLACEDCHAR,
+ ERRCODE_IO_NAMETOOLONG,
+ ERRCODE_IO_NOTEXISTS,
+ ERRCODE_IO_NOTEXISTSPATH,
+ ERRCODE_IO_NOTSUPPORTED,
+ ERRCODE_IO_NOTADIRECTORY,
+ ERRCODE_IO_NOTAFILE,
+ ERRCODE_IO_OUTOFSPACE,
+ ERRCODE_IO_TOOMANYOPENFILES,
+ ERRCODE_IO_OUTOFMEMORY,
+ ERRCODE_IO_PENDING,
+ ERRCODE_IO_RECURSIVE,
+ ERRCODE_IO_UNKNOWN,
+ ERRCODE_IO_WRITEPROTECTED,
+ ERRCODE_IO_WRONGFORMAT,
+ ERRCODE_IO_WRONGVERSION,
+ };
+
+ postError(aIoException.Classification, "io", aErrorCode[aIoException.Code], "");
+ selectApproved(rContinuations);
+
+ return true;
+}
+
+bool LOKInteractionHandler::handleNetworkException(const uno::Sequence<uno::Reference<task::XInteractionContinuation>> &rContinuations, const uno::Any &rRequest)
+{
+ ucb::InteractiveNetworkException aNetworkException;
+ if (!(rRequest >>= aNetworkException))
+ return false;
+
+ ErrCode nErrorCode;
+ OUString aMessage;
+
+ ucb::InteractiveNetworkOffLineException aOffLineException;
+ ucb::InteractiveNetworkResolveNameException aResolveNameException;
+ ucb::InteractiveNetworkConnectException aConnectException;
+ ucb::InteractiveNetworkReadException aReadException;
+ ucb::InteractiveNetworkWriteException aWriteException;
+ if (rRequest >>= aOffLineException)
+ {
+ nErrorCode = ERRCODE_INET_OFFLINE;
+ }
+ else if (rRequest >>= aResolveNameException)
+ {
+ nErrorCode = ERRCODE_INET_NAME_RESOLVE;
+ aMessage = aResolveNameException.Server;
+ }
+ else if (rRequest >>= aConnectException)
+ {
+ nErrorCode = ERRCODE_INET_CONNECT;
+ aMessage = aConnectException.Server;
+ }
+ else if (rRequest >>= aReadException)
+ {
+ nErrorCode = ERRCODE_INET_READ;
+ aMessage = aReadException.Diagnostic;
+ }
+ else if (rRequest >>= aWriteException)
+ {
+ nErrorCode = ERRCODE_INET_WRITE;
+ aMessage = aWriteException.Diagnostic;
+ }
+ else
+ {
+ nErrorCode = ERRCODE_INET_GENERAL;
+ }
+
+ postError(aNetworkException.Classification, "network", nErrorCode, aMessage);
+ selectApproved(rContinuations);
+
+ return true;
+}
+
+bool LOKInteractionHandler::handlePasswordRequest(const uno::Sequence<uno::Reference<task::XInteractionContinuation>> &rContinuations, const uno::Any &rRequest)
+{
+ task::DocumentPasswordRequest2 passwordRequest;
+ if (!(rRequest >>= passwordRequest))
+ return false;
+
if (m_pLOKit->hasOptionalFeature((passwordRequest.IsRequestPasswordToModify)
? LOK_FEATURE_DOCUMENT_PASSWORD_TO_MODIFY
: LOK_FEATURE_DOCUMENT_PASSWORD))
@@ -135,28 +297,26 @@ sal_Bool LOKInteractionHandler::handlePasswordRequest(const uno::Sequence<uno::R
}
}
}
- return sal_True;
+ return true;
}
sal_Bool SAL_CALL LOKInteractionHandler::handleInteractionRequest(
- const uno::Reference<task::XInteractionRequest>& xRequest)
-throw (uno::RuntimeException, std::exception)
+ const uno::Reference<task::XInteractionRequest>& xRequest) throw (uno::RuntimeException, std::exception)
{
uno::Sequence<uno::Reference<task::XInteractionContinuation>> const &rContinuations = xRequest->getContinuations();
-
uno::Any const request(xRequest->getRequest());
- task::DocumentPasswordRequest2 passwordRequest;
- if (request >>= passwordRequest)
- return handlePasswordRequest(rContinuations, passwordRequest);
- // TODO: add LOK api that allows handling this for real, for the moment we
- // just set the interaction as 'Approved'
- for (sal_Int32 i = 0; i < rContinuations.getLength(); ++i)
- {
- uno::Reference<task::XInteractionApprove> xApprove(rContinuations[i], uno::UNO_QUERY);
- if (xApprove.is())
- xApprove->select();
- }
+ if (handleIOException(rContinuations, request))
+ return true;
+
+ if (handleNetworkException(rContinuations, request))
+ return true;
+
+ if (handlePasswordRequest(rContinuations, request))
+ return true;
+
+ // TODO: perform more interactions 'for real' like the above
+ selectApproved(rContinuations);
return sal_True;
}
diff --git a/desktop/source/lib/lokinteractionhandler.hxx b/desktop/source/lib/lokinteractionhandler.hxx
index 3c18864e5b26..4a453c3d1aa7 100644
--- a/desktop/source/lib/lokinteractionhandler.hxx
+++ b/desktop/source/lib/lokinteractionhandler.hxx
@@ -22,13 +22,18 @@
#include <osl/conditn.hxx>
#include <cppuhelper/implbase.hxx>
+#include <tools/errcode.hxx>
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/task/DocumentPasswordRequest2.hpp>
#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/ucb/InteractiveNetworkException.hpp>
-namespace desktop { struct LibLibreOffice_Impl; }
+namespace desktop {
+ struct LibLibreOffice_Impl;
+ struct LibLODocument_Impl;
+}
/** InteractionHandler is an interface that provides the user with various dialogs / error messages.
@@ -44,6 +49,11 @@ class LOKInteractionHandler: public cppu::WeakImplHelper<com::sun::star::lang::X
{
private:
desktop::LibLibreOffice_Impl * m_pLOKit;
+ desktop::LibLODocument_Impl * m_pLOKDocument;
+
+ /// Command for which we use this interaction handler (like "load", "save", "saveas", ...)
+ OString m_command;
+
OUString m_Password;
bool m_usePassword;
osl::Condition m_havePassword;
@@ -51,14 +61,30 @@ private:
LOKInteractionHandler(const LOKInteractionHandler&) SAL_DELETED_FUNCTION;
LOKInteractionHandler& operator=(const LOKInteractionHandler&) SAL_DELETED_FUNCTION;
- sal_Bool handlePasswordRequest(const css::uno::Sequence<css::uno::Reference<css::task::XInteractionContinuation>> &rContinuations, const css::task::DocumentPasswordRequest2& passwordRequest);
+ /** Call the LOK_CALLBACK_ERROR on the LOK document (if available) or LOK lib.
+
+ The error itself is a JSON message, like:
+ {
+ "classification": "error" | "warning" | "info"
+ "kind": "network" etc.
+ "code": 403 | 404 | ...
+ "message": freeform description
+ }
+ */
+ void postError(css::task::InteractionClassification classif, const char* kind, ErrCode code, const OUString &message);
+
+ bool handleIOException(const css::uno::Sequence<css::uno::Reference<css::task::XInteractionContinuation>> &rContinuations, const css::uno::Any& rRequest);
+ bool handleNetworkException(const css::uno::Sequence<css::uno::Reference<css::task::XInteractionContinuation>> &rContinuations, const css::uno::Any& rRequest);
+ bool handlePasswordRequest(const css::uno::Sequence<css::uno::Reference<css::task::XInteractionContinuation>> &rContinuations, const css::uno::Any& rRequest);
public:
void SetPassword(char const* pPassword);
explicit LOKInteractionHandler(
com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const & rxContext,
- desktop::LibLibreOffice_Impl *);
+ const OString& rCommand,
+ desktop::LibLibreOffice_Impl *,
+ desktop::LibLODocument_Impl *pLOKDocumt = nullptr);
virtual ~LOKInteractionHandler();
diff --git a/include/LibreOfficeKit/LibreOfficeKitEnums.h b/include/LibreOfficeKit/LibreOfficeKitEnums.h
index 5931f7871e50..3f2a6ea470a8 100644
--- a/include/LibreOfficeKit/LibreOfficeKitEnums.h
+++ b/include/LibreOfficeKit/LibreOfficeKitEnums.h
@@ -265,6 +265,20 @@ typedef enum
* lok::Office::setDocumentPassword().
*/
LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY,
+
+ /**
+ * An error happened.
+ *
+ * The payload returns information further identifying the error, like:
+ *
+ * {
+ * "classification": "error" | "warning" | "info"
+ * "kind": "network" etc.
+ * "code": 403 | 404 | ...
+ * "message": freeform description
+ * }
+ */
+ LOK_CALLBACK_ERROR,
}
LibreOfficeKitCallbackType;
diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index bdf3a190e2e1..cad178be2f46 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -199,6 +199,8 @@ struct LOKDocView_Impl
void searchNotFound(const std::string& rPayload);
/// LOK decided to change parts, need to update UI.
void setPart(const std::string& rPayload);
+ /// LOK got an error callback.
+ void reportError(const std::string& rPayload);
};
namespace {
@@ -935,6 +937,8 @@ const char* LOKDocView_Impl::callbackTypeToString(int nType)
return "LOK_CALLBACK_DOCUMENT_SIZE_CHANGED";
case LOK_CALLBACK_SET_PART:
return "LOK_CALLBACK_SET_PART";
+ case LOK_CALLBACK_ERROR:
+ return "LOK_CALLBACK_ERROR";
}
return 0;
}
@@ -1042,6 +1046,11 @@ gboolean LOKDocView_Impl::callbackImpl(CallbackData* pCallback)
setPart(pCallback->m_aPayload);
}
break;
+ case LOK_CALLBACK_ERROR:
+ {
+ reportError(pCallback->m_aPayload);
+ }
+ break;
default:
g_assert(false);
break;
@@ -1109,6 +1118,18 @@ void LOKDocView_Impl::setPart(const std::string& rString)
renderDocument(0);
}
+void LOKDocView_Impl::reportError(const std::string& rString)
+{
+ GtkWidget *dialog = gtk_message_dialog_new(nullptr,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "%s",
+ rString.c_str());
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+}
+
static void lok_docview_class_init( gpointer ptr )
{
LOKDocViewClass* pClass = static_cast<LOKDocViewClass *>(ptr);