fix CID 1596595: Resource leaks, and CID 1596594: (CHECKED_RETURN)
[claws.git] / src / plugins / rssyl / rssyl_cb_menu.c
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
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
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
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
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
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
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
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
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
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 }