1 /*
2  *  xfce4-mailwatch-plugin - a mail notification applet for the xfce4 panel
3  *  Copyright (c) 2005-2008 Brian Tarricone <bjt23@cornell.edu>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; version 2 of the License ONLY.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU Library General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22 
23 #include <stdio.h>
24 
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28 
29 #ifdef HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif
32 
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #endif
36 
37 #ifdef HAVE_SYS_TYPES_H
38 #include <sys/types.h>
39 #endif
40 
41 #ifdef HAVE_SYS_SOCKET_H
42 #include <sys/socket.h>
43 #endif
44 
45 #if HAVE_NETINET_IN_H
46 #include <netinet/in.h>
47 #endif
48 
49 #ifdef HAVE_NETDB_H
50 #include <netdb.h>
51 #endif
52 
53 #ifdef HAVE_SYS_SELECT_H
54 #include <sys/select.h>
55 #endif
56 
57 #ifdef HAVE_SYS_WAIT_H
58 #include <sys/wait.h>
59 #endif
60 
61 #ifdef HAVE_FCNTL_H
62 #include <fcntl.h>
63 #endif
64 
65 #ifdef HAVE_ERRNO_H
66 #include <errno.h>
67 #endif
68 
69 #ifndef MSG_NOSIGNAL
70 #define MSG_NOSIGNAL 0
71 #endif
72 
73 #include <glib.h>
74 #include <gtk/gtk.h>
75 
76 #include <libxfce4util/libxfce4util.h>
77 #include <libxfce4ui/libxfce4ui.h>
78 
79 #include "mailwatch-utils.h"
80 #include "mailwatch.h"
81 #include "mailwatch-net-conn.h"
82 
83 #define BORDER         8
84 #define GMAIL_HOST     "mail.google.com"
85 #define GMAIL_ATOMURI  "/mail/feed/atom"
86 #define XFCE_MAILWATCH_GMAIL_MAILBOX(ptr)  ((XfceMailwatchGMailMailbox *)ptr)
87 
88 typedef struct
89 {
90     XfceMailwatchMailbox mailbox;
91 
92     GMutex config_mx;
93 
94     gchar *username;
95     gchar *password;
96     guint timeout;
97 
98     XfceMailwatch *mailwatch;
99 
100     /* current connection state */
101     gint running;
102     gpointer th;
103     XfceMailwatchNetConn *net_conn;
104     guint check_id;
105 } XfceMailwatchGMailMailbox;
106 
107 
108 static gboolean
gmail_should_continue(XfceMailwatchNetConn * net_conn,gpointer user_data)109 gmail_should_continue(XfceMailwatchNetConn *net_conn,
110                       gpointer user_data)
111 {
112     XfceMailwatchGMailMailbox *gmailbox = user_data;
113     return g_atomic_int_get(&gmailbox->running);
114 }
115 
116 static gssize
gmail_send(XfceMailwatchGMailMailbox * gmailbox,const gchar * buf)117 gmail_send(XfceMailwatchGMailMailbox *gmailbox, const gchar *buf)
118 {
119     GError *error = NULL;
120     gssize sent;
121 
122     sent = xfce_mailwatch_net_conn_send_data(gmailbox->net_conn,
123                                              (const guchar *)buf, -1,
124                                              &error);
125     if(sent < 0) {
126         xfce_mailwatch_log_message(gmailbox->mailwatch,
127                                    XFCE_MAILWATCH_MAILBOX(gmailbox),
128                                    XFCE_MAILWATCH_LOG_ERROR,
129                                    error->message);
130         g_error_free(error);
131     }
132 
133     return sent;
134 }
135 
136 static gssize
gmail_recv(XfceMailwatchGMailMailbox * gmailbox,gchar * buf,gsize len)137 gmail_recv(XfceMailwatchGMailMailbox *gmailbox, gchar *buf, gsize len)
138 {
139     GError *error = NULL;
140     gssize recvd;
141 
142     recvd = xfce_mailwatch_net_conn_recv_data(gmailbox->net_conn,
143                                               (guchar *)buf, len, &error);
144     if(recvd < 0) {
145         xfce_mailwatch_log_message(gmailbox->mailwatch,
146                                    XFCE_MAILWATCH_MAILBOX(gmailbox),
147                                    XFCE_MAILWATCH_LOG_ERROR,
148                                    error->message);
149         g_error_free(error);
150     }
151     buf[recvd] = 0;
152 
153     return recvd;
154 }
155 
156 static gboolean
gmail_connect(XfceMailwatchGMailMailbox * gmailbox,gint * port)157 gmail_connect(XfceMailwatchGMailMailbox *gmailbox, gint *port)
158 {
159     GError *error = NULL;
160 
161     TRACE("entering");
162 
163     g_return_val_if_fail(port, FALSE);
164 
165     gmailbox->net_conn = xfce_mailwatch_net_conn_new(GMAIL_HOST, "https");
166     xfce_mailwatch_net_conn_set_should_continue_func(gmailbox->net_conn,
167                                                      gmail_should_continue,
168                                                      gmailbox);
169 
170     if(xfce_mailwatch_net_conn_connect(gmailbox->net_conn, &error)) {
171         *port = xfce_mailwatch_net_conn_get_port(gmailbox->net_conn);
172         return TRUE;
173     } else {
174         xfce_mailwatch_log_message(gmailbox->mailwatch,
175                                    XFCE_MAILWATCH_MAILBOX(gmailbox),
176                                    XFCE_MAILWATCH_LOG_ERROR,
177                                    "%s", error->message);
178         g_error_free(error);
179         return FALSE;
180     }
181 }
182 
183 static gboolean
gmail_check_atom_feed(XfceMailwatchGMailMailbox * gmailbox,const gchar * username,const gchar * password,guint * new_messages)184 gmail_check_atom_feed(XfceMailwatchGMailMailbox *gmailbox,
185                       const gchar *username,
186                       const gchar *password,
187                       guint *new_messages)
188 {
189 #define BUFSIZE 8191
190     gboolean ret = FALSE, first_recv = TRUE;
191     GError *error = NULL;
192     gchar buf[BUFSIZE+1], *base64_creds, *p, *q;
193     gint bin, port = 0, respcode, tmp;
194 
195     if(!gmail_connect(gmailbox, &port)) {
196         DBG("failed to connect to gmail server");
197         return FALSE;
198     }
199 
200     if(!xfce_mailwatch_net_conn_make_secure(gmailbox->net_conn, &error)) {
201         xfce_mailwatch_log_message(gmailbox->mailwatch,
202                                    XFCE_MAILWATCH_MAILBOX(gmailbox),
203                                    XFCE_MAILWATCH_LOG_ERROR,
204                                    _("TLS handshake failed: %s"),
205                                    error->message);
206         g_error_free(error);
207         goto cleanup;
208     }
209 
210     g_snprintf(buf, BUFSIZE, "%s:%s", username, password);
211     base64_creds = g_base64_encode((guchar *)buf, strlen(buf));
212     if(!base64_creds) {
213         DBG("failed to base64 enc credentials");
214         goto cleanup;
215     }
216 
217     g_snprintf(buf, BUFSIZE, "GET %s HTTP/1.1\r\n" \
218                              "Host: %s:%d\r\n" \
219                              "User-Agent: %s/%s\r\n" \
220                              "Authorization: Basic %s\r\n" \
221                              "Connection: close\r\n" \
222                              "\r\n",
223                GMAIL_ATOMURI, GMAIL_HOST, port, PACKAGE, VERSION, base64_creds);
224     g_free(base64_creds);
225 
226     if(gmail_send(gmailbox, buf) != (gssize)strlen(buf)) {
227         DBG("failed to send req");
228         goto cleanup;
229     }
230 
231     for(;;) {
232         if(!xfce_mailwatch_net_conn_should_continue(gmailbox->net_conn))
233             break;
234 
235         bin = gmail_recv(gmailbox, buf, BUFSIZE);
236         if(bin <= 0) {
237             DBG("failed to recv response (%d)", bin);
238             break;
239         }
240 
241         if(first_recv) {
242             p = strstr(buf, " ");
243             DBG("got first space");
244             if(p) {
245                 q = strstr(p+1, " ");
246                 if(q) {
247                     DBG("got second space");
248                     *q = 0;
249                     respcode = atoi(p+1);
250                     DBG("response code is %d", respcode);
251                     if(respcode != 200) {
252                         if(respcode == 403 || respcode == 401) {
253                             xfce_mailwatch_log_message(gmailbox->mailwatch,
254                                                        XFCE_MAILWATCH_MAILBOX(gmailbox),
255                                                        XFCE_MAILWATCH_LOG_ERROR,
256                                                        _("Received HTTP response code %d.  The most likely reason for this is that your GMail username or password is incorrect."),
257                                                        respcode);
258                         } else {
259                             xfce_mailwatch_log_message(gmailbox->mailwatch,
260                                                        XFCE_MAILWATCH_MAILBOX(gmailbox),
261                                                        XFCE_MAILWATCH_LOG_ERROR,
262                                                        _("Received HTTP response code %d, which should be 200.  There may be a problem with GMail's servers, or they have incompatibly changed their authentication method or location of the new messages feed."),
263                                                        respcode);
264                         }
265                         break;
266                     }
267                     *q = ' ';
268                 }
269             }
270             first_recv = FALSE;
271         }
272 
273         p = strstr(buf, "<fullcount>");
274         if(!p)
275             continue;
276 
277         DBG("got opening <fullcount> tag: '%s'", p);
278 
279         q = strstr(p+1, "<");
280         if(!q) {
281             gchar buf1[1024];
282             bin = gmail_recv(gmailbox, buf1, BUFSIZE);
283             if(bin <= 0) {
284                 DBG("failed to recv response (%d)", bin);
285                 break;
286             }
287 
288             q = strstr(buf1, "<");
289             if(!q) {
290                 DBG("can't find </fullcount> closing tag");
291                 break;
292             }
293 
294             memmove(buf, p, strlen(p));
295             memcpy(buf+strlen(p), buf1, strlen(buf1));
296             buf[strlen(p)+strlen(buf1)] = 0;
297             p = buf;
298             q = strstr(p+1, "<");
299         }
300 
301         DBG("p=%p, q=%p", p, q);
302 
303         *q = 0;
304         p += 11;
305         if(p >= q) {
306             DBG("that's not right...");
307             break;
308         }
309 
310         tmp = atoi(p);
311         if(tmp < 0) {
312             DBG("new message count is <0");
313             break;
314         }
315 
316         *new_messages = tmp;
317         ret = TRUE;
318         break;
319     }
320 
321 cleanup:
322 
323     if(gmailbox->net_conn) {
324         xfce_mailwatch_net_conn_destroy(gmailbox->net_conn);
325         gmailbox->net_conn = NULL;
326     }
327 
328     return ret;
329 #undef BUFSIZE
330 }
331 
332 static void
gmail_check_mail(XfceMailwatchGMailMailbox * gmailbox)333 gmail_check_mail(XfceMailwatchGMailMailbox *gmailbox)
334 {
335 #define BUFSIZE 1024
336     gchar username[BUFSIZE], password[BUFSIZE];
337     guint new_messages = 0;
338 
339     g_mutex_lock(&(gmailbox->config_mx));
340 
341     if(!gmailbox->username || !gmailbox->password) {
342         g_mutex_unlock(&(gmailbox->config_mx));
343         return;
344     }
345 
346     g_strlcpy(username, gmailbox->username, BUFSIZE);
347     g_strlcpy(password, gmailbox->password, BUFSIZE);
348 
349     g_mutex_unlock(&(gmailbox->config_mx));
350 
351     if(gmail_check_atom_feed(gmailbox, username, password, &new_messages)) {
352         DBG("checked gmail, %u new messages", new_messages);
353         xfce_mailwatch_signal_new_messages(gmailbox->mailwatch,
354                                            XFCE_MAILWATCH_MAILBOX(gmailbox),
355                                            new_messages);
356     } else {
357         DBG("failed to connect to gmail server");
358     }
359 #undef BUFSIZE
360 }
361 
362 static gpointer
gmail_check_mail_th(gpointer data)363 gmail_check_mail_th(gpointer data)
364 {
365     XfceMailwatchGMailMailbox *gmailbox = XFCE_MAILWATCH_GMAIL_MAILBOX(data);
366 
367     while(!g_atomic_pointer_get(&gmailbox->th)
368           && g_atomic_int_get(&gmailbox->running))
369     {
370         g_thread_yield();
371     }
372 
373     if(!g_atomic_int_get(&gmailbox->running)) {
374         g_atomic_pointer_set(&gmailbox->th, NULL);
375         return NULL;
376     }
377 
378     gmail_check_mail(gmailbox);
379 
380     g_atomic_pointer_set(&gmailbox->th, NULL);
381     return NULL;
382 }
383 
384 static gboolean
gmail_check_mail_timeout(gpointer data)385 gmail_check_mail_timeout(gpointer data)
386 {
387     XfceMailwatchGMailMailbox *gmailbox = XFCE_MAILWATCH_GMAIL_MAILBOX(data);
388 
389     GThread *th;
390 
391     if(g_atomic_pointer_get(&gmailbox->th)) {
392         xfce_mailwatch_log_message(gmailbox->mailwatch,
393                                    XFCE_MAILWATCH_MAILBOX(gmailbox),
394                                    XFCE_MAILWATCH_LOG_WARNING,
395                                    _("Previous thread hasn't exited yet, not checking mail this time."));
396         return TRUE;
397     }
398 
399     th = g_thread_try_new(NULL, gmail_check_mail_th, gmailbox, NULL);
400     g_atomic_pointer_set(&gmailbox->th, th);
401 
402     return TRUE;
403 }
404 
405 static XfceMailwatchMailbox *
gmail_mailbox_new(XfceMailwatch * mailwatch,XfceMailwatchMailboxType * type)406 gmail_mailbox_new(XfceMailwatch *mailwatch, XfceMailwatchMailboxType *type)
407 {
408     XfceMailwatchGMailMailbox *gmailbox = g_new0(XfceMailwatchGMailMailbox, 1);
409     gmailbox->mailbox.type = type;
410     gmailbox->mailwatch = mailwatch;
411     gmailbox->timeout = XFCE_MAILWATCH_DEFAULT_TIMEOUT;
412     g_mutex_init(&gmailbox->config_mx);
413 
414     xfce_mailwatch_net_conn_init();
415 
416     return (XfceMailwatchMailbox *)gmailbox;
417 }
418 
419 static void
gmail_set_activated(XfceMailwatchMailbox * mailbox,gboolean activated)420 gmail_set_activated(XfceMailwatchMailbox *mailbox, gboolean activated)
421 {
422     XfceMailwatchGMailMailbox *gmailbox = XFCE_MAILWATCH_GMAIL_MAILBOX(mailbox);
423 
424     if(activated == g_atomic_int_get(&gmailbox->running))
425         return;
426 
427     if(activated) {
428         g_atomic_int_set(&gmailbox->running, TRUE);
429         gmailbox->check_id = g_timeout_add(gmailbox->timeout * 1000,
430                                            gmail_check_mail_timeout,
431                                            gmailbox);
432     } else {
433         g_atomic_int_set(&gmailbox->running, FALSE);
434         g_source_remove(gmailbox->check_id);
435         gmailbox->check_id = 0;
436     }
437 }
438 
439 static void
gmail_force_update_cb(XfceMailwatchMailbox * mailbox)440 gmail_force_update_cb(XfceMailwatchMailbox *mailbox)
441 {
442     XfceMailwatchGMailMailbox *gmailbox = XFCE_MAILWATCH_GMAIL_MAILBOX(mailbox);
443 
444     if(!g_atomic_pointer_get(&gmailbox->th)) {
445         gboolean restart = FALSE;
446 
447         if(gmailbox->check_id) {
448             g_source_remove(gmailbox->check_id);
449             restart = TRUE;
450         }
451 
452         gmail_check_mail_timeout(gmailbox);
453 
454         if(restart) {
455             gmailbox->check_id = g_timeout_add(gmailbox->timeout * 1000,
456                                                gmail_check_mail_timeout,
457                                                gmailbox);
458         }
459     }
460 }
461 
462 static gboolean
gmail_config_username_focus_out_cb(GtkWidget * w,GdkEventFocus * evt,gpointer user_data)463 gmail_config_username_focus_out_cb(GtkWidget *w,
464                                    GdkEventFocus *evt,
465                                    gpointer user_data)
466 {
467     XfceMailwatchGMailMailbox *gmailbox = XFCE_MAILWATCH_GMAIL_MAILBOX(user_data);
468 
469     g_mutex_lock(&(gmailbox->config_mx));
470 
471     g_free(gmailbox->username);
472     gmailbox->username = gtk_editable_get_chars(GTK_EDITABLE(w), 0, -1);
473 
474     g_mutex_unlock(&(gmailbox->config_mx));
475 
476     return FALSE;
477 }
478 
479 static gboolean
gmail_config_password_focus_out_cb(GtkWidget * w,GdkEventFocus * evt,gpointer user_data)480 gmail_config_password_focus_out_cb(GtkWidget *w,
481                                    GdkEventFocus *evt,
482                                    gpointer user_data)
483 {
484     XfceMailwatchGMailMailbox *gmailbox = XFCE_MAILWATCH_GMAIL_MAILBOX(user_data);
485 
486     g_mutex_lock(&(gmailbox->config_mx));
487 
488     g_free(gmailbox->password);
489     gmailbox->password = gtk_editable_get_chars(GTK_EDITABLE(w), 0, -1);
490 
491     g_mutex_unlock(&(gmailbox->config_mx));
492 
493     return FALSE;
494 }
495 
496 static gboolean
gmail_config_timeout_spinbutton_changed_cb(GtkSpinButton * sb,gpointer user_data)497 gmail_config_timeout_spinbutton_changed_cb(GtkSpinButton *sb,
498                                            gpointer user_data)
499 {
500     XfceMailwatchGMailMailbox *gmailbox = XFCE_MAILWATCH_GMAIL_MAILBOX(user_data);
501     guint value = (guint) gtk_spin_button_get_value_as_int(sb) * 60;
502 
503     if(value == gmailbox->timeout)
504         return FALSE;
505 
506     gmailbox->timeout = value;
507 
508     if(g_atomic_int_get(&gmailbox->running)) {
509         /* probably shouldn't do this so frequently */
510         if(gmailbox->check_id)
511             g_source_remove(gmailbox->check_id);
512         gmailbox->check_id = g_timeout_add(gmailbox->timeout * 1000,
513                                            gmail_check_mail_timeout,
514                                            gmailbox);
515     }
516 
517     return FALSE;
518 }
519 
520 static GtkContainer *
gmail_get_setup_page(XfceMailwatchMailbox * mailbox)521 gmail_get_setup_page(XfceMailwatchMailbox *mailbox)
522 {
523     XfceMailwatchGMailMailbox *gmailbox = XFCE_MAILWATCH_GMAIL_MAILBOX(mailbox);
524     GtkWidget *vbox, *hbox, *lbl, *entry, *sbtn;
525     GtkSizeGroup *sg;
526 
527     vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, BORDER/2);
528     gtk_widget_show(vbox);
529 
530     sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
531 
532     hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, BORDER/2);
533     gtk_widget_show(hbox);
534     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
535 
536     lbl = gtk_label_new_with_mnemonic(_("_Username:"));
537     gtk_label_set_xalign(GTK_LABEL(lbl), 0.0);
538     gtk_widget_show(lbl);
539     gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
540     gtk_size_group_add_widget(sg, lbl);
541 
542     entry = gtk_entry_new();
543     gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
544     if(gmailbox->username)
545         gtk_entry_set_text(GTK_ENTRY(entry), gmailbox->username);
546     gtk_widget_show(entry);
547     gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
548     g_signal_connect(G_OBJECT(entry), "focus-out-event",
549                      G_CALLBACK(gmail_config_username_focus_out_cb), gmailbox);
550     gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), entry);
551 
552     hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, BORDER/2);
553     gtk_widget_show(hbox);
554     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
555 
556     lbl = gtk_label_new_with_mnemonic(_("_Password:"));
557     gtk_label_set_xalign(GTK_LABEL(lbl), 0.0);
558     gtk_widget_show(lbl);
559     gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
560     gtk_size_group_add_widget(sg, lbl);
561 
562     entry = gtk_entry_new();
563     gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
564     gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
565     if(gmailbox->password)
566         gtk_entry_set_text(GTK_ENTRY(entry), gmailbox->password);
567     gtk_widget_show(entry);
568     gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
569     g_signal_connect(G_OBJECT(entry), "focus-out-event",
570                      G_CALLBACK(gmail_config_password_focus_out_cb), gmailbox);
571     gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), entry);
572 
573     hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, BORDER/2);
574     gtk_widget_show(hbox);
575     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
576 
577     lbl = gtk_label_new_with_mnemonic(_("Check for _new messages every"));
578     gtk_widget_show(lbl);
579     gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
580 
581     sbtn = gtk_spin_button_new_with_range(1.0, 1440.0, 1.0);
582     gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(sbtn), TRUE);
583     gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(sbtn), FALSE);
584     gtk_spin_button_set_value(GTK_SPIN_BUTTON(sbtn), gmailbox->timeout/60);
585     gtk_widget_show(sbtn);
586     gtk_box_pack_start(GTK_BOX(hbox), sbtn, FALSE, FALSE, 0);
587     g_signal_connect(G_OBJECT(sbtn), "value-changed",
588                      G_CALLBACK(gmail_config_timeout_spinbutton_changed_cb),
589                      gmailbox);
590     gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), sbtn);
591 
592     lbl = gtk_label_new(_("minute(s)."));
593     gtk_widget_show(lbl);
594     gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
595 
596     return GTK_CONTAINER(vbox);
597 }
598 
599 static void
gmail_restore_param_list(XfceMailwatchMailbox * mailbox,GList * params)600 gmail_restore_param_list(XfceMailwatchMailbox *mailbox, GList *params)
601 {
602     XfceMailwatchGMailMailbox *gmailbox = XFCE_MAILWATCH_GMAIL_MAILBOX(mailbox);
603     GList *l;
604 
605     g_mutex_lock(&(gmailbox->config_mx));
606 
607     for(l = params; l; l = l->next) {
608         XfceMailwatchParam *param = l->data;
609 
610         if(!strcmp(param->key, "username"))
611             gmailbox->username = g_strdup(param->value);
612         else if(!strcmp(param->key, "password"))
613             gmailbox->password = g_strdup(param->value);
614         else if(!strcmp(param->key, "timeout"))
615             gmailbox->timeout = atoi(param->value);
616     }
617 
618     g_mutex_unlock(&(gmailbox->config_mx));
619 }
620 
621 static GList *
gmail_save_param_list(XfceMailwatchMailbox * mailbox)622 gmail_save_param_list(XfceMailwatchMailbox *mailbox)
623 {
624     XfceMailwatchGMailMailbox *gmailbox = XFCE_MAILWATCH_GMAIL_MAILBOX(mailbox);
625     GList *params = NULL;
626     XfceMailwatchParam *param;
627 
628     g_mutex_lock(&(gmailbox->config_mx));
629 
630     param = g_new(XfceMailwatchParam, 1);
631     param->key = g_strdup("username");
632     param->value = g_strdup(gmailbox->username);
633     params = g_list_prepend(params, param);
634 
635     param = g_new(XfceMailwatchParam, 1);
636     param->key = g_strdup("password");
637     param->value = g_strdup(gmailbox->password);
638     params = g_list_prepend(params, param);
639 
640     param = g_new(XfceMailwatchParam, 1);
641     param->key = g_strdup("timeout");
642     param->value = g_strdup_printf("%u", gmailbox->timeout);
643     params = g_list_prepend(params, param);
644 
645     g_mutex_unlock(&(gmailbox->config_mx));
646 
647     return g_list_reverse(params);
648 }
649 
650 static void
gmail_mailbox_free(XfceMailwatchMailbox * mailbox)651 gmail_mailbox_free(XfceMailwatchMailbox *mailbox)
652 {
653     XfceMailwatchGMailMailbox *gmailbox = XFCE_MAILWATCH_GMAIL_MAILBOX(mailbox);
654 
655     gmail_set_activated(mailbox, FALSE);
656     while(g_atomic_pointer_get(&gmailbox->th))
657         g_thread_yield();
658 
659     g_mutex_clear(&gmailbox->config_mx);
660 
661     g_free(gmailbox->username);
662     g_free(gmailbox->password);
663 
664     g_free(gmailbox);
665 }
666 
667 XfceMailwatchMailboxType builtin_mailbox_type_gmail = {
668     "gmail",
669     N_("Remote GMail Mailbox"),
670     N_("The GMail plugin can connect to Google's mail service and securely retrieve the number of new messages."),
671 
672     gmail_mailbox_new,
673     gmail_set_activated,
674     gmail_force_update_cb,
675     gmail_get_setup_page,
676     gmail_restore_param_list,
677     gmail_save_param_list,
678     gmail_mailbox_free
679 };
680