1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2004 Hiroyuki Yamamoto
4  * This file (C) 2005-2018 Andrej Kacian <andrej@kacian.sk> and the
5  * Claws Mail team
6  *
7  * - callback handler functions for folderview rssyl context menu items
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27 
28 /* Global includes */
29 #include <glib.h>
30 #include <glib/gi18n.h>
31 #include <gtk/gtk.h>
32 
33 /* Claws Mail includes */
34 #include <folderview.h>
35 #include <alertpanel.h>
36 #include <gtk/inputdialog.h>
37 #include <prefs_common.h>
38 #include <folder_item_prefs.h>
39 #include <filesel.h>
40 #include <inc.h>
41 
42 /* Local includes */
43 #include "libfeed/parser_opml.h"
44 #include "rssyl_gtk.h"
45 #include "rssyl_feed.h"
46 #include "rssyl_feed_props.h"
47 #include "rssyl_update_feed.h"
48 #include "rssyl_subscribe.h"
49 #include "opml_import.h"
50 
rssyl_new_feed_cb(GtkAction * action,gpointer data)51 void rssyl_new_feed_cb(GtkAction *action,
52 		gpointer data)
53 {
54 	FolderView *folderview = (FolderView*)data;
55 	FolderItem *item;
56 	gchar *url;
57 
58 	debug_print("RSSyl: new_feed_cb\n");
59 
60 	g_return_if_fail(folderview->selected != NULL);
61 
62 	item = folderview_get_selected_item(folderview);
63 	g_return_if_fail(item != NULL);
64 	g_return_if_fail(item->folder != NULL);
65 
66 	url = input_dialog(_("Subscribe feed"),
67 			_("Input the URL of the news feed you wish to subscribe:"),
68 			"");
69 	if( url == NULL )	/* User cancelled */
70 		return;
71 
72 	rssyl_subscribe(item, url, RSSYL_SHOW_ERRORS | RSSYL_SHOW_RENAME_DIALOG);
73 
74 	g_free(url);
75 }
76 
rssyl_new_folder_cb(GtkAction * action,gpointer data)77 void rssyl_new_folder_cb(GtkAction *action,
78 		gpointer data)
79 {
80 	FolderView *folderview = (FolderView*)data;
81 	FolderItem *item;
82 	FolderItem *new_item;
83 	gchar *new_folder, *p, *tmp;
84 	gint i = 1;
85 
86 	if (!folderview->selected) return;
87 
88 	item = folderview_get_selected_item(folderview);
89 	g_return_if_fail(item != NULL);
90 	g_return_if_fail(item->folder != NULL);
91 
92 	new_folder = input_dialog(_("New folder"),
93 				  _("Input the name of new folder:"),
94 				  _("NewFolder"));
95 	if (!new_folder) return;
96 
97 	p = strchr(new_folder, G_DIR_SEPARATOR);
98 	if (p) {
99 		alertpanel_error(_("'%c' can't be used in folder name."),
100 				 G_DIR_SEPARATOR);
101 		g_free(new_folder);
102 		return;
103 	}
104 
105 	if (!folder_local_name_ok(new_folder)) {
106 		g_free(new_folder);
107 		return;
108 	}
109 
110 	/* Find an unused name for new folder */
111 	/* TODO: Perhaps stop after X attempts? */
112 	tmp = g_strdup(new_folder);
113 	while (folder_find_child_item_by_name(item, tmp)) {
114 		debug_print("RSSyl: Folder '%s' already exists, trying another name\n",
115 				new_folder);
116 		g_free(tmp);
117 		tmp = g_strdup_printf("%s__%d", new_folder, ++i);
118 	}
119 
120 	g_free(new_folder);
121 	new_folder = tmp;
122 
123 	new_item = folder_create_folder(item, new_folder);
124 	if (!new_item) {
125 		alertpanel_error(_("Can't create the folder '%s'."), new_folder);
126 		g_free(new_folder);
127 		return;
128 	}
129 
130 	g_free(new_folder);
131 
132 	folder_write_list();
133 }
134 
rssyl_remove_folder_cb(GtkAction * action,gpointer data)135 void rssyl_remove_folder_cb(GtkAction *action,
136 			     gpointer data)
137 {
138 	FolderView *folderview = (FolderView*)data;
139 	FolderItem *item, *opened;
140 	gchar *message, *name;
141 	AlertValue avalue;
142 	gchar *old_id;
143 
144 	item = folderview_get_selected_item(folderview);
145 	g_return_if_fail(item != NULL);
146 	g_return_if_fail(item->path != NULL);
147 	g_return_if_fail(item->folder != NULL);
148 	opened = folderview_get_opened_item(folderview);
149 
150 	name = trim_string(item->name, 32);
151 	AUTORELEASE_STR(name, {g_free(name); return;});
152 	message = g_strdup_printf
153 		(_("All folders and messages under '%s' will be permanently deleted. "
154 		   "Recovery will not be possible.\n\n"
155 		   "Do you really want to delete?"), name);
156 	avalue = alertpanel_full(_("Delete folder"), message,
157 				 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_FIRST, FALSE,
158 				 NULL, ALERT_WARNING);
159 	g_free(message);
160 	if (avalue != G_ALERTALTERNATE) return;
161 
162 	old_id = folder_item_get_identifier(item);
163 
164 	if (item == opened ||
165 			folder_is_child_of(item, opened)) {
166 		summary_clear_all(folderview->summaryview);
167 		folderview_close_opened(folderview, TRUE);
168 	}
169 
170 	if (item->folder->klass->remove_folder(item->folder, item) < 0) {
171 		folder_item_scan(item);
172 		alertpanel_error(_("Can't remove the folder '%s'."), name);
173 		g_free(old_id);
174 		return;
175 	}
176 
177 	folder_write_list();
178 
179 	prefs_filtering_delete_path(old_id);
180 	g_free(old_id);
181 
182 }
183 
rssyl_rename_cb(GtkAction * action,gpointer * data)184 void rssyl_rename_cb(GtkAction *action,
185 			     gpointer *data)
186 {
187 	FolderItem *item;
188 	gchar *new_folder;
189 	gchar *message;
190 	FolderView *folderview = (FolderView*)data;
191 	item = folderview_get_selected_item(folderview);
192 	g_return_if_fail(item != NULL);
193 	g_return_if_fail(item->path != NULL);
194 	g_return_if_fail(item->folder != NULL);
195 
196 	message = g_strdup_printf(_("Input new name for '%s':"), item->name);
197 	new_folder = input_dialog(_("Rename folder"), message, item->name);
198 	g_free(message);
199 	if (!new_folder) return;
200 
201 	if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
202 		alertpanel_error(_("'%c' can't be included in folder name."),
203 				 G_DIR_SEPARATOR);
204 		g_free(new_folder);
205 		return;
206 	}
207 
208 	if (!folder_local_name_ok(new_folder)) {
209 		g_free(new_folder);
210 		return;
211 	}
212 
213 	if (folder_find_child_item_by_name(folder_item_parent(item), new_folder)) {
214 		alertpanel_error(_("The folder '%s' already exists."), new_folder);
215 		g_free(new_folder);
216 		return;
217 	}
218 
219 	if (folder_item_rename(item, new_folder) < 0) {
220 		alertpanel_error(_("The folder could not be renamed.\n"
221 				   "The new folder name is not allowed."));
222 		g_free(new_folder);
223 		return;
224 	}
225 	g_free(new_folder);
226 
227 	folder_item_prefs_save_config(item);
228 	prefs_matcher_write_config();
229 	folder_write_list();
230 }
231 
rssyl_refresh_feed_cb(GtkAction * action,gpointer data)232 void rssyl_refresh_feed_cb(GtkAction *action,
233 		gpointer data)
234 {
235 	FolderView *folderview = (FolderView*)data;
236 	FolderItem *item = NULL;
237 	RFolderItem *ritem = NULL;
238 
239 	item = folderview_get_selected_item(folderview);
240 	g_return_if_fail(item != NULL);
241 	g_return_if_fail(item->folder != NULL);
242 
243 	ritem = (RFolderItem *)item;
244 
245 	/* Offline check */
246 	if( prefs_common_get_prefs()->work_offline &&
247 			!inc_offline_should_override(TRUE,
248 					ngettext("Claws Mail needs network access in order "
249 					"to update the feed.",
250 					"Claws Mail needs network access in order "
251 					"to update feeds.", 1))) {
252 		return;
253 	}
254 
255 	/* Update feed, displaying errors if any. */
256 	rssyl_update_feed(ritem, RSSYL_SHOW_ERRORS);
257 }
258 
rssyl_prop_cb(GtkAction * action,gpointer data)259 void rssyl_prop_cb(GtkAction *action, gpointer data)
260 {
261 	FolderView *folderview = (FolderView*)data;
262 	FolderItem *item;
263 	RFolderItem *ritem;
264 
265 	item = folderview_get_selected_item(folderview);
266 	g_return_if_fail(item != NULL);
267 	g_return_if_fail(item->folder != NULL);
268 
269 	debug_print("RSSyl: rssyl_prop_cb() for '%s'\n", item->name);
270 
271 	ritem = (RFolderItem *)item;
272 
273 	rssyl_gtk_prop(ritem);
274 }
275 
rssyl_update_all_cb(GtkAction * action,gpointer data)276 void rssyl_update_all_cb( GtkAction *action, gpointer data)
277 {
278 	FolderItem *item;
279 	FolderView *folderview = (FolderView*)data;
280 
281 	item = folderview_get_selected_item(folderview);
282 	g_return_if_fail(item != NULL);
283 	g_return_if_fail(item->folder != NULL);
284 
285 	debug_print("RSSyl: rssyl_update_all_cb(): clicked on '%s'\n", item->name);
286 
287 	if( item->folder->klass != rssyl_folder_get_class() ) {
288 		debug_print("RSSyl: this is not a RSSyl folder, returning\n");
289 		return;
290 	}
291 
292 	/* Offline check */
293 	if( prefs_common_get_prefs()->work_offline &&
294 			!inc_offline_should_override(TRUE,
295 					ngettext("Claws Mail needs network access in order "
296 					"to update the feed.",
297 					"Claws Mail needs network access in order "
298 					"to update feeds.", 1))) {
299 		return;
300 	}
301 
302 	rssyl_update_recursively(item);
303 }
304 
rssyl_remove_mailbox_cb(GtkAction * action,gpointer data)305 void rssyl_remove_mailbox_cb(GtkAction *action, gpointer data)
306 {
307 	FolderView *folderview = (FolderView *)data;
308 	FolderItem *item = NULL;
309 	gchar *n, *message;
310 	AlertValue avalue;
311 
312 	item = folderview_get_selected_item(folderview);
313 
314 	g_return_if_fail(item != NULL);
315 	g_return_if_fail(item->folder != NULL);
316 
317 	if( folder_item_parent(item) )
318 		return;
319 
320 	n = trim_string(item->folder->name, 32);
321 	message = g_strdup_printf(_("Really remove the feed tree `%s' ?\n"), n);
322 	avalue = alertpanel_full(_("Remove feed tree"), message,
323 				 GTK_STOCK_CANCEL, _("_Remove"), NULL, ALERTFOCUS_FIRST, FALSE,
324 				 NULL, ALERT_WARNING);
325 	g_free(message);
326 	g_free(n);
327 
328 	if( avalue != G_ALERTALTERNATE )
329 		return;
330 
331 	folderview_unselect(folderview);
332 	summary_clear_all(folderview->summaryview);
333 
334 	n = folder_item_get_path(item);
335 	if( remove_dir_recursive(n) < 0 ) {
336 		g_warning("can't remove directory '%s'", n);
337 		g_free(n);
338 		return;
339 	}
340 
341 	g_free(n);
342 	folder_destroy(item->folder);
343 }
344 
rssyl_import_feed_list_cb(GtkAction * action,gpointer data)345 void rssyl_import_feed_list_cb(GtkAction *action, gpointer data)
346 {
347 	FolderView *folderview = (FolderView *)data;
348 	FolderItem *item = NULL;
349 	gchar *path = NULL;
350 	OPMLImportCtx *ctx = NULL;
351 
352 	debug_print("RSSyl: import_feed_list_cb\n");
353 
354 	/* Ask user for a file to import */
355 	path = filesel_select_file_open_with_filter(
356 			_("Select an OPML file"), NULL, "*.opml");
357 	if (!is_file_exist(path)) {
358 		g_free(path);
359 		return;
360 	}
361 
362 	/* Find the destination folder for the import */
363 	g_return_if_fail(folderview->selected != NULL);
364 	item = folderview_get_selected_item(folderview);
365 	g_return_if_fail(item != NULL);
366 	g_return_if_fail(item->folder != NULL);
367 
368 	ctx = malloc( sizeof(OPMLImportCtx) );
369 	ctx->failures = 0;
370 	ctx->depth = rssyl_folder_depth(item) + 1;
371 	ctx->current = NULL;
372 	ctx->current = g_slist_append(ctx->current, item);
373 
374 	/* Start the whole shebang - call libfeed's OPML parser with correct
375 	 * user function */
376 	opml_process(path, rssyl_opml_import_func, (gpointer)ctx);
377 
378 	g_free(ctx);
379 }
380