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