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