1 /* $Id$ */
2 /* Copyright (c) 2006-2015 Pierre Pronchery <khorben@defora.org> */
3 /* This file is part of DeforaOS Desktop Mailer */
4 /* This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, version 3 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */
15
16
17
18 #include <dirent.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <assert.h>
24 #include <errno.h>
25 #include <libintl.h>
26 #include <openssl/err.h>
27 #include <openssl/ssl.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <Desktop.h>
30 #include "../include/Mailer/plugin.h"
31 #include "folder.h"
32 #include "message.h"
33 #include "compose.h"
34 #include "callbacks.h"
35 #include "mailer.h"
36 #include "../config.h"
37 #define _(string) gettext(string)
38 #define N_(string) (string)
39 #include "common.c"
40
41
42 /* constants */
43 #ifndef PREFIX
44 # define PREFIX "/usr/local"
45 #endif
46 #ifndef LIBDIR
47 # define LIBDIR PREFIX "/lib"
48 #endif
49 #ifndef PLUGINDIR
50 # define PLUGINDIR LIBDIR "/Mailer"
51 #endif
52
53
54 /* Mailer */
55 /* private */
56 /* types */
57 typedef enum _MailerPluginColumn
58 {
59 MPC_NAME = 0,
60 MPC_ENABLED,
61 MPC_ICON,
62 MPC_NAME_DISPLAY,
63 MPC_PLUGIN,
64 MPC_MAILERPLUGINDEFINITION,
65 MPC_MAILERPLUGIN,
66 MPC_WIDGET
67 } MailerPluginColumn;
68 #define MPC_LAST MPC_WIDGET
69 #define MPC_COUNT (MPC_LAST + 1)
70
71 struct _Mailer
72 {
73 Account ** available; /* XXX consider using another data type */
74 unsigned int available_cnt;
75
76 Account ** account;
77 unsigned int account_cnt;
78 Account * account_cur;
79 Folder * folder_cur;
80 Message * message_cur;
81
82 guint source;
83
84 /* configuration */
85 Config * config;
86
87 /* SSL */
88 SSL_CTX * ssl_ctx;
89
90 /* widgets */
91 /* folders */
92 GtkWidget * fo_window;
93 #if GTK_CHECK_VERSION(2, 18, 0)
94 GtkWidget * fo_infobar;
95 GtkWidget * fo_infobar_label;
96 #endif
97 GtkTreeStore * fo_store;
98 GtkWidget * fo_view;
99 /* headers */
100 GtkWidget * he_window;
101 GtkWidget * he_view;
102 GtkTreeViewColumn * he_view_from;
103 GtkTreeViewColumn * he_view_to;
104 /* body */
105 GtkWidget * bo_window;
106 GtkWidget * hdr_vbox;
107 GtkWidget * hdr_subject;
108 GtkWidget * hdr_from;
109 GtkWidget * hdr_to;
110 GtkWidget * hdr_date;
111 GtkTextBuffer * bo_buffer;
112 GtkWidget * bo_view;
113 GtkWidget * statusbar;
114 gint statusbar_id;
115 GtkWidget * st_online;
116 /* plug-ins */
117 GtkWidget * pl_window;
118 GtkWidget * pl_view;
119 GtkListStore * pl_store;
120 GtkWidget * pl_combo;
121 GtkWidget * pl_box;
122 MailerPluginHelper pl_helper;
123 /* about */
124 GtkWidget * ab_window;
125 /* preferences */
126 GtkWidget * pr_window;
127 GtkWidget * pr_accounts;
128 GtkWidget * pr_messages_font;
129 GtkListStore * pr_plugins_store;
130 GtkWidget * pr_plugins;
131 };
132
133 /* FIXME use a more elegant model with an AccountMessage directly */
134 typedef void (*MailerForeachMessageCallback)(Mailer * mailer,
135 GtkTreeModel * model, GtkTreeIter * iter);
136
137
138 /* constants */
139 static const char * _title[3] =
140 {
141 N_("New account"), N_("Account settings"), N_("Account confirmation")
142 };
143
144
145 /* variables */
146 #ifdef EMBEDDED
147 static const DesktopAccel _mailer_accel[] =
148 {
149 { G_CALLBACK(on_quit), GDK_CONTROL_MASK, GDK_KEY_Q },
150 { G_CALLBACK(on_view_source), GDK_CONTROL_MASK, GDK_KEY_U },
151 { NULL, 0, 0 }
152 };
153 #endif
154
155
156 #ifndef EMBEDDED
157 static const DesktopMenu _menu_file[] =
158 {
159 { N_("_New mail"), G_CALLBACK(on_file_new_mail), "stock_mail-compose",
160 GDK_CONTROL_MASK, GDK_KEY_N },
161 { N_("_Open..."), G_CALLBACK(on_file_open), GTK_STOCK_OPEN,
162 GDK_CONTROL_MASK, GDK_KEY_O },
163 { "", NULL, NULL, 0, 0 },
164 { N_("Send / Receive"), G_CALLBACK(on_file_send_receive),
165 "stock_mail-send-receive", GDK_CONTROL_MASK, GDK_KEY_R },
166 { "", NULL, NULL, 0, 0 },
167 { N_("_Print"), NULL, GTK_STOCK_PRINT, GDK_CONTROL_MASK, GDK_KEY_P },
168 { N_("Print pre_view"), NULL, GTK_STOCK_PRINT_PREVIEW, GDK_CONTROL_MASK,
169 0 },
170 { "", NULL, NULL, 0, 0 },
171 { N_("_Quit"), G_CALLBACK(on_file_quit), GTK_STOCK_QUIT,
172 GDK_CONTROL_MASK, GDK_KEY_Q },
173 { NULL, NULL, NULL, 0, 0 }
174 };
175
176 static const DesktopMenu _menu_edit[] =
177 {
178 { N_("_Cut"), G_CALLBACK(on_edit_cut), GTK_STOCK_CUT, GDK_CONTROL_MASK,
179 GDK_KEY_X },
180 { N_("Cop_y"), G_CALLBACK(on_edit_copy), GTK_STOCK_COPY,
181 GDK_CONTROL_MASK, GDK_KEY_C },
182 { N_("_Paste"), G_CALLBACK(on_edit_paste), GTK_STOCK_PASTE,
183 GDK_CONTROL_MASK, GDK_KEY_V },
184 { "", NULL, NULL, 0, 0 },
185 { N_("Select _All"), G_CALLBACK(on_edit_select_all),
186 #if GTK_CHECK_VERSION(2, 10, 0)
187 GTK_STOCK_SELECT_ALL,
188 #else
189 "edit-select-all",
190 #endif
191 GDK_CONTROL_MASK, GDK_KEY_A },
192 { N_("_Unselect all"), G_CALLBACK(on_edit_unselect_all), NULL, 0, 0 },
193 { "", NULL, NULL, 0, 0 },
194 { N_("_Preferences"), G_CALLBACK(on_edit_preferences),
195 GTK_STOCK_PREFERENCES, 0, 0 },
196 { NULL, NULL, NULL, 0, 0 }
197 };
198
199 static const DesktopMenu _menu_message[] =
200 {
201 { N_("_Reply"), G_CALLBACK(on_message_reply), "stock_mail-reply", 0,
202 0 },
203 { N_("Reply to _All"), G_CALLBACK(on_message_reply_to_all),
204 "stock_mail-reply-to-all", 0, 0 },
205 { N_("_Forward"), G_CALLBACK(on_message_forward), "stock_mail-forward",
206 0, 0 },
207 { "", NULL, NULL, 0, 0 },
208 { N_("Save _As..."), G_CALLBACK(on_message_save_as), GTK_STOCK_SAVE_AS,
209 GDK_CONTROL_MASK, GDK_KEY_S },
210 { "", NULL, NULL, 0, 0 },
211 { N_("_Delete"), G_CALLBACK(on_message_delete), GTK_STOCK_DELETE, 0,
212 GDK_KEY_Delete },
213 { "", NULL, NULL, 0, 0 },
214 { N_("_View source"), G_CALLBACK(on_message_view_source), NULL,
215 GDK_CONTROL_MASK, GDK_KEY_U },
216 { NULL, NULL, NULL, 0, 0 }
217 };
218
219 static const DesktopMenu _menu_help[] =
220 {
221 { N_("_Contents"), G_CALLBACK(on_help_contents), "help-contents", 0,
222 GDK_KEY_F1 },
223 #if GTK_CHECK_VERSION(2, 6, 0)
224 { N_("_About"), G_CALLBACK(on_help_about), GTK_STOCK_ABOUT, 0, 0 },
225 #else
226 { N_("_About"), G_CALLBACK(on_help_about), NULL, 0, 0 },
227 #endif
228 { NULL, NULL, NULL, 0, 0 }
229 };
230
231 static const DesktopMenubar _mailer_menubar[] =
232 {
233 { N_("_File"), _menu_file },
234 { N_("_Edit"), _menu_edit },
235 { N_("_Message"), _menu_message },
236 { N_("_Help"), _menu_help },
237 { NULL, NULL }
238 };
239 #endif
240
241 static DesktopToolbar _mailer_fo_toolbar[] =
242 {
243 { N_("New message"), G_CALLBACK(on_new_mail), "stock_mail-compose", 0,
244 0, NULL },
245 #ifdef EMBEDDED
246 { N_("Open message"), G_CALLBACK(on_open), GTK_STOCK_OPEN,
247 GDK_CONTROL_MASK, GDK_KEY_O, NULL },
248 #endif
249 { "", NULL, NULL, 0, 0, NULL },
250 { N_("Send / Receive"), G_CALLBACK(on_file_send_receive),
251 "stock_mail-send-receive", 0, 0, NULL },
252 { N_("Stop"), NULL, GTK_STOCK_STOP, 0, GDK_KEY_Escape, NULL },
253 { "", NULL, NULL, 0, 0, NULL },
254 #ifndef EMBEDDED
255 { N_("Reply"), G_CALLBACK(on_reply), "stock_mail-reply", 0, 0, NULL },
256 { N_("Reply to all"), G_CALLBACK(on_reply_to_all),
257 "stock_mail-reply-to-all", 0, 0, NULL },
258 { N_("Forward"), G_CALLBACK(on_forward), "stock_mail-forward", 0, 0,
259 NULL},
260 #endif
261 { N_("Delete"), G_CALLBACK(on_delete), GTK_STOCK_DELETE, 0, 0, NULL },
262 { N_("Print"), NULL, GTK_STOCK_PRINT, 0, 0, NULL },
263 #ifdef EMBEDDED
264 { "", NULL, NULL, 0, 0, NULL },
265 { N_("Preferences"), G_CALLBACK(on_preferences), GTK_STOCK_PREFERENCES,
266 0, 0, NULL },
267 #endif
268 { NULL, NULL, NULL, 0, 0, NULL }
269 };
270
271 #ifdef EMBEDDED
272 static DesktopToolbar _mailer_he_toolbar[] =
273 {
274 { N_("New mail"), G_CALLBACK(on_file_new_mail), "stock_mail-compose", 0,
275 0, NULL },
276 { "", NULL, NULL, 0, 0, NULL },
277 { N_("Reply"), G_CALLBACK(on_reply), "stock_mail-reply", 0, 0, NULL },
278 { N_("Reply to all"), G_CALLBACK(on_reply_to_all),
279 "stock_mail-reply-to-all", 0, 0, NULL },
280 { N_("Forward"), G_CALLBACK(on_forward), "stock_mail-forward", 0, 0,
281 NULL},
282 { N_("Delete"), G_CALLBACK(on_delete), GTK_STOCK_DELETE, 0, 0, NULL },
283 { NULL, NULL, NULL, 0, 0, NULL }
284 };
285
286 static DesktopToolbar _mailer_bo_toolbar[] =
287 {
288 { N_("New mail"), G_CALLBACK(on_file_new_mail), "stock_mail-compose", 0,
289 0, NULL },
290 { "", NULL, NULL, 0, 0, NULL },
291 { N_("Reply"), G_CALLBACK(on_reply), "stock_mail-reply", 0, 0, NULL },
292 { N_("Reply to all"), G_CALLBACK(on_reply_to_all),
293 "stock_mail-reply-to-all", 0, 0, NULL },
294 { N_("Forward"), G_CALLBACK(on_forward), "stock_mail-forward", 0, 0,
295 NULL},
296 { N_("Delete"), G_CALLBACK(on_delete), GTK_STOCK_DELETE, 0, 0, NULL },
297 { N_("Print"), NULL, GTK_STOCK_PRINT, 0, 0, NULL },
298 { NULL, NULL, NULL, 0, 0, NULL }
299 };
300 #endif
301
302
303 /* prototypes */
304 /* accessors */
305 static gboolean _mailer_plugin_is_enabled(Mailer * mailer, char const * plugin);
306 static char const * _mailer_get_font(Mailer * mailer);
307 static char * _mailer_get_config_filename(void);
308 static GList * _mailer_get_selected_headers(Mailer * mailer);
309
310 /* useful */
311 static int _mailer_config_load_account(Mailer * mailer, char const * name);
312 static gboolean _mailer_confirm(Mailer * mailer, char const * message);
313 static void _mailer_foreach_message_selected(Mailer * mailer,
314 MailerForeachMessageCallback callback);
315 static void _mailer_refresh_plugin(Mailer * mailer);
316 static void _mailer_refresh_title(Mailer * mailer);
317 static void _mailer_update_status(Mailer * mailer);
318 static void _mailer_update_view(Mailer * mailer);
319
320 /* callbacks */
321 static void _mailer_on_online_toggled(gpointer data);
322 static void _mailer_on_plugin_combo_changed(gpointer data);
323
324
325 /* public */
326 /* functions */
327 /* mailer_new */
328 static int _new_accounts(Mailer * mailer);
329 static GtkWidget * _new_folders_view(Mailer * mailer);
330 static void _on_folders_changed(GtkTreeSelection * selection, gpointer data);
331 static GtkWidget * _new_headers_view(Mailer * mailer);
332 static GtkWidget * _new_headers(Mailer * mailer);
333 static GtkTreeViewColumn * _headers_view_column_icon(GtkTreeView * view,
334 char const * title, int id, int sortid);
335 static GtkTreeViewColumn * _headers_view_column_text(GtkTreeView * view,
336 char const * title, int id, int sortid, int boldid);
337 static void _on_headers_changed(GtkTreeSelection * selection, gpointer data);
338 static gboolean _new_idle(gpointer data);
339 static void _idle_config_load(Mailer * mailer);
340 static void _idle_plugins_load(Mailer * mailer);
341
mailer_new(void)342 Mailer * mailer_new(void)
343 {
344 Mailer * mailer;
345 GtkAccelGroup * group;
346 GtkWidget * vbox;
347 GtkWidget * vbox2;
348 GtkWidget * hbox;
349 #ifndef EMBEDDED
350 GtkWidget * hpaned;
351 GtkWidget * hpaned2;
352 GtkWidget * vpaned;
353 #endif
354 GtkCellRenderer * renderer;
355 GtkWidget * widget;
356 char buf[128];
357
358 if((mailer = object_new(sizeof(*mailer))) == NULL)
359 {
360 error_print("mailer");
361 return NULL;
362 }
363 /* accounts */
364 _new_accounts(mailer);
365 mailer->account = NULL;
366 mailer->account_cnt = 0;
367 mailer->account_cur = NULL;
368 mailer->folder_cur = NULL;
369 mailer->message_cur = NULL;
370 /* plug-ins */
371 mailer->pl_helper.mailer = mailer;
372 mailer->pl_helper.error = mailer_error;
373 /* ssl */
374 SSL_load_error_strings();
375 SSL_library_init();
376 #ifndef OPENSSL_NO_SSL3
377 if((mailer->ssl_ctx = SSL_CTX_new(SSLv3_client_method())) == NULL
378 #else
379 if((mailer->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL
380 #endif
381 || SSL_CTX_set_cipher_list(mailer->ssl_ctx,
382 SSL_DEFAULT_CIPHER_LIST) != 1
383 || SSL_CTX_load_verify_locations(mailer->ssl_ctx, NULL,
384 "/etc/openssl/certs") != 1)
385 {
386 mailer_error(NULL, ERR_error_string(ERR_get_error(), buf), 1);
387 if(mailer->ssl_ctx != NULL)
388 SSL_CTX_free(mailer->ssl_ctx);
389 mailer->ssl_ctx = NULL;
390 }
391 #if 0 /* XXX nicer for the server (knows why we shutdown) but not for us */
392 else
393 SSL_CTX_set_verify(mailer->ssl_ctx, SSL_VERIFY_PEER, NULL);
394 #endif
395 /* widgets */
396 group = gtk_accel_group_new();
397 mailer->fo_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
398 gtk_window_add_accel_group(GTK_WINDOW(mailer->fo_window), group);
399 g_object_unref(group);
400 #ifndef EMBEDDED
401 gtk_window_set_default_size(GTK_WINDOW(mailer->fo_window), 800, 600);
402 gtk_window_set_title(GTK_WINDOW(mailer->fo_window), PACKAGE);
403 #else
404 gtk_window_set_default_size(GTK_WINDOW(mailer->fo_window), 200, 300);
405 gtk_window_set_title(GTK_WINDOW(mailer->fo_window),
406 _(PACKAGE " - Folders"));
407 #endif
408 #if GTK_CHECK_VERSION(2, 6, 0)
409 gtk_window_set_icon_name(GTK_WINDOW(mailer->fo_window), "mailer");
410 #endif
411 g_signal_connect_swapped(G_OBJECT(mailer->fo_window), "delete-event",
412 G_CALLBACK(on_closex), mailer);
413 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
414 /* menubar */
415 #ifndef EMBEDDED
416 widget = desktop_menubar_create(_mailer_menubar, mailer, group);
417 gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 0);
418 #else
419 desktop_accel_create(_mailer_accel, mailer, group);
420 #endif
421 /* toolbar */
422 widget = desktop_toolbar_create(_mailer_fo_toolbar, mailer, group);
423 gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
424 #if GTK_CHECK_VERSION(2, 18, 0)
425 /* infobar */
426 mailer->fo_infobar = gtk_info_bar_new_with_buttons(GTK_STOCK_CLOSE,
427 GTK_RESPONSE_CLOSE, NULL);
428 gtk_info_bar_set_message_type(GTK_INFO_BAR(mailer->fo_infobar),
429 GTK_MESSAGE_ERROR);
430 g_signal_connect(mailer->fo_infobar, "close", G_CALLBACK(
431 gtk_widget_hide), NULL);
432 g_signal_connect(mailer->fo_infobar, "response", G_CALLBACK(
433 gtk_widget_hide), NULL);
434 widget = gtk_info_bar_get_content_area(GTK_INFO_BAR(
435 mailer->fo_infobar));
436 mailer->fo_infobar_label = gtk_label_new(NULL);
437 gtk_widget_show(mailer->fo_infobar_label);
438 gtk_box_pack_start(GTK_BOX(widget), mailer->fo_infobar_label, TRUE,
439 TRUE, 0);
440 gtk_widget_set_no_show_all(mailer->fo_infobar, TRUE);
441 gtk_box_pack_start(GTK_BOX(vbox), mailer->fo_infobar, FALSE, TRUE, 0);
442 #endif
443 /* folders */
444 widget = gtk_scrolled_window_new(NULL, NULL);
445 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
446 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
447 mailer->fo_view = _new_folders_view(mailer);
448 gtk_container_add(GTK_CONTAINER(widget), mailer->fo_view);
449 #ifndef EMBEDDED
450 hpaned = gtk_hpaned_new();
451 gtk_paned_set_position(GTK_PANED(hpaned), 160);
452 gtk_paned_add1(GTK_PANED(hpaned), widget);
453 vpaned = gtk_vpaned_new();
454 gtk_paned_set_position(GTK_PANED(vpaned), 160);
455 gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0);
456 #else
457 gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0);
458 #endif
459 /* statusbar */
460 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
461 mailer->st_online = gtk_toggle_button_new();
462 g_signal_connect_swapped(mailer->st_online, "toggled", G_CALLBACK(
463 _mailer_on_online_toggled), mailer);
464 /* FIXME set icon and callback */
465 gtk_box_pack_start(GTK_BOX(hbox), mailer->st_online, FALSE, TRUE, 0);
466 mailer->statusbar = gtk_statusbar_new();
467 mailer->statusbar_id = 0;
468 gtk_box_pack_start(GTK_BOX(hbox), mailer->statusbar, TRUE, TRUE, 0);
469 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
470 gtk_container_add(GTK_CONTAINER(mailer->fo_window), vbox);
471 gtk_widget_show_all(vbox);
472 /* messages list */
473 #ifndef EMBEDDED
474 mailer->he_window = mailer->fo_window;
475 #else
476 group = gtk_accel_group_new();
477 mailer->he_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
478 gtk_window_add_accel_group(GTK_WINDOW(mailer->he_window), group);
479 g_object_unref(group);
480 gtk_window_set_default_size(GTK_WINDOW(mailer->he_window), 200, 300);
481 # if GTK_CHECK_VERSION(2, 6, 0)
482 gtk_window_set_icon_name(GTK_WINDOW(mailer->he_window), "mailer");
483 # endif
484 gtk_window_set_title(GTK_WINDOW(mailer->he_window), _("Message list"));
485 g_signal_connect_swapped(G_OBJECT(mailer->he_window), "delete-event",
486 G_CALLBACK(on_headers_closex), mailer);
487 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
488 gtk_container_add(GTK_CONTAINER(mailer->he_window), vbox);
489 widget = desktop_toolbar_create(_mailer_he_toolbar, mailer, group);
490 gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
491 #endif
492 widget = gtk_scrolled_window_new(NULL, NULL);
493 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
494 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
495 mailer->he_view = _new_headers_view(mailer);
496 gtk_container_add(GTK_CONTAINER(widget), mailer->he_view);
497 #ifndef EMBEDDED
498 gtk_paned_add1(GTK_PANED(vpaned), widget);
499 #else
500 gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0);
501 #endif
502 gtk_widget_show_all(vbox);
503 /* messages body */
504 #ifndef EMBEDDED
505 mailer->bo_window = mailer->fo_window;
506 #else
507 group = gtk_accel_group_new();
508 mailer->bo_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
509 gtk_window_add_accel_group(GTK_WINDOW(mailer->bo_window), group);
510 g_object_unref(group);
511 gtk_window_set_default_size(GTK_WINDOW(mailer->bo_window), 200, 300);
512 # if GTK_CHECK_VERSION(2, 6, 0)
513 gtk_window_set_icon_name(GTK_WINDOW(mailer->bo_window), "mailer");
514 # endif
515 gtk_window_set_title(GTK_WINDOW(mailer->bo_window), _("Message"));
516 g_signal_connect_swapped(G_OBJECT(mailer->bo_window), "delete-event",
517 G_CALLBACK(on_body_closex), mailer);
518 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
519 gtk_container_add(GTK_CONTAINER(mailer->bo_window), vbox);
520 widget = desktop_toolbar_create(_mailer_bo_toolbar, mailer, group);
521 gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
522 #endif
523 vbox2 = _new_headers(mailer);
524 mailer->bo_buffer = gtk_text_buffer_new(NULL);
525 mailer->bo_view = gtk_text_view_new_with_buffer(mailer->bo_buffer);
526 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(mailer->bo_view), FALSE);
527 gtk_text_view_set_editable(GTK_TEXT_VIEW(mailer->bo_view), FALSE);
528 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(mailer->bo_view),
529 GTK_WRAP_WORD_CHAR);
530 widget = gtk_scrolled_window_new(NULL, NULL);
531 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
532 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
533 gtk_container_add(GTK_CONTAINER(widget), mailer->bo_view);
534 gtk_box_pack_start(GTK_BOX(vbox2), widget, TRUE, TRUE, 0);
535 #ifndef EMBEDDED
536 gtk_paned_add2(GTK_PANED(vpaned), vbox2);
537 #else
538 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
539 #endif
540 /* plug-ins */
541 #ifndef EMBEDDED
542 mailer->pl_window = mailer->fo_window;
543 mailer->pl_view = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
544 #else
545 group = gtk_accel_group_new();
546 mailer->pl_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
547 gtk_window_add_accel_group(GTK_WINDOW(mailer->pl_window), group);
548 g_object_unref(group);
549 gtk_window_set_default_size(GTK_WINDOW(mailer->pl_window), 200, 300);
550 # if GTK_CHECK_VERSION(2, 6, 0)
551 gtk_window_set_icon_name(GTK_WINDOW(mailer->pl_window), "mailer");
552 # endif
553 gtk_window_set_title(GTK_WINDOW(mailer->pl_window), _("Plug-ins"));
554 g_signal_connect_swapped(G_OBJECT(mailer->pl_window), "delete-event",
555 G_CALLBACK(on_plugins_closex), mailer);
556 mailer->pl_view = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
557 gtk_container_add(GTK_CONTAINER(mailer->pl_window), mailer->pl_view);
558 #endif
559 mailer->pl_store = gtk_list_store_new(MPC_COUNT, G_TYPE_STRING,
560 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_STRING,
561 G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER,
562 G_TYPE_POINTER);
563 mailer->pl_combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(
564 mailer->pl_store));
565 g_signal_connect_swapped(G_OBJECT(mailer->pl_combo), "changed",
566 G_CALLBACK(_mailer_on_plugin_combo_changed), mailer);
567 renderer = gtk_cell_renderer_pixbuf_new();
568 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(mailer->pl_combo), renderer,
569 FALSE);
570 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(mailer->pl_combo),
571 renderer, "pixbuf", MPC_ICON, NULL);
572 renderer = gtk_cell_renderer_text_new();
573 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(mailer->pl_combo),
574 renderer, TRUE);
575 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(mailer->pl_combo),
576 renderer, "text", MPC_NAME_DISPLAY, NULL);
577 gtk_box_pack_start(GTK_BOX(mailer->pl_view), mailer->pl_combo, FALSE,
578 TRUE, 0);
579 mailer->pl_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
580 gtk_box_pack_start(GTK_BOX(mailer->pl_view), mailer->pl_box, TRUE, TRUE,
581 0);
582 gtk_widget_set_no_show_all(mailer->pl_view, TRUE);
583 gtk_container_set_border_width(GTK_CONTAINER(mailer->pl_view), 4);
584 #ifndef EMBEDDED
585 hpaned2 = gtk_hpaned_new();
586 gtk_paned_pack1(GTK_PANED(hpaned2), vpaned, TRUE, TRUE);
587 gtk_paned_pack2(GTK_PANED(hpaned2), mailer->pl_view, FALSE, TRUE);
588 gtk_paned_add2(GTK_PANED(hpaned), hpaned2);
589 #endif
590 gtk_widget_show_all(vbox);
591 /* widgets */
592 mailer->ab_window = NULL;
593 mailer->pr_window = NULL;
594 /* show window */
595 gtk_widget_hide(mailer->hdr_vbox);
596 _mailer_update_status(mailer);
597 gtk_widget_show(mailer->pl_window);
598 gtk_widget_show(mailer->fo_window);
599 /* load configuration */
600 mailer->source = g_idle_add(_new_idle, mailer);
601 return mailer;
602 }
603
_new_accounts(Mailer * mailer)604 static int _new_accounts(Mailer * mailer)
605 {
606 int ret = 0;
607 char * dirname;
608 DIR * dir;
609 struct dirent * de;
610 size_t len;
611 #ifdef __APPLE__
612 char const ext[] = ".dylib";
613 #else
614 char const ext[] = ".so";
615 #endif
616 Account ** p;
617
618 mailer->available = NULL;
619 mailer->available_cnt = 0;
620 if((dirname = string_new_append(PLUGINDIR, "/account", NULL)) == NULL)
621 return -1;
622 if((dir = opendir(dirname)) == NULL)
623 {
624 error_set_code(1, "%s: %s", dirname, strerror(errno));
625 string_delete(dirname);
626 return error_print("mailer");
627 }
628 for(de = readdir(dir); de != NULL; de = readdir(dir))
629 {
630 if((len = strlen(de->d_name)) < sizeof(ext)
631 || strcmp(ext, &de->d_name[
632 len - sizeof(ext) + 1]) != 0)
633 continue;
634 de->d_name[len - sizeof(ext) + 1] = '\0';
635 if((p = realloc(mailer->available, (mailer->available_cnt + 1)
636 * sizeof(*p))) == NULL)
637 {
638 error_set_print("mailer", 1, "%s", strerror(errno));
639 continue;
640 }
641 mailer->available = p;
642 if((p[mailer->available_cnt] = account_new(NULL, de->d_name,
643 NULL, NULL)) == NULL)
644 {
645 error_print("mailer");
646 continue;
647 }
648 mailer->available_cnt++;
649 }
650 if(closedir(dir) != 0)
651 ret = error_set_print("mailer", 1, "%s: %s", dirname, strerror(
652 errno));
653 string_delete(dirname);
654 return ret;
655 }
656
_new_folders_view(Mailer * mailer)657 static GtkWidget * _new_folders_view(Mailer * mailer)
658 {
659 GtkWidget * widget;
660 GtkCellRenderer * renderer;
661 GtkTreeSelection * treesel;
662
663 mailer->fo_store = gtk_tree_store_new(MFC_COUNT, G_TYPE_POINTER,
664 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_POINTER,
665 GDK_TYPE_PIXBUF, G_TYPE_STRING);
666 widget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(mailer->fo_store));
667 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(widget), FALSE);
668 renderer = gtk_cell_renderer_pixbuf_new();
669 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(widget), -1,
670 NULL, renderer, "pixbuf", MFC_ICON, NULL);
671 renderer = gtk_cell_renderer_text_new();
672 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(widget), -1,
673 _("Folders"), renderer, "text", MFC_NAME, NULL);
674 treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
675 g_signal_connect(G_OBJECT(treesel), "changed", G_CALLBACK(
676 _on_folders_changed), mailer);
677 return widget;
678 }
679
_on_folders_changed(GtkTreeSelection * selection,gpointer data)680 static void _on_folders_changed(GtkTreeSelection * selection, gpointer data)
681 {
682 Mailer * mailer = data;
683 GtkTreeModel * model;
684 GtkTreeIter iter;
685 GtkTreePath * path;
686 gboolean sent;
687
688 #ifdef DEBUG
689 fprintf(stderr, "DEBUG: %s()\n", __func__);
690 #endif
691 mailer->message_cur = NULL;
692 if(gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE)
693 {
694 mailer->account_cur = NULL;
695 mailer->folder_cur = NULL;
696 gtk_tree_view_set_model(GTK_TREE_VIEW(mailer->he_view), NULL);
697 _mailer_update_status(mailer);
698 return;
699 }
700 /* get current folder */
701 gtk_tree_model_get(model, &iter, MFC_FOLDER, &mailer->folder_cur, -1);
702 /* get current account */
703 path = gtk_tree_model_get_path(model, &iter);
704 while(gtk_tree_path_get_depth(path) > 1 && gtk_tree_path_up(path));
705 gtk_tree_model_get_iter(model, &iter, path);
706 gtk_tree_model_get(model, &iter, MFC_ACCOUNT, &mailer->account_cur, -1);
707 gtk_tree_path_free(path);
708 /* display relevant columns */
709 sent = (mailer->folder_cur != NULL && folder_get_type(
710 mailer->folder_cur) == FT_SENT) ? TRUE : FALSE;
711 gtk_tree_view_column_set_visible(mailer->he_view_from, !sent);
712 gtk_tree_view_column_set_visible(mailer->he_view_to, sent);
713 _mailer_update_view(mailer);
714 #ifdef EMBEDDED
715 if(model != NULL)
716 gtk_window_present(GTK_WINDOW(mailer->he_window));
717 #endif
718 }
719
_new_headers_view(Mailer * mailer)720 static GtkWidget * _new_headers_view(Mailer * mailer)
721 {
722 GtkWidget * widget;
723 GtkTreeView * treeview;
724 GtkTreeSelection * treesel;
725
726 widget = gtk_tree_view_new();
727 treeview = GTK_TREE_VIEW(widget);
728 gtk_tree_view_set_reorderable(treeview, FALSE);
729 gtk_tree_view_set_rules_hint(treeview, TRUE);
730 _headers_view_column_icon(treeview, "", MHC_ICON, MHC_READ);
731 _headers_view_column_text(treeview, _("Subject"), MHC_SUBJECT,
732 MHC_SUBJECT, MHC_WEIGHT);
733 mailer->he_view_from = _headers_view_column_text(treeview, _("From"),
734 MHC_FROM, MHC_FROM, MHC_WEIGHT);
735 mailer->he_view_to = _headers_view_column_text(treeview, _("To"),
736 MHC_TO, MHC_TO, MHC_WEIGHT);
737 _headers_view_column_text(treeview, _("Date"), MHC_DATE_DISPLAY,
738 MHC_DATE, MHC_WEIGHT);
739 treesel = gtk_tree_view_get_selection(treeview);
740 gtk_tree_selection_set_mode(treesel, GTK_SELECTION_MULTIPLE);
741 g_signal_connect(G_OBJECT(treesel), "changed", G_CALLBACK(
742 _on_headers_changed), mailer);
743 return widget;
744 }
745
_on_headers_changed(GtkTreeSelection * selection,gpointer data)746 static void _on_headers_changed(GtkTreeSelection * selection, gpointer data)
747 {
748 Mailer * mailer = data;
749 GtkTreeModel * model;
750 GList * sel;
751 GtkTreeIter iter;
752 gchar * p;
753 gchar * q;
754 gchar * r;
755 Message * message;
756
757 #ifdef DEBUG
758 fprintf(stderr, "DEBUG: %s()\n", __func__);
759 #endif
760 sel = gtk_tree_selection_get_selected_rows(selection, &model);
761 if(sel == NULL || sel->next != NULL) /* empty or multiple */
762 {
763 mailer->message_cur = NULL;
764 gtk_widget_hide(mailer->hdr_vbox);
765 gtk_text_view_set_buffer(GTK_TEXT_VIEW(mailer->bo_view),
766 mailer->bo_buffer);
767 g_list_foreach(sel, (GFunc)gtk_tree_path_free, NULL);
768 g_list_free(sel);
769 return;
770 }
771 gtk_tree_model_get_iter(model, &iter, sel->data);
772 gtk_tree_model_get(model, &iter, MHC_MESSAGE, &message, -1);
773 mailer->message_cur = message;
774 gtk_tree_model_get(model, &iter, MHC_SUBJECT, &p, -1);
775 gtk_label_set_text(GTK_LABEL(mailer->hdr_subject), p);
776 g_free(p);
777 gtk_tree_model_get(model, &iter, MHC_FROM, &p, MHC_FROM_EMAIL, &q, -1);
778 if(q == NULL || strlen(q) == 0 || strcmp(p, q) == 0)
779 r = g_strdup(p);
780 else
781 r = g_strdup_printf("%s <%s>", p, q);
782 gtk_label_set_text(GTK_LABEL(mailer->hdr_from), r);
783 g_free(p);
784 g_free(q);
785 g_free(r);
786 gtk_tree_model_get(model, &iter, MHC_TO, &p, MHC_TO_EMAIL, &q, -1);
787 if(q == NULL || strlen(q) == 0 || strcmp(p, q) == 0)
788 r = g_strdup(p);
789 else
790 r = g_strdup_printf("%s <%s>", p, q);
791 gtk_label_set_text(GTK_LABEL(mailer->hdr_to), r);
792 g_free(p);
793 g_free(q);
794 g_free(r);
795 gtk_tree_model_get(model, &iter, MHC_DATE_DISPLAY, &p, -1);
796 gtk_label_set_text(GTK_LABEL(mailer->hdr_date), p);
797 g_free(p);
798 message_set_read(message, TRUE);
799 gtk_widget_show(mailer->hdr_vbox);
800 _mailer_update_view(mailer);
801 g_list_foreach(sel, (GFunc)gtk_tree_path_free, NULL);
802 g_list_free(sel);
803 #ifdef EMBEDDED
804 gtk_window_present(GTK_WINDOW(mailer->bo_window));
805 #endif
806 }
807
_headers_view_column_icon(GtkTreeView * view,char const * title,int id,int sortid)808 static GtkTreeViewColumn * _headers_view_column_icon(GtkTreeView * view,
809 char const * title, int id, int sortid)
810 {
811 GtkCellRenderer * renderer;
812 GtkTreeViewColumn * column;
813
814 renderer = gtk_cell_renderer_pixbuf_new();
815 column = gtk_tree_view_column_new_with_attributes(title, renderer,
816 "pixbuf", id, NULL);
817 gtk_tree_view_column_set_sort_column_id(column, sortid);
818 gtk_tree_view_append_column(view, column);
819 return column;
820 }
821
_headers_view_column_text(GtkTreeView * view,char const * title,int id,int sortid,int weightid)822 static GtkTreeViewColumn * _headers_view_column_text(GtkTreeView * view,
823 char const * title, int id, int sortid, int weightid)
824 {
825 GtkCellRenderer * renderer;
826 GtkTreeViewColumn * column;
827
828 renderer = gtk_cell_renderer_text_new();
829 g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END,
830 NULL);
831 column = gtk_tree_view_column_new_with_attributes(title, renderer,
832 "text", id, (weightid >= 0) ? "weight" : NULL, weightid,
833 NULL);
834 #if GTK_CHECK_VERSION(2, 4, 0)
835 gtk_tree_view_column_set_expand(column, TRUE);
836 #endif
837 gtk_tree_view_column_set_resizable(column, TRUE);
838 gtk_tree_view_column_set_sort_column_id(column, sortid);
839 gtk_tree_view_append_column(view, column);
840 return column;
841 }
842
_new_headers(Mailer * mailer)843 static GtkWidget * _new_headers(Mailer * mailer)
844 {
845 struct
846 {
847 char * hdr;
848 GtkWidget ** widget;
849 } widgets[] =
850 {
851 { N_(" Subject: "), NULL },
852 { N_(" From: "), NULL },
853 { N_(" To: "), NULL },
854 { N_(" Date: "), NULL },
855 { NULL, NULL }
856 };
857 int i;
858 GtkWidget * vbox;
859 GtkWidget * hbox;
860 GtkWidget * widget;
861 GtkSizeGroup * group;
862 PangoFontDescription * bold;
863
864 widgets[0].widget = &mailer->hdr_subject;
865 widgets[1].widget = &mailer->hdr_from;
866 widgets[2].widget = &mailer->hdr_to;
867 widgets[3].widget = &mailer->hdr_date;
868 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
869 mailer->hdr_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
870 group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
871 bold = pango_font_description_new();
872 pango_font_description_set_weight(bold, PANGO_WEIGHT_BOLD);
873 for(i = 0; widgets[i].hdr != NULL; i++)
874 {
875 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
876 widget = gtk_label_new(_(widgets[i].hdr));
877 gtk_widget_override_font(widget, bold);
878 #if GTK_CHECK_VERSION(3, 14, 0)
879 g_object_set(widget, "halign", GTK_ALIGN_END,
880 "valign", GTK_ALIGN_START, NULL);
881 #else
882 gtk_misc_set_alignment(GTK_MISC(widget), 1.0, 0.0);
883 #endif
884 gtk_size_group_add_widget(GTK_SIZE_GROUP(group), widget);
885 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0);
886 widget = gtk_label_new("");
887 *(widgets[i].widget) = widget;
888 gtk_label_set_ellipsize(GTK_LABEL(widget),
889 PANGO_ELLIPSIZE_MIDDLE);
890 #if GTK_CHECK_VERSION(3, 14, 0)
891 g_object_set(widget, "halign", GTK_ALIGN_START,
892 "valign", GTK_ALIGN_START, NULL);
893 #else
894 gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.0);
895 #endif
896 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
897 gtk_box_pack_start(GTK_BOX(mailer->hdr_vbox), hbox, FALSE,
898 FALSE, 0);
899 }
900 gtk_box_pack_start(GTK_BOX(vbox), mailer->hdr_vbox, FALSE, FALSE, 0);
901 pango_font_description_free(bold);
902 return vbox;
903 }
904
_new_idle(gpointer data)905 static gboolean _new_idle(gpointer data)
906 {
907 Mailer * mailer = data;
908
909 _idle_config_load(mailer);
910 _idle_plugins_load(mailer);
911 return FALSE;
912 }
913
_idle_config_load(Mailer * mailer)914 static void _idle_config_load(Mailer * mailer)
915 {
916 char * filename;
917 char const * value;
918 PangoFontDescription * font;
919 char * p;
920 char * q;
921
922 mailer->source = 0;
923 if((mailer->config = config_new()) == NULL)
924 return;
925 if((filename = _mailer_get_config_filename()) == NULL)
926 return;
927 if(config_load(mailer->config, filename) != 0)
928 mailer_error(NULL, error_get(NULL), 1);
929 free(filename);
930 value = _mailer_get_font(mailer);
931 font = pango_font_description_from_string(value);
932 gtk_widget_override_font(mailer->bo_view, font);
933 pango_font_description_free(font);
934 /* check if we are online */
935 if((p = config_get(mailer->config, NULL, "online")) == NULL
936 || strtol(p, NULL, 10) != 0)
937 mailer_set_online(mailer, TRUE);
938 else
939 mailer_set_online(mailer, FALSE);
940 /* load accounts */
941 if((value = config_get(mailer->config, NULL, "accounts")) == NULL
942 || value[0] == '\0')
943 return;
944 if((p = strdup(value)) == NULL)
945 return;
946 value = p;
947 for(q = p; *q != '\0'; q++)
948 {
949 if(*q != ',')
950 continue;
951 *q = '\0';
952 _mailer_config_load_account(mailer, value);
953 value = q + 1;
954 }
955 if(value[0] != '\0')
956 _mailer_config_load_account(mailer, value);
957 free(p);
958 }
959
_idle_plugins_load(Mailer * mailer)960 static void _idle_plugins_load(Mailer * mailer)
961 {
962 char const * plugins;
963 char * p;
964 char * q;
965 size_t i;
966
967 if((plugins = config_get(mailer->config, NULL, "plugins")) == NULL
968 || strlen(plugins) == 0)
969 return;
970 if((p = strdup(plugins)) == NULL)
971 return; /* XXX report error */
972 for(q = p, i = 0;;)
973 {
974 if(q[i] == '\0')
975 {
976 mailer_load(mailer, q);
977 break;
978 }
979 if(q[i++] != ',')
980 continue;
981 q[i - 1] = '\0';
982 mailer_load(mailer, q);
983 q += i;
984 i = 0;
985 }
986 free(p);
987 }
988
989
990 /* mailer_delete */
991 static void _delete_plugins(Mailer * mailer);
992
mailer_delete(Mailer * mailer)993 void mailer_delete(Mailer * mailer)
994 {
995 unsigned int i;
996
997 _delete_plugins(mailer);
998 if(mailer->ssl_ctx != NULL)
999 SSL_CTX_free(mailer->ssl_ctx);
1000 if(mailer->source != 0)
1001 g_source_remove(mailer->source);
1002 for(i = 0; i < mailer->available_cnt; i++)
1003 account_delete(mailer->available[i]);
1004 free(mailer->available);
1005 for(i = 0; i < mailer->account_cnt; i++)
1006 account_delete(mailer->account[i]);
1007 free(mailer->account);
1008 g_object_unref(mailer->pl_store);
1009 object_delete(mailer);
1010 }
1011
_delete_plugins(Mailer * mailer)1012 static void _delete_plugins(Mailer * mailer)
1013 {
1014 GtkTreeModel * model = GTK_TREE_MODEL(mailer->pl_store);
1015 GtkTreeIter iter;
1016 gboolean valid;
1017 MailerPluginDefinition * mpd;
1018 MailerPlugin * mp;
1019 Plugin * plugin;
1020
1021 for(valid = gtk_tree_model_get_iter_first(model, &iter); valid == TRUE;
1022 valid = gtk_tree_model_iter_next(model, &iter))
1023 {
1024 gtk_tree_model_get(model, &iter, MPC_PLUGIN, &plugin,
1025 MPC_MAILERPLUGINDEFINITION, &mpd,
1026 MPC_MAILERPLUGIN, &mp, -1);
1027 if(mpd->destroy != NULL)
1028 mpd->destroy(mp);
1029 plugin_delete(plugin);
1030 }
1031 }
1032
1033
1034 /* accessors */
1035 /* mailer_get_config */
mailer_get_config(Mailer * mailer,char const * variable)1036 char const * mailer_get_config(Mailer * mailer, char const * variable)
1037 {
1038 return config_get(mailer->config, NULL, variable);
1039 }
1040
1041
1042 /* mailer_get_ssl_context */
mailer_get_ssl_context(Mailer * mailer)1043 SSL_CTX * mailer_get_ssl_context(Mailer * mailer)
1044 {
1045 return mailer->ssl_ctx;
1046 }
1047
1048
1049 /* mailer_is_online */
mailer_is_online(Mailer * mailer)1050 gboolean mailer_is_online(Mailer * mailer)
1051 {
1052 return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
1053 mailer->st_online));
1054 }
1055
1056
1057 /* mailer_set_online */
mailer_set_online(Mailer * mailer,gboolean online)1058 void mailer_set_online(Mailer * mailer, gboolean online)
1059 {
1060 GtkWidget * image;
1061 size_t i;
1062
1063 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mailer->st_online),
1064 online);
1065 image = gtk_image_new_from_stock(online ? GTK_STOCK_CONNECT
1066 : GTK_STOCK_DISCONNECT, GTK_ICON_SIZE_MENU);
1067 gtk_button_set_image(GTK_BUTTON(mailer->st_online), image);
1068 for(i = 0; i < mailer->account_cnt; i++)
1069 if(online)
1070 account_start(mailer->account[i]);
1071 else
1072 account_stop(mailer->account[i]);
1073 }
1074
1075
1076 /* mailer_set_status */
mailer_set_status(Mailer * mailer,char const * status)1077 void mailer_set_status(Mailer * mailer, char const * status)
1078 {
1079 GtkStatusbar * sb;
1080
1081 if(status == NULL)
1082 {
1083 _mailer_update_status(mailer);
1084 return;
1085 }
1086 sb = GTK_STATUSBAR(mailer->statusbar);
1087 if(mailer->statusbar_id != 0)
1088 gtk_statusbar_remove(sb, gtk_statusbar_get_context_id(sb, ""),
1089 mailer->statusbar_id);
1090 mailer->statusbar_id = gtk_statusbar_push(sb,
1091 gtk_statusbar_get_context_id(sb, ""), status);
1092 }
1093
1094
1095 /* useful */
1096 /* mailer_error */
mailer_error(Mailer * mailer,char const * message,int ret)1097 int mailer_error(Mailer * mailer, char const * message, int ret)
1098 {
1099 #if !GTK_CHECK_VERSION(2, 18, 0)
1100 GtkWidget * dialog;
1101 #endif
1102
1103 if(mailer == NULL)
1104 return error_set_print("mailer", ret, "%s", message);
1105 #if GTK_CHECK_VERSION(2, 18, 0)
1106 /* info bar */
1107 gtk_label_set_text(GTK_LABEL(mailer->fo_infobar_label), message);
1108 gtk_widget_show(mailer->fo_infobar);
1109 #else
1110 /* dialog window */
1111 dialog = gtk_message_dialog_new(GTK_WINDOW(mailer->fo_window),
1112 GTK_DIALOG_DESTROY_WITH_PARENT,
1113 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
1114 # if GTK_CHECK_VERSION(2, 6, 0)
1115 "%s", _("Error"));
1116 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
1117 # endif
1118 "%s", message);
1119 gtk_window_set_title(GTK_WINDOW(dialog), _("Error"));
1120 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(
1121 mailer->fo_window));
1122 g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(
1123 gtk_widget_destroy), NULL);
1124 gtk_widget_show(dialog);
1125 #endif
1126 return ret;
1127 }
1128
1129
1130 /* mailer_refresh_all */
mailer_refresh_all(Mailer * mailer)1131 void mailer_refresh_all(Mailer * mailer)
1132 {
1133 size_t i;
1134
1135 for(i = 0; i < mailer->account_cnt; i++)
1136 account_refresh(mailer->account[i]);
1137 }
1138
1139
1140 /* mailer_account_add */
mailer_account_add(Mailer * mailer,Account * account)1141 int mailer_account_add(Mailer * mailer, Account * account)
1142 {
1143 Account ** p;
1144
1145 #ifdef DEBUG
1146 fprintf(stderr, "DEBUG: %s(%p)\n", __func__, (void *)account);
1147 #endif
1148 if((p = realloc(mailer->account, sizeof(*p) * (mailer->account_cnt
1149 + 1))) == NULL)
1150 return -mailer_error(mailer, "realloc", 1);
1151 mailer->account = p;
1152 mailer->account[mailer->account_cnt] = account;
1153 mailer->account_cnt++;
1154 account_store(account, mailer->fo_store);
1155 /* XXX check (and report) errors */
1156 if(mailer_is_online(mailer))
1157 account_start(account);
1158 return 0;
1159 }
1160
1161
1162 #if 0 /* FIXME deprecate? */
1163 /* mailer_account_disable */
1164 int mailer_account_disable(Mailer * mailer, Account * account)
1165 {
1166 unsigned int i;
1167
1168 for(i = 0; i < mailer->account_cnt; i++)
1169 if(mailer->account[i] == account)
1170 break;
1171 if(i == mailer->account_cnt)
1172 return 1;
1173 account_set_enabled(account, 0);
1174 return 0;
1175 }
1176
1177
1178 /* mailer_account_enable */
1179 int mailer_account_enable(Mailer * mailer, Account * account)
1180 {
1181 unsigned int i;
1182
1183 for(i = 0; i < mailer->account_cnt; i++)
1184 if(mailer->account[i] == account)
1185 break;
1186 if(i == mailer->account_cnt)
1187 return 1;
1188 account_set_enabled(account, 1);
1189 return 0;
1190 }
1191 #endif
1192
1193
1194 /* mailer_compose */
mailer_compose(Mailer * mailer)1195 void mailer_compose(Mailer * mailer)
1196 {
1197 Compose * compose;
1198 Account * account;
1199 char const * title;
1200 char const * name;
1201 char const * email;
1202 char const * organization;
1203 gchar * p;
1204
1205 if((compose = compose_new(mailer->config)) == NULL)
1206 return; /* XXX report error */
1207 if((account = mailer->account_cur) == NULL)
1208 {
1209 if(mailer->account_cnt == 0)
1210 return;
1211 account = mailer->account[0];
1212 }
1213 title = account_get_title(account);
1214 if((name = config_get(mailer->config, title, "identity_name")) != NULL
1215 && name[0] == '\0')
1216 name = NULL;
1217 if((email = config_get(mailer->config, title, "identity_email")) != NULL
1218 && email[0] == '\0')
1219 email = NULL;
1220 if((p = g_strdup_printf("%s%s%s%s", (name != NULL) ? name : "",
1221 (name != NULL && email != NULL) ? " <"
1222 : "", (email != NULL) ? email : "",
1223 (name != NULL && email != NULL) ? ">"
1224 : "")) != NULL)
1225 {
1226 compose_set_from(compose, p);
1227 g_free(p);
1228 }
1229 organization = config_get(mailer->config, title,
1230 "identity_organization");
1231 if(organization != NULL && organization[0] != '\0')
1232 compose_set_header(compose, "Organization:", organization,
1233 TRUE);
1234 }
1235
1236
1237 /* mailer_delete_selected */
1238 static void _mailer_delete_selected_foreach(GtkTreeRowReference * reference,
1239 Mailer * mailer);
1240
mailer_delete_selected(Mailer * mailer)1241 void mailer_delete_selected(Mailer * mailer)
1242 {
1243 /* FIXME figure which area is focused first (deleting folders) */
1244 GtkTreeModel * model;
1245 GList * selected;
1246 GList * s;
1247 GtkTreePath * path;
1248 GtkTreeRowReference * reference;
1249
1250 if((model = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->he_view)))
1251 == NULL)
1252 return;
1253 if((selected = _mailer_get_selected_headers(mailer)) == NULL)
1254 return;
1255 /* FIXME move messages to trash first */
1256 if(_mailer_confirm(mailer, _("The messages selected will be deleted.\n"
1257 "Continue?")) != TRUE)
1258 {
1259 g_list_free(selected);
1260 return;
1261 }
1262 for(s = g_list_first(selected); s != NULL; s = g_list_next(s))
1263 {
1264 if((path = s->data) == NULL)
1265 continue;
1266 reference = gtk_tree_row_reference_new(model, path);
1267 s->data = reference;
1268 gtk_tree_path_free(path);
1269 }
1270 g_list_foreach(selected, (GFunc)_mailer_delete_selected_foreach,
1271 mailer);
1272 g_list_free(selected);
1273 }
1274
_mailer_delete_selected_foreach(GtkTreeRowReference * reference,Mailer * mailer)1275 static void _mailer_delete_selected_foreach(GtkTreeRowReference * reference,
1276 Mailer * mailer)
1277 {
1278 GtkTreeModel * model;
1279 GtkTreePath * path;
1280 GtkTreeIter iter;
1281 Message * message;
1282
1283 if((model = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->he_view)))
1284 == NULL)
1285 return;
1286 if(reference == NULL)
1287 return;
1288 if((path = gtk_tree_row_reference_get_path(reference)) == NULL)
1289 return;
1290 if(gtk_tree_model_get_iter(model, &iter, path) == TRUE)
1291 gtk_tree_model_get(model, &iter, MHC_MESSAGE, &message, -1);
1292 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
1293 gtk_tree_path_free(path);
1294 }
1295
1296
1297 /* mailer_copy */
mailer_copy(Mailer * mailer)1298 void mailer_copy(Mailer * mailer)
1299 {
1300 GtkTextBuffer * buffer;
1301 GtkClipboard * clipboard;
1302
1303 if(gtk_window_get_focus(GTK_WINDOW(mailer->fo_window))
1304 == mailer->bo_view)
1305 {
1306 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(
1307 mailer->bo_view));
1308 clipboard = gtk_widget_get_clipboard(mailer->bo_view,
1309 GDK_SELECTION_CLIPBOARD);
1310 gtk_text_buffer_copy_clipboard(buffer, clipboard);
1311 }
1312 /* FIXME implement the other widgets */
1313 }
1314
1315
1316 /* mailer_cut */
mailer_cut(Mailer * mailer)1317 void mailer_cut(Mailer * mailer)
1318 {
1319 GtkTextBuffer * buffer;
1320 GtkClipboard * clipboard;
1321
1322 if(gtk_window_get_focus(GTK_WINDOW(mailer->fo_window))
1323 == mailer->bo_view) /* XXX copies, really */
1324 {
1325 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(
1326 mailer->bo_view));
1327 clipboard = gtk_widget_get_clipboard(mailer->bo_view,
1328 GDK_SELECTION_CLIPBOARD);
1329 gtk_text_buffer_cut_clipboard(buffer, clipboard, FALSE);
1330 }
1331 /* FIXME implement the other widgets */
1332 }
1333
1334
1335 /* mailer_load */
mailer_load(Mailer * mailer,char const * plugin)1336 int mailer_load(Mailer * mailer, char const * plugin)
1337 {
1338 Plugin * p;
1339 MailerPluginDefinition * mpd;
1340 MailerPlugin * mp;
1341 GtkWidget * widget;
1342 GtkTreeIter iter;
1343 GtkIconTheme * theme;
1344 GdkPixbuf * icon = NULL;
1345
1346 #ifdef DEBUG
1347 fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, plugin);
1348 #endif
1349 if(_mailer_plugin_is_enabled(mailer, plugin))
1350 return 0;
1351 if((p = plugin_new(LIBDIR, PACKAGE, "plugins", plugin)) == NULL)
1352 return -mailer_error(NULL, error_get(NULL), 1);
1353 if((mpd = plugin_lookup(p, "plugin")) == NULL)
1354 {
1355 plugin_delete(p);
1356 return -mailer_error(NULL, error_get(NULL), 1);
1357 }
1358 if(mpd->init == NULL || mpd->destroy == NULL
1359 || (mp = mpd->init(&mailer->pl_helper)) == NULL)
1360 {
1361 plugin_delete(p);
1362 return -mailer_error(NULL, error_get(NULL), 1);
1363 }
1364 theme = gtk_icon_theme_get_default();
1365 if(mpd->icon != NULL)
1366 icon = gtk_icon_theme_load_icon(theme, mpd->icon, 24, 0, NULL);
1367 if(icon == NULL)
1368 icon = gtk_icon_theme_load_icon(theme, "gnome-settings", 24, 0,
1369 NULL);
1370 widget = NULL;
1371 if(mpd->get_widget != NULL && (widget = mpd->get_widget(mp)) != NULL)
1372 gtk_widget_hide(widget);
1373 /* FIXME hide from the list of active plug-ins if there is no widget */
1374 gtk_list_store_append(mailer->pl_store, &iter);
1375 gtk_list_store_set(mailer->pl_store, &iter, MPC_NAME, plugin,
1376 MPC_ICON, icon, MPC_NAME_DISPLAY, mpd->name,
1377 MPC_PLUGIN, p, MPC_MAILERPLUGINDEFINITION, mpd,
1378 MPC_MAILERPLUGIN, mp, MPC_WIDGET, widget, -1);
1379 if(widget == NULL)
1380 return 0;
1381 gtk_box_pack_start(GTK_BOX(mailer->pl_box), widget, TRUE, TRUE, 0);
1382 if(gtk_widget_get_no_show_all(mailer->pl_view) == TRUE)
1383 {
1384 gtk_combo_box_set_active(GTK_COMBO_BOX(mailer->pl_combo), 0);
1385 gtk_widget_set_no_show_all(mailer->pl_view, FALSE);
1386 gtk_widget_show_all(mailer->pl_view);
1387 }
1388 return 0;
1389 }
1390
1391
1392 /* mailer_open_selected_source */
1393 static void _open_selected_source(Mailer * mailer, GtkTreeModel * model,
1394 GtkTreeIter * iter);
1395
mailer_open_selected_source(Mailer * mailer)1396 void mailer_open_selected_source(Mailer * mailer)
1397 {
1398 _mailer_foreach_message_selected(mailer, _open_selected_source);
1399 }
1400
_open_selected_source(Mailer * mailer,GtkTreeModel * model,GtkTreeIter * iter)1401 static void _open_selected_source(Mailer * mailer, GtkTreeModel * model,
1402 GtkTreeIter * iter)
1403 {
1404 GtkWidget * window;
1405 GtkWidget * scrolled;
1406 PangoFontDescription * font;
1407 char const * p;
1408 GtkWidget * widget;
1409 GtkTextBuffer * tbuf;
1410
1411 gtk_tree_model_get(model, iter, MHC_MESSAGE, &mailer->message_cur, -1);
1412 if(mailer->message_cur == NULL)
1413 return;
1414 if((tbuf = account_select_source(mailer->account_cur,
1415 mailer->folder_cur,
1416 mailer->message_cur)) == NULL)
1417 return;
1418 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1419 gtk_window_set_default_size(GTK_WINDOW(window), 640, 480);
1420 /* XXX choose a better title */
1421 gtk_window_set_title(GTK_WINDOW(window), _("Mailer - View source"));
1422 scrolled = gtk_scrolled_window_new(NULL, NULL);
1423 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1424 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1425 widget = gtk_text_view_new_with_buffer(tbuf);
1426 if((p = config_get(mailer->config, NULL, "messages_font")) != NULL)
1427 {
1428 font = pango_font_description_from_string(p);
1429 gtk_widget_override_font(widget, font);
1430 pango_font_description_free(font);
1431 }
1432 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(widget), FALSE);
1433 gtk_text_view_set_editable(GTK_TEXT_VIEW(widget), FALSE);
1434 gtk_container_add(GTK_CONTAINER(scrolled), widget);
1435 gtk_container_add(GTK_CONTAINER(window), scrolled);
1436 gtk_widget_show_all(window);
1437 /* FIXME count the window */
1438 }
1439
1440
1441 /* mailer_paste */
mailer_paste(Mailer * mailer)1442 void mailer_paste(Mailer * mailer)
1443 {
1444 GtkTextBuffer * buffer;
1445 GtkClipboard * clipboard;
1446
1447 if(gtk_window_get_focus(GTK_WINDOW(mailer->fo_window))
1448 == mailer->bo_view) /* XXX does nothing, really */
1449 {
1450 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(
1451 mailer->bo_view));
1452 clipboard = gtk_widget_get_clipboard(mailer->bo_view,
1453 GDK_SELECTION_CLIPBOARD);
1454 gtk_text_buffer_paste_clipboard(buffer, clipboard, NULL, FALSE);
1455 }
1456 /* FIXME implement the other widgets */
1457 }
1458
1459
1460 /* mailer_reply_selected */
1461 static void _reply_selected(Mailer * mailer, GtkTreeModel * model,
1462 GtkTreeIter * iter);
1463
mailer_reply_selected(Mailer * mailer)1464 void mailer_reply_selected(Mailer * mailer)
1465 {
1466 _mailer_foreach_message_selected(mailer, _reply_selected);
1467 }
1468
_reply_selected(Mailer * mailer,GtkTreeModel * model,GtkTreeIter * iter)1469 static void _reply_selected(Mailer * mailer, GtkTreeModel * model,
1470 GtkTreeIter * iter)
1471 {
1472 Compose * compose;
1473 char * date;
1474 char * from;
1475 char * subject;
1476 char * to;
1477 char * p;
1478 char const * q;
1479 GtkTextBuffer * tbuf;
1480 GtkTextIter start;
1481 GtkTextIter end;
1482
1483 if((compose = compose_new(mailer->config)) == NULL)
1484 return; /* XXX error message? */
1485 gtk_tree_model_get(model, iter, MHC_DATE_DISPLAY, &date,
1486 MHC_FROM_EMAIL, &from, MHC_SUBJECT, &subject,
1487 MHC_TO_EMAIL, &to, -1);
1488 /* from */
1489 if(from != NULL)
1490 compose_set_header(compose, "To:", from, TRUE);
1491 /* to */
1492 if(to != NULL)
1493 compose_set_from(compose, to);
1494 /* FIXME also set the In-Reply-To field */
1495 /* subject */
1496 q = N_("Re: ");
1497 if(subject != NULL && strncasecmp(subject, q, strlen(q)) != 0
1498 && strncasecmp(subject, _(q), strlen(_(q))) != 0
1499 && (p = malloc(strlen(q) + strlen(subject) + 1))
1500 != NULL)
1501 {
1502 sprintf(p, "%s%s", q, subject);
1503 free(subject);
1504 subject = p;
1505 }
1506 compose_set_subject(compose, subject);
1507 /* body */
1508 compose_set_text(compose, "\nOn ");
1509 compose_append_text(compose, date);
1510 compose_append_text(compose, ", ");
1511 compose_append_text(compose, from);
1512 compose_append_text(compose, " wrote:\n");
1513 tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mailer->bo_view));
1514 for(gtk_text_buffer_get_start_iter(tbuf, &start), end = start;
1515 gtk_text_iter_is_end(&start) != TRUE; start = end)
1516 {
1517 gtk_text_iter_forward_line(&end);
1518 p = gtk_text_iter_get_text(&start, &end);
1519 /* stop if we recognize an unquoted signature */
1520 if(strcmp(p, "-- \n") == 0)
1521 {
1522 g_free(p);
1523 break;
1524 }
1525 compose_append_text(compose, (p[0] == '>') ? ">" : "> ");
1526 compose_append_text(compose, p);
1527 g_free(p);
1528 }
1529 compose_append_signature(compose);
1530 compose_set_modified(compose, FALSE);
1531 compose_scroll_to_offset(compose, 0);
1532 free(date);
1533 free(from);
1534 free(subject);
1535 }
1536
1537
1538 /* mailer_reply_selected_to_all */
1539 static void _reply_selected_to_all(Mailer * mailer, GtkTreeModel * model,
1540 GtkTreeIter * iter);
mailer_reply_selected_to_all(Mailer * mailer)1541 void mailer_reply_selected_to_all(Mailer * mailer)
1542 {
1543 _mailer_foreach_message_selected(mailer, _reply_selected_to_all);
1544 }
1545
_reply_selected_to_all(Mailer * mailer,GtkTreeModel * model,GtkTreeIter * iter)1546 static void _reply_selected_to_all(Mailer * mailer, GtkTreeModel * model,
1547 GtkTreeIter * iter)
1548 {
1549 /* FIXME really implement */
1550 _reply_selected(mailer, model, iter);
1551 }
1552
1553
1554 /* mailer_save_selected */
mailer_save_selected(Mailer * mailer,char const * filename)1555 gboolean mailer_save_selected(Mailer * mailer, char const * filename)
1556 {
1557 if(mailer->message_cur == NULL)
1558 return TRUE;
1559 if(filename == NULL)
1560 return mailer_save_selected_dialog(mailer);
1561 return (message_save(mailer->message_cur, filename) == 0)
1562 ? TRUE : FALSE;
1563 }
1564
1565
1566 /* mailer_save_selected_dialog */
mailer_save_selected_dialog(Mailer * mailer)1567 gboolean mailer_save_selected_dialog(Mailer * mailer)
1568 {
1569 gboolean ret;
1570 GtkWidget * dialog;
1571 char * filename = NULL;
1572
1573 if(mailer->message_cur == NULL)
1574 return TRUE;
1575 dialog = gtk_file_chooser_dialog_new(_("Save as..."),
1576 GTK_WINDOW(mailer->he_window),
1577 GTK_FILE_CHOOSER_ACTION_SAVE,
1578 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1579 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
1580 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1581 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(
1582 dialog));
1583 gtk_widget_destroy(dialog);
1584 if(filename == NULL)
1585 return FALSE;
1586 ret = mailer_save_selected(mailer, filename);
1587 g_free(filename);
1588 return ret;
1589 }
1590
1591
1592 /* mailer_select_all */
mailer_select_all(Mailer * mailer)1593 void mailer_select_all(Mailer * mailer)
1594 {
1595 GtkTreeSelection * treesel;
1596 #if GTK_CHECK_VERSION(2, 4, 0)
1597 GtkTextBuffer * tbuf;
1598 GtkTextIter start;
1599 GtkTextIter end;
1600 #endif
1601
1602 #if GTK_CHECK_VERSION(2, 4, 0)
1603 if(gtk_window_get_focus(GTK_WINDOW(mailer->fo_window))
1604 == mailer->bo_view)
1605 {
1606 tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mailer->bo_view));
1607 gtk_text_buffer_get_start_iter(tbuf, &start);
1608 gtk_text_buffer_get_end_iter(tbuf, &end);
1609 gtk_text_buffer_select_range(tbuf, &start, &end);
1610 return;
1611 }
1612 #endif
1613 treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(mailer->he_view));
1614 gtk_tree_selection_select_all(treesel);
1615 }
1616
1617
1618 /* messages */
mailer_message_open(Mailer * mailer,char const * filename)1619 gboolean mailer_message_open(Mailer * mailer, char const * filename)
1620 {
1621 Message * message;
1622 Compose * compose;
1623
1624 if(filename == NULL)
1625 return mailer_message_open_dialog(mailer);
1626 if((message = message_new_open(mailer, filename)) == NULL)
1627 {
1628 mailer_error(mailer, error_get(NULL), 1);
1629 return FALSE;
1630 }
1631 compose = compose_new_open(mailer->config, message);
1632 message_delete(message);
1633 return (compose != NULL) ? TRUE : FALSE;
1634 }
1635
1636
1637 /* mailer_message_open_dialog */
mailer_message_open_dialog(Mailer * mailer)1638 gboolean mailer_message_open_dialog(Mailer * mailer)
1639 {
1640 gboolean ret;
1641 GtkWidget * dialog;
1642 char * filename = NULL;
1643
1644 dialog = gtk_file_chooser_dialog_new(_("Open..."),
1645 GTK_WINDOW(mailer->he_window),
1646 GTK_FILE_CHOOSER_ACTION_OPEN,
1647 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1648 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
1649 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1650 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(
1651 dialog));
1652 gtk_widget_destroy(dialog);
1653 if(filename == NULL)
1654 return FALSE;
1655 ret = mailer_message_open(mailer, filename);
1656 g_free(filename);
1657 return ret;
1658 }
1659
1660
1661 /* mailer_show_about */
1662 static gboolean _about_on_closex(gpointer data);
1663
mailer_show_about(Mailer * mailer,gboolean show)1664 void mailer_show_about(Mailer * mailer, gboolean show)
1665 {
1666 GtkWidget * dialog;
1667
1668 if(mailer->ab_window != NULL)
1669 {
1670 if(show)
1671 gtk_window_present(GTK_WINDOW(mailer->ab_window));
1672 else
1673 gtk_widget_hide(mailer->ab_window);
1674 return;
1675 }
1676 dialog = desktop_about_dialog_new();
1677 mailer->ab_window = dialog;
1678 g_signal_connect_swapped(G_OBJECT(dialog), "delete-event", G_CALLBACK(
1679 _about_on_closex), mailer);
1680 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(
1681 mailer->fo_window));
1682 desktop_about_dialog_set_name(dialog, PACKAGE);
1683 desktop_about_dialog_set_version(dialog, VERSION);
1684 desktop_about_dialog_set_authors(dialog, _authors);
1685 desktop_about_dialog_set_comments(dialog, _comments);
1686 desktop_about_dialog_set_copyright(dialog, _copyright);
1687 desktop_about_dialog_set_license(dialog, _license);
1688 desktop_about_dialog_set_logo_icon_name(dialog, "mailer");
1689 desktop_about_dialog_set_translator_credits(dialog,
1690 _("translator-credits"));
1691 desktop_about_dialog_set_website(dialog, _website);
1692 gtk_widget_show(dialog);
1693 }
1694
_about_on_closex(gpointer data)1695 static gboolean _about_on_closex(gpointer data)
1696 {
1697 Mailer * mailer = data;
1698
1699 gtk_widget_hide(mailer->ab_window);
1700 return TRUE;
1701 }
1702
1703
1704 /* mailer_show_body */
mailer_show_body(Mailer * mailer,gboolean show)1705 void mailer_show_body(Mailer * mailer, gboolean show)
1706 {
1707 if(show == TRUE)
1708 gtk_window_present(GTK_WINDOW(mailer->bo_window));
1709 else
1710 gtk_widget_hide(mailer->bo_window);
1711 }
1712
1713
1714 /* mailer_show_headers */
mailer_show_headers(Mailer * mailer,gboolean show)1715 void mailer_show_headers(Mailer * mailer, gboolean show)
1716 {
1717 if(show == TRUE)
1718 gtk_window_present(GTK_WINDOW(mailer->he_window));
1719 else
1720 gtk_widget_hide(mailer->he_window);
1721 }
1722
1723
1724 /* mailer_show_plugins */
mailer_show_plugins(Mailer * mailer,gboolean show)1725 void mailer_show_plugins(Mailer * mailer, gboolean show)
1726 {
1727 if(show == TRUE)
1728 gtk_window_present(GTK_WINDOW(mailer->pl_window));
1729 else
1730 gtk_widget_hide(mailer->pl_window);
1731 }
1732
1733
1734 /* mailer_show_preferences */
1735 typedef enum _AccountColumn
1736 {
1737 AC_DATA = 0,
1738 AC_ACTIVE,
1739 AC_ENABLED,
1740 AC_TITLE,
1741 AC_TYPE,
1742 AC_WIDGET
1743 } AccountColumn;
1744 #define AC_LAST AC_WIDGET
1745 #define AC_COUNT (AC_LAST + 1)
1746
1747 static void _preferences_accounts(Mailer * mailer, GtkWidget * notebook);
1748 static void _preferences_display(Mailer * mailer, GtkWidget * notebook);
1749 static void _preferences_plugins(Mailer * mailer, GtkWidget * notebook);
1750 static void _preferences_set(Mailer * mailer);
1751 static void _preferences_set_plugins(Mailer * mailer);
1752
1753 /* callbacks */
1754 static gboolean _on_preferences_closex(gpointer data);
1755 static void _on_preferences_response(GtkWidget * widget, gint response,
1756 gpointer data);
1757 static void _on_preferences_account_delete(gpointer data);
1758 static void _on_preferences_account_edit(gpointer data);
1759 static void _on_preferences_account_move_down(gpointer data);
1760 static void _on_preferences_account_move_up(gpointer data);
1761 static void _on_preferences_account_new(gpointer data);
1762 static void _on_preferences_account_toggle(GtkCellRendererToggle * renderer,
1763 char * path, gpointer data);
1764 static void _on_preferences_cancel(gpointer data);
1765 static void _on_preferences_ok(gpointer data);
1766 static int _preferences_ok_accounts(Mailer * mailer);
1767 static int _preferences_ok_display(Mailer * mailer);
1768 static int _preferences_ok_plugins(Mailer * mailer);
1769 static int _preferences_ok_save(Mailer * mailer);
1770 static void _preferences_on_plugin_toggled(GtkCellRendererToggle * renderer,
1771 char * path, gpointer data);
1772
mailer_show_preferences(Mailer * mailer,gboolean show)1773 void mailer_show_preferences(Mailer * mailer, gboolean show)
1774 {
1775 GtkWidget * vbox;
1776 GtkWidget * notebook;
1777
1778 if(mailer->pr_window != NULL)
1779 {
1780 if(show)
1781 gtk_window_present(GTK_WINDOW(mailer->pr_window));
1782 else
1783 gtk_widget_hide(mailer->pr_window);
1784 return;
1785 }
1786 mailer->pr_window = gtk_dialog_new_with_buttons(
1787 _("Mailer preferences"), GTK_WINDOW(mailer->fo_window),
1788 GTK_DIALOG_DESTROY_WITH_PARENT,
1789 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1790 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1791 #ifndef EMBEDDED
1792 gtk_window_set_default_size(GTK_WINDOW(mailer->pr_window), 400, 300);
1793 #else
1794 gtk_window_set_default_size(GTK_WINDOW(mailer->pr_window), 200, 300);
1795 #endif
1796 g_signal_connect_swapped(G_OBJECT(mailer->pr_window), "delete-event",
1797 G_CALLBACK(_on_preferences_closex), mailer);
1798 g_signal_connect(G_OBJECT(mailer->pr_window), "response",
1799 G_CALLBACK(_on_preferences_response), mailer);
1800 #if GTK_CHECK_VERSION(2, 14, 0)
1801 vbox = gtk_dialog_get_content_area(GTK_DIALOG(mailer->pr_window));
1802 #else
1803 vbox = GTK_DIALOG(mailer->pr_window)->vbox;
1804 #endif
1805 notebook = gtk_notebook_new();
1806 /* accounts */
1807 _preferences_accounts(mailer, notebook);
1808 /* display */
1809 _preferences_display(mailer, notebook);
1810 /* plug-ins */
1811 _preferences_plugins(mailer, notebook);
1812 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
1813 _preferences_set(mailer);
1814 gtk_widget_show_all(vbox);
1815 if(show)
1816 gtk_widget_show(mailer->pr_window);
1817 else
1818 gtk_widget_hide(mailer->pr_window);
1819 }
1820
_preferences_accounts(Mailer * mailer,GtkWidget * notebook)1821 static void _preferences_accounts(Mailer * mailer, GtkWidget * notebook)
1822 {
1823 GtkWidget * vbox2;
1824 GtkWidget * vbox3;
1825 GtkWidget * hbox;
1826 GtkWidget * widget;
1827 GtkListStore * store;
1828 GtkCellRenderer * renderer;
1829 size_t i;
1830 Account * ac;
1831 GtkTreeIter iter;
1832
1833 vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
1834 gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4);
1835 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
1836 widget = gtk_scrolled_window_new(NULL, NULL);
1837 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget),
1838 GTK_SHADOW_IN);
1839 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
1840 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1841 store = gtk_list_store_new(AC_COUNT, G_TYPE_POINTER, G_TYPE_BOOLEAN,
1842 G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING,
1843 G_TYPE_POINTER);
1844 for(i = 0; i < mailer->account_cnt; i++)
1845 {
1846 ac = mailer->account[i];
1847 gtk_list_store_append(store, &iter);
1848 gtk_list_store_set(store, &iter, AC_DATA, ac, AC_ACTIVE, TRUE,
1849 AC_ENABLED, account_get_enabled(ac),
1850 AC_TITLE, account_get_title(ac),
1851 AC_TYPE, account_get_type(ac), -1);
1852 }
1853 mailer->pr_accounts = gtk_tree_view_new_with_model(GTK_TREE_MODEL(
1854 store));
1855 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(mailer->pr_accounts),
1856 TRUE);
1857 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(mailer->pr_accounts),
1858 FALSE);
1859 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(mailer->pr_accounts), TRUE);
1860 renderer = gtk_cell_renderer_toggle_new();
1861 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(
1862 _on_preferences_account_toggle), store);
1863 gtk_tree_view_append_column(GTK_TREE_VIEW(mailer->pr_accounts),
1864 gtk_tree_view_column_new_with_attributes(_("Enabled"),
1865 renderer, "active", AC_ENABLED, NULL));
1866 renderer = gtk_cell_renderer_text_new();
1867 gtk_tree_view_append_column(GTK_TREE_VIEW(mailer->pr_accounts),
1868 gtk_tree_view_column_new_with_attributes(_("Name"),
1869 renderer, "text", AC_TITLE, NULL));
1870 renderer = gtk_cell_renderer_text_new();
1871 gtk_tree_view_append_column(GTK_TREE_VIEW(mailer->pr_accounts),
1872 gtk_tree_view_column_new_with_attributes(_("Type"),
1873 renderer, "text", AC_TYPE, NULL));
1874 gtk_container_add(GTK_CONTAINER(widget), mailer->pr_accounts);
1875 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
1876 vbox3 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
1877 /* new account */
1878 widget = gtk_button_new_from_stock(GTK_STOCK_NEW);
1879 g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(
1880 _on_preferences_account_new), mailer);
1881 gtk_box_pack_start(GTK_BOX(vbox3), widget, FALSE, TRUE, 0);
1882 /* edit account */
1883 #if GTK_CHECK_VERSION(2, 6, 0)
1884 widget = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1885 #else
1886 widget = gtk_button_new_with_mnemonic("_Edit");
1887 #endif
1888 g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(
1889 _on_preferences_account_edit), mailer);
1890 gtk_box_pack_start(GTK_BOX(vbox3), widget, FALSE, TRUE, 0);
1891 /* delete account */
1892 widget = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1893 g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(
1894 _on_preferences_account_delete), mailer);
1895 gtk_box_pack_start(GTK_BOX(vbox3), widget, FALSE, TRUE, 0);
1896 /* move up */
1897 widget = gtk_button_new_from_stock(GTK_STOCK_GO_UP);
1898 g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(
1899 _on_preferences_account_move_up), mailer);
1900 gtk_box_pack_start(GTK_BOX(vbox3), widget, FALSE, TRUE, 0);
1901 /* move down */
1902 widget = gtk_button_new_from_stock(GTK_STOCK_GO_DOWN);
1903 g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(
1904 _on_preferences_account_move_down), mailer);
1905 gtk_box_pack_start(GTK_BOX(vbox3), widget, FALSE, TRUE, 0);
1906 gtk_box_pack_start(GTK_BOX(hbox), vbox3, FALSE, TRUE, 0);
1907 gtk_box_pack_start(GTK_BOX(vbox2), hbox, TRUE, TRUE, 0);
1908 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(
1909 _("Accounts")));
1910 }
1911
_preferences_display(Mailer * mailer,GtkWidget * notebook)1912 static void _preferences_display(Mailer * mailer, GtkWidget * notebook)
1913 {
1914 GtkSizeGroup * group;
1915 GtkWidget * vbox2;
1916 GtkWidget * hbox;
1917 GtkWidget * widget;
1918
1919 group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1920 vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
1921 gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4);
1922 /* default font */
1923 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
1924 widget = gtk_label_new(_("Messages font:"));
1925 #if GTK_CHECK_VERSION(3, 14, 0)
1926 g_object_set(widget, "halign", GTK_ALIGN_START, NULL);
1927 #else
1928 gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
1929 #endif
1930 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0);
1931 mailer->pr_messages_font = gtk_font_button_new();
1932 widget = mailer->pr_messages_font;
1933 gtk_size_group_add_widget(group, widget);
1934 gtk_font_button_set_use_font(GTK_FONT_BUTTON(widget), TRUE);
1935 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
1936 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
1937 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(
1938 _("Display")));
1939 }
1940
_preferences_plugins(Mailer * mailer,GtkWidget * notebook)1941 static void _preferences_plugins(Mailer * mailer, GtkWidget * notebook)
1942 {
1943 GtkWidget * vbox;
1944 GtkWidget * widget;
1945 GtkCellRenderer * renderer;
1946 GtkTreeViewColumn * column;
1947
1948 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
1949 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
1950 widget = gtk_scrolled_window_new(NULL, NULL);
1951 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget),
1952 GTK_SHADOW_IN);
1953 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
1954 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1955 mailer->pr_plugins_store = gtk_list_store_new(4, G_TYPE_STRING,
1956 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_STRING);
1957 mailer->pr_plugins = gtk_tree_view_new_with_model(GTK_TREE_MODEL(
1958 mailer->pr_plugins_store));
1959 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(mailer->pr_plugins),
1960 FALSE);
1961 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(mailer->pr_plugins), FALSE);
1962 renderer = gtk_cell_renderer_toggle_new();
1963 g_signal_connect(renderer, "toggled", G_CALLBACK(
1964 _preferences_on_plugin_toggled), mailer);
1965 column = gtk_tree_view_column_new_with_attributes(_("Enabled"),
1966 renderer, "active", 1, NULL);
1967 gtk_tree_view_append_column(GTK_TREE_VIEW(mailer->pr_plugins), column);
1968 column = gtk_tree_view_column_new_with_attributes(NULL,
1969 gtk_cell_renderer_pixbuf_new(), "pixbuf", 2, NULL);
1970 gtk_tree_view_append_column(GTK_TREE_VIEW(mailer->pr_plugins), column);
1971 column = gtk_tree_view_column_new_with_attributes(_("Name"),
1972 gtk_cell_renderer_text_new(), "text", 3, NULL);
1973 gtk_tree_view_column_set_sort_column_id(column, 3);
1974 gtk_tree_view_append_column(GTK_TREE_VIEW(mailer->pr_plugins), column);
1975 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
1976 mailer->pr_plugins_store), 3,
1977 GTK_SORT_ASCENDING);
1978 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(mailer->pr_plugins), TRUE);
1979 gtk_container_add(GTK_CONTAINER(widget), mailer->pr_plugins);
1980 gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0);
1981 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, gtk_label_new(
1982 _("Plug-ins")));
1983 }
1984
_preferences_set(Mailer * mailer)1985 static void _preferences_set(Mailer * mailer)
1986 {
1987 char const * p;
1988
1989 p = _mailer_get_font(mailer);
1990 gtk_font_button_set_font_name(GTK_FONT_BUTTON(mailer->pr_messages_font),
1991 p);
1992 _preferences_set_plugins(mailer);
1993 }
1994
_preferences_set_plugins(Mailer * mailer)1995 static void _preferences_set_plugins(Mailer * mailer)
1996 {
1997 DIR * dir;
1998 struct dirent * de;
1999 GtkIconTheme * theme;
2000 #ifdef __APPLE__
2001 char const ext[] = ".dylib";
2002 #else
2003 char const ext[] = ".so";
2004 #endif
2005 size_t len;
2006 Plugin * p;
2007 MailerPluginDefinition * mpd;
2008 GtkTreeIter iter;
2009 gboolean enabled;
2010 GdkPixbuf * icon;
2011
2012 gtk_list_store_clear(mailer->pr_plugins_store);
2013 if((dir = opendir(LIBDIR "/" PACKAGE "/plugins")) == NULL)
2014 return;
2015 theme = gtk_icon_theme_get_default();
2016 while((de = readdir(dir)) != NULL)
2017 {
2018 if((len = strlen(de->d_name)) < sizeof(ext))
2019 continue;
2020 if(strcmp(&de->d_name[len - sizeof(ext) + 1], ext) != 0)
2021 continue;
2022 de->d_name[len - sizeof(ext) + 1] = '\0';
2023 #ifdef DEBUG
2024 fprintf(stderr, "DEBUG: %s() \"%s\"\n", __func__, de->d_name);
2025 #endif
2026 if((p = plugin_new(LIBDIR, PACKAGE, "plugins", de->d_name))
2027 == NULL)
2028 continue;
2029 if((mpd = plugin_lookup(p, "plugin")) == NULL)
2030 {
2031 plugin_delete(p);
2032 continue;
2033 }
2034 enabled = _mailer_plugin_is_enabled(mailer, de->d_name);
2035 icon = (mpd->icon != NULL) ? gtk_icon_theme_load_icon(theme,
2036 mpd->icon, 24, 0, NULL) : NULL;
2037 if(icon == NULL)
2038 icon = gtk_icon_theme_load_icon(theme, "gnome-settings",
2039 24, 0, NULL);
2040 gtk_list_store_append(mailer->pr_plugins_store, &iter);
2041 gtk_list_store_set(mailer->pr_plugins_store, &iter,
2042 MPC_NAME, de->d_name, MPC_ENABLED, enabled,
2043 MPC_ICON, icon, MPC_NAME_DISPLAY, mpd->name,
2044 -1);
2045 plugin_delete(p);
2046 }
2047 closedir(dir);
2048 }
2049
_on_preferences_closex(gpointer data)2050 static gboolean _on_preferences_closex(gpointer data)
2051 {
2052 Mailer * mailer = data;
2053
2054 gtk_widget_hide(mailer->pr_window);
2055 return TRUE;
2056 }
2057
_on_preferences_response(GtkWidget * widget,gint response,gpointer data)2058 static void _on_preferences_response(GtkWidget * widget, gint response,
2059 gpointer data)
2060 {
2061 Mailer * mailer = data;
2062
2063 gtk_widget_hide(widget);
2064 if(response == GTK_RESPONSE_OK)
2065 _on_preferences_ok(mailer);
2066 else if(response == GTK_RESPONSE_CANCEL)
2067 _on_preferences_cancel(mailer);
2068 }
2069
2070
2071 /* _on_preferences_account_new */
2072 /* types */
2073 typedef struct _AccountData
2074 {
2075 Mailer * mailer;
2076 char * title;
2077 AccountIdentity identity;
2078 unsigned int available;
2079 Account * account;
2080 GtkWidget * assistant;
2081 GtkWidget * settings;
2082 GtkWidget * confirm;
2083 } AccountData;
2084
2085 /* functions */
2086 static GtkWidget * _assistant_account_select(AccountData * ad);
2087 static GtkWidget * _assistant_account_config(AccountConfig * config);
2088
2089 #if !GTK_CHECK_VERSION(2, 10, 0)
2090 # include "gtkassistant.c"
2091 #endif
2092 static void _on_assistant_cancel(GtkWidget * widget, gpointer data);
2093 static void _on_assistant_close(GtkWidget * widget, gpointer data);
2094 static void _on_assistant_apply(gpointer data);
2095 static void _on_assistant_prepare(GtkWidget * widget, GtkWidget * page,
2096 gpointer data);
2097 static void _on_entry_changed(GtkWidget * widget, gpointer data);
2098 static void _on_account_type_changed(GtkWidget * widget, gpointer data);
2099
_on_preferences_account_new(gpointer data)2100 static void _on_preferences_account_new(gpointer data)
2101 {
2102 Mailer * mailer = data;
2103 AccountData * ad;
2104 GtkAssistant * assistant;
2105 GtkWidget * page;
2106
2107 if(mailer->available_cnt == 0)
2108 {
2109 mailer_error(mailer, _("No account plug-in available"), 0);
2110 return;
2111 }
2112 if((ad = malloc(sizeof(*ad))) == NULL)
2113 {
2114 mailer_error(mailer, strerror(errno), 0);
2115 return;
2116 }
2117 ad->mailer = mailer;
2118 ad->title = strdup("");
2119 memset(&(ad->identity), 0, sizeof(ad->identity));
2120 ad->available = 0;
2121 ad->account = NULL;
2122 ad->assistant = gtk_assistant_new();
2123 assistant = GTK_ASSISTANT(ad->assistant);
2124 g_signal_connect(G_OBJECT(ad->assistant), "cancel", G_CALLBACK(
2125 _on_assistant_cancel), ad);
2126 g_signal_connect(G_OBJECT(ad->assistant), "close", G_CALLBACK(
2127 _on_assistant_close), ad);
2128 g_signal_connect_swapped(G_OBJECT(ad->assistant), "apply", G_CALLBACK(
2129 _on_assistant_apply), ad);
2130 g_signal_connect(G_OBJECT(ad->assistant), "prepare", G_CALLBACK(
2131 _on_assistant_prepare), ad);
2132 /* plug-in selection */
2133 page = _assistant_account_select(ad);
2134 gtk_assistant_append_page(assistant, page);
2135 gtk_assistant_set_page_title(assistant, page, _(_title[0]));
2136 gtk_assistant_set_page_type(assistant, page, GTK_ASSISTANT_PAGE_INTRO);
2137 gtk_assistant_set_page_complete(assistant, page, FALSE);
2138 /* plug-in preferences */
2139 page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
2140 g_object_ref(page); /* XXX currently leaks memory */
2141 ad->settings = page;
2142 gtk_widget_show(page);
2143 gtk_assistant_append_page(assistant, page);
2144 gtk_assistant_set_page_title(assistant, page, _(_title[1]));
2145 gtk_assistant_set_page_type(assistant, page,
2146 GTK_ASSISTANT_PAGE_CONTENT);
2147 gtk_assistant_set_page_complete(assistant, page, TRUE);
2148 /* confirmation page */
2149 page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
2150 ad->confirm = page;
2151 gtk_widget_show(page);
2152 gtk_assistant_append_page(assistant, page);
2153 gtk_assistant_set_page_title(assistant, page, _(_title[2]));
2154 gtk_assistant_set_page_type(assistant, page,
2155 GTK_ASSISTANT_PAGE_CONFIRM);
2156 gtk_assistant_set_page_complete(assistant, page, TRUE);
2157 gtk_widget_show(ad->assistant);
2158 }
2159
_on_assistant_cancel(GtkWidget * widget,gpointer data)2160 static void _on_assistant_cancel(GtkWidget * widget, gpointer data)
2161 {
2162 _on_assistant_close(widget, data);
2163 }
2164
_on_assistant_close(GtkWidget * widget,gpointer data)2165 static void _on_assistant_close(GtkWidget * widget, gpointer data)
2166 {
2167 AccountData * ad = data;
2168
2169 if(ad->account != NULL)
2170 account_delete(ad->account);
2171 free(ad);
2172 gtk_widget_destroy(widget);
2173 }
2174
_on_assistant_apply(gpointer data)2175 static void _on_assistant_apply(gpointer data)
2176 {
2177 AccountData * ad = data;
2178 GtkTreeModel * model;
2179 GtkTreeIter iter;
2180
2181 /* XXX check for errors */
2182 account_init(ad->account);
2183 model = gtk_tree_view_get_model(GTK_TREE_VIEW(ad->mailer->pr_accounts));
2184 gtk_list_store_append(GTK_LIST_STORE(model), &iter);
2185 #ifdef DEBUG
2186 fprintf(stderr, "%s%p%s%s%s%s\n", "AC_DATA ", (void *)ad->account,
2187 ", AC_ACTIVE FALSE, AC_ENABLED TRUE, AC_TITLE ",
2188 account_get_title(ad->account), ", AC_TYPE ",
2189 account_get_type(ad->account));
2190 #endif
2191 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
2192 AC_DATA, ad->account, AC_ACTIVE, FALSE,
2193 AC_ENABLED, TRUE,
2194 AC_TITLE, account_get_title(ad->account),
2195 AC_TYPE, account_get_type(ad->account), -1);
2196 ad->account = NULL;
2197 /* _on_assistant_close is then automatically called */
2198 }
2199
2200 /* on_assistant_prepare */
2201 static GtkWidget * _account_display(Account * account);
2202
_on_assistant_prepare(GtkWidget * widget,GtkWidget * page,gpointer data)2203 static void _on_assistant_prepare(GtkWidget * widget, GtkWidget * page,
2204 gpointer data)
2205 {
2206 static int old = 0;
2207 AccountData * ad = data;
2208 unsigned int i;
2209 Account * ac;
2210
2211 i = gtk_assistant_get_current_page(GTK_ASSISTANT(widget));
2212 gtk_window_set_title(GTK_WINDOW(widget), _(_title[i]));
2213 if(i == 1)
2214 {
2215 gtk_container_remove(GTK_CONTAINER(page), ad->settings);
2216 if(old == 0)
2217 {
2218 if(ad->account != NULL)
2219 account_delete(ad->account);
2220 ac = ad->mailer->available[ad->available];
2221 ad->account = account_new(ad->mailer,
2222 account_get_type(ac), ad->title, NULL);
2223 }
2224 if(ad->account == NULL)
2225 {
2226 mailer_error(ad->mailer, error_get(NULL), 0);
2227 gtk_assistant_set_current_page(GTK_ASSISTANT(widget),
2228 0);
2229 ad->settings = _assistant_account_select(ad);
2230 }
2231 else
2232 ad->settings = _assistant_account_config(
2233 account_get_config(ad->account));
2234 gtk_container_add(GTK_CONTAINER(page), ad->settings);
2235 gtk_widget_show_all(ad->settings);
2236 }
2237 else if(i == 2)
2238 {
2239 gtk_container_remove(GTK_CONTAINER(page), ad->confirm);
2240 ad->confirm = _account_display(ad->account);
2241 gtk_container_add(GTK_CONTAINER(page), ad->confirm);
2242 }
2243 old = i;
2244 }
2245
2246 /* _assistant_account_select */
2247 static void _on_account_name_changed(GtkWidget * widget, gpointer data);
2248 static void _account_add_label(GtkWidget * box, PangoFontDescription * desc,
2249 GtkSizeGroup * group, char const * text);
2250
_assistant_account_select(AccountData * ad)2251 static GtkWidget * _assistant_account_select(AccountData * ad)
2252 {
2253 GtkWidget * vbox;
2254 GtkWidget * hbox;
2255 GtkSizeGroup * group;
2256 PangoFontDescription * desc;
2257 GtkWidget * widget;
2258 unsigned int i;
2259
2260 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
2261 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
2262 group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
2263 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
2264 desc = pango_font_description_new();
2265 pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
2266 _account_add_label(hbox, desc, group, _("Account name"));
2267 widget = gtk_entry_new();
2268 g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(
2269 _on_account_name_changed), ad);
2270 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2271 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
2272 /* default identity */
2273 /* FIXME seems to not be remembered */
2274 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
2275 _account_add_label(hbox, NULL, group, _("Your name"));
2276 widget = gtk_entry_new();
2277 g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(
2278 _on_entry_changed), &(ad->identity.from));
2279 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2280 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
2281 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
2282 _account_add_label(hbox, NULL, group, _("e-mail address"));
2283 widget = gtk_entry_new();
2284 g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(
2285 _on_entry_changed), &(ad->identity.email));
2286 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2287 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
2288 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
2289 _account_add_label(hbox, NULL, group, _("Type of account"));
2290 #if GTK_CHECK_VERSION(2, 24, 0)
2291 widget = gtk_combo_box_text_new();
2292 #else
2293 widget = gtk_combo_box_new_text();
2294 #endif
2295 /* XXX this works because there is no plug-in list reload
2296 * would it be implemented this will need validation later */
2297 for(i = 0; i < ad->mailer->available_cnt; i++)
2298 #if GTK_CHECK_VERSION(2, 24, 0)
2299 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(widget),
2300 account_get_name(ad->mailer->available[i]));
2301 #else
2302 gtk_combo_box_append_text(GTK_COMBO_BOX(widget),
2303 account_get_name(ad->mailer->available[i]));
2304 #endif
2305 gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 0);
2306 g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(
2307 _on_account_type_changed), ad);
2308 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2309 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
2310 pango_font_description_free(desc);
2311 gtk_widget_show_all(vbox);
2312 return vbox;
2313 }
2314
_on_account_name_changed(GtkWidget * widget,gpointer data)2315 static void _on_account_name_changed(GtkWidget * widget, gpointer data)
2316 {
2317 AccountData * ad = data;
2318 int current;
2319 GtkWidget * page;
2320
2321 _on_entry_changed(widget, &ad->title);
2322 current = gtk_assistant_get_current_page(GTK_ASSISTANT(ad->assistant));
2323 page = gtk_assistant_get_nth_page(GTK_ASSISTANT(ad->assistant),
2324 current);
2325 gtk_assistant_set_page_complete(GTK_ASSISTANT(ad->assistant), page,
2326 strlen(ad->title) ? TRUE : FALSE);
2327 }
2328
_account_add_label(GtkWidget * box,PangoFontDescription * desc,GtkSizeGroup * group,char const * text)2329 static void _account_add_label(GtkWidget * box, PangoFontDescription * desc,
2330 GtkSizeGroup * group, char const * text)
2331 {
2332 static char buf[80]; /* XXX hard-coded size */
2333 GtkWidget * label;
2334
2335 snprintf(buf, sizeof(buf), "%s:", text);
2336 label = gtk_label_new(buf);
2337 if(desc != NULL)
2338 gtk_widget_override_font(label, desc);
2339 if(group != NULL)
2340 gtk_size_group_add_widget(group, label);
2341 #if GTK_CHECK_VERSION(3, 14, 0)
2342 g_object_set(label, "halign", GTK_ALIGN_START, NULL);
2343 #else
2344 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2345 #endif
2346 gtk_box_pack_start(GTK_BOX(box), label, FALSE, TRUE, 0);
2347 }
2348
2349 /* _assistant_account_config */
2350 static GtkWidget * _update_string(AccountConfig * config,
2351 PangoFontDescription * desc, GtkSizeGroup * group);
2352 static GtkWidget * _update_password(AccountConfig * config,
2353 PangoFontDescription * desc, GtkSizeGroup * group);
2354 static GtkWidget * _update_file(AccountConfig * config,
2355 PangoFontDescription * desc, GtkSizeGroup * group);
2356 static GtkWidget * _update_uint16(AccountConfig * config,
2357 PangoFontDescription * desc, GtkSizeGroup * group);
2358 static GtkWidget * _update_boolean(AccountConfig * config);
2359
_assistant_account_config(AccountConfig * config)2360 static GtkWidget * _assistant_account_config(AccountConfig * config)
2361 {
2362 GtkWidget * vbox;
2363 GtkSizeGroup * group;
2364 GtkWidget * widget;
2365 size_t i;
2366
2367 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
2368 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
2369 group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
2370 for(i = 0; config != NULL && config[i].type != ACT_NONE; i++)
2371 {
2372 switch(config[i].type)
2373 {
2374 case ACT_STRING:
2375 widget = _update_string(&config[i], NULL,
2376 group);
2377 break;
2378 case ACT_PASSWORD:
2379 widget = _update_password(&config[i], NULL,
2380 group);
2381 break;
2382 case ACT_FILE:
2383 widget = _update_file(&config[i], NULL, group);
2384 break;
2385 case ACT_UINT16:
2386 widget = _update_uint16(&config[i], NULL,
2387 group);
2388 break;
2389 case ACT_BOOLEAN:
2390 widget = _update_boolean(&config[i]);
2391 break;
2392 case ACT_SEPARATOR:
2393 widget = gtk_separator_new(
2394 GTK_ORIENTATION_HORIZONTAL);
2395 break;
2396 default: /* should not happen */
2397 assert(0);
2398 continue;
2399 }
2400 gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
2401 }
2402 return vbox;
2403 }
2404
_update_string(AccountConfig * config,PangoFontDescription * desc,GtkSizeGroup * group)2405 static GtkWidget * _update_string(AccountConfig * config,
2406 PangoFontDescription * desc, GtkSizeGroup * group)
2407 {
2408 GtkWidget * hbox;
2409 GtkWidget * widget;
2410
2411 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2412 _account_add_label(hbox, desc, group, config->title);
2413 widget = gtk_entry_new();
2414 if(config->value != NULL)
2415 gtk_entry_set_text(GTK_ENTRY(widget), config->value);
2416 g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(
2417 _on_entry_changed), &config->value);
2418 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2419 return hbox;
2420 }
2421
_update_password(AccountConfig * config,PangoFontDescription * desc,GtkSizeGroup * group)2422 static GtkWidget * _update_password(AccountConfig * config,
2423 PangoFontDescription * desc, GtkSizeGroup * group)
2424 {
2425 GtkWidget * hbox;
2426 GtkWidget * widget;
2427
2428 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2429 _account_add_label(hbox, desc, group, config->title);
2430 widget = gtk_entry_new();
2431 gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);
2432 if(config->value != NULL)
2433 gtk_entry_set_text(GTK_ENTRY(widget), config->value);
2434 g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(
2435 _on_entry_changed), &config->value);
2436 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2437 return hbox;
2438 }
2439
2440 static void _on_file_activated(GtkWidget * widget, gpointer data);
2441
_update_file(AccountConfig * config,PangoFontDescription * desc,GtkSizeGroup * group)2442 static GtkWidget * _update_file(AccountConfig * config,
2443 PangoFontDescription * desc, GtkSizeGroup * group)
2444 {
2445 GtkWidget * hbox;
2446 GtkWidget * widget;
2447
2448 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2449 _account_add_label(hbox, desc, group, config->title);
2450 widget = gtk_file_chooser_button_new(_("Choose file"),
2451 GTK_FILE_CHOOSER_ACTION_OPEN);
2452 if(config->value != NULL)
2453 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(widget),
2454 config->value);
2455 gtk_file_chooser_button_set_title(GTK_FILE_CHOOSER_BUTTON(widget),
2456 config->title);
2457 g_signal_connect(G_OBJECT(widget), "file-set", G_CALLBACK(
2458 _on_file_activated), &config->value);
2459 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2460 return hbox;
2461 }
2462
_on_file_activated(GtkWidget * widget,gpointer data)2463 static void _on_file_activated(GtkWidget * widget, gpointer data)
2464 {
2465 char * filename;
2466 char ** value = data;
2467 char * p = NULL;
2468
2469 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
2470 #ifdef DEBUG
2471 fprintf(stderr, "DEBUG: %s(%s)\n", __func__, filename);
2472 #endif
2473 if(filename == NULL)
2474 free(*value);
2475 else if((p = realloc(*value, strlen(filename) + 1)) == NULL)
2476 {
2477 mailer_error(NULL, strerror(errno), 0);
2478 return;
2479 }
2480 *value = p;
2481 if(filename != NULL)
2482 strcpy(p, filename);
2483 }
2484
2485 static void _on_uint16_changed(GtkWidget * widget, gpointer data);
2486
_update_uint16(AccountConfig * config,PangoFontDescription * desc,GtkSizeGroup * group)2487 static GtkWidget * _update_uint16(AccountConfig * config,
2488 PangoFontDescription * desc, GtkSizeGroup * group)
2489 {
2490 GtkWidget * hbox;
2491 GtkWidget * widget;
2492 uint16_t u16 = (intptr_t)(config->value);
2493 gdouble value = u16;
2494
2495 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2496 _account_add_label(hbox, desc, group, config->title);
2497 widget = gtk_spin_button_new_with_range(0, 65535, 1);
2498 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(widget), 0);
2499 gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), value);
2500 g_signal_connect(G_OBJECT(widget), "value-changed", G_CALLBACK(
2501 _on_uint16_changed), &config->value);
2502 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2503 return hbox;
2504 }
2505
_on_uint16_changed(GtkWidget * widget,gpointer data)2506 static void _on_uint16_changed(GtkWidget * widget, gpointer data)
2507 {
2508 int * value = data;
2509
2510 *value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
2511 #ifdef DEBUG
2512 fprintf(stderr, "DEBUG: new value is %d\n", *value);
2513 #endif
2514 }
2515
2516 static void _on_boolean_toggled(GtkWidget * widget, gpointer data);
_update_boolean(AccountConfig * config)2517 static GtkWidget * _update_boolean(AccountConfig * config)
2518 {
2519 GtkWidget * widget;
2520
2521 widget = gtk_check_button_new_with_label(config->title);
2522 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
2523 config->value != NULL);
2524 g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(
2525 _on_boolean_toggled), &config->value);
2526 return widget;
2527 }
2528
_on_boolean_toggled(GtkWidget * widget,gpointer data)2529 static void _on_boolean_toggled(GtkWidget * widget, gpointer data)
2530 {
2531 int * value = data;
2532
2533 *value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
2534 }
2535
2536 static GtkWidget * _display_string(AccountConfig * config,
2537 PangoFontDescription * desc, GtkSizeGroup * group);
2538 static GtkWidget * _display_password(AccountConfig * config,
2539 PangoFontDescription * desc, GtkSizeGroup * group);
2540 static GtkWidget * _display_file(AccountConfig * config,
2541 PangoFontDescription * desc, GtkSizeGroup * group);
2542 static GtkWidget * _display_uint16(AccountConfig * config,
2543 PangoFontDescription * desc, GtkSizeGroup * group);
2544 static GtkWidget * _display_boolean(AccountConfig * config,
2545 PangoFontDescription * desc, GtkSizeGroup * group);
_account_display(Account * account)2546 static GtkWidget * _account_display(Account * account)
2547 {
2548 AccountConfig * config;
2549 AccountConfig p;
2550 GtkWidget * vbox;
2551 GtkSizeGroup * group;
2552 PangoFontDescription * desc;
2553 GtkWidget * widget;
2554 unsigned int i;
2555
2556 config = account_get_config(account);
2557 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
2558 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
2559 group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
2560 p.name = NULL;
2561 p.title = _("Account name");
2562 p.value = (void *)account_get_title(account);
2563 desc = pango_font_description_new();
2564 pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
2565 widget = _display_string(&p, desc, group);
2566 gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
2567 for(i = 0; config[i].type != ACT_NONE; i++)
2568 {
2569 switch(config[i].type)
2570 {
2571 case ACT_STRING:
2572 widget = _display_string(&config[i], desc,
2573 group);
2574 break;
2575 case ACT_PASSWORD:
2576 widget = _display_password(&config[i], desc,
2577 group);
2578 break;
2579 case ACT_FILE:
2580 widget = _display_file(&config[i], desc, group);
2581 break;
2582 case ACT_UINT16:
2583 widget = _display_uint16(&config[i], desc,
2584 group);
2585 break;
2586 case ACT_BOOLEAN:
2587 widget = _display_boolean(&config[i], desc,
2588 group);
2589 break;
2590 case ACT_SEPARATOR:
2591 widget = gtk_separator_new(
2592 GTK_ORIENTATION_HORIZONTAL);
2593 break;
2594 default: /* should not happen */
2595 assert(0);
2596 continue;
2597 }
2598 gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
2599 }
2600 pango_font_description_free(desc);
2601 gtk_widget_show_all(vbox);
2602 return vbox;
2603 }
2604
_display_string(AccountConfig * config,PangoFontDescription * desc,GtkSizeGroup * group)2605 static GtkWidget * _display_string(AccountConfig * config,
2606 PangoFontDescription * desc, GtkSizeGroup * group)
2607 {
2608 GtkWidget * hbox;
2609 GtkWidget * widget;
2610
2611 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2612 _account_add_label(hbox, desc, group, config->title);
2613 widget = gtk_label_new(config->value);
2614 #if GTK_CHECK_VERSION(3, 14, 0)
2615 g_object_set(widget, "halign", GTK_ALIGN_START, NULL);
2616 #else
2617 gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
2618 #endif
2619 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2620 return hbox;
2621 }
2622
_display_file(AccountConfig * config,PangoFontDescription * desc,GtkSizeGroup * group)2623 static GtkWidget * _display_file(AccountConfig * config,
2624 PangoFontDescription * desc, GtkSizeGroup * group)
2625 {
2626 return _display_string(config, desc, group);
2627 }
2628
_display_password(AccountConfig * config,PangoFontDescription * desc,GtkSizeGroup * group)2629 static GtkWidget * _display_password(AccountConfig * config,
2630 PangoFontDescription * desc, GtkSizeGroup * group)
2631 {
2632 GtkWidget * hbox;
2633 GtkWidget * widget;
2634
2635 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2636 _account_add_label(hbox, desc, group, config->title);
2637 widget = gtk_label_new(_("hidden"));
2638 desc = pango_font_description_new();
2639 pango_font_description_set_style(desc, PANGO_STYLE_ITALIC);
2640 gtk_widget_override_font(widget, desc);
2641 #if GTK_CHECK_VERSION(3, 14, 0)
2642 g_object_set(widget, "halign", GTK_ALIGN_START, NULL);
2643 #else
2644 gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
2645 #endif
2646 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2647 return hbox;
2648 }
2649
_display_uint16(AccountConfig * config,PangoFontDescription * desc,GtkSizeGroup * group)2650 static GtkWidget * _display_uint16(AccountConfig * config,
2651 PangoFontDescription * desc, GtkSizeGroup * group)
2652 {
2653 GtkWidget * hbox;
2654 GtkWidget * widget;
2655 char buf[6];
2656 uint16_t u16 = (intptr_t)config->value;
2657
2658 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2659 _account_add_label(hbox, desc, group, config->title);
2660 snprintf(buf, sizeof(buf), "%hu", u16);
2661 widget = gtk_label_new(buf);
2662 #if GTK_CHECK_VERSION(3, 14, 0)
2663 g_object_set(widget, "halign", GTK_ALIGN_START, NULL);
2664 #else
2665 gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
2666 #endif
2667 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2668 return hbox;
2669 }
2670
_display_boolean(AccountConfig * config,PangoFontDescription * desc,GtkSizeGroup * group)2671 static GtkWidget * _display_boolean(AccountConfig * config,
2672 PangoFontDescription * desc, GtkSizeGroup * group)
2673 {
2674 GtkWidget * hbox;
2675 GtkWidget * widget;
2676
2677 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2678 _account_add_label(hbox, desc, group, config->title);
2679 widget = gtk_label_new(config->value != 0 ? _("Yes") : _("No"));
2680 #if GTK_CHECK_VERSION(3, 14, 0)
2681 g_object_set(widget, "halign", GTK_ALIGN_START, NULL);
2682 #else
2683 gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
2684 #endif
2685 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2686 return hbox;
2687 }
2688
_on_entry_changed(GtkWidget * widget,gpointer data)2689 static void _on_entry_changed(GtkWidget * widget, gpointer data)
2690 {
2691 const char * text;
2692 char ** value = data;
2693 char * p;
2694
2695 text = gtk_entry_get_text(GTK_ENTRY(widget));
2696 if((p = realloc(*value, strlen(text) + 1)) == NULL)
2697 {
2698 mailer_error(NULL, strerror(errno), 0);
2699 return;
2700 }
2701 *value = p;
2702 strcpy(p, text);
2703 }
2704
_on_account_type_changed(GtkWidget * widget,gpointer data)2705 static void _on_account_type_changed(GtkWidget * widget, gpointer data)
2706 {
2707 AccountData * ad = data;
2708
2709 ad->available = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
2710 #ifdef DEBUG
2711 fprintf(stderr, "%s%u%s", _("Account type "), ad->available,
2712 _(" active\n"));
2713 #endif
2714 }
2715
_on_preferences_account_toggle(GtkCellRendererToggle * renderer,char * path,gpointer data)2716 static void _on_preferences_account_toggle(GtkCellRendererToggle * renderer,
2717 char * path, gpointer data)
2718 {
2719 GtkListStore * store = data;
2720 GtkTreeIter iter;
2721
2722 gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, path);
2723 gtk_list_store_set(store, &iter, AC_ENABLED,
2724 !gtk_cell_renderer_toggle_get_active(renderer), -1);
2725 }
2726
2727 /* _on_preferences_account_edit */
2728 static GtkWidget * _account_edit(Mailer * mailer, Account * account);
2729 static gboolean _account_edit_on_closex(GtkWidget * widget, GdkEvent * event,
2730 gpointer data);
2731 static void _account_edit_on_response(GtkWidget * widget, gint response,
2732 gpointer data);
2733
_on_preferences_account_edit(gpointer data)2734 static void _on_preferences_account_edit(gpointer data)
2735 {
2736 Mailer * mailer = data;
2737 GtkTreeSelection * selection;
2738 GtkTreeModel * model;
2739 GtkTreeIter iter;
2740 Account * account;
2741 GtkWidget * widget;
2742
2743 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
2744 mailer->pr_accounts));
2745 if(gtk_tree_selection_get_selected(selection, &model, &iter) != TRUE)
2746 return;
2747 gtk_tree_model_get(model, &iter, AC_DATA, &account, AC_WIDGET, &widget,
2748 -1);
2749 if(widget != NULL)
2750 {
2751 gtk_window_present(GTK_WINDOW(widget));
2752 return;
2753 }
2754 widget = _account_edit(mailer, account);
2755 gtk_list_store_set(GTK_LIST_STORE(model), &iter, AC_WIDGET, widget, -1);
2756 }
2757
_account_edit(Mailer * mailer,Account * account)2758 static GtkWidget * _account_edit(Mailer * mailer, Account * account)
2759 {
2760 char const * title;
2761 char const * p;
2762 GtkWidget * window;
2763 char buf[80];
2764 GtkWidget * content;
2765 GtkWidget * notebook;
2766 GtkWidget * vbox;
2767 GtkWidget * frame;
2768 GtkWidget * vbox2;
2769 GtkWidget * widget;
2770 GtkWidget * hbox;
2771 GtkSizeGroup * group;
2772
2773 title = account_get_title(account);
2774 snprintf(buf, sizeof(buf), "%s%s", _("Edit account: "), title);
2775 window = gtk_dialog_new_with_buttons(buf, GTK_WINDOW(mailer->pr_window),
2776 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL,
2777 GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK,
2778 NULL);
2779 g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK(
2780 _account_edit_on_closex), NULL);
2781 g_signal_connect(G_OBJECT(window), "response", G_CALLBACK(
2782 _account_edit_on_response), NULL);
2783 #if GTK_CHECK_VERSION(2, 14, 0)
2784 content = gtk_dialog_get_content_area(GTK_DIALOG(window));
2785 #else
2786 content = GTK_DIALOG(window)->vbox;
2787 #endif
2788 gtk_container_set_border_width(GTK_CONTAINER(content), 4);
2789 notebook = gtk_notebook_new();
2790 group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
2791 /* account tab */
2792 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
2793 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
2794 /* account name */
2795 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
2796 widget = gtk_label_new(_("Account name:"));
2797 #if GTK_CHECK_VERSION(3, 14, 0)
2798 g_object_set(widget, "halign", GTK_ALIGN_START, NULL);
2799 #else
2800 gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
2801 #endif
2802 gtk_size_group_add_widget(group, widget);
2803 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0);
2804 widget = gtk_entry_new();
2805 gtk_entry_set_text(GTK_ENTRY(widget), title);
2806 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2807 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
2808 /* identity */
2809 frame = gtk_frame_new(_("Identity:"));
2810 vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
2811 gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4);
2812 /* identity: name */
2813 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
2814 widget = gtk_label_new(_("Name:"));
2815 #if GTK_CHECK_VERSION(3, 14, 0)
2816 g_object_set(widget, "halign", GTK_ALIGN_START, NULL);
2817 #else
2818 gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
2819 #endif
2820 gtk_size_group_add_widget(group, widget);
2821 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0);
2822 widget = gtk_entry_new();
2823 if((p = config_get(mailer->config, title, "identity_name")) != NULL)
2824 gtk_entry_set_text(GTK_ENTRY(widget), p);
2825 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2826 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, TRUE, 0);
2827 /* identity: address */
2828 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
2829 widget = gtk_label_new(_("Address:"));
2830 #if GTK_CHECK_VERSION(3, 14, 0)
2831 g_object_set(widget, "halign", GTK_ALIGN_START, NULL);
2832 #else
2833 gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
2834 #endif
2835 gtk_size_group_add_widget(group, widget);
2836 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0);
2837 widget = gtk_entry_new();
2838 if((p = config_get(mailer->config, title, "identity_email")) != NULL)
2839 gtk_entry_set_text(GTK_ENTRY(widget), p);
2840 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2841 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, TRUE, 0);
2842 /* identity: organization */
2843 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
2844 widget = gtk_label_new(_("Organization:"));
2845 #if GTK_CHECK_VERSION(3, 14, 0)
2846 g_object_set(widget, "halign", GTK_ALIGN_START, NULL);
2847 #else
2848 gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
2849 #endif
2850 gtk_size_group_add_widget(group, widget);
2851 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0);
2852 widget = gtk_entry_new();
2853 if((p = config_get(mailer->config, title, "identity_organization"))
2854 != NULL)
2855 gtk_entry_set_text(GTK_ENTRY(widget), p);
2856 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
2857 gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, TRUE, 0);
2858 gtk_container_add(GTK_CONTAINER(frame), vbox2);
2859 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, TRUE, 0);
2860 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, gtk_label_new(
2861 _("Account")));
2862 /* settings tab */
2863 /* FIXME this affects the account directly (eg cancel does not work) */
2864 widget = _assistant_account_config(account_get_config(account));
2865 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), widget, gtk_label_new(
2866 _("Settings")));
2867 gtk_box_pack_start(GTK_BOX(content), notebook, TRUE, TRUE, 0);
2868 gtk_widget_show_all(window);
2869 return window;
2870 }
2871
_account_edit_on_closex(GtkWidget * widget,GdkEvent * event,gpointer data)2872 static gboolean _account_edit_on_closex(GtkWidget * widget, GdkEvent * event,
2873 gpointer data)
2874 {
2875 _account_edit_on_response(widget, GTK_RESPONSE_CANCEL, data);
2876 return TRUE;
2877 }
2878
_account_edit_on_response(GtkWidget * widget,gint response,gpointer data)2879 static void _account_edit_on_response(GtkWidget * widget, gint response,
2880 gpointer data)
2881 {
2882 /* FIXME really implement */
2883 gtk_widget_hide(widget);
2884 }
2885
_on_preferences_account_delete(gpointer data)2886 static void _on_preferences_account_delete(gpointer data)
2887 {
2888 Mailer * mailer = data;
2889 GtkTreePath * path;
2890 GtkTreeModel * model;
2891 GtkTreeIter iter;
2892
2893 gtk_tree_view_get_cursor(GTK_TREE_VIEW(mailer->pr_accounts), &path,
2894 NULL);
2895 if(path == NULL)
2896 return;
2897 model = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->pr_accounts));
2898 gtk_tree_model_get_iter(model, &iter, path);
2899 gtk_tree_path_free(path);
2900 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
2901 /* FIXME non-interface code (flag account as deleted and on ok apply) */
2902 }
2903
_on_preferences_account_move_down(gpointer data)2904 static void _on_preferences_account_move_down(gpointer data)
2905 {
2906 Mailer * mailer = data;
2907 GtkTreeModel * model;
2908 GtkTreeIter iter;
2909 GtkTreeIter iter2;
2910 GtkTreeSelection * treesel;
2911
2912 treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(
2913 mailer->pr_accounts));
2914 if(!gtk_tree_selection_get_selected(treesel, &model, &iter))
2915 return;
2916 iter2 = iter;
2917 if(!gtk_tree_model_iter_next(model, &iter))
2918 return;
2919 gtk_list_store_swap(GTK_LIST_STORE(model), &iter, &iter2);
2920 }
2921
_on_preferences_account_move_up(gpointer data)2922 static void _on_preferences_account_move_up(gpointer data)
2923 {
2924 Mailer * mailer = data;
2925 GtkTreeModel * model;
2926 GtkTreeIter iter;
2927 GtkTreeIter iter2;
2928 GtkTreePath * path;
2929 GtkTreeSelection * treesel;
2930
2931 treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(
2932 mailer->pr_accounts));
2933 if(!gtk_tree_selection_get_selected(treesel, &model, &iter))
2934 return;
2935 path = gtk_tree_model_get_path(model, &iter);
2936 gtk_tree_path_prev(path);
2937 gtk_tree_model_get_iter(model, &iter2, path);
2938 gtk_tree_path_free(path);
2939 gtk_list_store_swap(GTK_LIST_STORE(model), &iter, &iter2);
2940 }
2941
_on_preferences_cancel(gpointer data)2942 static void _on_preferences_cancel(gpointer data)
2943 {
2944 Mailer * mailer = data;
2945
2946 gtk_widget_hide(mailer->pr_window);
2947 _preferences_set(mailer);
2948 }
2949
_on_preferences_ok(gpointer data)2950 static void _on_preferences_ok(gpointer data)
2951 {
2952 Mailer * mailer = data;
2953
2954 mailer_show_preferences(mailer, FALSE);
2955 if(_preferences_ok_accounts(mailer) != 0
2956 || _preferences_ok_display(mailer) != 0
2957 || _preferences_ok_plugins(mailer) != 0
2958 || _preferences_ok_save(mailer) != 0)
2959 mailer_error(mailer, _("An error occured while saving"
2960 " preferences"), 0);
2961 }
2962
_preferences_ok_accounts(Mailer * mailer)2963 static int _preferences_ok_accounts(Mailer * mailer)
2964 {
2965 GtkTreeModel * model;
2966 GtkTreeIter iter;
2967 GtkTreeModel * view_model;
2968 gboolean loop;
2969 Account * account;
2970 gboolean active;
2971 gboolean enabled;
2972 char * title;
2973 size_t title_len;
2974 char * accounts = NULL;
2975 size_t accounts_len = 0;
2976 char * p;
2977
2978 model = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->pr_accounts));
2979 view_model = gtk_tree_view_get_model(GTK_TREE_VIEW(
2980 mailer->fo_view));
2981 for(loop = gtk_tree_model_get_iter_first(model, &iter); loop == TRUE;
2982 loop = gtk_tree_model_iter_next(model, &iter))
2983 {
2984 gtk_tree_model_get(model, &iter, AC_DATA, &account,
2985 AC_ACTIVE, &active, AC_ENABLED, &enabled,
2986 AC_TITLE, &title, -1);
2987 title_len = strlen(title);
2988 if(account_config_save(account, mailer->config) != 0)
2989 return 1;
2990 if((p = realloc(accounts, accounts_len + title_len + 2))
2991 == NULL)
2992 {
2993 free(accounts);
2994 return 1;
2995 }
2996 accounts = p;
2997 sprintf(&accounts[accounts_len], "%s%s", accounts_len ? ","
2998 : "", title);
2999 accounts_len += title_len + (accounts_len ? 1 : 0);
3000 if(active)
3001 {
3002 if(enabled)
3003 continue;
3004 #if 0 /* FIXME API+behaviour change here */
3005 if(mailer_account_disable(mailer, account) == 0)
3006 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
3007 AC_ACTIVE, FALSE, -1);
3008 #endif
3009 }
3010 else if(enabled && mailer_account_add(mailer, account) == 0)
3011 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
3012 AC_ACTIVE, TRUE, -1);
3013 }
3014 /* FIXME delete accounts that need to be */
3015 /* FIXME force a refresh of the ones remaining and not just added */
3016 #ifdef DEBUG
3017 fprintf(stderr, "DEBUG: saved accounts \"%s\"\n", accounts);
3018 #endif
3019 config_set(mailer->config, "", "accounts", accounts);
3020 free(accounts);
3021 return 0;
3022 }
3023
_preferences_ok_display(Mailer * mailer)3024 static int _preferences_ok_display(Mailer * mailer)
3025 {
3026 PangoFontDescription * font = NULL;
3027 char const * p;
3028
3029 p = gtk_font_button_get_font_name(GTK_FONT_BUTTON(
3030 mailer->pr_messages_font));
3031 config_set(mailer->config, "", "messages_font", p);
3032 if(p != NULL)
3033 font = pango_font_description_from_string(p);
3034 gtk_widget_override_font(mailer->bo_view, font);
3035 if(font != NULL)
3036 pango_font_description_free(font);
3037 return 0;
3038 }
3039
_preferences_ok_plugins(Mailer * mailer)3040 static int _preferences_ok_plugins(Mailer * mailer)
3041 {
3042 GtkTreeModel * model = GTK_TREE_MODEL(mailer->pr_plugins_store);
3043 GtkTreeIter iter;
3044 gboolean valid;
3045 gchar * p;
3046 gboolean enabled;
3047 String * value = string_new("");
3048 String * sep = "";
3049
3050 for(valid = gtk_tree_model_get_iter_first(model, &iter); valid == TRUE;
3051 valid = gtk_tree_model_iter_next(model, &iter))
3052 {
3053 gtk_tree_model_get(model, &iter, 0, &p, 1, &enabled, -1);
3054 if(enabled)
3055 {
3056 mailer_load(mailer, p);
3057 string_append(&value, sep);
3058 string_append(&value, p);
3059 sep = ",";
3060 }
3061 else if(_mailer_plugin_is_enabled(mailer, p))
3062 mailer_unload(mailer, p);
3063 g_free(p);
3064 }
3065 config_set(mailer->config, NULL, "plugins", value);
3066 string_delete(value);
3067 return 0;
3068 }
3069
_preferences_ok_save(Mailer * mailer)3070 static int _preferences_ok_save(Mailer * mailer)
3071 {
3072 int ret;
3073 char * p;
3074
3075 if((p = _mailer_get_config_filename()) == NULL)
3076 return 1;
3077 ret = config_save(mailer->config, p);
3078 free(p);
3079 return ret;
3080 }
3081
_preferences_on_plugin_toggled(GtkCellRendererToggle * renderer,char * path,gpointer data)3082 static void _preferences_on_plugin_toggled(GtkCellRendererToggle * renderer,
3083 char * path, gpointer data)
3084 {
3085 Mailer * mailer = data;
3086 GtkTreeIter iter;
3087
3088 gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(
3089 mailer->pr_plugins_store), &iter, path);
3090 gtk_list_store_set(mailer->pr_plugins_store, &iter, 1,
3091 !gtk_cell_renderer_toggle_get_active(renderer), -1);
3092 }
3093
3094
3095 /* mailer_unload */
mailer_unload(Mailer * mailer,char const * plugin)3096 int mailer_unload(Mailer * mailer, char const * plugin)
3097 {
3098 GtkTreeModel * model = GTK_TREE_MODEL(mailer->pl_store);
3099 GtkTreeIter iter;
3100 gboolean valid;
3101 gchar * p;
3102 Plugin * pp;
3103 MailerPluginDefinition * mpd;
3104 MailerPlugin * mp;
3105 gboolean enabled = FALSE;
3106
3107 /* XXX this code is duplicated with _mailer_plugin_is_enabled() */
3108 for(valid = gtk_tree_model_get_iter_first(model, &iter); valid == TRUE;
3109 valid = gtk_tree_model_iter_next(model, &iter))
3110 {
3111 gtk_tree_model_get(model, &iter, MPC_NAME, &p, MPC_PLUGIN, &pp,
3112 MPC_MAILERPLUGINDEFINITION, &mpd,
3113 MPC_MAILERPLUGIN, &mp, -1);
3114 enabled = (strcmp(p, plugin) == 0) ? TRUE : FALSE;
3115 g_free(p);
3116 if(enabled)
3117 break;
3118 }
3119 if(enabled != TRUE)
3120 return 0;
3121 gtk_list_store_remove(mailer->pl_store, &iter);
3122 if(mpd->destroy != NULL)
3123 mpd->destroy(mp);
3124 plugin_delete(pp);
3125 return 0;
3126 }
3127
3128
3129 /* mailer_unselect_all */
mailer_unselect_all(Mailer * mailer)3130 void mailer_unselect_all(Mailer * mailer)
3131 {
3132 GtkTreeSelection * treesel;
3133 #if GTK_CHECK_VERSION(2, 4, 0)
3134 GtkTextBuffer * tbuf;
3135 GtkTextMark * mark;
3136 GtkTextIter iter;
3137 #endif
3138
3139 if(gtk_window_get_focus(GTK_WINDOW(mailer->fo_window))
3140 == mailer->bo_view)
3141 {
3142 #if GTK_CHECK_VERSION(2, 4, 0)
3143 tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mailer->bo_view));
3144 mark = gtk_text_buffer_get_mark(tbuf, "insert");
3145 gtk_text_buffer_get_iter_at_mark(tbuf, &iter, mark);
3146 gtk_text_buffer_select_range(tbuf, &iter, &iter);
3147 #endif
3148 return;
3149 }
3150 treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(mailer->he_view));
3151 gtk_tree_selection_unselect_all(treesel);
3152 }
3153
3154
3155 /* private */
3156 /* functions */
3157 /* accessors */
3158 /* mailer_get_config_filename */
_mailer_get_config_filename(void)3159 static char * _mailer_get_config_filename(void)
3160 /* FIXME consider replacing with mailer_save_config() */
3161 {
3162 char const * homedir;
3163 char * filename;
3164
3165 if((homedir = getenv("HOME")) == NULL)
3166 homedir = g_get_home_dir();
3167 if((filename = malloc(strlen(homedir) + sizeof(MAILER_CONFIG_FILE) + 1))
3168 == NULL)
3169 return NULL;
3170 sprintf(filename, "%s/%s", homedir, MAILER_CONFIG_FILE);
3171 return filename;
3172 }
3173
3174
3175 /* mailer_plugin_is_enabled */
_mailer_plugin_is_enabled(Mailer * mailer,char const * plugin)3176 static gboolean _mailer_plugin_is_enabled(Mailer * mailer, char const * plugin)
3177 {
3178 GtkTreeModel * model = GTK_TREE_MODEL(mailer->pl_store);
3179 GtkTreeIter iter;
3180 gchar * p;
3181 gboolean valid;
3182 int res;
3183
3184 for(valid = gtk_tree_model_get_iter_first(model, &iter); valid == TRUE;
3185 valid = gtk_tree_model_iter_next(model, &iter))
3186 {
3187 gtk_tree_model_get(model, &iter, MPC_NAME, &p, -1);
3188 res = strcmp(p, plugin);
3189 g_free(p);
3190 if(res == 0)
3191 return TRUE;
3192 }
3193 return FALSE;
3194 }
3195
3196
3197 /* mailer_get_font */
_mailer_get_font(Mailer * mailer)3198 static char const * _mailer_get_font(Mailer * mailer)
3199 {
3200 char const * p;
3201 char * q = NULL;
3202 GtkSettings * settings;
3203 PangoFontDescription * desc;
3204
3205 if((p = mailer_get_config(mailer, "messages_font")) != NULL)
3206 return p;
3207 settings = gtk_settings_get_default();
3208 g_object_get(G_OBJECT(settings), "gtk-font-name", &q, NULL);
3209 if(q == NULL)
3210 return MAILER_MESSAGES_FONT;
3211 desc = pango_font_description_from_string(q);
3212 g_free(q);
3213 pango_font_description_set_family(desc, "monospace");
3214 q = pango_font_description_to_string(desc);
3215 config_set(mailer->config, NULL, "messages_font", q);
3216 g_free(q);
3217 pango_font_description_free(desc);
3218 if((p = config_get(mailer->config, NULL, "messages_font")) != NULL)
3219 return p;
3220 return MAILER_MESSAGES_FONT;
3221 }
3222
3223
3224 /* mailer_get_selected_headers */
_mailer_get_selected_headers(Mailer * mailer)3225 static GList * _mailer_get_selected_headers(Mailer * mailer)
3226 {
3227 GtkTreeModel * model;
3228 GtkTreeSelection * treesel;
3229
3230 if((model = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->he_view)))
3231 == NULL)
3232 return NULL;
3233 if((treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(
3234 mailer->he_view))) == NULL)
3235 return NULL;
3236 return gtk_tree_selection_get_selected_rows(treesel, NULL);
3237 }
3238
3239
3240 /* useful */
3241 /* mailer_config_load_account */
_mailer_config_load_account(Mailer * mailer,char const * name)3242 static int _mailer_config_load_account(Mailer * mailer, char const * name)
3243 {
3244 Account * account;
3245 char const * type;
3246
3247 #ifdef DEBUG
3248 fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, name);
3249 #endif
3250 if((type = config_get(mailer->config, name, "type")) == NULL)
3251 return -1;
3252 if((account = account_new(mailer, type, name, mailer->fo_store))
3253 == NULL)
3254 return -mailer_error(mailer, error_get(NULL), 1);
3255 if(account_init(account) != 0
3256 || account_config_load(account, mailer->config) != 0
3257 || mailer_account_add(mailer, account) != 0)
3258 {
3259 account_delete(account);
3260 return -1;
3261 }
3262 return 0;
3263 }
3264
3265
3266 /* mailer_confirm */
_mailer_confirm(Mailer * mailer,char const * message)3267 static gboolean _mailer_confirm(Mailer * mailer, char const * message)
3268 {
3269 GtkWidget * dialog;
3270 int res;
3271
3272 dialog = gtk_message_dialog_new(GTK_WINDOW(mailer->fo_window),
3273 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3274 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
3275 #if GTK_CHECK_VERSION(2, 8, 0)
3276 "%s", _("Question"));
3277 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
3278 #endif
3279 "%s", message);
3280 gtk_window_set_title(GTK_WINDOW(dialog), _("Question"));
3281 res = gtk_dialog_run(GTK_DIALOG(dialog));
3282 gtk_widget_destroy(dialog);
3283 return (res == GTK_RESPONSE_YES) ? TRUE : FALSE;
3284 }
3285
3286
3287 /* mailer_foreach_message_selected */
_mailer_foreach_message_selected(Mailer * mailer,MailerForeachMessageCallback callback)3288 static void _mailer_foreach_message_selected(Mailer * mailer,
3289 MailerForeachMessageCallback callback)
3290 {
3291 GtkTreeModel * model;
3292 GtkTreeSelection * treesel;
3293 GList * selected;
3294 GList * s;
3295 GtkTreePath * path;
3296 GtkTreeIter iter;
3297
3298 if((model = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->he_view)))
3299 == NULL)
3300 return;
3301 if((treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(
3302 mailer->he_view))) == NULL)
3303 return;
3304 if((selected = gtk_tree_selection_get_selected_rows(treesel, NULL))
3305 == NULL)
3306 return;
3307 for(s = g_list_first(selected); s != NULL; s = g_list_next(s))
3308 {
3309 if((path = s->data) == NULL)
3310 continue;
3311 gtk_tree_model_get_iter(model, &iter, path);
3312 callback(mailer, model, &iter);
3313 }
3314 g_list_free(selected);
3315 }
3316
3317
3318 /* mailer_refresh_plugin */
_mailer_refresh_plugin(Mailer * mailer)3319 static void _mailer_refresh_plugin(Mailer * mailer)
3320 {
3321 GtkTreeModel * model = GTK_TREE_MODEL(mailer->pl_store);
3322 GtkTreeIter iter;
3323 MailerPluginDefinition * mpd;
3324 MailerPlugin * mp;
3325
3326 if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(mailer->pl_combo), &iter)
3327 != TRUE)
3328 return;
3329 gtk_tree_model_get(model, &iter, MPC_MAILERPLUGINDEFINITION, &mpd,
3330 MPC_MAILERPLUGIN, &mp, -1);
3331 if(mpd->refresh == NULL)
3332 return;
3333 mpd->refresh(mp, mailer->folder_cur, mailer->message_cur);
3334 }
3335
3336
3337 /* mailer_refresh_title */
_mailer_refresh_title(Mailer * mailer)3338 static void _mailer_refresh_title(Mailer * mailer)
3339 {
3340 char buf[80];
3341
3342 if(mailer->folder_cur == NULL)
3343 {
3344 gtk_window_set_title(GTK_WINDOW(mailer->he_window), PACKAGE);
3345 return;
3346 }
3347 snprintf(buf, sizeof(buf), "%s - %s (%s)", PACKAGE,
3348 folder_get_name(mailer->folder_cur),
3349 account_get_title(mailer->account_cur));
3350 gtk_window_set_title(GTK_WINDOW(mailer->he_window), buf);
3351 }
3352
3353
3354 /* mailer_update_status */
_mailer_update_status(Mailer * mailer)3355 static void _mailer_update_status(Mailer * mailer)
3356 {
3357 GtkTreeModel * store;
3358 int cnt;
3359 char buf[256];
3360
3361 if((store = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->he_view)))
3362 != NULL)
3363 {
3364 cnt = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store),
3365 NULL);
3366 snprintf(buf, sizeof(buf), _("%s/%s: %d %s"),
3367 account_get_name(mailer->account_cur),
3368 folder_get_name(mailer->folder_cur), cnt,
3369 (cnt > 1) ? _("messages") : _("message"));
3370 }
3371 else
3372 snprintf(buf, sizeof(buf), "%s", _("Ready"));
3373 mailer_set_status(mailer, buf);
3374 }
3375
3376
3377 /* mailer_update_view */
_mailer_update_view(Mailer * mailer)3378 static void _mailer_update_view(Mailer * mailer)
3379 {
3380 GtkTreeStore * store;
3381 GtkTreeModel * model;
3382 GtkTextBuffer * tbuf;
3383
3384 /* display headers */
3385 if(mailer->folder_cur != NULL && (store = folder_get_messages(
3386 mailer->folder_cur)) != NULL)
3387 {
3388 model = GTK_TREE_MODEL(store);
3389 /* display message */
3390 tbuf = account_select(mailer->account_cur, mailer->folder_cur,
3391 mailer->message_cur);
3392 gtk_text_view_set_buffer(GTK_TEXT_VIEW(mailer->bo_view), tbuf);
3393 }
3394 else
3395 model = NULL;
3396 gtk_tree_view_set_model(GTK_TREE_VIEW(mailer->he_view), model);
3397 _mailer_refresh_plugin(mailer);
3398 _mailer_refresh_title(mailer);
3399 _mailer_update_status(mailer);
3400 }
3401
3402
3403 /* callbacks */
3404 /* mailer_on_online_toggled */
_mailer_on_online_toggled(gpointer data)3405 static void _mailer_on_online_toggled(gpointer data)
3406 {
3407 Mailer * mailer = data;
3408 gboolean online;
3409
3410 online = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
3411 mailer->st_online));
3412 mailer_set_online(mailer, online);
3413 }
3414
3415
3416 /* mailer_on_plugin_combo_changed */
_mailer_on_plugin_combo_changed(gpointer data)3417 static void _mailer_on_plugin_combo_changed(gpointer data)
3418 {
3419 Mailer * mailer = data;
3420 GtkTreeModel * model = GTK_TREE_MODEL(mailer->pl_store);
3421 GtkTreeIter iter;
3422 gboolean valid;
3423 GtkWidget * widget;
3424
3425 for(valid = gtk_tree_model_get_iter_first(model, &iter); valid == TRUE;
3426 valid = gtk_tree_model_iter_next(model, &iter))
3427 {
3428 gtk_tree_model_get(GTK_TREE_MODEL(mailer->pl_store), &iter,
3429 MPC_WIDGET, &widget, -1);
3430 gtk_widget_hide(widget);
3431 }
3432 if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(mailer->pl_combo), &iter)
3433 != TRUE)
3434 return;
3435 gtk_tree_model_get(GTK_TREE_MODEL(mailer->pl_store), &iter, MPC_WIDGET,
3436 &widget, -1);
3437 gtk_widget_show(widget);
3438 _mailer_refresh_plugin(mailer);
3439 }
3440