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