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