2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2021 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 _("Select folder to store infected messages in"));
73 if (item
&& (item_id
= folder_item_get_identifier(item
)) != NULL
) {
74 gtk_editable_delete_text(GTK_EDITABLE(page
->save_folder
), 0, -1);
75 gtk_editable_insert_text(GTK_EDITABLE(page
->save_folder
), item_id
, strlen(item_id
), &newpos
);
80 static void clamd_folder_cb(GtkWidget
*widget
, gpointer data
)
85 struct ClamAvPage
*page
= (struct ClamAvPage
*) data
;
87 dialog
= gtk_file_chooser_dialog_new(
88 "Select file with clamd configuration [clamd.conf]",
90 GTK_FILE_CHOOSER_ACTION_OPEN
,
91 _("_Cancel"), GTK_RESPONSE_CANCEL
,
92 _("_Apply"), GTK_RESPONSE_APPLY
,
94 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog
), "/etc");
95 if (gtk_dialog_run (GTK_DIALOG(dialog
)) == GTK_RESPONSE_APPLY
) {
96 file
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog
));
97 debug_print("New clamd.conf: %s\n", file
);
99 gtk_editable_delete_text(GTK_EDITABLE(page
->config_folder
), 0, -1);
100 gtk_editable_insert_text(GTK_EDITABLE(page
->config_folder
), file
, strlen(file
), &newpos
);
104 gtk_widget_destroy(dialog
);
107 static void check_permission(gchar
* folder
) {
110 if (g_stat(folder
, &info
) < 0)
112 mode_t perm
= info
.st_mode
& ~(S_IFMT
);
113 debug_print("%s: Old file permission: %05o\n", folder
, perm
);
114 if ((perm
& S_IXOTH
) != S_IXOTH
) {
115 perm
= perm
| S_IXOTH
;
116 g_chmod(folder
, perm
);
118 debug_print("%s: New file permission: %05o\n", folder
, perm
);
121 static void folder_permission_cb(GtkWidget
*widget
, gpointer data
) {
122 static gchar
* folders
[] = {
124 ".claws-mail/mimetmp",
127 const gchar
* home
= get_home_dir();
130 check_permission((gchar
*) home
);
131 for (i
= 0; folders
[i
]; i
++) {
132 gchar
* file
= g_strdup_printf("%s/%s", home
, folders
[i
]);
133 check_permission(file
);
138 static void clamav_show_config(Config
* config
) {
140 if (config
->ConfigType
== MANUAL
) {
141 gtk_widget_hide(hbox_auto1
);
142 gtk_widget_hide(hbox_auto2
);
143 gtk_widget_show(hbox_manual1
);
144 gtk_widget_show(hbox_manual2
);
147 gtk_widget_hide(hbox_manual1
);
148 gtk_widget_hide(hbox_manual2
);
149 gtk_widget_show(hbox_auto1
);
150 gtk_widget_show(hbox_auto2
);
155 static void setting_type_cb(GtkWidget
*widget
, gpointer data
) {
156 gboolean state
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
157 struct ClamAvPage
*page
= (struct ClamAvPage
*) data
;
160 gboolean tmp_conf
= FALSE
;
162 if (page
&& page
->page
.widget
) {
163 /* Reset configuration */
164 debug_print("Resetting configuration\n");
165 gtk_editable_delete_text(GTK_EDITABLE(page
->config_folder
), 0, -1);
166 gtk_editable_delete_text(GTK_EDITABLE(page
->config_host
), 0, -1);
167 gtk_spin_button_set_value(GTK_SPIN_BUTTON(page
->config_port
), (gdouble
) 0);
168 clamav_save_config();
170 c
= clamd_get_config();
172 c
= clamd_config_new();
176 /* Automatic configuration */
177 debug_print("Setting clamd to automatic configuration\n");
178 if (clamd_find_socket()) {
180 Config
* clamd_conf
= clamd_get_config();
181 if (clamd_conf
->automatic
.folder
)
182 c
->automatic
.folder
= g_strdup(clamd_conf
->automatic
.folder
);
184 c
->automatic
.folder
= g_strdup("");
186 if (c
->ConfigType
== AUTOMATIC
) {
187 gtk_editable_insert_text(GTK_EDITABLE(page
->config_folder
),
188 c
->automatic
.folder
, strlen(c
->automatic
.folder
), &newpos
);
189 clamav_save_config();
192 c
->ConfigType
= AUTOMATIC
;
193 if (page
->config_type
)
194 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page
->config_type
), TRUE
);
197 /* Manual configuration */
198 debug_print("Setting clamd to manual configuration\n");
199 c
->ConfigType
= MANUAL
;
200 if (page
->config_type
)
201 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page
->config_type
), FALSE
);
203 clamav_show_config(c
);
205 clamd_config_free(c
);
209 static void clamav_create_widget_func(PrefsPage
* _page
, GtkWindow
*window
, gpointer data
)
211 struct ClamAvPage
*page
= (struct ClamAvPage
*) _page
;
212 ClamAvConfig
*config
;
213 Config
*clamd_config
;
215 GtkWidget
*vbox1
, *vbox2
;
216 GtkWidget
*enable_clamav
;
218 /* GtkWidget *enable_arc;*/
220 GtkAdjustment
*max_size_adj
;
223 GtkWidget
*recv_infected
;
224 GtkWidget
*save_folder
;
225 GtkWidget
*save_folder_select
;
226 GtkWidget
*clamd_conf_label
;
227 GtkWidget
*config_folder
;
228 GtkWidget
*config_host
;
229 GtkWidget
*config_port
;
230 GtkWidget
*config_folder_select
;
232 GtkWidget
*permission_label
;
233 GtkWidget
*permission_select
;
234 GtkWidget
*host_label
;
235 GtkWidget
*port_label
;
236 GtkWidget
*setting_type
;
238 enable_clamav
= page
->enable_clamav
;
240 vbox1
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, VSPACING
);
241 gtk_widget_show (vbox1
);
242 gtk_container_set_border_width (GTK_CONTAINER (vbox1
), VBOX_BORDER
);
244 vbox2
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 4);
245 gtk_widget_show (vbox2
);
246 gtk_box_pack_start (GTK_BOX (vbox1
), vbox2
, FALSE
, FALSE
, 0);
248 PACK_CHECK_BUTTON (vbox2
, enable_clamav
, _("Enable virus scanning"));
249 /* PACK_CHECK_BUTTON (vbox2, enable_arc, _("Scan archive contents"));
251 SET_TOGGLE_SENSITIVITY (enable_clamav, enable_arc);*/
253 hbox1
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 8);
254 gtk_widget_show (hbox1
);
255 gtk_box_pack_start (GTK_BOX (vbox2
), hbox1
, FALSE
, FALSE
, 0);
256 /* SET_TOGGLE_SENSITIVITY (enable_arc, hbox1);*/
258 label1
= gtk_label_new(_("Maximum attachment size"));
259 gtk_widget_show (label1
);
260 gtk_box_pack_start (GTK_BOX (hbox1
), label1
, FALSE
, FALSE
, 0);
261 SET_TOGGLE_SENSITIVITY (enable_clamav
, label1
);
263 max_size_adj
= gtk_adjustment_new (1, 1, 1024, 1, 10, 0);
264 max_size
= gtk_spin_button_new (GTK_ADJUSTMENT (max_size_adj
), 1, 0);
265 gtk_widget_show (max_size
);
266 gtk_box_pack_start (GTK_BOX (hbox1
), max_size
, FALSE
, FALSE
, 0);
267 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (max_size
), TRUE
);
268 gtk_widget_set_tooltip_text(max_size
,
269 _("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_box_new(GTK_ORIENTATION_HORIZONTAL
, 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_widget_set_tooltip_text(recv_infected
,
285 _("Save mail that contains viruses"));
286 SET_TOGGLE_SENSITIVITY (enable_clamav
, recv_infected
);
288 save_folder
= gtk_entry_new ();
289 gtk_widget_show (save_folder
);
290 gtk_box_pack_start (GTK_BOX (hbox1
), save_folder
, TRUE
, TRUE
, 0);
291 gtk_widget_set_tooltip_text(save_folder
,
292 _("Folder for storing infected mail. Leave empty to use the default trash folder"));
293 SET_TOGGLE_SENSITIVITY (enable_clamav
, save_folder
);
295 save_folder_select
= gtkut_get_browse_directory_btn(_("_Browse"));
296 gtk_widget_show (save_folder_select
);
297 gtk_box_pack_start (GTK_BOX (hbox1
), save_folder_select
, FALSE
, FALSE
, 0);
298 gtk_widget_set_tooltip_text(save_folder_select
,
299 _("Click this button to select a folder for storing infected mail"));
300 SET_TOGGLE_SENSITIVITY (enable_clamav
, save_folder_select
);
302 hbox1
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 8);
303 gtk_widget_show (hbox1
);
304 gtk_box_pack_start (GTK_BOX (vbox2
), hbox1
, FALSE
, FALSE
, 0);
306 setting_type
= gtk_check_button_new_with_label(_("Automatic configuration"));
307 /*gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(setting_type), TRUE);*/
308 gtk_widget_show (setting_type
);
309 gtk_box_pack_start (GTK_BOX (hbox1
), setting_type
, FALSE
, FALSE
, 0);
310 gtk_widget_set_tooltip_text(setting_type
,
311 _("Should configuration be done automatic or manual"));
312 SET_TOGGLE_SENSITIVITY (enable_clamav
, setting_type
);
314 hbox_auto1
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 8);
315 gtk_widget_show (hbox_auto1
);
316 gtk_box_pack_start (GTK_BOX (vbox2
), hbox_auto1
, FALSE
, FALSE
, 0);
318 clamd_conf_label
= gtk_label_new(_("Where is clamd.conf"));
319 gtk_widget_show (clamd_conf_label
);
320 gtk_box_pack_start (GTK_BOX (hbox_auto1
), clamd_conf_label
, FALSE
, FALSE
, 0);
322 config_folder
= gtk_entry_new ();
323 gtk_widget_show (config_folder
);
324 gtk_box_pack_start (GTK_BOX (hbox_auto1
), config_folder
, TRUE
, TRUE
, 0);
325 gtk_widget_set_tooltip_text(config_folder
,
326 _("Full path to clamd.conf. If this field is not empty then the plugin has been able to locate the file automatically"));
327 SET_TOGGLE_SENSITIVITY (enable_clamav
, config_folder
);
329 config_folder_select
= gtkut_get_browse_directory_btn(_("Br_owse"));
330 gtk_widget_show (config_folder_select
);
331 gtk_box_pack_start (GTK_BOX (hbox_auto1
), config_folder_select
, FALSE
, FALSE
, 0);
332 gtk_widget_set_tooltip_text(config_folder_select
,
333 _("Click this button to select full path to clamd.conf"));
334 SET_TOGGLE_SENSITIVITY (enable_clamav
, config_folder_select
);
336 hbox_auto2
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 8);
337 gtk_widget_show (hbox_auto2
);
338 gtk_box_pack_start (GTK_BOX (vbox2
), hbox_auto2
, FALSE
, FALSE
, 0);
340 permission_label
= gtk_label_new(_("Check permission for folders and adjust if necessary"));
341 gtk_widget_show (permission_label
);
342 gtk_box_pack_start (GTK_BOX (hbox_auto2
), permission_label
, FALSE
, FALSE
, 0);
344 blank
= gtk_label_new("");
345 gtk_widget_show (blank
);
346 gtk_box_pack_start (GTK_BOX (hbox_auto2
), blank
, TRUE
, TRUE
, 0);
348 permission_select
= gtkut_stock_button("edit-find-replace", _("Find and _Replace"));
349 /*gtk_button_new_with_mnemonic(_("_Check Permission"));*/
350 gtk_widget_show (permission_select
);
351 gtk_box_pack_start (GTK_BOX (hbox_auto2
), permission_select
, FALSE
, FALSE
, 0);
352 gtk_widget_set_tooltip_text(permission_select
,
353 _("Click this button to check and adjust folder permissions"));
354 SET_TOGGLE_SENSITIVITY (enable_clamav
, permission_select
);
356 hbox_manual1
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 8);
357 gtk_widget_show (hbox_manual1
);
358 gtk_box_pack_start (GTK_BOX (vbox2
), hbox_manual1
, FALSE
, FALSE
, 0);
360 host_label
= gtk_label_new(_("Remote Host"));
361 gtk_widget_show (host_label
);
362 gtk_box_pack_start (GTK_BOX (hbox_manual1
), host_label
, FALSE
, FALSE
, 0);
364 config_host
= gtk_entry_new ();
365 gtk_widget_show (config_host
);
366 gtk_box_pack_start (GTK_BOX (hbox_manual1
), config_host
, FALSE
, FALSE
, 0);
367 gtk_widget_set_tooltip_text(config_host
,
368 _("Hostname or IP for remote host running clamav daemon"));
369 SET_TOGGLE_SENSITIVITY (enable_clamav
, config_host
);
371 blank
= gtk_label_new("");
372 gtk_widget_show (blank
);
373 gtk_box_pack_start (GTK_BOX (hbox_manual1
), blank
, TRUE
, TRUE
, 0);
375 hbox_manual2
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 8);
376 gtk_widget_show (hbox_manual2
);
377 gtk_box_pack_start (GTK_BOX (vbox2
), hbox_manual2
, FALSE
, FALSE
, 0);
379 port_label
= gtk_label_new(_("Port"));
380 gtk_widget_show (port_label
);
381 gtk_box_pack_start (GTK_BOX (hbox_manual2
), port_label
, FALSE
, FALSE
, 0);
383 config_port
= gtk_spin_button_new_with_range(0, 65535, 1);
384 gtk_widget_show (config_port
);
385 gtk_box_pack_start (GTK_BOX (hbox_manual2
), config_port
, FALSE
, FALSE
, 0);
386 gtk_widget_set_tooltip_text(config_port
,
387 _("Port number where clamav daemon is listening"));
389 blank
= gtk_label_new("");
390 gtk_widget_show (blank
);
391 gtk_box_pack_start (GTK_BOX (hbox_manual2
), blank
, TRUE
, TRUE
, 0);
393 SET_TOGGLE_SENSITIVITY (enable_clamav
, config_port
);
395 config
= clamav_get_config();
397 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_clamav
), config
->clamav_enable
);
398 /* gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_arc), config->clamav_enable_arc);*/
399 gtk_spin_button_set_value(GTK_SPIN_BUTTON(max_size
), (float) config
->clamav_max_size
);
400 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(recv_infected
), config
->clamav_recv_infected
);
401 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(setting_type
), config
->clamd_config_type
);
403 g_signal_connect(G_OBJECT(save_folder_select
), "clicked",
404 G_CALLBACK(foldersel_cb
), page
);
405 g_signal_connect(G_OBJECT(config_folder_select
), "clicked",
406 G_CALLBACK(clamd_folder_cb
), page
);
407 g_signal_connect(G_OBJECT(permission_select
), "clicked",
408 G_CALLBACK(folder_permission_cb
), page
);
409 g_signal_connect(G_OBJECT(setting_type
), "clicked",
410 G_CALLBACK(setting_type_cb
), page
);
412 clamd_config
= clamd_get_config();
414 if (config
->clamav_save_folder
!= NULL
)
415 gtk_entry_set_text(GTK_ENTRY(save_folder
), config
->clamav_save_folder
);
416 if (!config
->clamd_config_type
) {
417 /*if (config->clamd_host && strlen(config->clamd_host) > 0 && config->clamd_port > 0) {*/
418 gtk_entry_set_text(GTK_ENTRY(config_host
), config
->clamd_host
);
419 gtk_spin_button_set_value(GTK_SPIN_BUTTON(config_port
), (gdouble
) config
->clamd_port
);
420 /* activate manual checkbox and blind folder */
421 debug_print("Showing manual configuration and hiding automatic configuration\n");
422 if (! clamd_config
) {
423 clamd_config
= clamd_config_new();
424 clamd_config
->ConfigType
= MANUAL
;
425 clamav_show_config(clamd_config
);
426 clamd_config_free(clamd_config
);
429 clamav_show_config(clamd_config
);
432 //else if (config->clamd_config_folder == NULL || strlen(config->clamd_config_folder) == 0) {
433 if (clamd_find_socket()) {
434 Config
* c
= clamd_get_config();
435 if (c
&& c
->ConfigType
== AUTOMATIC
) {
436 config
->clamd_config_folder
= g_strdup(c
->automatic
.folder
);
437 /* deactivate manual checkbox and blind host and port */
438 debug_print("Showing automatic configuration and hiding manual configuration\n");
439 clamav_show_config(c
);
441 gtk_editable_delete_text(GTK_EDITABLE(config_folder
), 0, -1);
442 gtk_editable_insert_text(GTK_EDITABLE(config_folder
),
443 config
->clamd_config_folder
, strlen(config
->clamd_config_folder
), &newpos
);
445 else if (c
&& c
->ConfigType
== MANUAL
) {
446 /* deactivate automatic automatic configuration */
447 debug_print("Showing manual configuration and hiding automatic configuration\n");
448 clamav_show_config(c
);
453 gtk_entry_set_text(GTK_ENTRY(config_folder), config->clamd_config_folder);
454 // deactivate manual checkbox and blind host and port
455 debug_print("Showing automatic configuration and hiding manual configuration\n");
456 if (! clamd_config) {
457 clamd_config = clamd_config_new();
458 clamd_config->ConfigType = AUTOMATIC;
459 clamav_show_config(clamd_config);
460 clamd_config_free(clamd_config);
463 clamav_show_config(clamd_config);
466 page
->enable_clamav
= enable_clamav
;
467 /* page->enable_arc = enable_arc;*/
468 page
->max_size
= max_size
;
469 page
->recv_infected
= recv_infected
;
470 page
->save_folder
= save_folder
;
471 page
->config_type
= setting_type
;
472 page
->config_folder
= config_folder
;
473 page
->config_host
= config_host
;
474 page
->config_port
= config_port
;
475 page
->page
.widget
= vbox1
;
477 clamav_save_config();
480 static void clamav_destroy_widget_func(PrefsPage
*_page
)
482 debug_print("Destroying Clamd widget\n");
485 static void clamav_save_func(PrefsPage
*_page
)
487 struct ClamAvPage
*page
= (struct ClamAvPage
*) _page
;
488 ClamAvConfig
*config
;
490 debug_print("Saving Clamd Page\n");
492 config
= clamav_get_config();
494 config
->clamav_enable
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page
->enable_clamav
));
495 /* config->clamav_enable_arc = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->enable_arc));*/
497 config
->clamav_max_size
= gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(page
->max_size
));
498 config
->clamav_recv_infected
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page
->recv_infected
));
499 g_free(config
->clamav_save_folder
);
500 config
->clamav_save_folder
= gtk_editable_get_chars(GTK_EDITABLE(page
->save_folder
), 0, -1);
501 config
->clamd_config_type
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page
->config_type
));
502 g_free(config
->clamd_config_folder
);
503 config
->clamd_config_folder
= gtk_editable_get_chars(GTK_EDITABLE(page
->config_folder
), 0, -1);
504 g_free(config
->clamd_host
);
505 config
->clamd_host
= gtk_editable_get_chars(GTK_EDITABLE(page
->config_host
), 0, -1);
506 config
->clamd_port
= gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(page
->config_port
));
508 if (config
->clamav_enable
) {
509 Clamd_Stat status
= clamd_prepare();
512 g_warning("[New config] no socket information");
513 alertpanel_error(_("New config\nNo socket information.\nAntivirus disabled."));
516 g_warning("[New config] Clamd does not respond to ping");
517 alertpanel_warning(_("New config\nClamd does not respond to ping.\nIs clamd running?"));
523 clamav_save_config();
526 static struct ClamAvPage clamav_page
;
528 static void gtk_message_callback(gchar
*message
)
530 statusbar_print_all("%s", message
);
533 gint
clamav_gtk_init(void)
535 static gchar
*path
[3];
537 path
[0] = _("Plugins");
538 path
[1] = _("Clam AntiVirus");
541 clamav_page
.page
.path
= path
;
542 clamav_page
.page
.create_widget
= clamav_create_widget_func
;
543 clamav_page
.page
.destroy_widget
= clamav_destroy_widget_func
;
544 clamav_page
.page
.save_page
= clamav_save_func
;
545 clamav_page
.page
.weight
= 35.0;
547 prefs_gtk_register_page((PrefsPage
*) &clamav_page
);
548 clamav_set_message_callback(gtk_message_callback
);
550 debug_print("Clamd GTK plugin loaded\n");
554 void clamav_gtk_done(void)
556 prefs_gtk_unregister_page((PrefsPage
*) &clamav_page
);