1 /**
2  * @file subscription_dialog.c  property dialog for feed subscriptions
3  *
4  * Copyright (C) 2004-2017 Lars Windolf <lars.windolf@gmx.de>
5  * Copyright (C) 2004-2006 Nathan J. Conrad <t98502@users.sourceforge.net>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 
22 #include "ui/subscription_dialog.h"
23 
24 #include <libxml/uri.h>
25 #include <string.h>
26 
27 #include "common.h"
28 #include "conf.h"
29 #include "db.h"
30 #include "debug.h"
31 #include "feed.h"
32 #include "feedlist.h"
33 #include "node.h"
34 #include "update.h"
35 #include "ui/liferea_dialog.h"
36 #include "ui/ui_common.h"
37 #include "ui/feed_list_node.h"
38 
39 /* Note: these update interval literals should be kept in sync with the
40    ones in ui_prefs.c! */
41 
42 static const gchar * default_update_interval_unit_options[] = {
43 	N_("minutes"),
44 	N_("hours"),
45 	N_("days"),
46 	NULL
47 };
48 
49 /** common private structure for all subscription dialogs */
50 struct SubscriptionDialogPrivate {
51 
52 	subscriptionPtr subscription;	/** used only for "properties" dialog */
53 
54 	gint selector; /* Desiginates which fileselection dialog box is open.
55 				   Set to 'u' for source
56 				   Set to 'f' for filter */
57 
58 	GtkWidget *dialog;
59 	GtkWidget *feedNameEntry;
60 	GtkWidget *refreshInterval;
61 	GtkWidget *refreshIntervalUnit;
62 	GtkWidget *sourceEntry;
63 	GtkWidget *selectFile;
64 	GtkWidget *fileRadio;
65 	GtkWidget *urlRadio;
66 	GtkWidget *cmdRadio;
67 	GtkWidget *authcheckbox;
68 	GtkWidget *credTable;
69 	GtkWidget *username;
70 	GtkWidget *password;
71 };
72 
73 /* properties dialog */
74 
75 #define SUBSCRIPTION_PROP_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), SUBSCRIPTION_PROP_DIALOG_TYPE, SubscriptionDialogPrivate))
76 
77 static GObjectClass *parent_class = NULL;
78 
79 G_DEFINE_TYPE (SubscriptionPropDialog, subscription_prop_dialog, G_TYPE_OBJECT);
80 
81 static void
subscription_prop_dialog_finalize(GObject * object)82 subscription_prop_dialog_finalize (GObject *object)
83 {
84 	SubscriptionPropDialog *spd = SUBSCRIPTION_PROP_DIALOG (object);
85 
86 	gtk_widget_destroy (spd->priv->dialog);
87 
88 	G_OBJECT_CLASS (parent_class)->finalize (object);
89 }
90 
91 static void
subscription_prop_dialog_class_init(SubscriptionPropDialogClass * klass)92 subscription_prop_dialog_class_init (SubscriptionPropDialogClass *klass)
93 {
94 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
95 
96 	parent_class = g_type_class_peek_parent (klass);
97 
98 	object_class->finalize = subscription_prop_dialog_finalize;
99 
100 	g_type_class_add_private (object_class, sizeof(SubscriptionDialogPrivate));
101 }
102 
103 static gchar *
ui_subscription_create_url(gchar * url,gboolean auth,const gchar * username,const gchar * password)104 ui_subscription_create_url (gchar *url,
105                             gboolean auth,
106 			    const gchar *username,
107 			    const gchar *password)
108 {
109 	gchar	*source = NULL;
110 	gchar *str, *tmp2;
111 
112 	/* First, strip leading and trailing whitespace */
113 	str = g_strstrip(url);
114 
115 	/* Add http:// if needed */
116 	if (strstr(str, "://") == NULL) {
117 		tmp2 = g_strdup_printf("http://%s",str);
118 		g_free(str);
119 		str = tmp2;
120 	}
121 
122 	/* Add trailing / if needed */
123 	if (strstr(strstr(str, "://") + 3, "/") == NULL) {
124 		tmp2 = g_strdup_printf("%s/", str);
125 		g_free(str);
126 		str = tmp2;
127 	}
128 
129 	/* Use the values in the textboxes if also specified in the URL! */
130 	if(auth) {
131 		xmlURIPtr uri = xmlParseURI(str);
132 		if (uri != NULL) {
133 			xmlChar *sourceUrl;
134 			xmlFree(uri->user);
135 			uri->user = g_strdup_printf("%s:%s", username, password);
136 			sourceUrl = xmlSaveUri(uri);
137 			source = g_strdup((gchar *) sourceUrl);
138 			g_free(uri->user);
139 			uri->user = NULL;
140 			xmlFree(sourceUrl);
141 			xmlFreeURI(uri);
142 		} else
143 			source = g_strdup(str);
144 	} else {
145 		source = g_strdup(str);
146 	}
147 	g_free(str);
148 
149 	return source;
150 }
151 
152 static gchar *
ui_subscription_dialog_decode_source(SubscriptionDialogPrivate * ui_data)153 ui_subscription_dialog_decode_source (SubscriptionDialogPrivate *ui_data)
154 {
155 	gchar	*source = NULL;
156 
157 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ui_data->fileRadio)))
158 		source = g_strdup (gtk_entry_get_text (GTK_ENTRY (ui_data->sourceEntry)));
159 
160 	else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ui_data->urlRadio)))
161 		source = ui_subscription_create_url (g_strdup (gtk_entry_get_text (GTK_ENTRY (ui_data->sourceEntry))),
162 		                                     ui_data->authcheckbox &&
163 		                                     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ui_data->authcheckbox)),
164 		                                     ui_data->username?gtk_entry_get_text (GTK_ENTRY (ui_data->username)):NULL,
165 		                                     ui_data->password?gtk_entry_get_text (GTK_ENTRY (ui_data->password)):NULL);
166 	else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ui_data->cmdRadio)))
167 		source = g_strdup_printf ("|%s", gtk_entry_get_text (GTK_ENTRY (ui_data->sourceEntry)));
168 
169 	return source;
170 }
171 
172 static void
on_propdialog_response(GtkDialog * dialog,gint response_id,gpointer user_data)173 on_propdialog_response (GtkDialog *dialog,
174                         gint response_id,
175 			gpointer user_data)
176 {
177 	SubscriptionPropDialog *spd = (SubscriptionPropDialog *)user_data;
178 
179 	if(response_id == GTK_RESPONSE_OK) {
180 		gchar		*newSource;
181 		const gchar	*newFilter;
182 		gboolean	needsUpdate = FALSE;
183 		subscriptionPtr	subscription = spd->priv->subscription;
184 		nodePtr		node = spd->priv->subscription->node;
185 		feedPtr		feed = (feedPtr)node->data;
186 
187 		if (SUBSCRIPTION_TYPE(subscription) == feed_get_subscription_type ()) {
188 			/* "General" */
189 			node_set_title(node, gtk_entry_get_text(GTK_ENTRY(spd->priv->feedNameEntry)));
190 
191 			/* Source */
192 			newSource = ui_subscription_dialog_decode_source(spd->priv);
193 
194 			/* Filter handling */
195 			newFilter = gtk_entry_get_text(GTK_ENTRY(liferea_dialog_lookup(spd->priv->dialog, "filterEntry")));
196 			if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "filterCheckbox"))) &&
197 			   strcmp(newFilter,"")) { /* Maybe this should be a test to see if the file exists? */
198 				if(subscription_get_filter(subscription) == NULL ||
199 				   strcmp(newFilter, subscription_get_filter(subscription))) {
200 					subscription_set_filter(subscription, newFilter);
201 					needsUpdate = TRUE;
202 				}
203 			} else {
204 				if(subscription_get_filter(subscription)) {
205 					subscription_set_filter(subscription, NULL);
206 					needsUpdate = TRUE;
207 				}
208 			}
209 
210 			/* if URL has changed... */
211 			if(strcmp(newSource, subscription_get_source(subscription))) {
212 				subscription_set_source(subscription, newSource);
213 				needsUpdate = TRUE;
214 			}
215 			g_free(newSource);
216 
217 			/* Update interval handling */
218 			if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (GTK_WIDGET (dialog), "updateIntervalNever"))))
219 				subscription_set_update_interval (subscription, -2);
220 			else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (GTK_WIDGET (dialog), "updateIntervalDefault"))))
221 				subscription_set_update_interval (subscription, -1);
222 			else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (GTK_WIDGET (dialog), "updateIntervalSpecific")))) {
223 				gint intervalUnit = gtk_combo_box_get_active (GTK_COMBO_BOX (spd->priv->refreshIntervalUnit));
224 				gint updateInterval = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (spd->priv->refreshInterval));
225 				if (intervalUnit == 1)
226 					updateInterval *= 60;	/* hours */
227 				if (intervalUnit == 2)
228 					updateInterval *= 1440;	/* days */
229 
230 				subscription_set_update_interval (subscription, updateInterval);
231 				db_subscription_update (subscription);
232 			}
233 		}
234 
235 		/* "Archive" handling */
236 		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(GTK_WIDGET(dialog), "feedCacheDefault"))))
237 			feed->cacheLimit = CACHE_DEFAULT;
238 		else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(GTK_WIDGET(dialog), "feedCacheDisable"))))
239 			feed->cacheLimit = CACHE_DISABLE;
240 		else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(GTK_WIDGET(dialog), "feedCacheUnlimited"))))
241 			feed->cacheLimit = CACHE_UNLIMITED;
242 		else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(GTK_WIDGET(dialog), "feedCacheLimited"))))
243 			feed->cacheLimit = gtk_spin_button_get_value(GTK_SPIN_BUTTON(liferea_dialog_lookup(GTK_WIDGET(dialog), "cacheItemLimit")));
244 
245 		if (SUBSCRIPTION_TYPE(subscription) == feed_get_subscription_type ()) {
246 			/* "Download" Options */
247 			subscription->updateOptions->dontUseProxy = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(GTK_WIDGET(dialog), "dontUseProxyCheck")));
248 		}
249 
250 		/* "Advanced" options */
251 		feed->encAutoDownload = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (GTK_WIDGET (dialog), "enclosureDownloadCheck")));
252 		node->loadItemLink    = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (GTK_WIDGET (dialog), "loadItemLinkCheck")));
253 		feed->ignoreComments  = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (GTK_WIDGET (dialog), "ignoreCommentFeeds")));
254 		feed->markAsRead      = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (GTK_WIDGET (dialog), "markAsReadCheck")));
255 		feed->html5Extract    = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (GTK_WIDGET (dialog), "html5ExtractCheck")));
256 
257 		feed_list_node_update (node->id);
258 		feedlist_schedule_save ();
259 		db_subscription_update (subscription);
260 		if (needsUpdate)
261 			subscription_update (subscription, FEED_REQ_PRIORITY_HIGH);
262 	}
263 
264 	g_object_unref(spd);
265 }
266 
267 static void
on_feed_prop_filtercheck(GtkToggleButton * button,gpointer user_data)268 on_feed_prop_filtercheck (GtkToggleButton *button,
269                           gpointer user_data)
270 {
271 	SubscriptionDialogPrivate *ui_data = (SubscriptionDialogPrivate *)user_data;
272 
273 	gboolean filter = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (ui_data->dialog, "filterCheckbox")));
274 	gtk_widget_set_sensitive (liferea_dialog_lookup(ui_data->dialog, "filterbox"), filter);
275 }
276 
277 static void
ui_subscription_prop_enable_httpauth(SubscriptionDialogPrivate * ui_data,gboolean enable)278 ui_subscription_prop_enable_httpauth (SubscriptionDialogPrivate *ui_data,
279                                       gboolean enable)
280 {
281 	gboolean on;
282 
283 	if(ui_data->authcheckbox) {
284 		on = enable && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ui_data->authcheckbox));
285 		gtk_widget_set_sensitive(ui_data->authcheckbox,enable);
286 		gtk_widget_set_sensitive(ui_data->credTable,on);
287 	}
288 }
289 
290 static void
on_feed_prop_authcheck(GtkToggleButton * button,gpointer user_data)291 on_feed_prop_authcheck (GtkToggleButton *button,
292                         gpointer user_data)
293 {
294 	SubscriptionDialogPrivate *ui_data = (SubscriptionDialogPrivate *)user_data;
295 	gboolean url = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ui_data->urlRadio));
296 
297 	ui_subscription_prop_enable_httpauth(ui_data, url);
298 }
299 
300 static void
on_feed_prop_url_radio(GtkToggleButton * button,gpointer user_data)301 on_feed_prop_url_radio (GtkToggleButton *button,
302                         gpointer user_data)
303 {
304 	SubscriptionDialogPrivate *ui_data = (SubscriptionDialogPrivate *)user_data;
305 	gboolean url = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ui_data->urlRadio));
306 	gboolean file = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ui_data->fileRadio));
307 	gboolean cmd = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ui_data->cmdRadio));
308 
309 	ui_subscription_prop_enable_httpauth(ui_data, url);
310 	gtk_widget_set_sensitive(ui_data->selectFile, file || cmd);
311 }
312 
313 static void
on_selectfileok_clicked(const gchar * filename,gpointer user_data)314 on_selectfileok_clicked (const gchar *filename,
315                          gpointer user_data)
316 {
317 	SubscriptionDialogPrivate *ui_data = (SubscriptionDialogPrivate *)user_data;
318 	gchar *utfname;
319 
320 	if (!filename)
321 		return;
322 
323 	utfname = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
324 
325 	if (utfname) {
326 		if (ui_data->selector == 'u')
327 			gtk_entry_set_text (GTK_ENTRY (ui_data->sourceEntry), utfname);
328 		else
329 			gtk_entry_set_text (GTK_ENTRY (liferea_dialog_lookup (ui_data->dialog, "filterEntry")), utfname);
330 	}
331 
332 	g_free (utfname);
333 }
334 
335 static void
on_selectfile_pressed(GtkButton * button,gpointer user_data)336 on_selectfile_pressed (GtkButton *button,
337                        gpointer user_data)
338 {
339 	SubscriptionDialogPrivate *ui_data = (SubscriptionDialogPrivate *)user_data;
340 	const gchar *utfname;
341 	gchar *name;
342 
343 	if (GTK_WIDGET (button) == ui_data->selectFile) {
344 		ui_data->selector = 'u';
345 		utfname = gtk_entry_get_text (GTK_ENTRY (ui_data->sourceEntry));
346 	} else {
347 		ui_data->selector = 'f';
348 		utfname = gtk_entry_get_text (GTK_ENTRY (liferea_dialog_lookup (ui_data->dialog, "filterEntry")));
349 	}
350 
351 	name = g_filename_from_utf8 (utfname, -1, NULL, NULL, NULL);
352 	ui_choose_file (_("Choose File"), _("_Open"), FALSE, on_selectfileok_clicked, name, NULL, NULL, NULL, ui_data);
353 	g_free (name);
354 }
355 
356 static void
on_feed_prop_cache_radio(GtkToggleButton * button,gpointer user_data)357 on_feed_prop_cache_radio (GtkToggleButton *button,
358                           gpointer user_data)
359 {
360 	SubscriptionDialogPrivate *ui_data = (SubscriptionDialogPrivate *)user_data;
361 	gboolean limited = gtk_toggle_button_get_active(button);
362 
363 	gtk_widget_set_sensitive(liferea_dialog_lookup(GTK_WIDGET(ui_data->dialog), "cacheItemLimit"), limited);
364 }
365 
366 static void
on_feed_prop_update_radio(GtkToggleButton * button,gpointer user_data)367 on_feed_prop_update_radio (GtkToggleButton *button,
368                            gpointer user_data)
369 {
370 	SubscriptionDialogPrivate *priv = (SubscriptionDialogPrivate *) user_data;
371 	gboolean limited = gtk_toggle_button_get_active (button);
372 
373 	gtk_widget_set_sensitive (priv->refreshInterval, limited);
374 	gtk_widget_set_sensitive (priv->refreshIntervalUnit, limited);
375 }
376 
377 static void
subscription_prop_dialog_load(SubscriptionPropDialog * spd,subscriptionPtr subscription)378 subscription_prop_dialog_load (SubscriptionPropDialog *spd,
379                                subscriptionPtr subscription)
380 {
381 	gint 		interval;
382 	gint		default_update_interval;
383 	gint		defaultInterval, spinSetInterval;
384 	gchar 		*defaultIntervalStr;
385 	nodePtr		node = subscription->node;
386 	feedPtr		feed = (feedPtr)node->data;
387 
388 	spd->priv->subscription = subscription;
389 
390 	/* General */
391 	gtk_entry_set_text(GTK_ENTRY(spd->priv->feedNameEntry), node_get_title(node));
392 
393 	spd->priv->refreshInterval = liferea_dialog_lookup(spd->priv->dialog,"refreshIntervalSpinButton");
394 
395 	interval = subscription_get_update_interval(subscription);
396 	defaultInterval = subscription_get_default_update_interval(subscription);
397 	conf_get_int_value (DEFAULT_UPDATE_INTERVAL, &default_update_interval);
398 	spinSetInterval = defaultInterval > 0 ? defaultInterval : default_update_interval;
399 
400 	if (-2 >= interval) {
401 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup(spd->priv->dialog, "updateIntervalNever")), TRUE);
402 	} else if (-1 == interval) {
403 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup(spd->priv->dialog, "updateIntervalDefault")), TRUE);
404 	} else {
405 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup(spd->priv->dialog, "updateIntervalSpecific")), TRUE);
406 		spinSetInterval = interval;
407 	}
408 
409 	/* Set refresh interval spin button and combo box */
410 	if (spinSetInterval % 1440 == 0) {	/* days */
411 		gtk_combo_box_set_active (GTK_COMBO_BOX (spd->priv->refreshIntervalUnit), 2);
412 		spinSetInterval /= 1440;
413 	} else if (spinSetInterval % 60 == 0) {	/* hours */
414 		gtk_combo_box_set_active (GTK_COMBO_BOX (spd->priv->refreshIntervalUnit), 1);
415 		spinSetInterval /= 60;
416 	} else {
417 		gtk_combo_box_set_active (GTK_COMBO_BOX (spd->priv->refreshIntervalUnit), 0);
418 	}
419 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (spd->priv->refreshInterval), spinSetInterval);
420 
421 	gtk_widget_set_sensitive (spd->priv->refreshInterval, interval > 0);
422 	gtk_widget_set_sensitive (spd->priv->refreshIntervalUnit, interval > 0);
423 
424 	/* setup info label about default update interval */
425 	if(-1 != defaultInterval)
426 		defaultIntervalStr = g_strdup_printf(ngettext("The provider of this feed suggests an update interval of %d minute.",
427 		                                              "The provider of this feed suggests an update interval of %d minutes.",
428 		                                              defaultInterval), defaultInterval);
429 	else
430 		defaultIntervalStr = g_strdup(_("This feed specifies no default update interval."));
431 
432 	gtk_label_set_text(GTK_LABEL(liferea_dialog_lookup(spd->priv->dialog, "feedUpdateInfo")), defaultIntervalStr);
433 	g_free(defaultIntervalStr);
434 
435 	/* Source (only for feeds) */
436 	if (SUBSCRIPTION_TYPE(subscription) == feed_get_subscription_type ()) {
437 		if(subscription_get_source(subscription)[0] == '|') {
438 			gtk_entry_set_text(GTK_ENTRY(spd->priv->sourceEntry), &(subscription_get_source(subscription)[1]));
439 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(spd->priv->cmdRadio), TRUE);
440 			ui_subscription_prop_enable_httpauth(spd->priv, FALSE);
441 			gtk_widget_set_sensitive(spd->priv->selectFile, TRUE);
442 		} else if(strstr(subscription_get_source(subscription), "://") != NULL) {
443 			xmlURIPtr uri = xmlParseURI(subscription_get_source(subscription));
444 			xmlChar *parsedUrl;
445 			if(uri) {
446 				if(uri->user) {
447 					gchar *user = uri->user;
448 					gchar *pass = strstr(user, ":");
449 					if(pass) {
450 						pass[0] = '\0';
451 						pass++;
452 						gtk_entry_set_text(GTK_ENTRY(spd->priv->password), pass);
453 					}
454 					gtk_entry_set_text(GTK_ENTRY(spd->priv->username), user);
455 					xmlFree(uri->user);
456 					uri->user = NULL;
457 					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(spd->priv->authcheckbox), TRUE);
458 				}
459 				parsedUrl = xmlSaveUri(uri);
460 				gtk_entry_set_text(GTK_ENTRY(spd->priv->sourceEntry), (gchar *) parsedUrl);
461 				xmlFree(parsedUrl);
462 				xmlFreeURI(uri);
463 			} else {
464 				gtk_entry_set_text(GTK_ENTRY(spd->priv->sourceEntry), subscription_get_source(subscription));
465 			}
466 			ui_subscription_prop_enable_httpauth(spd->priv, TRUE);
467 			gtk_widget_set_sensitive(spd->priv->selectFile, FALSE);
468 		} else {
469 			/* File */
470 			gtk_entry_set_text(GTK_ENTRY(spd->priv->sourceEntry), subscription_get_source(subscription));
471 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(spd->priv->fileRadio), TRUE);
472 			ui_subscription_prop_enable_httpauth(spd->priv, FALSE);
473 			gtk_widget_set_sensitive(spd->priv->selectFile, TRUE);
474 		}
475 
476 		if(subscription_get_filter(subscription)) {
477 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "filterCheckbox")), TRUE);
478 			gtk_entry_set_text(GTK_ENTRY(liferea_dialog_lookup(spd->priv->dialog, "filterEntry")), subscription_get_filter(subscription));
479 		}
480 	}
481 
482 	/* Archive */
483 	if(feed->cacheLimit == CACHE_DISABLE) {
484 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "feedCacheDisable")), TRUE);
485 	} else if(feed->cacheLimit == CACHE_DEFAULT) {
486 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "feedCacheDefault")), TRUE);
487 	} else if(feed->cacheLimit == CACHE_UNLIMITED) {
488 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "feedCacheUnlimited")), TRUE);
489 	} else {
490 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "feedCacheLimited")), TRUE);
491 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "cacheItemLimit")), feed->cacheLimit);
492 	}
493 
494 	gtk_widget_set_sensitive(liferea_dialog_lookup(spd->priv->dialog, "cacheItemLimit"), feed->cacheLimit > 0);
495 
496 	on_feed_prop_filtercheck(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "filterCheckbox")), spd->priv);
497 
498 	/* Download */
499 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "dontUseProxyCheck")), subscription->updateOptions->dontUseProxy);
500 
501 	/* Advanced */
502 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (spd->priv->dialog, "enclosureDownloadCheck")), feed->encAutoDownload);
503 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (spd->priv->dialog, "loadItemLinkCheck")), node->loadItemLink);
504 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (spd->priv->dialog, "ignoreCommentFeeds")), feed->ignoreComments);
505 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (spd->priv->dialog, "markAsReadCheck")), feed->markAsRead);
506 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (spd->priv->dialog, "html5ExtractCheck")), feed->html5Extract);
507 
508 	/* Remove tabs we do not need... */
509 	if (SUBSCRIPTION_TYPE(subscription) != feed_get_subscription_type ()) {
510 		/* Remove "General", "Source" and "Download" tab */
511 		gtk_notebook_remove_page (GTK_NOTEBOOK (liferea_dialog_lookup (spd->priv->dialog, "subscriptionPropNotebook")), 0);
512 		gtk_notebook_remove_page (GTK_NOTEBOOK (liferea_dialog_lookup (spd->priv->dialog, "subscriptionPropNotebook")), 0);
513 		gtk_notebook_remove_page (GTK_NOTEBOOK (liferea_dialog_lookup (spd->priv->dialog, "subscriptionPropNotebook")), 1);
514 	}
515 }
516 
517 static void
subscription_prop_dialog_init(SubscriptionPropDialog * spd)518 subscription_prop_dialog_init (SubscriptionPropDialog *spd)
519 {
520 	GtkWidget	*propdialog;
521 
522 	spd->priv = SUBSCRIPTION_PROP_DIALOG_GET_PRIVATE (spd);
523 	spd->priv->dialog = propdialog = liferea_dialog_new ("properties");
524 
525 	/* set default update interval spin button and unit combo box */
526 	ui_common_setup_combo_menu (liferea_dialog_lookup (propdialog, "refreshIntervalUnitComboBox"),
527 	                            default_update_interval_unit_options,
528 	                            NULL /* no callback */,
529 	                            -1 /* default value */ );
530 
531 	spd->priv->feedNameEntry = liferea_dialog_lookup (propdialog, "feedNameEntry");
532 	spd->priv->refreshInterval = liferea_dialog_lookup (propdialog, "refreshIntervalSpinButton");
533 	spd->priv->refreshIntervalUnit = liferea_dialog_lookup (propdialog, "refreshIntervalUnitComboBox");
534 	spd->priv->sourceEntry = liferea_dialog_lookup (propdialog, "sourceEntry");
535 	spd->priv->selectFile = liferea_dialog_lookup (propdialog, "selectSourceFileButton");
536 	spd->priv->fileRadio = liferea_dialog_lookup (propdialog, "feed_loc_file");
537 	spd->priv->urlRadio = liferea_dialog_lookup (propdialog, "feed_loc_url");
538 	spd->priv->cmdRadio = liferea_dialog_lookup (propdialog, "feed_loc_command");
539 
540 	spd->priv->authcheckbox = liferea_dialog_lookup (propdialog, "HTTPauthCheck");
541 	spd->priv->username = liferea_dialog_lookup (propdialog, "usernameEntry");
542 	spd->priv->password = liferea_dialog_lookup (propdialog, "passwordEntry");
543 	spd->priv->credTable = liferea_dialog_lookup (propdialog, "httpAuthBox");
544 
545 	g_signal_connect (spd->priv->selectFile, "clicked", G_CALLBACK (on_selectfile_pressed), spd->priv);
546 	g_signal_connect (spd->priv->urlRadio, "toggled", G_CALLBACK (on_feed_prop_url_radio), spd->priv);
547 	g_signal_connect (spd->priv->fileRadio, "toggled", G_CALLBACK (on_feed_prop_url_radio), spd->priv);
548 	g_signal_connect (spd->priv->cmdRadio, "toggled", G_CALLBACK (on_feed_prop_url_radio), spd->priv);
549 	g_signal_connect (spd->priv->authcheckbox, "toggled", G_CALLBACK (on_feed_prop_authcheck), spd->priv);
550 
551 	g_signal_connect (liferea_dialog_lookup (propdialog, "filterCheckbox"), "toggled", G_CALLBACK (on_feed_prop_filtercheck), spd->priv);
552 	g_signal_connect (liferea_dialog_lookup (propdialog, "filterSelectFile"), "clicked", G_CALLBACK (on_selectfile_pressed), spd->priv);
553 	g_signal_connect (liferea_dialog_lookup (propdialog, "feedCacheLimited"), "toggled", G_CALLBACK (on_feed_prop_cache_radio), spd->priv);
554 	g_signal_connect (liferea_dialog_lookup (propdialog, "updateIntervalSpecific"), "toggled", G_CALLBACK(on_feed_prop_update_radio), spd->priv);
555 
556 	g_signal_connect (G_OBJECT (propdialog), "response", G_CALLBACK (on_propdialog_response), spd);
557 
558 	gtk_widget_show_all (propdialog);
559 }
560 
561 SubscriptionPropDialog *
subscription_prop_dialog_new(subscriptionPtr subscription)562 subscription_prop_dialog_new (subscriptionPtr subscription)
563 {
564 	SubscriptionPropDialog *spd;
565 
566 	spd = SUBSCRIPTION_PROP_DIALOG (g_object_new (SUBSCRIPTION_PROP_DIALOG_TYPE, NULL));
567 	subscription_prop_dialog_load(spd, subscription);
568 	return spd;
569 }
570 
571 /* complex "New" dialog */
572 
573 #define NEW_SUBSCRIPTION_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), NEW_SUBSCRIPTION_DIALOG_TYPE, SubscriptionDialogPrivate))
574 
575 G_DEFINE_TYPE (NewSubscriptionDialog, new_subscription_dialog, G_TYPE_OBJECT);
576 
577 static void
new_subscription_dialog_finalize(GObject * object)578 new_subscription_dialog_finalize (GObject *object)
579 {
580 	NewSubscriptionDialog *nsd = NEW_SUBSCRIPTION_DIALOG (object);
581 
582 	gtk_widget_destroy (nsd->priv->dialog);
583 
584 	G_OBJECT_CLASS (parent_class)->finalize (object);
585 }
586 
587 static void
new_subscription_dialog_class_init(NewSubscriptionDialogClass * klass)588 new_subscription_dialog_class_init (NewSubscriptionDialogClass *klass)
589 {
590 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
591 
592 	parent_class = g_type_class_peek_parent (klass);
593 
594 	object_class->finalize = new_subscription_dialog_finalize;
595 
596 	g_type_class_add_private (object_class, sizeof(SubscriptionDialogPrivate));
597 }
598 
599 static void
on_newdialog_response(GtkDialog * dialog,gint response_id,gpointer user_data)600 on_newdialog_response (GtkDialog *dialog, gint response_id, gpointer user_data)
601 {
602 	NewSubscriptionDialog *nsd = (NewSubscriptionDialog *)user_data;
603 
604 	if (response_id == GTK_RESPONSE_OK) {
605 		gchar *source = NULL;
606 		const gchar *filter = NULL;
607 		updateOptionsPtr options;
608 		nodePtr duplicateUrlNode = NULL;
609 
610 		/* Source */
611 		source = ui_subscription_dialog_decode_source (nsd->priv);
612 
613 		/* Filter handling */
614 		filter = gtk_entry_get_text (GTK_ENTRY (liferea_dialog_lookup (nsd->priv->dialog, "filterEntry")));
615 		if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (nsd->priv->dialog, "filterCheckbox"))) ||
616 		    !strcmp(filter,"")) { /* Maybe this should be a test to see if the file exists? */
617 			filter = NULL;
618 		}
619 
620 		options = g_new0 (struct updateOptions, 1);
621 		options->dontUseProxy = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup(GTK_WIDGET (dialog), "dontUseProxyCheck")));
622 
623 		duplicateUrlNode = feedlist_find_node (feedlist_get_root (), NODE_BY_URL, source);
624 		if (duplicateUrlNode == NULL) {
625 			feedlist_add_subscription (source, filter, options, FEED_REQ_PRIORITY_HIGH);
626 			g_free (source);
627 		} else {
628 			feed_list_node_add_duplicate_url_subscription (subscription_new (source, filter, options), duplicateUrlNode);
629 		}
630 	}
631 
632 	g_object_unref (nsd);
633 }
634 
635 static void
new_subscription_dialog_init(NewSubscriptionDialog * nsd)636 new_subscription_dialog_init (NewSubscriptionDialog *nsd)
637 {
638 	GtkWidget	*newdialog;
639 
640 	nsd->priv = NEW_SUBSCRIPTION_DIALOG_GET_PRIVATE (nsd);
641 	nsd->priv->dialog = newdialog = liferea_dialog_new ("new_subscription");
642 
643 	/* Setup source entry */
644 	nsd->priv->sourceEntry = liferea_dialog_lookup (newdialog,"sourceEntry");
645 	gtk_widget_grab_focus (GTK_WIDGET (nsd->priv->sourceEntry));
646 	gtk_entry_set_activates_default (GTK_ENTRY (nsd->priv->sourceEntry), TRUE);
647 
648 	nsd->priv->selectFile = liferea_dialog_lookup (newdialog,"selectSourceFileButton");
649 	g_signal_connect (nsd->priv->selectFile, "clicked", G_CALLBACK (on_selectfile_pressed), nsd->priv);
650 
651 	/* Feed location radio buttons */
652 	nsd->priv->fileRadio = liferea_dialog_lookup (newdialog, "feed_loc_file");
653 	nsd->priv->urlRadio = liferea_dialog_lookup (newdialog, "feed_loc_url");
654 	nsd->priv->cmdRadio = liferea_dialog_lookup (newdialog, "feed_loc_command");
655 
656 	g_signal_connect (nsd->priv->urlRadio, "toggled", G_CALLBACK (on_feed_prop_url_radio), nsd->priv);
657 	g_signal_connect (nsd->priv->fileRadio, "toggled", G_CALLBACK (on_feed_prop_url_radio), nsd->priv);
658 	g_signal_connect (nsd->priv->cmdRadio, "toggled", G_CALLBACK (on_feed_prop_url_radio), nsd->priv);
659 
660 	g_signal_connect (liferea_dialog_lookup (newdialog, "filterCheckbox"), "toggled", G_CALLBACK (on_feed_prop_filtercheck), nsd->priv);
661 	g_signal_connect (liferea_dialog_lookup (newdialog, "filterSelectFile"), "clicked", G_CALLBACK (on_selectfile_pressed), nsd->priv);
662 
663 	gtk_widget_grab_default (liferea_dialog_lookup (newdialog, "newfeedbtn"));
664 	g_signal_connect (G_OBJECT (newdialog), "response", G_CALLBACK (on_newdialog_response), nsd);
665 
666 	on_feed_prop_filtercheck (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (newdialog, "filterCheckbox")), nsd->priv);
667 	on_feed_prop_url_radio (GTK_TOGGLE_BUTTON (nsd->priv->urlRadio), nsd->priv);
668 
669 	gtk_widget_show_all (newdialog);
670 }
671 
672 static NewSubscriptionDialog *
ui_complex_subscription_dialog_new(void)673 ui_complex_subscription_dialog_new (void)
674 {
675 	NewSubscriptionDialog *nsd;
676 
677 	nsd = NEW_SUBSCRIPTION_DIALOG (g_object_new (NEW_SUBSCRIPTION_DIALOG_TYPE, NULL));
678 	return nsd;
679 }
680 
681 /* simple "New" dialog */
682 
683 #define SIMPLE_SUBSCRIPTION_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), SIMPLE_SUBSCRIPTION_DIALOG_TYPE, SubscriptionDialogPrivate))
684 
685 G_DEFINE_TYPE (SimpleSubscriptionDialog, simple_subscription_dialog, G_TYPE_OBJECT);
686 
687 static void
simple_subscription_dialog_finalize(GObject * object)688 simple_subscription_dialog_finalize (GObject *object)
689 {
690 	SimpleSubscriptionDialog *ssd = SIMPLE_SUBSCRIPTION_DIALOG (object);
691 
692 	gtk_widget_destroy (ssd->priv->dialog);
693 
694 	G_OBJECT_CLASS (parent_class)->finalize (object);
695 }
696 
697 static void
simple_subscription_dialog_class_init(SimpleSubscriptionDialogClass * klass)698 simple_subscription_dialog_class_init (SimpleSubscriptionDialogClass *klass)
699 {
700 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
701 
702 	parent_class = g_type_class_peek_parent (klass);
703 
704 	object_class->finalize = simple_subscription_dialog_finalize;
705 
706 	g_type_class_add_private (object_class, sizeof (SubscriptionDialogPrivate));
707 }
708 
709 static void
on_simple_newdialog_response(GtkDialog * dialog,gint response_id,gpointer user_data)710 on_simple_newdialog_response (GtkDialog *dialog, gint response_id, gpointer user_data)
711 {
712 	SimpleSubscriptionDialog *ssd = (SimpleSubscriptionDialog *) user_data;
713 	gchar *source = NULL;
714 	nodePtr duplicateUrlNode = NULL;
715 
716 	if (response_id == GTK_RESPONSE_OK) {
717 		source = ui_subscription_create_url (g_strdup (gtk_entry_get_text (GTK_ENTRY(ssd->priv->sourceEntry))),
718 		                                      FALSE /* auth */, NULL /* user */, NULL /* passwd */);
719 
720 		duplicateUrlNode = feedlist_find_node (feedlist_get_root (), NODE_BY_URL, source);
721 		if (duplicateUrlNode == NULL) {
722 			feedlist_add_subscription (source, NULL, NULL, FEED_REQ_PRIORITY_HIGH);
723 			g_free (source);
724 		} else {
725 			feed_list_node_add_duplicate_url_subscription (subscription_new (source, NULL, NULL), duplicateUrlNode);
726 		}
727 	}
728 
729 	if (response_id == GTK_RESPONSE_APPLY) /* misused for "Advanced" */
730 		ui_complex_subscription_dialog_new ();
731 
732 	g_object_unref (ssd);
733 }
734 
735 static void
simple_subscription_dialog_init(SimpleSubscriptionDialog * ssd)736 simple_subscription_dialog_init (SimpleSubscriptionDialog *ssd)
737 {
738 	GtkWidget	*newdialog;
739 
740 	ssd->priv = SIMPLE_SUBSCRIPTION_DIALOG_GET_PRIVATE (ssd);
741 	ssd->priv->dialog = newdialog = liferea_dialog_new ("simple_subscription");
742 
743 	/* Setup source entry */
744 	ssd->priv->sourceEntry = liferea_dialog_lookup (newdialog, "sourceEntry");
745 	gtk_widget_grab_focus (GTK_WIDGET (ssd->priv->sourceEntry));
746 	gtk_entry_set_activates_default (GTK_ENTRY (ssd->priv->sourceEntry), TRUE);
747 
748 	g_signal_connect (G_OBJECT (newdialog), "response",
749 	                  G_CALLBACK (on_simple_newdialog_response), ssd);
750 
751 	gtk_widget_show_all (newdialog);
752 }
753 
754 SimpleSubscriptionDialog *
subscription_dialog_new(void)755 subscription_dialog_new (void)
756 {
757 	SimpleSubscriptionDialog *ssd;
758 
759 	ssd = SIMPLE_SUBSCRIPTION_DIALOG (g_object_new (SIMPLE_SUBSCRIPTION_DIALOG_TYPE, NULL));
760 	return ssd;
761 }
762