2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2010 the Claws Mail Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 # include "claws-features.h"
27 #include <glib/gi18n.h>
32 #include <gtk/gtkutils.h>
34 #include "common/claws.h"
35 #include "common/version.h"
40 #include "prefs_gtk.h"
41 #include "foldersel.h"
42 #include "clamav_plugin.h"
43 #include "statusbar.h"
44 #include "alertpanel.h"
45 #include "clamd-plugin.h"
51 GtkWidget *enable_clamav;
52 /* GtkWidget *enable_arc;*/
54 GtkWidget *recv_infected;
55 GtkWidget *save_folder;
56 GtkWidget *config_type;
57 GtkWidget *config_folder;
58 GtkWidget *config_host;
59 GtkWidget *config_port;
62 static GtkWidget *hbox_auto1, *hbox_auto2, *hbox_manual1, *hbox_manual2;
64 static void foldersel_cb(GtkWidget *widget, gpointer data)
66 struct ClamAvPage *page = (struct ClamAvPage *) data;
71 item = foldersel_folder_sel(NULL, FOLDER_SEL_MOVE, NULL, FALSE);
72 if (item && (item_id = folder_item_get_identifier(item)) != NULL) {
73 gtk_editable_delete_text(GTK_EDITABLE(page->save_folder), 0, -1);
74 gtk_editable_insert_text(GTK_EDITABLE(page->save_folder), item_id, strlen(item_id), &newpos);
79 static void clamd_folder_cb(GtkWidget *widget, gpointer data)
84 struct ClamAvPage *page = (struct ClamAvPage *) data;
86 dialog = gtk_file_chooser_dialog_new(
87 "Select file with clamd configuration [clamd.conf]",
89 GTK_FILE_CHOOSER_ACTION_OPEN,
90 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
91 GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
93 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), "/etc");
94 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_APPLY) {
95 file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
96 debug_print("New clamd.conf: %s\n", file);
98 gtk_editable_delete_text(GTK_EDITABLE(page->config_folder), 0, -1);
99 gtk_editable_insert_text(GTK_EDITABLE(page->config_folder), file, strlen(file), &newpos);
103 gtk_widget_destroy(dialog);
106 static void check_permission(gchar* folder) {
109 if (g_stat(folder, &info) < 0)
111 mode_t perm = info.st_mode & ~(S_IFMT);
112 debug_print("%s: Old file permission: %05o\n", folder, perm);
113 if ((perm & S_IXOTH) != S_IXOTH) {
114 perm = perm | S_IXOTH;
115 g_chmod(folder, perm);
117 debug_print("%s: New file permission: %05o\n", folder, perm);
120 static void folder_permission_cb(GtkWidget *widget, gpointer data) {
121 static gchar* folders[] = {
123 ".claws-mail/mimetmp",
126 const gchar* home = g_get_home_dir();
129 check_permission((gchar *) home);
130 for (i = 0; folders[i]; i++) {
131 gchar* file = g_strdup_printf("%s/%s", home, folders[i]);
132 check_permission(file);
137 static void clamav_show_config(Config* config) {
139 if (config->ConfigType == MANUAL) {
140 gtk_widget_hide(hbox_auto1);
141 gtk_widget_hide(hbox_auto2);
142 gtk_widget_show(hbox_manual1);
143 gtk_widget_show(hbox_manual2);
146 gtk_widget_hide(hbox_manual1);
147 gtk_widget_hide(hbox_manual2);
148 gtk_widget_show(hbox_auto1);
149 gtk_widget_show(hbox_auto2);
154 static void setting_type_cb(GtkWidget *widget, gpointer data) {
155 gboolean state = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
156 struct ClamAvPage *page = (struct ClamAvPage *) data;
159 gboolean tmp_conf = FALSE;
161 if (page && page->page.widget) {
162 /* Reset configuration */
163 debug_print("Resetting configuration\n");
164 gtk_editable_delete_text(GTK_EDITABLE(page->config_folder), 0, -1);
165 gtk_editable_delete_text(GTK_EDITABLE(page->config_host), 0, -1);
166 gtk_editable_delete_text(GTK_EDITABLE(page->config_port), 0, -1);
167 clamav_save_config();
169 c = clamd_get_config();
171 c = clamd_config_new();
175 /* Automatic configuration */
176 debug_print("Setting clamd to automatic configuration\n");
177 if (clamd_find_socket()) {
179 Config* clamd_conf = clamd_get_config();
180 if (clamd_conf->automatic.folder)
181 c->automatic.folder = g_strdup(clamd_conf->automatic.folder);
183 c->automatic.folder = g_strdup("");
185 if (c->ConfigType == AUTOMATIC) {
186 gtk_editable_insert_text(GTK_EDITABLE(page->config_folder),
187 c->automatic.folder, strlen(c->automatic.folder), &newpos);
188 clamav_save_config();
191 c->ConfigType = AUTOMATIC;
192 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->config_type), TRUE);
195 /* Manual configuration */
196 debug_print("Setting clamd to manual configuration\n");
197 c->ConfigType = MANUAL;
198 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->config_type), FALSE);
200 clamav_show_config(c);
202 clamd_config_free(c);
206 static void clamav_create_widget_func(PrefsPage * _page, GtkWindow *window, gpointer data)
208 struct ClamAvPage *page = (struct ClamAvPage *) _page;
209 ClamAvConfig *config;
210 Config *clamd_config;
212 GtkWidget *vbox1, *vbox2;
213 GtkWidget *enable_clamav;
215 /* GtkWidget *enable_arc;*/
217 GtkObject *max_size_adj;
220 GtkWidget *recv_infected;
221 GtkWidget *save_folder;
222 GtkWidget *save_folder_select;
223 GtkWidget *clamd_conf_label;
224 GtkWidget *config_folder;
225 GtkWidget *config_host;
226 GtkWidget *config_port;
227 GtkWidget *config_folder_select;
229 GtkWidget *permission_label;
230 GtkWidget *permission_select;
231 GtkWidget *host_label;
232 GtkWidget *port_label;
233 GtkWidget *setting_type;
234 GtkTooltips *tooltips;
236 tooltips = gtk_tooltips_new();
237 enable_clamav = page->enable_clamav;
239 vbox1 = gtk_vbox_new (FALSE, VSPACING);
240 gtk_widget_show (vbox1);
241 gtk_container_set_border_width (GTK_CONTAINER (vbox1), VBOX_BORDER);
243 vbox2 = gtk_vbox_new (FALSE, 4);
244 gtk_widget_show (vbox2);
245 gtk_box_pack_start (GTK_BOX (vbox1), vbox2, FALSE, FALSE, 0);
247 PACK_CHECK_BUTTON (vbox2, enable_clamav, _("Enable virus scanning"));
248 /* PACK_CHECK_BUTTON (vbox2, enable_arc, _("Scan archive contents"));
250 SET_TOGGLE_SENSITIVITY (enable_clamav, enable_arc);*/
252 hbox1 = gtk_hbox_new (FALSE, 8);
253 gtk_widget_show (hbox1);
254 gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, FALSE, 0);
255 /* SET_TOGGLE_SENSITIVITY (enable_arc, hbox1);*/
257 label1 = gtk_label_new(_("Maximum attachment size"));
258 gtk_widget_show (label1);
259 gtk_box_pack_start (GTK_BOX (hbox1), label1, FALSE, FALSE, 0);
260 SET_TOGGLE_SENSITIVITY (enable_clamav, label1);
262 max_size_adj = gtk_adjustment_new (1, 1, 1024, 1, 10, 0);
263 max_size = gtk_spin_button_new (GTK_ADJUSTMENT (max_size_adj), 1, 0);
264 gtk_widget_show (max_size);
265 gtk_box_pack_start (GTK_BOX (hbox1), max_size, FALSE, FALSE, 0);
266 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (max_size), TRUE);
267 gtk_tooltips_set_tip(tooltips, max_size,
268 _("Message attachments larger than this will not be scanned"),
270 SET_TOGGLE_SENSITIVITY (enable_clamav, max_size);
272 label2 = gtk_label_new(_("MB"));
273 gtk_widget_show (label2);
274 gtk_box_pack_start (GTK_BOX (hbox1), label2, FALSE, FALSE, 0);
275 SET_TOGGLE_SENSITIVITY (enable_clamav, label2);
277 hbox1 = gtk_hbox_new (FALSE, 8);
278 gtk_widget_show (hbox1);
279 gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, FALSE, 0);
281 recv_infected = gtk_check_button_new_with_label(_("Save infected mail in"));
282 gtk_widget_show (recv_infected);
283 gtk_box_pack_start (GTK_BOX (hbox1), recv_infected, FALSE, FALSE, 0);
284 gtk_tooltips_set_tip(tooltips, recv_infected,
285 _("Save mail that contains viruses"),
287 SET_TOGGLE_SENSITIVITY (enable_clamav, recv_infected);
289 save_folder = gtk_entry_new ();
290 gtk_widget_show (save_folder);
291 gtk_box_pack_start (GTK_BOX (hbox1), save_folder, TRUE, TRUE, 0);
292 gtk_tooltips_set_tip(tooltips, save_folder,
293 _("Folder for storing infected mail. Leave empty to use the default trash folder"),
295 SET_TOGGLE_SENSITIVITY (enable_clamav, save_folder);
297 save_folder_select = gtkut_get_browse_directory_btn(_("_Browse"));
298 gtk_widget_show (save_folder_select);
299 gtk_box_pack_start (GTK_BOX (hbox1), save_folder_select, FALSE, FALSE, 0);
300 gtk_tooltips_set_tip(tooltips, save_folder_select,
301 _("Click this button to select a folder for storing infected mail"),
303 SET_TOGGLE_SENSITIVITY (enable_clamav, save_folder_select);
305 hbox1 = gtk_hbox_new (FALSE, 8);
306 gtk_widget_show (hbox1);
307 gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, FALSE, 0);
309 setting_type = gtk_check_button_new_with_label(_("Automatic configuration"));
310 /*gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(setting_type), TRUE);*/
311 gtk_widget_show (setting_type);
312 gtk_box_pack_start (GTK_BOX (hbox1), setting_type, FALSE, FALSE, 0);
313 gtk_tooltips_set_tip(tooltips, setting_type,
314 _("Should configuration be done automatic or manual"),
316 SET_TOGGLE_SENSITIVITY (enable_clamav, setting_type);
318 hbox_auto1 = gtk_hbox_new (FALSE, 8);
319 gtk_widget_show (hbox_auto1);
320 gtk_box_pack_start (GTK_BOX (vbox2), hbox_auto1, FALSE, FALSE, 0);
322 clamd_conf_label = gtk_label_new(_("Where is clamd.conf"));
323 gtk_widget_show (clamd_conf_label);
324 gtk_box_pack_start (GTK_BOX (hbox_auto1), clamd_conf_label, FALSE, FALSE, 0);
326 config_folder = gtk_entry_new ();
327 gtk_widget_show (config_folder);
328 gtk_box_pack_start (GTK_BOX (hbox_auto1), config_folder, TRUE, TRUE, 0);
329 gtk_tooltips_set_tip(tooltips, config_folder,
330 _("Full path to clamd.conf. If this field is not empty then the plugin has been able to locate the file automatically"),
332 SET_TOGGLE_SENSITIVITY (enable_clamav, config_folder);
334 config_folder_select = gtkut_get_browse_directory_btn(_("Br_owse"));
335 gtk_widget_show (config_folder_select);
336 gtk_box_pack_start (GTK_BOX (hbox_auto1), config_folder_select, FALSE, FALSE, 0);
337 gtk_tooltips_set_tip(tooltips, config_folder_select,
338 _("Click this button to select full path to clamd.conf"),
340 SET_TOGGLE_SENSITIVITY (enable_clamav, config_folder_select);
342 hbox_auto2 = gtk_hbox_new (FALSE, 8);
343 gtk_widget_show (hbox_auto2);
344 gtk_box_pack_start (GTK_BOX (vbox2), hbox_auto2, FALSE, FALSE, 0);
346 permission_label = gtk_label_new(_("Check permission for folders and adjust if necessary"));
347 gtk_widget_show (permission_label);
348 gtk_box_pack_start (GTK_BOX (hbox_auto2), permission_label, FALSE, FALSE, 0);
350 blank = gtk_label_new("");
351 gtk_widget_show (blank);
352 gtk_box_pack_start (GTK_BOX (hbox_auto2), blank, TRUE, TRUE, 0);
354 permission_select = gtk_button_new_from_stock(GTK_STOCK_FIND_AND_REPLACE);
355 /*gtk_button_new_with_mnemonic(_("_Check Permission"));*/
356 gtk_widget_show (permission_select);
357 gtk_box_pack_start (GTK_BOX (hbox_auto2), permission_select, FALSE, FALSE, 0);
358 gtk_tooltips_set_tip(tooltips, permission_select,
359 _("Click this button to check and adjust folder permissions"),
361 SET_TOGGLE_SENSITIVITY (enable_clamav, permission_select);
363 hbox_manual1 = gtk_hbox_new (FALSE, 8);
364 gtk_widget_show (hbox_manual1);
365 gtk_box_pack_start (GTK_BOX (vbox2), hbox_manual1, FALSE, FALSE, 0);
367 host_label = gtk_label_new(_("Remote Host"));
368 gtk_widget_show (host_label);
369 gtk_box_pack_start (GTK_BOX (hbox_manual1), host_label, FALSE, FALSE, 0);
371 config_host = gtk_entry_new ();
372 gtk_widget_show (config_host);
373 gtk_box_pack_start (GTK_BOX (hbox_manual1), config_host, FALSE, FALSE, 0);
374 gtk_tooltips_set_tip(tooltips, config_host,
375 _("Hostname or IP for remote host running clamav daemon"),
377 SET_TOGGLE_SENSITIVITY (enable_clamav, config_host);
379 blank = gtk_label_new("");
380 gtk_widget_show (blank);
381 gtk_box_pack_start (GTK_BOX (hbox_manual1), blank, TRUE, TRUE, 0);
383 hbox_manual2 = gtk_hbox_new (FALSE, 8);
384 gtk_widget_show (hbox_manual2);
385 gtk_box_pack_start (GTK_BOX (vbox2), hbox_manual2, FALSE, FALSE, 0);
387 port_label = gtk_label_new(_("Port"));
388 gtk_widget_show (port_label);
389 gtk_box_pack_start (GTK_BOX (hbox_manual2), port_label, FALSE, FALSE, 0);
391 config_port = gtk_entry_new ();
392 gtk_entry_set_width_chars(GTK_ENTRY(config_port), 5);
393 gtk_entry_set_max_length(GTK_ENTRY(config_port), 5);
394 gtk_widget_show (config_port);
395 gtk_box_pack_start (GTK_BOX (hbox_manual2), config_port, FALSE, FALSE, 0);
396 gtk_tooltips_set_tip(tooltips, config_port,
397 _("Port number where clamav daemon is listening"),
400 blank = gtk_label_new("");
401 gtk_widget_show (blank);
402 gtk_box_pack_start (GTK_BOX (hbox_manual2), blank, TRUE, TRUE, 0);
404 SET_TOGGLE_SENSITIVITY (enable_clamav, config_port);
406 g_signal_connect(G_OBJECT(save_folder_select), "clicked",
407 G_CALLBACK(foldersel_cb), page);
408 g_signal_connect(G_OBJECT(config_folder_select), "clicked",
409 G_CALLBACK(clamd_folder_cb), page);
410 g_signal_connect(G_OBJECT(permission_select), "clicked",
411 G_CALLBACK(folder_permission_cb), page);
412 g_signal_connect(G_OBJECT(setting_type), "clicked",
413 G_CALLBACK(setting_type_cb), page);
415 config = clamav_get_config();
417 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_clamav), config->clamav_enable);
418 /* gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_arc), config->clamav_enable_arc);*/
419 gtk_spin_button_set_value(GTK_SPIN_BUTTON(max_size), (float) config->clamav_max_size);
420 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(recv_infected), config->clamav_recv_infected);
421 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(setting_type), config->clamd_config_type);
423 clamd_config = clamd_get_config();
425 if (config->clamav_save_folder != NULL)
426 gtk_entry_set_text(GTK_ENTRY(save_folder), config->clamav_save_folder);
427 if (!config->clamd_config_type) {
428 /*if (config->clamd_host && strlen(config->clamd_host) > 0 && config->clamd_port > 0) {*/
429 gtk_entry_set_text(GTK_ENTRY(config_host), config->clamd_host);
430 gchar* s = int2char(config->clamd_port);
431 gtk_entry_set_text(GTK_ENTRY(config_port), s);
433 /* activate manual checkbox and blind folder */
434 debug_print("Showing manual configuration and hiding automatic configuration\n");
435 if (! clamd_config) {
436 clamd_config = clamd_config_new();
437 clamd_config->ConfigType = MANUAL;
438 clamav_show_config(clamd_config);
439 clamd_config_free(clamd_config);
442 clamav_show_config(clamd_config);
445 //else if (config->clamd_config_folder == NULL || strlen(config->clamd_config_folder) == 0) {
446 if (clamd_find_socket()) {
447 Config* c = clamd_get_config();
448 if (c && c->ConfigType == AUTOMATIC) {
449 config->clamd_config_folder = g_strdup(c->automatic.folder);
450 /* deactivate manual checkbox and blind host and port */
451 debug_print("Showing automatic configuration and hiding manual configuration\n");
452 clamav_show_config(c);
454 gtk_editable_delete_text(GTK_EDITABLE(config_folder), 0, -1);
455 gtk_editable_insert_text(GTK_EDITABLE(config_folder),
456 config->clamd_config_folder, strlen(config->clamd_config_folder), &newpos);
458 else if (c && c->ConfigType == MANUAL) {
459 /* deactivate automatic automatic configuration */
460 debug_print("Showing manual configuration and hiding automatic configuration\n");
461 clamav_show_config(c);
466 gtk_entry_set_text(GTK_ENTRY(config_folder), config->clamd_config_folder);
467 // deactivate manual checkbox and blind host and port
468 debug_print("Showing automatic configuration and hiding manual configuration\n");
469 if (! clamd_config) {
470 clamd_config = clamd_config_new();
471 clamd_config->ConfigType = AUTOMATIC;
472 clamav_show_config(clamd_config);
473 clamd_config_free(clamd_config);
476 clamav_show_config(clamd_config);
479 page->enable_clamav = enable_clamav;
480 /* page->enable_arc = enable_arc;*/
481 page->max_size = max_size;
482 page->recv_infected = recv_infected;
483 page->save_folder = save_folder;
484 page->config_type = setting_type;
485 page->config_folder = config_folder;
486 page->config_host = config_host;
487 page->config_port = config_port;
488 page->page.widget = vbox1;
490 clamav_save_config();
493 static void clamav_destroy_widget_func(PrefsPage *_page)
495 debug_print("Destroying Clamd widget\n");
498 static void clamav_save_func(PrefsPage *_page)
500 struct ClamAvPage *page = (struct ClamAvPage *) _page;
501 ClamAvConfig *config;
503 debug_print("Saving Clamd Page\n");
505 config = clamav_get_config();
507 config->clamav_enable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->enable_clamav));
508 /* config->clamav_enable_arc = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->enable_arc));*/
510 config->clamav_max_size = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(page->max_size));
511 config->clamav_recv_infected = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->recv_infected));
512 g_free(config->clamav_save_folder);
513 config->clamav_save_folder = gtk_editable_get_chars(GTK_EDITABLE(page->save_folder), 0, -1);
514 config->clamd_config_type = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->config_type));
515 g_free(config->clamd_config_folder);
516 config->clamd_config_folder = gtk_editable_get_chars(GTK_EDITABLE(page->config_folder), 0, -1);
517 g_free(config->clamd_host);
518 config->clamd_host = gtk_editable_get_chars(GTK_EDITABLE(page->config_host), 0, -1);
519 config->clamd_port = atoi(gtk_entry_get_text(GTK_ENTRY(page->config_port)));
521 if (config->clamav_enable) {
522 Clamd_Stat status = clamd_prepare();
525 g_warning("[New config] No socket information");
526 alertpanel_error(_("New config\nNo socket information.\nAntivirus disabled."));
529 g_warning("[New config] Clamd does not respond to ping");
530 alertpanel_warning(_("New config\nClamd does not respond to ping.\nIs clamd running?"));
536 clamav_save_config();
539 static struct ClamAvPage clamav_page;
541 static void gtk_message_callback(gchar *message)
543 statusbar_print_all("%s", message);
546 gint clamav_gtk_init(void)
548 static gchar *path[3];
550 path[0] = _("Plugins");
551 path[1] = _("Clam AntiVirus");
554 clamav_page.page.path = path;
555 clamav_page.page.create_widget = clamav_create_widget_func;
556 clamav_page.page.destroy_widget = clamav_destroy_widget_func;
557 clamav_page.page.save_page = clamav_save_func;
558 clamav_page.page.weight = 35.0;
560 prefs_gtk_register_page((PrefsPage *) &clamav_page);
561 clamav_set_message_callback(gtk_message_callback);
563 debug_print("Clamd GTK plugin loaded\n");
567 void clamav_gtk_done(void)
569 prefs_gtk_unregister_page((PrefsPage *) &clamav_page);