aboutsummaryrefslogtreecommitdiffstats
path: root/mail/session.c
blob: 086a7c12fc9642057c541ee284cd60243adf7d80 (plain) (blame)
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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/*
 * session.c: handles the session information and resource manipulation
 *
 * Author:
 *   Miguel de Icaza (miguel@gnu.org)
 *
 * (C) 2000 Helix Code, Inc. http://www.helixcode.com
 */
#include <config.h>
#include <gnome.h>
#include "mail.h"
#include "mail-threads.h"

CamelSession *session;
GHashTable *passwords;

/* FIXME: Will this ever be called in a non-async
 * manner? Better hope not, cause if that happens
 * we deadlock....
 */

#define ASYNC_AUTH_CALLBACK

#ifndef ASYNC_AUTH_CALLBACK
static void
request_callback (gchar *string, gpointer data)
{
    char **ans = data;

    if (string)
        *ans = g_strdup(string);
    else
        *ans = NULL;
}
#endif

char *
mail_request_dialog (const char *prompt, gboolean secret, const char *key)
{
#ifndef ASYNC_AUTH_CALLBACK
    GtkWidget *dialog;
#endif

    char *ans;

    if (!passwords)
        passwords = g_hash_table_new (g_str_hash, g_str_equal);

    ans = g_hash_table_lookup (passwords, key);
    if (ans)
        return g_strdup (ans);

#ifndef ASYNC_AUTH_CALLBACK
    /* XXX parent window? */
    dialog = gnome_request_dialog (secret, prompt, NULL, 0,
                       request_callback, &ans, NULL);
    if (!dialog)
        return NULL;
    if (gnome_dialog_run_and_close (GNOME_DIALOG (dialog)) == -1 ||
        ans == NULL)
        return NULL;
#else
    if (!mail_op_get_password ((char *) prompt, secret, &ans))
        return NULL;
#endif

    g_hash_table_insert (passwords, g_strdup (key), g_strdup (ans));
    return ans;
}

static char *
auth_callback (CamelAuthCallbackMode mode, char *data, gboolean secret,
           CamelService *service, char *item, CamelException *ex)
{
    char *key, *ans;

    if (!passwords)
        passwords = g_hash_table_new (g_str_hash, g_str_equal);

    key = g_strdup_printf ("%s:%s",
                   camel_url_to_string (service->url, FALSE),
                   item);

    if (mode == CAMEL_AUTHENTICATOR_TELL) {
        if (!data) {
            g_hash_table_remove (passwords, key);
            g_free (key);
        } else {
            gpointer old_key, old_data;

            if (g_hash_table_lookup_extended (passwords, key,
                              &old_key,
                              &old_data)) {
                g_hash_table_insert (passwords, old_key, data);
                g_free (old_data);
                g_free (key);
            } else
                g_hash_table_insert (passwords, key, data);
        }

        return NULL;
    }

    ans = mail_request_dialog (data, secret, key);
    g_free (key);

    if (!ans) {
        camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
                     "User canceled operation.");
    }

    return ans;
}

/* ******************** */

typedef struct _timeout_data_s {
    CamelTimeoutCallback cb;
    gpointer camel_data;
    gboolean result;
} timeout_data_t;

static gchar *
describe_camel_timeout (gpointer in_data, gboolean gerund)
{
    /* FIXME this is so wrong */

    if (gerund)
        return g_strdup ("Keeping connection alive");
    else
        return g_strdup ("Keep connection alive");
}

static void
noop_camel_timeout (gpointer in_data, gpointer op_data, CamelException *ex)
{
}

static void
do_camel_timeout (gpointer in_data, gpointer op_data, CamelException *ex)
{
    timeout_data_t *td = (timeout_data_t *) in_data;

    td->result = (td->cb) (td->camel_data);
}

static const mail_operation_spec spec_camel_timeout =
{
    describe_camel_timeout,
    0,
    noop_camel_timeout,
    do_camel_timeout,
    noop_camel_timeout
};

static gboolean 
camel_timeout (gpointer data)
{
    timeout_data_t *td = (timeout_data_t *) data;

    if (td->result == FALSE) {
        g_free (td);
        return FALSE;
    }

    mail_operation_queue (&spec_camel_timeout, td, FALSE);
    return TRUE;
}

static guint
register_callback (guint32 interval, CamelTimeoutCallback cb, gpointer camel_data)
{
    timeout_data_t *td;

    /* We do this because otherwise the timeout can get called
     * more often than the dispatch thread can get rid of it,
     * leading to timeout calls piling up, and we don't have a
     * good way to watch the return values. It's not cool.
     */
    g_return_val_if_fail (interval > 1000, 0);

    td = g_new (timeout_data_t, 1);
    td->result = TRUE;
    td->cb = cb;
    td->camel_data = camel_data;

    return gtk_timeout_add_full (interval, camel_timeout, NULL,
                     td, g_free);
}

static gboolean
remove_callback (guint handle)
{
    gtk_timeout_remove (handle);
    return TRUE;
}

/* ******************** */

void
session_init (void)
{
    camel_init ();
    session = camel_session_new (auth_callback, register_callback, 
                     remove_callback);
}

static gboolean
free_entry (gpointer key, gpointer value, gpointer user_data)
{
    g_free (key);
    memset (value, 0, strlen (value));
    g_free (value);
    return TRUE;
}

void
forget_passwords (BonoboUIHandler *uih, void *user_data, const char *path)
{
    g_hash_table_foreach_remove (passwords, free_entry, NULL);
}