glib/CMakeLists.txt | 6 glib/demo/CMakeLists.txt | 1 glib/demo/main.c | 4 glib/demo/signature.c | 437 ++++++++++++++ glib/demo/signature.h | 31 + glib/poppler-document.cc | 98 +++ glib/poppler-document.h | 5 glib/poppler-form-field.cc | 1088 ++++++++++++++++++++++++++++++++++++ glib/poppler-form-field.h | 114 +++ glib/poppler.h | 5 glib/reference/poppler-sections.txt | 51 + glib/reference/poppler.types | 2 12 files changed, 1840 insertions(+), 2 deletions(-)
New commits: commit bdd922b7caaa965828e0e45a6cde0b1585c9740e Author: Jan-Michael Brummer <[email protected]> Date: Wed Oct 5 08:20:13 2022 +0200 Signatures: Add signing API to glib part Rectangle corrections by Marek Kasik diff --git a/glib/CMakeLists.txt b/glib/CMakeLists.txt index 52e8687a..4e17440c 100644 --- a/glib/CMakeLists.txt +++ b/glib/CMakeLists.txt @@ -99,6 +99,10 @@ target_link_libraries(poppler-glib poppler PkgConfig::GLIB2 ${CAIRO_LIBRARIES} F target_include_directories(poppler-glib SYSTEM PRIVATE ${CAIRO_INCLUDE_DIRS}) install(TARGETS poppler-glib RUNTIME DESTINATION bin LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +if (ENABLE_NSS3) + target_include_directories(poppler-glib SYSTEM PRIVATE ${NSS3_INCLUDE_DIRS}) +endif() + install(FILES ${poppler_glib_public_headers} ${CMAKE_CURRENT_BINARY_DIR}/poppler-enums.h @@ -150,3 +154,5 @@ endif () if(ENABLE_GTK_DOC) add_subdirectory(reference) endif() + +check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO) \ No newline at end of file diff --git a/glib/demo/CMakeLists.txt b/glib/demo/CMakeLists.txt index 4c1ae9a5..1520d840 100644 --- a/glib/demo/CMakeLists.txt +++ b/glib/demo/CMakeLists.txt @@ -18,6 +18,7 @@ set(poppler_glib_demo_SRCS layers.c selections.c taggedstruct.c + signature.c ) poppler_add_test(poppler-glib-demo BUILD_GTK_TESTS ${poppler_glib_demo_SRCS}) diff --git a/glib/demo/main.c b/glib/demo/main.c index e7fdea13..9b95b3ed 100644 --- a/glib/demo/main.c +++ b/glib/demo/main.c @@ -38,6 +38,7 @@ #include "find.h" #include "print.h" #include "selections.h" +#include "signature.h" enum { @@ -69,7 +70,8 @@ static const PopplerGlibDemo demo_list[] = { { "Info", pgd_info_create_widget }, { "Text", pgd_text_create_widget }, { "Tagged Structure", pgd_taggedstruct_create_widget }, { "Find", pgd_find_create_widget }, - { "Print", pgd_print_create_widget } }; + { "Print", pgd_print_create_widget }, + { "Signature", pgd_signature_create_widget } }; static void pgd_demo_changed(GtkTreeSelection *selection, GtkNotebook *notebook) { diff --git a/glib/demo/signature.c b/glib/demo/signature.c new file mode 100644 index 00000000..15c68c5a --- /dev/null +++ b/glib/demo/signature.c @@ -0,0 +1,437 @@ +/* + * Copyright (C) 2022-2023 Jan-Michael Brummer <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <gtk/gtk.h> +#include <string.h> + +#include "signature.h" +#include "utils.h" + +typedef struct +{ + PopplerDocument *doc; + PopplerPage *page; + GtkWidget *darea; + cairo_surface_t *surface; + gint num_page; + gint redraw_idle; + GdkPoint start; + GdkPoint stop; + gboolean started; + GdkCursorType cursor; + GtkWidget *main_box; + gdouble scale; +} PgdSignatureDemo; + +/* Render area */ +static cairo_surface_t *pgd_signature_render_page(PgdSignatureDemo *demo) +{ + cairo_t *cr; + PopplerPage *page; + gdouble width, height; + cairo_surface_t *surface = NULL; + + page = poppler_document_get_page(demo->doc, demo->num_page); + if (!page) { + return NULL; + } + + poppler_page_get_size(page, &width, &height); + + width *= demo->scale; + height *= demo->scale; + gtk_widget_set_size_request(demo->darea, width, height); + + surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height); + cr = cairo_create(surface); + + if (demo->scale != 1.0) { + cairo_scale(cr, demo->scale, demo->scale); + } + + cairo_save(cr); + cairo_set_source_rgb(cr, 1, 1, 1); + + cairo_rectangle(cr, 0, 0, width, height); + cairo_fill(cr); + cairo_restore(cr); + + cairo_save(cr); + poppler_page_render(page, cr); + cairo_restore(cr); + + cairo_destroy(cr); + g_object_unref(page); + + return surface; +} + +static void draw_selection_rect(PgdSignatureDemo *demo, cairo_t *cr) +{ + gint pos_x1, pos_x2, pos_y1, pos_y2; + gint x, y, w, h; + + pos_x1 = demo->start.x; + pos_y1 = demo->start.y; + pos_x2 = demo->stop.x; + pos_y2 = demo->stop.y; + + x = MIN(pos_x1, pos_x2); + y = MIN(pos_y1, pos_y2); + w = ABS(pos_x1 - pos_x2); + h = ABS(pos_y1 - pos_y2); + + if (w <= 0 || h <= 0) { + return; + } + + cairo_save(cr); + + cairo_rectangle(cr, x + 1, y + 1, w - 2, h - 2); + cairo_set_source_rgba(cr, 0.2, 0.6, 0.8, 0.2); + cairo_fill(cr); + + cairo_rectangle(cr, x + 0.5, y + 0.5, w - 1, h - 1); + cairo_set_source_rgba(cr, 0.2, 0.6, 0.8, 0.35); + cairo_set_line_width(cr, 1); + cairo_stroke(cr); + + cairo_restore(cr); +} + +static gboolean pgd_signature_view_drawing_area_draw(GtkWidget *area, cairo_t *cr, PgdSignatureDemo *demo) +{ + if (demo->num_page == -1) { + return FALSE; + } + + if (!demo->surface) { + demo->surface = pgd_signature_render_page(demo); + if (!demo->surface) { + return FALSE; + } + } + + cairo_set_source_surface(cr, demo->surface, 0, 0); + cairo_paint(cr); + + if (demo->started) { + draw_selection_rect(demo, cr); + } + + return TRUE; +} + +static gboolean pgd_signature_viewer_redraw(PgdSignatureDemo *demo) +{ + cairo_surface_destroy(demo->surface); + demo->surface = NULL; + + gtk_widget_queue_draw(demo->darea); + + demo->redraw_idle = 0; + + return FALSE; +} + +static void pgd_signature_viewer_queue_redraw(PgdSignatureDemo *demo) +{ + if (demo->redraw_idle == 0) { + demo->redraw_idle = g_idle_add((GSourceFunc)pgd_signature_viewer_redraw, demo); + } +} + +static void pgd_signature_page_selector_value_changed(GtkSpinButton *spinbutton, PgdSignatureDemo *demo) +{ + demo->num_page = (gint)gtk_spin_button_get_value(spinbutton) - 1; + pgd_signature_viewer_queue_redraw(demo); + + demo->page = poppler_document_get_page(demo->doc, demo->num_page); +} + +static void pgd_signature_drawing_area_realize(GtkWidget *area, PgdSignatureDemo *demo) +{ + gtk_widget_add_events(area, GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); +} + +char *password_callback(const char *in) +{ + GtkWidget *dialog; + GtkWidget *box; + GtkWidget *entry; + char *ret; + + dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, "Enter password"); + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "Enter password to open: %s", in); + gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); + + box = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog)); + entry = gtk_entry_new(); + gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); + gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); + gtk_box_pack_end(GTK_BOX(box), entry, TRUE, TRUE, 6); + gtk_widget_show_all(box); + + gtk_dialog_run(GTK_DIALOG(dialog)); + ret = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry))); + gtk_widget_destroy(dialog); + + return ret; +} + +static void pgd_signature_update_cursor(PgdSignatureDemo *demo, GdkCursorType cursor_type) +{ + GdkCursor *cursor = NULL; + + if (cursor_type == demo->cursor) { + return; + } + + if (cursor_type != GDK_LAST_CURSOR) { + cursor = gdk_cursor_new_for_display(gtk_widget_get_display(demo->main_box), cursor_type); + } + + demo->cursor = cursor_type; + + gdk_window_set_cursor(gtk_widget_get_window(demo->main_box), cursor); + gdk_display_flush(gtk_widget_get_display(demo->main_box)); + if (cursor) { + g_object_unref(cursor); + } +} + +static void pgd_signature_start_signing(GtkWidget *button, PgdSignatureDemo *demo) +{ + demo->start.x = 0; + demo->start.y = 0; + demo->stop.x = 0; + demo->stop.y = 0; + demo->started = TRUE; + pgd_signature_update_cursor(demo, GDK_TCROSS); +} + +static gboolean pgd_signature_drawing_area_button_press(GtkWidget *area, GdkEventButton *event, PgdSignatureDemo *demo) +{ + if (!demo->page || event->button != 1 || !demo->started) { + return FALSE; + } + + demo->start.x = event->x; + demo->start.y = event->y; + demo->stop = demo->start; + + pgd_signature_viewer_queue_redraw(demo); + + return TRUE; +} + +static gboolean pgd_signature_drawing_area_motion_notify(GtkWidget *area, GdkEventMotion *event, PgdSignatureDemo *demo) +{ + gdouble width, height; + + if (!demo->page || demo->start.x == -1 || !demo->started) { + return FALSE; + } + + demo->stop.x = event->x; + demo->stop.y = event->y; + + poppler_page_get_size(demo->page, &width, &height); + width *= demo->scale; + height *= demo->scale; + + /* Keep the drawing within the page */ + demo->stop.x = CLAMP(demo->stop.x, 0, width); + demo->stop.y = CLAMP(demo->stop.y, 0, height); + + pgd_signature_viewer_queue_redraw(demo); + + return TRUE; +} + +static void on_signing_done(GObject *source, GAsyncResult *result, gpointer user_data) +{ + PopplerDocument *document = POPPLER_DOCUMENT(source); + g_autoptr(GError) error = NULL; + gboolean ret = poppler_document_sign_finish(document, result, &error); + + g_print("%s: result %d\n", __FUNCTION__, ret); + if (error) { + g_print("Error: %s", error->message); + } +} + +static gboolean pgd_signature_drawing_area_button_release(GtkWidget *area, GdkEventButton *event, PgdSignatureDemo *demo) +{ + if (!demo->page || event->button != 1 || !demo->started) { + return FALSE; + } + + demo->started = FALSE; + pgd_signature_update_cursor(demo, GDK_LAST_CURSOR); + + /* poppler_certificate_set_nss_dir ("./glib/demo/cert"); */ + poppler_set_nss_password_callback(password_callback); + GList *available_certificates = poppler_get_available_signing_certificates(); + + if (available_certificates) { + g_autofree char *signature = NULL; + g_autofree char *signature_left = NULL; + PopplerSigningData *data = poppler_signing_data_new(); + PopplerRectangle rect; + PopplerCertificateInfo *certificate_info; + time_t t; + double width, height; + + certificate_info = available_certificates->data; + time(&t); + + poppler_signing_data_set_certificate_info(data, certificate_info); + poppler_signing_data_set_page(data, demo->num_page); + poppler_signing_data_set_field_partial_name(data, g_uuid_string_random()); + poppler_signing_data_set_destination_filename(data, "test.pdf"); + poppler_signing_data_set_reason(data, "I'm the author"); + poppler_signing_data_set_location(data, "At my desk"); + + poppler_page_get_size(demo->page, &width, &height); + + rect.x1 = demo->start.x > demo->stop.x ? demo->stop.x : demo->start.x; + rect.y1 = demo->start.y > demo->stop.y ? demo->stop.y : demo->start.y; + rect.x2 = demo->start.x > demo->stop.x ? demo->start.x : demo->stop.x; + rect.y2 = demo->start.y > demo->stop.y ? demo->start.y : demo->stop.y; + + /* Adjust scale */ + rect.x1 /= demo->scale; + rect.y1 /= demo->scale; + rect.x2 /= demo->scale; + rect.y2 /= demo->scale; + + rect.y1 = height - rect.y1; + rect.y2 = height - rect.y2; + + poppler_signing_data_set_signature_rectangle(data, &rect); + + signature = g_strdup_printf("Digitally signed by %s\nDate: %s", poppler_certificate_info_get_subject_common_name(certificate_info), ctime(&t)); + poppler_signing_data_set_signature_text(data, signature); + + signature_left = g_strdup_printf("%s", poppler_certificate_info_get_subject_common_name(certificate_info)); + poppler_signing_data_set_signature_text_left(data, signature_left); + + poppler_document_sign(demo->doc, data, NULL, on_signing_done, NULL); + } + + return TRUE; +} + +static void pgd_signature_scale_selector_value_changed(GtkSpinButton *spinbutton, PgdSignatureDemo *demo) +{ + demo->scale = gtk_spin_button_get_value(spinbutton); + pgd_signature_viewer_queue_redraw(demo); +} + +/* Main UI */ +GtkWidget *pgd_signature_create_widget(PopplerDocument *document) +{ + PgdSignatureDemo *demo; + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *button; + GtkWidget *hbox, *page_selector; + GtkWidget *scale_hbox, *scale_selector; + GtkWidget *swindow; + gchar *str; + gint n_pages; + + demo = g_new0(PgdSignatureDemo, 1); + demo->cursor = GDK_LAST_CURSOR; + demo->doc = g_object_ref(document); + demo->scale = 1.0; + + n_pages = poppler_document_get_n_pages(document); + + vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); + + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); + + label = gtk_label_new("Page:"); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0); + gtk_widget_show(label); + + page_selector = gtk_spin_button_new_with_range(1, n_pages, 1); + g_signal_connect(G_OBJECT(page_selector), "value-changed", G_CALLBACK(pgd_signature_page_selector_value_changed), (gpointer)demo); + gtk_box_pack_start(GTK_BOX(hbox), page_selector, FALSE, TRUE, 0); + gtk_widget_show(page_selector); + + str = g_strdup_printf("of %d", n_pages); + label = gtk_label_new(str); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0); + gtk_widget_show(label); + g_free(str); + + scale_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); + + label = gtk_label_new("Scale:"); + gtk_box_pack_start(GTK_BOX(scale_hbox), label, TRUE, TRUE, 0); + gtk_widget_show(label); + + scale_selector = gtk_spin_button_new_with_range(0, 10.0, 0.1); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(scale_selector), 1.0); + g_signal_connect(G_OBJECT(scale_selector), "value-changed", G_CALLBACK(pgd_signature_scale_selector_value_changed), (gpointer)demo); + gtk_box_pack_start(GTK_BOX(scale_hbox), scale_selector, TRUE, TRUE, 0); + gtk_widget_show(scale_selector); + + gtk_box_pack_start(GTK_BOX(hbox), scale_hbox, FALSE, TRUE, 0); + gtk_widget_show(scale_hbox); + + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_mnemonic("_Sign"); + g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(pgd_signature_start_signing), (gpointer)demo); + gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + gtk_widget_show(hbox); + + /* Demo Area (Render) */ + demo->darea = gtk_drawing_area_new(); + g_signal_connect(demo->darea, "draw", G_CALLBACK(pgd_signature_view_drawing_area_draw), demo); + g_signal_connect(demo->darea, "realize", G_CALLBACK(pgd_signature_drawing_area_realize), (gpointer)demo); + g_signal_connect(demo->darea, "button_press_event", G_CALLBACK(pgd_signature_drawing_area_button_press), (gpointer)demo); + g_signal_connect(demo->darea, "motion_notify_event", G_CALLBACK(pgd_signature_drawing_area_motion_notify), (gpointer)demo); + g_signal_connect(demo->darea, "button_release_event", G_CALLBACK(pgd_signature_drawing_area_button_release), (gpointer)demo); + + swindow = gtk_scrolled_window_new(NULL, NULL); +#if GTK_CHECK_VERSION(3, 7, 8) + gtk_container_add(GTK_CONTAINER(swindow), demo->darea); +#else + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(swindow), demo->darea); +#endif + gtk_widget_show(demo->darea); + + gtk_widget_show(swindow); + + gtk_box_pack_start(GTK_BOX(vbox), swindow, TRUE, TRUE, 0); + + demo->main_box = vbox; + + demo->num_page = 0; + demo->page = poppler_document_get_page(demo->doc, demo->num_page); + pgd_signature_viewer_queue_redraw(demo); + + return vbox; +} diff --git a/glib/demo/signature.h b/glib/demo/signature.h new file mode 100644 index 00000000..cbdf7f43 --- /dev/null +++ b/glib/demo/signature.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 Jan-Michael Brummer <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <gtk/gtk.h> +#include <poppler.h> + +#ifndef _SIGNATURE_H_ +# define _SIGNATURE_H_ + +G_BEGIN_DECLS + +GtkWidget *pgd_signature_create_widget(PopplerDocument *document); + +G_END_DECLS + +#endif /* _SIGNATURE_H_ */ diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc index 7505a6fe..4092e51d 100644 --- a/glib/poppler-document.cc +++ b/glib/poppler-document.cc @@ -56,6 +56,7 @@ # include <PDFDocEncoding.h> # include <OptionalContent.h> # include <ViewerPreferences.h> +# include "UTF.h" #endif #include "poppler.h" @@ -3814,3 +3815,100 @@ GooString *_poppler_convert_date_time_to_pdf_date(GDateTime *datetime) g_free(date_str); return out_str.release(); } + +static void _poppler_sign_document_thread(GTask *task, PopplerDocument *document, const PopplerSigningData *signing_data, GCancellable *cancellable) +{ + const PopplerCertificateInfo *certificate_info; + const char *signing_data_signature_text; + const PopplerColor *font_color; + const PopplerColor *border_color; + const PopplerColor *background_color; + gboolean ret; + + g_return_if_fail(POPPLER_IS_DOCUMENT(document)); + g_return_if_fail(signing_data != nullptr); + + signing_data_signature_text = poppler_signing_data_get_signature_text(signing_data); + if (signing_data_signature_text == nullptr) { + g_task_return_new_error(task, POPPLER_ERROR, POPPLER_ERROR_SIGNING, "No signature given"); + return; + } + + certificate_info = poppler_signing_data_get_certificate_info(signing_data); + if (certificate_info == nullptr) { + g_task_return_new_error(task, POPPLER_ERROR, POPPLER_ERROR_SIGNING, "Invalid certificate information provided for signing"); + return; + } + + PopplerPage *page = poppler_document_get_page(document, poppler_signing_data_get_page(signing_data)); + if (page == nullptr) { + g_task_return_new_error(task, POPPLER_ERROR, POPPLER_ERROR_SIGNING, "Invalid page number selected for signing"); + return; + } + + font_color = poppler_signing_data_get_font_color(signing_data); + border_color = poppler_signing_data_get_border_color(signing_data); + background_color = poppler_signing_data_get_background_color(signing_data); + + std::unique_ptr<GooString> signature_text = std::unique_ptr<GooString>(utf8ToUtf16WithBom(signing_data_signature_text)); + std::unique_ptr<GooString> signature_text_left = std::unique_ptr<GooString>(utf8ToUtf16WithBom(poppler_signing_data_get_signature_text_left(signing_data))); + const auto field_partial_name = new GooString(poppler_signing_data_get_field_partial_name(signing_data), strlen(poppler_signing_data_get_field_partial_name(signing_data))); + const auto owner_pwd = std::optional<GooString>(poppler_signing_data_get_document_owner_password(signing_data)); + const auto user_pwd = std::optional<GooString>(poppler_signing_data_get_document_user_password(signing_data)); + const auto reason = std::unique_ptr<GooString>(poppler_signing_data_get_reason(signing_data) ? new GooString(poppler_signing_data_get_reason(signing_data), strlen(poppler_signing_data_get_reason(signing_data))) : nullptr); + const auto location = std::unique_ptr<GooString>(poppler_signing_data_get_location(signing_data) ? new GooString(poppler_signing_data_get_location(signing_data), strlen(poppler_signing_data_get_location(signing_data))) : nullptr); + const PopplerRectangle *rect = poppler_signing_data_get_signature_rectangle(signing_data); + + ret = document->doc->sign(poppler_signing_data_get_destination_filename(signing_data), poppler_certificate_info_get_id((PopplerCertificateInfo *)certificate_info), + poppler_signing_data_get_password(signing_data) ? poppler_signing_data_get_password(signing_data) : "", field_partial_name, poppler_signing_data_get_page(signing_data) + 1, + PDFRectangle(rect->x1, rect->y1, rect->x2, rect->y2), *signature_text, *signature_text_left, poppler_signing_data_get_font_size(signing_data), poppler_signing_data_get_left_font_size(signing_data), + std::make_unique<AnnotColor>(font_color->red, font_color->green, font_color->blue), poppler_signing_data_get_border_width(signing_data), + std::make_unique<AnnotColor>(border_color->red, border_color->green, border_color->blue), std::make_unique<AnnotColor>(background_color->red, background_color->green, background_color->blue), reason.get(), + location.get(), poppler_signing_data_get_image_path(signing_data) ? poppler_signing_data_get_image_path(signing_data) : "", owner_pwd, user_pwd); + + g_task_return_boolean(task, ret); +} + +/** + * poppler_document_sign: + * @document: a #PopplerDocument + * @signing_data: a #PopplerSigningData + * @cancellable: a #GCancellable + * @callback: a #GAsyncReadyCallback + * @user_data: user data used by callback function + * + * Sign #document using #signing_data. + * + * Since: 23.07.0 + **/ +void poppler_document_sign(PopplerDocument *document, const PopplerSigningData *signing_data, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) +{ + g_autoptr(GTask) task = nullptr; + + g_return_if_fail(POPPLER_IS_DOCUMENT(document)); + g_return_if_fail(signing_data != nullptr); + + task = g_task_new(document, cancellable, callback, user_data); + g_task_set_task_data(task, (void *)signing_data, nullptr); + + g_task_run_in_thread(task, (GTaskThreadFunc)_poppler_sign_document_thread); +} + +/** + * poppler_document_sign_finish: + * @document: a #PopplerDocument + * @result: a #GAsyncResult + * @error: a #GError + * + * Finish poppler_sign_document and get return status or error. + * + * Returns: %TRUE on successful signing a document, otherwise %FALSE and error is set. + * + * Since: 23.07.0 + **/ +gboolean poppler_document_sign_finish(PopplerDocument *document, GAsyncResult *result, GError **error) +{ + g_return_val_if_fail(g_task_is_valid(result, document), FALSE); + + return g_task_propagate_boolean(G_TASK(result), error); +} diff --git a/glib/poppler-document.h b/glib/poppler-document.h index 3dabfa2f..a793e08b 100644 --- a/glib/poppler-document.h +++ b/glib/poppler-document.h @@ -521,6 +521,11 @@ void poppler_ps_file_set_duplex(PopplerPSFile *ps_file, gboolean duplex); POPPLER_PUBLIC void poppler_ps_file_free(PopplerPSFile *ps_file); +POPPLER_PUBLIC +void poppler_document_sign(PopplerDocument *document, const PopplerSigningData *signing_data, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); +POPPLER_PUBLIC +gboolean poppler_document_sign_finish(PopplerDocument *document, GAsyncResult *result, GError **error); + /** * PopplerPageRange: * @start_page: first page in the range of pages diff --git a/glib/poppler-form-field.cc b/glib/poppler-form-field.cc index 5ff189a0..d2206288 100644 --- a/glib/poppler-form-field.cc +++ b/glib/poppler-form-field.cc @@ -27,6 +27,12 @@ #include "poppler.h" #include "poppler-private.h" +#include <CertificateInfo.h> +#ifdef ENABLE_NSS3 +# include <NSSCryptoSignBackend.h> +#endif +#include <CryptoSignBackend.h> + /** * SECTION:poppler-form-field * @short_description: Form Field @@ -1033,3 +1039,1085 @@ gchar *poppler_form_field_choice_get_text(PopplerFormField *field) tmp = static_cast<FormWidgetChoice *>(field->widget)->getEditChoice(); return tmp ? _poppler_goo_string_to_utf8(tmp) : nullptr; } + +/* Signing Data */ + +struct _PopplerSigningData +{ + char *destination_filename; + PopplerCertificateInfo *certificate_info; + int page; + + char *signature_text; + char *signature_text_left; + PopplerRectangle signature_rect; + + PopplerColor font_color; + gdouble font_size; + gdouble left_font_size; + + PopplerColor border_color; + gdouble border_width; + + PopplerColor background_color; + + char *field_partial_name; + char *reason; + char *location; + char *image_path; + char *password; + char *document_owner_password; + char *document_user_password; +}; + +typedef struct _PopplerSigningData PopplerSigningData; + +G_DEFINE_BOXED_TYPE(PopplerSigningData, poppler_signing_data, poppler_signing_data_copy, poppler_signing_data_free) + +/** + * poppler_signing_data_new: + * + * Creates a new #PopplerSigningData with default content. + * + * Return value: a new #PopplerSigningData. It must be freed with poppler_signing_data_free() when done. + * + * Since: 23.07.0 + **/ +PopplerSigningData *poppler_signing_data_new(void) +{ + PopplerSigningData *data = (PopplerSigningData *)g_malloc0(sizeof(PopplerSigningData)); + + data->password = g_strdup(""); + data->page = 0; + + data->font_size = 10.0; + data->left_font_size = 20.0; + data->border_width = 1.5; + + /* Grey background */ + auto background_color = PopplerColor(); + background_color.red = 0xEF; + background_color.green = 0xEF; + background_color.blue = 0xEF; + poppler_signing_data_set_background_color(data, &background_color); + + /* Red border color */ + auto border_color = PopplerColor(); + border_color.red = 0xFF; + border_color.green = 0x00; + border_color.blue = 0x00; + poppler_signing_data_set_border_color(data, &border_color); + + /* Red font color */ + auto font_color = PopplerColor(); + font_color.red = 0xFF; + font_color.green = 0x00; + border_color.blue = 0x00; + poppler_signing_data_set_font_color(data, &font_color); + + return data; +} + +/** + * poppler_signing_data_copy: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Copies @signing_data, creating an identical #PopplerSigningData. + * + * Return value: (transfer full): a new #PopplerSigningData structure identical to @signing_data + * + * Since: 23.07.0 + **/ +PopplerSigningData *poppler_signing_data_copy(const PopplerSigningData *signing_data) +{ + PopplerSigningData *data; + + g_return_val_if_fail(signing_data != nullptr, nullptr); + + data = (PopplerSigningData *)g_malloc0(sizeof(PopplerSigningData)); + data->destination_filename = g_strdup(signing_data->destination_filename); + data->certificate_info = poppler_certificate_info_copy(signing_data->certificate_info); + data->page = signing_data->page; + + data->signature_text = g_strdup(signing_data->signature_text); + data->signature_text_left = g_strdup(signing_data->signature_text_left); + memcpy(&data->signature_rect, &signing_data->signature_rect, sizeof(PopplerRectangle)); + + memcpy(&data->font_color, &signing_data->font_color, sizeof(PopplerColor)); + data->font_size = signing_data->font_size; + data->left_font_size = signing_data->left_font_size; + + memcpy(&data->border_color, &signing_data->border_color, sizeof(PopplerColor)); + data->border_width = signing_data->border_width; + + memcpy(&data->background_color, &signing_data->background_color, sizeof(PopplerColor)); + + data->field_partial_name = g_strdup(signing_data->field_partial_name); + data->reason = g_strdup(signing_data->reason); + data->location = g_strdup(signing_data->location); + data->image_path = g_strdup(signing_data->image_path); + data->password = g_strdup(signing_data->password); + data->document_owner_password = g_strdup(signing_data->document_owner_password); + data->document_user_password = g_strdup(signing_data->document_user_password); + + return data; +} + +/** + * poppler_signing_data_free: + * @signing_data: (nullable): a #PopplerSigningData structure containing signing data + * + * Frees @signing_data + * + * Since: 23.07.0 + **/ +void poppler_signing_data_free(PopplerSigningData *signing_data) +{ + if (!signing_data) { + return; + } + + g_clear_pointer(&signing_data->destination_filename, g_free); + g_clear_pointer(&signing_data->certificate_info, poppler_certificate_info_free); + g_clear_pointer(&signing_data->signature_text, g_free); + g_clear_pointer(&signing_data->signature_text_left, g_free); + g_clear_pointer(&signing_data->field_partial_name, g_free); + g_clear_pointer(&signing_data->reason, g_free); + g_clear_pointer(&signing_data->location, g_free); + g_clear_pointer(&signing_data->image_path, g_free); + + if (signing_data->password) { +#ifdef HAVE_EXPLICIT_BZERO + explicit_bzero(signing_data->password, strlen(signing_data->password)); +#else + memset(signing_data->password, 0, strlen(signing_data->password)); +#endif + g_clear_pointer(&signing_data->password, g_free); + } + + if (signing_data->document_owner_password) { +#ifdef HAVE_EXPLICIT_BZERO + explicit_bzero(signing_data->document_owner_password, strlen(signing_data->document_owner_password)); +#else + memset(signing_data->document_owner_password, 0, strlen(signing_data->document_owner_password)); +#endif + g_clear_pointer(&signing_data->document_owner_password, g_free); + } + + if (signing_data->document_user_password) { +#ifdef HAVE_EXPLICIT_BZERO + explicit_bzero(signing_data->document_user_password, strlen(signing_data->document_user_password)); +#else + memset(signing_data->document_user_password, 0, strlen(signing_data->document_user_password)); +#endif + g_clear_pointer(&signing_data->document_user_password, g_free); + } + + g_free(signing_data); +} + +/** + * poppler_signing_data_set_destination_filename: + * @signing_data: a #PopplerSigningData structure containing signing data + * @filename: destination filename + * + * Set destination file name. + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_destination_filename(PopplerSigningData *signing_data, const gchar *filename) +{ + g_return_if_fail(signing_data != nullptr); + g_return_if_fail(filename != nullptr); + + if (signing_data->destination_filename == filename) { + return; + } + + g_clear_pointer(&signing_data->destination_filename, g_free); + signing_data->destination_filename = g_strdup(filename); +} + +/** + * poppler_signing_data_get_destination_filename: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get destination file name. + * + * Return value: destination filename + * + * Since: 23.07.0 + **/ +const gchar *poppler_signing_data_get_destination_filename(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, nullptr); + + return signing_data->destination_filename; +} + +/** + * poppler_signing_data_set_certificate_info: + * @signing_data: a #PopplerSigningData structure containing signing data + * @certificate_info: a #PopplerCertificateInfo + * + * Set certification information. + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_certificate_info(PopplerSigningData *signing_data, const PopplerCertificateInfo *certificate_info) +{ + g_return_if_fail(signing_data != nullptr); + g_return_if_fail(certificate_info != nullptr); + + if (signing_data->certificate_info == certificate_info) { + return; + } + + g_clear_pointer(&signing_data->certificate_info, poppler_certificate_info_free); + signing_data->certificate_info = poppler_certificate_info_copy(certificate_info); +} + +/** + * poppler_signing_data_get_certificate_info: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get certification information. + * + * Return value: a #PopplerCertificateInfo + * + * Since: 23.07.0 + **/ +const PopplerCertificateInfo *poppler_signing_data_get_certificate_info(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, nullptr); + return signing_data->certificate_info; +} + +/** + * poppler_signing_data_set_page: + * @signing_data: a #PopplerSigningData structure containing signing data + * @page: a page number + * + * Set page (>=0). + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_page(PopplerSigningData *signing_data, int page) +{ + g_return_if_fail(signing_data != nullptr); + + if (page < 0) { + return; + } + + signing_data->page = page; +} + +/** + * poppler_signing_data_get_page: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get page. + * + * Return value: page number + * + * Since: 23.07.0 + **/ +int poppler_signing_data_get_page(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, 0); + return signing_data->page; +} + +/** + * poppler_signing_data_set_signature_text: + * @signing_data: a #PopplerSigningData structure containing signing data + * @signature_text: text to show as main signature + * + * Set signature text. + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_signature_text(PopplerSigningData *signing_data, const gchar *signature_text) +{ + g_return_if_fail(signing_data != nullptr); + g_return_if_fail(signature_text != nullptr); + + if (signing_data->signature_text == signature_text) { + return; + } + + g_clear_pointer(&signing_data->signature_text, g_free); + signing_data->signature_text = g_strdup(signature_text); +} + +/** + * poppler_signing_data_get_signature_text: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get signature text. + * + * Return value: signature text + * + * Since: 23.07.0 + **/ +const gchar *poppler_signing_data_get_signature_text(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, nullptr); + return signing_data->signature_text; +} + +/** + * poppler_signing_data_set_signature_text_left: + * @signing_data: a #PopplerSigningData structure containing signing data + * @signature_text_left: text to show as small left signature + * + * Set small signature text on the left hand. + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_signature_text_left(PopplerSigningData *signing_data, const gchar *signature_text_left) +{ + g_return_if_fail(signing_data != nullptr); + g_return_if_fail(signature_text_left != nullptr); + + if (signing_data->signature_text_left == signature_text_left) { + return; + } + + g_clear_pointer(&signing_data->signature_text_left, g_free); + signing_data->signature_text_left = g_strdup(signature_text_left); +} + +/** + * poppler_signing_data_get_signature_text_left: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get signature text left. + * + * Return value: signature text left + * + * Since: 23.07.0 + **/ +const gchar *poppler_signing_data_get_signature_text_left(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, nullptr); + return signing_data->signature_text_left; +} + +/** + * poppler_signing_data_set_signature_rectangle: + * @signing_data: a #PopplerSigningData structure containing signing data + * @signature_rect: a #PopplerRectangle where signature should be shown + * + * Set signature rectangle. + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_signature_rectangle(PopplerSigningData *signing_data, const PopplerRectangle *signature_rect) +{ + g_return_if_fail(signing_data != nullptr); + g_return_if_fail(signature_rect != nullptr); + + memcpy(&signing_data->signature_rect, signature_rect, sizeof(PopplerRectangle)); +} + +/** + * poppler_signing_data_get_signature_rectangle: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get signature rectangle. + * + * Return value: a #PopplerRectangle + * + * Since: 23.07.0 + **/ +const PopplerRectangle *poppler_signing_data_get_signature_rectangle(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, nullptr); + return &signing_data->signature_rect; +} + +/** + * poppler_signing_data_set_font_color: + * @signing_data: a #PopplerSigningData structure containing signing data + * @font_color: a #PopplerColor to be used as signature font color + * + * Set signature font color. + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_font_color(PopplerSigningData *signing_data, const PopplerColor *font_color) +{ + g_return_if_fail(signing_data != nullptr); + g_return_if_fail(font_color != nullptr); + + memcpy(&signing_data->font_color, font_color, sizeof(PopplerColor)); +} + +/** + * poppler_signing_data_get_font_color: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get signature font color. + * + * Return value: a #PopplerColor + * + * Since: 23.07.0 + **/ +const PopplerColor *poppler_signing_data_get_font_color(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, nullptr); + return &signing_data->font_color; +} + +/** + * poppler_signing_data_set_font_size: + * @signing_data: a #PopplerSigningData structure containing signing data + * @font_size: signature font size + * + * Set signature font size (>0). + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_font_size(PopplerSigningData *signing_data, gdouble font_size) +{ + g_return_if_fail(signing_data != nullptr); + + if (font_size <= 0) { + return; + } + + signing_data->font_size = font_size; +} + +/** + * poppler_signing_data_get_font_size: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get signature font size. + * + * Return value: font size + * + * Since: 23.07.0 + **/ +gdouble poppler_signing_data_get_font_size(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, 20.0f); + return signing_data->font_size; +} + +/** + * poppler_signing_data_set_left_font_size: + * @signing_data: a #PopplerSigningData structure containing signing data + * @font_size: signature font size + * + * Set signature left font size (> 0). + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_left_font_size(PopplerSigningData *signing_data, gdouble left_font_size) +{ + g_return_if_fail(signing_data != nullptr); + + if (left_font_size <= 0) { + return; + } + + signing_data->left_font_size = left_font_size; +} + +/** + * poppler_signing_data_get_left_font_size: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get signature left font size. + * + * Return value: left font size + * + * Since: 23.07.0 + **/ +gdouble poppler_signing_data_get_left_font_size(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, 12.0); + return signing_data->left_font_size; +} + +/** + * poppler_signing_data_set_border_color: + * @signing_data: a #PopplerSigningData structure containing signing data + * @border_color: a #PopplerColor to be used for signature border + * + * Set signature border color. + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_border_color(PopplerSigningData *signing_data, const PopplerColor *border_color) +{ + g_return_if_fail(signing_data != nullptr); + g_return_if_fail(border_color != nullptr); + + memcpy(&signing_data->border_color, border_color, sizeof(PopplerColor)); +} + +/** + * poppler_signing_data_get_border_color: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get signature border color. + * + * Return value: a #PopplerColor + * + * Since: 23.07.0 + **/ +const PopplerColor *poppler_signing_data_get_border_color(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, nullptr); + return &signing_data->border_color; +} + +/** + * poppler_signing_data_set_border_width: + * @signing_data: a #PopplerSigningData structure containing signing data + * @border_width: border width + * + * Set signature border width. + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_border_width(PopplerSigningData *signing_data, gdouble border_width) +{ + g_return_if_fail(signing_data != nullptr); + + if (border_width < 0) { + return; + } + + signing_data->border_width = border_width; +} + +/** + * poppler_signing_data_get_border_width: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get signature border width. + * + * Return value: border width + * + * Since: 23.07.0 + **/ +gdouble poppler_signing_data_get_border_width(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, 12); + return signing_data->border_width; +} + +/** + * poppler_signing_data_set_background_color: + * @signing_data: a #PopplerSigningData structure containing signing data + * @background_color: a #PopplerColor to be used for signature background + * + * Set signature background color. + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_background_color(PopplerSigningData *signing_data, const PopplerColor *background_color) +{ + g_return_if_fail(signing_data != nullptr); + g_return_if_fail(background_color != nullptr); + + memcpy(&signing_data->background_color, background_color, sizeof(PopplerColor)); +} + +/** + * poppler_signing_data_get_background_color: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get signature background color. + * + * Return value: a #PopplerColor + * + * Since: 23.07.0 + **/ +const PopplerColor *poppler_signing_data_get_background_color(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, nullptr); + return &signing_data->background_color; +} + +/** + * poppler_signing_data_set_field_partial_name: + * @signing_data: a #PopplerSigningData structure containing signing data + * @field_partial_name: a field partial name + * + * Set field partial name (existing field id or a new one) where signature is placed. + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_field_partial_name(PopplerSigningData *signing_data, const gchar *field_partial_name) +{ + g_return_if_fail(signing_data != nullptr); + g_return_if_fail(field_partial_name != nullptr); + + g_clear_pointer(&signing_data->field_partial_name, g_free); + signing_data->field_partial_name = g_strdup(field_partial_name); +} + +/** + * poppler_signing_data_get_field_partial_name: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get field partial name. + * + * Return value: field partial name + * + * Since: 23.07.0 + **/ +const gchar *poppler_signing_data_get_field_partial_name(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, ""); + return signing_data->field_partial_name; +} + +/** + * poppler_signing_data_set_reason: + * @signing_data: a #PopplerSigningData structure containing signing data + * @reason: a reason + * + * Set reason for signature (e.g. I'm approver). + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_reason(PopplerSigningData *signing_data, const gchar *reason) +{ + g_return_if_fail(signing_data != nullptr); + g_return_if_fail(reason != nullptr); + + if (signing_data->reason == reason) { + return; + } + + g_clear_pointer(&signing_data->reason, g_free); + signing_data->reason = g_strdup(reason); +} + +/** + * poppler_signing_data_get_reason: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get reason. + * + * Return value: reason + * + * Since: 23.07.0 + **/ +const gchar *poppler_signing_data_get_reason(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, nullptr); + return signing_data->reason; +} + +/** + * poppler_signing_data_set_location: + * @signing_data: a #PopplerSigningData structure containing signing data + * @location: a location + * + * Set signature location (e.g. "At my desk"). + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_location(PopplerSigningData *signing_data, const gchar *location) +{ + g_return_if_fail(signing_data != nullptr); + g_return_if_fail(location != nullptr); + + if (signing_data->location == location) { + return; + } + + g_clear_pointer(&signing_data->location, g_free); + signing_data->location = g_strdup(location); +} + +/** + * poppler_signing_data_get_location: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get location. + * + * Return value: location + * + * Since: 23.07.0 + **/ +const gchar *poppler_signing_data_get_location(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, nullptr); + return signing_data->location; +} + +/** + * poppler_signing_data_set_image_path: + * @signing_data: a #PopplerSigningData structure containing signing data + * @image_path: signature image path + * + * Set signature background (watermark) image path. + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_image_path(PopplerSigningData *signing_data, const gchar *image_path) +{ + g_return_if_fail(signing_data != nullptr); + g_return_if_fail(image_path != nullptr); + + if (signing_data->image_path == image_path) { + return; + } + + g_clear_pointer(&signing_data->image_path, g_free); + signing_data->image_path = g_strdup(image_path); +} + +/** + * poppler_signing_data_get_image_path: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get image path. + * + * Return value: image path + * + * Since: 23.07.0 + **/ +const gchar *poppler_signing_data_get_image_path(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, nullptr); + return signing_data->image_path; +} + +/** + * poppler_signing_data_set_password: + * @signing_data: a #PopplerSigningData structure containing signing data + * @password: a password + * + * Set password for the signing key. + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_password(PopplerSigningData *signing_data, const gchar *password) +{ + g_return_if_fail(signing_data != nullptr); + g_return_if_fail(password != nullptr); + + if (signing_data->password == password) { + return; + } + + g_clear_pointer(&signing_data->password, g_free); + signing_data->password = g_strdup(password); +} + +/** + * poppler_signing_data_get_password: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get signing key password. + * + * Return value: password + * + * Since: 23.07.0 + **/ +const gchar *poppler_signing_data_get_password(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, nullptr); + return signing_data->password; +} + +/** + * poppler_signing_data_set_document_owner_password: + * @signing_data: a #PopplerSigningData structure containing signing data + * @document_owner_password: document owner password + * + * Set document owner password (for encrypted files). + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_document_owner_password(PopplerSigningData *signing_data, const gchar *document_owner_password) +{ + g_return_if_fail(signing_data != nullptr); + g_return_if_fail(document_owner_password != nullptr); + + if (signing_data->document_owner_password == document_owner_password) { + return; + } + + g_clear_pointer(&signing_data->document_owner_password, g_free); + signing_data->document_owner_password = g_strdup(document_owner_password); +} + +/** + * poppler_signing_data_get_document_owner_password: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get document owner password. + * + * Return value: document owner password (for encrypted files) + * + * Since: 23.07.0 + **/ +const gchar *poppler_signing_data_get_document_owner_password(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, nullptr); + return signing_data->document_owner_password; +} + +/** + * poppler_signing_data_set_document_user_password: + * @signing_data: a #PopplerSigningData structure containing signing data + * @document_user_password: document user password + * + * Set document user password (for encrypted files). + * + * Since: 23.07.0 + **/ +void poppler_signing_data_set_document_user_password(PopplerSigningData *signing_data, const gchar *document_user_password) +{ + g_return_if_fail(signing_data != nullptr); + g_return_if_fail(document_user_password != nullptr); + + if (signing_data->document_user_password == document_user_password) { + return; + } + + g_clear_pointer(&signing_data->document_user_password, g_free); + signing_data->document_user_password = g_strdup(document_user_password); +} + +/** + * poppler_signing_data_get_document_user_password: + * @signing_data: a #PopplerSigningData structure containing signing data + * + * Get document user password. + * + * Return value: document user password (for encrypted files) + * + * Since: 23.07.0 + **/ +const gchar *poppler_signing_data_get_document_user_password(const PopplerSigningData *signing_data) +{ + g_return_val_if_fail(signing_data != nullptr, ""); + return signing_data->document_user_password; +} + +/* Certificate Information */ + +struct _PopplerCertificateInfo +{ + char *id; + char *subject_common_name; +}; + +typedef struct _PopplerCertificateInfo PopplerCertificateInfo; + +G_DEFINE_BOXED_TYPE(PopplerCertificateInfo, poppler_certificate_info, poppler_certificate_info_copy, poppler_certificate_info_free) + +/** + * poppler_certificate_info_new: + * + * Creates a new #PopplerCertificateInfo + * + * Return value: a new #PopplerCertificateInfo. It must be freed with poppler_certificate_info_free() when done. + * + * Since: 23.07.0 + **/ +PopplerCertificateInfo *poppler_certificate_info_new(void) +{ + return (PopplerCertificateInfo *)g_malloc0(sizeof(PopplerCertificateInfo)); +} + +/** + * poppler_certificate_info_get_id: + * @certificate_info: a #PopplerCertificateInfo structure containing certificate information + * + * Get certificate nick name + * + * Return value: certificate nick name + * + * Since: 23.07.0 + **/ +const char *poppler_certificate_info_get_id(const PopplerCertificateInfo *certificate_info) +{ + g_return_val_if_fail(certificate_info != nullptr, nullptr); + return certificate_info->id; +} + +/** + * poppler_certificate_info_get_subject_common_name: + * @certificate_info: a #PopplerCertificateInfo structure containing certificate information + * + * Get certificate subject common name + * + * Return value: certificate subject common name + * + * Since: 23.07.0 + **/ +const char *poppler_certificate_info_get_subject_common_name(const PopplerCertificateInfo *certificate_info) +{ + g_return_val_if_fail(certificate_info != nullptr, nullptr); + return certificate_info->subject_common_name; +} + +static PopplerCertificateInfo *create_certificate_info(const X509CertificateInfo *ci) +{ + PopplerCertificateInfo *certificate_info; + + g_return_val_if_fail(ci != nullptr, nullptr); + + certificate_info = poppler_certificate_info_new(); + certificate_info->id = g_strdup(ci->getNickName().c_str()); + certificate_info->subject_common_name = g_strdup(ci->getSubjectInfo().commonName.c_str()); + return certificate_info; +} + +/** + * poppler_certificate_info_copy: + * @certificate_info: a #PopplerCertificateInfo structure containing certificate information + * + * Copies @certificate_info, creating an identical #PopplerCertificateInfo. + * + * Return value: (transfer full): a new #PopplerCertificateInfo structure identical to @certificate_info + * + * Since: 23.07.0 + **/ +PopplerCertificateInfo *poppler_certificate_info_copy(const PopplerCertificateInfo *certificate_info) +{ + PopplerCertificateInfo *dup; + + g_return_val_if_fail(certificate_info != nullptr, nullptr); + + dup = (PopplerCertificateInfo *)g_malloc0(sizeof(PopplerCertificateInfo)); + dup->id = g_strdup(certificate_info->id); + dup->subject_common_name = g_strdup(certificate_info->subject_common_name); + + return dup; +} + +/** + * poppler_certificate_info_free: + * @certificate_info: a #PopplerCertificateInfo structure containing certificate information + * + * Frees @certificate_info + * + * Since: 23.07.0 + **/ +void poppler_certificate_info_free(PopplerCertificateInfo *certificate_info) +{ + if (certificate_info == nullptr) { + return; + } + + g_clear_pointer(&certificate_info->id, g_free); + g_clear_pointer(&certificate_info->subject_common_name, g_free); + + g_free(certificate_info); +} + +/** + * poppler_get_available_signing_certificates: + * + * Get all available signing certificate information + * + * Returns: (transfer full) (element-type PopplerCertificateInfo): all available signing certificate information + **/ +GList *poppler_get_available_signing_certificates(void) +{ + GList *list = nullptr; +#ifdef ENABLE_NSS3 + std::vector<std::unique_ptr<X509CertificateInfo>> vCerts = CryptoSign::Factory::createActive()->getAvailableSigningCertificates(); + + for (auto &cert : vCerts) { + PopplerCertificateInfo *certificate_info = create_certificate_info(cert.get()); + list = g_list_append(list, certificate_info); + } +#endif + return list; +} + +/** + * poppler_get_certificate_info_by_id: + * + * Get certificate by nick name + * + * Returns: (transfer full): a #PopplerCertificateInfo or %NULL if not found + **/ +PopplerCertificateInfo *poppler_get_certificate_info_by_id(const char *id) +{ + PopplerCertificateInfo *ret = nullptr; + GList *certificate_info = poppler_get_available_signing_certificates(); + GList *list; + + for (list = certificate_info; list != nullptr; list = list->next) { + PopplerCertificateInfo *info = (PopplerCertificateInfo *)list->data; + + if (g_strcmp0(info->id, id) == 0) { + ret = poppler_certificate_info_copy(info); + break; + } + } + + g_list_free_full(certificate_info, (GDestroyNotify)poppler_certificate_info_free); + + return ret; +} + +/* NSS functions */ + +/** + * poppler_set_nss_dir: + * + * Set NSS directory + * + * Since: 23.07.0 + **/ +void poppler_set_nss_dir(const char *path) +{ +#ifdef ENABLE_NSS3 + NSSSignatureConfiguration::setNSSDir(GooString(path)); +#else + (void)path; +#endif +} + +/** + * poppler_get_nss_dir: + * + * Get NSS directory + * + * Return value: (transfer full): nss directroy. + * + * Since: 23.07.0 + **/ +char *poppler_get_nss_dir(void) +{ +#ifdef ENABLE_NSS3 + return g_strdup(NSSSignatureConfiguration::getNSSDir().c_str()); +#else + return nullptr; +#endif +} + +/** + * poppler_set_nss_password_callback: + * @func: (scope call): a #PopplerNssPasswordFunc that represents a signature annotation + * + * A callback which asks for certificate password + * + * Since: 23.07.0 + **/ +void poppler_set_nss_password_callback(PopplerNssPasswordFunc func) +{ +#ifdef ENABLE_NSS3 + NSSSignatureConfiguration::setNSSPasswordCallback(func); +#else + g_warning("poppler_set_nss_password_callback called but this poppler is built without NSS support"); + (void)func; +#endif +} diff --git a/glib/poppler-form-field.h b/glib/poppler-form-field.h index b48c5064..d6218ab0 100644 --- a/glib/poppler-form-field.h +++ b/glib/poppler-form-field.h @@ -249,6 +249,120 @@ const gchar *poppler_signature_info_get_signer_name(const PopplerSignatureInfo * POPPLER_PUBLIC GDateTime *poppler_signature_info_get_local_signing_time(const PopplerSignatureInfo *siginfo); +/* Signing Data */ +#define POPPLER_TYPE_SIGNING_DATA (poppler_signing_data_get_type()) +POPPLER_PUBLIC +GType poppler_signing_data_get_type(void) G_GNUC_CONST; +POPPLER_PUBLIC +PopplerSigningData *poppler_signing_data_new(void); +POPPLER_PUBLIC +PopplerSigningData *poppler_signing_data_copy(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_free(PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_destination_filename(PopplerSigningData *signing_data, const gchar *filename); +POPPLER_PUBLIC +const gchar *poppler_signing_data_get_destination_filename(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_certificate_info(PopplerSigningData *signing_data, const PopplerCertificateInfo *certificate_info); +POPPLER_PUBLIC +const PopplerCertificateInfo *poppler_signing_data_get_certificate_info(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_page(PopplerSigningData *signing_data, int page); +POPPLER_PUBLIC +int poppler_signing_data_get_page(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_signature_text(PopplerSigningData *signing_data, const gchar *signature_text); +POPPLER_PUBLIC +const gchar *poppler_signing_data_get_signature_text(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_signature_text_left(PopplerSigningData *signing_data, const gchar *signature_text_left); +POPPLER_PUBLIC +const gchar *poppler_signing_data_get_signature_text_left(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_signature_rectangle(PopplerSigningData *signing_data, const PopplerRectangle *signature_rect); +POPPLER_PUBLIC +const PopplerRectangle *poppler_signing_data_get_signature_rectangle(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_font_color(PopplerSigningData *signing_data, const PopplerColor *font_color); +POPPLER_PUBLIC +const PopplerColor *poppler_signing_data_get_font_color(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_font_size(PopplerSigningData *signing_data, gdouble font_size); +POPPLER_PUBLIC +gdouble poppler_signing_data_get_font_size(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_left_font_size(PopplerSigningData *signing_data, gdouble font_size); +POPPLER_PUBLIC +gdouble poppler_signing_data_get_left_font_size(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_border_color(PopplerSigningData *signing_data, const PopplerColor *border_color); +POPPLER_PUBLIC +const PopplerColor *poppler_signing_data_get_border_color(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_border_width(PopplerSigningData *signing_data, gdouble border_width); +POPPLER_PUBLIC +gdouble poppler_signing_data_get_border_width(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_background_color(PopplerSigningData *signing_data, const PopplerColor *background_color); +POPPLER_PUBLIC +const PopplerColor *poppler_signing_data_get_background_color(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_field_partial_name(PopplerSigningData *signing_data, const gchar *field_partial_name); +POPPLER_PUBLIC +const gchar *poppler_signing_data_get_field_partial_name(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_reason(PopplerSigningData *signing_data, const gchar *reason); +POPPLER_PUBLIC +const gchar *poppler_signing_data_get_reason(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_location(PopplerSigningData *signing_data, const gchar *location); +POPPLER_PUBLIC +const gchar *poppler_signing_data_get_location(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_image_path(PopplerSigningData *signing_data, const gchar *image_path); +POPPLER_PUBLIC +const gchar *poppler_signing_data_get_image_path(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_password(PopplerSigningData *signing_data, const gchar *password); +POPPLER_PUBLIC +const gchar *poppler_signing_data_get_password(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_document_owner_password(PopplerSigningData *signing_data, const gchar *document_owner_password); +POPPLER_PUBLIC +const gchar *poppler_signing_data_get_document_owner_password(const PopplerSigningData *signing_data); +POPPLER_PUBLIC +void poppler_signing_data_set_document_user_password(PopplerSigningData *signing_data, const gchar *document_user_password); +POPPLER_PUBLIC +const gchar *poppler_signing_data_get_document_user_password(const PopplerSigningData *signing_data); + +/* Certificate Information */ +#define POPPLER_TYPE_CERTIFICATE_INFO (poppler_certificate_info_get_type()) +POPPLER_PUBLIC +GType poppler_certificate_info_get_type(void) G_GNUC_CONST; +PopplerCertificateInfo *poppler_certificate_info_new(void); +POPPLER_PUBLIC +PopplerCertificateInfo *poppler_certificate_info_copy(const PopplerCertificateInfo *certificate_info); +POPPLER_PUBLIC +void poppler_certificate_info_free(PopplerCertificateInfo *certificate_info); +POPPLER_PUBLIC +const char *poppler_certificate_info_get_id(const PopplerCertificateInfo *certificate_info); +POPPLER_PUBLIC +const char *poppler_certificate_info_get_subject_common_name(const PopplerCertificateInfo *certificate_info); +POPPLER_PUBLIC +PopplerCertificateInfo *poppler_get_certificate_info_by_id(const char *id); +POPPLER_PUBLIC +GList *poppler_get_available_signing_certificates(void); + +/* NSS */ +POPPLER_PUBLIC +void poppler_set_nss_dir(const char *path); +POPPLER_PUBLIC +char *poppler_get_nss_dir(void); +typedef char *(*PopplerNssPasswordFunc)(const gchar *text); +POPPLER_PUBLIC +void poppler_set_nss_password_callback(PopplerNssPasswordFunc func); + G_END_DECLS #endif /* __POPPLER_FORM_FIELD_H__ */ diff --git a/glib/poppler.h b/glib/poppler.h index 710b7b23..70f2172a 100644 --- a/glib/poppler.h +++ b/glib/poppler.h @@ -47,7 +47,8 @@ typedef enum POPPLER_ERROR_ENCRYPTED, POPPLER_ERROR_OPEN_FILE, POPPLER_ERROR_BAD_CATALOG, - POPPLER_ERROR_DAMAGED + POPPLER_ERROR_DAMAGED, + POPPLER_ERROR_SIGNING } PopplerError; /** @@ -220,6 +221,8 @@ typedef struct _PopplerTextSpan PopplerTextSpan; typedef struct _PopplerPageRange PopplerPageRange; typedef struct _PopplerSignatureInfo PopplerSignatureInfo; typedef struct _PopplerAnnotStamp PopplerAnnotStamp; +typedef struct _PopplerCertificateInfo PopplerCertificateInfo; +typedef struct _PopplerSigningData PopplerSigningData; /** * PopplerBackend: diff --git a/glib/reference/poppler-sections.txt b/glib/reference/poppler-sections.txt index f027cd03..aa09e2d5 100644 --- a/glib/reference/poppler-sections.txt +++ b/glib/reference/poppler-sections.txt @@ -417,6 +417,57 @@ poppler_signature_info_get_certificate_status poppler_signature_info_get_signature_status poppler_signature_info_get_signer_name poppler_signature_info_get_local_signing_time +poppler_signing_data_new +poppler_signing_data_copy +poppler_signing_data_free +poppler_signing_data_set_destination_filename +poppler_signing_data_set_certificate_info +poppler_signing_data_set_page +poppler_signing_data_set_signature_text +poppler_signing_data_set_signature_text_left +poppler_signing_data_set_signature_rectangle +poppler_signing_data_set_font_color +poppler_signing_data_set_font_size +poppler_signing_data_set_left_font_size +poppler_signing_data_set_border_color +poppler_signing_data_set_border_width +poppler_signing_data_set_background_color +poppler_signing_data_set_field_partial_name +poppler_signing_data_set_reason +poppler_signing_data_set_location +poppler_signing_data_set_image_path +poppler_signing_data_set_password +poppler_signing_data_set_document_owner_password +poppler_signing_data_set_document_user_password +poppler_signing_data_get_destination_filename +poppler_signing_data_get_certificate_info +poppler_signing_data_get_page +poppler_signing_data_get_signature_text +poppler_signing_data_get_signature_text_left +poppler_signing_data_get_signature_rectangle +poppler_signing_data_get_font_color +poppler_signing_data_get_font_size +poppler_signing_data_get_left_font_size +poppler_signing_data_get_border_color +poppler_signing_data_get_border_width +poppler_signing_data_get_background_color +poppler_signing_data_get_field_partial_name +poppler_signing_data_get_reason +poppler_signing_data_get_location +poppler_signing_data_get_image_path +poppler_signing_data_get_password +poppler_signing_data_get_document_owner_password +poppler_signing_data_get_document_user_password +poppler_certificate_info_new +poppler_certificate_info_copy +poppler_certificate_info_get_nick_name +poppler_certificate_info_get_subject_common_name +poppler_get_certificate_info_by_nick_name +poppler_set_nss_dir +poppler_get_nss_dir +poppler_set_nss_password_callback +poppler_get_available_signing_certificates +poppler_certificate_info_free <SUBSECTION Standard> POPPLER_FORM_FIELD diff --git a/glib/reference/poppler.types b/glib/reference/poppler.types index 1ab636b3..216633f4 100644 --- a/glib/reference/poppler.types +++ b/glib/reference/poppler.types @@ -92,3 +92,5 @@ poppler_structure_writing_mode_get_type poppler_text_attributes_get_type poppler_text_span_get_type poppler_viewer_preferences_get_type +poppler_signing_data_get_type +poppler_certificate_info_get_type \ No newline at end of file
