ddbeb86f312b3744e7304296bbb43973c992b330
[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(_("%s <span weight=\"bold\">(this event recurs)</span>"),
565                                         event->start);
566                         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->start), tmp);
567                         gtk_label_set_use_markup(GTK_LABEL(vcalviewer->start), TRUE);
568                         g_free(tmp);
569                 } else if (event->rec_occurence) {
570                         gchar *tmp = g_strdup_printf(_("%s <span weight=\"bold\">(this event is part of a recurring event)</span>"),
571                                         event->start);
572                         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->start), tmp);
573                         gtk_label_set_use_markup(GTK_LABEL(vcalviewer->start), TRUE);
574                         g_free(tmp);
575                 } else {
576                         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->start), event->start);
577                 }
578         } else {
579                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->start), "-");
580         }
581
582 /* end */
583         if (event->end && *(event->end)) {
584                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->end), event->end);
585         } else {
586                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->end), "-");
587         }
588         
589 /* attendees */
590         attendees = g_strdup("");
591         for (list = vcal_manager_get_answers_emails(event); 
592              list && list->data; list = list->next) {
593                 gchar *attendee = (gchar *)list->data;
594                 gchar *name = vcal_manager_get_attendee_name(event, attendee);
595                 gchar *ename = g_markup_printf_escaped("%s", name?name:"");
596                 gchar *eatt = g_markup_printf_escaped("%s", attendee);
597                 enum icalparameter_partstat acode = vcal_manager_get_reply_for_attendee(event, attendee);
598                 gchar *answer = vcal_manager_get_reply_text_for_attendee(event, attendee);
599                 gchar *type = vcal_manager_get_cutype_text_for_attendee(event, attendee);
600                 gchar *tmp = NULL;
601                 gint e_len, n_len;
602                 tmp = g_strdup_printf(
603                                 "%s%s&lt;%s&gt; (%s, <span%s>%s</span>)", 
604                                 (ename && *(ename))?ename:"",
605                                 (ename && *(ename))?" ":"",
606                                 (eatt && *(eatt))?eatt:"", 
607                                 (type && *(type))?type:"", 
608                                 (acode != ICAL_PARTSTAT_ACCEPTED ? " foreground=\"red\"":""),
609                                 (answer && *(answer))?answer:"");
610                 e_len = strlen(attendees);
611                 n_len = strlen(tmp);
612                 if (e_len) {
613                         attendees = g_realloc(attendees, e_len+n_len+2);
614                         *(attendees+e_len) = '\n';
615                         strcpy(attendees+e_len+1, tmp);
616                 } else {
617                         attendees = g_realloc(attendees, e_len+n_len+1);
618                         strcpy(attendees, tmp);
619                 }
620                 g_free(tmp);
621                 g_free(answer);
622                 g_free(type);
623                 g_free(name);
624                 g_free(ename);
625                 g_free(eatt);
626         }
627         
628         if (attendees && *(attendees)) {
629                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->attendees), attendees);
630         } else {
631                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->attendees), "-");
632         }
633         g_free(attendees);
634         gtk_label_set_use_markup(GTK_LABEL(vcalviewer->attendees), TRUE);
635         
636 /* buttons */
637         if (!mine)
638                 if (event->type != ICAL_VTODO_COMPONENT)
639                         vcalviewer_answer_set_choices(vcalviewer, event, event->method);
640                 else
641                         vcalviewer_answer_set_choices(vcalviewer, event, ICAL_METHOD_PUBLISH);
642         else {
643                 vcalviewer_answer_set_choices(vcalviewer, event, ICAL_METHOD_REPLY);
644                 gtk_widget_show(vcalviewer->reedit);
645                 gtk_widget_show(vcalviewer->cancel);
646         }
647
648 /* save if cancelled */
649         if (save_evt)
650                 vcal_manager_save_event(event, TRUE);
651 }
652
653 gchar *vcalviewer_get_uid_from_mimeinfo(MimeInfo *mimeinfo)
654 {
655         gchar *tmpfile = procmime_get_tmp_file_name(mimeinfo);
656         const gchar *charset = procmime_mimeinfo_get_parameter(mimeinfo, "charset");
657         gchar *compstr = NULL;
658         gchar *res = NULL;
659         VCalEvent *event = NULL;
660
661         if (!charset)
662                 charset = CS_WINDOWS_1252;
663         
664         if (!strcasecmp(charset, CS_ISO_8859_1))
665                 charset = CS_WINDOWS_1252;
666
667         if (procmime_get_part(tmpfile, mimeinfo) < 0) {
668                 g_warning("Can't get mimepart file");   
669                 g_free(tmpfile);
670                 return NULL;
671         }
672         
673         compstr = file_read_to_str(tmpfile);
674         
675         event = vcal_get_event_from_ical(compstr, charset);
676         if (event)
677                 res = g_strdup(event->uid);
678         
679         vcal_manager_free_event(event);
680
681         debug_print("got uid: %s\n", res);
682         return res;
683
684 }
685
686 static void vcalviewer_get_request_values(VCalViewer *vcalviewer, MimeInfo *mimeinfo, gboolean is_todo) 
687 {
688         VCalEvent *saved_event = NULL;
689         const gchar *charset = procmime_mimeinfo_get_parameter(mimeinfo, "charset");
690         const gchar *saveme =  procmime_mimeinfo_get_parameter(mimeinfo, "vcalsave");
691         
692         if (!vcalviewer->event)
693                 return;
694
695         if (!charset)
696                 charset = CS_WINDOWS_1252;
697         
698         if (!strcasecmp(charset, CS_ISO_8859_1))
699                 charset = CS_WINDOWS_1252;
700
701         /* see if we have it registered and more recent */
702         saved_event = vcal_manager_load_event(vcalviewer->event->uid);
703         if (saved_event && saved_event->sequence >= vcalviewer->event->sequence) {
704                 charset = CS_INTERNAL;
705                 saved_event->method = vcalviewer->event->method;
706                 vcalviewer_display_event(vcalviewer, saved_event);
707                 vcal_manager_free_event(saved_event);
708                 return;
709         } else if (saved_event) {
710                 vcal_manager_free_event(saved_event);
711         }
712
713         /* load it and register it */
714
715         if (!saveme || strcmp(saveme,"no"))
716                 vcal_manager_save_event(vcalviewer->event, FALSE);
717
718         vcalviewer_display_event(vcalviewer, vcalviewer->event);
719 }
720
721 static void vcalviewer_get_reply_values(VCalViewer *vcalviewer, MimeInfo *mimeinfo) 
722 {
723         const gchar *charset = procmime_mimeinfo_get_parameter(mimeinfo, "charset");
724         VCalEvent *saved_event = NULL;
725         gchar *attendee = NULL, *label = NULL;
726         Answer *answer = NULL;
727
728         if (!vcalviewer->event)
729                 return;
730
731         if (!charset)
732                 charset = CS_WINDOWS_1252;
733         
734         if (!strcasecmp(charset, CS_ISO_8859_1))
735                 charset = CS_WINDOWS_1252;
736
737         if (!vcalviewer->event->answers || g_slist_length(vcalviewer->event->answers) > 1) {
738                 g_warning("strange, no answers or more than one");
739         } 
740         
741         if (vcalviewer->event->answers) {
742                 answer = (Answer *)vcalviewer->event->answers->data;
743                 attendee = g_strdup(answer->attendee);
744         }
745                 
746
747         if (!answer) {
748                 label = g_strjoin(" ",
749                         _("You have received an answer to an unknown meeting proposal."),
750                         _("Details follow:"), NULL);
751                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
752         } else {
753                 label = g_strdup_printf(_("You have received an answer to a meeting proposal.\n"
754                         "%s has %s the invitation whose details follow:"),
755                         attendee, vcal_manager_answer_get_text(answer->answer));
756                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
757                 g_free(attendee);
758         }
759         g_free(label);
760
761         saved_event = vcal_manager_load_event(vcalviewer->event->uid);
762         if (saved_event && answer) {
763                 vcal_manager_update_answer(saved_event, 
764                         answer->attendee, answer->name, answer->answer, answer->cutype);
765                 vcal_manager_save_event(saved_event, TRUE);
766                 saved_event->method = vcalviewer->event->method;
767                 vcalviewer_display_event(vcalviewer, saved_event);
768                 vcal_manager_free_event(saved_event);
769                 return;
770         }
771
772         if (vcalviewer->event->organizer) {
773                 if (vcalviewer->event->orgname) {
774                         gchar *addr = g_strconcat(vcalviewer->event->orgname, " <", 
775                                         vcalviewer->event->organizer, ">", NULL);
776                         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->who), addr);
777                         g_free(addr);
778                 } else {
779                         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->who),
780                                 vcalviewer->event->organizer);
781                 }
782         } else {
783                 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->who), "-");
784         }
785         
786         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->location),
787                 vcalviewer->event->location?vcalviewer->event->location:"-");
788
789         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->summary), 
790                 vcalviewer->event->summary?vcalviewer->event->summary:"-");
791
792         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->description), 
793                 vcalviewer->event->description?vcalviewer->event->description:"-");
794
795         g_free(vcalviewer->url);
796         if (vcalviewer->event->url) {
797                 vcalviewer->url = g_strdup(vcalviewer->event->url);
798                 gtk_widget_show(vcalviewer->uribtn);
799         } else {
800                 vcalviewer->url = NULL;
801                 gtk_widget_hide(vcalviewer->uribtn);
802         }
803
804         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->start), 
805                 vcalviewer->event->start?vcalviewer->event->start:"-");
806         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->end), 
807                 vcalviewer->event->end?vcalviewer->event->end:"-");
808
809         GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->attendees), "-"); 
810
811         vcalviewer_answer_set_choices(vcalviewer, NULL, ICAL_METHOD_REPLY);
812 }
813
814 static void vcalviewer_get_event(VCalViewer *vcalviewer, MimeInfo *mimeinfo) 
815 {
816         gchar *tmpfile = get_tmpfile(vcalviewer);
817         const gchar *charset = procmime_mimeinfo_get_parameter(mimeinfo, "charset");
818
819         if (!charset)
820                 charset = CS_WINDOWS_1252;
821         
822         if (!strcasecmp(charset, CS_ISO_8859_1))
823                 charset = CS_WINDOWS_1252;
824         
825         if (vcalviewer->event) {
826                 vcal_manager_free_event(vcalviewer->event);
827                 vcalviewer->event = NULL;
828         }
829         
830         if (!tmpfile) {
831                 vcalviewer_reset(vcalviewer);
832                 vcalviewer_show_error(vcalviewer, _("Error - could not get the calendar MIME part."));
833                 return;
834         }
835
836         vcalviewer->event = vcalviewer_get_component(tmpfile, charset);
837         if (!vcalviewer->event) {
838                 vcalviewer_reset(vcalviewer);
839                 vcalviewer_show_error(vcalviewer, _("Error - no calendar part found."));
840                 return;
841         }
842         
843         if (vcalviewer->event->type == ICAL_VTODO_COMPONENT) {
844                 vcalviewer_get_request_values(vcalviewer, mimeinfo, TRUE);
845         } else if (vcalviewer->event->method == ICAL_METHOD_REQUEST ||
846                    vcalviewer->event->method == ICAL_METHOD_PUBLISH ||
847                    vcalviewer->event->method == ICAL_METHOD_CANCEL) {
848                 vcalviewer_get_request_values(vcalviewer, mimeinfo, FALSE);
849         } else if (vcalviewer->event->method == ICAL_METHOD_REPLY) {
850                 vcalviewer_get_reply_values(vcalviewer, mimeinfo);
851         } else {
852                 vcalviewer_reset(vcalviewer);
853                 vcalviewer_show_error(vcalviewer, _("Error - Unknown calendar component type."));
854         }
855 }
856
857 static VCalViewer *s_vcalviewer = NULL;
858
859 static void vcal_viewer_show_mimepart(MimeViewer *_mimeviewer, const gchar *file, MimeInfo *mimeinfo)
860 {
861         VCalViewer *vcalviewer = (VCalViewer *) _mimeviewer;
862         START_TIMING("");
863
864         s_vcalviewer = vcalviewer;
865
866         if (mimeinfo == NULL) {
867                 vcal_viewer_clear_viewer(_mimeviewer);
868                 END_TIMING();
869                 return;
870         }
871         debug_print("vcal_viewer_show_mimepart : %s\n", file);
872
873         vcal_viewer_clear_viewer(_mimeviewer);
874         gtk_widget_show_all(vcalviewer->scrolledwin);
875         g_free(vcalviewer->file);
876         vcalviewer->file = g_strdup(file);
877         vcalviewer->mimeinfo = mimeinfo;
878         vcalviewer_hide_error(vcalviewer);
879         vcalviewer_get_event(vcalviewer, mimeinfo);
880         GTK_EVENTS_FLUSH();
881         gtk_widget_set_size_request(vcalviewer->description, 
882                 vcalviewer->scrolledwin->allocation.width - 200, -1);
883         gtk_label_set_line_wrap(GTK_LABEL(vcalviewer->location), TRUE);
884         gtk_label_set_line_wrap(GTK_LABEL(vcalviewer->summary), TRUE);
885         gtk_label_set_line_wrap(GTK_LABEL(vcalviewer->description), TRUE);
886         gtk_label_set_line_wrap(GTK_LABEL(vcalviewer->attendees), FALSE);
887         
888         if (prefs_common_get_prefs()->textfont) {
889                 PangoFontDescription *font_desc;
890
891                 font_desc = pango_font_description_from_string
892                                                 (prefs_common_get_prefs()->textfont);
893                 if (font_desc) {
894                         gtk_widget_modify_font(
895                                 vcalviewer->description, font_desc);
896                         pango_font_description_free(font_desc);
897                 }
898         }
899         END_TIMING();   
900 }
901
902 void vcalviewer_reload(FolderItem *item)
903 {
904         if (s_vcalviewer) {
905                 MainWindow *mainwin = mainwindow_get_mainwindow();
906                 Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
907
908                 folder_item_scan(item);
909                 if (mainwin && mainwin->summaryview->folder_item) {
910                         FolderItem *cur = mainwin->summaryview->folder_item;
911                         if (cur->folder == folder)
912                                 folder_item_scan(cur);
913                 }
914                 if (mainwin && mainwin->summaryview->folder_item == item) {
915                         debug_print("reload: %p, %p\n", (MimeViewer *)s_vcalviewer, s_vcalviewer->mimeinfo);
916                         summary_redisplay_msg(mainwin->summaryview);
917                 }
918         }
919 }
920
921 static void vcal_viewer_destroy_viewer(MimeViewer *_mimeviewer)
922 {
923         VCalViewer *vcalviewer = (VCalViewer *) _mimeviewer;
924
925         debug_print("vcal_viewer_destroy_viewer\n");
926
927         if (s_vcalviewer == vcalviewer)
928                 s_vcalviewer = NULL;
929         vcal_viewer_clear_viewer(_mimeviewer);
930         g_free(vcalviewer);
931 }
932
933 static gboolean vcalviewer_reedit_cb(GtkButton *widget, gpointer data)
934 {
935         VCalViewer *vcalviewer = (VCalViewer *)data;
936         gchar * uid = vcalviewer_get_uid_from_mimeinfo(vcalviewer->mimeinfo);
937         VCalEvent *event = NULL;
938         
939         s_vcalviewer = vcalviewer;
940         /* see if we have it registered and more recent */
941         event = vcal_manager_load_event(uid);
942         vcal_meeting_create(event);
943         vcal_manager_free_event(event);
944         return TRUE;
945 }
946
947 static gboolean vcalviewer_uribtn_cb(GtkButton *widget, gpointer data)
948 {
949         VCalViewer *vcalviewer = (VCalViewer *)data;
950
951         if (vcalviewer->url)
952                 open_uri(vcalviewer->url, prefs_common_get_uri_cmd());
953
954         return TRUE;
955 }
956
957 void vcalendar_refresh_folder_contents(FolderItem *item)
958 {
959         Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
960         if (folder && item->folder == folder) {
961                 MainWindow *mainwin = mainwindow_get_mainwindow();
962                 folder_item_scan(item);
963                 if (mainwin->summaryview->folder_item == item) {
964                         summary_show(mainwin->summaryview, item);
965                 }
966         }
967 }
968
969 static void send_cancel_notify_toggled_cb(GtkToggleButton *button, gboolean *data)
970 {
971         *data = gtk_toggle_button_get_active(button);
972 }
973
974 void vcalendar_cancel_meeting(FolderItem *item, const gchar *uid)
975 {
976         VCalEvent *event = NULL;
977         VCalMeeting *meet = NULL;
978         gchar *file = NULL;
979         gint val = 0;
980         Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
981         gboolean redisp = FALSE;
982         GtkWidget *send_notify_chkbtn = gtk_check_button_new_with_label(_("Send a notification to the attendees"));
983         gboolean send_notify = TRUE;
984
985         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(send_notify_chkbtn), TRUE);
986         gtk_widget_show(send_notify_chkbtn);
987         g_signal_connect(G_OBJECT(send_notify_chkbtn), "toggled", 
988                          G_CALLBACK(send_cancel_notify_toggled_cb),
989                          &send_notify);
990
991         val = alertpanel_full(_("Cancel meeting"),
992                                    _("Are you sure you want to cancel this meeting?"),
993                                    GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
994                                    send_notify_chkbtn, ALERT_WARNING, G_ALERTDEFAULT);
995
996         if (val != G_ALERTALTERNATE)
997                 return;
998
999         event = vcal_manager_load_event(uid);
1000         if (!event)
1001                 return;
1002         event->method = ICAL_METHOD_CANCEL;
1003         
1004         if (folder) {
1005                 MainWindow *mainwin = mainwindow_get_mainwindow();
1006                 if (mainwin->summaryview->folder_item == item) {
1007                         redisp = TRUE;
1008                         summary_show(mainwin->summaryview, NULL);
1009                 }
1010         }
1011         
1012         if (send_notify) {
1013                 meet = vcal_meeting_create_hidden(event);
1014                 if (!vcal_meeting_send(meet)) {
1015                         event->method = ICAL_METHOD_REQUEST;
1016                         vcal_manager_save_event(event, TRUE);
1017                         vcal_manager_free_event(event);
1018                         if (folder)
1019                                 folder_item_scan(item);
1020
1021                         if (folder && redisp) {
1022                                 MainWindow *mainwin = mainwindow_get_mainwindow();
1023                                 summary_show(mainwin->summaryview, item);
1024                         }
1025                         return;
1026                 }
1027         }
1028
1029         vcal_manager_save_event(event, TRUE);
1030         
1031         file = vcal_manager_get_event_file(event->uid);
1032         g_unlink(file);
1033         vcal_manager_free_event(event);
1034         g_free(file);
1035         if (folder)
1036                 folder_item_scan(item);
1037         if (folder && redisp) {
1038                 MainWindow *mainwin = mainwindow_get_mainwindow();
1039                 summary_show(mainwin->summaryview, item);
1040         }
1041
1042         return;
1043 }
1044
1045 static gboolean vcalviewer_cancel_cb(GtkButton *widget, gpointer data)
1046 {
1047         VCalViewer *vcalviewer = (VCalViewer *)data;
1048         FolderItem *item = vcalendar_get_current_item();
1049         gchar * uid = vcalviewer_get_uid_from_mimeinfo(vcalviewer->mimeinfo);
1050         vcalendar_cancel_meeting(item, uid);
1051         return TRUE;
1052 }
1053
1054 static gboolean vcalviewer_action_cb(GtkButton *widget, gpointer data)
1055 {
1056         VCalViewer *vcalviewer = (VCalViewer *)data;
1057         gint index = gtk_combo_box_get_active(GTK_COMBO_BOX(vcalviewer->answer));
1058         enum icalparameter_partstat reply[3] = {ICAL_PARTSTAT_ACCEPTED, ICAL_PARTSTAT_TENTATIVE, ICAL_PARTSTAT_DECLINED};
1059         PrefsAccount *account = NULL;
1060         VCalEvent *saved_event = NULL, *event = NULL;
1061         debug_print("index chosen %d\n", index);
1062         
1063         if (index < 0 || index > 2) {
1064                 return TRUE;
1065         }
1066         
1067         s_vcalviewer = vcalviewer;
1068         
1069         if (!vcalviewer->event) {
1070                 g_warning("can't get event");
1071                 return TRUE;
1072         }
1073
1074 /* see if we have it registered and more recent */
1075         event = vcalviewer->event;
1076         saved_event = vcal_manager_load_event(vcalviewer->event->uid);
1077         if (saved_event && saved_event->sequence >= vcalviewer->event->sequence) {
1078                 saved_event->method = vcalviewer->event->method;
1079                 event = saved_event;
1080         } else if (saved_event) {
1081                 vcal_manager_free_event(saved_event);
1082                 saved_event = NULL;
1083         }
1084         account = vcal_manager_get_account_from_event(event);
1085         
1086         if (!account) {
1087                 AlertValue val = alertpanel_full(_("No account found"), 
1088                                         _("You have no account matching any attendee.\n"
1089                                             "Do you want to reply anyway?"),
1090                                         GTK_STOCK_CANCEL, _("+Reply anyway"), NULL, FALSE,
1091                                         NULL, ALERT_QUESTION, G_ALERTDEFAULT);
1092                 if (val == G_ALERTALTERNATE) {          
1093                         account = account_get_default();
1094                         vcal_manager_update_answer(event, account->address, 
1095                                         account->name,
1096                                         ICAL_PARTSTAT_NEEDSACTION, 
1097                                         ICAL_CUTYPE_INDIVIDUAL);
1098                 } else {
1099                         if (saved_event)
1100                                 vcal_manager_free_event(saved_event);
1101                         return TRUE;
1102                 }
1103         }
1104         
1105         vcal_manager_update_answer(event, account->address, account->name, reply[index], 0);
1106         
1107         if (event->organizer && *(event->organizer) && 
1108             !vcal_manager_reply(account, event)) {
1109                 g_warning("couldn't send reply");
1110         } else {
1111                 debug_print("no organizer, not sending answer\n");
1112         }
1113         
1114         vcal_manager_save_event(event, TRUE);
1115
1116         vcalviewer_display_event(vcalviewer, event);
1117         if (saved_event)
1118                 vcal_manager_free_event(saved_event);
1119         return TRUE;
1120 };
1121
1122 #define TABLE_ADD_LINE(label_text, widget) {                            \
1123         gchar *tmpstr = g_strdup_printf("<span weight=\"bold\">%s</span>",\
1124                                 label_text);                            \
1125         GtkWidget *label = gtk_label_new(tmpstr);                       \
1126         g_free(tmpstr);                                                 \
1127         gtk_label_set_use_markup (GTK_LABEL (label), TRUE);             \
1128         gtk_misc_set_alignment (GTK_MISC(label), 1, 0);                 \
1129         gtk_table_attach (GTK_TABLE (vcalviewer->table),                \
1130                           label, 0, 1, i, i+1,                          \
1131                           GTK_FILL, GTK_FILL, 6, 6);                    \
1132         gtk_table_attach (GTK_TABLE (vcalviewer->table),                \
1133                           widget, 1, 2, i, i+1,                         \
1134                           GTK_FILL, GTK_FILL, 6, 6);                    \
1135         if (GTK_IS_LABEL(widget)) {                                     \
1136                 gtk_label_set_use_markup(GTK_LABEL (widget), TRUE);     \
1137                 gtk_misc_set_alignment (GTK_MISC(widget),0, 0);         \
1138                 gtk_label_set_line_wrap(GTK_LABEL(widget), TRUE);       \
1139         }                                                               \
1140         i++;                                                            \
1141 }
1142
1143 static gchar *vcal_viewer_get_selection(MimeViewer *_viewer)
1144 {
1145         VCalViewer *viewer = (VCalViewer *)_viewer;
1146         if (viewer->summary == NULL)
1147                 return NULL;
1148         if (gtk_label_get_text(GTK_LABEL(viewer->description))
1149         &&  *(gtk_label_get_text(GTK_LABEL(viewer->description))) > 2) {
1150                 gint start, end;
1151                 if (gtk_label_get_selection_bounds(GTK_LABEL(viewer->description), 
1152                                                    &start, &end)) {
1153                         gchar *tmp = g_strdup(gtk_label_get_text(
1154                                                 GTK_LABEL(viewer->description))+start);
1155                         tmp[end-start] = '\0';
1156                         return tmp;
1157                 } else {
1158                         return g_strdup(gtk_label_get_text(GTK_LABEL(viewer->description)));
1159                 }
1160         }
1161         else if (gtk_label_get_text(GTK_LABEL(viewer->summary))
1162         &&  *(gtk_label_get_text(GTK_LABEL(viewer->summary))) > 2)
1163                 return g_strdup(gtk_label_get_text(GTK_LABEL(viewer->summary)));
1164         else 
1165                 return NULL;
1166 }
1167
1168
1169 static gboolean vcal_viewer_scroll_page(MimeViewer *_viewer, gboolean up)
1170 {
1171         VCalViewer *viewer = (VCalViewer *)_viewer;
1172         GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment(
1173                 GTK_SCROLLED_WINDOW(viewer->scrolledwin));
1174         
1175         return gtkutils_scroll_page(viewer->table, vadj, up);
1176 }
1177
1178 static void vcal_viewer_scroll_one_line(MimeViewer *_viewer, gboolean up)
1179 {
1180         VCalViewer *viewer = (VCalViewer *)_viewer;
1181         GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment(
1182                 GTK_SCROLLED_WINDOW(viewer->scrolledwin));
1183         
1184         gtkutils_scroll_one_line(viewer->table, vadj, up);
1185 }
1186
1187 MimeViewer *vcal_viewer_create(void)
1188 {
1189         VCalViewer *vcalviewer;
1190         int i = 0;
1191         GtkWidget *hbox = NULL, *vbox = NULL;
1192         GtkWidget *warning_img;
1193         GtkWidget *warning_label;
1194         
1195         debug_print("Creating vcal view...\n");
1196         vcalviewer = g_new0(VCalViewer, 1);
1197         vcalviewer->mimeviewer.factory = &vcal_viewer_factory;
1198
1199         vcalviewer->mimeviewer.get_widget = vcal_viewer_get_widget;
1200         vcalviewer->mimeviewer.show_mimepart = vcal_viewer_show_mimepart;
1201         vcalviewer->mimeviewer.clear_viewer = vcal_viewer_clear_viewer;
1202         vcalviewer->mimeviewer.destroy_viewer = vcal_viewer_destroy_viewer;
1203         vcalviewer->mimeviewer.get_selection = vcal_viewer_get_selection;
1204         vcalviewer->mimeviewer.scroll_page = vcal_viewer_scroll_page;
1205         vcalviewer->mimeviewer.scroll_one_line = vcal_viewer_scroll_one_line;
1206
1207         vcalviewer->table = gtk_table_new(8, 2, FALSE);
1208         vcalviewer->type = gtk_label_new("meeting");
1209         vcalviewer->who = gtk_label_new("who");
1210         vcalviewer->start = gtk_label_new("start");
1211         vcalviewer->end = gtk_label_new("end");
1212         vcalviewer->location = gtk_label_new("location");
1213         vcalviewer->summary = gtk_label_new("summary");
1214         vcalviewer->description = gtk_label_new("description");
1215         vcalviewer->attendees = gtk_label_new("attendees");
1216
1217         vcalviewer->answer = gtk_combo_box_new_text();
1218         vcalviewer->url = NULL;
1219         vcalviewer->button = gtk_button_new_with_label(_("Answer"));
1220         vcalviewer->reedit = gtk_button_new_with_label(_("Edit meeting..."));
1221         vcalviewer->cancel = gtk_button_new_with_label(_("Cancel meeting..."));
1222         vcalviewer->uribtn = gtk_button_new_with_label(_("Launch website"));
1223         vcalviewer->unavail_box = gtk_hbox_new(FALSE, 6);
1224         warning_img = gtk_image_new_from_stock
1225                         (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
1226         warning_label = gtk_label_new(_("You are already busy at this time."));
1227
1228         gtk_box_pack_start(GTK_BOX(vcalviewer->unavail_box), warning_img, FALSE, FALSE, 0);
1229         gtk_box_pack_start(GTK_BOX(vcalviewer->unavail_box), warning_label, FALSE, FALSE, 0);
1230         
1231         hbox = gtk_hbox_new(FALSE, 6);
1232         gtk_box_pack_start(GTK_BOX(hbox), vcalviewer->answer, FALSE, FALSE, 0);
1233         gtk_box_pack_start(GTK_BOX(hbox), vcalviewer->button, FALSE, FALSE, 0);
1234         gtk_box_pack_start(GTK_BOX(hbox), vcalviewer->reedit, FALSE, FALSE, 0);
1235         gtk_box_pack_start(GTK_BOX(hbox), vcalviewer->cancel, FALSE, FALSE, 0);
1236         gtk_box_pack_start(GTK_BOX(hbox), vcalviewer->uribtn, FALSE, FALSE, 0);
1237         
1238         vbox = gtk_vbox_new(FALSE, 6);
1239         gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1240         gtk_box_pack_start(GTK_BOX(vbox), vcalviewer->unavail_box, FALSE, FALSE, 0);
1241
1242         vcalviewer_answer_set_choices(vcalviewer, NULL, ICAL_METHOD_REQUEST);
1243
1244         gtk_label_set_selectable(GTK_LABEL(vcalviewer->type), TRUE);
1245         gtk_label_set_selectable(GTK_LABEL(vcalviewer->who), TRUE);
1246         gtk_label_set_selectable(GTK_LABEL(vcalviewer->start), TRUE);
1247         gtk_label_set_selectable(GTK_LABEL(vcalviewer->end), TRUE);
1248         gtk_label_set_selectable(GTK_LABEL(vcalviewer->location), TRUE);
1249         gtk_label_set_selectable(GTK_LABEL(vcalviewer->summary), TRUE);
1250         gtk_label_set_selectable(GTK_LABEL(vcalviewer->description), TRUE);
1251         gtk_label_set_selectable(GTK_LABEL(vcalviewer->attendees), TRUE);
1252
1253         g_signal_connect(G_OBJECT(vcalviewer->button), "clicked",
1254                          G_CALLBACK(vcalviewer_action_cb), vcalviewer);
1255
1256         g_signal_connect(G_OBJECT(vcalviewer->reedit), "clicked",
1257                          G_CALLBACK(vcalviewer_reedit_cb), vcalviewer);
1258
1259         g_signal_connect(G_OBJECT(vcalviewer->cancel), "clicked",
1260                          G_CALLBACK(vcalviewer_cancel_cb), vcalviewer);
1261
1262         g_signal_connect(G_OBJECT(vcalviewer->uribtn), "clicked",
1263                          G_CALLBACK(vcalviewer_uribtn_cb), vcalviewer);
1264
1265         TABLE_ADD_LINE(_("Event:"), vcalviewer->type);
1266         TABLE_ADD_LINE(_("Organizer:"), vcalviewer->who);
1267         TABLE_ADD_LINE(_("Location:"), vcalviewer->location);
1268         TABLE_ADD_LINE(_("Summary:"), vcalviewer->summary);
1269         TABLE_ADD_LINE(_("Starting:"), vcalviewer->start);
1270         TABLE_ADD_LINE(_("Ending:"), vcalviewer->end);
1271         TABLE_ADD_LINE(_("Description:"), vcalviewer->description);
1272         TABLE_ADD_LINE(_("Attendees:"), vcalviewer->attendees);
1273         gtk_label_set_line_wrap(GTK_LABEL(vcalviewer->attendees), FALSE);
1274         TABLE_ADD_LINE(_("Action:"), vbox);
1275         
1276         vcalviewer->scrolledwin = gtk_scrolled_window_new(NULL, NULL);
1277         gtk_scrolled_window_add_with_viewport(
1278                 GTK_SCROLLED_WINDOW(vcalviewer->scrolledwin), 
1279                 vcalviewer->table);
1280         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vcalviewer->scrolledwin),
1281                                        GTK_POLICY_NEVER,
1282                                        GTK_POLICY_AUTOMATIC);
1283         
1284         gtk_widget_show_all(vcalviewer->scrolledwin);
1285         return (MimeViewer *) vcalviewer;
1286 }
1287
1288 static gchar *content_types[] =
1289         {"text/calendar", NULL};
1290         
1291 MimeViewerFactory vcal_viewer_factory =
1292 {
1293         content_types,
1294         0,
1295         vcal_viewer_create,
1296 };
1297
1298 static gint alert_timeout_tag = 0;
1299 static gint scan_timeout_tag = 0;
1300
1301 static gboolean vcal_webcal_check(gpointer data)
1302 {
1303         Folder *root = folder_find_from_name ("vCalendar", vcal_folder_get_class());
1304
1305         if (prefs_common_get_prefs()->work_offline)
1306                 return TRUE;
1307         
1308         manual_update = FALSE;
1309         folderview_check_new(root);
1310         manual_update = TRUE;
1311         return TRUE;
1312 }
1313
1314 static guint context_menu_id = 0;
1315 static guint main_menu_id = 0;
1316
1317 void vcalendar_init(void)
1318 {
1319         MainWindow *mainwin = mainwindow_get_mainwindow();
1320         Folder *folder = NULL;
1321         gchar *directory = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
1322                                 "vcalendar", NULL);
1323         START_TIMING("");
1324         if (!is_dir_exist(directory) && make_dir (directory) != 0) {
1325                 g_free(directory);
1326                 return;
1327         }
1328
1329         g_free(directory);
1330
1331         vcal_prefs_init();
1332
1333         mimeview_register_viewer_factory(&vcal_viewer_factory);
1334         folder_register_class(vcal_folder_get_class());
1335
1336         folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
1337         if (!folder) {
1338                 START_TIMING("creating folder");
1339                 folder = folder_new(vcal_folder_get_class(), "vCalendar", NULL);
1340                 folder->klass->create_tree(folder);
1341                 folder_add(folder);
1342                 folder_scan_tree(folder, TRUE);
1343                 END_TIMING();
1344         }
1345
1346         if (!folder->inbox) {
1347                 folder->klass->create_tree(folder);
1348                 folder_scan_tree(folder, TRUE);
1349         }
1350         if (folder->klass->scan_required(folder, folder->inbox)) {
1351                 START_TIMING("scanning folder");
1352                 folder_item_scan(folder->inbox);
1353                 END_TIMING();
1354         }
1355         
1356         vcal_folder_gtk_init();
1357
1358         alert_timeout_tag = g_timeout_add(60*1000, 
1359                                 (GSourceFunc)vcal_meeting_alert_check, 
1360                                 (gpointer)NULL);
1361         scan_timeout_tag = g_timeout_add(3600*1000, 
1362                                 (GSourceFunc)vcal_webcal_check, 
1363                                 (gpointer)NULL);
1364         if (prefs_common_get_prefs()->enable_color) {
1365                 gtkut_convert_int_to_gdk_color(prefs_common_get_prefs()->uri_col,
1366                                        &uri_color);
1367         }
1368
1369         gtk_action_group_add_actions(mainwin->action_group, vcalendar_main_menu,
1370                         1, (gpointer)mainwin);
1371         MENUITEM_ADDUI_ID_MANAGER(mainwin->ui_manager, "/Menu/Message", "CreateMeeting", 
1372                           "Message/CreateMeeting", GTK_UI_MANAGER_MENUITEM,
1373                           main_menu_id)
1374         MENUITEM_ADDUI_ID_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "CreateMeeting", 
1375                           "Message/CreateMeeting", GTK_UI_MANAGER_MENUITEM,
1376                           context_menu_id)
1377         END_TIMING();
1378 }
1379
1380 void vcalendar_done(void)
1381 {
1382         MainWindow *mainwin = mainwindow_get_mainwindow();
1383         FolderView *folderview = NULL;
1384         FolderItem *fitem = NULL;
1385
1386         icalmemory_free_ring();
1387
1388         vcal_folder_free_data();
1389
1390         if (mainwin == NULL)
1391                 return;
1392
1393         folderview = mainwin->folderview;
1394         fitem = folderview->summaryview->folder_item;
1395
1396         if (fitem && 
1397             fitem->folder->klass == vcal_folder_get_class()) {
1398                 folderview_unselect(folderview);
1399                 summary_clear_all(folderview->summaryview);
1400                 if (fitem->folder->klass->item_closed)
1401                         fitem->folder->klass->item_closed(fitem);
1402         }
1403
1404         mimeview_unregister_viewer_factory(&vcal_viewer_factory);
1405         folder_unregister_class(vcal_folder_get_class());
1406         vcal_folder_gtk_done();
1407         vcal_prefs_done();
1408         g_source_remove(alert_timeout_tag);
1409         alert_timeout_tag = 0;
1410         g_source_remove(scan_timeout_tag);
1411         scan_timeout_tag = 0;
1412
1413         MENUITEM_REMUI_MANAGER(mainwin->ui_manager,mainwin->action_group, "Message/CreateMeeting", main_menu_id);
1414         main_menu_id = 0;
1415         MENUITEM_REMUI_MANAGER(mainwin->ui_manager,mainwin->action_group, "Message/CreateMeeting", context_menu_id);
1416         context_menu_id = 0;
1417 }