Merge branch 'master' of ssh+git://git.claws-mail.org/home/git/claws
[claws.git] / src / plugins / vcalendar / vcalendar.c
1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2007 Colin Leroy <colin@colino.net> and 
4  * the Claws Mail team
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #  include "config.h"
23 #include "claws-features.h"
24 #endif
25
26 #include <stddef.h>
27 #include <glib.h>
28 #include <glib/gi18n.h>
29
30 #include <ical.h>
31 #include <gtk/gtk.h>
32
33 #if USE_PTHREAD
34 #include "pthread.h"
35 #endif
36
37 #include "folder.h"
38 #include "folder_item_prefs.h"
39 #include "mimeview.h"
40 #include "utils.h"
41 #include "vcalendar.h"
42 #include "vcal_manager.h"
43 #include "vcal_folder.h"
44 #include "vcal_meeting_gtk.h"
45 #include "vcal_interface.h"
46 #include "prefs_account.h"
47 #include "prefs_common.h"
48 #include "menu.h"
49 #include "account.h"
50 #include "codeconv.h"
51 #include "xml.h"
52 #include "xmlprops.h"
53 #include "alertpanel.h"
54 #include "vcal_prefs.h"
55 #include "statusbar.h"
56 #include "timing.h"
57 #include "inc.h"
58
59 MimeViewerFactory vcal_viewer_factory;
60
61 static void create_meeting_from_message_cb_ui(GtkAction *action, gpointer data);
62
63 static GdkColor uri_color = {
64         (gulong)0,
65         (gushort)0,
66         (gushort)0,
67         (gushort)0
68 };
69
70 struct _VCalViewer
71 {
72         MimeViewer mimeviewer;
73
74         gchar     *file;
75         MimeInfo  *mimeinfo;
76         gchar     *tmpfile;
77         VCalEvent *event;
78
79         GtkWidget *scrolledwin;
80         GtkWidget *table;
81         GtkWidget *type;
82         GtkWidget *who;
83         GtkWidget *start;
84         GtkWidget *end;
85         GtkWidget *location;
86         GtkWidget *summary;
87         GtkWidget *description;
88         gchar     *url;
89         GtkWidget *answer;
90         GtkWidget *button;
91         GtkWidget *reedit;
92         GtkWidget *cancel;
93         GtkWidget *uribtn;
94         GtkWidget *attendees;
95         GtkWidget *unavail_box;
96 };
97
98 static GtkActionEntry vcalendar_main_menu[] = {{
99         "Message/CreateMeeting",
100         NULL, N_("Create meeting from message..."), NULL, NULL, G_CALLBACK(create_meeting_from_message_cb_ui)
101 }};
102
103 static void create_meeting_from_message_cb_ui(GtkAction *action, gpointer data)
104 {
105         MainWindow *mainwin = mainwindow_get_mainwindow();
106         SummaryView *summaryview = mainwin->summaryview;
107         GSList *msglist = summary_get_selected_msg_list(summaryview);
108         FolderItem *item = NULL;
109         GSList *cur;
110         gchar *msg;
111         gint total=0;
112
113         if (summary_is_locked(summaryview) || !msglist) {
114                 if (msglist)
115                         g_slist_free(msglist);
116                 return;
117         }
118         total = g_slist_length(msglist);
119         
120         msg = g_strdup_printf(_("You are about to create %d "
121                                        "meetings, one by one. Do you "
122                                        "want to continue?"), 
123                                        total);
124         if (total > 9
125         &&  alertpanel(_("Warning"), msg, GTK_STOCK_CANCEL, "+" GTK_STOCK_YES, NULL)
126             != G_ALERTALTERNATE) {
127                 g_free(msg);
128                 return;
129         }
130         g_free(msg);
131
132         main_window_cursor_wait(summaryview->mainwin);
133         gtk_cmclist_freeze(GTK_CMCLIST(summaryview->ctree));
134         folder_item_update_freeze();
135         inc_lock();
136
137         item = summaryview->folder_item;
138
139         STATUSBAR_PUSH(mainwin, _("Creating meeting..."));
140
141         for (cur = msglist; cur; cur = cur->next) {
142                 MsgInfo *msginfo = procmsg_msginfo_get_full_info((MsgInfo *)cur->data);
143                 VCalEvent *event = NULL;
144                 FILE *fp = NULL;
145
146                 if (MSG_IS_ENCRYPTED(msginfo->flags)) {
147                         fp = procmime_get_first_encrypted_text_content(msginfo);
148                 } else {
149                         fp = procmime_get_first_text_content(msginfo);
150                 }
151                 
152                 if (fp) {
153                         gchar uid[256];
154                         time_t t = time(NULL);
155                         time_t t2 = t+3600;
156                         gchar *org = NULL;
157                         gchar *orgname = NULL;
158                         gchar *summary = g_strdup(msginfo->subject ? msginfo->subject:_("no subject"));
159                         gchar *description = file_read_stream_to_str(fp);
160                         gchar *dtstart = g_strdup(icaltime_as_ical_string(icaltime_from_timet(t, FALSE)));
161                         gchar *dtend = g_strdup(icaltime_as_ical_string(icaltime_from_timet(t2, FALSE)));
162                         gchar *recur = NULL;
163                         gchar *tzid = g_strdup("UTC");
164                         gchar *url = NULL;
165                         gint method = ICAL_METHOD_REQUEST;
166                         gint sequence = 1;
167                         PrefsAccount *account = NULL;
168                         
169                         fclose(fp);
170
171                         if (item && item->prefs && item->prefs->enable_default_account)
172                                 account = account_find_from_id(item->prefs->default_account);
173
174                         if (!account) 
175                                 account = account_get_cur_account();
176                         
177                         if (!account)
178                                 goto bail;
179
180                         org = g_strdup(account->address);
181
182                         if (account->set_domain && account->domain) {
183                                 g_snprintf(uid, sizeof(uid), "%s", account->domain); 
184                         } else if (!strncmp(get_domain_name(), "localhost", strlen("localhost"))) {
185                                 g_snprintf(uid, sizeof(uid), "%s", 
186                                         strchr(account->address, '@') ?
187                                         strchr(account->address, '@')+1 :
188                                         account->address);
189                         } else {
190                                 g_snprintf(uid, sizeof(uid), "%s", "");
191                         }
192                         generate_msgid(uid, 255, account->address);
193                         
194                         event = vcal_manager_new_event(uid,
195                                         org, NULL, NULL/*location*/, summary, description, 
196                                         dtstart, dtend, recur, tzid, url, method, sequence, 
197                                         ICAL_VTODO_COMPONENT);
198                         
199                         /* hack to get default hours */
200                         g_free(event->dtstart);
201                         g_free(event->dtend);
202                         event->dtstart = NULL;
203                         event->dtend = NULL;
204
205                         vcal_meeting_create(event);
206                         vcal_manager_free_event(event);
207                         
208 bail:
209                         g_free(org);
210                         g_free(orgname);
211                         g_free(summary);
212                         g_free(description);
213                         g_free(dtstart);
214                         g_free(dtend);
215                         g_free(recur);
216                         g_free(tzid);
217                         g_free(url);
218                 }
219
220                 procmsg_msginfo_free(msginfo);
221         }
222
223         statusbar_progress_all(0,0,0);
224         STATUSBAR_POP(mainwin);
225         inc_unlock();
226         folder_item_update_thaw();
227         gtk_cmclist_thaw(GTK_CMCLIST(summaryview->ctree));
228         main_window_cursor_normal(summaryview->mainwin);
229         g_slist_free(msglist);
230 }
231
232 static gchar *get_tmpfile(VCalViewer *vcalviewer)
233 {
234         gchar *tmpfile = NULL;
235         
236         if (!vcalviewer->tmpfile) {
237                 tmpfile = procmime_get_tmp_file_name(vcalviewer->mimeinfo);
238                 debug_print("creating %s\n", tmpfile);
239
240                 if (procmime_get_part(tmpfile, vcalviewer->mimeinfo) < 0) {
241                         g_warning("Can't get mimepart file");   
242                         g_free(tmpfile);
243                         return NULL;
244                 }
245                 vcalviewer->tmpfile = tmpfile;
246         }
247         
248         return vcalviewer->tmpfile;
249 }
250
251 static GtkWidget *vcal_viewer_get_widget(MimeViewer *_mimeviewer)
252 {
253         VCalViewer *vcalviewer = (VCalViewer *) _mimeviewer;
254
255         debug_print("vcal_viewer_get_widget\n");
256         gtk_widget_show_all(vcalviewer->scrolledwin);
257         return vcalviewer->scrolledwin;
258 }
259
260 static void vcal_viewer_clear_viewer(MimeViewer *_mimeviewer)
261 {
262         VCalViewer *vcalviewer = (VCalViewer *) _mimeviewer;
263
264         debug_print("vcal_viewer_clear_viewer\n");
265
266         g_free(vcalviewer->file);
267         vcalviewer->file = NULL;
268         if (vcalviewer->tmpfile) {
269                 debug_print("unlinking %s\n", vcalviewer->tmpfile);
270                 g_unlink(vcalviewer->tmpfile);
271                 g_free(vcalviewer->tmpfile);
272                 vcalviewer->tmpfile = NULL;
273         }
274         vcalviewer->mimeinfo = NULL;
275 }
276
277 static VCalEvent *vcalviewer_get_component(const gchar *file, const gchar *charset)
278 {
279         gchar *compstr = NULL;
280         VCalEvent *event = NULL;
281         FILE *fp;
282         GByteArray *array;
283         gchar buf[BUFSIZ];
284         gint n_read;
285
286         g_return_val_if_fail(file != NULL, NULL);
287
288         if ((fp = g_fopen(file, "rb")) == NULL) {
289                 FILE_OP_ERROR(file, "g_fopen");
290                 return NULL;
291         }
292
293         array = g_byte_array_new();
294
295         while ((n_read = fread(buf, sizeof(gchar), sizeof(buf), fp)) > 0) {
296                 if (n_read < sizeof(buf) && ferror(fp))
297                         break;
298                 g_byte_array_append(array, (guchar *)buf, n_read);
299         }
300
301         if (ferror(fp)) {
302                 FILE_OP_ERROR("file stream", "fread");
303                 g_byte_array_free(array, TRUE);
304                 fclose(fp);
305                 return NULL;
306         }
307
308         buf[0] = '\0';
309         g_byte_array_append(array, (guchar *)buf, 1);
310         compstr = (gchar *)array->data;
311         g_byte_array_free(array, FALSE);
312
313         fclose(fp);     
314
315         if (compstr) {
316                 event = vcal_get_event_from_ical(compstr, charset);
317                 g_free(compstr);
318         }
319         
320         return event;
321 }
322
323 #define GTK_LABEL_SET_TEXT_TRIMMED(label, text) {               \
324         gchar *tmplbl = strretchomp(g_strdup(text));            \
325         gtk_label_set_text(label, tmplbl);                      \
326         g_free(tmplbl);                                         \
327 }
328
329 static void vcalviewer_answer_set_choices(VCalViewer *vcalviewer, VCalEvent *event, enum icalproperty_method method);
330
331 static void vcalviewer_reset(VCalViewer *vcalviewer) 
332 {
333         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), "-");
334         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->who), "-");
335         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->location), "-");
336         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->summary), "-");
337         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->description), "-");
338         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->start), "-");
339         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->end), "-");
340         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->attendees), "-");
341         g_free(vcalviewer->url);
342         vcalviewer->url = NULL;
343         gtk_widget_hide(vcalviewer->uribtn);
344         vcalviewer_answer_set_choices(vcalviewer, NULL, ICAL_METHOD_CANCEL);
345 }
346
347 static void vcalviewer_show_error(VCalViewer *vcalviewer, const gchar *msg)
348 {
349         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), msg);
350 }
351
352 static void vcalviewer_hide_error(VCalViewer *vcalviewer)
353 {
354         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), "-");
355 }
356
357 static void vcalviewer_show_unavailable(VCalViewer *vcalviewer, gboolean visi)
358 {
359         if (visi)
360                 gtk_widget_show_all(vcalviewer->unavail_box);
361         else
362                 gtk_widget_hide(vcalviewer->unavail_box);
363 }
364
365 static void vcalviewer_answer_set_choices(VCalViewer *vcalviewer, VCalEvent *event, enum icalproperty_method method)
366 {
367         int i = 0;
368         
369         gtk_widget_hide(vcalviewer->reedit);
370         gtk_widget_hide(vcalviewer->cancel);
371         gtk_widget_hide(vcalviewer->answer);
372         gtk_widget_hide(vcalviewer->button);
373
374         for (i = 0; i < 3; i++) 
375                 gtk_combo_box_remove_text(GTK_COMBO_BOX(vcalviewer->answer), 0);
376         
377         vcalviewer_show_unavailable(vcalviewer, FALSE);
378
379         if (method == ICAL_METHOD_REQUEST && event && !event->rec_occurence) {
380                 PrefsAccount *account = vcal_manager_get_account_from_event(event);
381                 
382                 if (!account)
383                         account = vcal_manager_get_account_from_event(vcalviewer->event);
384
385                 if (!account && event) {
386                         account = account_get_default();
387                         vcal_manager_update_answer(event, account->address, 
388                                         account->name,
389                                         ICAL_PARTSTAT_NEEDSACTION, 
390                                         ICAL_CUTYPE_INDIVIDUAL);
391                 }
392                 if (account) {
393                         gtk_combo_box_append_text(GTK_COMBO_BOX(vcalviewer->answer), _("Accept"));
394                         gtk_combo_box_append_text(GTK_COMBO_BOX(vcalviewer->answer), _("Tentatively accept"));
395                         gtk_combo_box_append_text(GTK_COMBO_BOX(vcalviewer->answer), _("Decline"));
396                         gtk_widget_set_sensitive(vcalviewer->answer, TRUE);
397                         gtk_widget_set_sensitive(vcalviewer->button, TRUE);
398                         gtk_widget_show(vcalviewer->answer);
399                         gtk_widget_show(vcalviewer->button);
400                 } else {
401                         gtk_combo_box_append_text(GTK_COMBO_BOX(vcalviewer->answer), "-");
402                         gtk_widget_set_sensitive(vcalviewer->answer, FALSE);
403                         gtk_widget_set_sensitive(vcalviewer->button, FALSE);
404                 }
405         } else {
406                 gtk_combo_box_append_text(GTK_COMBO_BOX(vcalviewer->answer), "-");
407                 gtk_widget_set_sensitive(vcalviewer->answer, FALSE);
408                 gtk_widget_set_sensitive(vcalviewer->button, FALSE);
409         }
410         gtk_combo_box_set_active(GTK_COMBO_BOX(vcalviewer->answer), 0);
411         
412         if (event && event->method == ICAL_METHOD_REQUEST) {
413                 PrefsAccount *account = vcal_manager_get_account_from_event(event);
414                 gchar *internal_ifb = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
415                                         "vcalendar", G_DIR_SEPARATOR_S, 
416                                         "internal.ifb", NULL);
417                 gchar *myfb = file_read_to_str(internal_ifb);
418                 g_free(internal_ifb);
419                 if (account) {
420                         enum icalparameter_partstat answer = 
421                                 vcal_manager_get_reply_for_attendee(event, account->address);
422                                 
423                         if (answer == ICAL_PARTSTAT_ACCEPTED)
424                                 gtk_combo_box_set_active(GTK_COMBO_BOX(vcalviewer->answer), 0);
425                         if (answer == ICAL_PARTSTAT_TENTATIVE)
426                                 gtk_combo_box_set_active(GTK_COMBO_BOX(vcalviewer->answer), 1);
427                         if (answer == ICAL_PARTSTAT_DECLINED)
428                                 gtk_combo_box_set_active(GTK_COMBO_BOX(vcalviewer->answer), 2);
429                         if (event->dtstart && event->dtend && myfb && *myfb 
430                         && answer != ICAL_PARTSTAT_ACCEPTED 
431                         && answer != ICAL_PARTSTAT_TENTATIVE) {
432                                 if (!attendee_available(NULL, event->dtstart, event->dtend, myfb))
433                                         vcalviewer_show_unavailable(vcalviewer, TRUE);
434                         }
435                 }
436                 g_free(myfb);
437         }
438
439         g_free(vcalviewer->url);
440         if (event && event->url && *(event->url)) {
441                 vcalviewer->url = g_strdup(event->url);
442                 gtk_widget_show(vcalviewer->uribtn);
443         } else {
444                 vcalviewer->url = NULL;
445                 gtk_widget_hide(vcalviewer->uribtn);
446         }
447 }
448
449 static FolderItem *vcalendar_get_current_item(void)
450 {
451         MainWindow *mainwin = mainwindow_get_mainwindow();
452         FolderItem *item = NULL;
453         Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
454         
455         if (mainwin) {
456                 item = mainwin->summaryview->folder_item;
457                 if (item->folder == folder)
458                         return item;
459                 else 
460                         return folder->inbox;
461         } else {
462                 return NULL;
463         }
464 }
465
466 void vcalviewer_display_event (VCalViewer *vcalviewer, VCalEvent *event)
467 {
468         GSList *list = NULL;
469         gchar *attendees = NULL;
470         gboolean mine = FALSE;
471         gchar *label = NULL;
472         gboolean save_evt = FALSE;
473         FolderItem *item = vcalendar_get_current_item();
474         if (!event)
475                 return;
476         if (!vcalviewer)
477                 return;
478
479 /* general */
480         if (event->type == ICAL_VTODO_COMPONENT) {
481
482                 label = g_strjoin(" ", _("You have a Todo item."),
483                                 _("Details follow:"), NULL);
484                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
485
486         } else if (event->method == ICAL_METHOD_REQUEST) {
487
488                 if (account_find_from_address(event->organizer, FALSE)) {
489                         label = g_strjoin(" ", _("You have created a meeting."),
490                                         _("Details follow:"), NULL);
491                         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
492                         mine = TRUE;
493                 } else {
494                         label = g_strjoin(" ", _("You have been invited to a meeting."),
495                                                 _("Details follow:"), NULL);
496                         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
497                 }
498
499         } else if (event->method == ICAL_METHOD_CANCEL) {
500
501                 label = g_strjoin(" ",
502                                 _("A meeting to which you had been invited has been cancelled."),
503                                 _("Details follow:"), NULL);
504                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
505                 save_evt = TRUE;
506                 vcalendar_refresh_folder_contents(item);
507         } else if (event->method == ICAL_METHOD_REPLY) {
508                 /* don't change label */
509         } else {
510
511                 label = g_strjoin(" ", _("You have been forwarded an appointment."),
512                                 _("Details follow:"), NULL);
513                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
514         }
515
516         g_free(label);
517
518 /* organizer */
519         if (event->orgname && *(event->orgname)
520         &&  event->organizer && *(event->organizer)) {
521                 gchar *addr = g_strconcat(event->orgname, " <", event->organizer, ">", NULL);
522                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->who), addr);
523                 g_free(addr);
524         } else if (event->organizer && *(event->organizer)) {
525                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->who), event->organizer);
526         } else {
527                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->who), "-");
528         }
529
530 /* location */
531         if (event->location && *(event->location)) {
532                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->location), event->location);
533         } else {
534                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->location), "-");
535         }
536
537 /* summary */
538         if (event->summary && *(event->summary)) {
539                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->summary), event->summary);
540         } else {
541                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->summary), "-");
542         }
543
544 /* description */
545         if (event->description && *(event->description)) {
546                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->description), event->description);
547         } else {
548                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->description), "-");
549         }
550
551 /* url */
552         g_free(vcalviewer->url);
553         if (event->url && *(event->url)) {
554                 vcalviewer->url = g_strdup(event->url);
555                 gtk_widget_show(vcalviewer->uribtn);
556         } else {
557                 vcalviewer->url = NULL;
558                 gtk_widget_hide(vcalviewer->uribtn);
559         }
560         
561 /* start */
562         if (event->start && *(event->start)) {
563                 if (event->recur && *(event->recur)) {
564                         gchar *tmp = g_strdup_printf(g_strconcat("%s <span weight=\"bold\">",
565                                                         _("(this event recurs)"),"</span>", NULL),
566                                         event->start);
567                         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->start), tmp);
568                         gtk_label_set_use_markup(GTK_LABEL(vcalviewer->start), TRUE);
569                         g_free(tmp);
570                 } else if (event->rec_occurence) {
571                         gchar *tmp = g_strdup_printf(g_strconcat("%s <span weight=\"bold\">",
572                                                         _("(this event is part of a recurring event)"),
573                                                         "</span>", NULL),
574                                         event->start);
575                         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->start), tmp);
576                         gtk_label_set_use_markup(GTK_LABEL(vcalviewer->start), TRUE);
577                         g_free(tmp);
578                 } else {
579                         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->start), event->start);
580                 }
581         } else {
582                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->start), "-");
583         }
584
585 /* end */
586         if (event->end && *(event->end)) {
587                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->end), event->end);
588         } else {
589                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->end), "-");
590         }
591         
592 /* attendees */
593         attendees = g_strdup("");
594         for (list = vcal_manager_get_answers_emails(event); 
595              list && list->data; list = list->next) {
596                 gchar *attendee = (gchar *)list->data;
597                 gchar *name = vcal_manager_get_attendee_name(event, attendee);
598                 gchar *ename = g_markup_printf_escaped("%s", name?name:"");
599                 gchar *eatt = g_markup_printf_escaped("%s", attendee);
600                 enum icalparameter_partstat acode = vcal_manager_get_reply_for_attendee(event, attendee);
601                 gchar *answer = vcal_manager_get_reply_text_for_attendee(event, attendee);
602                 gchar *type = vcal_manager_get_cutype_text_for_attendee(event, attendee);
603                 gchar *tmp = NULL;
604                 gint e_len, n_len;
605                 tmp = g_strdup_printf(
606                                 "%s%s&lt;%s&gt; (%s, <span%s>%s</span>)", 
607                                 (ename && *(ename))?ename:"",
608                                 (ename && *(ename))?" ":"",
609                                 (eatt && *(eatt))?eatt:"", 
610                                 (type && *(type))?type:"", 
611                                 (acode != ICAL_PARTSTAT_ACCEPTED ? " foreground=\"red\"":""),
612                                 (answer && *(answer))?answer:"");
613                 e_len = strlen(attendees);
614                 n_len = strlen(tmp);
615                 if (e_len) {
616                         attendees = g_realloc(attendees, e_len+n_len+2);
617                         *(attendees+e_len) = '\n';
618                         strcpy(attendees+e_len+1, tmp);
619                 } else {
620                         attendees = g_realloc(attendees, e_len+n_len+1);
621                         strcpy(attendees, tmp);
622                 }
623                 g_free(tmp);
624                 g_free(answer);
625                 g_free(type);
626                 g_free(name);
627                 g_free(ename);
628                 g_free(eatt);
629         }
630         
631         if (attendees && *(attendees)) {
632                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->attendees), attendees);
633         } else {
634                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->attendees), "-");
635         }
636         g_free(attendees);
637         gtk_label_set_use_markup(GTK_LABEL(vcalviewer->attendees), TRUE);
638         
639 /* buttons */
640         if (!mine)
641                 if (event->type != ICAL_VTODO_COMPONENT)
642                         vcalviewer_answer_set_choices(vcalviewer, event, event->method);
643                 else
644                         vcalviewer_answer_set_choices(vcalviewer, event, ICAL_METHOD_PUBLISH);
645         else {
646                 vcalviewer_answer_set_choices(vcalviewer, event, ICAL_METHOD_REPLY);
647                 gtk_widget_show(vcalviewer->reedit);
648                 gtk_widget_show(vcalviewer->cancel);
649         }
650
651 /* save if cancelled */
652         if (save_evt)
653                 vcal_manager_save_event(event, TRUE);
654 }
655
656 gchar *vcalviewer_get_uid_from_mimeinfo(MimeInfo *mimeinfo)
657 {
658         gchar *tmpfile = procmime_get_tmp_file_name(mimeinfo);
659         const gchar *charset = procmime_mimeinfo_get_parameter(mimeinfo, "charset");
660         gchar *compstr = NULL;
661         gchar *res = NULL;
662         VCalEvent *event = NULL;
663
664         if (!charset)
665                 charset = CS_WINDOWS_1252;
666         
667         if (!strcasecmp(charset, CS_ISO_8859_1))
668                 charset = CS_WINDOWS_1252;
669
670         if (procmime_get_part(tmpfile, mimeinfo) < 0) {
671                 g_warning("Can't get mimepart file");   
672                 g_free(tmpfile);
673                 return NULL;
674         }
675         
676         compstr = file_read_to_str(tmpfile);
677         
678         event = vcal_get_event_from_ical(compstr, charset);
679         if (event)
680                 res = g_strdup(event->uid);
681         
682         vcal_manager_free_event(event);
683
684         debug_print("got uid: %s\n", res);
685         return res;
686
687 }
688
689 static void vcalviewer_get_request_values(VCalViewer *vcalviewer, MimeInfo *mimeinfo, gboolean is_todo) 
690 {
691         VCalEvent *saved_event = NULL;
692         const gchar *charset = procmime_mimeinfo_get_parameter(mimeinfo, "charset");
693         const gchar *saveme =  procmime_mimeinfo_get_parameter(mimeinfo, "vcalsave");
694         
695         if (!vcalviewer->event)
696                 return;
697
698         if (!charset)
699                 charset = CS_WINDOWS_1252;
700         
701         if (!strcasecmp(charset, CS_ISO_8859_1))
702                 charset = CS_WINDOWS_1252;
703
704         /* see if we have it registered and more recent */
705         saved_event = vcal_manager_load_event(vcalviewer->event->uid);
706         if (saved_event && saved_event->sequence >= vcalviewer->event->sequence) {
707                 charset = CS_INTERNAL;
708                 saved_event->method = vcalviewer->event->method;
709                 vcalviewer_display_event(vcalviewer, saved_event);
710                 vcal_manager_free_event(saved_event);
711                 return;
712         } else if (saved_event) {
713                 vcal_manager_free_event(saved_event);
714         }
715
716         /* load it and register it */
717
718         if (!saveme || strcmp(saveme,"no"))
719                 vcal_manager_save_event(vcalviewer->event, FALSE);
720
721         vcalviewer_display_event(vcalviewer, vcalviewer->event);
722 }
723
724 static void vcalviewer_get_reply_values(VCalViewer *vcalviewer, MimeInfo *mimeinfo) 
725 {
726         const gchar *charset = procmime_mimeinfo_get_parameter(mimeinfo, "charset");
727         VCalEvent *saved_event = NULL;
728         gchar *attendee = NULL, *label = NULL;
729         Answer *answer = NULL;
730
731         if (!vcalviewer->event)
732                 return;
733
734         if (!charset)
735                 charset = CS_WINDOWS_1252;
736         
737         if (!strcasecmp(charset, CS_ISO_8859_1))
738                 charset = CS_WINDOWS_1252;
739
740         if (!vcalviewer->event->answers || g_slist_length(vcalviewer->event->answers) > 1) {
741                 g_warning("strange, no answers or more than one");
742         } 
743         
744         if (vcalviewer->event->answers) {
745                 answer = (Answer *)vcalviewer->event->answers->data;
746                 attendee = g_strdup(answer->attendee);
747         }
748                 
749
750         if (!answer) {
751                 label = g_strjoin(" ",
752                         _("You have received an answer to an unknown meeting proposal."),
753                         _("Details follow:"), NULL);
754                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
755         } else {
756                 label = g_strdup_printf(_("You have received an answer to a meeting proposal.\n"
757                         "%s has %s the invitation whose details follow:"),
758                         attendee, vcal_manager_answer_get_text(answer->answer));
759                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
760                 g_free(attendee);
761         }
762         g_free(label);
763
764         saved_event = vcal_manager_load_event(vcalviewer->event->uid);
765         if (saved_event && answer) {
766                 vcal_manager_update_answer(saved_event, 
767                         answer->attendee, answer->name, answer->answer, answer->cutype);
768                 vcal_manager_save_event(saved_event, TRUE);
769                 saved_event->method = vcalviewer->event->method;
770                 vcalviewer_display_event(vcalviewer, saved_event);
771                 vcal_manager_free_event(saved_event);
772                 return;
773         }
774
775         if (vcalviewer->event->organizer) {
776                 if (vcalviewer->event->orgname) {
777                         gchar *addr = g_strconcat(vcalviewer->event->orgname, " <", 
778                                         vcalviewer->event->organizer, ">", NULL);
779                         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->who), addr);
780                         g_free(addr);
781                 } else {
782                         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->who),
783                                 vcalviewer->event->organizer);
784                 }
785         } else {
786                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->who), "-");
787         }
788         
789         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->location),
790                 vcalviewer->event->location?vcalviewer->event->location:"-");
791
792         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->summary), 
793                 vcalviewer->event->summary?vcalviewer->event->summary:"-");
794
795         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->description), 
796                 vcalviewer->event->description?vcalviewer->event->description:"-");
797
798         g_free(vcalviewer->url);
799         if (vcalviewer->event->url) {
800                 vcalviewer->url = g_strdup(vcalviewer->event->url);
801                 gtk_widget_show(vcalviewer->uribtn);
802         } else {
803                 vcalviewer->url = NULL;
804                 gtk_widget_hide(vcalviewer->uribtn);
805         }
806
807         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->start), 
808                 vcalviewer->event->start?vcalviewer->event->start:"-");
809         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->end), 
810                 vcalviewer->event->end?vcalviewer->event->end:"-");
811
812         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->attendees), "-"); 
813
814         vcalviewer_answer_set_choices(vcalviewer, NULL, ICAL_METHOD_REPLY);
815 }
816
817 static void vcalviewer_get_event(VCalViewer *vcalviewer, MimeInfo *mimeinfo) 
818 {
819         gchar *tmpfile = get_tmpfile(vcalviewer);
820         const gchar *charset = procmime_mimeinfo_get_parameter(mimeinfo, "charset");
821
822         if (!charset)
823                 charset = CS_WINDOWS_1252;
824         
825         if (!strcasecmp(charset, CS_ISO_8859_1))
826                 charset = CS_WINDOWS_1252;
827         
828         if (vcalviewer->event) {
829                 vcal_manager_free_event(vcalviewer->event);
830                 vcalviewer->event = NULL;
831         }
832         
833         if (!tmpfile) {
834                 vcalviewer_reset(vcalviewer);
835                 vcalviewer_show_error(vcalviewer, _("Error - could not get the calendar MIME part."));
836                 return;
837         }
838
839         vcalviewer->event = vcalviewer_get_component(tmpfile, charset);
840         if (!vcalviewer->event) {
841                 vcalviewer_reset(vcalviewer);
842                 vcalviewer_show_error(vcalviewer, _("Error - no calendar part found."));
843                 return;
844         }
845         
846         if (vcalviewer->event->type == ICAL_VTODO_COMPONENT) {
847                 vcalviewer_get_request_values(vcalviewer, mimeinfo, TRUE);
848         } else if (vcalviewer->event->method == ICAL_METHOD_REQUEST ||
849                    vcalviewer->event->method == ICAL_METHOD_PUBLISH ||
850                    vcalviewer->event->method == ICAL_METHOD_CANCEL) {
851                 vcalviewer_get_request_values(vcalviewer, mimeinfo, FALSE);
852         } else if (vcalviewer->event->method == ICAL_METHOD_REPLY) {
853                 vcalviewer_get_reply_values(vcalviewer, mimeinfo);
854         } else {
855                 vcalviewer_reset(vcalviewer);
856                 vcalviewer_show_error(vcalviewer, _("Error - Unknown calendar component type."));
857         }
858 }
859
860 static VCalViewer *s_vcalviewer = NULL;
861
862 static void vcal_viewer_show_mimepart(MimeViewer *_mimeviewer, const gchar *file, MimeInfo *mimeinfo)
863 {
864         VCalViewer *vcalviewer = (VCalViewer *) _mimeviewer;
865         START_TIMING("");
866
867         s_vcalviewer = vcalviewer;
868
869         if (mimeinfo == NULL) {
870                 vcal_viewer_clear_viewer(_mimeviewer);
871                 END_TIMING();
872                 return;
873         }
874         debug_print("vcal_viewer_show_mimepart : %s\n", file);
875
876         vcal_viewer_clear_viewer(_mimeviewer);
877         gtk_widget_show_all(vcalviewer->scrolledwin);
878         g_free(vcalviewer->file);
879         vcalviewer->file = g_strdup(file);
880         vcalviewer->mimeinfo = mimeinfo;
881         vcalviewer_hide_error(vcalviewer);
882         vcalviewer_get_event(vcalviewer, mimeinfo);
883         GTK_EVENTS_FLUSH();
884         gtk_widget_set_size_request(vcalviewer->description, 
885                 vcalviewer->scrolledwin->allocation.width - 200, -1);
886         gtk_label_set_line_wrap(GTK_LABEL(vcalviewer->location), TRUE);
887         gtk_label_set_line_wrap(GTK_LABEL(vcalviewer->summary), TRUE);
888         gtk_label_set_line_wrap(GTK_LABEL(vcalviewer->description), TRUE);
889         gtk_label_set_line_wrap(GTK_LABEL(vcalviewer->attendees), FALSE);
890         
891         if (prefs_common_get_prefs()->textfont) {
892                 PangoFontDescription *font_desc;
893
894                 font_desc = pango_font_description_from_string
895                                                 (prefs_common_get_prefs()->textfont);
896                 if (font_desc) {
897                         gtk_widget_modify_font(
898                                 vcalviewer->description, font_desc);
899                         pango_font_description_free(font_desc);
900                 }
901         }
902         END_TIMING();   
903 }
904
905 void vcalviewer_reload(FolderItem *item)
906 {
907         if (s_vcalviewer) {
908                 MainWindow *mainwin = mainwindow_get_mainwindow();
909                 Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
910
911                 folder_item_scan(item);
912                 if (mainwin && mainwin->summaryview->folder_item) {
913                         FolderItem *cur = mainwin->summaryview->folder_item;
914                         if (cur->folder == folder)
915                                 folder_item_scan(cur);
916                 }
917                 if (mainwin && mainwin->summaryview->folder_item == item) {
918                         debug_print("reload: %p, %p\n", (MimeViewer *)s_vcalviewer, s_vcalviewer->mimeinfo);
919                         summary_redisplay_msg(mainwin->summaryview);
920                 }
921         }
922 }
923
924 static void vcal_viewer_destroy_viewer(MimeViewer *_mimeviewer)
925 {
926         VCalViewer *vcalviewer = (VCalViewer *) _mimeviewer;
927
928         debug_print("vcal_viewer_destroy_viewer\n");
929
930         if (s_vcalviewer == vcalviewer)
931                 s_vcalviewer = NULL;
932         vcal_viewer_clear_viewer(_mimeviewer);
933         g_free(vcalviewer);
934 }
935
936 static gboolean vcalviewer_reedit_cb(GtkButton *widget, gpointer data)
937 {
938         VCalViewer *vcalviewer = (VCalViewer *)data;
939         gchar * uid = vcalviewer_get_uid_from_mimeinfo(vcalviewer->mimeinfo);
940         VCalEvent *event = NULL;
941         
942         s_vcalviewer = vcalviewer;
943         /* see if we have it registered and more recent */
944         event = vcal_manager_load_event(uid);
945         vcal_meeting_create(event);
946         vcal_manager_free_event(event);
947         return TRUE;
948 }
949
950 static gboolean vcalviewer_uribtn_cb(GtkButton *widget, gpointer data)
951 {
952         VCalViewer *vcalviewer = (VCalViewer *)data;
953
954         if (vcalviewer->url)
955                 open_uri(vcalviewer->url, prefs_common_get_uri_cmd());
956
957         return TRUE;
958 }
959
960 void vcalendar_refresh_folder_contents(FolderItem *item)
961 {
962         Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
963         if (folder && item->folder == folder) {
964                 MainWindow *mainwin = mainwindow_get_mainwindow();
965                 folder_item_scan(item);
966                 if (mainwin->summaryview->folder_item == item) {
967                         summary_show(mainwin->summaryview, item);
968                 }
969         }
970 }
971
972 static void send_cancel_notify_toggled_cb(GtkToggleButton *button, gboolean *data)
973 {
974         *data = gtk_toggle_button_get_active(button);
975 }
976
977 void vcalendar_cancel_meeting(FolderItem *item, const gchar *uid)
978 {
979         VCalEvent *event = NULL;
980         VCalMeeting *meet = NULL;
981         gchar *file = NULL;
982         gint val = 0;
983         Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
984         gboolean redisp = FALSE;
985         GtkWidget *send_notify_chkbtn = gtk_check_button_new_with_label(_("Send a notification to the attendees"));
986         gboolean send_notify = TRUE;
987
988         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(send_notify_chkbtn), TRUE);
989         gtk_widget_show(send_notify_chkbtn);
990         g_signal_connect(G_OBJECT(send_notify_chkbtn), "toggled", 
991                          G_CALLBACK(send_cancel_notify_toggled_cb),
992                          &send_notify);
993
994         val = alertpanel_full(_("Cancel meeting"),
995                                    _("Are you sure you want to cancel this meeting?"),
996                                    GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
997                                    send_notify_chkbtn, ALERT_WARNING, G_ALERTDEFAULT);
998
999         if (val != G_ALERTALTERNATE)
1000                 return;
1001
1002         event = vcal_manager_load_event(uid);
1003         if (!event)
1004                 return;
1005         event->method = ICAL_METHOD_CANCEL;
1006         
1007         if (folder) {
1008                 MainWindow *mainwin = mainwindow_get_mainwindow();
1009                 if (mainwin->summaryview->folder_item == item) {
1010                         redisp = TRUE;
1011                         summary_show(mainwin->summaryview, NULL);
1012                 }
1013         }
1014         
1015         if (send_notify) {
1016                 meet = vcal_meeting_create_hidden(event);
1017                 if (!vcal_meeting_send(meet)) {
1018                         event->method = ICAL_METHOD_REQUEST;
1019                         vcal_manager_save_event(event, TRUE);
1020                         vcal_manager_free_event(event);
1021                         if (folder)
1022                                 folder_item_scan(item);
1023
1024                         if (folder && redisp) {
1025                                 MainWindow *mainwin = mainwindow_get_mainwindow();
1026                                 summary_show(mainwin->summaryview, item);
1027                         }
1028                         return;
1029                 }
1030         }
1031
1032         vcal_manager_save_event(event, TRUE);
1033         
1034         file = vcal_manager_get_event_file(event->uid);
1035         g_unlink(file);
1036         vcal_manager_free_event(event);
1037         g_free(file);
1038         if (folder)
1039                 folder_item_scan(item);
1040         if (folder && redisp) {
1041                 MainWindow *mainwin = mainwindow_get_mainwindow();
1042                 summary_show(mainwin->summaryview, item);
1043         }
1044
1045         return;
1046 }
1047
1048 static gboolean vcalviewer_cancel_cb(GtkButton *widget, gpointer data)
1049 {
1050         VCalViewer *vcalviewer = (VCalViewer *)data;
1051         FolderItem *item = vcalendar_get_current_item();
1052         gchar * uid = vcalviewer_get_uid_from_mimeinfo(vcalviewer->mimeinfo);
1053         vcalendar_cancel_meeting(item, uid);
1054         return TRUE;
1055 }
1056
1057 static gboolean vcalviewer_action_cb(GtkButton *widget, gpointer data)
1058 {
1059         VCalViewer *vcalviewer = (VCalViewer *)data;
1060         gint index = gtk_combo_box_get_active(GTK_COMBO_BOX(vcalviewer->answer));
1061         enum icalparameter_partstat reply[3] = {ICAL_PARTSTAT_ACCEPTED, ICAL_PARTSTAT_TENTATIVE, ICAL_PARTSTAT_DECLINED};
1062         PrefsAccount *account = NULL;
1063         VCalEvent *saved_event = NULL, *event = NULL;
1064         debug_print("index chosen %d\n", index);
1065         
1066         if (index < 0 || index > 2) {
1067                 return TRUE;
1068         }
1069         
1070         s_vcalviewer = vcalviewer;
1071         
1072         if (!vcalviewer->event) {
1073                 g_warning("can't get event");
1074                 return TRUE;
1075         }
1076
1077 /* see if we have it registered and more recent */
1078         event = vcalviewer->event;
1079         saved_event = vcal_manager_load_event(vcalviewer->event->uid);
1080         if (saved_event && saved_event->sequence >= vcalviewer->event->sequence) {
1081                 saved_event->method = vcalviewer->event->method;
1082                 event = saved_event;
1083         } else if (saved_event) {
1084                 vcal_manager_free_event(saved_event);
1085                 saved_event = NULL;
1086         }
1087         account = vcal_manager_get_account_from_event(event);
1088         
1089         if (!account) {
1090                 AlertValue val = alertpanel_full(_("No account found"), 
1091                                         _("You have no account matching any attendee.\n"
1092                                             "Do you want to reply anyway?"),
1093                                         GTK_STOCK_CANCEL, g_strconcat("+", _("Reply anyway"), NULL),
1094                                         NULL, FALSE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
1095                 if (val == G_ALERTALTERNATE) {          
1096                         account = account_get_default();
1097                         vcal_manager_update_answer(event, account->address, 
1098                                         account->name,
1099                                         ICAL_PARTSTAT_NEEDSACTION, 
1100                                         ICAL_CUTYPE_INDIVIDUAL);
1101                 } else {
1102                         if (saved_event)
1103                                 vcal_manager_free_event(saved_event);
1104                         return TRUE;
1105                 }
1106         }
1107         
1108         vcal_manager_update_answer(event, account->address, account->name, reply[index], 0);
1109         
1110         if (event->organizer && *(event->organizer) && 
1111             !vcal_manager_reply(account, event)) {
1112                 g_warning("couldn't send reply");
1113         } else {
1114                 debug_print("no organizer, not sending answer\n");
1115         }
1116         
1117         vcal_manager_save_event(event, TRUE);
1118
1119         vcalviewer_display_event(vcalviewer, event);
1120         if (saved_event)
1121                 vcal_manager_free_event(saved_event);
1122         return TRUE;
1123 };
1124
1125 #define TABLE_ADD_LINE(label_text, widget) {                            \
1126         gchar *tmpstr = g_strdup_printf("<span weight=\"bold\">%s</span>",\
1127                                 label_text);                            \
1128         GtkWidget *label = gtk_label_new(tmpstr);                       \
1129         g_free(tmpstr);                                                 \
1130         gtk_label_set_use_markup (GTK_LABEL (label), TRUE);             \
1131         gtk_misc_set_alignment (GTK_MISC(label), 1, 0);                 \
1132         gtk_table_attach (GTK_TABLE (vcalviewer->table),                \
1133                           label, 0, 1, i, i+1,                          \
1134                           GTK_FILL, GTK_FILL, 6, 6);                    \
1135         gtk_table_attach (GTK_TABLE (vcalviewer->table),                \
1136                           widget, 1, 2, i, i+1,                         \
1137                           GTK_FILL, GTK_FILL, 6, 6);                    \
1138         if (GTK_IS_LABEL(widget)) {                                     \
1139                 gtk_label_set_use_markup(GTK_LABEL (widget), TRUE);     \
1140                 gtk_misc_set_alignment (GTK_MISC(widget),0, 0);         \
1141                 gtk_label_set_line_wrap(GTK_LABEL(widget), TRUE);       \
1142         }                                                               \
1143         i++;                                                            \
1144 }
1145
1146 static gchar *vcal_viewer_get_selection(MimeViewer *_viewer)
1147 {
1148         VCalViewer *viewer = (VCalViewer *)_viewer;
1149         if (viewer->summary == NULL)
1150                 return NULL;
1151         if (gtk_label_get_text(GTK_LABEL(viewer->description))
1152         &&  *(gtk_label_get_text(GTK_LABEL(viewer->description))) > 2) {
1153                 gint start, end;
1154                 if (gtk_label_get_selection_bounds(GTK_LABEL(viewer->description), 
1155                                                    &start, &end)) {
1156                         gchar *tmp = g_strdup(gtk_label_get_text(
1157                                                 GTK_LABEL(viewer->description))+start);
1158                         tmp[end-start] = '\0';
1159                         return tmp;
1160                 } else {
1161                         return g_strdup(gtk_label_get_text(GTK_LABEL(viewer->description)));
1162                 }
1163         }
1164         else if (gtk_label_get_text(GTK_LABEL(viewer->summary))
1165         &&  *(gtk_label_get_text(GTK_LABEL(viewer->summary))) > 2)
1166                 return g_strdup(gtk_label_get_text(GTK_LABEL(viewer->summary)));
1167         else 
1168                 return NULL;
1169 }
1170
1171
1172 static gboolean vcal_viewer_scroll_page(MimeViewer *_viewer, gboolean up)
1173 {
1174         VCalViewer *viewer = (VCalViewer *)_viewer;
1175         GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment(
1176                 GTK_SCROLLED_WINDOW(viewer->scrolledwin));
1177         
1178         return gtkutils_scroll_page(viewer->table, vadj, up);
1179 }
1180
1181 static void vcal_viewer_scroll_one_line(MimeViewer *_viewer, gboolean up)
1182 {
1183         VCalViewer *viewer = (VCalViewer *)_viewer;
1184         GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment(
1185                 GTK_SCROLLED_WINDOW(viewer->scrolledwin));
1186         
1187         gtkutils_scroll_one_line(viewer->table, vadj, up);
1188 }
1189
1190 MimeViewer *vcal_viewer_create(void)
1191 {
1192         VCalViewer *vcalviewer;
1193         int i = 0;
1194         GtkWidget *hbox = NULL, *vbox = NULL;
1195         GtkWidget *warning_img;
1196         GtkWidget *warning_label;
1197         
1198         debug_print("Creating vcal view...\n");
1199         vcalviewer = g_new0(VCalViewer, 1);
1200         vcalviewer->mimeviewer.factory = &vcal_viewer_factory;
1201
1202         vcalviewer->mimeviewer.get_widget = vcal_viewer_get_widget;
1203         vcalviewer->mimeviewer.show_mimepart = vcal_viewer_show_mimepart;
1204         vcalviewer->mimeviewer.clear_viewer = vcal_viewer_clear_viewer;
1205         vcalviewer->mimeviewer.destroy_viewer = vcal_viewer_destroy_viewer;
1206         vcalviewer->mimeviewer.get_selection = vcal_viewer_get_selection;
1207         vcalviewer->mimeviewer.scroll_page = vcal_viewer_scroll_page;
1208         vcalviewer->mimeviewer.scroll_one_line = vcal_viewer_scroll_one_line;
1209
1210         vcalviewer->table = gtk_table_new(8, 2, FALSE);
1211         vcalviewer->type = gtk_label_new("meeting");
1212         vcalviewer->who = gtk_label_new("who");
1213         vcalviewer->start = gtk_label_new("start");
1214         vcalviewer->end = gtk_label_new("end");
1215         vcalviewer->location = gtk_label_new("location");
1216         vcalviewer->summary = gtk_label_new("summary");
1217         vcalviewer->description = gtk_label_new("description");
1218         vcalviewer->attendees = gtk_label_new("attendees");
1219
1220         vcalviewer->answer = gtk_combo_box_new_text();
1221         vcalviewer->url = NULL;
1222         vcalviewer->button = gtk_button_new_with_label(_("Answer"));
1223         vcalviewer->reedit = gtk_button_new_with_label(_("Edit meeting..."));
1224         vcalviewer->cancel = gtk_button_new_with_label(_("Cancel meeting..."));
1225         vcalviewer->uribtn = gtk_button_new_with_label(_("Launch website"));
1226         vcalviewer->unavail_box = gtk_hbox_new(FALSE, 6);
1227         warning_img = gtk_image_new_from_stock
1228                         (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
1229         warning_label = gtk_label_new(_("You are already busy at this time."));
1230
1231         gtk_box_pack_start(GTK_BOX(vcalviewer->unavail_box), warning_img, FALSE, FALSE, 0);
1232         gtk_box_pack_start(GTK_BOX(vcalviewer->unavail_box), warning_label, FALSE, FALSE, 0);
1233         
1234         hbox = gtk_hbox_new(FALSE, 6);
1235         gtk_box_pack_start(GTK_BOX(hbox), vcalviewer->answer, FALSE, FALSE, 0);
1236         gtk_box_pack_start(GTK_BOX(hbox), vcalviewer->button, FALSE, FALSE, 0);
1237         gtk_box_pack_start(GTK_BOX(hbox), vcalviewer->reedit, FALSE, FALSE, 0);
1238         gtk_box_pack_start(GTK_BOX(hbox), vcalviewer->cancel, FALSE, FALSE, 0);
1239         gtk_box_pack_start(GTK_BOX(hbox), vcalviewer->uribtn, FALSE, FALSE, 0);
1240         
1241         vbox = gtk_vbox_new(FALSE, 6);
1242         gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1243         gtk_box_pack_start(GTK_BOX(vbox), vcalviewer->unavail_box, FALSE, FALSE, 0);
1244
1245         vcalviewer_answer_set_choices(vcalviewer, NULL, ICAL_METHOD_REQUEST);
1246
1247         gtk_label_set_selectable(GTK_LABEL(vcalviewer->type), TRUE);
1248         gtk_label_set_selectable(GTK_LABEL(vcalviewer->who), TRUE);
1249         gtk_label_set_selectable(GTK_LABEL(vcalviewer->start), TRUE);
1250         gtk_label_set_selectable(GTK_LABEL(vcalviewer->end), TRUE);
1251         gtk_label_set_selectable(GTK_LABEL(vcalviewer->location), TRUE);
1252         gtk_label_set_selectable(GTK_LABEL(vcalviewer->summary), TRUE);
1253         gtk_label_set_selectable(GTK_LABEL(vcalviewer->description), TRUE);
1254         gtk_label_set_selectable(GTK_LABEL(vcalviewer->attendees), TRUE);
1255
1256         g_signal_connect(G_OBJECT(vcalviewer->button), "clicked",
1257                          G_CALLBACK(vcalviewer_action_cb), vcalviewer);
1258
1259         g_signal_connect(G_OBJECT(vcalviewer->reedit), "clicked",
1260                          G_CALLBACK(vcalviewer_reedit_cb), vcalviewer);
1261
1262         g_signal_connect(G_OBJECT(vcalviewer->cancel), "clicked",
1263                          G_CALLBACK(vcalviewer_cancel_cb), vcalviewer);
1264
1265         g_signal_connect(G_OBJECT(vcalviewer->uribtn), "clicked",
1266                          G_CALLBACK(vcalviewer_uribtn_cb), vcalviewer);
1267
1268         TABLE_ADD_LINE(_("Event:"), vcalviewer->type);
1269         TABLE_ADD_LINE(_("Organizer:"), vcalviewer->who);
1270         TABLE_ADD_LINE(_("Location:"), vcalviewer->location);
1271         TABLE_ADD_LINE(_("Summary:"), vcalviewer->summary);
1272         TABLE_ADD_LINE(_("Starting:"), vcalviewer->start);
1273         TABLE_ADD_LINE(_("Ending:"), vcalviewer->end);
1274         TABLE_ADD_LINE(_("Description:"), vcalviewer->description);
1275         TABLE_ADD_LINE(_("Attendees:"), vcalviewer->attendees);
1276         gtk_label_set_line_wrap(GTK_LABEL(vcalviewer->attendees), FALSE);
1277         TABLE_ADD_LINE(_("Action:"), vbox);
1278         
1279         vcalviewer->scrolledwin = gtk_scrolled_window_new(NULL, NULL);
1280         gtk_scrolled_window_add_with_viewport(
1281                 GTK_SCROLLED_WINDOW(vcalviewer->scrolledwin), 
1282                 vcalviewer->table);
1283         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vcalviewer->scrolledwin),
1284                                        GTK_POLICY_NEVER,
1285                                        GTK_POLICY_AUTOMATIC);
1286         
1287         gtk_widget_show_all(vcalviewer->scrolledwin);
1288         return (MimeViewer *) vcalviewer;
1289 }
1290
1291 static gchar *content_types[] =
1292         {"text/calendar", NULL};
1293         
1294 MimeViewerFactory vcal_viewer_factory =
1295 {
1296         content_types,
1297         0,
1298         vcal_viewer_create,
1299 };
1300
1301 static gint alert_timeout_tag = 0;
1302 static gint scan_timeout_tag = 0;
1303
1304 static gboolean vcal_webcal_check(gpointer data)
1305 {
1306         Folder *root = folder_find_from_name ("vCalendar", vcal_folder_get_class());
1307
1308         if (prefs_common_get_prefs()->work_offline)
1309                 return TRUE;
1310         
1311         manual_update = FALSE;
1312         folderview_check_new(root);
1313         manual_update = TRUE;
1314         return TRUE;
1315 }
1316
1317 static guint context_menu_id = 0;
1318 static guint main_menu_id = 0;
1319
1320 void vcalendar_init(void)
1321 {
1322         MainWindow *mainwin = mainwindow_get_mainwindow();
1323         Folder *folder = NULL;
1324         gchar *directory = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
1325                                 "vcalendar", NULL);
1326         START_TIMING("");
1327         if (!is_dir_exist(directory) && make_dir (directory) != 0) {
1328                 g_free(directory);
1329                 return;
1330         }
1331
1332         g_free(directory);
1333
1334         vcal_prefs_init();
1335
1336         mimeview_register_viewer_factory(&vcal_viewer_factory);
1337         folder_register_class(vcal_folder_get_class());
1338
1339         folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
1340         if (!folder) {
1341                 START_TIMING("creating folder");
1342                 folder = folder_new(vcal_folder_get_class(), "vCalendar", NULL);
1343                 folder->klass->create_tree(folder);
1344                 folder_add(folder);
1345                 folder_scan_tree(folder, TRUE);
1346                 END_TIMING();
1347         }
1348
1349         if (!folder->inbox) {
1350                 folder->klass->create_tree(folder);
1351                 folder_scan_tree(folder, TRUE);
1352         }
1353         if (folder->klass->scan_required(folder, folder->inbox)) {
1354                 START_TIMING("scanning folder");
1355                 folder_item_scan(folder->inbox);
1356                 END_TIMING();
1357         }
1358         
1359         vcal_folder_gtk_init();
1360
1361         alert_timeout_tag = g_timeout_add(60*1000, 
1362                                 (GSourceFunc)vcal_meeting_alert_check, 
1363                                 (gpointer)NULL);
1364         scan_timeout_tag = g_timeout_add(3600*1000, 
1365                                 (GSourceFunc)vcal_webcal_check, 
1366                                 (gpointer)NULL);
1367         if (prefs_common_get_prefs()->enable_color) {
1368                 gtkut_convert_int_to_gdk_color(prefs_common_get_prefs()->uri_col,
1369                                        &uri_color);
1370         }
1371
1372         gtk_action_group_add_actions(mainwin->action_group, vcalendar_main_menu,
1373                         1, (gpointer)mainwin);
1374         MENUITEM_ADDUI_ID_MANAGER(mainwin->ui_manager, "/Menu/Message", "CreateMeeting", 
1375                           "Message/CreateMeeting", GTK_UI_MANAGER_MENUITEM,
1376                           main_menu_id)
1377         MENUITEM_ADDUI_ID_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "CreateMeeting", 
1378                           "Message/CreateMeeting", GTK_UI_MANAGER_MENUITEM,
1379                           context_menu_id)
1380         END_TIMING();
1381 }
1382
1383 void vcalendar_done(void)
1384 {
1385         MainWindow *mainwin = mainwindow_get_mainwindow();
1386         FolderView *folderview = NULL;
1387         FolderItem *fitem = NULL;
1388
1389         icalmemory_free_ring();
1390
1391         vcal_folder_free_data();
1392
1393         if (mainwin == NULL)
1394                 return;
1395
1396         folderview = mainwin->folderview;
1397         fitem = folderview->summaryview->folder_item;
1398
1399         if (fitem && 
1400             fitem->folder->klass == vcal_folder_get_class()) {
1401                 folderview_unselect(folderview);
1402                 summary_clear_all(folderview->summaryview);
1403                 if (fitem->folder->klass->item_closed)
1404                         fitem->folder->klass->item_closed(fitem);
1405         }
1406
1407         mimeview_unregister_viewer_factory(&vcal_viewer_factory);
1408         folder_unregister_class(vcal_folder_get_class());
1409         vcal_folder_gtk_done();
1410         vcal_prefs_done();
1411         g_source_remove(alert_timeout_tag);
1412         alert_timeout_tag = 0;
1413         g_source_remove(scan_timeout_tag);
1414         scan_timeout_tag = 0;
1415
1416         MENUITEM_REMUI_MANAGER(mainwin->ui_manager,mainwin->action_group, "Message/CreateMeeting", main_menu_id);
1417         main_menu_id = 0;
1418         MENUITEM_REMUI_MANAGER(mainwin->ui_manager,mainwin->action_group, "Message/CreateMeeting", context_menu_id);
1419         context_menu_id = 0;
1420 }