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 
create_meeting_from_message_cb_ui(GtkAction * action,gpointer data)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 
get_tmpfile(VCalViewer * vcalviewer)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 
vcal_viewer_get_widget(MimeViewer * _mimeviewer)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 
vcal_viewer_clear_viewer(MimeViewer * _mimeviewer)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 
vcalviewer_get_component(const gchar * file,const gchar * charset)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 
vcalviewer_reset(VCalViewer * vcalviewer)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 
vcalviewer_show_error(VCalViewer * vcalviewer,const gchar * msg)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 
vcalviewer_hide_error(VCalViewer * vcalviewer)344 static void vcalviewer_hide_error(VCalViewer *vcalviewer)
345 {
346 	GTK_LABEL_SET_TEXT_TRIMMED(GTK_LABEL(vcalviewer->type), "-");
347 }
348 
vcalviewer_show_unavailable(VCalViewer * vcalviewer,gboolean visi)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 
vcalviewer_answer_set_choices(VCalViewer * vcalviewer,VCalEvent * event,icalproperty_method method)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 
vcalendar_get_current_item(void)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 
vcalviewer_display_event(VCalViewer * vcalviewer,VCalEvent * event)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 
vcalviewer_get_uid_from_mimeinfo(MimeInfo * mimeinfo)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 
vcalviewer_get_request_values(VCalViewer * vcalviewer,MimeInfo * mimeinfo,gboolean is_todo)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 
vcalviewer_get_reply_values(VCalViewer * vcalviewer,MimeInfo * mimeinfo)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 
vcalviewer_get_event(VCalViewer * vcalviewer,MimeInfo * mimeinfo)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 
vcal_viewer_show_mimepart(MimeViewer * _mimeviewer,const gchar * file,MimeInfo * mimeinfo)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 
vcalviewer_reload(FolderItem * item)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 
vcal_viewer_destroy_viewer(MimeViewer * _mimeviewer)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 
vcalviewer_reedit_cb(GtkButton * widget,gpointer data)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 
vcalviewer_uribtn_cb(GtkButton * widget,gpointer data)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 
vcalendar_refresh_folder_contents(FolderItem * item)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 
send_cancel_notify_toggled_cb(GtkToggleButton * button,gboolean * data)940 static void send_cancel_notify_toggled_cb(GtkToggleButton *button, gboolean *data)
941 {
942 	*data = gtk_toggle_button_get_active(button);
943 }
944 
vcalendar_cancel_meeting(FolderItem * item,const gchar * uid)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 
vcalviewer_cancel_cb(GtkButton * widget,gpointer data)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 
vcalviewer_action_cb(GtkButton * widget,gpointer data)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 
vcal_viewer_get_selection(MimeViewer * _viewer)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 
vcal_viewer_scroll_page(MimeViewer * _viewer,gboolean up)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 
vcal_viewer_scroll_one_line(MimeViewer * _viewer,gboolean up)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 
vcal_viewer_create(void)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 
vcal_webcal_check(gpointer data)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 
vcalendar_init(void)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 
vcalendar_done(void)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 }
1389