]> www.fi.muni.cz Git - evince.git/blob - shell/ev-password.c
Support for gnome-keyring for encrypted PDF's.
[evince.git] / shell / ev-password.c
1 /* this file is part of evince, a gnome document viewer
2  *
3  *  Copyright (C) 2005 Red Hat, Inc
4  *
5  * Evince is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * Evince is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <glib/gi18n.h>
25 #include <gtk/gtk.h>
26 #include <glade/glade.h>
27 #include <gnome-keyring.h>
28 #include <libgnomevfs/gnome-vfs-utils.h>
29
30 #include "ev-password.h"
31
32 enum {
33         PROP_0,
34         PROP_URI,
35 };
36
37 struct _EvPasswordDialogPrivate {
38         
39         gchar *uri;
40     
41         GtkWidget *bad_label;
42         GtkWidget *label;
43         GtkWidget *entry;
44         GtkWidget *check_default;
45         GtkWidget *check_session;
46 };
47
48 #define EV_PASSWORD_DIALOG_GET_PRIVATE(object) \
49         (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_PASSWORD_DIALOG, EvPasswordDialogPrivate));
50
51 G_DEFINE_TYPE (EvPasswordDialog, ev_password_dialog, GTK_TYPE_DIALOG)
52
53
54 static void ev_password_dialog_entry_changed_cb   (GtkEditable *editable,
55                                                    EvPasswordDialog *dialog);
56 static void ev_password_dialog_entry_activated_cb (GtkEntry *entry,
57                                                    EvPasswordDialog *dialog);
58 static void ev_password_set_bad_password_label    (EvPasswordDialog *dialog,
59                                                    gchar     *message);
60 static void ev_password_search_in_keyring         (EvPasswordDialog *dialog, 
61                                                    const gchar *uri);
62
63 static void
64 ev_password_dialog_set_property (GObject      *object,
65                                  guint         prop_id,
66                                  const GValue *value,
67                                  GParamSpec   *pspec)
68 {
69         EvPasswordDialog *dialog = EV_PASSWORD_DIALOG (object);
70         char *format;
71         char *markup;
72         char *base_name;
73         char *file_name;
74
75         switch (prop_id)
76         {
77         case PROP_URI:
78                 dialog->priv->uri = g_strdup (g_value_get_string (value));
79
80                 file_name = gnome_vfs_format_uri_for_display (dialog->priv->uri);
81                 base_name = g_path_get_basename (file_name);
82                 format = g_strdup_printf ("<span size=\"larger\" weight=\"bold\">%s</span>\n\n%s",
83                                           _("Password required"),
84                                           _("The document <i>%s</i> is locked and requires a password before it can be opened."));
85                 markup = g_markup_printf_escaped (format, base_name);
86
87                 gtk_label_set_markup (GTK_LABEL (dialog->priv->label), markup);
88
89                 g_free (base_name);
90                 g_free (file_name);
91                 g_free (format);
92                 g_free (markup);
93
94                 ev_password_search_in_keyring (dialog, dialog->priv->uri);
95                 break;
96         default:
97                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
98                 break;
99         }
100 }
101
102 static void
103 ev_password_dialog_finalize (GObject *object)
104 {
105         EvPasswordDialog *dialog = EV_PASSWORD_DIALOG (object);
106
107         if (dialog->priv->uri) {
108                 g_free (dialog->priv->uri);
109                 dialog->priv->uri = NULL;
110         }
111
112         G_OBJECT_CLASS (ev_password_dialog_parent_class)->finalize (object);
113 }
114
115
116 static void
117 ev_password_dialog_class_init (EvPasswordDialogClass *class)
118 {
119         GObjectClass *g_object_class;
120         GtkWidgetClass *widget_class;
121
122         g_object_class = G_OBJECT_CLASS (class);
123         widget_class = GTK_WIDGET_CLASS (class);
124
125         g_type_class_add_private (g_object_class, sizeof (EvPasswordDialogPrivate));
126
127         g_object_class->set_property = ev_password_dialog_set_property;
128         g_object_class->finalize = ev_password_dialog_finalize;
129         
130         g_object_class_install_property (g_object_class,
131                                          PROP_URI,
132                                          g_param_spec_string ("uri",
133                                                               "Document URI",
134                                                               "Encrypted document URI",
135                                                               NULL,
136                                                               G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
137 }
138
139
140 static void
141 ev_password_dialog_init (EvPasswordDialog *dialog)
142 {
143         GtkWidget *hbox;
144         const char *glade_file = DATADIR "/evince-password.glade";
145         GladeXML *xml;
146
147         dialog->priv = EV_PASSWORD_DIALOG_GET_PRIVATE (dialog);
148                 
149         gtk_window_set_title (GTK_WINDOW (dialog), _("Enter password"));
150         gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
151         gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
152         gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
153         gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 12);
154
155         gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL,
156                                GTK_RESPONSE_CANCEL);
157         gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_OK,
158                                GTK_RESPONSE_OK);
159
160         xml = glade_xml_new (glade_file, "hbox-contents", NULL);
161         g_assert (xml);
162         
163         hbox = glade_xml_get_widget (xml, "hbox-contents");
164         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
165
166         dialog->priv->bad_label = glade_xml_get_widget (xml, "bad_password_label");
167         dialog->priv->check_default = glade_xml_get_widget (xml, "savesession_checkbutton");
168         dialog->priv->check_session = glade_xml_get_widget (xml, "savekeyring_checkbutton");
169         dialog->priv->entry = glade_xml_get_widget (xml, "password_entry");
170         dialog->priv->label = glade_xml_get_widget (xml, "password_label");
171
172         g_signal_connect (dialog->priv->entry, "changed", G_CALLBACK (ev_password_dialog_entry_changed_cb), dialog);
173         g_signal_connect (dialog->priv->entry, "activate", G_CALLBACK (ev_password_dialog_entry_activated_cb), dialog);
174
175         ev_password_set_bad_password_label (dialog, " ");
176         
177         if (!gnome_keyring_is_available ()) {
178                 gtk_widget_hide (dialog->priv->check_default);
179                 gtk_widget_hide (dialog->priv->check_session);
180         }
181
182         g_object_unref (xml);
183 }
184
185 static void
186 ev_password_set_bad_password_label (EvPasswordDialog *dialog,
187                                     gchar     *message)
188 {
189         gchar *markup;
190
191         markup = g_strdup_printf ("<span color=\"red\" size=\"smaller\">%s</span>",
192                                   message);
193         gtk_label_set_markup (GTK_LABEL (dialog->priv->bad_label), markup);
194         g_free (markup);
195 }
196
197 static void
198 ev_password_dialog_entry_changed_cb (GtkEditable *editable,
199                                      EvPasswordDialog *dialog)
200 {
201         const char *text;
202
203         text = gtk_entry_get_text (GTK_ENTRY (editable));
204
205         if (text == NULL || *text == '\0')
206                 gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), 
207                                                    GTK_RESPONSE_OK, FALSE);
208         else
209                 gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), 
210                                                    GTK_RESPONSE_OK, TRUE);
211
212         ev_password_set_bad_password_label (dialog, " ");
213 }
214
215 static void
216 ev_password_dialog_entry_activated_cb (GtkEntry *entry,
217                                        EvPasswordDialog *dialog)
218 {
219         gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
220 }
221
222 void
223 ev_password_dialog_save_password (EvPasswordDialog *dialog)
224 {
225         GnomeKeyringAttributeList *attributes;
226         GnomeKeyringAttribute attribute;
227         guint32 item_id;
228         gchar *name;
229         gchar *unescaped_uri;
230
231         attributes = gnome_keyring_attribute_list_new ();
232
233         attribute.name = g_strdup ("type");
234         attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
235         attribute.value.string = g_strdup ("document_password");
236         g_array_append_val (attributes, attribute);
237  
238         attribute.name = g_strdup ("uri");
239         attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
240         attribute.value.string = g_strdup (dialog->priv->uri);
241         g_array_append_val (attributes, attribute);
242         
243         unescaped_uri = gnome_vfs_unescape_string_for_display (dialog->priv->uri);
244         name = g_strdup_printf (_("Password for document %s"), unescaped_uri);  
245
246         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_default))) {
247                 gnome_keyring_item_create_sync (NULL,
248                                                 GNOME_KEYRING_ITEM_GENERIC_SECRET,
249                                                 name,
250                                                 attributes,
251                                                 ev_password_dialog_get_password (dialog),
252                                                 TRUE,
253                                                 &item_id);
254         }
255
256         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_session))) {
257                 gnome_keyring_item_create_sync ("session",
258                                                 GNOME_KEYRING_ITEM_GENERIC_SECRET,
259                                                 name,
260                                                 attributes,
261                                                 ev_password_dialog_get_password (dialog),
262                                                 TRUE,
263                                                 &item_id);
264         }
265         
266         gnome_keyring_attribute_list_free (attributes);
267         g_free (name);
268         g_free (unescaped_uri);
269         
270         return;
271 }
272
273 static void 
274 ev_password_keyring_found_cb (GnomeKeyringResult result,
275                               GList             *list,
276                               gpointer           data)
277
278 {
279         GnomeKeyringFound *found;
280         EvPasswordDialog *dialog = EV_PASSWORD_DIALOG (data);
281
282         if (result != GNOME_KEYRING_RESULT_OK || list == NULL) 
283                     return;
284
285         found = list->data;
286         gtk_entry_set_text (GTK_ENTRY (dialog->priv->entry), found->secret);
287 }                         
288
289 static void
290 ev_password_search_in_keyring (EvPasswordDialog *dialog, const gchar *uri)
291 {
292         GnomeKeyringAttributeList *attributes;
293         GnomeKeyringAttribute attribute;
294         
295         attributes = gnome_keyring_attribute_list_new ();
296
297         attribute.name = g_strdup ("type");
298         attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
299         attribute.value.string = g_strdup ("document_password");
300         g_array_append_val (attributes, attribute);
301  
302         attribute.name = g_strdup ("uri");
303         attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
304         attribute.value.string = g_strdup (uri);
305         g_array_append_val (attributes, attribute);
306          
307         gnome_keyring_find_items  (GNOME_KEYRING_ITEM_GENERIC_SECRET,
308                                    attributes,
309                                    ev_password_keyring_found_cb,
310                                    g_object_ref (dialog),
311                                    g_object_unref);
312         gnome_keyring_attribute_list_free (attributes);
313         return;
314 }
315
316 char *
317 ev_password_dialog_get_password (EvPasswordDialog *dialog)
318 {
319         return g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->priv->entry)));
320 }
321
322 void
323 ev_password_dialog_set_bad_pass (EvPasswordDialog *dialog)
324 {
325         gtk_entry_set_text (GTK_ENTRY (dialog->priv->entry), "");
326         ev_password_set_bad_password_label (dialog, _("Incorrect password"));
327 }
328
329