vCalendar: Honor VTIMEZONE component if present
[claws.git] / src / plugins / vcalendar / vcalendar.c
bloba6d968496358d227dc914018a5e694880c7ebf88
1 /*
2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2022 the Claws Mail team and Colin Leroy
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.
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.
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.
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #include "claws-features.h"
23 #endif
25 #include <stddef.h>
26 #include <glib.h>
27 #include <glib/gi18n.h>
29 #include <libical/ical.h>
30 #include <gtk/gtk.h>
32 #if USE_PTHREAD
33 #include "pthread.h"
34 #endif
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"
59 MimeViewerFactory vcal_viewer_factory;
61 static void create_meeting_from_message_cb_ui(GtkAction *action, gpointer data);
63 static GdkRGBA uri_color = {
64 0, 0, 0, 1
67 struct _VCalViewer
69 MimeViewer mimeviewer;
71 gchar *file;
72 MimeInfo *mimeinfo;
73 gchar *tmpfile;
74 VCalEvent *event;
76 GtkWidget *scrolledwin;
77 GtkWidget *table;
78 GtkWidget *type;
79 GtkWidget *who;
80 GtkWidget *start;
81 GtkWidget *end;
82 GtkWidget *location;
83 GtkWidget *summary;
84 GtkWidget *description;
85 gchar *url;
86 GtkWidget *answer;
87 GtkWidget *button;
88 GtkWidget *reedit;
89 GtkWidget *cancel;
90 GtkWidget *uribtn;
91 GtkWidget *attendees;
92 GtkWidget *unavail_box;
95 static GtkActionEntry vcalendar_main_menu[] = {{
96 "Message/CreateMeeting",
97 NULL, N_("Create meeting from message..."), NULL, NULL, G_CALLBACK(create_meeting_from_message_cb_ui)
98 }};
100 static void create_meeting_from_message_cb_ui(GtkAction *action, gpointer data)
102 MainWindow *mainwin = mainwindow_get_mainwindow();
103 SummaryView *summaryview = mainwin->summaryview;
104 GSList *msglist = summary_get_selected_msg_list(summaryview);
105 FolderItem *item = NULL;
106 GSList *cur;
107 gchar *msg;
108 gint total=0;
110 if (summary_is_locked(summaryview) || !msglist) {
111 if (msglist)
112 g_slist_free(msglist);
113 return;
115 total = g_slist_length(msglist);
117 msg = g_strdup_printf(_("You are about to create %d "
118 "meetings, one by one. Do you "
119 "want to continue?"),
120 total);
121 if (total > 9
122 && alertpanel(_("Warning"), msg, NULL, _("_Cancel"),
123 NULL, _("_Yes"), NULL, NULL, ALERTFOCUS_SECOND)
124 != G_ALERTALTERNATE) {
125 g_free(msg);
126 return;
128 g_free(msg);
130 main_window_cursor_wait(summaryview->mainwin);
131 gtk_cmclist_freeze(GTK_CMCLIST(summaryview->ctree));
132 folder_item_update_freeze();
133 inc_lock();
135 item = summaryview->folder_item;
137 STATUSBAR_PUSH(mainwin, _("Creating meeting..."));
139 for (cur = msglist; cur; cur = cur->next) {
140 MsgInfo *msginfo = procmsg_msginfo_get_full_info((MsgInfo *)cur->data);
141 VCalEvent *event = NULL;
142 FILE *fp = NULL;
144 if (MSG_IS_ENCRYPTED(msginfo->flags)) {
145 fp = procmime_get_first_encrypted_text_content(msginfo);
146 } else {
147 fp = procmime_get_first_text_content(msginfo);
150 if (fp) {
151 gchar *uid;
152 time_t t = time(NULL);
153 time_t t2 = t+3600;
154 gchar *org = NULL;
155 gchar *orgname = NULL;
156 gchar *summary = g_strdup(msginfo->subject ? msginfo->subject:_("no subject"));
157 gchar *description = file_read_stream_to_str(fp);
158 gchar *dtstart = g_strdup(icaltime_as_ical_string(icaltime_from_timet_with_zone(t, FALSE, NULL)));
159 gchar *dtend = g_strdup(icaltime_as_ical_string(icaltime_from_timet_with_zone(t2, FALSE, NULL)));
160 gchar *recur = NULL;
161 gchar *tzid = g_strdup("UTC");
162 gchar *url = NULL;
163 gint method = ICAL_METHOD_REQUEST;
164 gint sequence = 1;
165 gchar *created = g_strdup(icaltime_as_ical_string(icaltime_from_timet_with_zone(time(NULL), FALSE, NULL)));
166 gchar *last_modified = g_strdup(icaltime_as_ical_string(icaltime_from_timet_with_zone(time(NULL), FALSE, NULL)));
167 PrefsAccount *account = NULL;
169 claws_fclose(fp);
171 if (item && item->prefs && item->prefs->enable_default_account)
172 account = account_find_from_id(item->prefs->default_account);
174 if (!account)
175 account = account_get_cur_account();
177 if (!account)
178 goto bail;
180 org = g_strdup(account->address);
182 uid = prefs_account_generate_msgid(account);
184 event = vcal_manager_new_event(uid,
185 org, NULL, NULL/*location*/, summary, description,
186 dtstart, dtend, recur, tzid, url, method, sequence,
187 created, last_modified, ICAL_VTODO_COMPONENT);
188 g_free(uid);
190 /* hack to get default hours */
191 g_free(event->dtstart);
192 g_free(event->dtend);
193 event->dtstart = NULL;
194 event->dtend = NULL;
196 vcal_meeting_create(event);
197 vcal_manager_free_event(event);
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 g_free(created);
210 g_free(last_modified);
213 procmsg_msginfo_free(&msginfo);
216 statusbar_progress_all(0,0,0);
217 STATUSBAR_POP(mainwin);
218 inc_unlock();
219 folder_item_update_thaw();
220 gtk_cmclist_thaw(GTK_CMCLIST(summaryview->ctree));
221 main_window_cursor_normal(summaryview->mainwin);
222 g_slist_free(msglist);
225 static gchar *get_tmpfile(VCalViewer *vcalviewer)
227 gchar *tmpfile = NULL;
229 if (!vcalviewer->tmpfile) {
230 tmpfile = procmime_get_tmp_file_name(vcalviewer->mimeinfo);
231 debug_print("creating %s\n", tmpfile);
233 if (procmime_get_part(tmpfile, vcalviewer->mimeinfo) < 0) {
234 g_warning("can't get mimepart file");
235 g_free(tmpfile);
236 return NULL;
238 vcalviewer->tmpfile = tmpfile;
241 return vcalviewer->tmpfile;
244 static GtkWidget *vcal_viewer_get_widget(MimeViewer *_mimeviewer)
246 VCalViewer *vcalviewer = (VCalViewer *) _mimeviewer;
248 debug_print("vcal_viewer_get_widget\n");
249 gtk_widget_show_all(vcalviewer->scrolledwin);
250 return vcalviewer->scrolledwin;
253 static void vcal_viewer_clear_viewer(MimeViewer *_mimeviewer)
255 VCalViewer *vcalviewer = (VCalViewer *) _mimeviewer;
257 debug_print("vcal_viewer_clear_viewer\n");
259 g_free(vcalviewer->file);
260 vcalviewer->file = NULL;
261 if (vcalviewer->tmpfile) {
262 debug_print("unlinking %s\n", vcalviewer->tmpfile);
263 g_unlink(vcalviewer->tmpfile);
264 g_free(vcalviewer->tmpfile);
265 vcalviewer->tmpfile = NULL;
267 vcalviewer->mimeinfo = NULL;
270 static VCalEvent *vcalviewer_get_component(const gchar *file, const gchar *charset)
272 gchar *compstr = NULL;
273 VCalEvent *event = NULL;
274 FILE *fp;
275 GByteArray *array;
276 gchar buf[BUFSIZ];
277 gint n_read;
279 g_return_val_if_fail(file != NULL, NULL);
281 if ((fp = claws_fopen(file, "rb")) == NULL) {
282 FILE_OP_ERROR(file, "claws_fopen");
283 return NULL;
286 array = g_byte_array_new();
288 while ((n_read = claws_fread(buf, sizeof(gchar), sizeof(buf), fp)) > 0) {
289 if (n_read < sizeof(buf) && claws_ferror(fp))
290 break;
291 g_byte_array_append(array, (guchar *)buf, n_read);
294 if (claws_ferror(fp)) {
295 FILE_OP_ERROR("file stream", "claws_fread");
296 g_byte_array_free(array, TRUE);
297 claws_fclose(fp);
298 return NULL;
301 buf[0] = '\0';
302 g_byte_array_append(array, (guchar *)buf, 1);
303 compstr = (gchar *)array->data;
304 g_byte_array_free(array, FALSE);
306 claws_fclose(fp);
308 if (compstr) {
309 event = vcal_get_event_from_ical(compstr, charset);
310 g_free(compstr);
313 return event;
316 #define GTK_LABEL_SET_TEXT_TRIMMED(label, text) { \
317 gchar *tmplbl = strretchomp(g_strdup(text)); \
318 gtk_label_set_text(label, tmplbl); \
319 g_free(tmplbl); \
322 static void vcalviewer_answer_set_choices(VCalViewer *vcalviewer, VCalEvent *event, icalproperty_method method);
324 static void vcalviewer_reset(VCalViewer *vcalviewer)
326 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), "-");
327 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->who), "-");
328 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->location), "-");
329 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->summary), "-");
330 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->description), "-");
331 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->start), "-");
332 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->end), "-");
333 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->attendees), "-");
334 g_free(vcalviewer->url);
335 vcalviewer->url = NULL;
336 gtk_widget_hide(vcalviewer->uribtn);
337 vcalviewer_answer_set_choices(vcalviewer, NULL, ICAL_METHOD_CANCEL);
340 static void vcalviewer_show_error(VCalViewer *vcalviewer, const gchar *msg)
342 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), msg);
345 static void vcalviewer_hide_error(VCalViewer *vcalviewer)
347 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), "-");
350 static void vcalviewer_show_unavailable(VCalViewer *vcalviewer, gboolean visi)
352 if (visi)
353 gtk_widget_show_all(vcalviewer->unavail_box);
354 else
355 gtk_widget_hide(vcalviewer->unavail_box);
358 static void vcalviewer_answer_set_choices(VCalViewer *vcalviewer, VCalEvent *event, icalproperty_method method)
360 int i = 0;
362 gtk_widget_hide(vcalviewer->reedit);
363 gtk_widget_hide(vcalviewer->cancel);
364 gtk_widget_hide(vcalviewer->answer);
365 gtk_widget_hide(vcalviewer->button);
367 for (i = 0; i < 3; i++)
368 gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(vcalviewer->answer), 0);
370 vcalviewer_show_unavailable(vcalviewer, FALSE);
372 if (method == ICAL_METHOD_REQUEST && event && !event->rec_occurrence) {
373 PrefsAccount *account = vcal_manager_get_account_from_event(event);
375 if (!account)
376 account = vcal_manager_get_account_from_event(vcalviewer->event);
378 if (!account && event) {
379 account = account_get_default();
380 vcal_manager_update_answer(event, account->address,
381 account->name,
382 ICAL_PARTSTAT_NEEDSACTION,
383 ICAL_CUTYPE_INDIVIDUAL);
385 if (account) {
386 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(vcalviewer->answer), _("Accept"));
387 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(vcalviewer->answer), _("Tentatively accept"));
388 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(vcalviewer->answer), _("Decline"));
389 gtk_widget_set_sensitive(vcalviewer->answer, TRUE);
390 gtk_widget_set_sensitive(vcalviewer->button, TRUE);
391 gtk_widget_show(vcalviewer->answer);
392 gtk_widget_show(vcalviewer->button);
393 } else {
394 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(vcalviewer->answer), "-");
395 gtk_widget_set_sensitive(vcalviewer->answer, FALSE);
396 gtk_widget_set_sensitive(vcalviewer->button, FALSE);
398 } else {
399 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(vcalviewer->answer), "-");
400 gtk_widget_set_sensitive(vcalviewer->answer, FALSE);
401 gtk_widget_set_sensitive(vcalviewer->button, FALSE);
403 gtk_combo_box_set_active(GTK_COMBO_BOX(vcalviewer->answer), 0);
405 if (event && event->method == ICAL_METHOD_REQUEST) {
406 PrefsAccount *account = vcal_manager_get_account_from_event(event);
407 gchar *internal_ifb = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
408 "vcalendar", G_DIR_SEPARATOR_S,
409 "internal.ifb", NULL);
410 gchar *myfb = file_read_to_str(internal_ifb);
411 g_free(internal_ifb);
412 if (account) {
413 icalparameter_partstat answer =
414 vcal_manager_get_reply_for_attendee(event, account->address);
416 if (answer == ICAL_PARTSTAT_ACCEPTED)
417 gtk_combo_box_set_active(GTK_COMBO_BOX(vcalviewer->answer), 0);
418 if (answer == ICAL_PARTSTAT_TENTATIVE)
419 gtk_combo_box_set_active(GTK_COMBO_BOX(vcalviewer->answer), 1);
420 if (answer == ICAL_PARTSTAT_DECLINED)
421 gtk_combo_box_set_active(GTK_COMBO_BOX(vcalviewer->answer), 2);
422 if (event->dtstart && event->dtend && myfb && *myfb
423 && answer != ICAL_PARTSTAT_ACCEPTED
424 && answer != ICAL_PARTSTAT_TENTATIVE) {
425 if (!attendee_available(NULL, event->dtstart, event->dtend, myfb))
426 vcalviewer_show_unavailable(vcalviewer, TRUE);
429 g_free(myfb);
432 g_free(vcalviewer->url);
433 if (event && event->url && *(event->url)) {
434 vcalviewer->url = g_strdup(event->url);
435 gtk_widget_show(vcalviewer->uribtn);
436 } else {
437 vcalviewer->url = NULL;
438 gtk_widget_hide(vcalviewer->uribtn);
442 static FolderItem *vcalendar_get_current_item(void)
444 MainWindow *mainwin = mainwindow_get_mainwindow();
445 FolderItem *item = NULL;
446 Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
448 if (mainwin) {
449 item = mainwin->summaryview->folder_item;
450 if (item == NULL)
451 return NULL;
452 if (item->folder == folder)
453 return item;
454 else
455 return folder->inbox;
456 } else {
457 return NULL;
461 void vcalviewer_display_event (VCalViewer *vcalviewer, VCalEvent *event)
463 GSList *list = NULL;
464 gchar *attendees = NULL;
465 gboolean mine = FALSE;
466 gchar *label = NULL;
467 gboolean save_evt = FALSE;
468 FolderItem *item = vcalendar_get_current_item();
469 if (!event)
470 return;
471 if (!vcalviewer)
472 return;
474 /* general */
475 if (event->type == ICAL_VTODO_COMPONENT) {
477 label = g_strjoin(" ", _("You have a Todo item."),
478 _("Details follow:"), NULL);
479 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
481 } else if (event->method == ICAL_METHOD_REQUEST) {
483 if (account_find_from_address(event->organizer, FALSE)) {
484 label = g_strjoin(" ", _("You have created a meeting."),
485 _("Details follow:"), NULL);
486 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
487 mine = TRUE;
488 } else {
489 label = g_strjoin(" ", _("You have been invited to a meeting."),
490 _("Details follow:"), NULL);
491 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
494 } else if (event->method == ICAL_METHOD_CANCEL) {
496 label = g_strjoin(" ",
497 _("A meeting to which you had been invited has been cancelled."),
498 _("Details follow:"), NULL);
499 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
500 save_evt = TRUE;
501 vcalendar_refresh_folder_contents(item);
502 } else if (event->method == ICAL_METHOD_REPLY) {
503 /* don't change label */
504 } else {
506 label = g_strjoin(" ", _("You have been forwarded an appointment."),
507 _("Details follow:"), NULL);
508 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
511 g_free(label);
513 /* organizer */
514 if (event->orgname && *(event->orgname)
515 && event->organizer && *(event->organizer)) {
516 gchar *addr = g_strconcat(event->orgname, " <", event->organizer, ">", NULL);
517 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->who), addr);
518 g_free(addr);
519 } else if (event->organizer && *(event->organizer)) {
520 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->who), event->organizer);
521 } else {
522 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->who), "-");
525 /* location */
526 if (event->location && *(event->location)) {
527 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->location), event->location);
528 } else {
529 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->location), "-");
532 /* summary */
533 if (event->summary && *(event->summary)) {
534 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->summary), event->summary);
535 } else {
536 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->summary), "-");
539 /* description */
540 if (event->description && *(event->description)) {
541 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->description), event->description);
542 } else {
543 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->description), "-");
546 /* url */
547 g_free(vcalviewer->url);
548 if (event->url && *(event->url)) {
549 vcalviewer->url = g_strdup(event->url);
550 gtk_widget_show(vcalviewer->uribtn);
551 } else {
552 vcalviewer->url = NULL;
553 gtk_widget_hide(vcalviewer->uribtn);
556 /* start */
557 if (event->start && *(event->start)) {
558 if (event->recur && *(event->recur)) {
559 gchar *tmp = g_strdup_printf("%s <span weight=\"bold\">%s</span>",
560 _("(this event recurs)"), 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("%s <span weight=\"bold\">%s</span>",
566 _("(this event is part of a recurring event)"), event->start);
567 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->start), tmp);
568 gtk_label_set_use_markup(GTK_LABEL(vcalviewer->start), TRUE);
569 g_free(tmp);
570 } else {
571 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->start), event->start);
573 } else {
574 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->start), "-");
577 /* end */
578 if (event->end && *(event->end)) {
579 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->end), event->end);
580 } else {
581 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->end), "-");
584 /* attendees */
585 attendees = g_strdup("");
586 for (list = vcal_manager_get_answers_emails(event);
587 list && list->data; list = list->next) {
588 gchar *attendee = (gchar *)list->data;
589 gchar *name = vcal_manager_get_attendee_name(event, attendee);
590 gchar *ename = g_markup_printf_escaped("%s", name?name:"");
591 gchar *eatt = g_markup_printf_escaped("%s", attendee);
592 icalparameter_partstat acode = vcal_manager_get_reply_for_attendee(event, attendee);
593 gchar *answer = vcal_manager_get_reply_text_for_attendee(event, attendee);
594 gchar *type = vcal_manager_get_cutype_text_for_attendee(event, attendee);
595 gchar *tmp = NULL;
596 gint e_len, n_len;
597 tmp = g_strdup_printf(
598 "%s%s&lt;%s&gt; (%s, <span%s>%s</span>)",
599 (ename && *(ename))?ename:"",
600 (ename && *(ename))?" ":"",
601 (eatt && *(eatt))?eatt:"",
602 (type && *(type))?type:"",
603 (acode != ICAL_PARTSTAT_ACCEPTED ? " foreground=\"red\"":""),
604 (answer && *(answer))?answer:"");
605 e_len = strlen(attendees);
606 n_len = strlen(tmp);
607 if (e_len) {
608 attendees = g_realloc(attendees, e_len+n_len+2);
609 *(attendees+e_len) = '\n';
610 strcpy(attendees+e_len+1, tmp);
611 } else {
612 attendees = g_realloc(attendees, e_len+n_len+1);
613 strcpy(attendees, tmp);
615 g_free(tmp);
616 g_free(answer);
617 g_free(type);
618 g_free(name);
619 g_free(ename);
620 g_free(eatt);
623 if (attendees && *(attendees)) {
624 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->attendees), attendees);
625 } else {
626 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->attendees), "-");
628 g_free(attendees);
629 gtk_label_set_use_markup(GTK_LABEL(vcalviewer->attendees), TRUE);
631 /* buttons */
632 if (!mine)
633 if (event->type != ICAL_VTODO_COMPONENT)
634 vcalviewer_answer_set_choices(vcalviewer, event, event->method);
635 else
636 vcalviewer_answer_set_choices(vcalviewer, event, ICAL_METHOD_PUBLISH);
637 else {
638 vcalviewer_answer_set_choices(vcalviewer, event, ICAL_METHOD_REPLY);
639 gtk_widget_show(vcalviewer->reedit);
640 gtk_widget_show(vcalviewer->cancel);
643 /* save if cancelled */
644 if (save_evt)
645 vcal_manager_save_event(event, TRUE);
648 gchar *vcalviewer_get_uid_from_mimeinfo(MimeInfo *mimeinfo)
650 gchar *compstr = NULL;
651 gchar *res = NULL;
652 VCalEvent *event = NULL;
654 compstr = procmime_get_part_as_string(mimeinfo, TRUE);
656 event = vcal_get_event_from_ical(compstr, NULL);
657 if (event)
658 res = g_strdup(event->uid);
660 vcal_manager_free_event(event);
662 debug_print("got uid: %s\n", res);
663 return res;
667 static void vcalviewer_get_request_values(VCalViewer *vcalviewer, MimeInfo *mimeinfo, gboolean is_todo)
669 VCalEvent *saved_event = NULL;
670 const gchar *saveme = procmime_mimeinfo_get_parameter(mimeinfo, "vcalsave");
672 if (!vcalviewer->event)
673 return;
675 /* see if we have it registered and more recent */
676 saved_event = vcal_manager_load_event(vcalviewer->event->uid);
677 if (saved_event && saved_event->sequence > vcalviewer->event->sequence) {
678 saved_event->method = vcalviewer->event->method;
679 vcalviewer_display_event(vcalviewer, saved_event);
680 vcal_manager_free_event(saved_event);
681 return;
682 } else if (saved_event) {
683 vcal_manager_free_event(saved_event);
686 /* load it and register it */
688 if (!saveme || strcmp(saveme,"no"))
689 vcal_manager_save_event(vcalviewer->event, FALSE);
691 vcalviewer_display_event(vcalviewer, vcalviewer->event);
694 static void vcalviewer_get_reply_values(VCalViewer *vcalviewer, MimeInfo *mimeinfo)
696 VCalEvent *saved_event = NULL;
697 gchar *attendee = NULL, *label = NULL;
698 Answer *answer = NULL;
700 if (!vcalviewer->event)
701 return;
703 if (!vcalviewer->event->answers || g_slist_length(vcalviewer->event->answers) > 1) {
704 g_warning("strange, no answers or more than one");
707 if (vcalviewer->event->answers) {
708 answer = (Answer *)vcalviewer->event->answers->data;
709 attendee = g_strdup(answer->attendee);
713 if (!answer) {
714 label = g_strjoin(" ",
715 _("You have received an answer to an unknown meeting proposal."),
716 _("Details follow:"), NULL);
717 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
718 } else {
719 label = g_strdup_printf(_("You have received an answer to a meeting proposal.\n"
720 "%s has %s the invitation whose details follow:"),
721 attendee, vcal_manager_answer_get_text(answer->answer));
722 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), label);
723 g_free(attendee);
725 g_free(label);
727 saved_event = vcal_manager_load_event(vcalviewer->event->uid);
728 if (saved_event && answer) {
729 vcal_manager_update_answer(saved_event,
730 answer->attendee, answer->name, answer->answer, answer->cutype);
731 vcal_manager_save_event(saved_event, TRUE);
732 saved_event->method = vcalviewer->event->method;
733 vcalviewer_display_event(vcalviewer, saved_event);
734 vcal_manager_free_event(saved_event);
735 return;
736 } else if (saved_event) {
737 vcal_manager_free_event(saved_event);
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);
750 } else {
751 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->who), "-");
754 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->location),
755 vcalviewer->event->location?vcalviewer->event->location:"-");
757 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->summary),
758 vcalviewer->event->summary?vcalviewer->event->summary:"-");
760 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->description),
761 vcalviewer->event->description?vcalviewer->event->description:"-");
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);
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:"-");
777 GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->attendees), "-");
779 vcalviewer_answer_set_choices(vcalviewer, NULL, ICAL_METHOD_REPLY);
782 static void vcalviewer_get_event(VCalViewer *vcalviewer, MimeInfo *mimeinfo)
784 gchar *tmpfile = get_tmpfile(vcalviewer);
785 const gchar *charset = procmime_mimeinfo_get_parameter(mimeinfo, "charset");
787 if (!charset)
788 charset = CS_WINDOWS_1252;
790 if (!strcasecmp(charset, CS_ISO_8859_1))
791 charset = CS_WINDOWS_1252;
793 if (vcalviewer->event) {
794 vcal_manager_free_event(vcalviewer->event);
795 vcalviewer->event = NULL;
798 if (!tmpfile) {
799 vcalviewer_reset(vcalviewer);
800 vcalviewer_show_error(vcalviewer, _("Error - could not get the calendar MIME part."));
801 return;
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;
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."));
825 static VCalViewer *s_vcalviewer = NULL;
827 static void vcal_viewer_show_mimepart(MimeViewer *_mimeviewer, const gchar *file, MimeInfo *mimeinfo)
829 VCalViewer *vcalviewer = (VCalViewer *) _mimeviewer;
830 GtkAllocation allocation;
832 START_TIMING("");
834 s_vcalviewer = vcalviewer;
836 if (mimeinfo == NULL) {
837 vcal_viewer_clear_viewer(_mimeviewer);
838 END_TIMING();
839 return;
841 debug_print("vcal_viewer_show_mimepart : %s\n", file);
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);
859 if (prefs_common_get_prefs()->textfont) {
860 PangoFontDescription *font_desc;
862 font_desc = pango_font_description_from_string
863 (prefs_common_get_prefs()->textfont);
864 if (font_desc) {
865 gtk_widget_override_font(
866 vcalviewer->description, font_desc);
867 pango_font_description_free(font_desc);
870 END_TIMING();
873 void vcalviewer_reload(FolderItem *item)
875 if (s_vcalviewer) {
876 MainWindow *mainwin = mainwindow_get_mainwindow();
877 Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
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);
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);
892 static void vcal_viewer_destroy_viewer(MimeViewer *_mimeviewer)
894 VCalViewer *vcalviewer = (VCalViewer *) _mimeviewer;
896 debug_print("vcal_viewer_destroy_viewer\n");
898 if (s_vcalviewer == vcalviewer)
899 s_vcalviewer = NULL;
900 vcal_viewer_clear_viewer(_mimeviewer);
901 g_free(vcalviewer);
904 static gboolean vcalviewer_reedit_cb(GtkButton *widget, gpointer data)
906 VCalViewer *vcalviewer = (VCalViewer *)data;
907 gchar * uid = vcalviewer_get_uid_from_mimeinfo(vcalviewer->mimeinfo);
908 VCalEvent *event = NULL;
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;
918 static gboolean vcalviewer_uribtn_cb(GtkButton *widget, gpointer data)
920 VCalViewer *vcalviewer = (VCalViewer *)data;
922 if (vcalviewer->url)
923 open_uri(vcalviewer->url, prefs_common_get_uri_cmd());
925 return TRUE;
928 void vcalendar_refresh_folder_contents(FolderItem *item)
930 g_return_if_fail(item != NULL);
932 Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
933 if (folder && item->folder == folder) {
934 MainWindow *mainwin = mainwindow_get_mainwindow();
935 folder_item_scan(item);
936 if (mainwin->summaryview->folder_item == item) {
937 summary_show(mainwin->summaryview, item, FALSE);
942 static void send_cancel_notify_toggled_cb(GtkToggleButton *button, gboolean *data)
944 *data = gtk_toggle_button_get_active(button);
947 void vcalendar_cancel_meeting(FolderItem *item, const gchar *uid)
949 VCalEvent *event = NULL;
950 VCalMeeting *meet = NULL;
951 gchar *file = NULL;
952 gint val = 0;
953 Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
954 gboolean redisp = FALSE;
955 GtkWidget *send_notify_chkbtn = gtk_check_button_new_with_label(_("Send a notification to the attendees"));
956 gboolean send_notify = TRUE;
958 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(send_notify_chkbtn), TRUE);
959 gtk_widget_show(send_notify_chkbtn);
960 g_signal_connect(G_OBJECT(send_notify_chkbtn), "toggled",
961 G_CALLBACK(send_cancel_notify_toggled_cb),
962 &send_notify);
964 val = alertpanel_full(_("Cancel meeting"),
965 _("Are you sure you want to cancel this meeting?"),
966 NULL, _("_No"), NULL, _("_Yes"), NULL, NULL,
967 ALERTFOCUS_FIRST, FALSE, send_notify_chkbtn, ALERT_WARNING);
969 if (val != G_ALERTALTERNATE)
970 return;
972 event = vcal_manager_load_event(uid);
973 if (!event)
974 return;
975 event->method = ICAL_METHOD_CANCEL;
977 if (folder) {
978 MainWindow *mainwin = mainwindow_get_mainwindow();
979 if (mainwin->summaryview->folder_item == item) {
980 redisp = TRUE;
981 summary_show(mainwin->summaryview, NULL, FALSE);
985 if (send_notify) {
986 meet = vcal_meeting_create_hidden(event);
987 if (!vcal_meeting_send(meet)) {
988 event->method = ICAL_METHOD_REQUEST;
989 vcal_manager_save_event(event, TRUE);
990 vcal_manager_free_event(event);
991 if (folder)
992 folder_item_scan(item);
994 if (folder && redisp) {
995 MainWindow *mainwin = mainwindow_get_mainwindow();
996 summary_show(mainwin->summaryview, item, FALSE);
998 return;
1002 vcal_manager_save_event(event, TRUE);
1004 file = vcal_manager_get_event_file(event->uid);
1005 g_unlink(file);
1006 vcal_manager_free_event(event);
1007 g_free(file);
1008 if (folder)
1009 folder_item_scan(item);
1010 if (folder && redisp) {
1011 MainWindow *mainwin = mainwindow_get_mainwindow();
1012 summary_show(mainwin->summaryview, item, FALSE);
1015 return;
1018 static gboolean vcalviewer_cancel_cb(GtkButton *widget, gpointer data)
1020 VCalViewer *vcalviewer = (VCalViewer *)data;
1021 FolderItem *item = vcalendar_get_current_item();
1022 gchar * uid = vcalviewer_get_uid_from_mimeinfo(vcalviewer->mimeinfo);
1023 vcalendar_cancel_meeting(item, uid);
1024 return TRUE;
1027 static gboolean vcalviewer_action_cb(GtkButton *widget, gpointer data)
1029 VCalViewer *vcalviewer = (VCalViewer *)data;
1030 gint index = gtk_combo_box_get_active(GTK_COMBO_BOX(vcalviewer->answer));
1031 icalparameter_partstat reply[3] = {ICAL_PARTSTAT_ACCEPTED, ICAL_PARTSTAT_TENTATIVE, ICAL_PARTSTAT_DECLINED};
1032 PrefsAccount *account = NULL;
1033 VCalEvent *saved_event = NULL, *event = NULL;
1034 debug_print("index chosen %d\n", index);
1036 if (index < 0 || index > 2) {
1037 return TRUE;
1040 s_vcalviewer = vcalviewer;
1042 if (!vcalviewer->event) {
1043 g_warning("can't get event");
1044 return TRUE;
1047 /* see if we have it registered and more recent */
1048 event = vcalviewer->event;
1049 saved_event = vcal_manager_load_event(vcalviewer->event->uid);
1050 if (saved_event && saved_event->sequence >= vcalviewer->event->sequence) {
1051 saved_event->method = vcalviewer->event->method;
1052 event = saved_event;
1053 } else if (saved_event) {
1054 vcal_manager_free_event(saved_event);
1055 saved_event = NULL;
1057 account = vcal_manager_get_account_from_event(event);
1059 if (!account) {
1060 AlertValue val = alertpanel_full(_("No account found"),
1061 _("You have no account matching any attendee.\n"
1062 "Do you want to reply anyway?"),
1063 NULL, _("_Cancel"), NULL, _("Reply anyway"), NULL, NULL,
1064 ALERTFOCUS_SECOND, FALSE, NULL, ALERT_QUESTION);
1065 if (val == G_ALERTALTERNATE) {
1066 account = account_get_default();
1067 vcal_manager_update_answer(event, account->address,
1068 account->name,
1069 ICAL_PARTSTAT_NEEDSACTION,
1070 ICAL_CUTYPE_INDIVIDUAL);
1071 } else {
1072 if (saved_event)
1073 vcal_manager_free_event(saved_event);
1074 return TRUE;
1078 vcal_manager_update_answer(event, account->address, account->name, reply[index], 0);
1080 if (event->organizer && *(event->organizer) &&
1081 !vcal_manager_reply(account, event)) {
1082 g_warning("couldn't send reply");
1083 } else {
1084 debug_print("no organizer, not sending answer\n");
1087 vcal_manager_save_event(event, TRUE);
1089 vcalviewer_display_event(vcalviewer, event);
1090 if (saved_event)
1091 vcal_manager_free_event(saved_event);
1092 return TRUE;
1095 #define TABLE_ADD_LINE(label_text, widget) { \
1096 gchar *tmpstr = g_strdup_printf("<span weight=\"bold\">%s</span>",\
1097 label_text); \
1098 GtkWidget *label = gtk_label_new(tmpstr); \
1099 g_free(tmpstr); \
1100 gtk_label_set_use_markup (GTK_LABEL (label), TRUE); \
1101 gtk_label_set_xalign (GTK_LABEL(label), 1.0); \
1102 gtk_grid_attach(GTK_GRID(vcalviewer->table), label, 0, i, 1, 1);\
1103 gtk_widget_set_hexpand(label, TRUE); \
1104 gtk_widget_set_halign(label, GTK_ALIGN_FILL); \
1105 gtk_grid_attach(GTK_GRID(vcalviewer->table), widget, \
1106 1, i, 1, 1); \
1107 gtk_widget_set_hexpand(widget, TRUE); \
1108 gtk_widget_set_halign(widget, GTK_ALIGN_FILL); \
1109 if (GTK_IS_LABEL(widget)) { \
1110 gtk_label_set_use_markup(GTK_LABEL (widget), TRUE); \
1111 gtk_label_set_xalign(GTK_LABEL(widget), 0.0); \
1112 gtk_label_set_yalign(GTK_LABEL(widget), 0.0); \
1113 gtk_label_set_line_wrap_mode(GTK_LABEL(widget), \
1114 PANGO_WRAP_CHAR); \
1115 gtk_label_set_line_wrap(GTK_LABEL(widget), TRUE); \
1117 i++; \
1120 static gchar *vcal_viewer_get_selection(MimeViewer *_viewer)
1122 VCalViewer *viewer = (VCalViewer *)_viewer;
1123 if (viewer->summary == NULL)
1124 return NULL;
1125 if (gtk_label_get_text(GTK_LABEL(viewer->description))
1126 && *(gtk_label_get_text(GTK_LABEL(viewer->description))) > 2) {
1127 gint start, end;
1128 if (gtk_label_get_selection_bounds(GTK_LABEL(viewer->description),
1129 &start, &end)) {
1130 gchar *tmp = g_strdup(gtk_label_get_text(
1131 GTK_LABEL(viewer->description))+start);
1132 tmp[end-start] = '\0';
1133 return tmp;
1134 } else {
1135 return g_strdup(gtk_label_get_text(GTK_LABEL(viewer->description)));
1138 else if (gtk_label_get_text(GTK_LABEL(viewer->summary))
1139 && *(gtk_label_get_text(GTK_LABEL(viewer->summary))) > 2)
1140 return g_strdup(gtk_label_get_text(GTK_LABEL(viewer->summary)));
1141 else
1142 return NULL;
1146 static gboolean vcal_viewer_scroll_page(MimeViewer *_viewer, gboolean up)
1148 VCalViewer *viewer = (VCalViewer *)_viewer;
1149 GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment(
1150 GTK_SCROLLED_WINDOW(viewer->scrolledwin));
1152 return gtkutils_scroll_page(viewer->table, vadj, up);
1155 static void vcal_viewer_scroll_one_line(MimeViewer *_viewer, gboolean up)
1157 VCalViewer *viewer = (VCalViewer *)_viewer;
1158 GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment(
1159 GTK_SCROLLED_WINDOW(viewer->scrolledwin));
1161 gtkutils_scroll_one_line(viewer->table, vadj, up);
1164 MimeViewer *vcal_viewer_create(void)
1166 VCalViewer *vcalviewer;
1167 int i = 0;
1168 GtkWidget *hbox = NULL, *vbox = NULL;
1169 GtkWidget *warning_img;
1170 GtkWidget *warning_label;
1172 debug_print("Creating vcal view...\n");
1173 vcalviewer = g_new0(VCalViewer, 1);
1174 vcalviewer->mimeviewer.factory = &vcal_viewer_factory;
1176 vcalviewer->mimeviewer.get_widget = vcal_viewer_get_widget;
1177 vcalviewer->mimeviewer.show_mimepart = vcal_viewer_show_mimepart;
1178 vcalviewer->mimeviewer.clear_viewer = vcal_viewer_clear_viewer;
1179 vcalviewer->mimeviewer.destroy_viewer = vcal_viewer_destroy_viewer;
1180 vcalviewer->mimeviewer.get_selection = vcal_viewer_get_selection;
1181 vcalviewer->mimeviewer.scroll_page = vcal_viewer_scroll_page;
1182 vcalviewer->mimeviewer.scroll_one_line = vcal_viewer_scroll_one_line;
1184 vcalviewer->table = gtk_grid_new();
1185 vcalviewer->type = gtk_label_new("meeting");
1186 vcalviewer->who = gtk_label_new("who");
1187 vcalviewer->start = gtk_label_new("start");
1188 vcalviewer->end = gtk_label_new("end");
1189 vcalviewer->location = gtk_label_new("location");
1190 vcalviewer->summary = gtk_label_new("summary");
1191 vcalviewer->description = gtk_label_new("description");
1192 vcalviewer->attendees = gtk_label_new("attendees");
1194 vcalviewer->answer = gtk_combo_box_text_new();
1195 vcalviewer->url = NULL;
1196 vcalviewer->button = gtk_button_new_with_label(_("Answer"));
1197 vcalviewer->reedit = gtk_button_new_with_label(_("Edit meeting..."));
1198 vcalviewer->cancel = gtk_button_new_with_label(_("Cancel meeting..."));
1199 vcalviewer->uribtn = gtk_button_new_with_label(_("Launch website"));
1200 vcalviewer->unavail_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
1201 warning_img = gtk_image_new_from_icon_name
1202 ("dialog-warning", GTK_ICON_SIZE_SMALL_TOOLBAR);
1203 warning_label = gtk_label_new(_("You are already busy at this time."));
1205 gtk_box_pack_start(GTK_BOX(vcalviewer->unavail_box), warning_img, FALSE, FALSE, 0);
1206 gtk_box_pack_start(GTK_BOX(vcalviewer->unavail_box), warning_label, FALSE, FALSE, 0);
1208 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
1209 gtk_box_pack_start(GTK_BOX(hbox), vcalviewer->answer, FALSE, FALSE, 0);
1210 gtk_box_pack_start(GTK_BOX(hbox), vcalviewer->button, FALSE, FALSE, 0);
1211 gtk_box_pack_start(GTK_BOX(hbox), vcalviewer->reedit, FALSE, FALSE, 0);
1212 gtk_box_pack_start(GTK_BOX(hbox), vcalviewer->cancel, FALSE, FALSE, 0);
1213 gtk_box_pack_start(GTK_BOX(hbox), vcalviewer->uribtn, FALSE, FALSE, 0);
1215 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
1216 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1217 gtk_box_pack_start(GTK_BOX(vbox), vcalviewer->unavail_box, FALSE, FALSE, 0);
1219 vcalviewer_answer_set_choices(vcalviewer, NULL, ICAL_METHOD_REQUEST);
1221 gtk_label_set_selectable(GTK_LABEL(vcalviewer->type), TRUE);
1222 gtk_label_set_selectable(GTK_LABEL(vcalviewer->who), TRUE);
1223 gtk_label_set_selectable(GTK_LABEL(vcalviewer->start), TRUE);
1224 gtk_label_set_selectable(GTK_LABEL(vcalviewer->end), TRUE);
1225 gtk_label_set_selectable(GTK_LABEL(vcalviewer->location), TRUE);
1226 gtk_label_set_selectable(GTK_LABEL(vcalviewer->summary), TRUE);
1227 gtk_label_set_selectable(GTK_LABEL(vcalviewer->description), TRUE);
1228 gtk_label_set_selectable(GTK_LABEL(vcalviewer->attendees), TRUE);
1230 g_signal_connect(G_OBJECT(vcalviewer->button), "clicked",
1231 G_CALLBACK(vcalviewer_action_cb), vcalviewer);
1233 g_signal_connect(G_OBJECT(vcalviewer->reedit), "clicked",
1234 G_CALLBACK(vcalviewer_reedit_cb), vcalviewer);
1236 g_signal_connect(G_OBJECT(vcalviewer->cancel), "clicked",
1237 G_CALLBACK(vcalviewer_cancel_cb), vcalviewer);
1239 g_signal_connect(G_OBJECT(vcalviewer->uribtn), "clicked",
1240 G_CALLBACK(vcalviewer_uribtn_cb), vcalviewer);
1242 TABLE_ADD_LINE(_("Event:"), vcalviewer->type);
1243 TABLE_ADD_LINE(_("Organizer:"), vcalviewer->who);
1244 TABLE_ADD_LINE(_("Location:"), vcalviewer->location);
1245 TABLE_ADD_LINE(_("Summary:"), vcalviewer->summary);
1246 TABLE_ADD_LINE(_("Starting:"), vcalviewer->start);
1247 TABLE_ADD_LINE(_("Ending:"), vcalviewer->end);
1248 TABLE_ADD_LINE(_("Description:"), vcalviewer->description);
1249 TABLE_ADD_LINE(_("Attendees:"), vcalviewer->attendees);
1250 gtk_label_set_line_wrap(GTK_LABEL(vcalviewer->attendees), FALSE);
1251 TABLE_ADD_LINE(_("Action:"), vbox);
1253 vcalviewer->scrolledwin = gtk_scrolled_window_new(NULL, NULL);
1254 gtk_widget_set_name(GTK_WIDGET(vcalviewer->scrolledwin), "vcalendar_viewer");
1255 gtk_container_add(GTK_CONTAINER(vcalviewer->scrolledwin),
1256 vcalviewer->table);
1257 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vcalviewer->scrolledwin),
1258 GTK_POLICY_NEVER,
1259 GTK_POLICY_AUTOMATIC);
1261 gtk_widget_show_all(vcalviewer->scrolledwin);
1262 return (MimeViewer *) vcalviewer;
1265 static gchar *content_types[] =
1266 {"text/calendar", NULL};
1268 MimeViewerFactory vcal_viewer_factory =
1270 content_types,
1272 vcal_viewer_create,
1275 static gint alert_timeout_tag = 0;
1276 static gint scan_timeout_tag = 0;
1278 static gboolean vcal_webcal_check(gpointer data)
1280 Folder *root = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
1282 if (prefs_common_get_prefs()->work_offline)
1283 return TRUE;
1285 manual_update = FALSE;
1286 folderview_check_new(root);
1287 manual_update = TRUE;
1288 return TRUE;
1291 static guint context_menu_id = 0;
1292 static guint main_menu_id = 0;
1294 void vcalendar_init(void)
1296 MainWindow *mainwin = mainwindow_get_mainwindow();
1297 Folder *folder = NULL;
1298 gchar *directory = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
1299 "vcalendar", NULL);
1300 START_TIMING("");
1301 if (!is_dir_exist(directory) && make_dir (directory) != 0) {
1302 g_free(directory);
1303 return;
1306 g_free(directory);
1308 vcal_prefs_init();
1310 mimeview_register_viewer_factory(&vcal_viewer_factory);
1311 folder_register_class(vcal_folder_get_class());
1313 folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
1314 if (!folder) {
1315 START_TIMING("creating folder");
1316 folder = folder_new(vcal_folder_get_class(), PLUGIN_NAME, NULL);
1317 folder->klass->create_tree(folder);
1318 folder_add(folder);
1319 folder_scan_tree(folder, TRUE);
1320 END_TIMING();
1323 if (!folder->inbox) {
1324 folder->klass->create_tree(folder);
1325 folder_scan_tree(folder, TRUE);
1327 if (folder->klass->scan_required(folder, folder->inbox)) {
1328 START_TIMING("scanning folder");
1329 folder_item_scan(folder->inbox);
1330 END_TIMING();
1333 vcal_folder_gtk_init();
1335 alert_timeout_tag = g_timeout_add(60*1000,
1336 (GSourceFunc)vcal_meeting_alert_check,
1337 (gpointer)NULL);
1338 scan_timeout_tag = g_timeout_add(3600*1000,
1339 (GSourceFunc)vcal_webcal_check,
1340 (gpointer)NULL);
1341 if (prefs_common_get_prefs()->enable_color) {
1342 uri_color = prefs_common_get_prefs()->color[COL_URI];
1345 gtk_action_group_add_actions(mainwin->action_group, vcalendar_main_menu,
1346 1, (gpointer)mainwin);
1347 MENUITEM_ADDUI_ID_MANAGER(mainwin->ui_manager, "/Menu/Message", "CreateMeeting",
1348 "Message/CreateMeeting", GTK_UI_MANAGER_MENUITEM,
1349 main_menu_id)
1350 MENUITEM_ADDUI_ID_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "CreateMeeting",
1351 "Message/CreateMeeting", GTK_UI_MANAGER_MENUITEM,
1352 context_menu_id)
1353 END_TIMING();
1356 void vcalendar_done(void)
1358 MainWindow *mainwin = mainwindow_get_mainwindow();
1359 FolderView *folderview = NULL;
1360 FolderItem *fitem = NULL;
1362 icalmemory_free_ring();
1364 vcal_folder_free_data();
1366 if (mainwin == NULL)
1367 return;
1369 folderview = mainwin->folderview;
1370 fitem = folderview->summaryview->folder_item;
1372 if (fitem &&
1373 fitem->folder->klass == vcal_folder_get_class()) {
1374 folderview_unselect(folderview);
1375 summary_clear_all(folderview->summaryview);
1376 if (fitem->folder->klass->item_closed)
1377 fitem->folder->klass->item_closed(fitem);
1380 mimeview_unregister_viewer_factory(&vcal_viewer_factory);
1381 folder_unregister_class(vcal_folder_get_class());
1382 vcal_folder_gtk_done();
1383 vcal_prefs_done();
1384 g_source_remove(alert_timeout_tag);
1385 alert_timeout_tag = 0;
1386 g_source_remove(scan_timeout_tag);
1387 scan_timeout_tag = 0;
1389 MENUITEM_REMUI_MANAGER(mainwin->ui_manager,mainwin->action_group, "Message/CreateMeeting", main_menu_id);
1390 main_menu_id = 0;
1391 MENUITEM_REMUI_MANAGER(mainwin->ui_manager,mainwin->action_group, "Message/CreateMeeting", context_menu_id);
1392 context_menu_id = 0;