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