Fixes Coverity CIDs: 1220388 1372362 1220222 1358399 1223756 1223757 1220305 1220269...
[claws.git] / src / plugins / rssyl / rssyl_feed_props.c
1 /*
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>
5  *
6  * - Plugin preferences
7  *
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.
12  *
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.
17  *
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.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #  include "config.h"
25 #endif
26
27 /* Global includes */
28 #include <glib.h>
29 #include <glib/gi18n.h>
30 #include <gdk/gdkkeysyms.h>
31
32 /* Claws Mail includes */
33 #include <mainwindow.h>
34 #include <prefs_gtk.h>
35
36 /* Local includes */
37 #include "rssyl.h"
38 #include "rssyl_feed.h"
39 #include "rssyl_feed_props.h"
40 #include "rssyl_prefs.h"
41 #include "rssyl_update_feed.h"
42
43 static void rssyl_gtk_prop_store(RFolderItem *ritem)
44 {
45         gchar *url, *auth_user, *auth_pass;
46         gint x, old_ri, old_fetch_comments;
47         gboolean use_default_ri = FALSE, keep_old = FALSE;
48         FolderItem *item;
49
50         g_return_if_fail(ritem != NULL);
51         g_return_if_fail(ritem->feedprop != NULL);
52         g_return_if_fail(ritem->url != NULL);
53
54         url = (gchar *)gtk_entry_get_text(GTK_ENTRY(ritem->feedprop->url));
55
56         if( strlen(url) && strcmp(ritem->url, url)) {
57                 rssyl_passwd_set(ritem, NULL);
58                 g_free(ritem->url);
59                 ritem->url = g_strdup(url);
60         }
61
62         ritem->auth->type = gtk_combo_box_get_active(GTK_COMBO_BOX(ritem->feedprop->auth_type));
63
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);
68                 }
69                 ritem->auth->username = g_strdup(auth_user);
70         }
71
72         auth_pass = (gchar *)gtk_entry_get_text(GTK_ENTRY(ritem->feedprop->auth_password));
73         rssyl_passwd_set(ritem, auth_pass);
74
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" ) );
80
81         /* Use default if checkbutton is set */
82         if( use_default_ri )
83                 x = rssyl_prefs_get()->refresh;
84         else
85                 x = gtk_spin_button_get_value_as_int(
86                                 GTK_SPIN_BUTTON(ritem->feedprop->refresh_interval) );
87
88         old_ri = ritem->refresh_interval;
89         ritem->refresh_interval = x;
90
91         /* Set timer for next automatic refresh, if needed. */
92         if( x > 0 ) {
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);
97                 }
98         } else
99                 ritem->refresh_id = 0;
100
101         old_fetch_comments = ritem->fetch_comments;
102         ritem->fetch_comments = gtk_toggle_button_get_active(
103                         GTK_TOGGLE_BUTTON(ritem->feedprop->fetch_comments));
104
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;
109         }
110         
111         ritem->fetch_comments_max_age = gtk_spin_button_get_value_as_int(
112                         GTK_SPIN_BUTTON(ritem->feedprop->fetch_comments_max_age));
113
114         keep_old = gtk_toggle_button_get_active(
115                         GTK_TOGGLE_BUTTON(ritem->feedprop->keep_old));
116         ritem->keep_old = keep_old;
117
118         ritem->silent_update =
119                 gtk_combo_box_get_active(GTK_COMBO_BOX(ritem->feedprop->silent_update));
120
121         ritem->write_heading = gtk_toggle_button_get_active(
122                         GTK_TOGGLE_BUTTON(ritem->feedprop->write_heading));
123
124         ritem->ignore_title_rename = gtk_toggle_button_get_active(
125                         GTK_TOGGLE_BUTTON(ritem->feedprop->ignore_title_rename));
126
127         ritem->ssl_verify_peer = gtk_toggle_button_get_active(
128                         GTK_TOGGLE_BUTTON(ritem->feedprop->ssl_verify_peer));
129
130         /* Store updated properties */
131         item = &ritem->item;
132         item->folder->klass->item_get_xml(item->folder, item);
133 }
134
135 static gboolean
136 rssyl_feedprop_togglebutton_toggled_cb(GtkToggleButton *tb,
137                 gpointer data)
138 {
139         gboolean active = gtk_toggle_button_get_active(tb);
140         RFeedProp *feedprop = (RFeedProp *)data;
141         GtkWidget *sb = NULL;
142
143         if( (GtkWidget *)tb == feedprop->default_refresh_interval ) {
144                 active = !active;
145                 sb = feedprop->refresh_interval;
146         } else if( (GtkWidget *)tb == feedprop->fetch_comments ) {
147                 sb = feedprop->fetch_comments_max_age;
148         }
149
150         g_return_val_if_fail(sb != NULL, FALSE);
151
152         gtk_widget_set_sensitive(sb, active);
153
154         return FALSE;
155 }
156
157 static void
158 rssyl_feedprop_auth_type_changed_cb(GtkComboBox *cb, gpointer data)
159 {
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);
164 }
165
166 static gboolean
167 rssyl_props_cancel_cb(GtkWidget *widget, gpointer data)
168 {
169         RFolderItem *ritem = (RFolderItem *)data;
170
171         debug_print("RSSyl: Cancel pressed\n");
172
173         gtk_widget_destroy(ritem->feedprop->window);
174
175         return FALSE;
176 }
177
178 static gboolean
179 rssyl_props_ok_cb(GtkWidget *widget, gpointer data)
180 {
181         RFolderItem *ritem = (RFolderItem *)data;
182
183         debug_print("RSSyl: OK pressed\n");
184         rssyl_gtk_prop_store(ritem);
185
186         gtk_widget_destroy(ritem->feedprop->window);
187
188         return FALSE;
189 }
190
191 static gboolean
192 rssyl_props_trim_cb(GtkWidget *widget, gpointer data)
193 {
194         RFolderItem *ritem = (RFolderItem *)data;
195         gboolean k = ritem->keep_old;
196
197         if( k )
198                 ritem->keep_old = FALSE;
199
200         rssyl_update_feed(ritem, FALSE);
201
202         if( k )
203                 ritem->keep_old = TRUE;
204
205         return FALSE;
206 }
207
208 static gboolean
209 rssyl_props_key_press_cb(GtkWidget *widget, GdkEventKey *event,
210                 gpointer data)
211 {
212         if (event) {
213                 switch (event->keyval) {
214                         case GDK_Escape:
215                                 rssyl_props_cancel_cb(widget, data);
216                                 return TRUE;
217                         case GDK_Return:
218                         case GDK_KP_Enter:
219                                 rssyl_props_ok_cb(widget, data);
220                                 return TRUE;
221                         default:
222                                 break;
223                 }
224         }
225
226         return FALSE;
227 }
228
229 void rssyl_gtk_prop(RFolderItem *ritem)
230 {
231         MainWindow *mainwin = mainwindow_get_mainwindow();
232         RFeedProp *feedprop;
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;
238         GtkObject *adj;
239         gint refresh;
240
241         g_return_if_fail(ritem != NULL);
242
243         feedprop = g_new0(RFeedProp, 1);
244
245         /**** Create required widgets ****/
246
247         /* Window */
248         feedprop->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
249
250         /* URL entry */
251         feedprop->url = gtk_entry_new();
252         gtk_entry_set_text(GTK_ENTRY(feedprop->url), ritem->url);
253
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),
258 #else
259         feedprop->auth_type = gtk_combo_box_text_new();
260         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->auth_type),
261 #endif
262                         _("No authentication"));
263 #if !GTK_CHECK_VERSION(2, 24, 0)
264         gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->auth_type),
265 #else
266         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->auth_type),
267 #endif
268                         _("HTTP Basic authentication"));
269         gtk_combo_box_set_active(GTK_COMBO_BOX(feedprop->auth_type),
270                         ritem->auth->type);
271
272         /* Auth username */
273         feedprop->auth_username = gtk_entry_new();
274         gtk_entry_set_text(GTK_ENTRY(feedprop->auth_username),
275                         ritem->auth->username);
276
277         /* Auth password */
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);
282         if (pwd != NULL) {
283                 memset(pwd, 0, strlen(pwd));
284                 g_free(pwd);
285         }
286
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);
293
294         if( ritem->refresh_interval >= 0 && !ritem->default_refresh_interval )
295                 refresh = ritem->refresh_interval;
296         else
297                 refresh = rssyl_prefs_get()->refresh;
298
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),
304                         ritem->keep_old);
305
306         /* "Trim" button */
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"));
310
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);
316
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),
321                         1, 0);
322
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),
327                         1, 0);
328
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),
333 #else
334         feedprop->silent_update = gtk_combo_box_text_new();
335         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->silent_update),
336 #endif
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),
340 #else
341         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->silent_update),
342 #endif
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),
346 #else
347         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->silent_update),
348 #endif
349                         _("Never mark it as new"));
350         gtk_combo_box_set_active(GTK_COMBO_BOX(feedprop->silent_update),
351                         ritem->silent_update);
352
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);
358
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."));
367
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);
373
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);
378
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);
382
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);
397
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);
402
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);
406
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),
411                         (gpointer)feedprop);
412         gtk_box_pack_start(GTK_BOX(inner_vbox), feedprop->fetch_comments, FALSE, FALSE, 0);
413
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);
430
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);
434
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);
446
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);
453
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);
457
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),
463                         (gpointer)feedprop);
464
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"),
476                         "</small>", NULL));
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);
480
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);
484
485         /* Buttonbox */
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);
491
492         /* Cancel button */
493         cancel_button = gtk_button_new();
494         gtk_container_add(GTK_CONTAINER(bbox), cancel_button);
495
496         cancel_align = gtk_alignment_new(0.5, 0.5, 0, 0);
497         gtk_container_add(GTK_CONTAINER(cancel_button), cancel_align);
498
499         cancel_hbox = gtk_hbox_new(FALSE, 2);
500         gtk_container_add(GTK_CONTAINER(cancel_align), cancel_hbox);
501
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);
505
506         cancel_label = gtk_label_new_with_mnemonic(_("_Cancel"));
507         gtk_box_pack_end(GTK_BOX(cancel_hbox), cancel_label, FALSE, FALSE, 0);
508
509         g_signal_connect(G_OBJECT(cancel_button), "clicked",
510                         G_CALLBACK(rssyl_props_cancel_cb), ritem);
511
512         /* OK button */
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 );
516
517         ok_align = gtk_alignment_new(0.5, 0.5, 0, 0);
518         gtk_container_add(GTK_CONTAINER(ok_button), ok_align);
519
520         ok_hbox = gtk_hbox_new(FALSE, 2);
521         gtk_container_add(GTK_CONTAINER(ok_align), ok_hbox);
522
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);
526
527         ok_label = gtk_label_new_with_mnemonic(_("_OK"));
528         gtk_box_pack_end(GTK_BOX(ok_hbox), ok_label, FALSE, FALSE, 0);
529
530         g_signal_connect(G_OBJECT(ok_button), "clicked",
531                         G_CALLBACK(rssyl_props_ok_cb), ritem);
532
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) );
539
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);
543
544         /* ...and voila! */
545         gtk_widget_show_all(feedprop->window);
546         gtk_widget_grab_default(ok_button);
547
548         /* Unselect the text in URL entry */
549         gtk_editable_select_region(GTK_EDITABLE(feedprop->url), 0, 0);
550
551         ritem->feedprop = feedprop;
552 }