#include "gl-app.h" #include #include #ifndef PATH_MAX #define PATH_MAX 2048 #endif #include "mupdf/helpers/pkcs7-check.h" #include "mupdf/helpers/pkcs7-openssl.h" static pdf_widget *sig_widget; static char sig_designated_name[500]; static enum pdf_signature_error sig_cert_error; static enum pdf_signature_error sig_digest_error; static int sig_subsequent_edits; static char cert_filename[PATH_MAX]; static struct input cert_password; static void do_sign(void) { pdf_pkcs7_signer *signer = NULL; fz_var(signer); fz_try(ctx) { signer = pkcs7_openssl_read_pfx(ctx, cert_filename, cert_password.text); pdf_sign_signature(ctx, pdf, sig_widget, signer); ui_show_warning_dialog("Signed document successfully."); } fz_always(ctx) { if (signer) signer->drop(signer); } fz_catch(ctx) ui_show_warning_dialog("%s", fz_caught_message(ctx)); if (pdf_update_page(ctx, sig_widget->page)) render_page(); } static void do_clear_signature(void) { fz_try(ctx) { pdf_clear_signature(ctx, pdf, sig_widget); ui_show_warning_dialog("Signature cleared successfully."); } fz_catch(ctx) ui_show_warning_dialog("%s", fz_caught_message(ctx)); if (pdf_update_page(ctx, sig_widget->page)) render_page(); } static void cert_password_dialog(void) { int is; ui_dialog_begin(400, (ui.gridsize+4)*3); { ui_layout(T, X, NW, 2, 2); ui_label("Password:"); is = ui_input(&cert_password, 200, 1); ui_layout(B, X, NW, 2, 2); ui_panel_begin(0, ui.gridsize, 0, 0, 0); { ui_layout(R, NONE, S, 0, 0); if (ui_button("Cancel")) ui.dialog = NULL; ui_spacer(); if (ui_button("Okay") || is == UI_INPUT_ACCEPT) { ui.dialog = NULL; do_sign(); } } ui_panel_end(); } ui_dialog_end(); } static int cert_file_filter(const char *fn) { return !!strstr(fn, ".pfx"); } static void cert_file_dialog(void) { if (ui_open_file(cert_filename)) { if (cert_filename[0] != 0) { ui_input_init(&cert_password, ""); ui.focus = &cert_password; ui.dialog = cert_password_dialog; } else ui.dialog = NULL; } } static void sig_sign_dialog(void) { const char *label = pdf_field_label(ctx, sig_widget->obj); ui_dialog_begin(400, (ui.gridsize+4)*3 + ui.lineheight*10); { ui_layout(T, X, NW, 2, 2); ui_label("%s", label); ui_spacer(); ui_label("Would you like to sign this field?"); ui_layout(B, X, NW, 2, 2); ui_panel_begin(0, ui.gridsize, 0, 0, 0); { ui_layout(R, NONE, S, 0, 0); if (ui_button("Cancel") || (!ui.focus && ui.key == KEY_ESCAPE)) ui.dialog = NULL; ui_spacer(); if (!(pdf_field_flags(ctx, sig_widget->obj) & PDF_FIELD_IS_READ_ONLY)) { if (ui_button("Sign")) { fz_strlcpy(cert_filename, filename, sizeof cert_filename); ui_init_open_file(".", cert_file_filter); ui.dialog = cert_file_dialog; } } } ui_panel_end(); } ui_dialog_end(); } static void sig_verify_dialog(void) { const char *label = pdf_field_label(ctx, sig_widget->obj); ui_dialog_begin(400, (ui.gridsize+4)*3 + ui.lineheight*10); { ui_layout(T, X, NW, 2, 2); ui_label("%s", label); ui_spacer(); ui_label("Designated name: %s.", sig_designated_name); ui_spacer(); if (sig_cert_error) ui_label("Certificate error: %s", pdf_signature_error_description(sig_cert_error)); else ui_label("Certificate is trusted."); ui_spacer(); if (sig_digest_error) ui_label("Digest error: %s", pdf_signature_error_description(sig_digest_error)); else if (sig_subsequent_edits) ui_label("The signature is valid but there have been edits since signing."); else ui_label("The document is unchanged since signing."); ui_layout(B, X, NW, 2, 2); ui_panel_begin(0, ui.gridsize, 0, 0, 0); { ui_layout(L, NONE, S, 0, 0); if (ui_button("Clear")) { ui.dialog = NULL; do_clear_signature(); } ui_layout(R, NONE, S, 0, 0); if (ui_button("Close") || (!ui.focus && ui.key == KEY_ESCAPE)) ui.dialog = NULL; } ui_panel_end(); } ui_dialog_end(); } static void show_sig_dialog(pdf_widget *widget) { fz_try(ctx) { sig_widget = widget; if (pdf_signature_is_signed(ctx, pdf, widget->obj)) { sig_cert_error = pdf_check_certificate(ctx, pdf, widget->obj); sig_digest_error = pdf_check_digest(ctx, pdf, widget->obj); sig_subsequent_edits = pdf_signature_incremental_change_since_signing(ctx, pdf, widget->obj); pdf_signature_designated_name(ctx, pdf, widget->obj, sig_designated_name, sizeof(sig_designated_name)); ui.dialog = sig_verify_dialog; } else { ui.dialog = sig_sign_dialog; } } fz_catch(ctx) ui_show_warning_dialog("%s", fz_caught_message(ctx)); } static pdf_widget *tx_widget; static struct input tx_input; static void tx_dialog(void) { int ff = pdf_field_flags(ctx, tx_widget->obj); const char *label = pdf_field_label(ctx, tx_widget->obj); int tx_h = (ff & PDF_TX_FIELD_IS_MULTILINE) ? 10 : 1; int lbl_h = ui_break_lines((char*)label, NULL, 20, 394, NULL); int is; ui_dialog_begin(400, (ui.gridsize+4)*3 + ui.lineheight*(tx_h+lbl_h-2)); { ui_layout(T, X, NW, 2, 2); ui_label("%s", label); is = ui_input(&tx_input, 200, tx_h); ui_layout(B, X, NW, 2, 2); ui_panel_begin(0, ui.gridsize, 0, 0, 0); { ui_layout(R, NONE, S, 0, 0); if (ui_button("Cancel") || (!ui.focus && ui.key == KEY_ESCAPE)) ui.dialog = NULL; ui_spacer(); if (ui_button("Okay") || is == UI_INPUT_ACCEPT) { pdf_set_text_field_value(ctx, tx_widget, tx_input.text); if (pdf_update_page(ctx, tx_widget->page)) render_page(); ui.dialog = NULL; } } ui_panel_end(); } ui_dialog_end(); } void show_tx_dialog(pdf_widget *widget) { ui_input_init(&tx_input, pdf_field_value(ctx, widget->obj)); ui.focus = &tx_input; ui.dialog = tx_dialog; tx_widget = widget; } static pdf_widget *ch_widget; static void ch_dialog(void) { const char *label; const char *value; char **options; int n, choice; int label_h; label = pdf_field_label(ctx, ch_widget->obj); label_h = ui_break_lines((char*)label, NULL, 20, 394, NULL); n = pdf_choice_widget_options(ctx, ch_widget, 0, NULL); options = fz_malloc_array(ctx, n, char *); pdf_choice_widget_options(ctx, ch_widget, 0, (const char **)options); value = pdf_field_value(ctx, ch_widget->obj); ui_dialog_begin(400, (ui.gridsize+4)*3 + ui.lineheight*(label_h-1)); { ui_layout(T, X, NW, 2, 2); ui_label("%s", label); choice = ui_select("Widget/Ch", value, (const char **)options, n); if (choice >= 0) pdf_set_choice_field_value(ctx, ch_widget, options[choice]); ui_layout(B, X, NW, 2, 2); ui_panel_begin(0, ui.gridsize, 0, 0, 0); { ui_layout(R, NONE, S, 0, 0); if (ui_button("Cancel") || (!ui.focus && ui.key == KEY_ESCAPE)) ui.dialog = NULL; ui_spacer(); if (ui_button("Okay")) { if (pdf_update_page(ctx, ch_widget->page)) render_page(); ui.dialog = NULL; } } ui_panel_end(); } ui_dialog_end(); fz_free(ctx, options); } void do_widget_canvas(fz_irect canvas_area) { pdf_widget *widget; fz_rect bounds; fz_irect area; if (!pdf) return; for (widget = pdf_first_widget(ctx, page); widget; widget = pdf_next_widget(ctx, widget)) { bounds = pdf_bound_widget(ctx, widget); bounds = fz_transform_rect(bounds, view_page_ctm); area = fz_irect_from_rect(bounds); if (ui_mouse_inside(canvas_area) && ui_mouse_inside(area)) { if (!widget->is_hot) pdf_annot_event_enter(ctx, widget); widget->is_hot = 1; ui.hot = widget; if (!ui.active && ui.down) { ui.active = widget; pdf_annot_event_down(ctx, widget); if (selected_annot != widget) { if (selected_annot && pdf_annot_type(ctx, selected_annot) == PDF_ANNOT_WIDGET) pdf_annot_event_blur(ctx, selected_annot); selected_annot = widget; pdf_annot_event_focus(ctx, widget); } } } else { if (widget->is_hot) pdf_annot_event_exit(ctx, widget); widget->is_hot = 0; } /* Set is_hot and is_active to select current appearance */ widget->is_active = (ui.active == widget && ui.down); if (showform) { glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glColor4f(0, 0, 1, 0.1f); glRectf(area.x0, area.y0, area.x1, area.y1); glDisable(GL_BLEND); } if (ui.active == widget || (!ui.active && ui.hot == widget)) { glLineStipple(1, 0xAAAA); glEnable(GL_LINE_STIPPLE); glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); glEnable(GL_BLEND); glColor4f(1, 1, 1, 1); glBegin(GL_LINE_LOOP); glVertex2f(area.x0-0.5f, area.y0-0.5f); glVertex2f(area.x1+0.5f, area.y0-0.5f); glVertex2f(area.x1+0.5f, area.y1+0.5f); glVertex2f(area.x0-0.5f, area.y1+0.5f); glEnd(); glDisable(GL_BLEND); glDisable(GL_LINE_STIPPLE); } if (ui.hot == widget && ui.active == widget && !ui.down) { pdf_annot_event_up(ctx, widget); if (pdf_widget_type(ctx, widget) == PDF_WIDGET_TYPE_SIGNATURE) { show_sig_dialog(widget); } else { if (pdf_field_flags(ctx, widget->obj) & PDF_FIELD_IS_READ_ONLY) continue; switch (pdf_widget_type(ctx, widget)) { default: break; case PDF_WIDGET_TYPE_CHECKBOX: case PDF_WIDGET_TYPE_RADIOBUTTON: pdf_toggle_widget(ctx, widget); break; case PDF_WIDGET_TYPE_TEXT: show_tx_dialog(widget); break; case PDF_WIDGET_TYPE_COMBOBOX: case PDF_WIDGET_TYPE_LISTBOX: ui.dialog = ch_dialog; ch_widget = widget; break; } } } } if (pdf_update_page(ctx, page)) render_page(); }