2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001-2016 the Claws Mail team
4 * This file (C) 2005 Andrej Kacian <andrej@kacian.sk>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #include <glib/gi18n.h>
30 #include <gdk/gdkkeysyms.h>
32 /* Claws Mail includes */
33 #include <mainwindow.h>
34 #include <prefs_gtk.h>
38 #include "rssyl_feed.h"
39 #include "rssyl_feed_props.h"
40 #include "rssyl_prefs.h"
41 #include "rssyl_update_feed.h"
43 static void rssyl_gtk_prop_store(RFolderItem *ritem)
45 gchar *url, *auth_user, *auth_pass;
46 gint x, old_ri, old_fetch_comments;
47 gboolean use_default_ri = FALSE, keep_old = FALSE;
50 g_return_if_fail(ritem != NULL);
51 g_return_if_fail(ritem->feedprop != NULL);
52 g_return_if_fail(ritem->url != NULL);
54 url = (gchar *)gtk_entry_get_text(GTK_ENTRY(ritem->feedprop->url));
56 if( strlen(url) && strcmp(ritem->url, url)) {
57 rssyl_passwd_set(ritem, NULL);
59 ritem->url = g_strdup(url);
62 ritem->auth->type = gtk_combo_box_get_active(GTK_COMBO_BOX(ritem->feedprop->auth_type));
64 auth_user = (gchar *)gtk_entry_get_text(GTK_ENTRY(ritem->feedprop->auth_username));
65 if (auth_user != NULL) {
66 if (ritem->auth->username) {
67 g_free(ritem->auth->username);
69 ritem->auth->username = g_strdup(auth_user);
72 auth_pass = (gchar *)gtk_entry_get_text(GTK_ENTRY(ritem->feedprop->auth_password));
73 rssyl_passwd_set(ritem, auth_pass);
75 use_default_ri = gtk_toggle_button_get_active(
76 GTK_TOGGLE_BUTTON(ritem->feedprop->default_refresh_interval));
77 ritem->default_refresh_interval = use_default_ri;
78 debug_print("store: default refresh interval is %s\n",
79 ( use_default_ri ? "ON" : "OFF" ) );
81 /* Use default if checkbutton is set */
83 x = rssyl_prefs_get()->refresh;
85 x = gtk_spin_button_get_value_as_int(
86 GTK_SPIN_BUTTON(ritem->feedprop->refresh_interval) );
88 old_ri = ritem->refresh_interval;
89 ritem->refresh_interval = x;
91 /* Set timer for next automatic refresh, if needed. */
93 if( old_ri != x || ritem->refresh_id == 0 ) {
94 debug_print("RSSyl: GTK - refresh interval changed to %d , updating "
95 "timeout\n", ritem->refresh_interval);
96 rssyl_feed_start_refresh_timeout(ritem);
99 ritem->refresh_id = 0;
101 old_fetch_comments = ritem->fetch_comments;
102 ritem->fetch_comments = gtk_toggle_button_get_active(
103 GTK_TOGGLE_BUTTON(ritem->feedprop->fetch_comments));
105 if (!old_fetch_comments && ritem->fetch_comments) {
106 /* reset the RFolderItem's mtime to be sure we get all
107 * available comments */
108 ritem->item.mtime = 0;
111 ritem->fetch_comments_max_age = gtk_spin_button_get_value_as_int(
112 GTK_SPIN_BUTTON(ritem->feedprop->fetch_comments_max_age));
114 keep_old = gtk_toggle_button_get_active(
115 GTK_TOGGLE_BUTTON(ritem->feedprop->keep_old));
116 ritem->keep_old = keep_old;
118 ritem->silent_update =
119 gtk_combo_box_get_active(GTK_COMBO_BOX(ritem->feedprop->silent_update));
121 ritem->write_heading = gtk_toggle_button_get_active(
122 GTK_TOGGLE_BUTTON(ritem->feedprop->write_heading));
124 ritem->ignore_title_rename = gtk_toggle_button_get_active(
125 GTK_TOGGLE_BUTTON(ritem->feedprop->ignore_title_rename));
127 ritem->ssl_verify_peer = gtk_toggle_button_get_active(
128 GTK_TOGGLE_BUTTON(ritem->feedprop->ssl_verify_peer));
130 /* Store updated properties */
132 item->folder->klass->item_get_xml(item->folder, item);
136 rssyl_feedprop_togglebutton_toggled_cb(GtkToggleButton *tb,
139 gboolean active = gtk_toggle_button_get_active(tb);
140 RFeedProp *feedprop = (RFeedProp *)data;
141 GtkWidget *sb = NULL;
143 if( (GtkWidget *)tb == feedprop->default_refresh_interval ) {
145 sb = feedprop->refresh_interval;
146 } else if( (GtkWidget *)tb == feedprop->fetch_comments ) {
147 sb = feedprop->fetch_comments_max_age;
150 g_return_val_if_fail(sb != NULL, FALSE);
152 gtk_widget_set_sensitive(sb, active);
158 rssyl_feedprop_auth_type_changed_cb(GtkComboBox *cb, gpointer data)
160 RFeedProp *feedprop = (RFeedProp *)data;
161 gboolean enable = (FEED_AUTH_NONE != gtk_combo_box_get_active(cb));
162 gtk_widget_set_sensitive(GTK_WIDGET(feedprop->auth_username), enable);
163 gtk_widget_set_sensitive(GTK_WIDGET(feedprop->auth_password), enable);
167 rssyl_props_cancel_cb(GtkWidget *widget, gpointer data)
169 RFolderItem *ritem = (RFolderItem *)data;
171 debug_print("RSSyl: Cancel pressed\n");
173 gtk_widget_destroy(ritem->feedprop->window);
179 rssyl_props_ok_cb(GtkWidget *widget, gpointer data)
181 RFolderItem *ritem = (RFolderItem *)data;
183 debug_print("RSSyl: OK pressed\n");
184 rssyl_gtk_prop_store(ritem);
186 gtk_widget_destroy(ritem->feedprop->window);
192 rssyl_props_trim_cb(GtkWidget *widget, gpointer data)
194 RFolderItem *ritem = (RFolderItem *)data;
195 gboolean k = ritem->keep_old;
198 ritem->keep_old = FALSE;
200 rssyl_update_feed(ritem, FALSE);
203 ritem->keep_old = TRUE;
209 rssyl_props_key_press_cb(GtkWidget *widget, GdkEventKey *event,
213 switch (event->keyval) {
215 rssyl_props_cancel_cb(widget, data);
219 rssyl_props_ok_cb(widget, data);
229 void rssyl_gtk_prop(RFolderItem *ritem)
231 MainWindow *mainwin = mainwindow_get_mainwindow();
233 GtkWidget *vbox, *frame, *label, *hbox,
234 *inner_vbox, *auth_hbox, *auth_user_label, *auth_pass_label,
235 *bbox, *cancel_button, *cancel_align,
236 *cancel_hbox, *cancel_image, *cancel_label, *ok_button, *ok_align,
237 *ok_hbox, *ok_image, *ok_label, *trim_button, *silent_update_label;
241 g_return_if_fail(ritem != NULL);
243 feedprop = g_new0(RFeedProp, 1);
245 /**** Create required widgets ****/
248 feedprop->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
251 feedprop->url = gtk_entry_new();
252 gtk_entry_set_text(GTK_ENTRY(feedprop->url), ritem->url);
254 /* URL auth type combo */
255 #if !GTK_CHECK_VERSION(2, 24, 0)
256 feedprop->auth_type = gtk_combo_box_new_text();
257 gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->auth_type),
259 feedprop->auth_type = gtk_combo_box_text_new();
260 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->auth_type),
262 _("No authentication"));
263 #if !GTK_CHECK_VERSION(2, 24, 0)
264 gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->auth_type),
266 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->auth_type),
268 _("HTTP Basic authentication"));
269 gtk_combo_box_set_active(GTK_COMBO_BOX(feedprop->auth_type),
273 feedprop->auth_username = gtk_entry_new();
274 gtk_entry_set_text(GTK_ENTRY(feedprop->auth_username),
275 ritem->auth->username);
278 feedprop->auth_password = gtk_entry_new();
279 gtk_entry_set_visibility(GTK_ENTRY(feedprop->auth_password), FALSE);
280 gchar *pwd = rssyl_passwd_get(ritem);
281 gtk_entry_set_text(GTK_ENTRY(feedprop->auth_password), pwd);
283 memset(pwd, 0, strlen(pwd));
287 /* "Use default refresh interval" checkbutton */
288 feedprop->default_refresh_interval = gtk_check_button_new_with_mnemonic(
289 _("Use default refresh interval"));
290 gtk_toggle_button_set_active(
291 GTK_TOGGLE_BUTTON(feedprop->default_refresh_interval),
292 ritem->default_refresh_interval);
294 if( ritem->refresh_interval >= 0 && !ritem->default_refresh_interval )
295 refresh = ritem->refresh_interval;
297 refresh = rssyl_prefs_get()->refresh;
299 /* "Keep old items" checkbutton */
300 feedprop->keep_old = gtk_check_button_new_with_mnemonic(
301 _("Keep old items"));
302 gtk_toggle_button_set_active(
303 GTK_TOGGLE_BUTTON(feedprop->keep_old),
307 trim_button = gtk_button_new_with_mnemonic(_("_Trim"));
308 gtk_widget_set_tooltip_text(trim_button,
309 _("Update feed, deleting items which are no longer in the source feed"));
311 feedprop->fetch_comments = gtk_check_button_new_with_mnemonic(
312 _("Fetch comments if possible"));
313 gtk_toggle_button_set_active(
314 GTK_TOGGLE_BUTTON(feedprop->fetch_comments),
315 ritem->fetch_comments);
317 /* Fetch comments max age spinbutton */
318 adj = gtk_adjustment_new(ritem->fetch_comments_max_age,
319 -1, 100000, 1, 10, 0);
320 feedprop->fetch_comments_max_age = gtk_spin_button_new(GTK_ADJUSTMENT(adj),
323 /* Refresh interval spinbutton */
324 adj = gtk_adjustment_new(refresh,
325 0, 100000, 10, 100, 0);
326 feedprop->refresh_interval = gtk_spin_button_new(GTK_ADJUSTMENT(adj),
329 /* Silent update - combobox */
330 #if !GTK_CHECK_VERSION(2, 24, 0)
331 feedprop->silent_update = gtk_combo_box_new_text();
332 gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
334 feedprop->silent_update = gtk_combo_box_text_new();
335 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->silent_update),
337 _("Always mark it as new"));
338 #if !GTK_CHECK_VERSION(2, 24, 0)
339 gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
341 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->silent_update),
343 _("Only mark it as new if its text has changed"));
344 #if !GTK_CHECK_VERSION(2, 24, 0)
345 gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
347 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->silent_update),
349 _("Never mark it as new"));
350 gtk_combo_box_set_active(GTK_COMBO_BOX(feedprop->silent_update),
351 ritem->silent_update);
353 feedprop->write_heading = gtk_check_button_new_with_mnemonic(
354 _("Add item title to the top of message"));
355 gtk_toggle_button_set_active(
356 GTK_TOGGLE_BUTTON(feedprop->write_heading),
357 ritem->write_heading);
359 /* Ignore title rename - checkbox */
360 feedprop->ignore_title_rename = gtk_check_button_new_with_mnemonic(
361 _("Ignore title rename"));
362 gtk_toggle_button_set_active(
363 GTK_TOGGLE_BUTTON(feedprop->ignore_title_rename),
364 ritem->ignore_title_rename);
365 gtk_widget_set_tooltip_text(feedprop->ignore_title_rename,
366 _("Enable this to keep current folder name, even if feed author changes title of the feed."));
368 /* Verify SSL peer certificate */
369 feedprop->ssl_verify_peer = gtk_check_button_new_with_label(
370 _("Verify SSL/TLS certificate validity"));
371 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(feedprop->ssl_verify_peer),
372 ritem->ssl_verify_peer);
374 /* === Now pack all the widgets */
375 vbox = gtk_vbox_new(FALSE, 5);
376 gtk_container_add(GTK_CONTAINER(feedprop->window), vbox);
377 gtk_container_set_border_width(GTK_CONTAINER(feedprop->window), 10);
379 inner_vbox = gtk_vbox_new(FALSE, 7);
380 gtk_box_pack_start(GTK_BOX(inner_vbox), feedprop->url, FALSE, FALSE, 0);
381 gtk_entry_set_activates_default(GTK_ENTRY(feedprop->url), TRUE);
383 /* Auth combo + user (label + entry) + pass (label + entry) */
384 auth_hbox = gtk_hbox_new(FALSE, 7);
385 gtk_box_pack_start(GTK_BOX(auth_hbox), feedprop->auth_type, FALSE, FALSE, 0);
386 g_signal_connect(G_OBJECT(feedprop->auth_type), "changed",
387 G_CALLBACK(rssyl_feedprop_auth_type_changed_cb),
388 (gpointer) feedprop);
389 g_signal_emit_by_name(G_OBJECT(feedprop->auth_type), "changed");
390 auth_user_label = gtk_label_new(_("User name"));
391 gtk_box_pack_start(GTK_BOX(auth_hbox), auth_user_label, FALSE, FALSE, 0);
392 gtk_box_pack_start(GTK_BOX(auth_hbox), feedprop->auth_username, FALSE, FALSE, 0);
393 auth_pass_label = gtk_label_new(_("Password"));
394 gtk_box_pack_start(GTK_BOX(auth_hbox), auth_pass_label, FALSE, FALSE, 0);
395 gtk_box_pack_start(GTK_BOX(auth_hbox), feedprop->auth_password, FALSE, FALSE, 0);
396 gtk_box_pack_start(GTK_BOX(inner_vbox), auth_hbox, FALSE, FALSE, 0);
398 /* Verify SSL peer certificate - checkbutton */
399 gtk_box_pack_start(GTK_BOX(inner_vbox), feedprop->ssl_verify_peer, FALSE, FALSE, 0);
400 /* Ignore title rename - checkbutton */
401 gtk_box_pack_start(GTK_BOX(inner_vbox), feedprop->ignore_title_rename, FALSE, FALSE, 0);
403 PACK_FRAME (vbox, frame, _("Source URL"));
404 gtk_container_set_border_width(GTK_CONTAINER(inner_vbox), 7);
405 gtk_container_add(GTK_CONTAINER(frame), inner_vbox);
407 inner_vbox = gtk_vbox_new(FALSE, 7);
408 /* Fetch comments - checkbutton */
409 g_signal_connect(G_OBJECT(feedprop->fetch_comments), "toggled",
410 G_CALLBACK(rssyl_feedprop_togglebutton_toggled_cb),
412 gtk_box_pack_start(GTK_BOX(inner_vbox), feedprop->fetch_comments, FALSE, FALSE, 0);
414 hbox = gtk_hbox_new(FALSE, 7);
415 /* Fetch comments max age - label */
416 label = gtk_label_new(_("Fetch comments on posts aged less than"));
417 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
418 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
419 /* Fetch comments max age - spinbutton */
420 gtk_widget_set_sensitive(feedprop->fetch_comments_max_age,
421 ritem->fetch_comments);
422 gtk_box_pack_start(GTK_BOX(hbox), feedprop->fetch_comments_max_age, FALSE, FALSE, 0);
423 /* Fetch comments max age - units label */
424 label = gtk_label_new(g_strconcat(_("days"), "<small> ",
425 _("Set to -1 to fetch all comments"), "</small>", NULL));
426 gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
427 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
428 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
429 gtk_box_pack_start(GTK_BOX(inner_vbox), hbox, FALSE, FALSE, 0);
431 PACK_FRAME (vbox, frame, _("Comments"));
432 gtk_container_set_border_width(GTK_CONTAINER(inner_vbox), 7);
433 gtk_container_add(GTK_CONTAINER(frame), inner_vbox);
435 inner_vbox = gtk_vbox_new(FALSE, 7);
436 hbox = gtk_hbox_new(FALSE, 7);
437 /* Write heading - checkbox */
438 gtk_box_pack_start(GTK_BOX(inner_vbox), feedprop->write_heading, FALSE, FALSE, 0);
439 /* Keep old items - checkbutton */
440 gtk_box_pack_start(GTK_BOX(hbox), feedprop->keep_old, FALSE, FALSE, 0);
441 /* 'Trim' - button */
442 gtk_box_pack_start(GTK_BOX(hbox), trim_button, FALSE, FALSE, 0);
443 g_signal_connect(G_OBJECT(trim_button), "clicked",
444 G_CALLBACK(rssyl_props_trim_cb), ritem);
445 gtk_box_pack_start(GTK_BOX(inner_vbox), hbox, FALSE, FALSE, 0);
447 hbox = gtk_hbox_new(FALSE, 7);
448 /* Silent update - label */
449 silent_update_label = gtk_label_new(_("If an item changes"));
450 gtk_box_pack_start(GTK_BOX(hbox), silent_update_label, FALSE, FALSE, 0);
451 gtk_box_pack_start(GTK_BOX(hbox), feedprop->silent_update, FALSE, FALSE, 0);
452 gtk_box_pack_start(GTK_BOX(inner_vbox), hbox, FALSE, FALSE, 0);
454 PACK_FRAME (vbox, frame, _("Items"));
455 gtk_container_set_border_width(GTK_CONTAINER(inner_vbox), 7);
456 gtk_container_add(GTK_CONTAINER(frame), inner_vbox);
458 inner_vbox = gtk_vbox_new(FALSE, 7);
459 /* Use default refresh interval - checkbutton */
460 gtk_box_pack_start(GTK_BOX(inner_vbox), feedprop->default_refresh_interval, FALSE, FALSE, 0);
461 g_signal_connect(G_OBJECT(feedprop->default_refresh_interval), "toggled",
462 G_CALLBACK(rssyl_feedprop_togglebutton_toggled_cb),
465 hbox = gtk_hbox_new(FALSE, 7);
466 /* Refresh interval - label */
467 label = gtk_label_new(_("Refresh interval"));
468 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
469 /* Refresh interval - spinbutton */
470 gtk_widget_set_sensitive(feedprop->refresh_interval,
471 !ritem->default_refresh_interval);
472 gtk_box_pack_start(GTK_BOX(hbox), feedprop->refresh_interval, FALSE, FALSE, 0);
473 /* Refresh interval - units label */
474 label = gtk_label_new(g_strconcat(_("minutes"), "<small> ",
475 _("Set to 0 to disable automatic refreshing for this feed"),
477 gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
478 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
479 gtk_box_pack_start(GTK_BOX(inner_vbox), hbox, FALSE, FALSE, 0);
481 PACK_FRAME (vbox, frame, _("Refresh"));
482 gtk_container_set_border_width(GTK_CONTAINER(inner_vbox), 7);
483 gtk_container_add(GTK_CONTAINER(frame), inner_vbox);
486 bbox = gtk_hbutton_box_new();
487 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
488 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
489 gtk_box_set_spacing(GTK_BOX(bbox), 5);
490 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
493 cancel_button = gtk_button_new();
494 gtk_container_add(GTK_CONTAINER(bbox), cancel_button);
496 cancel_align = gtk_alignment_new(0.5, 0.5, 0, 0);
497 gtk_container_add(GTK_CONTAINER(cancel_button), cancel_align);
499 cancel_hbox = gtk_hbox_new(FALSE, 2);
500 gtk_container_add(GTK_CONTAINER(cancel_align), cancel_hbox);
502 cancel_image = gtk_image_new_from_stock(GTK_STOCK_CANCEL,
503 GTK_ICON_SIZE_BUTTON);
504 gtk_box_pack_start(GTK_BOX(cancel_hbox), cancel_image, FALSE, FALSE, 0);
506 cancel_label = gtk_label_new_with_mnemonic(_("_Cancel"));
507 gtk_box_pack_end(GTK_BOX(cancel_hbox), cancel_label, FALSE, FALSE, 0);
509 g_signal_connect(G_OBJECT(cancel_button), "clicked",
510 G_CALLBACK(rssyl_props_cancel_cb), ritem);
513 ok_button = gtk_button_new();
514 gtk_container_add(GTK_CONTAINER(bbox), ok_button);
515 GTK_WIDGET_SET_FLAGS(ok_button, GTK_CAN_DEFAULT );
517 ok_align = gtk_alignment_new(0.5, 0.5, 0, 0);
518 gtk_container_add(GTK_CONTAINER(ok_button), ok_align);
520 ok_hbox = gtk_hbox_new(FALSE, 2);
521 gtk_container_add(GTK_CONTAINER(ok_align), ok_hbox);
523 ok_image = gtk_image_new_from_stock(GTK_STOCK_OK,
524 GTK_ICON_SIZE_BUTTON);
525 gtk_box_pack_start(GTK_BOX(ok_hbox), ok_image, FALSE, FALSE, 0);
527 ok_label = gtk_label_new_with_mnemonic(_("_OK"));
528 gtk_box_pack_end(GTK_BOX(ok_hbox), ok_label, FALSE, FALSE, 0);
530 g_signal_connect(G_OBJECT(ok_button), "clicked",
531 G_CALLBACK(rssyl_props_ok_cb), ritem);
533 /* Set some misc. stuff */
534 gtk_window_set_title(GTK_WINDOW(feedprop->window),
535 g_strdup(_("Set feed properties")) );
536 gtk_window_set_modal(GTK_WINDOW(feedprop->window), TRUE);
537 gtk_window_set_transient_for(GTK_WINDOW(feedprop->window),
538 GTK_WINDOW(mainwin->window) );
540 /* Attach callbacks to handle Enter and Escape keys */
541 g_signal_connect(G_OBJECT(feedprop->window), "key_press_event",
542 G_CALLBACK(rssyl_props_key_press_cb), ritem);
545 gtk_widget_show_all(feedprop->window);
546 gtk_widget_grab_default(ok_button);
548 /* Unselect the text in URL entry */
549 gtk_editable_select_region(GTK_EDITABLE(feedprop->url), 0, 0);
551 ritem->feedprop = feedprop;