b71bb79343caca598ab20e2782f3916480b6663f
[claws.git] / src / news_gtk.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2007 Hiroyuki Yamamoto & the Claws Mail Team
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
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include "defs.h"
25
26 #include <glib.h>
27 #include <glib/gi18n.h>
28
29 #include <gtk/gtk.h>
30
31 #include "utils.h"
32 #include "folder.h"
33 #include "folderview.h"
34 #include "menu.h"
35 #include "account.h"
36 #include "alertpanel.h"
37 #include "grouplistdialog.h"
38 #include "prefs_common.h"
39 #include "news_gtk.h"
40 #include "common/hooks.h"
41 #include "inc.h"
42 #include "news.h"
43 #include "statusbar.h"
44
45 static void subscribe_newsgroup_cb(FolderView *folderview, guint action, GtkWidget *widget);
46 static void unsubscribe_newsgroup_cb(FolderView *folderview, guint action, GtkWidget *widget);
47 static void update_tree_cb(FolderView *folderview, guint action, GtkWidget *widget);
48 static void download_cb(FolderView *folderview, guint action, GtkWidget *widget);
49 static void sync_cb(FolderView *folderview, guint action, GtkWidget *widget);
50
51 static GtkItemFactoryEntry news_popup_entries[] =
52 {
53         {N_("/_Subscribe to newsgroup..."),     NULL, subscribe_newsgroup_cb,    0, NULL},
54         {N_("/_Unsubscribe newsgroup"),         NULL, unsubscribe_newsgroup_cb,  0, NULL},
55         {"/---",                                NULL, NULL,                      0, "<Separator>"},
56         {N_("/Synchronise"),                    NULL, sync_cb,          0, NULL},
57         {N_("/Down_load messages"),             NULL, download_cb,               0, NULL},
58         {"/---",                                NULL, NULL,                      0, "<Separator>"},
59         {N_("/_Check for new messages"),        NULL, update_tree_cb,            0, NULL},
60         {"/---",                                NULL, NULL,                      0, "<Separator>"},
61 };
62
63 static void set_sensitivity(GtkItemFactory *factory, FolderItem *item);
64
65 static FolderViewPopup news_popup =
66 {
67         "news",
68         "<NewsFolder>",
69         NULL,
70         set_sensitivity
71 };
72
73 void news_gtk_init(void)
74 {
75         guint i, n_entries;
76
77         n_entries = sizeof(news_popup_entries) /
78                 sizeof(news_popup_entries[0]);
79         for (i = 0; i < n_entries; i++)
80                 news_popup.entries = g_slist_append(news_popup.entries, &news_popup_entries[i]);
81
82         folderview_register_popup(&news_popup);
83 }
84
85 static void set_sensitivity(GtkItemFactory *factory, FolderItem *item)
86 {
87         MainWindow *mainwin = mainwindow_get_mainwindow();
88         
89 #define SET_SENS(name, sens) \
90         menu_set_sensitive(factory, name, sens)
91
92         SET_SENS("/Subscribe to newsgroup...", 
93                  folder_item_parent(item) == NULL 
94                  && mainwin->lock_count == 0
95                  && news_folder_locked(item->folder) == 0);
96         SET_SENS("/Unsubscribe newsgroup",     
97                  folder_item_parent(item) != NULL 
98                  && mainwin->lock_count == 0
99                  && news_folder_locked(item->folder) == 0);
100         SET_SENS("/Check for new messages",    
101                  folder_item_parent(item) == NULL 
102                  && mainwin->lock_count == 0
103                  && news_folder_locked(item->folder) == 0);
104         SET_SENS("/Synchronise",    
105                  item ? (folder_item_parent(item) != NULL && folder_want_synchronise(item->folder))
106                          : FALSE);
107
108 #undef SET_SENS
109 }
110
111 static void subscribe_newsgroup_cb(FolderView *folderview, guint action, GtkWidget *widget)
112 {
113         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
114         GtkCTreeNode *servernode, *node;
115         Folder *folder;
116         FolderItem *item;
117         FolderItem *rootitem;
118         FolderItem *newitem;
119         GSList *new_subscr;
120         GSList *cur;
121         GNode *gnode;
122         MainWindow *mainwin = mainwindow_get_mainwindow();
123         
124         if (!folderview->selected) return;
125
126         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
127         g_return_if_fail(item != NULL);
128
129         if (mainwin->lock_count || news_folder_locked(item->folder))
130                 return;
131
132         folder = item->folder;
133         g_return_if_fail(folder != NULL);
134         g_return_if_fail(FOLDER_TYPE(folder) == F_NEWS);
135         g_return_if_fail(folder->account != NULL);
136
137         if (GTK_CTREE_ROW(folderview->selected)->parent != NULL)
138                 servernode = GTK_CTREE_ROW(folderview->selected)->parent;
139         else
140                 servernode = folderview->selected;
141
142         rootitem = gtk_ctree_node_get_row_data(ctree, servernode);
143
144         new_subscr = grouplist_dialog(folder);
145
146         /* remove unsubscribed newsgroups */
147         for (gnode = folder->node->children; gnode != NULL; ) {
148                 GNode *next = gnode->next;
149
150                 item = FOLDER_ITEM(gnode->data);
151                 if (g_slist_find_custom(new_subscr, item->path,
152                                         (GCompareFunc)g_ascii_strcasecmp) != NULL) {
153                         gnode = next;
154                         continue;
155                 }
156
157                 node = gtk_ctree_find_by_row_data(ctree, servernode, item);
158                 if (!node) {
159                         gnode = next;
160                         continue;
161                 }
162
163                 if (folderview->opened == node) {
164                         summary_clear_all(folderview->summaryview);
165                         folderview->opened = NULL;
166                 }
167
168                 gtk_ctree_remove_node(ctree, node);
169                 folder_item_remove(item);
170
171                 gnode = next;
172         }
173
174         gtk_clist_freeze(GTK_CLIST(ctree));
175
176         /* add subscribed newsgroups */
177         for (cur = new_subscr; cur != NULL; cur = cur->next) {
178                 gchar *name = (gchar *)cur->data;
179                 FolderUpdateData hookdata;
180
181                 if (folder_find_child_item_by_name(rootitem, name) != NULL)
182                         continue;
183
184                 newitem = folder_item_new(folder, name, name);
185                 folder_item_append(rootitem, newitem);
186
187                 hookdata.folder = newitem->folder;
188                 hookdata.update_flags = FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDERITEM;
189                 hookdata.item = newitem;
190                 hooks_invoke(FOLDER_UPDATE_HOOKLIST, &hookdata);
191         }
192
193         gtk_clist_thaw(GTK_CLIST(ctree));
194
195         slist_free_strings(new_subscr);
196         g_slist_free(new_subscr);
197
198         folder_write_list();
199 }
200
201 static void unsubscribe_newsgroup_cb(FolderView *folderview, guint action,
202                                      GtkWidget *widget)
203 {
204         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
205         FolderItem *item;
206         gchar *name;
207         gchar *message;
208         gchar *old_id;
209         AlertValue avalue;
210         MainWindow *mainwin = mainwindow_get_mainwindow();
211         
212         if (!folderview->selected) return;
213
214         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
215         g_return_if_fail(item != NULL);
216
217         if (mainwin->lock_count || news_folder_locked(item->folder))
218                 return;
219
220         g_return_if_fail(item->folder != NULL);
221         g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS);
222         g_return_if_fail(item->folder->account != NULL);
223
224         old_id = folder_item_get_identifier(item);
225
226         name = trim_string(item->path, 32);
227         message = g_strdup_printf(_("Really unsubscribe newsgroup '%s'?"), name);
228         avalue = alertpanel_full(_("Unsubscribe newsgroup"), message,
229                                  GTK_STOCK_CANCEL, _("_Unsubscribe"), NULL, FALSE,
230                                  NULL, ALERT_WARNING, G_ALERTDEFAULT);
231         g_free(message);
232         g_free(name);
233         if (avalue != G_ALERTALTERNATE) return;
234
235         if (folderview->opened == folderview->selected) {
236                 summary_clear_all(folderview->summaryview);
237                 folderview->opened = NULL;
238         }
239
240         if(item->folder->klass->remove_folder(item->folder, item) < 0) {
241                 folder_item_scan(item);
242                 alertpanel_error(_("Can't remove the folder '%s'."), name);
243                 g_free(old_id);
244                 return;
245         }
246         
247         folder_write_list();
248         
249         prefs_filtering_delete_path(old_id);
250         g_free(old_id);
251 }
252
253 static void update_tree_cb(FolderView *folderview, guint action,
254                            GtkWidget *widget)
255 {
256         FolderItem *item;
257         MainWindow *mainwin = mainwindow_get_mainwindow();
258         
259         item = folderview_get_selected_item(folderview);
260         g_return_if_fail(item != NULL);
261
262         if (mainwin->lock_count || news_folder_locked(item->folder))
263                 return;
264
265         summary_show(folderview->summaryview, NULL);
266
267         g_return_if_fail(item->folder != NULL);
268
269         folderview_check_new(item->folder);
270 }
271
272 static void sync_cb(FolderView *folderview, guint action,
273                            GtkWidget *widget)
274 {
275         FolderItem *item;
276
277         item = folderview_get_selected_item(folderview);
278         g_return_if_fail(item != NULL);
279         folder_synchronise(item->folder);
280 }
281
282 void news_gtk_synchronise(FolderItem *item, gint days)
283 {
284         MainWindow *mainwin = mainwindow_get_mainwindow();
285         FolderView *folderview = mainwin->folderview;
286         GSList *mlist;
287         GSList *cur;
288         gint num = 0;
289         gint total = 0;
290         time_t t = time(NULL);
291
292         g_return_if_fail(item != NULL);
293         g_return_if_fail(item->folder != NULL);
294
295         if (mainwin->lock_count || news_folder_locked(item->folder))
296                 return;
297
298         total = item->total_msgs;
299
300         main_window_cursor_wait(mainwin);
301         inc_lock();
302         main_window_lock(mainwin);
303         gtk_widget_set_sensitive(folderview->ctree, FALSE);
304         main_window_progress_on(mainwin);
305         GTK_EVENTS_FLUSH();
306
307         mlist = folder_item_get_msg_list(item);
308         for (cur = mlist; cur != NULL; cur = cur->next) {
309                 MsgInfo *msginfo = (MsgInfo *)cur->data;
310                 gint age = (t - msginfo->date_t) / (60*60*24);
311                 if (days == 0 || age <= days)
312                         folder_item_fetch_msg_full(msginfo->folder, msginfo->msgnum, TRUE, TRUE);
313                 statusbar_progress_all(num++,total, 100);
314                 if (num % 100 == 0)
315                         GTK_EVENTS_FLUSH();
316         }
317
318         statusbar_progress_all(0,0,0);
319         procmsg_msg_list_free(mlist);
320         folder_set_ui_func(item->folder, NULL, NULL);
321         main_window_progress_off(mainwin);
322         gtk_widget_set_sensitive(folderview->ctree, TRUE);
323         main_window_unlock(mainwin);
324         inc_unlock();
325         main_window_cursor_normal(mainwin);
326 }
327
328 static void download_cb(FolderView *folderview, guint action,
329                         GtkWidget *widget)
330 {
331         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
332         FolderItem *item;
333
334         if (!folderview->selected) return;
335
336         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
337         news_gtk_synchronise(item, 0);
338 }