From fe80bd09aa8bbe1e190d91c7f85c2a8b977c1dd1 Mon Sep 17 00:00:00 2001 From: Pranav Kant Date: Wed, 27 Jan 2016 16:56:14 +0530 Subject: [PATCH 392/398] lokdocview: Handle password protected documents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-on: https://gerrit.libreoffice.org/21861 Tested-by: Jenkins Reviewed-by: Caolán McNamara Tested-by: Caolán McNamara (cherry picked from commit 18fbddcca569c109ca2f46f7d791187e672d4d83) Signed-off-by: Michael Stahl Change-Id: I606a1112c8eb4c1cc4596d6947ce1223543cc87c (cherry picked from commit 89a3c1b4d69aac447606dc6f0e661b2ef4dddc8c) --- include/LibreOfficeKit/LibreOfficeKitGtk.h | 12 +++ .../qa/gtktiledviewer/gtktiledviewer.cxx | 50 ++++++++++ libreofficekit/source/gtk/lokdocview.cxx | 109 ++++++++++++++++++++- 3 files changed, 166 insertions(+), 5 deletions(-) diff --git a/include/LibreOfficeKit/LibreOfficeKitGtk.h b/include/LibreOfficeKit/LibreOfficeKitGtk.h index e06d154f772e..1df27c106214 100644 --- a/include/LibreOfficeKit/LibreOfficeKitGtk.h +++ b/include/LibreOfficeKit/LibreOfficeKitGtk.h @@ -275,6 +275,18 @@ gboolean lok_doc_view_paste (LOKDocView* gsize nSize); /** + * lok_doc_view_set_document_password: + * @pDocView: The #LOKDocView instance + * @pUrl: the URL of the document to set password for, as sent with signal `password-required` + * @pPassword: (nullable): the password, NULL for no password + * + * Set the password for password protected documents + */ +void lok_doc_view_set_document_password (LOKDocView* pDocView, + const gchar* pURL, + const gchar* pPassword); + +/** * lok_doc_view_pixel_to_twip: * @pDocView: The #LOKDocView instance * @fInput: The value in pixels to convert to twips diff --git a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx index a21daf199fa7..3dc9f246f18e 100644 --- a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx +++ b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx @@ -462,10 +462,20 @@ static void toggleFindbar(GtkWidget* pButton, gpointer /*pItem*/) } } +static void +setLOKFeatures (GtkWidget* pDocView) +{ + g_object_set(G_OBJECT(pDocView), + "doc-password", TRUE, + "doc-password-to-modify", TRUE, + nullptr); +} + /// Common initialization, regardless if it's just a new view or a full init. static TiledWindow& setupWidgetAndCreateWindow(GtkWidget* pDocView) { setupDocView(pDocView); + setLOKFeatures(pDocView); TiledWindow aWindow; aWindow.m_pDocView = pDocView; GtkWidget* pWindow = createWindow(aWindow); @@ -797,6 +807,45 @@ static void formulaChanged(LOKDocView* pLOKDocView, char* pPayload, gpointer /*p gtk_entry_set_text(GTK_ENTRY(rWindow.m_pFormulabarEntry), pPayload); } +/// LOKDocView password is requried to open the document +static void passwordRequired(LOKDocView* pLOKDocView, gchar* pUrl, gboolean bModify, gpointer /*pData*/) +{ + GtkWidget* pPasswordDialog = gtk_dialog_new_with_buttons ("Password required", + GTK_WINDOW (gtk_widget_get_toplevel(GTK_WIDGET(pLOKDocView))), + GTK_DIALOG_MODAL, + "OK", + GTK_RESPONSE_OK, + nullptr); + g_object_set(G_OBJECT(pPasswordDialog), "resizable", FALSE, nullptr); + GtkWidget* pDialogMessageArea = gtk_dialog_get_content_area (GTK_DIALOG (pPasswordDialog)); + GtkWidget* pPasswordEntry = gtk_entry_new (); + gtk_entry_set_visibility (GTK_ENTRY(pPasswordEntry), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY(pPasswordEntry), '*'); + gtk_box_pack_end(GTK_BOX(pDialogMessageArea), pPasswordEntry, TRUE, TRUE, 2); + if (bModify) + { + GtkWidget* pSecondaryLabel = gtk_label_new ("Document requires password to edit"); + gtk_box_pack_end(GTK_BOX(pDialogMessageArea), pSecondaryLabel, TRUE, TRUE, 2); + gtk_dialog_add_button (GTK_DIALOG (pPasswordDialog), "Open as read-only", GTK_RESPONSE_ACCEPT); + } + gtk_widget_show_all(pPasswordDialog); + + gint res = gtk_dialog_run (GTK_DIALOG(pPasswordDialog)); + switch (res) + { + case GTK_RESPONSE_OK: + lok_doc_view_set_document_password (pLOKDocView, pUrl, gtk_entry_get_text(GTK_ENTRY(pPasswordEntry))); + break; + case GTK_RESPONSE_ACCEPT: + // User accepts to open this document as read-only + case GTK_RESPONSE_DELETE_EVENT: + lok_doc_view_set_document_password (pLOKDocView, pUrl, nullptr); + break; + } + + gtk_widget_destroy(pPasswordDialog); +} + static void toggleToolItem(GtkWidget* pWidget, gpointer /*pData*/) { TiledWindow& rWindow = lcl_getTiledWindow(pWidget); @@ -1254,6 +1303,7 @@ static void setupDocView(GtkWidget* pDocView) g_signal_connect(pDocView, "hyperlink-clicked", G_CALLBACK(signalHyperlink), NULL); g_signal_connect(pDocView, "cursor-changed", G_CALLBACK(cursorChanged), NULL); g_signal_connect(pDocView, "formula-changed", G_CALLBACK(formulaChanged), NULL); + g_signal_connect(pDocView, "password-required", G_CALLBACK(passwordRequired), nullptr); } int main( int argc, char* argv[] ) diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx index 960c8c1f2624..f0dd7342c1a3 100644 --- a/libreofficekit/source/gtk/lokdocview.cxx +++ b/libreofficekit/source/gtk/lokdocview.cxx @@ -65,6 +65,8 @@ struct LOKDocViewPrivateImpl glong m_nDocumentHeightTwips; /// View or edit mode. gboolean m_bEdit; + /// LOK Features + guint64 m_nLOKFeatures; /// Position and size of the visible cursor. GdkRectangle m_aVisibleCursor; /// Cursor overlay is visible or hidden (for blinking). @@ -138,6 +140,7 @@ struct LOKDocViewPrivateImpl m_nDocumentWidthTwips(0), m_nDocumentHeightTwips(0), m_bEdit(FALSE), + m_nLOKFeatures(0), m_aVisibleCursor({0, 0, 0, 0}), m_bCursorOverlayVisible(false), m_bCursorVisible(true), @@ -192,6 +195,7 @@ enum COMMAND_RESULT, FORMULA_CHANGED, TEXT_SELECTION, + PASSWORD_REQUIRED, LAST_SIGNAL }; @@ -212,6 +216,8 @@ enum PROP_DOC_HEIGHT, PROP_CAN_ZOOM_IN, PROP_CAN_ZOOM_OUT, + PROP_DOC_PASSWORD, + PROP_DOC_PASSWORD_TO_MODIFY, PROP_LAST }; @@ -311,6 +317,10 @@ callbackTypeToString (int nType) return "LOK_CALLBACK_SET_PART"; case LOK_CALLBACK_SEARCH_RESULT_SELECTION: return "LOK_CALLBACK_SEARCH_RESULT_SELECTION"; + case LOK_CALLBACK_DOCUMENT_PASSWORD: + return "LOK_CALLBACK_DOCUMENT_PASSWORD"; + case LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY: + return "LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY"; } return nullptr; } @@ -783,6 +793,7 @@ globalCallback (gpointer pData) { CallbackData* pCallback = static_cast(pData); LOKDocViewPrivate& priv = getPrivate(pCallback->m_pDocView); + gboolean bModify = false; switch (pCallback->m_nType) { @@ -804,12 +815,12 @@ globalCallback (gpointer pData) g_signal_emit (pCallback->m_pDocView, doc_view_signals[LOAD_CHANGED], 0, 1.0); } break; - case LOK_CALLBACK_DOCUMENT_PASSWORD: case LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY: + bModify = true; + case LOK_CALLBACK_DOCUMENT_PASSWORD: { char const*const pURL(pCallback->m_aPayload.c_str()); - // TODO maybe allow more passwords - priv->m_pOffice->pClass->setDocumentPassword(priv->m_pOffice, pURL, "1"); + g_signal_emit (pCallback->m_pDocView, doc_view_signals[PASSWORD_REQUIRED], 0, pURL, bModify); } break; default: @@ -1910,6 +1921,8 @@ static void lok_doc_view_set_property (GObject* object, guint propId, const GVal { LOKDocView* pDocView = LOK_DOC_VIEW (object); LOKDocViewPrivate& priv = getPrivate(pDocView); + gboolean bDocPasswordEnabled = priv->m_nLOKFeatures & LOK_FEATURE_DOCUMENT_PASSWORD; + gboolean bDocPasswordToModifyEnabled = priv->m_nLOKFeatures & LOK_FEATURE_DOCUMENT_PASSWORD_TO_MODIFY; switch (propId) { @@ -1937,6 +1950,20 @@ static void lok_doc_view_set_property (GObject* object, guint propId, const GVal case PROP_DOC_HEIGHT: priv->m_nDocumentHeightTwips = g_value_get_long (value); break; + case PROP_DOC_PASSWORD: + if (g_value_get_boolean (value) != bDocPasswordEnabled) + { + priv->m_nLOKFeatures = priv->m_nLOKFeatures ^ LOK_FEATURE_DOCUMENT_PASSWORD; + priv->m_pOffice->pClass->setOptionalFeatures(priv->m_pOffice, priv->m_nLOKFeatures); + } + break; + case PROP_DOC_PASSWORD_TO_MODIFY: + if ( g_value_get_boolean (value) != bDocPasswordToModifyEnabled) + { + priv->m_nLOKFeatures = priv->m_nLOKFeatures ^ LOK_FEATURE_DOCUMENT_PASSWORD_TO_MODIFY; + priv->m_pOffice->pClass->setOptionalFeatures(priv->m_pOffice, priv->m_nLOKFeatures); + } + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propId, pspec); } @@ -1985,6 +2012,12 @@ static void lok_doc_view_get_property (GObject* object, guint propId, GValue *va case PROP_CAN_ZOOM_OUT: g_value_set_boolean (value, priv->m_bCanZoomOut); break; + case PROP_DOC_PASSWORD: + g_value_set_boolean (value, priv->m_nLOKFeatures & LOK_FEATURE_DOCUMENT_PASSWORD); + break; + case PROP_DOC_PASSWORD_TO_MODIFY: + g_value_set_boolean (value, priv->m_nLOKFeatures & LOK_FEATURE_DOCUMENT_PASSWORD_TO_MODIFY); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propId, pspec); } @@ -2034,8 +2067,6 @@ static gboolean lok_doc_view_initable_init (GInitable *initable, GCancellable* / return FALSE; } -// priv->m_pOffice->pClass->setOptionalFeatures(priv->m_pOffice, LOK_FEATURE_DOCUMENT_PASSWORD|LOK_FEATURE_DOCUMENT_PASSWORD_TO_MODIFY); - return TRUE; } @@ -2223,6 +2254,33 @@ static void lok_doc_view_class_init (LOKDocViewClass* pClass) static_cast(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + /** + * LOKDocView:doc-password: + * + * Set it to true if client supports providing password for viewing + * password protected documents + */ + properties[PROP_DOC_PASSWORD] = + g_param_spec_boolean("doc-password", + "Document password capability", + "Whether client supports providing document passwords", + FALSE, + static_cast(G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS)); + + /** + * LOKDocView:doc-password-to-modify: + * + * Set it to true if client supports providing password for edit-protected documents + */ + properties[PROP_DOC_PASSWORD_TO_MODIFY] = + g_param_spec_boolean("doc-password-to-modify", + "Edit document password capability", + "Whether the client supports providing passwords to edit documents", + FALSE, + static_cast(G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS)); + g_object_class_install_properties(pGObjectClass, PROP_LAST, properties); /** @@ -2409,6 +2467,37 @@ static void lok_doc_view_class_init (LOKDocViewClass* pClass) g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + + /** + * LOKDocView::password-required: + * @pDocView: the #LOKDocView on which the signal is emitted + * @pUrl: URL of the document for which password is required + * @bModify: whether password id required to modify the document + * This is true when password is required to edit the document, + * while it can still be viewed without password. In such cases, provide a NULL + * password for read-only access to the document. + * If false, password is required for opening the document, and document + * cannot be opened without providing a valid password. + * + * Password must be provided by calling lok_doc_view_set_document_password + * function with pUrl as provided by the callback. + * + * Upon entering a invalid password, another `password-required` signal is + * emitted. + * Upon entering a valid password, document starts to load. + * Upon entering a NULL password: if bModify is %TRUE, document starts to + * open in view-only mode, else loading of document is aborted. + */ + doc_view_signals[PASSWORD_REQUIRED] = + g_signal_new("password-required", + G_TYPE_FROM_CLASS(pGObjectClass), + G_SIGNAL_RUN_FIRST, + 0, + nullptr, nullptr, + g_cclosure_marshal_generic, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_BOOLEAN); } SAL_DLLPUBLIC_EXPORT GtkWidget* @@ -2786,6 +2875,16 @@ lok_doc_view_paste (LOKDocView* pDocView, return ret; } +SAL_DLLPUBLIC_EXPORT void +lok_doc_view_set_document_password (LOKDocView* pDocView, + const gchar* pURL, + const gchar* pPassword) +{ + LOKDocViewPrivate& priv = getPrivate(pDocView); + + priv->m_pOffice->pClass->setDocumentPassword(priv->m_pOffice, pURL, pPassword); +} + SAL_DLLPUBLIC_EXPORT gfloat lok_doc_view_pixel_to_twip (LOKDocView* pDocView, float fInput) { -- 2.12.0