2008-07-07 [colin] 3.5.0cvs18
[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 #include "inputdialog.h"
45
46 static void subscribe_newsgroup_cb(FolderView *folderview, guint action, GtkWidget *widget);
47 static void unsubscribe_newsgroup_cb(FolderView *folderview, guint action, GtkWidget *widget);
48 static void rename_newsgroup_cb(FolderView *folderview, guint action, GtkWidget *widget);
49 static void update_tree_cb(FolderView *folderview, guint action, GtkWidget *widget);
50 static void download_cb(FolderView *folderview, guint action, GtkWidget *widget);
51 static void sync_cb(FolderView *folderview, guint action, GtkWidget *widget);
52
53 static GtkItemFactoryEntry news_popup_entries[] =
54 {
55         {N_("/_Subscribe to newsgroup..."),     NULL, subscribe_newsgroup_cb,    0, NULL},
56         {N_("/_Unsubscribe newsgroup"),         NULL, unsubscribe_newsgroup_cb,  0, NULL},
57         {"/---",                                NULL, NULL,                      0, "<Separator>"},
58         {N_("/Synchronise"),                    NULL, sync_cb,          0, NULL},
59         {N_("/Down_load messages"),             NULL, download_cb,               0, NULL},
60         {N_("/_Rename folder..."),              NULL, rename_newsgroup_cb,       0, NULL},
61         {"/---",                                NULL, NULL,                      0, "<Separator>"},
62         {N_("/_Check for new messages"),        NULL, update_tree_cb,            0, NULL},
63         {"/---",                                NULL, NULL,                      0, "<Separator>"},
64 };
65
66 static void set_sensitivity(GtkItemFactory *factory, FolderItem *item);
67
68 static FolderViewPopup news_popup =
69 {
70         "news",
71         "<NewsFolder>",
72         NULL,
73         set_sensitivity
74 };
75
76 void news_gtk_init(void)
77 {
78         guint i, n_entries;
79
80         n_entries = sizeof(news_popup_entries) /
81                 sizeof(news_popup_entries[0]);
82         for (i = 0; i < n_entries; i++)
83                 news_popup.entries = g_slist_append(news_popup.entries, &news_popup_entries[i]);
84
85         folderview_register_popup(&news_popup);
86 }
87
88 static void set_sensitivity(GtkItemFactory *factory, FolderItem *item)
89 {
90         MainWindow *mainwin = mainwindow_get_mainwindow();
91         
92 #define SET_SENS(name, sens) \
93         menu_set_sensitive(factory, name, sens)
94
95         SET_SENS("/Subscribe to newsgroup...", 
96                  folder_item_parent(item) == NULL 
97                  && mainwin->lock_count == 0
98                  && news_folder_locked(item->folder) == 0);
99         SET_SENS("/Unsubscribe newsgroup",     
100                  folder_item_parent(item) != NULL 
101                  && mainwin->lock_count == 0
102                  && news_folder_locked(item->folder) == 0);
103         SET_SENS("/Check for new messages",    
104                  folder_item_parent(item) == NULL 
105                  && mainwin->lock_count == 0
106                  && news_folder_locked(item->folder) == 0);
107         SET_SENS("/Synchronise",    
108                  item ? (folder_item_parent(item) != NULL && folder_want_synchronise(item->folder))
109                          : FALSE);
110         SET_SENS("/Rename folder...", 
111                  folder_item_parent(item) != NULL 
112                  && mainwin->lock_count == 0
113                  && news_folder_locked(item->folder) == 0);
114 #undef SET_SENS
115 }
116
117 static void subscribe_newsgroup_cb(FolderView *folderview, guint action, GtkWidget *widget)
118 {
119         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
120         GtkCTreeNode *servernode, *node;
121         Folder *folder;
122         FolderItem *item;
123         FolderItem *rootitem;
124         FolderItem *newitem;
125         GSList *new_subscr;
126         GSList *cur;
127         GNode *gnode;
128         MainWindow *mainwin = mainwindow_get_mainwindow();
129         
130         if (!folderview->selected) return;
131
132         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
133         g_return_if_fail(item != NULL);
134
135         if (mainwin->lock_count || news_folder_locked(item->folder))
136                 return;
137
138         folder = item->folder;
139         g_return_if_fail(folder != NULL);
140         g_return_if_fail(FOLDER_TYPE(folder) == F_NEWS);
141         g_return_if_fail(folder->account != NULL);
142
143         if (GTK_CTREE_ROW(folderview->selected)->parent != NULL)
144                 servernode = GTK_CTREE_ROW(folderview->selected)->parent;
145         else
146                 servernode = folderview->selected;
147
148         rootitem = gtk_ctree_node_get_row_data(ctree, servernode);
149
150         new_subscr = grouplist_dialog(folder);
151
152         /* remove unsubscribed newsgroups */
153         for (gnode = folder->node->children; gnode != NULL; ) {
154                 GNode *next = gnode->next;
155
156                 item = FOLDER_ITEM(gnode->data);
157                 if (g_slist_find_custom(new_subscr, item->path,
158                                         (GCompareFunc)g_ascii_strcasecmp) != NULL) {
159                         gnode = next;
160                         continue;
161                 }
162
163                 node = gtk_ctree_find_by_row_data(ctree, servernode, item);
164                 if (!node) {
165                         gnode = next;
166                         continue;
167                 }
168
169                 if (folderview->opened == node) {
170                         summary_clear_all(folderview->summaryview);
171                         folderview->opened = NULL;
172                 }
173
174                 gtk_ctree_remove_node(ctree, node);
175                 folder_item_remove(item);
176
177                 gnode = next;
178         }
179
180         gtk_clist_freeze(GTK_CLIST(ctree));
181
182         /* add subscribed newsgroups */
183         for (cur = new_subscr; cur != NULL; cur = cur->next) {
184                 gchar *name = (gchar *)cur->data;
185                 FolderUpdateData hookdata;
186
187                 if (folder_find_child_item_by_name(rootitem, name) != NULL)
188                         continue;
189
190                 newitem = folder_item_new(folder, name, name);
191                 folder_item_append(rootitem, newitem);
192
193                 hookdata.folder = newitem->folder;
194                 hookdata.update_flags = FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDERITEM;
195                 hookdata.item = newitem;
196                 hooks_invoke(FOLDER_UPDATE_HOOKLIST, &hookdata);
197         }
198
199         gtk_clist_thaw(GTK_CLIST(ctree));
200
201         slist_free_strings(new_subscr);
202         g_slist_free(new_subscr);
203
204         folder_write_list();
205 }
206
207 static void unsubscribe_newsgroup_cb(FolderView *folderview, guint action,
208                                      GtkWidget *widget)
209 {
210         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
211         FolderItem *item;
212         gchar *name;
213         gchar *message;
214         gchar *old_id;
215         AlertValue avalue;
216         MainWindow *mainwin = mainwindow_get_mainwindow();
217         
218         if (!folderview->selected) return;
219
220         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
221         g_return_if_fail(item != NULL);
222
223         if (mainwin->lock_count || news_folder_locked(item->folder))
224                 return;
225
226         g_return_if_fail(item->folder != NULL);
227         g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS);
228         g_return_if_fail(item->folder->account != NULL);
229
230         old_id = folder_item_get_identifier(item);
231
232         name = trim_string(item->path, 32);
233         message = g_strdup_printf(_("Really unsubscribe newsgroup '%s'?"), name);
234         avalue = alertpanel_full(_("Unsubscribe newsgroup"), message,
235                                  GTK_STOCK_CANCEL, _("_Unsubscribe"), NULL, FALSE,
236                                  NULL, ALERT_WARNING, G_ALERTDEFAULT);
237         g_free(message);
238         g_free(name);
239         if (avalue != G_ALERTALTERNATE) return;
240
241         if (folderview->opened == folderview->selected) {
242                 summary_clear_all(folderview->summaryview);
243                 folderview->opened = NULL;
244         }
245
246         if(item->folder->klass->remove_folder(item->folder, item) < 0) {
247                 folder_item_scan(item);
248                 alertpanel_error(_("Can't remove the folder '%s'."), name);
249                 g_free(old_id);
250                 return;
251         }
252         
253         folder_write_list();
254         
255         prefs_filtering_delete_path(old_id);
256         g_free(old_id);
257 }
258
259 static FolderItem *find_child_by_name(FolderItem *item, const gchar *name)
260 {
261         GNode *node;
262         FolderItem *child;
263
264         for (node = item->node->children; node != NULL; node = node->next) {
265                 child = FOLDER_ITEM(node->data);
266                 if (strcmp2(child->name, name) == 0) {
267                         return child;
268                 }
269         }
270
271         return NULL;
272 }
273
274 static void rename_newsgroup_cb(FolderView *folderview, guint action,
275                                 GtkWidget *widget)
276 {
277         FolderItem *item;
278         gchar *new_folder;
279         gchar *name;
280         gchar *message;
281
282         item = folderview_get_selected_item(folderview);
283         g_return_if_fail(item != NULL);
284         g_return_if_fail(item->path != NULL);
285         g_return_if_fail(item->folder != NULL);
286
287         name = trim_string(item->name, 32);
288         message = g_strdup_printf(_("Input new name for '%s':"), name);
289         new_folder = input_dialog(_("Rename newsgroup folder"), message, item->name);
290         g_free(message);
291         g_free(name);
292
293         if (!new_folder) return;
294         AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
295
296         if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
297                 alertpanel_error(_("'%c' can't be included in folder name."),
298                                  G_DIR_SEPARATOR);
299                 return;
300         }
301
302         if (find_child_by_name(folder_item_parent(item), new_folder)) {
303                 name = trim_string(new_folder, 32);
304                 alertpanel_error(_("The folder '%s' already exists."), name);
305                 g_free(name);
306                 return;
307         }
308
309         if (folder_item_rename(item, new_folder) < 0) {
310                 alertpanel_error(_("The folder could not be renamed.\n"
311                                    "The new folder name is not allowed."));
312                 return;
313         }
314
315         folder_write_list();
316 }
317
318 static void update_tree_cb(FolderView *folderview, guint action,
319                            GtkWidget *widget)
320 {
321         FolderItem *item;
322         MainWindow *mainwin = mainwindow_get_mainwindow();
323         
324         item = folderview_get_selected_item(folderview);
325         g_return_if_fail(item != NULL);
326
327         if (mainwin->lock_count || news_folder_locked(item->folder))
328                 return;
329
330         summary_show(folderview->summaryview, NULL);
331
332         g_return_if_fail(item->folder != NULL);
333
334         folderview_check_new(item->folder);
335 }
336
337 static void sync_cb(FolderView *folderview, guint action,
338                            GtkWidget *widget)
339 {
340         FolderItem *item;
341
342         item = folderview_get_selected_item(folderview);
343         g_return_if_fail(item != NULL);
344         folder_synchronise(item->folder);
345 }
346
347 void news_gtk_synchronise(FolderItem *item, gint days)
348 {
349         MainWindow *mainwin = mainwindow_get_mainwindow();
350         FolderView *folderview = mainwin->folderview;
351         GSList *mlist;
352         GSList *cur;
353         gint num = 0;
354         gint total = 0;
355         time_t t = time(NULL);
356
357         g_return_if_fail(item != NULL);
358         g_return_if_fail(item->folder != NULL);
359
360         if (mainwin->lock_count || news_folder_locked(item->folder))
361                 return;
362
363         total = item->total_msgs;
364
365         main_window_cursor_wait(mainwin);
366         inc_lock();
367         main_window_lock(mainwin);
368         gtk_widget_set_sensitive(folderview->ctree, FALSE);
369         main_window_progress_on(mainwin);
370         GTK_EVENTS_FLUSH();
371
372         mlist = folder_item_get_msg_list(item);
373         for (cur = mlist; cur != NULL; cur = cur->next) {
374                 MsgInfo *msginfo = (MsgInfo *)cur->data;
375                 gint age = (t - msginfo->date_t) / (60*60*24);
376                 if (days == 0 || age <= days)
377                         folder_item_fetch_msg_full(msginfo->folder, msginfo->msgnum, TRUE, TRUE);
378                 statusbar_progress_all(num++,total, 100);
379                 if (num % 100 == 0)
380                         GTK_EVENTS_FLUSH();
381         }
382
383         statusbar_progress_all(0,0,0);
384         procmsg_msg_list_free(mlist);
385         folder_set_ui_func(item->folder, NULL, NULL);
386         main_window_progress_off(mainwin);
387         gtk_widget_set_sensitive(folderview->ctree, TRUE);
388         main_window_unlock(mainwin);
389         inc_unlock();
390         main_window_cursor_normal(mainwin);
391 }
392
393 static void download_cb(FolderView *folderview, guint action,
394                         GtkWidget *widget)
395 {
396         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
397         FolderItem *item;
398
399         if (!folderview->selected) return;
400
401         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
402         news_gtk_synchronise(item, 0);
403 }