1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
6 * Copyright (C) 2001 Ximian, Inc.
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU Lesser General Public
12 * License as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
26 * This looks a lot more complicated than it is, and than you'd think
27 * it would need to be. There is however, method to the madness.
29 * The code most cope with being called from any thread at any time,
30 * recursively from the main thread, and then serialising every
31 * request so that sane and correct values are always returned, and
32 * duplicate requests are never made.
34 * To this end, every call is marshalled and queued and a dispatch
35 * method invoked until that request is satisfied. If mainloop
36 * recursion occurs, then the sub-call will necessarily return out of
37 * order, but will not be processed out of order.
45 #include <libgnome/gnome-config.h>
46 #include <glib/gi18n-lib.h>
47 #include <gtk/gtkversion.h>
48 #include <gtk/gtkentry.h>
49 #include <gtk/gtkvbox.h>
50 #include <gtk/gtkcheckbutton.h>
51 #include <gtk/gtkmessagedialog.h>
53 #include "e-passwords.h"
54 #include "libedataserver/e-msgport.h"
55 #include "libedataserver/e-url.h"
57 #ifdef WITH_GNOME_KEYRING
58 #include <gnome-keyring.h>
61 #ifndef ENABLE_THREADS
62 #define ENABLE_THREADS (1)
68 static pthread_t main_thread;
69 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
70 #define LOCK() pthread_mutex_lock(&lock)
71 #define UNLOCK() pthread_mutex_unlock(&lock)
82 void (*dispatch)(struct _EPassMsg *);
85 struct _GtkWindow *parent;
86 const char *component;
101 guint noreply:1; /* supress replies; when calling
102 * dispatch functions from others */
105 typedef struct _EPassMsg EPassMsg;
107 static GHashTable *passwords = NULL;
108 static GtkDialog *password_dialog = NULL;
109 static EDList request_list = E_DLIST_INITIALISER(request_list);
111 static int ep_online_state = TRUE;
113 static char *decode_base64 (char *base64);
114 static int base64_encode_close(unsigned char *in, int inlen, gboolean break_lines, unsigned char *out, int *state, int *save);
115 static int base64_encode_step(unsigned char *in, int len, gboolean break_lines, unsigned char *out, int *state, int *save);
118 ep_idle_dispatch(void *data)
122 /* As soon as a password window is up we stop; it will
123 re-invoke us when it has been closed down */
125 while (password_dialog == NULL && (msg = (EPassMsg *)e_dlist_remhead(&request_list))) {
140 ep_msg_new(void (*dispatch)(EPassMsg *))
146 msg = g_malloc0(sizeof(*msg));
147 msg->dispatch = dispatch;
148 msg->msg.reply_port = e_msgport_new();
149 #ifdef ENABLE_THREADS
150 msg->ismain = pthread_equal(pthread_self(), main_thread);
158 ep_msg_free(EPassMsg *msg)
160 e_msgport_destroy(msg->msg.reply_port);
161 g_free(msg->password);
166 ep_msg_send(EPassMsg *msg)
171 e_dlist_addtail(&request_list, (EDListNode *)&msg->msg);
174 idle_id = g_idle_add(ep_idle_dispatch, NULL);
184 ep_idle_dispatch(NULL);
185 while ((m = (EPassMsg *)e_msgport_get(msg->msg.reply_port)) == NULL)
186 g_main_context_iteration(NULL, TRUE);
189 EMsg *reply_msg = e_msgport_wait(msg->msg.reply_port);
190 g_assert(reply_msg == &msg->msg);
194 /* the functions that actually do the work */
195 #ifdef WITH_GNOME_KEYRING
197 ep_clear_passwords_keyring(EPassMsg *msg)
199 GnomeKeyringAttributeList *attributes;
200 GnomeKeyringResult result;
201 GList *matches = NULL, *tmp;
202 char *default_keyring = NULL;
204 result = gnome_keyring_get_default_keyring_sync (&default_keyring);
205 if (!default_keyring) {
206 if (gnome_keyring_create_sync ("default", NULL) != GNOME_KEYRING_RESULT_OK) {
208 e_msgport_reply(&msg->msg);
211 default_keyring = g_strdup ("default");
214 d(g_print("Get Default %d\n", result));
216 /* Not called at all */
217 attributes = gnome_keyring_attribute_list_new ();
218 gnome_keyring_attribute_list_append_string (attributes, "application", "Evolution");
220 result = gnome_keyring_find_items_sync (GNOME_KEYRING_ITEM_NETWORK_PASSWORD, attributes, &matches);
221 d(g_print ("Find Items %d\n", result));
223 gnome_keyring_attribute_list_free (attributes);
226 g_print ("Couldn't clear password");
228 for (tmp = matches; tmp; tmp = tmp->next) {
229 result = gnome_keyring_item_delete_sync (default_keyring, ((GnomeKeyringFound *) tmp->data)->item_id);
230 d(g_print("Delete Items %d\n", result));
234 g_free (default_keyring);
236 e_msgport_reply(&msg->msg);
240 ep_clear_passwords_file(EPassMsg *msg)
244 path = g_strdup_printf ("/Evolution/Passwords-%s", msg->component);
246 gnome_config_private_clean_section (path);
247 gnome_config_private_sync_file ("/Evolution");
252 e_msgport_reply(&msg->msg);
256 free_entry (gpointer key, gpointer value, gpointer user_data)
259 memset (value, 0, strlen (value));
264 #ifdef WITH_GNOME_KEYRING
266 ep_forget_passwords_keyring(EPassMsg *msg)
268 GnomeKeyringAttributeList *attributes;
269 GnomeKeyringResult result;
270 GList *matches = NULL, *tmp;
271 char *default_keyring = NULL;
273 result = gnome_keyring_get_default_keyring_sync (&default_keyring);
274 if (!default_keyring) {
275 if (gnome_keyring_create_sync ("default", NULL) != GNOME_KEYRING_RESULT_OK) {
277 e_msgport_reply(&msg->msg);
280 default_keyring = g_strdup ("default");
282 d(g_print("Get Default %d\n", result));
284 attributes = gnome_keyring_attribute_list_new ();
285 gnome_keyring_attribute_list_append_string (attributes, "application", "Evolution");
287 result = gnome_keyring_find_items_sync (GNOME_KEYRING_ITEM_NETWORK_PASSWORD, attributes, &matches);
288 d(g_print ("Find Items %d\n", result));
290 gnome_keyring_attribute_list_free (attributes);
293 g_print ("Couldn't clear password");
295 for (tmp = matches; tmp; tmp = tmp->next) {
296 result = gnome_keyring_item_delete_sync (default_keyring, ((GnomeKeyringFound *) tmp->data)->item_id);
297 d(g_print("Delete Items %d\n", result));
301 g_free (default_keyring);
303 /* free up the session passwords */
304 g_hash_table_foreach_remove (passwords, free_entry, NULL);
307 e_msgport_reply(&msg->msg);
312 ep_forget_passwords_file(EPassMsg *msg)
317 it = gnome_config_private_init_iterator_sections("/Evolution");
318 while ( (it = gnome_config_iterator_next(it, &key, NULL)) ) {
319 if (0 == strncmp(key, "Passwords-", 10)) {
320 char *section = g_strdup_printf("/Evolution/%s", key);
322 gnome_config_private_clean_section (section);
328 gnome_config_private_sync_file ("/Evolution");
330 /* free up the session passwords */
331 g_hash_table_foreach_remove (passwords, free_entry, NULL);
334 e_msgport_reply(&msg->msg);
338 password_path (const char *component_name, const char *key)
340 char *keycopy, *path;
342 keycopy = g_strdup (key);
344 for (i = 0; i < strlen (keycopy); i ++)
345 if (keycopy[i] == '/' || keycopy[i] =='=')
348 path = g_strdup_printf ("/Evolution/Passwords-%s/%s", component_name, keycopy);
355 #ifdef WITH_GNOME_KEYRING
357 ep_remember_password_keyring(EPassMsg *msg)
359 gpointer okey, value;
361 if (g_hash_table_lookup_extended (passwords, msg->key, &okey, &value)) {
362 /* add it to the on-disk cache of passwords */
363 GnomeKeyringAttributeList *attributes;
364 GnomeKeyringResult result;
365 EUri *uri = e_uri_new (okey);
368 if (!strcmp (uri->protocol, "ldap") && !uri->user) {
369 /* LDAP doesnt use username in url. Let the url be the user key. So safe it */
370 char *keycopy = g_strdup (msg->key);
373 for (i = 0; i < strlen (keycopy); i ++)
374 if (keycopy[i] == '/' || keycopy[i] =='=')
379 attributes = gnome_keyring_attribute_list_new ();
380 gnome_keyring_attribute_list_append_string (attributes, "user", uri->user);
381 gnome_keyring_attribute_list_append_string (attributes, "server", uri->host);
382 gnome_keyring_attribute_list_append_string (attributes, "application", "Evolution");
384 result = gnome_keyring_item_create_sync (NULL, /* Use default keyring */
385 GNOME_KEYRING_ITEM_NETWORK_PASSWORD, /* type */
387 attributes, /* attribute list */
388 value, /* password */
389 TRUE, /* Update if already exists */
392 d(g_print("Remember %s: %d/%d\n", msg->key, result, item_id));
394 gnome_keyring_attribute_list_free (attributes);
396 /* now remove it from our session hash */
397 g_hash_table_remove (passwords, msg->key);
405 e_msgport_reply(&msg->msg);
410 ep_remember_password_file(EPassMsg *msg)
412 gpointer okey, value;
414 int len, state, save;
416 if (g_hash_table_lookup_extended (passwords, msg->key, &okey, &value)) {
417 /* add it to the on-disk cache of passwords */
418 path = password_path (msg->component, okey);
420 len = strlen (value);
421 pass64 = g_malloc0 ((len + 2) * 4 / 3 + 1);
423 base64_encode_close (value, len, FALSE, (guchar *)pass64, &state, &save);
425 gnome_config_private_set_string (path, pass64);
429 /* now remove it from our session hash */
430 g_hash_table_remove (passwords, msg->key);
434 gnome_config_private_sync_file ("/Evolution");
438 e_msgport_reply(&msg->msg);
441 #ifdef WITH_GNOME_KEYRING
443 ep_forget_password_keyring (EPassMsg *msg)
445 GnomeKeyringAttributeList *attributes;
446 GnomeKeyringResult result;
447 GList *matches = NULL, *tmp;
448 char *default_keyring = NULL;
449 gpointer okey, value;
450 EUri *uri = e_uri_new (msg->key);
452 if (!strcmp (uri->protocol, "ldap") && !uri->user) {
453 /* LDAP doesnt use username in url. Let the url be the user key. So safe it */
454 char *keycopy = g_strdup (msg->key);
457 for (i = 0; i < strlen (keycopy); i ++)
458 if (keycopy[i] == '/' || keycopy[i] =='=')
463 if (g_hash_table_lookup_extended (passwords, msg->key, &okey, &value)) {
464 g_hash_table_remove (passwords, msg->key);
465 memset (value, 0, strlen (value));
470 if (!uri->host && !uri->user)
471 /* No need to remove from keyring for pass phrases */
474 result = gnome_keyring_get_default_keyring_sync (&default_keyring);
475 if (!default_keyring) {
476 if (gnome_keyring_create_sync ("default", NULL) != GNOME_KEYRING_RESULT_OK)
478 default_keyring = g_strdup ("default");
481 d(g_print("Get Default %d\n", result));
483 attributes = gnome_keyring_attribute_list_new ();
484 gnome_keyring_attribute_list_append_string (attributes, "user", uri->user);
485 gnome_keyring_attribute_list_append_string (attributes, "server", uri->host);
486 gnome_keyring_attribute_list_append_string (attributes, "application", "Evolution");
488 result = gnome_keyring_find_items_sync (GNOME_KEYRING_ITEM_NETWORK_PASSWORD, attributes, &matches);
489 d(g_print ("Find Items %d\n", result));
491 gnome_keyring_attribute_list_free (attributes);
494 g_print ("Couldn't clear password");
496 for (tmp = matches; tmp; tmp = tmp->next) {
497 GArray *pattr = ((GnomeKeyringFound *) tmp->data)->attributes;
499 GnomeKeyringAttribute *attr;
500 gboolean accept = TRUE;
503 for (i =0; (i < pattr->len) && accept; i++)
505 attr = &g_array_index (pattr, GnomeKeyringAttribute, i);
506 if (!strcmp(attr->name, "user")) {
508 if (strcmp (attr->value.string, uri->user))
510 } else if (!strcmp(attr->name, "server")) {
512 if (strcmp (attr->value.string, uri->host))
516 if (present == 2 && accept) {
517 result = gnome_keyring_item_delete_sync (default_keyring, ((GnomeKeyringFound *) tmp->data)->item_id);
518 d(g_print("Delete Items %s %s %d\n", uri->host, uri->user, result));
524 g_free (default_keyring);
528 e_msgport_reply(&msg->msg);
535 ep_forget_password_file (EPassMsg *msg)
537 gpointer okey, value;
540 if (g_hash_table_lookup_extended (passwords, msg->key, &okey, &value)) {
541 g_hash_table_remove (passwords, msg->key);
542 memset (value, 0, strlen (value));
547 /* clear it in the on disk db */
548 path = password_path (msg->component, msg->key);
549 gnome_config_private_clean_key (path);
550 gnome_config_private_sync_file ("/Evolution");
554 e_msgport_reply(&msg->msg);
558 #ifdef WITH_GNOME_KEYRING
560 ep_get_password_keyring (EPassMsg *msg)
563 GnomeKeyringAttributeList *attributes;
564 GnomeKeyringResult result;
565 GList *matches = NULL, *tmp;
567 passwd = g_hash_table_lookup (passwords, msg->key);
569 msg->password = g_strdup(passwd);
571 EUri *uri = e_uri_new (msg->key);
573 if (!strcmp (uri->protocol, "ldap") && !uri->user) {
574 /* LDAP doesnt use username in url. Let the url be the user key. So safe it */
575 char *keycopy = g_strdup (msg->key);
578 for (i = 0; i < strlen (keycopy); i ++)
579 if (keycopy[i] == '/' || keycopy[i] =='=')
584 if (uri->host && uri->user) {
585 /* We dont store passphrases.*/
587 attributes = gnome_keyring_attribute_list_new ();
588 gnome_keyring_attribute_list_append_string (attributes, "user", uri->user);
589 gnome_keyring_attribute_list_append_string (attributes, "server", uri->host);
590 gnome_keyring_attribute_list_append_string (attributes, "application", "Evolution");
591 printf("get %s %s\n", uri->user, msg->key);
593 result = gnome_keyring_find_items_sync (GNOME_KEYRING_ITEM_NETWORK_PASSWORD, attributes, &matches);
594 d(g_print ("Find Items %d\n", result));
596 gnome_keyring_attribute_list_free (attributes);
599 g_print ("Couldn't Get password %d\n", result);
601 /* FIXME: What to do if this returns more than one? */
602 for (tmp = matches; tmp; tmp = tmp->next) {
603 GArray *pattr = ((GnomeKeyringFound *) tmp->data)->attributes;
605 GnomeKeyringAttribute *attr;
606 gboolean accept = TRUE;
609 for (i =0; (i < pattr->len) && accept; i++)
611 attr = &g_array_index (pattr, GnomeKeyringAttribute, i);
613 if (!strcmp(attr->name, "user") && attr->value.string) {
615 if (strcmp (attr->value.string, uri->user))
617 } else if (!strcmp(attr->name, "server") && attr->value.string) {
619 if (strcmp (attr->value.string, uri->host))
623 if (present == 2 && accept) {
624 msg->password = g_strdup (((GnomeKeyringFound *) tmp->data)->secret);
635 e_msgport_reply(&msg->msg);
640 ep_get_password_file (EPassMsg *msg)
643 char *encoded = NULL;
645 passwd = g_hash_table_lookup (passwords, msg->key);
647 msg->password = g_strdup(passwd);
649 /* not part of the session hash, look it up in the on disk db */
650 path = password_path (msg->component, msg->key);
651 encoded = gnome_config_private_get_string_with_default (path, NULL);
654 msg->password = decode_base64 (encoded);
660 e_msgport_reply(&msg->msg);
664 ep_add_password (EPassMsg *msg)
666 gpointer okey, value;
668 if (g_hash_table_lookup_extended (passwords, msg->key, &okey, &value)) {
669 g_hash_table_remove (passwords, msg->key);
674 g_hash_table_insert (passwords, g_strdup (msg->key), g_strdup (msg->oldpass));
677 e_msgport_reply(&msg->msg);
680 static void ep_ask_password(EPassMsg *msg);
683 pass_response(GtkDialog *dialog, int response, void *data)
685 EPassMsg *msg = data;
686 int type = msg->flags & E_PASSWORDS_REMEMBER_MASK;
687 EDList pending = E_DLIST_INITIALISER(pending);
690 if (response == GTK_RESPONSE_OK) {
691 msg->password = g_strdup(gtk_entry_get_text((GtkEntry *)msg->entry));
693 if (type != E_PASSWORDS_REMEMBER_NEVER) {
694 int noreply = msg->noreply;
696 *msg->remember = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (msg->check));
700 if (*msg->remember || type == E_PASSWORDS_REMEMBER_FOREVER) {
701 msg->oldpass = msg->password;
702 ep_add_password(msg);
704 #ifdef WITH_GNOME_KEYRING
705 if (*msg->remember && type == E_PASSWORDS_REMEMBER_FOREVER) {
706 if (gnome_keyring_is_available())
707 ep_remember_password_keyring(msg);
709 ep_remember_password_file(msg);
712 if (*msg->remember && type == E_PASSWORDS_REMEMBER_FOREVER)
713 ep_remember_password_file(msg);
716 msg->noreply = noreply;
720 gtk_widget_destroy((GtkWidget *)dialog);
721 password_dialog = NULL;
723 /* ok, here things get interesting, we suck up any pending
724 * operations on this specific password, and return the same
725 * result or ignore other operations */
728 mw = (EPassMsg *)request_list.head;
729 mn = (EPassMsg *)mw->msg.ln.next;
731 #ifdef WITH_GNOME_KEYRING
732 if ((mw->dispatch == (gnome_keyring_is_available() ? ep_forget_password_keyring : ep_forget_password_file)
734 if ((mw->dispatch == ep_forget_password_file
736 #ifdef WITH_GNOME_KEYRING
737 || mw->dispatch == (gnome_keyring_is_available() ? ep_get_password_keyring : ep_get_password_file)
739 || mw->dispatch == ep_get_password_file
741 || mw->dispatch == ep_ask_password)
742 && (strcmp(mw->component, msg->component) == 0
743 && strcmp(mw->key, msg->key) == 0)) {
744 e_dlist_remove((EDListNode *)mw);
745 mw->password = g_strdup(msg->password);
746 e_msgport_reply(&mw->msg);
749 mn = (EPassMsg *)mn->msg.ln.next;
754 e_msgport_reply(&msg->msg);
756 ep_idle_dispatch(NULL);
760 ep_ask_password(EPassMsg *msg)
763 int type = msg->flags & E_PASSWORDS_REMEMBER_MASK;
764 guint noreply = msg->noreply;
769 /*password_dialog = (GtkDialog *)e_error_new(msg->parent, "mail:ask-session-password", msg->prompt, NULL);*/
770 password_dialog = (GtkDialog *)gtk_message_dialog_new (msg->parent,
772 GTK_MESSAGE_QUESTION,
773 GTK_BUTTONS_OK_CANCEL,
775 gtk_window_set_title(GTK_WINDOW(password_dialog), msg->title);
777 gtk_widget_ensure_style (GTK_WIDGET (password_dialog));
778 gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (password_dialog)->vbox), 0);
779 gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (password_dialog)->action_area), 12);
781 gtk_dialog_set_default_response(password_dialog, GTK_RESPONSE_OK);
783 vbox = gtk_vbox_new (FALSE, 12);
784 gtk_widget_show (vbox);
785 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (password_dialog)->vbox), vbox, TRUE, FALSE, 0);
786 gtk_container_set_border_width((GtkContainer *)vbox, 12);
788 msg->entry = gtk_entry_new ();
790 a11y = gtk_widget_get_accessible (msg->entry);
791 atk_object_set_description (a11y, msg->prompt);
792 gtk_entry_set_visibility ((GtkEntry *)msg->entry, !(msg->flags & E_PASSWORDS_SECRET));
793 gtk_entry_set_activates_default((GtkEntry *)msg->entry, TRUE);
794 gtk_box_pack_start (GTK_BOX (vbox), msg->entry, TRUE, FALSE, 3);
795 gtk_widget_show (msg->entry);
796 gtk_widget_grab_focus (msg->entry);
798 if ((msg->flags & E_PASSWORDS_REPROMPT)) {
799 #ifdef WITH_GNOME_KEYRING
800 if (gnome_keyring_is_available())
801 ep_get_password_keyring(msg);
803 ep_get_password_file(msg);
805 ep_get_password_file(msg);
808 gtk_entry_set_text ((GtkEntry *) msg->entry, msg->password);
809 g_free (msg->password);
810 msg->password = NULL;
814 /* static password, shouldn't be remembered between sessions,
815 but will be remembered within the session beyond our control */
816 if (type != E_PASSWORDS_REMEMBER_NEVER) {
817 if (msg->flags & E_PASSWORDS_PASSPHRASE) {
818 msg->check = gtk_check_button_new_with_mnemonic(type == E_PASSWORDS_REMEMBER_FOREVER
819 ? _("_Remember this passphrase")
820 : _("_Remember this passphrase for the remainder of this session"));
822 msg->check = gtk_check_button_new_with_mnemonic(type == E_PASSWORDS_REMEMBER_FOREVER
823 ? _("_Remember this password")
824 : _("_Remember this password for the remainder of this session"));
827 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (msg->check), *msg->remember);
828 gtk_box_pack_start (GTK_BOX (vbox), msg->check, TRUE, FALSE, 3);
829 if ((msg->flags & E_PASSWORDS_DISABLE_REMEMBER))
830 gtk_widget_set_sensitive(msg->check, FALSE);
831 gtk_widget_show (msg->check);
834 msg->noreply = noreply;
836 g_signal_connect(password_dialog, "response", G_CALLBACK (pass_response), msg);
839 gtk_dialog_run (GTK_DIALOG (password_dialog));
841 gtk_widget_show((GtkWidget *)password_dialog);
848 * Initializes the e_passwords routines. Must be called before any other
849 * e_passwords_* function.
852 e_passwords_init (void)
857 /* create the per-session hash table */
858 passwords = g_hash_table_new (g_str_hash, g_str_equal);
859 #ifdef ENABLE_THREADS
860 main_thread = pthread_self();
868 * e_passwords_cancel:
870 * Cancel any outstanding password operations and close any dialogues
871 * currently being shown.
874 e_passwords_cancel(void)
879 while ((msg = (EPassMsg *)e_dlist_remhead(&request_list)))
880 e_msgport_reply(&msg->msg);
884 gtk_dialog_response(password_dialog,GTK_RESPONSE_CANCEL);
888 * e_passwords_shutdown:
890 * Cleanup routine to call before exiting.
893 e_passwords_shutdown (void)
895 #ifdef WITH_GNOME_KEYRING
896 /* shouldn't need this really - everything is synchronous */
897 if (!gnome_keyring_is_available())
898 gnome_config_private_sync_file ("/Evolution");
900 gnome_config_private_sync_file ("/Evolution");
902 e_passwords_cancel();
905 /* and destroy our per session hash */
906 g_hash_table_foreach_remove (passwords, free_entry, NULL);
907 g_hash_table_destroy (passwords);
913 * e_passwords_set_online:
916 * Set the offline-state of the application. This is a work-around
917 * for having the backends fully offline aware, and returns a
918 * cancellation response instead of prompting for passwords.
920 * FIXME: This is not a permanent api, review post 2.0.
923 e_passwords_set_online(int state)
925 ep_online_state = state;
926 /* TODO: we could check that a request is open and close it, or maybe who cares */
930 * e_passwords_forget_passwords:
932 * Forgets all cached passwords, in memory and on disk.
935 e_passwords_forget_passwords (void)
937 #ifdef WITH_GNOME_KEYRING
938 EPassMsg *msg = ep_msg_new(gnome_keyring_is_available() ? ep_forget_passwords_keyring : ep_forget_passwords_file);
940 EPassMsg *msg = ep_msg_new(ep_forget_passwords_file);
948 * e_passwords_clear_passwords:
950 * Forgets all disk cached passwords for the component.
953 e_passwords_clear_passwords (const char *component_name)
955 #ifdef WITH_GNOME_KEYRING
956 EPassMsg *msg = ep_msg_new(gnome_keyring_is_available() ? ep_clear_passwords_keyring : ep_clear_passwords_file);
958 EPassMsg *msg = ep_msg_new(ep_clear_passwords_file);
961 msg->component = component_name;
967 * e_passwords_remember_password:
970 * Saves the password associated with @key to disk.
973 e_passwords_remember_password (const char *component_name, const char *key)
977 g_return_if_fail(component_name != NULL);
978 g_return_if_fail(key != NULL);
980 #ifdef WITH_GNOME_KEYRING
981 msg = ep_msg_new(gnome_keyring_is_available() ? ep_remember_password_keyring : ep_remember_password_file);
983 msg = ep_msg_new(ep_remember_password_file);
985 msg->component = component_name;
993 * e_passwords_forget_password:
996 * Forgets the password associated with @key, in memory and on disk.
999 e_passwords_forget_password (const char *component_name, const char *key)
1003 g_return_if_fail(component_name != NULL);
1004 g_return_if_fail(key != NULL);
1006 #ifdef WITH_GNOME_KEYRING
1007 msg = ep_msg_new(gnome_keyring_is_available() ? ep_forget_password_keyring : ep_forget_password_file);
1009 msg = ep_msg_new(ep_forget_password_file);
1011 msg->component = component_name;
1019 * e_passwords_get_password:
1022 * Return value: the password associated with @key, or %NULL. Caller
1023 * must free the returned password.
1026 e_passwords_get_password (const char *component_name, const char *key)
1031 g_return_val_if_fail(component_name != NULL, NULL);
1032 g_return_val_if_fail(key != NULL, NULL);
1034 #ifdef WITH_GNOME_KEYRING
1035 msg = ep_msg_new(gnome_keyring_is_available() ? ep_get_password_keyring : ep_get_password_file);
1037 msg = ep_msg_new(ep_get_password_file);
1040 msg->component = component_name;
1045 passwd = msg->password;
1046 msg->password = NULL;
1053 * e_passwords_add_password:
1055 * @passwd: the password for @key
1057 * This stores the @key/@passwd pair in the current session's password
1061 e_passwords_add_password (const char *key, const char *passwd)
1065 g_return_if_fail(key != NULL);
1066 g_return_if_fail(passwd != NULL);
1068 msg = ep_msg_new(ep_add_password);
1070 msg->oldpass = passwd;
1077 * e_passwords_ask_password:
1078 * @title: title for the password dialog
1079 * @component_name: the name of the component for which we're storing
1080 * the password (e.g. Mail, Addressbook, etc.)
1081 * @key: key to store the password under
1082 * @prompt: prompt string
1083 * @type: whether or not to offer to remember the password,
1085 * @remember: on input, the default state of the remember checkbox.
1086 * on output, the state of the checkbox when the dialog was closed.
1087 * @parent: parent window of the dialog, or %NULL
1089 * Asks the user for a password.
1091 * Return value: the password, which the caller must free, or %NULL if
1092 * the user cancelled the operation. *@remember will be set if the
1093 * return value is non-%NULL and @remember_type is not
1094 * E_PASSWORDS_DO_NOT_REMEMBER.
1097 e_passwords_ask_password (const char *title, const char *component_name,
1100 EPasswordsRememberType type,
1105 EPassMsg *msg = ep_msg_new(ep_ask_password);
1107 if ((type & E_PASSWORDS_ONLINE) && !ep_online_state)
1111 msg->component = component_name;
1113 msg->prompt = prompt;
1115 msg->remember = remember;
1116 msg->parent = parent;
1119 passwd = msg->password;
1120 msg->password = NULL;
1128 static char *base64_alphabet =
1129 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1131 static unsigned char camel_mime_base64_rank[256] = {
1132 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
1133 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
1134 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
1135 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255,
1136 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
1137 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
1138 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1139 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255,
1140 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
1141 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
1142 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
1143 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
1144 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
1145 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
1146 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
1147 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
1150 /* call this when finished encoding everything, to
1151 flush off the last little bit */
1153 base64_encode_close(unsigned char *in, int inlen, gboolean break_lines, unsigned char *out, int *state, int *save)
1156 unsigned char *outptr = out;
1159 outptr += base64_encode_step(in, inlen, break_lines, outptr, state, save);
1161 c1 = ((unsigned char *)save)[1];
1162 c2 = ((unsigned char *)save)[2];
1164 switch (((char *)save)[0]) {
1166 outptr[2] = base64_alphabet[ ( (c2 &0x0f) << 2 ) ];
1167 g_assert(outptr[2] != 0);
1172 outptr[0] = base64_alphabet[ c1 >> 2 ];
1173 outptr[1] = base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 )];
1188 performs an 'encode step', only encodes blocks of 3 characters to the
1189 output at a time, saves left-over state in state and save (initialise to
1190 0 on first invocation).
1193 base64_encode_step(unsigned char *in, int len, gboolean break_lines, unsigned char *out, int *state, int *save)
1195 register unsigned char *inptr, *outptr;
1203 if (len + ((char *)save)[0] > 2) {
1204 unsigned char *inend = in+len-2;
1205 register int c1, c2, c3;
1206 register int already;
1210 switch (((char *)save)[0]) {
1211 case 1: c1 = ((unsigned char *)save)[1]; goto skip1;
1212 case 2: c1 = ((unsigned char *)save)[1];
1213 c2 = ((unsigned char *)save)[2]; goto skip2;
1216 /* yes, we jump into the loop, no i'm not going to change it, it's beautiful! */
1217 while (inptr < inend) {
1223 *outptr++ = base64_alphabet[ c1 >> 2 ];
1224 *outptr++ = base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 ) ];
1225 *outptr++ = base64_alphabet[ ( (c2 &0x0f) << 2 ) | (c3 >> 6) ];
1226 *outptr++ = base64_alphabet[ c3 & 0x3f ];
1227 /* this is a bit ugly ... */
1228 if (break_lines && (++already)>=19) {
1234 ((char *)save)[0] = 0;
1235 len = 2-(inptr-inend);
1240 register char *saveout;
1242 /* points to the slot for the next char to save */
1243 saveout = & (((char *)save)[1]) + ((char *)save)[0];
1245 /* len can only be 0 1 or 2 */
1247 case 2: *saveout++ = *inptr++;
1248 case 1: *saveout++ = *inptr++;
1250 ((char *)save)[0]+=len;
1258 * base64_decode_step: decode a chunk of base64 encoded data
1260 * @len: max length of data to decode
1261 * @out: output stream
1262 * @state: holds the number of bits that are stored in @save
1263 * @save: leftover bits that have not yet been decoded
1265 * Decodes a chunk of base64 encoded data
1268 base64_decode_step(unsigned char *in, int len, unsigned char *out, int *state, unsigned int *save)
1270 register unsigned char *inptr, *outptr;
1271 unsigned char *inend, c;
1272 register unsigned int v;
1278 /* convert 4 base64 bytes to 3 normal bytes */
1282 while (inptr<inend) {
1283 c = camel_mime_base64_rank[*inptr++];
1299 /* quick scan back for '=' on the end somewhere */
1300 /* fortunately we can drop 1 output char for each trailing = (upto 2) */
1302 while (inptr>in && i) {
1304 if (camel_mime_base64_rank[*inptr] != 0xff) {
1311 /* if i!= 0 then there is a truncation error! */
1316 decode_base64 (char *base64)
1320 int len, out, state;
1323 len = strlen (base64);
1324 plain = g_malloc0 (len);
1326 out = base64_decode_step ((guchar *)base64, len, plain, &state, &save);
1328 base64_decode_step ((guchar *)pad, 4 - len % 4, plain + out,
1332 return (char *)plain;