--- evolution-data-server-1.10.0/libedataserverui/e-passwords.h.e-passwords 2007-01-03 05:09:27.000000000 -0500 +++ evolution-data-server-1.10.0/libedataserverui/e-passwords.h 2007-03-14 18:05:55.000000000 -0400 @@ -28,45 +28,65 @@ G_BEGIN_DECLS -/* - initialization is now implicit when you call any of the functions - below, although this is only correct if the functions are called - from the main thread. - - e_passwords_shutdown should be called at exit time to synch the - password on-disk storage, and to free up in-memory storage. */ -void e_passwords_init (void); - -void e_passwords_shutdown (void); -void e_passwords_cancel(void); -void e_passwords_set_online(int state); -void e_passwords_remember_password (const char *component, const char *key); -void e_passwords_add_password (const char *key, const char *passwd); -char *e_passwords_get_password (const char *component, const char *key); -void e_passwords_forget_password (const char *component, const char *key); -void e_passwords_forget_passwords (void); -void e_passwords_clear_passwords (const char *component); - +/** + * EPasswordsRememberType: + * @E_PASSWORDS_REMEMBER_NEVER: + * Do not remember the password. + * @E_PASSWORDS_REMEMBER_SESSION: + * Remember the password for this session only. + * @E_PASSWORDS_REMEMBER_FOREVER: + * Remember the password across multiple sessions. + * @E_PASSWORDS_REMEMBER_MASK: + * Mask value separates the mutually-exclusive values + * of the enumeration from the flags. + * @E_PASSWORDS_SECRET: + * Do not show the password as it's being typed. + * @E_PASSWORDS_REPROMPT: + * Populate the dialog with the current password (if one exists). + * @E_PASSWORDS_ONLINE: + * Only prompt the user for a password if we're online. + * @E_PASSWORDS_DISABLE_REMEMBER: + * Disable the "remember password" option on the dialog. + * @E_PASSWORDS_PASSPHRASE: + * Ask for a passphrase instead of a password. + **/ typedef enum { E_PASSWORDS_REMEMBER_NEVER, E_PASSWORDS_REMEMBER_SESSION, E_PASSWORDS_REMEMBER_FOREVER, E_PASSWORDS_REMEMBER_MASK = 0xf, - /* option bits */ - E_PASSWORDS_SECRET = 1<<8, - E_PASSWORDS_REPROMPT = 1<<9, - E_PASSWORDS_ONLINE = 1<<10, /* only ask if we're online */ - E_PASSWORDS_DISABLE_REMEMBER = 1<<11, /* disable the 'remember password' checkbox */ - E_PASSWORDS_PASSPHRASE = 1<<12, /* We are asking a passphrase */ + /* flags */ + E_PASSWORDS_SECRET = 1 << 8, + E_PASSWORDS_REPROMPT = 1 << 9, + E_PASSWORDS_ONLINE = 1 << 10, + E_PASSWORDS_DISABLE_REMEMBER = 1 << 11, + E_PASSWORDS_PASSPHRASE = 1 << 12, } EPasswordsRememberType; -char * e_passwords_ask_password (const char *title, - const char*component_name, const char *key, - const char *prompt, - EPasswordsRememberType remember_type, - gboolean *remember, - GtkWindow *parent); +#ifndef EDS_DISABLE_DEPRECATED +void e_passwords_init (void); +void e_passwords_shutdown (void); +void e_passwords_cancel (void); +#endif +void e_passwords_set_online (gboolean online); +void e_passwords_remember_password (const gchar *component, + const gchar *key); +void e_passwords_add_password (const gchar *key, + const gchar *password); +gchar * e_passwords_get_password (const gchar *component, + const gchar *key); +void e_passwords_forget_password (const gchar *component, + const gchar *key); +void e_passwords_forget_passwords (void); +void e_passwords_clear_passwords (const gchar *component); +gchar * e_passwords_ask_password (const gchar *title, + const gchar *component, + const gchar *key, + const gchar *prompt, + EPasswordsRememberType remember_type, + gboolean *remember, + GtkWindow *parent); G_END_DECLS --- evolution-data-server-1.10.0/libedataserverui/e-passwords.c.e-passwords 2007-02-09 03:38:09.000000000 -0500 +++ evolution-data-server-1.10.0/libedataserverui/e-passwords.c 2007-03-14 20:27:01.000000000 -0400 @@ -23,18 +23,29 @@ */ /* - * This looks a lot more complicated than it is, and than you'd think - * it would need to be. There is however, method to the madness. + * The threading model was changed in version 1.11. Here's the details. * - * The code most cope with being called from any thread at any time, - * recursively from the main thread, and then serialising every - * request so that sane and correct values are always returned, and - * duplicate requests are never made. + * We now use a dedicated "dispatcher" thread to process password messages. + * The callback functions do not use synchronization guards when accessing + * the password store, so those functions must only be called from the + * dispatcher thread. * - * To this end, every call is marshalled and queued and a dispatch - * method invoked until that request is satisfied. If mainloop - * recursion occurs, then the sub-call will necessarily return out of - * order, but will not be processed out of order. + * Message processing behind a visible password dialog is the trickiest + * part to get right. We want to, at all costs, avoid repeatedly prompting + * the user for the same password. To that end, when the password dialog + * for some key 'X' is visible, the dispatcher thread is blocked and + * subsequent messages for key 'X' are expedited by redirecting them to a + * special "express queue" [1]. + * + * Once the password dialog is closed, all messages in the express queue + * are either (depending on the user's response) cancelled or loaded with + * the new password and returned to the sender. The express queue is then + * closed so that no new messages can enter, and the dispatcher thread + * resumes its normal processing. + * + * [1] Yes, it's a stupid name, but it's the best I could think of. It's + * somewhat analogous to an express lane on a freeway because messages + * get through faster. */ #ifdef HAVE_CONFIG_H @@ -42,159 +53,384 @@ #endif #include -#include +#include #include -#include -#include -#include -#include -#include #include "e-passwords.h" -#include "libedataserver/e-msgport.h" +#include "libedataserver/e-flag.h" #include "libedataserver/e-url.h" #if WITH_GNOME_KEYRING #include #endif -#ifndef ENABLE_THREADS -#define ENABLE_THREADS (1) -#endif - -#ifdef ENABLE_THREADS -#include - -static pthread_t main_thread; -static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; -#define LOCK() pthread_mutex_lock(&lock) -#define UNLOCK() pthread_mutex_unlock(&lock) -#else -#define LOCK() -#define UNLOCK() -#endif +#define d(x) -#define d(x) x +typedef struct _EPassMsg EPassMsg; +typedef struct _EPassDialogData EPassDialogData; +typedef void (*EPassCallback) (EPassMsg *msg); struct _EPassMsg { - EMsg msg; - void (*dispatch)(struct _EPassMsg *); + /* The 'expedite' flag indicates that the message + * is eligible for entry into the express queue. */ - /* input */ - struct _GtkWindow *parent; - const char *component; - const char *key; - const char *title; - const char *prompt; - const char *oldpass; - guint32 flags; + /* dispatching */ + EPassCallback callback; + gboolean expedite; + EFlag *done; + + /* input/output */ + const gchar *component; + const gchar *key; + gchar *password; + gpointer data; +}; - /* output */ - gboolean *remember; - char *password; +struct _EPassDialogData { - /* work variables */ - GtkWidget *entry; - GtkWidget *check; - guint ismain:1; - guint noreply:1; /* supress replies; when calling - * dispatch functions from others */ + /* settings */ + GtkWindow *parent; + const gchar *title; + const gchar *prompt; + gint flags; + + /* input/output */ + gboolean remember; + gint response; + + /* synchronization */ + EFlag *done; }; -typedef struct _EPassMsg EPassMsg; +/* Forward Declarations */ +static void ep_msg_dispatch (EPassMsg *msg); -static GHashTable *passwords = NULL; -static GtkDialog *password_dialog; -static EDList request_list = E_DLIST_INITIALISER(request_list); -static int idle_id; -static int ep_online_state = TRUE; - -static char *decode_base64 (char *base64); -static int base64_encode_close(unsigned char *in, int inlen, gboolean break_lines, unsigned char *out, int *state, int *save); -static int base64_encode_step(unsigned char *in, int len, gboolean break_lines, unsigned char *out, int *state, int *save); +static GThreadPool *dispatcher = NULL; +static GHashTable *password_cache = NULL; +static gboolean ep_online_state = TRUE; -static gboolean -ep_idle_dispatch(void *data) +/* The queue's lock also guards the key. */ +static const gchar *express_key = NULL; +static GAsyncQueue *express_queue = NULL; + +#define KEY_FILE_GROUP_PREFIX "Passwords-" +static GKeyFile *key_file = NULL; + +static gchar * +ep_key_file_get_filename (void) { - EPassMsg *msg; + /* XXX It would be nice to someday move this data elsewhere, or else + * fully migrate to GNOME Keyring or whatever software supercedes it. + * Evolution is one of the few remaining GNOME-2 applications that + * still uses the deprecated ~/.gnome2-private directory. */ + + return g_build_filename (g_get_home_dir (), + ".gnome2_private", "Evolution", NULL); +} - /* As soon as a password window is up we stop; it will - re-invoke us when it has been closed down */ - LOCK(); - while (password_dialog == NULL && (msg = (EPassMsg *)e_dlist_remhead(&request_list))) { - UNLOCK(); +static gchar * +ep_key_file_get_group (const gchar *component) +{ + return g_strconcat (KEY_FILE_GROUP_PREFIX, component, NULL); +} + +static gchar * +ep_key_file_normalize_key (const gchar *key) +{ + /* XXX Previous code converted all slashes and equal signs in the + * key to underscores for use with "gnome-config" functions. While + * it may not be necessary to convert slashes for use with GKeyFile, + * and an equal sign was most likely never encountered in a key, we + * continue to do the same for backward-compatibility. */ + + gchar *normalized_key, *cp; - msg->dispatch(msg); + normalized_key = g_strdup (key); + for (cp = normalized_key; *cp != '\0'; cp++) + if (*cp == '/' || *cp == '=') + *cp = '_'; + + return normalized_key; +} + +static void +ep_key_file_load (void) +{ + gchar *filename; + GError *error = NULL; - LOCK(); + filename = ep_key_file_get_filename (); + + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) + goto exit; + + g_key_file_load_from_file (key_file, filename, + G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, + &error); + + if (error != NULL) { + g_warning ("%s", error->message); + g_error_free (error); } - idle_id = 0; - UNLOCK(); +exit: + g_free (filename); +} - return FALSE; +static void +ep_key_file_save (void) +{ + gchar *contents; + gchar *filename; + gsize length; + GError *error = NULL; + + filename = ep_key_file_get_filename (); + contents = g_key_file_to_data (key_file, &length, NULL); + + g_file_set_contents (filename, contents, length, &error); + + if (error != NULL) { + g_warning ("%s", error->message); + g_error_free (error); + } + + g_free (contents); + g_free (filename); } -static EPassMsg * -ep_msg_new(void (*dispatch)(EPassMsg *)) +static gchar * +ep_password_encode (const gchar *password) { - EPassMsg *msg; + /* XXX The previous Base64 encoding function did not encode the + * password's trailing nul byte. This makes decoding the Base64 + * string into a nul-terminated password more difficult, but we + * continue to do it this way for backward-compatibility. */ + + gsize length = strlen (password); + return g_base64_encode ((const guchar *) password, length); +} + +static gchar * +ep_password_decode (const gchar *encoded_password) +{ + /* XXX The previous Base64 encoding function did not encode the + * password's trailing nul byte, so we have to append a nul byte + * to the decoded data to make it a nul-terminated string. */ + + gchar *password; + gsize length; - e_passwords_init(); + password = (gchar *) g_base64_decode (encoded_password, &length); + password = g_realloc (password, length + 1); + password[length] = '\0'; - msg = g_malloc0(sizeof(*msg)); - msg->dispatch = dispatch; - msg->msg.reply_port = e_msgport_new(); -#ifdef ENABLE_THREADS - msg->ismain = pthread_equal(pthread_self(), main_thread); + return password; +} + +static gpointer +ep_init (gpointer data) +{ + /* Initialize the data structures with unbounded lifetimes. */ + + dispatcher = g_thread_pool_new ( + (GFunc) ep_msg_dispatch, NULL, 1, FALSE, NULL); + + password_cache = g_hash_table_new_full ( + g_str_hash, g_str_equal, g_free, g_free); + + express_queue = g_async_queue_new (); + +#ifdef WITH_GNOME_KEYRING + if (!gnome_keyring_is_available ()) { + key_file = g_key_file_new (); + ep_key_file_load (); + } #else - msg->ismain = TRUE; + key_file = g_key_file_new (); + ep_key_file_load (); #endif + + return NULL; +} + +static EPassMsg * +ep_msg_new (EPassCallback callback, gboolean expedite) +{ + static GOnce once = G_ONCE_INIT; + EPassMsg *msg; + + g_once (&once, ep_init, NULL); + + msg = g_slice_new0 (EPassMsg); + msg->callback = callback; + msg->expedite = expedite; + msg->done = e_flag_new (); + return msg; } static void -ep_msg_free(EPassMsg *msg) +ep_msg_dispatch (EPassMsg *msg) { - e_msgport_destroy(msg->msg.reply_port); - g_free(msg->password); - g_free(msg); + msg->callback (msg); + e_flag_set (msg->done); +} + +static gboolean +ep_msg_expedite (EPassMsg *msg) +{ + gboolean success = FALSE; + + g_async_queue_lock (express_queue); + if (express_key != NULL && strcmp (msg->key, express_key) == 0) { + g_async_queue_push_unlocked (express_queue, msg); + success = TRUE; + } + g_async_queue_unlock (express_queue); + + return success; } static void -ep_msg_send(EPassMsg *msg) +ep_msg_send (EPassMsg *msg) { - int needidle = 0; + GMainContext *context; + + context = g_main_context_default (); + + /* Expedite flag requires a key. */ + g_assert (!msg->expedite || msg->key != NULL); + + if (!(msg->expedite && ep_msg_expedite (msg))) + g_thread_pool_push (dispatcher, msg, NULL); - LOCK(); - e_dlist_addtail(&request_list, (EDListNode *)&msg->msg); - if (!idle_id) { - if (!msg->ismain) - idle_id = g_idle_add(ep_idle_dispatch, NULL); + g_debug ("%s: in main thread? %d", G_STRFUNC, + g_main_context_is_owner (context)); + + /* Don't block the main loop. */ + if (g_main_context_is_owner (context)) + while (!e_flag_is_set (msg->done)) + g_main_context_iteration (context, TRUE); + else + e_flag_wait (msg->done); +} + +static void +ep_msg_free (EPassMsg *msg) +{ + e_flag_free (msg->done); + g_slice_free (EPassMsg, msg); +} + +static EPassDialogData * +ep_dialog_data_new (GtkWindow *parent, const gchar *title, + const gchar *prompt, gboolean remember, gint flags) +{ + EPassDialogData *data; + + data = g_slice_new0 (EPassDialogData); + data->done = e_flag_new (); + + data->parent = parent; + data->title = title; + data->prompt = prompt; + data->remember = remember; + data->flags = flags; + + return data; +} + +static void +ep_dialog_data_free (EPassDialogData *data) +{ + e_flag_free (data->done); + g_slice_free (EPassDialogData, data); +} + +static gboolean +ep_dialog_run (EPassMsg *msg) +{ + /* This function must run in the main thread. */ + + EPassDialogData *data = msg->data; + GtkBox *box; + GtkWidget *dialog; + GtkWidget *entry; + GtkWidget *check_button = NULL; + gboolean visible; + gint remember; + + visible = !(data->flags & E_PASSWORDS_SECRET); + remember = data->flags & E_PASSWORDS_REMEMBER_MASK; + + /* Create a standard message dialog. */ + dialog = gtk_message_dialog_new ( + data->parent, 0, GTK_MESSAGE_QUESTION, + GTK_BUTTONS_OK_CANCEL, "%s", data->prompt); + gtk_window_set_title (GTK_WINDOW (dialog), data->title); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); + + box = GTK_BOX (GTK_DIALOG (dialog)->vbox); + + /* Add a GtkEntry for the password. */ + entry = gtk_entry_new (); + gtk_box_pack_start (box, entry, TRUE, FALSE, 3); + gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); + gtk_entry_set_visibility (GTK_ENTRY (entry), visible); + if (msg->password != NULL) { + gtk_entry_set_text (GTK_ENTRY (entry), msg->password); + g_free (msg->password); + msg->password = NULL; + } + atk_object_set_description ( + gtk_widget_get_accessible (entry), data->prompt); + gtk_widget_grab_focus (entry); + gtk_widget_show (entry); + + /* Add a GtkCheckButton for the "remember" option. */ + if (remember != E_PASSWORDS_REMEMBER_NEVER) { + if (data->flags & E_PASSWORDS_PASSPHRASE) + check_button = gtk_check_button_new_with_mnemonic ( + (remember == E_PASSWORDS_REMEMBER_FOREVER) ? + _("_Remember this passphrase") : + _("_Remember this passphrase for the " + "remainder of this session")); else - needidle = 1; - } - UNLOCK(); + check_button = gtk_check_button_new_with_mnemonic ( + (remember == E_PASSWORDS_REMEMBER_FOREVER) ? + _("_Remember this password") : + _("_Remember this password for the " + "remainder of this session")); + gtk_box_pack_start (box, check_button, TRUE, FALSE, 3); + gtk_toggle_button_set_active ( + GTK_TOGGLE_BUTTON (check_button), data->remember); + if (data->flags & E_PASSWORDS_DISABLE_REMEMBER) + gtk_widget_set_sensitive (check_button, FALSE); + gtk_widget_show (check_button); + } + + /* Run the dialog and collect the results. */ + data->response = gtk_dialog_run (GTK_DIALOG (dialog)); + msg->password = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry))); + if (check_button != NULL) + data->remember = gtk_toggle_button_get_active ( + GTK_TOGGLE_BUTTON (check_button)); + else + data->remember = FALSE; - if (msg->ismain) { - EPassMsg *m; + gtk_widget_destroy (dialog); + e_flag_set (data->done); - if (needidle) - ep_idle_dispatch(NULL); - while ((m = (EPassMsg *)e_msgport_get(msg->msg.reply_port)) == NULL) - g_main_context_iteration(NULL, TRUE); - g_assert(m == msg); - } else { - EMsg *reply_msg = e_msgport_wait(msg->msg.reply_port); - g_assert(reply_msg == &msg->msg); - } + return FALSE; } -/* the functions that actually do the work */ +/* The rest of these static functions must run in the dispatcher thread. */ + #if WITH_GNOME_KEYRING static void -ep_clear_passwords_keyring(EPassMsg *msg) +ep_clear_passwords_keyring (EPassMsg *msg) { GnomeKeyringAttributeList *attributes; GnomeKeyringAttribute attribute; @@ -205,11 +441,8 @@ result = gnome_keyring_get_default_keyring_sync (&default_keyring); if (!default_keyring) { - if (gnome_keyring_create_sync ("default", NULL) != GNOME_KEYRING_RESULT_OK) { - if (!msg->noreply) - e_msgport_reply(&msg->msg); - return; - } + if (gnome_keyring_create_sync ("default", NULL) != GNOME_KEYRING_RESULT_OK) + return; default_keyring = g_strdup ("default"); } @@ -239,38 +472,44 @@ } g_free (default_keyring); - if (!msg->noreply) - e_msgport_reply(&msg->msg); } #endif + static void -ep_clear_passwords_file(EPassMsg *msg) +ep_clear_passwords_keyfile (EPassMsg *msg) { - char *path; + gchar *group; + GError *error = NULL; - path = g_strdup_printf ("/Evolution/Passwords-%s", msg->component); + group = ep_key_file_get_group (msg->component); - gnome_config_private_clean_section (path); - gnome_config_private_sync_file ("/Evolution"); - - g_free (path); + g_key_file_remove_group (key_file, group, &error); + if (error == NULL) + ep_key_file_save (); + else { + g_warning ("%s", error->message); + g_error_free (error); + } - if (!msg->noreply) - e_msgport_reply(&msg->msg); + g_free (group); } -static gboolean -free_entry (gpointer key, gpointer value, gpointer user_data) +static void +ep_clear_passwords (EPassMsg *msg) { - g_free (key); - memset (value, 0, strlen (value)); - g_free (value); - return TRUE; +#if WITH_GNOME_KEYRING + if (gnome_keyring_is_available ()) + ep_clear_passwords_keyring (msg); + else + ep_clear_passwords_keyfile (msg); +#else + ep_clear_passwords_keyfile (msg); +#endif } #if WITH_GNOME_KEYRING static void -ep_forget_passwords_keyring(EPassMsg *msg) +ep_forget_passwords_keyring (EPassMsg *msg) { GnomeKeyringAttributeList *attributes; GnomeKeyringAttribute attribute; @@ -281,11 +520,8 @@ result = gnome_keyring_get_default_keyring_sync (&default_keyring); if (!default_keyring) { - if (gnome_keyring_create_sync ("default", NULL) != GNOME_KEYRING_RESULT_OK) { - if (!msg->noreply) - e_msgport_reply(&msg->msg); - return; - } + if (gnome_keyring_create_sync ("default", NULL) != GNOME_KEYRING_RESULT_OK) + return; default_keyring = g_strdup ("default"); } d(g_print("Get Default %d\n", result)); @@ -316,69 +552,54 @@ g_free (default_keyring); /* free up the session passwords */ - g_hash_table_foreach_remove (passwords, free_entry, NULL); - - if (!msg->noreply) - e_msgport_reply(&msg->msg); + g_hash_table_remove_all (password_cache); } #endif static void -ep_forget_passwords_file(EPassMsg *msg) +ep_forget_passwords_keyfile (EPassMsg *msg) { - void *it; - char *key; + gchar **groups; + gsize length, ii; - it = gnome_config_private_init_iterator_sections("/Evolution"); - while ( (it = gnome_config_iterator_next(it, &key, NULL)) ) { - if (0 == strncmp(key, "Passwords-", 10)) { - char *section = g_strdup_printf("/Evolution/%s", key); + g_hash_table_remove_all (password_cache); - gnome_config_private_clean_section (section); - g_free(section); - } - g_free(key); + groups = g_key_file_get_groups (key_file, &length); + for (ii = 0; ii < length; ii++) { + if (!g_str_has_prefix (groups[ii], KEY_FILE_GROUP_PREFIX)) + continue; + g_key_file_remove_group (key_file, groups[ii], NULL); } - - gnome_config_private_sync_file ("/Evolution"); - - /* free up the session passwords */ - g_hash_table_foreach_remove (passwords, free_entry, NULL); - - if (!msg->noreply) - e_msgport_reply(&msg->msg); + ep_key_file_save (); + g_strfreev (groups); } -static char * -password_path (const char *component_name, const char *key) +static void +ep_forget_passwords (EPassMsg *msg) { - char *keycopy, *path; - int i; - keycopy = g_strdup (key); - - for (i = 0; i < strlen (keycopy); i ++) - if (keycopy[i] == '/' || keycopy[i] =='=') - keycopy[i] = '_'; - - path = g_strdup_printf ("/Evolution/Passwords-%s/%s", component_name, keycopy); - - g_free (keycopy); - - return path; +#if WITH_GNOME_KEYRING + if (gnome_keyring_is_available ()) + ep_forget_passwords_keyring (msg); + else + ep_forget_passwords_keyfile (msg); +#else + ep_forget_passwords_keyfile (msg); +#endif } #if WITH_GNOME_KEYRING static void -ep_remember_password_keyring(EPassMsg *msg) +ep_remember_password_keyring (EPassMsg *msg) { - gpointer okey, value; + gpointer value; - if (g_hash_table_lookup_extended (passwords, msg->key, &okey, &value)) { + value = g_hash_table_lookup (password_cache, msg->key); + if (value != NULL) { /* add it to the on-disk cache of passwords */ GnomeKeyringAttributeList *attributes; GnomeKeyringAttribute attribute; GnomeKeyringResult result; - EUri *uri = e_uri_new (okey); + EUri *uri = e_uri_new (msg->key); guint32 item_id; if (!strcmp (uri->protocol, "ldap") && !uri->user) { @@ -419,48 +640,48 @@ d(g_print("Remember %s: %d/%d\n", msg->key, result, item_id)); /* now remove it from our session hash */ - g_hash_table_remove (passwords, msg->key); - g_free (okey); - g_free (value); + g_hash_table_remove (password_cache, msg->key); e_uri_free (uri); } - - if (!msg->noreply) - e_msgport_reply(&msg->msg); } #endif static void -ep_remember_password_file(EPassMsg *msg) +ep_remember_password_keyfile (EPassMsg *msg) { - gpointer okey, value; - char *path, *pass64; - int len, state, save; - - if (g_hash_table_lookup_extended (passwords, msg->key, &okey, &value)) { - /* add it to the on-disk cache of passwords */ - path = password_path (msg->component, okey); + gchar *group, *key, *password; - len = strlen (value); - pass64 = g_malloc0 ((len + 2) * 4 / 3 + 1); - state = save = 0; - base64_encode_close (value, len, FALSE, (guchar *)pass64, &state, &save); - - gnome_config_private_set_string (path, pass64); - g_free (path); - g_free (pass64); + password = g_hash_table_lookup (password_cache, msg->key); + if (password == NULL) { + g_warning ("Password for key \"%s\" not found", msg->key); + return; + } - /* now remove it from our session hash */ - g_hash_table_remove (passwords, msg->key); - g_free (okey); - g_free (value); + group = ep_key_file_get_group (msg->component); + key = ep_key_file_normalize_key (msg->key); + password = ep_password_encode (password); + + g_hash_table_remove (password_cache, msg->key); + g_key_file_set_string (key_file, group, key, password); + ep_key_file_save (); - gnome_config_private_sync_file ("/Evolution"); - } + g_free (group); + g_free (key); + g_free (password); +} - if (!msg->noreply) - e_msgport_reply(&msg->msg); +static void +ep_remember_password (EPassMsg *msg) +{ +#if WITH_GNOME_KEYRING + if (gnome_keyring_is_available ()) + ep_remember_password_keyring (msg); + else + ep_remember_password_keyfile (msg); +#else + ep_remember_password_keyfile (msg); +#endif } #if WITH_GNOME_KEYRING @@ -472,7 +693,6 @@ GnomeKeyringResult result; GList *matches = NULL, *tmp; char *default_keyring = NULL; - gpointer okey, value; EUri *uri = e_uri_new (msg->key); if (!strcmp (uri->protocol, "ldap") && !uri->user) { @@ -486,27 +706,17 @@ uri->user = keycopy; } - if (g_hash_table_lookup_extended (passwords, msg->key, &okey, &value)) { - g_hash_table_remove (passwords, msg->key); - memset (value, 0, strlen (value)); - g_free (okey); - g_free (value); - } + g_hash_table_remove (password_cache, msg->key); if (!uri->host && !uri->user) { /* No need to remove from keyring for pass phrases */ - if (!msg->noreply) - e_msgport_reply(&msg->msg); return; } result = gnome_keyring_get_default_keyring_sync (&default_keyring); if (!default_keyring) { - if (gnome_keyring_create_sync ("default", NULL) != GNOME_KEYRING_RESULT_OK) { - if (!msg->noreply) - e_msgport_reply(&msg->msg); - return; - } + if (gnome_keyring_create_sync ("default", NULL) != GNOME_KEYRING_RESULT_OK) + return; default_keyring = g_strdup ("default"); } @@ -567,35 +777,44 @@ } g_free (default_keyring); - - if (!msg->noreply) - e_msgport_reply(&msg->msg); } #endif static void -ep_forget_password_file (EPassMsg *msg) +ep_forget_password_keyfile (EPassMsg *msg) { - gpointer okey, value; - char *path; + gchar *group, *key; + GError *error = NULL; - if (g_hash_table_lookup_extended (passwords, msg->key, &okey, &value)) { - g_hash_table_remove (passwords, msg->key); - memset (value, 0, strlen (value)); - g_free (okey); - g_free (value); + g_hash_table_remove (password_cache, msg->key); + + group = ep_key_file_get_group (msg->component); + key = ep_key_file_normalize_key (msg->key); + + g_key_file_remove_key (key_file, group, key, &error); + if (error == NULL) + ep_key_file_save (); + else { + g_warning ("%s", error->message); + g_error_free (error); } - /* clear it in the on disk db */ - path = password_path (msg->component, msg->key); - gnome_config_private_clean_key (path); - gnome_config_private_sync_file ("/Evolution"); - g_free (path); - - if (!msg->noreply) - e_msgport_reply(&msg->msg); + g_free (group); + g_free (key); } +static void +ep_forget_password (EPassMsg *msg) +{ +#if WITH_GNOME_KEYRING + if (gnome_keyring_is_available ()) + ep_forget_password_keyring (msg); + else + ep_forget_password_keyfile (msg); +#else + ep_forget_password_keyfile (msg); +#endif +} #if WITH_GNOME_KEYRING static void @@ -605,11 +824,11 @@ GnomeKeyringAttributeList *attributes; GnomeKeyringAttribute attribute; GnomeKeyringResult result; - GList *matches = NULL, *tmp; + GList *matches = NULL, *tmp; - passwd = g_hash_table_lookup (passwords, msg->key); + passwd = g_hash_table_lookup (password_cache, msg->key); if (passwd) { - msg->password = g_strdup(passwd); + msg->password = g_strdup (passwd); } else { EUri *uri = e_uri_new (msg->key); @@ -683,287 +902,154 @@ } } - - if (!msg->noreply) - e_msgport_reply(&msg->msg); } #endif static void -ep_get_password_file (EPassMsg *msg) +ep_get_password_keyfile (EPassMsg *msg) { - char *path, *passwd; - char *encoded = NULL; + gchar *group, *key, *password; + GError *error = NULL; - passwd = g_hash_table_lookup (passwords, msg->key); - if (passwd) { - msg->password = g_strdup(passwd); - } else { - /* not part of the session hash, look it up in the on disk db */ - path = password_path (msg->component, msg->key); - encoded = gnome_config_private_get_string_with_default (path, NULL); - g_free (path); - if (encoded) { - msg->password = decode_base64 (encoded); - g_free (encoded); - } + password = g_hash_table_lookup (password_cache, msg->key); + if (password != NULL) { + msg->password = g_strdup (password); + return; } - if (!msg->noreply) - e_msgport_reply(&msg->msg); -} + group = ep_key_file_get_group (msg->component); + key = ep_key_file_normalize_key (msg->key); -static void -ep_add_password (EPassMsg *msg) -{ - gpointer okey, value; - - if (g_hash_table_lookup_extended (passwords, msg->key, &okey, &value)) { - g_hash_table_remove (passwords, msg->key); - g_free (okey); - g_free (value); + password = g_key_file_get_string (key_file, group, key, &error); + if (password != NULL) { + msg->password = ep_password_decode (password); + g_free (password); + } else { + g_warning ("%s", error->message); + g_error_free (error); } - g_hash_table_insert (passwords, g_strdup (msg->key), g_strdup (msg->oldpass)); - - if (!msg->noreply) - e_msgport_reply(&msg->msg); + g_free (group); + g_free (key); } -static void ep_ask_password(EPassMsg *msg); - static void -pass_response(GtkDialog *dialog, int response, void *data) +ep_get_password (EPassMsg *msg) { - EPassMsg *msg = data; - int type = msg->flags & E_PASSWORDS_REMEMBER_MASK; - EDList pending = E_DLIST_INITIALISER(pending); - EPassMsg *mw, *mn; - - if (response == GTK_RESPONSE_OK) { - msg->password = g_strdup(gtk_entry_get_text((GtkEntry *)msg->entry)); - - if (type != E_PASSWORDS_REMEMBER_NEVER) { - int noreply = msg->noreply; - - *msg->remember = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (msg->check)); - - msg->noreply = 1; - - if (*msg->remember || type == E_PASSWORDS_REMEMBER_FOREVER) { - msg->oldpass = msg->password; - ep_add_password(msg); - } #if WITH_GNOME_KEYRING - if (*msg->remember && type == E_PASSWORDS_REMEMBER_FOREVER) { - if (gnome_keyring_is_available()) - ep_remember_password_keyring(msg); - else - ep_remember_password_file(msg); - } + if (gnome_keyring_is_available ()) + ep_get_password_keyring (msg); + else + ep_get_password_keyfile (msg); #else - if (*msg->remember && type == E_PASSWORDS_REMEMBER_FOREVER) - ep_remember_password_file(msg); -#endif - - msg->noreply = noreply; - } - } - - gtk_widget_destroy((GtkWidget *)dialog); - password_dialog = NULL; - - /* ok, here things get interesting, we suck up any pending - * operations on this specific password, and return the same - * result or ignore other operations */ - - LOCK(); - mw = (EPassMsg *)request_list.head; - mn = (EPassMsg *)mw->msg.ln.next; - while (mn) { -#if WITH_GNOME_KEYRING - if ((mw->dispatch == (gnome_keyring_is_available() ? ep_forget_password_keyring : ep_forget_password_file) -#else - if ((mw->dispatch == ep_forget_password_file + ep_get_password_keyfile (msg); #endif -#if WITH_GNOME_KEYRING - || mw->dispatch == (gnome_keyring_is_available() ? ep_get_password_keyring : ep_get_password_file) -#else - || mw->dispatch == ep_get_password_file -#endif - || mw->dispatch == ep_ask_password) - && (strcmp(mw->component, msg->component) == 0 - && strcmp(mw->key, msg->key) == 0)) { - e_dlist_remove((EDListNode *)mw); - mw->password = g_strdup(msg->password); - e_msgport_reply(&mw->msg); - } - mw = mn; - mn = (EPassMsg *)mn->msg.ln.next; - } - UNLOCK(); +} - if (!msg->noreply) - e_msgport_reply(&msg->msg); +static void +ep_add_password (EPassMsg *msg) +{ + gchar *key = g_strdup (msg->key); + gchar *password = g_strdup (msg->password); - ep_idle_dispatch(NULL); + g_hash_table_insert (password_cache, key, password); } static void -ep_ask_password(EPassMsg *msg) +ep_ask_password (EPassMsg *msg) { - GtkWidget *vbox; - int type = msg->flags & E_PASSWORDS_REMEMBER_MASK; - guint noreply = msg->noreply; - AtkObject *a11y; + EPassDialogData *data = msg->data; + gchar *password; + gint remember; + + /* Open the express queue for this key. This allows us to catch + * incoming operations on this key while waiting for the user to + * provide a password. Once we have the password, immediately + * process any messages in the express queue. */ + g_async_queue_lock (express_queue); + express_key = msg->key; + g_async_queue_unlock (express_queue); + + if (data->flags & E_PASSWORDS_REPROMPT) + ep_get_password (msg); + + /* Run the password dialog in the main thread. */ + g_idle_add ((GSourceFunc) ep_dialog_run, msg); + + /* Wait for the user to respond. */ + e_flag_wait (data->done); + + /* If the user cancelled the dialog then we need to dispatch + * any messages that we trapped in the express queue. */ + if (data->response != GTK_RESPONSE_OK) { + g_async_queue_lock (express_queue); + express_key = NULL; + while ((msg = g_async_queue_try_pop_unlocked (express_queue))) + ep_msg_dispatch (msg); + g_async_queue_unlock (express_queue); + return; + } - msg->noreply = 1; + remember = data->flags & E_PASSWORDS_REMEMBER_MASK; - /*password_dialog = (GtkDialog *)e_error_new(msg->parent, "mail:ask-session-password", msg->prompt, NULL);*/ - password_dialog = (GtkDialog *)gtk_message_dialog_new (msg->parent, - 0, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_OK_CANCEL, - "%s", msg->prompt); - gtk_window_set_title(GTK_WINDOW(password_dialog), msg->title); + if (remember == E_PASSWORDS_REMEMBER_NEVER) + goto cleanup; - gtk_widget_ensure_style (GTK_WIDGET (password_dialog)); - gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (password_dialog)->vbox), 0); - gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (password_dialog)->action_area), 12); + if (data->remember || remember == E_PASSWORDS_REMEMBER_FOREVER) + ep_add_password (msg); -#if !GTK_CHECK_VERSION (2,4,0) - gtk_dialog_set_has_separator(password_dialog, FALSE); -#endif - gtk_dialog_set_default_response(password_dialog, GTK_RESPONSE_OK); + if (data->remember && remember == E_PASSWORDS_REMEMBER_FOREVER) + ep_remember_password (msg); - vbox = gtk_vbox_new (FALSE, 12); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (password_dialog)->vbox), vbox, TRUE, FALSE, 0); - gtk_container_set_border_width((GtkContainer *)vbox, 12); - - msg->entry = gtk_entry_new (); +cleanup: - a11y = gtk_widget_get_accessible (msg->entry); - atk_object_set_description (a11y, msg->prompt); - gtk_entry_set_visibility ((GtkEntry *)msg->entry, !(msg->flags & E_PASSWORDS_SECRET)); - gtk_entry_set_activates_default((GtkEntry *)msg->entry, TRUE); - gtk_box_pack_start (GTK_BOX (vbox), msg->entry, TRUE, FALSE, 3); - gtk_widget_show (msg->entry); - gtk_widget_grab_focus (msg->entry); - - if ((msg->flags & E_PASSWORDS_REPROMPT)) { -#if WITH_GNOME_KEYRING - if (gnome_keyring_is_available()) - ep_get_password_keyring(msg); - else - ep_get_password_file(msg); -#else - ep_get_password_file(msg); -#endif - if (msg->password) { - gtk_entry_set_text ((GtkEntry *) msg->entry, msg->password); - g_free (msg->password); - msg->password = NULL; - } - } + password = g_strdup (msg->password); - /* static password, shouldn't be remembered between sessions, - but will be remembered within the session beyond our control */ - if (type != E_PASSWORDS_REMEMBER_NEVER) { - if (msg->flags & E_PASSWORDS_PASSPHRASE) { - msg->check = gtk_check_button_new_with_mnemonic(type == E_PASSWORDS_REMEMBER_FOREVER - ? _("_Remember this passphrase") - : _("_Remember this passphrase for the remainder of this session")); - } else { - msg->check = gtk_check_button_new_with_mnemonic(type == E_PASSWORDS_REMEMBER_FOREVER - ? _("_Remember this password") - : _("_Remember this password for the remainder of this session")); - - } - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (msg->check), *msg->remember); - gtk_box_pack_start (GTK_BOX (vbox), msg->check, TRUE, FALSE, 3); - if ((msg->flags & E_PASSWORDS_DISABLE_REMEMBER)) - gtk_widget_set_sensitive(msg->check, FALSE); - gtk_widget_show (msg->check); + /* Close the express queue and process any messages there. */ + g_async_queue_lock (express_queue); + express_key = NULL; + while ((msg = g_async_queue_try_pop_unlocked (express_queue))) { + msg->password = g_strdup (password); + e_flag_set (msg->done); } - - msg->noreply = noreply; + g_async_queue_unlock (express_queue); - g_signal_connect(password_dialog, "response", G_CALLBACK (pass_response), msg); - gtk_widget_show((GtkWidget *)password_dialog); + g_free (password); } - /** * e_passwords_init: * - * Initializes the e_passwords routines. Must be called before any other - * e_passwords_* function. + * This function is here for backward-compatibility. It does nothing. **/ void e_passwords_init (void) { - LOCK(); - - if (!passwords) { - /* create the per-session hash table */ - passwords = g_hash_table_new (g_str_hash, g_str_equal); -#ifdef ENABLE_THREADS - main_thread = pthread_self(); -#endif - } - - UNLOCK(); } /** - * e_passwords_cancel: - * - * Cancel any outstanding password operations and close any dialogues - * currently being shown. + * e_passwords_shutdown: + * + * This function is here for backward-compatibility. It does nothing. **/ void -e_passwords_cancel(void) +e_passwords_shutdown (void) { - EPassMsg *msg; - - LOCK(); - while ((msg = (EPassMsg *)e_dlist_remhead(&request_list))) - e_msgport_reply(&msg->msg); - UNLOCK(); - - if (password_dialog) - gtk_dialog_response(password_dialog,GTK_RESPONSE_CANCEL); } /** - * e_passwords_shutdown: - * - * Cleanup routine to call before exiting. + * e_passwords_cancel: + * + * This function is here for backward-compatibility. It does nothing. **/ void -e_passwords_shutdown (void) +e_passwords_cancel(void) { -#ifdef WITH_GNOME_KEYRING - /* shouldn't need this really - everything is synchronous */ - if (!gnome_keyring_is_available()) - gnome_config_private_sync_file ("/Evolution"); -#else - gnome_config_private_sync_file ("/Evolution"); -#endif - e_passwords_cancel(); - - if (passwords) { - /* and destroy our per session hash */ - g_hash_table_foreach_remove (passwords, free_entry, NULL); - g_hash_table_destroy (passwords); - passwords = NULL; - } } /** * e_passwords_set_online: - * @state: + * @online: * * Set the offline-state of the application. This is a work-around * for having the backends fully offline aware, and returns a @@ -972,10 +1058,11 @@ * FIXME: This is not a permanent api, review post 2.0. **/ void -e_passwords_set_online(int state) +e_passwords_set_online (gboolean online) { - ep_online_state = state; - /* TODO: we could check that a request is open and close it, or maybe who cares */ + /* TODO We could check that a request is open and close it, + * or maybe who cares */ + ep_online_state = online; } /** @@ -986,150 +1073,137 @@ void e_passwords_forget_passwords (void) { -#if WITH_GNOME_KEYRING - EPassMsg *msg = ep_msg_new(gnome_keyring_is_available() ? ep_forget_passwords_keyring : ep_forget_passwords_file); -#else - EPassMsg *msg = ep_msg_new(ep_forget_passwords_file); -#endif - - ep_msg_send(msg); - ep_msg_free(msg); + EPassMsg *msg; + + msg = ep_msg_new (ep_forget_passwords, FALSE); + + ep_msg_send (msg); + ep_msg_free (msg); } /** * e_passwords_clear_passwords: + * @component: component name of the caller * * Forgets all disk cached passwords for the component. **/ void -e_passwords_clear_passwords (const char *component_name) +e_passwords_clear_passwords (const gchar *component) { -#if WITH_GNOME_KEYRING - EPassMsg *msg = ep_msg_new(gnome_keyring_is_available() ? ep_clear_passwords_keyring : ep_clear_passwords_file); -#else - EPassMsg *msg = ep_msg_new(ep_clear_passwords_file); -#endif + EPassMsg *msg; - msg->component = component_name; - ep_msg_send(msg); - ep_msg_free(msg); + g_return_if_fail (component != NULL); + + msg = ep_msg_new (ep_clear_passwords, FALSE); + msg->component = component; + + ep_msg_send (msg); + ep_msg_free (msg); } /** * e_passwords_remember_password: + * @component: component name of the caller * @key: the key * * Saves the password associated with @key to disk. **/ void -e_passwords_remember_password (const char *component_name, const char *key) +e_passwords_remember_password (const gchar *component, const gchar *key) { EPassMsg *msg; - g_return_if_fail(component_name != NULL); - g_return_if_fail(key != NULL); + g_return_if_fail (component != NULL); + g_return_if_fail (key != NULL); -#if WITH_GNOME_KEYRING - msg = ep_msg_new(gnome_keyring_is_available() ? ep_remember_password_keyring : ep_remember_password_file); -#else - msg = ep_msg_new(ep_remember_password_file); -#endif - msg->component = component_name; + msg = ep_msg_new (ep_remember_password, FALSE); + msg->component = component; msg->key = key; - ep_msg_send(msg); - ep_msg_free(msg); + ep_msg_send (msg); + ep_msg_free (msg); } /** * e_passwords_forget_password: + * @component: component name of the caller * @key: the key * * Forgets the password associated with @key, in memory and on disk. **/ void -e_passwords_forget_password (const char *component_name, const char *key) +e_passwords_forget_password (const gchar *component, const gchar *key) { EPassMsg *msg; - g_return_if_fail(component_name != NULL); - g_return_if_fail(key != NULL); + g_return_if_fail (component != NULL); + g_return_if_fail (key != NULL); -#if WITH_GNOME_KEYRING - msg = ep_msg_new(gnome_keyring_is_available() ? ep_forget_password_keyring : ep_forget_password_file); -#else - msg = ep_msg_new(ep_forget_password_file); -#endif - msg->component = component_name; + msg = ep_msg_new (ep_forget_password, TRUE); + msg->component = component; msg->key = key; - ep_msg_send(msg); - ep_msg_free(msg); + ep_msg_send (msg); + ep_msg_free (msg); } /** * e_passwords_get_password: + * @component: component name of the caller * @key: the key * * Return value: the password associated with @key, or %NULL. Caller * must free the returned password. **/ char * -e_passwords_get_password (const char *component_name, const char *key) +e_passwords_get_password (const gchar *component, const gchar *key) { EPassMsg *msg; - char *passwd; + char *password; - g_return_val_if_fail(component_name != NULL, NULL); - g_return_val_if_fail(key != NULL, NULL); + g_return_val_if_fail (component != NULL, NULL); + g_return_val_if_fail (key != NULL, NULL); -#if WITH_GNOME_KEYRING - msg = ep_msg_new(gnome_keyring_is_available() ? ep_get_password_keyring : ep_get_password_file); -#else - msg = ep_msg_new(ep_get_password_file); -#endif - - msg->component = component_name; + msg = ep_msg_new (ep_get_password, TRUE); + msg->component = component; msg->key = key; - ep_msg_send(msg); - - passwd = msg->password; - msg->password = NULL; - ep_msg_free(msg); + ep_msg_send (msg); + password = msg->password; + ep_msg_free (msg); - return passwd; + return password; } /** * e_passwords_add_password: * @key: a key - * @passwd: the password for @key + * @password: the password for @key * * This stores the @key/@passwd pair in the current session's password * hash. **/ void -e_passwords_add_password (const char *key, const char *passwd) +e_passwords_add_password (const gchar *key, const gchar *password) { EPassMsg *msg; - g_return_if_fail(key != NULL); - g_return_if_fail(passwd != NULL); + g_return_if_fail (key != NULL); + g_return_if_fail (password != NULL); - msg = ep_msg_new(ep_add_password); + msg = ep_msg_new (ep_add_password, FALSE); msg->key = key; - msg->oldpass = passwd; + msg->password = g_strdup (password); - ep_msg_send(msg); - ep_msg_free(msg); + ep_msg_send (msg); + g_free (msg->password); + ep_msg_free (msg); } /** * e_passwords_ask_password: * @title: title for the password dialog - * @component_name: the name of the component for which we're storing - * the password (e.g. Mail, Addressbook, etc.) + * @component: component name of the caller * @key: key to store the password under * @prompt: prompt string * @secret: whether or not the password text should be ***ed out @@ -1146,241 +1220,45 @@ * return value is non-%NULL and @remember_type is not * E_PASSWORDS_DO_NOT_REMEMBER. **/ -char * -e_passwords_ask_password (const char *title, const char *component_name, - const char *key, - const char *prompt, +gchar * +e_passwords_ask_password (const gchar *title, + const gchar *component, + const gchar *key, + const gchar *prompt, EPasswordsRememberType type, - gboolean *remember, + gboolean *p_remember, GtkWindow *parent) { - char *passwd; - EPassMsg *msg = ep_msg_new(ep_ask_password); + EPassMsg *msg; + EPassDialogData *data; + gboolean remember; + gchar *password; + + g_return_val_if_fail (title != NULL, NULL); + g_return_val_if_fail (component != NULL, NULL); + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (prompt != NULL, NULL); if ((type & E_PASSWORDS_ONLINE) && !ep_online_state) return NULL; - msg->title = title; - msg->component = component_name; - msg->key = key; - msg->prompt = prompt; - msg->flags = type; - msg->remember = remember; - msg->parent = parent; - - ep_msg_send(msg); - passwd = msg->password; - msg->password = NULL; - ep_msg_free(msg); - - return passwd; -} - - - -static char *base64_alphabet = -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -static unsigned char camel_mime_base64_rank[256] = { - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255, - 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, - 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, -}; - -/* call this when finished encoding everything, to - flush off the last little bit */ -static int -base64_encode_close(unsigned char *in, int inlen, gboolean break_lines, unsigned char *out, int *state, int *save) -{ - int c1, c2; - unsigned char *outptr = out; - - if (inlen>0) - outptr += base64_encode_step(in, inlen, break_lines, outptr, state, save); + remember = (p_remember != NULL) ? *p_remember : FALSE; + data = ep_dialog_data_new (parent, title, prompt, remember, type); - c1 = ((unsigned char *)save)[1]; - c2 = ((unsigned char *)save)[2]; - - switch (((char *)save)[0]) { - case 2: - outptr[2] = base64_alphabet[ ( (c2 &0x0f) << 2 ) ]; - g_assert(outptr[2] != 0); - goto skip; - case 1: - outptr[2] = '='; - skip: - outptr[0] = base64_alphabet[ c1 >> 2 ]; - outptr[1] = base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 )]; - outptr[3] = '='; - outptr += 4; - break; - } - if (break_lines) - *outptr++ = '\n'; - - *save = 0; - *state = 0; - - return outptr-out; -} - -/* - performs an 'encode step', only encodes blocks of 3 characters to the - output at a time, saves left-over state in state and save (initialise to - 0 on first invocation). -*/ -static int -base64_encode_step(unsigned char *in, int len, gboolean break_lines, unsigned char *out, int *state, int *save) -{ - register unsigned char *inptr, *outptr; - - if (len<=0) - return 0; - - inptr = in; - outptr = out; - - if (len + ((char *)save)[0] > 2) { - unsigned char *inend = in+len-2; - register int c1, c2, c3; - register int already; - - already = *state; - - switch (((char *)save)[0]) { - case 1: c1 = ((unsigned char *)save)[1]; goto skip1; - case 2: c1 = ((unsigned char *)save)[1]; - c2 = ((unsigned char *)save)[2]; goto skip2; - } - - /* yes, we jump into the loop, no i'm not going to change it, it's beautiful! */ - while (inptr < inend) { - c1 = *inptr++; - skip1: - c2 = *inptr++; - skip2: - c3 = *inptr++; - *outptr++ = base64_alphabet[ c1 >> 2 ]; - *outptr++ = base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 ) ]; - *outptr++ = base64_alphabet[ ( (c2 &0x0f) << 2 ) | (c3 >> 6) ]; - *outptr++ = base64_alphabet[ c3 & 0x3f ]; - /* this is a bit ugly ... */ - if (break_lines && (++already)>=19) { - *outptr++='\n'; - already = 0; - } - } - - ((char *)save)[0] = 0; - len = 2-(inptr-inend); - *state = already; - } - - if (len>0) { - register char *saveout; - - /* points to the slot for the next char to save */ - saveout = & (((char *)save)[1]) + ((char *)save)[0]; - - /* len can only be 0 1 or 2 */ - switch(len) { - case 2: *saveout++ = *inptr++; - case 1: *saveout++ = *inptr++; - } - ((char *)save)[0]+=len; - } - - return outptr-out; -} - - -/** - * base64_decode_step: decode a chunk of base64 encoded data - * @in: input stream - * @len: max length of data to decode - * @out: output stream - * @state: holds the number of bits that are stored in @save - * @save: leftover bits that have not yet been decoded - * - * Decodes a chunk of base64 encoded data - **/ -static int -base64_decode_step(unsigned char *in, int len, unsigned char *out, int *state, unsigned int *save) -{ - register unsigned char *inptr, *outptr; - unsigned char *inend, c; - register unsigned int v; - int i; - - inend = in+len; - outptr = out; - - /* convert 4 base64 bytes to 3 normal bytes */ - v=*save; - i=*state; - inptr = in; - while (inptr>16; - *outptr++ = v>>8; - *outptr++ = v; - i=0; - } - } - } + msg = ep_msg_new (ep_ask_password, TRUE); + msg->component = component; + msg->key = key; + msg->data = data; - *save = v; - *state = i; + ep_msg_send (msg); + password = msg->password; + remember = data->remember; + ep_msg_free (msg); - /* quick scan back for '=' on the end somewhere */ - /* fortunately we can drop 1 output char for each trailing = (upto 2) */ - i=2; - while (inptr>in && i) { - inptr--; - if (camel_mime_base64_rank[*inptr] != 0xff) { - if (*inptr == '=') - outptr--; - i--; - } - } + ep_dialog_data_free (data); - /* if i!= 0 then there is a truncation error! */ - return outptr-out; -} + if (p_remember != NULL) + *p_remember = remember; -static char * -decode_base64 (char *base64) -{ - guchar *plain; - char *pad = "=="; - int len, out, state; - unsigned int save; - - len = strlen (base64); - plain = g_malloc0 (len); - state = save = 0; - out = base64_decode_step ((guchar *)base64, len, plain, &state, &save); - if (len % 4) { - base64_decode_step ((guchar *)pad, 4 - len % 4, plain + out, - &state, &save); - } - - return (char *)plain; + return password; } --- evolution-data-server-1.10.0/libedataserver/e-msgport.h.e-passwords 2007-02-26 04:52:17.000000000 -0500 +++ evolution-data-server-1.10.0/libedataserver/e-msgport.h 2007-03-14 18:05:55.000000000 -0400 @@ -54,7 +54,7 @@ /* header for any message */ typedef struct _EMsg { - EDListNode ln; + EDListNode ln; /* deprecated */ EMsgPort *reply_port; gint flags; } EMsg;