1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2013 Colin Leroy <colin@colino.net> and
4  * the Claws Mail team
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #  include "config.h"
23 #include "claws-features.h"
24 #endif
25 
26 #include <stddef.h>
27 #include <glib.h>
28 #include <glib/gi18n.h>
29 
30 #include "defs.h"
31 
32 #ifdef USE_PTHREAD
33 #include <pthread.h>
34 #endif
35 #include <libical/ical.h>
36 #include <gtk/gtk.h>
37 #include <gdk/gdkkeysyms.h>
38 #include <curl/curl.h>
39 #include <curl/curlver.h>
40 #include "combobox.h"
41 
42 #include "vcalendar.h"
43 #include "vcal_folder.h"
44 #include "vcal_manager.h"
45 #include "vcal_meeting_gtk.h"
46 #include "vcal_prefs.h"
47 #include "common-views.h"
48 #include "mainwindow.h"
49 #include "prefs_account.h"
50 #include "account.h"
51 #include "filesel.h"
52 #include "alertpanel.h"
53 #include "addr_compl.h"
54 #include "gtkutils.h"
55 #include "log.h"
56 #include "utils.h"
57 #include "file-utils.h"
58 
59 struct _VCalMeeting
60 {
61 	gchar     *uid;
62 	gint       sequence;
63 	gint 	   method;
64 	GtkWidget *window;
65 #ifndef GENERIC_UMPC
66 	GtkWidget *table;
67 #else
68 	GtkWidget *table1;
69 	GtkWidget *table2;
70 #endif
71 	GtkWidget *type;
72 	GtkWidget *who;
73 	GtkWidget *avail_evtbox;
74 	GtkWidget *avail_img;
75 	GtkWidget *start_c;
76 	GtkWidget *start_time;
77 	GtkWidget *end_c;
78 	GtkWidget *end_time;
79 	GtkWidget *location;
80 	GtkWidget *summary;
81 	GtkWidget *description;
82 	GSList 	  *attendees;
83 	GtkWidget *attendees_vbox;
84 	GtkWidget *save_btn;
85 	GtkWidget *avail_btn;
86 	GSList 	  *avail_accounts;
87 	GtkWidget *total_avail_evtbox;
88 	GtkWidget *total_avail_img;
89 	GtkWidget *total_avail_msg;
90 	PrefsAccount *account;
91 	gboolean visible;
92 };
93 
94 struct _VCalAttendee {
95 	GtkWidget *address;
96 	GtkWidget *remove_btn;
97 	GtkWidget *add_btn;
98 	GtkWidget *cutype;
99 	GtkWidget *hbox;
100 	VCalMeeting *meet;
101 	gchar *status;
102 	GtkWidget *avail_evtbox;
103 	GtkWidget *avail_img;
104 	gchar *cached_contents;
105 	gboolean org;
106 };
107 
108 static GdkCursor *watch_cursor = NULL;
109 
110 VCalAttendee *attendee_add(VCalMeeting *meet, gchar *address, gchar *name, gchar *partstat, gchar *cutype, gboolean first);
111 
112 #ifndef GENERIC_UMPC
113 #define TABLE_ADD_LINE(label_text, widget, do_space) {				\
114 	gchar *tmpstr = g_strdup_printf("<span weight=\"bold\">%s</span>",	\
115 				label_text?label_text:"");			\
116 	GtkWidget *label = NULL;				 		\
117 	GtkWidget *spacer = NULL;						\
118 	GtkWidget *s_hbox = NULL;						\
119 	if (do_space) {								\
120 		spacer = gtk_label_new("");					\
121 		gtk_widget_set_size_request(spacer, 18, 16);				\
122 		s_hbox = gtk_hbox_new(FALSE, 6);				\
123 		gtk_box_pack_start(GTK_BOX(s_hbox), spacer, FALSE, FALSE, 0);	\
124 		gtk_box_pack_start(GTK_BOX(s_hbox), widget, TRUE, TRUE, 0);	\
125 	}									\
126 	if (label_text) {							\
127 		label = gtk_label_new(tmpstr);					\
128 		g_free(tmpstr);							\
129 		gtk_label_set_use_markup (GTK_LABEL (label), TRUE);		\
130 		gtk_misc_set_alignment (GTK_MISC(label), 1, 0.5);		\
131 		gtk_table_attach (GTK_TABLE (meet->table), 			\
132 				  label, 0, 1, i, i+1,				\
133 				  GTK_FILL, GTK_FILL, 6, 6);			\
134 		gtk_table_attach (GTK_TABLE (meet->table), 			\
135 				  do_space?s_hbox:widget, 1, 2, i, i+1,		\
136 				  GTK_FILL|GTK_EXPAND, GTK_FILL, 6, 6);		\
137 		if (GTK_IS_LABEL(widget)) {					\
138 			gtk_label_set_use_markup(GTK_LABEL (widget), TRUE);	\
139 			gtk_misc_set_alignment (GTK_MISC(widget),0, 0);		\
140 			gtk_label_set_line_wrap(GTK_LABEL(widget), TRUE);	\
141 		}								\
142 	} else {								\
143 		g_free(tmpstr);							\
144 		gtk_table_attach (GTK_TABLE (meet->table), 			\
145 				  do_space?s_hbox:widget, 0, 2, i, i+1,		\
146 				  GTK_FILL|GTK_EXPAND, GTK_FILL, 6, 6);		\
147 	}									\
148 	i++;									\
149 }
150 #else
151 #define TABLE_ADD_LINE(label_text, widget, do_space, intable1) {			\
152 	gchar *tmpstr = g_strdup_printf("<span weight=\"bold\">%s</span>",	\
153 				label_text?label_text:"");			\
154 	GtkWidget *label = NULL;				 		\
155 	GtkWidget *spacer = NULL;						\
156 	GtkWidget *s_hbox = NULL;						\
157 	if (do_space) {								\
158 		spacer = gtk_label_new("");					\
159 		gtk_widget_set_size_request(spacer, 18, 16);				\
160 		s_hbox = gtk_hbox_new(FALSE, 6);				\
161 		gtk_box_pack_start(GTK_BOX(s_hbox), spacer, FALSE, FALSE, 0);	\
162 		gtk_box_pack_start(GTK_BOX(s_hbox), widget, TRUE, TRUE, 0);	\
163 	}									\
164 	if (label_text) {							\
165 		label = gtk_label_new(tmpstr);					\
166 		g_free(tmpstr);							\
167 		gtk_label_set_use_markup (GTK_LABEL (label), TRUE);		\
168 		gtk_misc_set_alignment (GTK_MISC(label), 1, 0.5);		\
169 		if(intable1)	{						\
170 			gtk_table_attach (GTK_TABLE (meet->table1), 		\
171 					  label, 0, 1, i, i+1,			\
172 					  GTK_FILL, GTK_FILL, 1, 1);		\
173 		}								\
174 		else	{							\
175 			gtk_table_attach (GTK_TABLE (meet->table2), 		\
176 					  label, 0, 1, i, i+1,			\
177 					  GTK_FILL, GTK_FILL, 1, 1);		\
178 		}								\
179 		if(intable1)	{						\
180 			gtk_table_attach (GTK_TABLE (meet->table1), 		\
181 					  do_space?s_hbox:widget, 1, 2, i, i+1,	\
182 					  GTK_FILL|GTK_EXPAND, GTK_FILL, 1, 1);	\
183 		}								\
184 		else	{							\
185 			gtk_table_attach (GTK_TABLE (meet->table2), 		\
186 					  do_space?s_hbox:widget, 1, 2, i, i+1,	\
187 					  GTK_FILL|GTK_EXPAND, GTK_FILL, 1, 1);	\
188 		}								\
189 		if (GTK_IS_LABEL(widget)) {					\
190 			gtk_label_set_use_markup(GTK_LABEL (widget), TRUE);	\
191 			gtk_misc_set_alignment (GTK_MISC(widget),0, 0);		\
192 			gtk_label_set_line_wrap(GTK_LABEL(widget), TRUE);	\
193 		}								\
194 	} else {								\
195 		g_free(tmpstr);							\
196 		if(intable1)	{						\
197 			gtk_table_attach (GTK_TABLE (meet->table1), 		\
198 					  do_space?s_hbox:widget, 0, 2, i, i+1,	\
199 					  GTK_FILL|GTK_EXPAND, GTK_FILL, 1, 1);	\
200 		}								\
201 		else	{							\
202 			gtk_table_attach (GTK_TABLE (meet->table2), 		\
203 					  do_space?s_hbox:widget, 0, 2, i, i+1,	\
204 					  GTK_FILL|GTK_EXPAND, GTK_FILL, 1, 1);	\
205 		}								\
206 	}									\
207 	i++;									\
208 }
209 #endif
210 enum {
211 	DAY,
212 	MONTH,
213 	YEAR,
214 	HOUR,
215 	MINUTE
216 };
217 
avail_btn_can_be_sensitive(void)218 static gboolean avail_btn_can_be_sensitive(void)
219 {
220 	if (vcalprefs.freebusy_get_url == NULL
221 	||  *vcalprefs.freebusy_get_url == '\0')
222 		return FALSE;
223 	else
224 		return TRUE;
225 }
226 
get_dtdate(const gchar * str,gint field)227 static gint get_dtdate(const gchar *str, gint field)
228 {
229 	time_t t = icaltime_as_timet((icaltime_from_string(str)));
230 	struct tm buft;
231 	struct tm *lt;
232 
233 	tzset();
234 
235 #ifdef G_OS_WIN32
236 	if (t < 0)
237 		t = 1;
238 #endif
239 	lt = localtime_r(&t, &buft);
240 
241 	switch(field){
242 	case DAY:
243 		return lt->tm_mday;
244 	case MONTH:
245 		return lt->tm_mon + 1;
246 	case YEAR:
247 		return lt->tm_year + 1900;
248 	case HOUR:
249 		return lt->tm_hour;
250 	case MINUTE:
251 		return lt->tm_min;
252 	}
253 	return -1;
254 
255 }
256 
add_btn_cb(GtkButton * widget,gpointer data)257 static gboolean add_btn_cb(GtkButton *widget, gpointer data)
258 {
259 	VCalAttendee *attendee = (VCalAttendee *)data;
260 	attendee_add(attendee->meet, NULL, NULL, NULL, NULL, FALSE);
261 	return TRUE;
262 }
263 
remove_btn_cb(GtkButton * widget,gpointer data)264 static gboolean remove_btn_cb(GtkButton *widget, gpointer data)
265 {
266 	VCalAttendee *attendee = (VCalAttendee *)data;
267 	gtk_container_remove(GTK_CONTAINER(attendee->meet->attendees_vbox), attendee->hbox);
268 	attendee->meet->attendees = g_slist_remove(attendee->meet->attendees, attendee);
269 
270 	g_free(attendee->status);
271 
272 	return TRUE;
273 }
274 
attendee_add(VCalMeeting * meet,gchar * address,gchar * name,gchar * partstat,gchar * cutype,gboolean first)275 VCalAttendee *attendee_add(VCalMeeting *meet, gchar *address, gchar *name, gchar *partstat, gchar *cutype, gboolean first)
276 {
277 	GtkWidget *att_hbox = gtk_hbox_new(FALSE, 6);
278 	VCalAttendee *attendee 	= g_new0(VCalAttendee, 1);
279 
280 	attendee->address	= gtk_entry_new();
281 	attendee->cutype	= gtk_combo_box_text_new();
282 	attendee->avail_evtbox  = gtk_event_box_new();
283 	attendee->avail_img	= gtk_image_new_from_stock
284                         (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
285 
286 	gtk_widget_show(attendee->address);
287 	gtk_widget_show(attendee->cutype);
288 	gtk_widget_show(attendee->avail_evtbox);
289 
290 	CLAWS_SET_TIP(attendee->address, _("Use <tab> to autocomplete from addressbook"));
291 	gtk_widget_set_size_request(attendee->avail_evtbox, 18, 16);
292 	gtk_event_box_set_visible_window(GTK_EVENT_BOX(attendee->avail_evtbox), FALSE);
293 	gtk_container_add (GTK_CONTAINER(attendee->avail_evtbox), attendee->avail_img);
294 
295 	if (address) {
296 		gchar *str = g_strdup_printf("%s%s%s%s",
297 				(name && strlen(name))?name:"",
298 				(name && strlen(name))?" <":"",
299 				address,
300 				(name && strlen(name))?">":"");
301 		gtk_entry_set_text(GTK_ENTRY(attendee->address), str);
302 		g_free(str);
303 	}
304 
305 	if (partstat)
306 		attendee->status = g_strdup(partstat);
307 
308 	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(attendee->cutype), _("Individual"));
309 	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(attendee->cutype), _("Group"));
310 	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(attendee->cutype), _("Resource"));
311 	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(attendee->cutype), _("Room"));
312 
313 	gtk_combo_box_set_active(GTK_COMBO_BOX(attendee->cutype), 0);
314 
315 	if (cutype) {
316 		if (!strcmp(cutype, "group"))
317 			gtk_combo_box_set_active(GTK_COMBO_BOX(attendee->cutype), 1);
318 		if (!strcmp(cutype, "resource"))
319 			gtk_combo_box_set_active(GTK_COMBO_BOX(attendee->cutype), 2);
320 		if (!strcmp(cutype, "room"))
321 			gtk_combo_box_set_active(GTK_COMBO_BOX(attendee->cutype), 3);
322 	}
323 
324 	attendee->add_btn	= gtk_button_new_with_label(_("Add..."));
325 	attendee->remove_btn	= gtk_button_new_with_label(_("Remove"));
326 	attendee->meet		= meet;
327 	attendee->hbox		= att_hbox;
328 
329 	gtk_widget_show(attendee->add_btn);
330 	gtk_widget_show(attendee->remove_btn);
331 	gtk_widget_show(attendee->hbox);
332 
333 	gtk_box_pack_start(GTK_BOX(attendee->hbox), attendee->avail_evtbox, FALSE, FALSE, 0);
334 	gtk_widget_set_sensitive(attendee->remove_btn, !first);
335 	meet->attendees 	= g_slist_append(meet->attendees, attendee);
336 
337 	g_signal_connect(G_OBJECT(attendee->remove_btn), "clicked",
338 			 G_CALLBACK(remove_btn_cb), attendee);
339 	g_signal_connect(G_OBJECT(attendee->add_btn), "clicked",
340 			 G_CALLBACK(add_btn_cb), attendee);
341 
342 	gtk_box_pack_start(GTK_BOX(att_hbox), attendee->address, FALSE, FALSE, 0);
343 	gtk_box_pack_start(GTK_BOX(att_hbox), attendee->cutype, FALSE, FALSE, 0);
344 	gtk_box_pack_start(GTK_BOX(att_hbox), attendee->add_btn, FALSE, FALSE, 0);
345 	gtk_box_pack_start(GTK_BOX(att_hbox), attendee->remove_btn, FALSE, FALSE, 0);
346 	gtk_box_pack_start(GTK_BOX(meet->attendees_vbox), att_hbox, FALSE, FALSE, 0);
347 	address_completion_register_entry(GTK_ENTRY(attendee->address), FALSE);
348 #ifndef GENERIC_UMPC
349 	gtk_widget_set_size_request(attendee->address, 320, -1);
350 #else
351 	gtk_widget_set_size_request(attendee->address, 220, -1);
352 #endif
353 	return attendee;
354 }
355 
get_organizer(VCalMeeting * meet)356 static gchar *get_organizer(VCalMeeting *meet)
357 {
358 	int index = gtk_combo_box_get_active(GTK_COMBO_BOX(meet->who));
359 	int i = 0;
360 	GSList *cur = meet->avail_accounts;
361 	while (i < index && cur && cur->data) {
362 		debug_print("%d:skipping %s\n",i,((PrefsAccount *)(cur->data))->address);
363 		cur = cur->next;
364 		i++;
365 	}
366 	if (cur && cur->data)
367 		return g_strdup(((PrefsAccount *)(cur->data))->address);
368 	else
369 		return g_strdup("");
370 }
371 
get_organizer_name(VCalMeeting * meet)372 static gchar *get_organizer_name(VCalMeeting *meet)
373 {
374 	int index = gtk_combo_box_get_active(GTK_COMBO_BOX(meet->who));
375 	int i = 0;
376 	GSList *cur = meet->avail_accounts;
377 	while (i < index && cur && cur->data) {
378 		debug_print("%d:skipping %s\n",i,((PrefsAccount *)(cur->data))->address);
379 		cur = cur->next;
380 		i++;
381 	}
382 	if (cur && cur->data)
383 		return g_strdup(((PrefsAccount *)(cur->data))->name);
384 	else
385 		return g_strdup("");
386 }
387 
get_current_gmt_offset(void)388 static int get_current_gmt_offset(void)
389 {
390 	time_t now = time(NULL);
391 	struct tm gmt;
392 	struct tm local;
393 
394 	tzset();
395 
396 #ifdef G_OS_WIN32
397 	if (now < 0)
398 		now = 1;
399 #endif
400 	gmtime_r(& now, & gmt);
401 	localtime_r(& now, & local);
402 
403 	local.tm_isdst = 0;
404 	return mktime(&local)-mktime(&gmt);
405 }
406 
get_gmt_offset_at_time(time_t then)407 static int get_gmt_offset_at_time(time_t then)
408 {
409 	struct tm gmt;
410 	struct tm local;
411 
412 	tzset();
413 
414 #ifdef G_OS_WIN32
415 	if (then < 0)
416 		then = 1;
417 #endif
418 	gmtime_r(& then, & gmt);
419 	localtime_r(& then, & local);
420 
421 	local.tm_isdst = 0;
422 	return mktime(&local)-mktime(&gmt);
423 }
424 
get_date(VCalMeeting * meet,int start)425 static gchar *get_date(VCalMeeting *meet, int start)
426 {
427 	struct tm *lt;
428 	time_t t;
429 	guint d, m, y;
430 	int dst_offset = 0;
431 	struct tm buft;
432 
433 	tzset();
434 
435 	t = time(NULL);
436 #ifdef G_OS_WIN32
437 	if (t < 0)
438 		t = 1;
439 #endif
440 	lt = localtime_r(&t, &buft);
441 
442 	gtk_calendar_get_date(GTK_CALENDAR(start ? meet->start_c : meet->end_c), &y, &m, &d);
443 	lt->tm_mday = d;
444 	lt->tm_mon  = m;
445 	lt->tm_year = y - 1900;
446 	lt->tm_hour = 0;
447 	lt->tm_min  = 0;
448 	lt->tm_sec  = 0;
449 
450 	if (start) {
451 		gtkut_time_select_get_time(GTK_COMBO_BOX(meet->start_time), &lt->tm_hour, &lt->tm_min);
452 	} else {
453 		gtkut_time_select_get_time(GTK_COMBO_BOX(meet->end_time), &lt->tm_hour, &lt->tm_min);
454 	}
455 
456 	debug_print("%d %d %d, %d:%d\n", lt->tm_mday, lt->tm_mon, lt->tm_year, lt->tm_hour, lt->tm_min);
457 	t = mktime(lt);
458 
459 	dst_offset = get_current_gmt_offset() - get_gmt_offset_at_time(t);
460 	debug_print("DST change offset to apply to time %d\n", dst_offset);
461 	t += dst_offset;
462 	debug_print("%s\n", ctime(&t));
463 	return g_strdup(icaltime_as_ical_string(icaltime_from_timet_with_zone(t, FALSE, NULL)));
464 }
465 
get_location(VCalMeeting * meet)466 static gchar *get_location(VCalMeeting *meet)
467 {
468 	return gtk_editable_get_chars(GTK_EDITABLE(meet->location),0, -1);
469 }
470 
get_summary(VCalMeeting * meet)471 static gchar *get_summary(VCalMeeting *meet)
472 {
473 	return gtk_editable_get_chars(GTK_EDITABLE(meet->summary),0, -1);
474 }
475 
get_description(VCalMeeting * meet)476 static gchar *get_description(VCalMeeting *meet)
477 {
478 	GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(meet->description));
479 	GtkTextIter start, end;
480 
481 	gtk_text_buffer_get_start_iter(buffer, &start);
482 	gtk_text_buffer_get_end_iter(buffer, &end);
483 	return gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
484 }
485 
vcal_meeting_free(VCalMeeting * meet)486 void vcal_meeting_free(VCalMeeting *meet)
487 {
488 	debug_print("freeing meeting\n");
489 	g_free(meet->uid);
490 	address_completion_end(meet->window);
491 	g_slist_free(meet->avail_accounts);
492 	g_slist_free(meet->attendees);
493 	g_free(meet);
494 }
495 
destroy_meeting_cb(GtkWidget * widget,gpointer data)496 static void destroy_meeting_cb(GtkWidget *widget, gpointer data)
497 {
498 	VCalMeeting *meet = (VCalMeeting *)data;
499 	vcal_meeting_free(meet);
500 }
501 
vcal_destroy(VCalMeeting * meet)502 static void vcal_destroy(VCalMeeting *meet)
503 {
504 	GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(meet->description));
505 	gtk_text_buffer_remove_selection_clipboard(buffer, gtk_clipboard_get(GDK_SELECTION_PRIMARY));
506 	gtk_widget_destroy(meet->window);
507 }
508 
meeting_key_pressed(GtkWidget * widget,GdkEventKey * event,gpointer data)509 static gboolean meeting_key_pressed(GtkWidget *widget,
510 				    GdkEventKey *event,
511 				    gpointer data)
512 {
513 	VCalMeeting *meet = (VCalMeeting *)data;
514 
515 	if (event && event->keyval == GDK_KEY_Escape) {
516 		vcal_destroy(meet);
517 	}
518 	return FALSE;
519 }
520 
521 static void meeting_end_changed(GtkWidget *widget, gpointer data);
522 
meeting_start_changed(GtkWidget * widget,gpointer data)523 static void meeting_start_changed(GtkWidget *widget, gpointer data)
524 {
525 	VCalMeeting *meet = (VCalMeeting *)data;
526 	struct tm start_lt;
527 	struct tm end_lt;
528 	time_t start_t, end_t;
529 	guint d, m, y;
530 
531 	if (!gtkut_time_select_get_time(GTK_COMBO_BOX(meet->start_time), &start_lt.tm_hour, &start_lt.tm_min))
532 		return;
533 	tzset();
534 
535 	start_t = time(NULL);
536 	end_t = time(NULL);
537 #ifdef G_OS_WIN32
538 	if (start_t < 0)
539 		start_t = 1;
540 	if (end_t < 0)
541 		end_t = 1;
542 #endif
543 	localtime_r(&start_t, &start_lt);
544 	localtime_r(&end_t, &end_lt);
545 
546 	gtk_calendar_get_date(GTK_CALENDAR(meet->start_c), &y, &m, &d);
547 	start_lt.tm_mday = d; start_lt.tm_mon  = m; start_lt.tm_year = y - 1900;
548 
549 	start_t = mktime(&start_lt);
550 	debug_print("start %s\n", ctime(&start_t));
551 
552 	gtk_calendar_get_date(GTK_CALENDAR(meet->end_c), &y, &m, &d);
553 	end_lt.tm_mday = d; end_lt.tm_mon  = m; end_lt.tm_year = y - 1900;
554 
555 	gtkut_time_select_get_time(GTK_COMBO_BOX(meet->end_time), &end_lt.tm_hour, &end_lt.tm_min);
556 
557 	end_t = mktime(&end_lt);
558 
559 	debug_print("end   %s\n", ctime(&end_t));
560 
561 	if (end_t > start_t) {
562 		debug_print("ok\n");
563 		return;
564 	}
565 	end_t = start_t + 3600;
566 
567 #ifdef G_OS_WIN32
568 	if (end_t < 0)
569 		end_t = 1;
570 #endif
571 	localtime_r(&end_t, &end_lt);
572 	debug_print("n %d %d %d, %d:%d\n", end_lt.tm_mday, end_lt.tm_mon, end_lt.tm_year, end_lt.tm_hour, end_lt.tm_min);
573 
574 	g_signal_handlers_block_by_func(gtk_bin_get_child(GTK_BIN(meet->end_time)), meeting_end_changed, meet);
575 	g_signal_handlers_block_by_func(meet->end_c, meeting_end_changed, meet);
576 
577 	gtk_calendar_select_day(GTK_CALENDAR(meet->end_c), end_lt.tm_mday);
578 
579 	gtk_calendar_select_month(GTK_CALENDAR(meet->end_c),
580 				end_lt.tm_mon,
581 				end_lt.tm_year + 1900);
582 
583 	gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet->end_time), end_lt.tm_hour, end_lt.tm_min);
584 
585 	g_signal_handlers_unblock_by_func(gtk_bin_get_child(GTK_BIN(meet->end_time)), meeting_end_changed, meet);
586 	g_signal_handlers_unblock_by_func(meet->end_c, meeting_end_changed, meet);
587 }
588 
meeting_end_changed(GtkWidget * widget,gpointer data)589 static void meeting_end_changed(GtkWidget *widget, gpointer data)
590 {
591 	VCalMeeting *meet = (VCalMeeting *)data;
592 	struct tm start_lt;
593 	struct tm end_lt;
594 	time_t start_t, end_t;
595 	guint d, m, y;
596 
597 	if (!gtkut_time_select_get_time(GTK_COMBO_BOX(meet->end_time), &end_lt.tm_hour, &end_lt.tm_min))
598 		return;
599 	start_t = time(NULL);
600 	end_t = time(NULL);
601 
602 	tzset();
603 
604 #ifdef G_OS_WIN32
605 	if (start_t < 0)
606 		start_t = 1;
607 	if (end_t < 0)
608 		end_t = 1;
609 #endif
610 	localtime_r(&start_t, &start_lt);
611 	localtime_r(&end_t, &end_lt);
612 
613 	gtk_calendar_get_date(GTK_CALENDAR(meet->start_c), &y, &m, &d);
614 	start_lt.tm_mday = d; start_lt.tm_mon  = m; start_lt.tm_year = y - 1900;
615 	gtkut_time_select_get_time(GTK_COMBO_BOX(meet->start_time), &start_lt.tm_hour, &start_lt.tm_min);
616 
617 	start_t = mktime(&start_lt);
618 	debug_print("start %s\n", ctime(&start_t));
619 
620 	gtk_calendar_get_date(GTK_CALENDAR(meet->end_c), &y, &m, &d);
621 	end_lt.tm_mday = d; end_lt.tm_mon  = m; end_lt.tm_year = y - 1900;
622 
623 	end_t = mktime(&end_lt);
624 
625 	debug_print("end   %s\n", ctime(&end_t));
626 
627 	if (end_t > start_t) {
628 		debug_print("ok\n");
629 		return;
630 	}
631 	start_t = end_t - 3600;
632 
633 	tzset();
634 
635 #ifdef G_OS_WIN32
636 	if (start_t < 0)
637 		start_t = 1;
638 #endif
639 	localtime_r(&start_t, &start_lt);
640 	debug_print("n %d %d %d, %d:%d\n", start_lt.tm_mday, start_lt.tm_mon, start_lt.tm_year, start_lt.tm_hour, start_lt.tm_min);
641 
642 	g_signal_handlers_block_by_func(gtk_bin_get_child(GTK_BIN(meet->start_time)), meeting_start_changed, meet);
643 	g_signal_handlers_block_by_func(meet->start_c, meeting_start_changed, meet);
644 
645 	gtk_calendar_select_day(GTK_CALENDAR(meet->start_c), start_lt.tm_mday);
646 
647 	gtk_calendar_select_month(GTK_CALENDAR(meet->start_c),
648 				start_lt.tm_mon,
649 				start_lt.tm_year + 1900);
650 
651 	gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet->start_time), start_lt.tm_hour, start_lt.tm_min);
652 
653 	g_signal_handlers_unblock_by_func(gtk_bin_get_child(GTK_BIN(meet->start_time)), meeting_start_changed, meet);
654 	g_signal_handlers_unblock_by_func(meet->start_c, meeting_start_changed, meet);
655 }
656 
att_update_icon(VCalMeeting * meet,VCalAttendee * attendee,gint avail,gchar * text)657 static void att_update_icon(VCalMeeting *meet, VCalAttendee *attendee, gint avail, gchar *text)
658 {
659 	const gchar *icon = GTK_STOCK_DIALOG_INFO;
660 
661 	switch (avail) {
662 		case 0:  icon = GTK_STOCK_DIALOG_WARNING;	break;
663 		case 1:  icon = GTK_STOCK_DIALOG_INFO;		break;
664 		default: icon = GTK_STOCK_DIALOG_QUESTION;	break;
665 	}
666 	if (!gtk_entry_get_text(GTK_ENTRY(attendee->address))
667 	 || strlen(gtk_entry_get_text(GTK_ENTRY(attendee->address)))==0) {
668 		if (attendee->avail_img) {
669 			gtk_widget_hide(attendee->avail_img);
670 		}
671 		CLAWS_SET_TIP(attendee->avail_evtbox, NULL);
672 	} else if (attendee->avail_img) {
673 		gtk_image_set_from_stock
674 		        (GTK_IMAGE(attendee->avail_img),
675 			icon,
676 			GTK_ICON_SIZE_SMALL_TOOLBAR);
677 		gtk_widget_show(attendee->avail_img);
678 		CLAWS_SET_TIP(attendee->avail_evtbox, text);
679 	}
680 }
681 
attendee_available(VCalAttendee * attendee,const gchar * dtstart,const gchar * dtend,const gchar * contents)682 gboolean attendee_available(VCalAttendee *attendee, const gchar *dtstart, const gchar *dtend, const gchar *contents)
683 {
684 	icalcomponent *toplvl, *vfreebusy;
685 	icalproperty *busyprop;
686 	struct icaltimetype start = icaltime_from_string(dtstart);
687 	struct icaltimetype end = icaltime_from_string(dtend);
688 	gboolean result = TRUE;
689 
690 
691 	if (contents == NULL)
692 		return TRUE;
693 
694 	toplvl = icalcomponent_new_from_string((gchar *)contents);
695 
696 	if (toplvl == NULL)
697 		return TRUE;
698 
699 	vfreebusy = icalcomponent_get_first_component(toplvl, ICAL_VFREEBUSY_COMPONENT);
700 	while (vfreebusy && icalcomponent_isa(vfreebusy) != ICAL_VFREEBUSY_COMPONENT)
701 		vfreebusy = icalcomponent_get_next_component(toplvl, ICAL_VFREEBUSY_COMPONENT);
702 
703 	if (vfreebusy) {
704 		busyprop = icalcomponent_get_first_property(vfreebusy, ICAL_FREEBUSY_PROPERTY);
705 		while (busyprop) {
706 			struct icalperiodtype ipt = icalproperty_get_freebusy(busyprop);
707 
708 			if ( icaltime_compare(start, ipt.end) >= 0 || icaltime_compare(end, ipt.start) <= 0 ) {
709 				result = TRUE;
710 			} else {
711 				result = FALSE;
712 				break;
713 			}
714 			busyprop = icalcomponent_get_next_property(vfreebusy, ICAL_FREEBUSY_PROPERTY);
715 		}
716 	}
717 
718 	icalcomponent_free(toplvl);
719 	return result;
720 }
721 
get_avail_msg(const gchar * unavailable_persons,gboolean multiple,gboolean short_version,gint offset_before,gint offset_after)722 static gchar *get_avail_msg(const gchar *unavailable_persons, gboolean multiple,
723 	gboolean short_version, gint offset_before, gint offset_after)
724 {
725 	gchar *msg, *intro = NULL, *outro = NULL, *before = NULL, *after = NULL;
726 
727 	if (multiple)
728 		intro = g_strdup(_("The following people are busy at the time of your planned meeting:\n- "));
729 	else if (!strcmp(unavailable_persons, _("You")))
730 		intro = g_strdup(_("You are busy at the time of your planned meeting"));
731 	else
732 		intro = g_strdup_printf(_("%s is busy at the time of your planned meeting"), unavailable_persons);
733 	if (offset_before == 3600)
734 		before = g_strdup_printf(_("%d hour sooner"), offset_before/3600);
735 	else if (offset_before > 3600 && offset_before%3600 == 0)
736 		before = g_strdup_printf(_("%d hours sooner"), offset_before/3600);
737 	else if (offset_before > 3600)
738 		before = g_strdup_printf(_("%d hours and %d minutes sooner"), offset_before/3600, (offset_before%3600)/60);
739 	else if (offset_before == 1800)
740 		before = g_strdup_printf(_("%d minutes sooner"), offset_before/60);
741 	else
742 		before = NULL;
743 
744 	if (offset_after == 3600)
745 		after = g_strdup_printf(_("%d hour later"), offset_after/3600);
746 	else if (offset_after > 3600 && offset_after%3600 == 0)
747 		after = g_strdup_printf(_("%d hours later"), offset_after/3600);
748 	else if (offset_after > 3600)
749 		after = g_strdup_printf(_("%d hours and %d minutes later"), offset_after/3600, (offset_after%3600)/60);
750 	else if (offset_after == 1800)
751 		after = g_strdup_printf(_("%d minutes later"), offset_after/60);
752 	else
753 		after = NULL;
754 
755 	if (multiple) {
756 		if (before && after)
757 			outro = g_strdup_printf(_("\n\nEveryone would be available %s or %s."), before, after);
758 		else if (before || after)
759 			outro = g_strdup_printf(_("\n\nEveryone would be available %s."), before?before:after);
760 		else
761 			outro = g_strdup_printf(_("\n\nIt isn't possible to have this meeting with everyone "
762 						"in the previous or next 6 hours."));
763 	} else {
764 		if (short_version) {
765 			if (before && after)
766 				outro = g_markup_printf_escaped(_("would be available %s or %s"), before, after);
767 			else if (before || after)
768 				outro = g_markup_printf_escaped(_("would be available %s"), before?before:after);
769 			else
770 				outro = g_strdup_printf(_("not available"));
771 		} else {
772 			if (before && after)
773 				outro = g_markup_printf_escaped(_(", but would be available %s or %s."), before, after);
774 			else if (before || after)
775 				outro = g_markup_printf_escaped(_(", but would be available %s."), before?before:after);
776 			else
777 				outro = g_strdup_printf(_(", and isn't available "
778 							"in the previous or next 6 hours."));
779 		}
780 	}
781 	if (multiple && short_version)
782 		msg = g_strconcat(outro+2, NULL);
783 	else if (multiple)
784 		msg = g_strconcat(intro, unavailable_persons, outro, NULL);
785 	else if (short_version)
786 		msg = g_strdup(outro);
787 	else
788 		msg = g_strconcat(intro, outro, NULL);
789 	g_free(intro);
790 	g_free(outro);
791 	g_free(before);
792 	g_free(after);
793 	return msg;
794 }
795 
find_availability(const gchar * dtstart,const gchar * dtend,GSList * attendees,gboolean for_send,VCalMeeting * meet)796 static gboolean find_availability(const gchar *dtstart, const gchar *dtend, GSList *attendees, gboolean for_send, VCalMeeting *meet)
797 {
798 	GSList *cur;
799 	gint offset = -1800, offset_before = 0, offset_after = 0;
800 	gboolean found = FALSE;
801 	gchar *unavailable_persons = NULL;
802 	gchar *msg = NULL;
803 	struct icaltimetype start = icaltime_from_string(dtstart);
804 	struct icaltimetype end = icaltime_from_string(dtend);
805 	AlertValue val = G_ALERTALTERNATE;
806 	gint total = 0;
807 	GHashTable *avail_table_avail = g_hash_table_new(NULL, g_direct_equal);
808 	GHashTable *avail_table_before = g_hash_table_new(NULL, g_direct_equal);
809 	GHashTable *avail_table_after = g_hash_table_new(NULL, g_direct_equal);
810 
811 	for (cur = attendees; cur; cur = cur->next) {
812 		VCalAttendee *attendee = (VCalAttendee *)cur->data;
813 		if (!attendee_available(attendee, icaltime_as_ical_string(start), icaltime_as_ical_string(end),
814 				attendee->cached_contents)) {
815 			gchar *mail = NULL;
816 
817 			if (attendee->org)
818 				mail = g_strdup(_("You"));
819 			else
820 				mail = gtk_editable_get_chars(GTK_EDITABLE(attendee->address), 0, -1);
821 
822 			if (unavailable_persons == NULL) {
823 				unavailable_persons = g_markup_printf_escaped("%s", mail);
824 			} else {
825 				gchar *tmp = g_markup_printf_escaped("%s,\n- %s", unavailable_persons, mail);
826 				g_free(unavailable_persons);
827 				unavailable_persons = tmp;
828 			}
829 			total++;
830 			g_free(mail);
831 			att_update_icon(meet, attendee, 0, _("not available"));
832 		} else {
833 			if (attendee->cached_contents != NULL)
834 				att_update_icon(meet, attendee, 1, _("available"));
835 			else
836 				att_update_icon(meet, attendee, 2, _("Free/busy retrieval failed"));
837 
838 			g_hash_table_insert(avail_table_avail, attendee, GINT_TO_POINTER(1));
839 		}
840 	}
841 	offset = -1800;
842 	found = FALSE;
843 	while (!found && offset >= -3600*6) {
844 		gboolean ok = TRUE;
845 		struct icaltimetype new_start = icaltime_from_timet_with_zone(icaltime_as_timet(start)+offset, FALSE, NULL);
846 		struct icaltimetype new_end   = icaltime_from_timet_with_zone(icaltime_as_timet(end)+offset, FALSE, NULL);
847 		for (cur = attendees; cur; cur = cur->next) {
848 			VCalAttendee *attendee = (VCalAttendee *)cur->data;
849 			debug_print("trying %s - %s (offset %d)\n",
850 				icaltime_as_ical_string(new_start), icaltime_as_ical_string(new_end), offset);
851 			if (!attendee_available(attendee, icaltime_as_ical_string(new_start), icaltime_as_ical_string(new_end),
852 					attendee->cached_contents)) {
853 				ok = FALSE;
854 				break;
855 			} else {
856 				if (!g_hash_table_lookup(avail_table_before, attendee)
857 				&&  !g_hash_table_lookup(avail_table_avail, attendee))
858 					g_hash_table_insert(avail_table_before, attendee, GINT_TO_POINTER(-offset));
859 			}
860 		}
861 		if (ok) {
862 			found = TRUE;
863 			offset_before = -offset;
864 		}
865 		offset -= 1800;
866 	}
867 	found = FALSE;
868 	offset = 1800;
869 	while (!found && offset <= 3600*6) {
870 		gboolean ok = TRUE;
871 		struct icaltimetype new_start = icaltime_from_timet_with_zone(icaltime_as_timet(start)+offset, FALSE, NULL);
872 		struct icaltimetype new_end   = icaltime_from_timet_with_zone(icaltime_as_timet(end)+offset, FALSE, NULL);
873 		for (cur = attendees; cur; cur = cur->next) {
874 			VCalAttendee *attendee = (VCalAttendee *)cur->data;
875 			debug_print("trying %s - %s (offset %d)\n",
876 				icaltime_as_ical_string(new_start), icaltime_as_ical_string(new_end), offset);
877 			if (!attendee_available(attendee, icaltime_as_ical_string(new_start), icaltime_as_ical_string(new_end),
878 					attendee->cached_contents)) {
879 				ok = FALSE;
880 				break;
881 			} else {
882 				if (!g_hash_table_lookup(avail_table_after, attendee)
883 				&&  !g_hash_table_lookup(avail_table_avail, attendee))
884 					g_hash_table_insert(avail_table_after, attendee, GINT_TO_POINTER(offset));
885 			}
886 		}
887 		if (ok) {
888 			found = TRUE;
889 			offset_after = offset;
890 		}
891 
892 		offset += 1800;
893 	}
894 
895 	for (cur = attendees; cur; cur = cur->next) {
896 		VCalAttendee *attendee = (VCalAttendee *)cur->data;
897 		gint ok = GPOINTER_TO_INT(g_hash_table_lookup(avail_table_avail, attendee));
898 		gint o_before = GPOINTER_TO_INT(g_hash_table_lookup(avail_table_before, attendee));
899 		gint o_after = GPOINTER_TO_INT(g_hash_table_lookup(avail_table_after, attendee));
900 		if (!o_before && !o_after && !ok) {
901 			att_update_icon(meet, attendee, 0, _("not available"));
902 		} else if ((o_before != 0 || o_after != 0) && !ok) {
903 			if (attendee->org)
904 				msg = get_avail_msg(_("You"), FALSE, TRUE, o_before, o_after);
905 			else
906 				msg = get_avail_msg(gtk_entry_get_text(GTK_ENTRY(attendee->address)), FALSE, TRUE, o_before, o_after);
907 			att_update_icon(meet, attendee, 0, msg);
908 			g_free(msg);
909 		}
910 
911 	}
912 	g_hash_table_destroy(avail_table_before);
913 	g_hash_table_destroy(avail_table_after);
914 
915 	if (for_send) {
916 		msg = get_avail_msg(unavailable_persons, (total > 1), FALSE, offset_before, offset_after);
917 
918 		val = alertpanel_full(_("Not everyone is available"), msg,
919 				   	GTK_STOCK_CANCEL, _("Send anyway"), NULL, ALERTFOCUS_FIRST,
920 						FALSE, NULL, ALERT_QUESTION);
921 		g_free(msg);
922 	}
923 	msg = get_avail_msg(unavailable_persons, TRUE, TRUE, offset_before, offset_after);
924 	g_free(unavailable_persons);
925 	gtk_image_set_from_stock
926 		(GTK_IMAGE(meet->total_avail_img),
927 		GTK_STOCK_DIALOG_WARNING,
928 		GTK_ICON_SIZE_SMALL_TOOLBAR);
929 	gtk_widget_show(meet->total_avail_img);
930 	gtk_label_set_text(GTK_LABEL(meet->total_avail_msg), _("Not everyone is available. "
931 				"See tooltips for more info..."));
932 	CLAWS_SET_TIP(meet->total_avail_evtbox, msg);
933 	g_free(msg);
934 	return (val == G_ALERTALTERNATE);
935 }
936 
check_attendees_availability(VCalMeeting * meet,gboolean tell_if_ok,gboolean for_send)937 static gboolean check_attendees_availability(VCalMeeting *meet, gboolean tell_if_ok, gboolean for_send)
938 {
939 	GSList *cur;
940 	gchar *tmp = NULL;
941 	gchar *real_url = NULL;
942 	gint num_format = 0;
943 	gchar *change_user = NULL, *change_dom = NULL;
944 	gchar *dtstart = NULL;
945 	gchar *dtend = NULL;
946 	gboolean find_avail = FALSE;
947 	gboolean res = TRUE, uncertain = FALSE;
948 	gchar *organizer = NULL;
949 	VCalAttendee *dummy_org = NULL;
950 	gchar *internal_ifb = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
951 				"vcalendar", G_DIR_SEPARATOR_S,
952 				"internal.ifb", NULL);
953 	gboolean local_only = FALSE;
954 	GSList *attlist;
955 	GdkWindow *gdkwin;
956 
957 	if (vcalprefs.freebusy_get_url == NULL
958 	||  *vcalprefs.freebusy_get_url == '\0') {
959 		local_only = TRUE;
960 	} else {
961 		real_url = g_strdup(vcalprefs.freebusy_get_url);
962 		tmp = real_url;
963 
964 		while (strchr(tmp, '%')) {
965 			tmp = strchr(tmp, '%')+1;
966 			num_format++;
967 		}
968 		if (num_format > 2) {
969 			g_warning("wrong format in %s!", real_url);
970 			g_free(real_url);
971 			return FALSE;
972 		}
973 
974 		tmp = NULL;
975 		if (strstr(real_url, "%u") != NULL) {
976 			change_user = strstr(real_url, "%u");
977 			*(strstr(real_url, "%u")+1) = 's';
978 		}
979 		if (strstr(real_url, "%d") != NULL) {
980 			change_dom = strstr(real_url, "%d");
981 			*(strstr(real_url, "%d")+1) = 's';
982 		}
983 		debug_print("url format %s\n", real_url);
984 	}
985 	dtstart = get_date(meet, TRUE);
986 	dtend = get_date(meet, FALSE);
987 
988 	/* hack to check our own avail. */
989 	organizer = get_organizer(meet);
990 	dummy_org = g_new0(VCalAttendee, 1);
991 	dummy_org->address	= gtk_entry_new();
992 	dummy_org->avail_img	= meet->avail_img;
993 	dummy_org->avail_evtbox	= meet->avail_evtbox;
994 	dummy_org->org = TRUE;
995 	gtk_entry_set_text(GTK_ENTRY(dummy_org->address), organizer);
996 	g_free(organizer);
997 	dummy_org->cached_contents = file_read_to_str(internal_ifb);
998 	g_free(internal_ifb);
999 
1000 	if (!local_only) {
1001 		meet->attendees = g_slist_prepend(meet->attendees, dummy_org);
1002 		attlist = meet->attendees;
1003 	} else {
1004 		attlist = g_slist_prepend(NULL, dummy_org);
1005 	}
1006 
1007 	gtk_widget_set_sensitive(meet->save_btn, FALSE);
1008 	gtk_widget_set_sensitive(meet->avail_btn, FALSE);
1009 
1010 	gdkwin = gtk_widget_get_window(meet->window);
1011 	if (gdkwin != NULL)
1012 		gdk_window_set_cursor(gdkwin, watch_cursor);
1013 
1014 	for (cur = attlist; cur && cur->data; cur = cur->next) {
1015 		VCalAttendee *attendee = (VCalAttendee *)cur->data;
1016 		gchar *email = gtk_editable_get_chars(GTK_EDITABLE(attendee->address), 0, -1);
1017 		gchar *remail, *user, *domain;
1018 		gchar *contents = NULL;
1019 
1020 		if (*email == '\0') {
1021 			g_free(email);
1022 			att_update_icon(meet, attendee, 0, NULL);
1023 			continue;
1024 		}
1025 
1026 		if (!local_only) {
1027 			remail = g_strdup(email);
1028 
1029 			extract_address(remail);
1030 			if (strrchr(remail, ' '))
1031 				user = g_strdup(strrchr(remail, ' ')+1);
1032 			else
1033 				user = g_strdup(remail);
1034 			if (strchr(user, '@')) {
1035 				domain = g_strdup(strchr(user, '@')+1);
1036 				*(strchr(user, '@')) = '\0';
1037 			} else {
1038 				domain = g_strdup("");
1039 			}
1040 			g_free(remail);
1041 			if (change_user && change_dom) {
1042 				if (change_user < change_dom)
1043 					tmp = g_strdup_printf(real_url, user, domain);
1044 				else
1045 					tmp = g_strdup_printf(real_url, domain, user);
1046 			} else if (change_user) {
1047 				tmp = g_strdup_printf(real_url, user);
1048 			} else if (change_dom) {
1049 				tmp = g_strdup_printf(real_url, domain);
1050 			} else {
1051 				tmp = g_strdup(real_url);
1052 			}
1053 			g_free(user);
1054 			g_free(domain);
1055 			debug_print("url to get %s\n", tmp);
1056 		}
1057 
1058 		if (attendee->cached_contents != NULL) {
1059 			contents = attendee->cached_contents;
1060 			attendee->cached_contents = NULL;
1061 		} else if (!local_only) {
1062 			if (strncmp(tmp, "http://", 7)
1063 			&& strncmp(tmp, "https://", 8)
1064 			&& strncmp(tmp, "webcal://", 9)
1065 			&& strncmp(tmp, "webcals://", 10)
1066 			&& strncmp(tmp, "ftp://", 6))
1067 				contents = file_read_to_str(tmp);
1068 			else {
1069 				gchar *label = g_strdup_printf(_("Fetching planning for %s..."), email);
1070 				if (!strncmp(tmp, "webcal", 6)) {
1071 					gchar *tmp2 = g_strdup_printf("http%s", tmp+6);
1072 					g_free(tmp);
1073 					tmp = tmp2;
1074 				}
1075 				contents = vcal_curl_read(tmp, label, FALSE, NULL);
1076 				g_free(label);
1077 			}
1078 		} else {
1079 			contents = NULL;
1080 		}
1081 
1082 		g_free(email);
1083 		g_free(tmp);
1084 
1085 		if (contents == NULL) {
1086 			uncertain = TRUE;
1087 			att_update_icon(meet, attendee, 2, _("Free/busy retrieval failed"));
1088 			continue;
1089 		}
1090 		else {
1091 			if (!attendee_available(attendee, dtstart, dtend, contents)) {
1092 				find_avail = TRUE;
1093 				debug_print("not available!\n");
1094 			} else {
1095 				debug_print("available!\n");
1096 				att_update_icon(meet, attendee, 1, _("Available"));
1097 			}
1098 			attendee->cached_contents = contents;
1099 
1100 		}
1101 	}
1102 
1103 	if (find_avail) {
1104 		res = find_availability((dtstart), (dtend), attlist, for_send, meet);
1105 	} else {
1106 		res = TRUE;
1107 		if (tell_if_ok) {
1108 			if (for_send)
1109 				alertpanel_notice(_("Everyone is available."));
1110 			else if (!uncertain) {
1111 				gtk_image_set_from_stock
1112 		        		(GTK_IMAGE(meet->total_avail_img),
1113 					GTK_STOCK_DIALOG_INFO,
1114 					GTK_ICON_SIZE_SMALL_TOOLBAR);
1115 				gtk_widget_show(meet->total_avail_img);
1116 				gtk_label_set_text(GTK_LABEL(meet->total_avail_msg), _("Everyone is available."));
1117 				CLAWS_SET_TIP(meet->total_avail_evtbox, NULL);
1118 			} else {
1119 				gtk_image_set_from_stock
1120 		        		(GTK_IMAGE(meet->total_avail_img),
1121 					GTK_STOCK_DIALOG_QUESTION,
1122 					GTK_ICON_SIZE_SMALL_TOOLBAR);
1123 				gtk_widget_show(meet->total_avail_img);
1124 				gtk_label_set_text(GTK_LABEL(meet->total_avail_msg), _("Everyone is available."));
1125 				CLAWS_SET_TIP(meet->total_avail_evtbox, _("Everyone seems available, but some free/busy information failed to be retrieved."));
1126 			}
1127 		}
1128 	}
1129 
1130 	for (cur = attlist; cur && cur->data; cur = cur->next) {
1131 		VCalAttendee *attendee = (VCalAttendee *)cur->data;
1132 		g_free(attendee->cached_contents);
1133 		attendee->cached_contents = NULL;
1134 	}
1135 	gtk_widget_set_sensitive(meet->save_btn, TRUE);
1136 	gtk_widget_set_sensitive(meet->avail_btn, avail_btn_can_be_sensitive());
1137 
1138 	if (gdkwin != NULL)
1139 		gdk_window_set_cursor(gdkwin, NULL);
1140 
1141 	if (!local_only)
1142 		meet->attendees = g_slist_remove(meet->attendees, dummy_org);
1143 	else
1144 		g_slist_free(attlist);
1145 	gtk_widget_destroy(dummy_org->address);
1146 	g_free(dummy_org);
1147 
1148 	if (!local_only)
1149 		g_free(real_url);
1150 
1151 	g_free(dtstart);
1152 	g_free(dtend);
1153 	return res;
1154 }
1155 
check_avail_cb(GtkButton * widget,gpointer data)1156 static gboolean check_avail_cb(GtkButton *widget, gpointer data)
1157 {
1158 	VCalMeeting *meet = (VCalMeeting *)data;
1159 	check_attendees_availability(meet, TRUE, FALSE);
1160 	return TRUE;
1161 }
1162 
send_meeting_cb(GtkButton * widget,gpointer data)1163 static gboolean send_meeting_cb(GtkButton *widget, gpointer data)
1164 {
1165 	VCalMeeting *meet = (VCalMeeting *)data;
1166 	gchar *uid = NULL;
1167 	gchar *organizer = NULL;
1168 	gchar *organizer_name = NULL;
1169 	gchar *dtstart = NULL;
1170 	gchar *dtend = NULL;
1171 	gchar *tzid = NULL;
1172 	gchar *location = NULL;
1173 	gchar *summary = NULL;
1174 	gchar *description = NULL;
1175 	VCalEvent *event = NULL;
1176 	GSList *cur;
1177 	PrefsAccount *account = NULL;
1178 	gboolean res = FALSE;
1179 	gboolean found_att = FALSE;
1180 	Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
1181 	gboolean redisp = FALSE;
1182 	GdkWindow *gdkwin;
1183 
1184 	if (meet->uid == NULL && meet->visible &&
1185 	    !check_attendees_availability(meet, FALSE, TRUE)) {
1186 		return FALSE;
1187 	}
1188 
1189 	if (folder) {
1190 		MainWindow *mainwin = mainwindow_get_mainwindow();
1191 		if (mainwin->summaryview->folder_item == folder->inbox) {
1192 			redisp = TRUE;
1193 			summary_show(mainwin->summaryview, NULL, FALSE);
1194 		}
1195 	}
1196 	gtk_widget_set_sensitive(meet->save_btn, FALSE);
1197 	gtk_widget_set_sensitive(meet->avail_btn, FALSE);
1198 
1199 	gdkwin = gtk_widget_get_window(meet->window);
1200 	if (gdkwin != NULL)
1201 		gdk_window_set_cursor(gdkwin, watch_cursor);
1202 
1203 	organizer	= get_organizer(meet);
1204 	account		= account_find_from_address(organizer, FALSE);
1205 
1206 	if(account == NULL) {
1207 		debug_print("can't get account from address %s\n", organizer);
1208 		g_free(organizer);
1209 		return FALSE;
1210 	}
1211 
1212 	organizer_name	= get_organizer_name(meet);
1213 
1214 	if (meet->uid) {
1215 		uid 	= g_strdup(meet->uid);
1216 	} else {
1217 		uid 	= prefs_account_generate_msgid(account);
1218 	}
1219 
1220 	dtstart		= get_date(meet, TRUE);
1221 	dtend		= get_date(meet, FALSE);
1222 	location	= get_location(meet);
1223 	summary		= get_summary(meet);
1224 	description	= get_description(meet);
1225 
1226 	event = vcal_manager_new_event(uid, organizer, organizer_name, location, summary, description,
1227 					dtstart, dtend, NULL, tzid, NULL, meet->method,
1228 					meet->sequence,
1229 					ICAL_VEVENT_COMPONENT);
1230 
1231 	vcal_manager_update_answer(event, organizer, organizer_name,
1232 				   ICAL_PARTSTAT_ACCEPTED,
1233 				   ICAL_CUTYPE_INDIVIDUAL);
1234 
1235 	for (cur = meet->attendees; cur && cur->data; cur = cur->next) {
1236 		VCalAttendee *attendee = (VCalAttendee *)cur->data;
1237 		gchar *email = gtk_editable_get_chars(GTK_EDITABLE(attendee->address), 0, -1);
1238 		gint index = 0;
1239 		gchar *orig_email = email;
1240 		gchar *name = NULL;
1241 		enum icalparameter_cutype cutype = ICAL_CUTYPE_INDIVIDUAL;
1242 		enum icalparameter_partstat status = ICAL_PARTSTAT_NEEDSACTION;
1243 
1244 		index = gtk_combo_box_get_active(GTK_COMBO_BOX(attendee->cutype));
1245 
1246 		cutype = ICAL_CUTYPE_INDIVIDUAL + index;
1247 		if (attendee->status) {
1248 			if(!strcmp(attendee->status, "accepted"))
1249 				status = ICAL_PARTSTAT_ACCEPTED;
1250 			if(!strcmp(attendee->status, "tentatively accepted"))
1251 				status = ICAL_PARTSTAT_TENTATIVE;
1252 			if(!strcmp(attendee->status, "declined"))
1253 				status = ICAL_PARTSTAT_DECLINED;
1254 			g_free(attendee->status);
1255 		}
1256 		if (strlen(email)) {
1257 			if (strstr(email, " <")) {
1258 				name = email;
1259 				email = strstr(email," <") + 2;
1260 				*(strstr(name," <")) = '\0';
1261 				if (strstr(email, ">"))
1262 					*(strstr(email, ">")) = '\0';
1263 			}
1264 
1265 			vcal_manager_update_answer(event, email, name,
1266 					status,	cutype);
1267 
1268 			found_att = strcmp(email, organizer);
1269 		}
1270 		g_free(orig_email);
1271 	}
1272 
1273 	if (found_att)
1274 		res = vcal_manager_request(account, event);
1275 	else
1276 		res = TRUE;
1277 	g_free(uid);
1278 	g_free(organizer);
1279 	g_free(organizer_name);
1280 	g_free(dtstart);
1281 	g_free(dtend);
1282 	g_free(description);
1283 	g_free(location);
1284 	g_free(summary);
1285 	vcal_manager_free_event(event);
1286 
1287 	gtk_widget_set_sensitive(meet->save_btn, TRUE);
1288 	gtk_widget_set_sensitive(meet->avail_btn, avail_btn_can_be_sensitive());
1289 	if (gdkwin != NULL)
1290 		gdk_window_set_cursor(gdkwin, NULL);
1291 
1292 	if (res) {
1293 		vcal_destroy(meet);
1294 	} else {
1295 		alertpanel_error(_("Could not send the meeting invitation.\n"
1296 				   "Check the recipients."));
1297 	}
1298 
1299 	if (folder)
1300 		folder_item_scan(folder->inbox);
1301 
1302 	if (folder && redisp) {
1303 		MainWindow *mainwin = mainwindow_get_mainwindow();
1304 		summary_show(mainwin->summaryview, folder->inbox, FALSE);
1305 	}
1306 
1307 	return res;
1308 }
1309 
vcal_meeting_create_real(VCalEvent * event,gboolean visible)1310 static VCalMeeting *vcal_meeting_create_real(VCalEvent *event, gboolean visible)
1311 {
1312 	VCalMeeting *meet = g_new0(VCalMeeting, 1);
1313 	GtkTextBuffer *buffer = NULL;
1314 	GtkWidget *date_hbox, *date_vbox, *save_hbox, *label, *hbox;
1315 	gchar *s = NULL;
1316 	int i = 0, num = 0;
1317 	GtkWidget *scrolledwin;
1318 	GList *accounts;
1319 #ifdef GENERIC_UMPC
1320 	GtkWidget *notebook;
1321 	GtkWidget *maemo_vbox0;
1322 #endif
1323 
1324 	if (!watch_cursor)
1325 		watch_cursor = gdk_cursor_new(GDK_WATCH);
1326 
1327 	meet->visible = visible;
1328 
1329 	meet->window 		= gtkut_window_new(GTK_WINDOW_TOPLEVEL, "vcal_meeting_gtk");
1330 #ifndef GENERIC_UMPC
1331 	meet->table  		= gtk_table_new(7, 2, FALSE);
1332 #else
1333 	meet->table1  		= gtk_table_new(4, 2, FALSE);
1334 	meet->table2  		= gtk_table_new(2, 2, FALSE);
1335 #endif
1336 	meet->who    		= gtk_combo_box_text_new();
1337 
1338 	meet->start_c		= gtk_calendar_new();
1339 	meet->end_c		= gtk_calendar_new();
1340 
1341 	meet->avail_evtbox  = gtk_event_box_new();
1342 	meet->avail_img	= gtk_image_new_from_stock
1343                         (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
1344 
1345 	meet->start_time = gtkut_time_select_combo_new();
1346 
1347 	meet->end_time = gtkut_time_select_combo_new();
1348 
1349 	meet->location  	= gtk_entry_new();
1350 	meet->summary		= gtk_entry_new();
1351 	meet->description	= gtk_text_view_new();
1352         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(meet->description));
1353         gtk_text_view_set_editable(GTK_TEXT_VIEW(meet->description), TRUE);
1354         gtk_text_buffer_add_selection_clipboard(buffer, gtk_clipboard_get(GDK_SELECTION_PRIMARY));
1355 
1356 	scrolledwin = gtk_scrolled_window_new(NULL, NULL);
1357 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
1358 				       GTK_POLICY_AUTOMATIC,
1359 				       GTK_POLICY_AUTOMATIC);
1360 	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
1361 					    GTK_SHADOW_IN);
1362 	gtk_container_add(GTK_CONTAINER(scrolledwin), meet->description);
1363 
1364 	if (event) {
1365 		meet->uid = g_strdup(event->uid);
1366 		meet->sequence = event->sequence + 1;
1367 		meet->method = (event->method == ICAL_METHOD_CANCEL ?
1368 				ICAL_METHOD_CANCEL:ICAL_METHOD_REQUEST);
1369 
1370 		gtk_entry_set_text(GTK_ENTRY(meet->location), event->location);
1371 		gtk_entry_set_text(GTK_ENTRY(meet->summary), event->summary);
1372 		gtk_text_buffer_set_text(buffer, event->description, -1);
1373 	} else
1374 		meet->method = ICAL_METHOD_REQUEST;
1375 
1376 	meet->save_btn		= gtk_button_new_with_label(_("Save & Send"));
1377 	meet->avail_btn		= gtk_button_new_with_label(_("Check availability"));
1378 
1379 	meet->total_avail_evtbox  = gtk_event_box_new();
1380 	meet->total_avail_img	= gtk_image_new_from_stock
1381                         (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
1382 	meet->total_avail_msg = gtk_label_new("");
1383 
1384 	gtk_widget_set_size_request(meet->total_avail_evtbox, 18, 16);
1385 	gtk_event_box_set_visible_window(GTK_EVENT_BOX(meet->total_avail_evtbox), FALSE);
1386 	gtk_container_add (GTK_CONTAINER(meet->total_avail_evtbox), meet->total_avail_img);
1387 
1388 	g_signal_connect(G_OBJECT(meet->save_btn), "clicked",
1389 			 G_CALLBACK(send_meeting_cb), meet);
1390 
1391 	g_signal_connect(G_OBJECT(meet->avail_btn), "clicked",
1392 			 G_CALLBACK(check_avail_cb), meet);
1393 
1394 	g_signal_connect(G_OBJECT(meet->window), "destroy",
1395 			 G_CALLBACK(destroy_meeting_cb), meet);
1396 	g_signal_connect(G_OBJECT(meet->window), "key_press_event",
1397 			 G_CALLBACK(meeting_key_pressed), meet);
1398 
1399 
1400 	gtk_widget_set_size_request(meet->description, -1, 100);
1401 	gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(meet->description), GTK_WRAP_WORD);
1402 
1403 	if (!event || (event && !event->dtstart && !event->dtend)) {
1404 		time_t t = time (NULL)+ 3600;
1405 		struct tm buft1, buft2;
1406  		struct tm *lt = localtime_r (&t, &buft1);
1407 		mktime(lt);
1408 		gtk_calendar_select_day(GTK_CALENDAR(meet->start_c),
1409 					lt->tm_mday);
1410 		gtk_calendar_select_month(GTK_CALENDAR(meet->start_c),
1411 					lt->tm_mon, lt->tm_year + 1900);
1412 
1413 		gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet->start_time), lt->tm_hour, 0);
1414 
1415 		t += 3600;
1416 		lt = localtime_r(&t, &buft2);
1417 
1418 		gtk_calendar_select_day(GTK_CALENDAR(meet->end_c),
1419 					lt->tm_mday);
1420 		gtk_calendar_select_month(GTK_CALENDAR(meet->end_c),
1421 					lt->tm_mon, lt->tm_year + 1900);
1422 
1423 		gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet->end_time), lt->tm_hour, 0);
1424 	} else {
1425 		gtk_calendar_select_day(GTK_CALENDAR(meet->start_c),
1426 					get_dtdate(event->dtstart, DAY));
1427 		gtk_calendar_select_day(GTK_CALENDAR(meet->end_c),
1428 					get_dtdate(event->dtend, DAY));
1429 
1430 		gtk_calendar_select_month(GTK_CALENDAR(meet->start_c),
1431 					get_dtdate(event->dtstart, MONTH)-1,
1432 					get_dtdate(event->dtstart, YEAR));
1433 		gtk_calendar_select_month(GTK_CALENDAR(meet->end_c),
1434 					get_dtdate(event->dtend, MONTH)-1,
1435 					get_dtdate(event->dtend, YEAR));
1436 
1437 		gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet->start_time),
1438 					get_dtdate(event->dtstart, HOUR),
1439 					get_dtdate(event->dtstart, MINUTE));
1440 
1441 		gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet->end_time),
1442 					get_dtdate(event->dtend, HOUR),
1443 					get_dtdate(event->dtend, MINUTE));
1444 	}
1445 
1446 	g_signal_connect(G_OBJECT(meet->start_c), "day-selected",
1447 			 G_CALLBACK(meeting_start_changed), meet);
1448 	g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN(meet->start_time))),
1449 			 "changed",
1450 			 G_CALLBACK(meeting_start_changed),
1451 			 meet);
1452 
1453 	g_signal_connect(G_OBJECT(meet->end_c), "day-selected",
1454 			 G_CALLBACK(meeting_end_changed), meet);
1455 	g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN(meet->end_time))),
1456 			 "changed",
1457 			 G_CALLBACK(meeting_end_changed),
1458 			 meet);
1459 
1460 #ifndef GENERIC_UMPC
1461 	gtk_widget_set_size_request(meet->start_time, 80, -1);
1462 	gtk_widget_set_size_request(meet->end_time, 80, -1);
1463 #else
1464 	gtk_widget_set_size_request(meet->start_time, 120, -1);
1465 	gtk_widget_set_size_request(meet->end_time, 120, -1);
1466 #endif
1467 
1468 	date_hbox = gtk_hbox_new(FALSE, 6);
1469 	date_vbox = gtk_vbox_new(FALSE, 6);
1470 	hbox = gtk_hbox_new(FALSE, 6);
1471 	label = gtk_label_new(g_strconcat("<b>",_("Starts at:"),"</b> ",NULL));
1472 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1473 	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
1474 
1475 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1476 	gtk_box_pack_start(GTK_BOX(hbox), meet->start_time, FALSE, FALSE, 0);
1477 	label = gtk_label_new(g_strconcat("<b> ",_("on:"),"</b>",NULL));
1478 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1479 	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
1480 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1481 	gtk_box_pack_start(GTK_BOX(date_vbox), hbox, FALSE, FALSE, 0);
1482 	gtk_box_pack_start(GTK_BOX(date_vbox), meet->start_c, FALSE, FALSE, 0);
1483 	gtk_box_pack_start(GTK_BOX(date_hbox), date_vbox, FALSE, FALSE, 0);
1484 
1485 #ifndef GENERIC_UMPC
1486 	label = gtk_label_new(" ");
1487 #else
1488 	label = gtk_label_new("");
1489 #endif
1490 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1491 	gtk_box_pack_start(GTK_BOX(date_hbox), label, TRUE, TRUE, 0);
1492 
1493 	date_vbox = gtk_vbox_new(FALSE, 6);
1494 	hbox = gtk_hbox_new(FALSE, 6);
1495 	label = gtk_label_new(g_strconcat("<b>",_("Ends at:"),"</b> ", NULL));
1496 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1497 	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
1498 
1499 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1500 	gtk_box_pack_start(GTK_BOX(hbox), meet->end_time, FALSE, FALSE, 0);
1501 	label = gtk_label_new(g_strconcat("<b> ",_("on:"),"</b>",NULL));
1502 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1503 	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
1504 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1505 	gtk_box_pack_start(GTK_BOX(date_vbox), hbox, FALSE, FALSE, 0);
1506 	gtk_box_pack_start(GTK_BOX(date_vbox), meet->end_c, FALSE, FALSE, 0);
1507 	gtk_box_pack_start(GTK_BOX(date_hbox), date_vbox, FALSE, FALSE, 0);
1508 
1509 	meet->attendees_vbox = gtk_vbox_new(FALSE, 6);
1510 	gtk_widget_show_all(meet->attendees_vbox);
1511 	if (!event) {
1512 		attendee_add(meet, NULL, NULL, NULL, NULL, TRUE);
1513 	} else {
1514 		gboolean firstadd = TRUE;
1515 		GSList *list = vcal_manager_get_answers_emails(event);
1516 		while (list && list->data) {
1517 			gchar *address = (gchar *)list->data;
1518 			gchar *name = vcal_manager_get_attendee_name(event, address);
1519 			gchar *answer = vcal_manager_get_reply_text_for_attendee(event, address);
1520 			gchar *type = vcal_manager_get_cutype_text_for_attendee(event, address);
1521 			if (strcmp(event->organizer, address)) {
1522 				attendee_add(meet, address, name, answer, type, firstadd);
1523 				firstadd = FALSE;
1524 			}
1525 			g_free(name);
1526 			g_free(answer);
1527 			g_free(type);
1528 			list = list->next;
1529 		}
1530 
1531 		if (firstadd == TRUE)
1532 			attendee_add(meet, NULL, NULL, NULL, NULL, TRUE);
1533 	}
1534 
1535 	if (!event) {
1536 		gtk_window_set_title(GTK_WINDOW(meet->window), _("New meeting"));
1537 	} else {
1538 		gchar *title = g_strdup_printf(_("%s - Edit meeting"),
1539 			event->summary);
1540 		gtk_window_set_title(GTK_WINDOW(meet->window), title);
1541 		g_free(title);
1542 	}
1543 	address_completion_start(meet->window);
1544 
1545 	accounts = account_get_list();
1546 	g_return_val_if_fail(accounts != NULL, NULL);
1547 
1548 	for (i = 0; accounts != NULL; accounts = accounts->next) {
1549 		PrefsAccount *ac = (PrefsAccount *)accounts->data;
1550 
1551 		if (ac->protocol == A_NNTP) {
1552 			continue;
1553 		}
1554 		if (!event && ac == account_get_cur_account()) {
1555 			num = i;
1556 		}
1557 		else if (event && !strcmp(ac->address, event->organizer))
1558 			num = i;
1559 
1560 		meet->avail_accounts = g_slist_append(meet->avail_accounts, ac);
1561 
1562 		if (ac->name)
1563 			s = g_strdup_printf("%s: %s <%s>",
1564 					       ac->account_name,
1565 					       ac->name, ac->address);
1566 		else
1567 			s = g_strdup_printf("%s: %s",
1568 					       ac->account_name, ac->address);
1569 
1570 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(meet->who), s);
1571 		g_free(s);
1572 		i++;
1573 	}
1574 	gtk_combo_box_set_active(GTK_COMBO_BOX(meet->who), num);
1575 
1576 	save_hbox = gtk_hbox_new(FALSE, 6);
1577 	gtk_box_pack_start(GTK_BOX(save_hbox), meet->save_btn, FALSE, FALSE, 0);
1578 	gtk_box_pack_start(GTK_BOX(save_hbox), meet->avail_btn, FALSE, FALSE, 0);
1579 	gtk_box_pack_start(GTK_BOX(save_hbox), meet->total_avail_evtbox, FALSE, FALSE, 0);
1580 	gtk_box_pack_start(GTK_BOX(save_hbox), meet->total_avail_msg, FALSE, FALSE, 0);
1581 
1582 	hbox = gtk_hbox_new(FALSE, 6);
1583 	gtk_box_pack_start(GTK_BOX(hbox), meet->avail_evtbox, FALSE, FALSE, 0);
1584 	gtk_box_pack_start(GTK_BOX(hbox), meet->who, TRUE, TRUE, 0);
1585 
1586 	gtk_widget_set_size_request(meet->avail_evtbox, 18, 16);
1587 	gtk_event_box_set_visible_window(GTK_EVENT_BOX(meet->avail_evtbox), FALSE);
1588 	gtk_container_add (GTK_CONTAINER(meet->avail_evtbox), meet->avail_img);
1589 
1590 #ifndef GENERIC_UMPC
1591 	TABLE_ADD_LINE(_("Organizer:"), hbox, FALSE);
1592 	TABLE_ADD_LINE(_("Summary:"), meet->summary, TRUE);
1593 	TABLE_ADD_LINE(_("Time:"), date_hbox, TRUE);
1594 	TABLE_ADD_LINE(_("Location:"), meet->location, TRUE);
1595 	TABLE_ADD_LINE(_("Description:"), scrolledwin, TRUE);
1596 	TABLE_ADD_LINE(_("Attendees:"), meet->attendees_vbox, FALSE);
1597 	TABLE_ADD_LINE("", save_hbox, TRUE);
1598 
1599 	gtk_widget_set_size_request(meet->window, -1, -1);
1600 	gtk_container_add(GTK_CONTAINER(meet->window), meet->table);
1601 #else
1602 	TABLE_ADD_LINE(_("Organizer:"), hbox, FALSE, TRUE);
1603 	TABLE_ADD_LINE(_("Summary:"), meet->summary, TRUE, TRUE);
1604 	TABLE_ADD_LINE(_("Location:"), meet->location, FALSE, TRUE);
1605 	TABLE_ADD_LINE(_("Description:"), scrolledwin, TRUE, TRUE);
1606 	TABLE_ADD_LINE(_("Attendees:"), meet->attendees_vbox, FALSE, TRUE);
1607 	TABLE_ADD_LINE("", date_hbox, TRUE, FALSE);
1608 
1609 	notebook = gtk_notebook_new ();
1610 	gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE);
1611 	gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1612 			meet->table1,
1613 			gtk_label_new_with_mnemonic(_("Event:")));
1614 
1615 	gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1616 			meet->table2,
1617 			gtk_label_new_with_mnemonic(_("Time:")));
1618 	gtk_widget_show (notebook);
1619 
1620 	maemo_vbox0 = gtk_vbox_new(FALSE, 3);
1621 	gtk_box_pack_start(GTK_BOX(maemo_vbox0), notebook, TRUE, TRUE, 0);
1622 	gtk_box_pack_start(GTK_BOX(maemo_vbox0), save_hbox, FALSE, FALSE, 0);
1623 
1624 	gtk_widget_set_size_request(meet->window, -1, -1);
1625 	gtk_container_add (GTK_CONTAINER (meet->window), maemo_vbox0);
1626 
1627 	maemo_connect_key_press_to_mainwindow(GTK_WINDOW(meet->window));
1628 #endif
1629 	if (visible) {
1630 		GSList *cur;
1631 		gtk_widget_show_all(meet->window);
1632 		for (cur = meet->attendees; cur; cur = cur->next) {
1633 			gtk_widget_hide(((VCalAttendee *)cur->data)->avail_img);
1634 		}
1635 		gtk_widget_hide(meet->avail_img);
1636 		gtk_widget_hide(meet->total_avail_img);
1637 		gtk_widget_set_sensitive(meet->avail_btn, avail_btn_can_be_sensitive());
1638 	}
1639 	return meet;
1640 }
1641 
vcal_meeting_create(VCalEvent * event)1642 VCalMeeting *vcal_meeting_create(VCalEvent *event)
1643 {
1644 	return vcal_meeting_create_real(event, TRUE);
1645 }
1646 
vcal_meeting_create_with_start(VCalEvent * event,struct tm * sdate)1647 VCalMeeting *vcal_meeting_create_with_start(VCalEvent *event, struct tm *sdate)
1648 {
1649 	VCalMeeting *meet = vcal_meeting_create(event);
1650 
1651 	gtk_calendar_select_day(GTK_CALENDAR(meet->start_c),
1652 				sdate->tm_mday);
1653 	gtk_calendar_select_day(GTK_CALENDAR(meet->end_c),
1654 				sdate->tm_mday);
1655 
1656 	gtk_calendar_select_month(GTK_CALENDAR(meet->start_c),
1657 				sdate->tm_mon, sdate->tm_year+1900);
1658 	gtk_calendar_select_month(GTK_CALENDAR(meet->end_c),
1659 				sdate->tm_mon, sdate->tm_year+1900);
1660 
1661 	if (sdate->tm_hour != 0) {
1662 		gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet->start_time), sdate->tm_hour, 0);
1663 
1664 		if (sdate->tm_hour < 23) {
1665 			gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet->end_time), sdate->tm_hour+1, 0);
1666 		} else {
1667 			struct tm tm_tomorrow;
1668 
1669 			tm_tomorrow.tm_mday = sdate->tm_mday;
1670 			tm_tomorrow.tm_mon = sdate->tm_mon;
1671 			tm_tomorrow.tm_wday = sdate->tm_wday;
1672 			tm_tomorrow.tm_year = sdate->tm_year+1900;
1673 			tm_tomorrow.tm_hour = sdate->tm_hour;
1674 			orage_move_day(&tm_tomorrow, +1);
1675 			gtk_calendar_select_day(GTK_CALENDAR(meet->end_c),
1676 						tm_tomorrow.tm_mday);
1677 			gtk_calendar_select_month(GTK_CALENDAR(meet->end_c),
1678 						tm_tomorrow.tm_mon, tm_tomorrow.tm_year);
1679 
1680 			gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet->end_time), 0, 0);
1681 		}
1682 	}
1683 	return meet;
1684 }
1685 
vcal_meeting_create_hidden(VCalEvent * event)1686 VCalMeeting *vcal_meeting_create_hidden(VCalEvent *event)
1687 {
1688 	return vcal_meeting_create_real(event, FALSE);
1689 }
1690 
vcal_meeting_send(VCalMeeting * meet)1691 gboolean vcal_meeting_send(VCalMeeting *meet)
1692 {
1693 	return send_meeting_cb(NULL, meet);
1694 }
1695 
vcal_meeting_alert_check(gpointer data)1696 gboolean vcal_meeting_alert_check(gpointer data)
1697 {
1698 	GSList *events = NULL, *cur = NULL;
1699 
1700 	if (!vcalprefs.alert_enable)
1701 		return TRUE;
1702 
1703 	events = vcal_folder_get_waiting_events();
1704 
1705 	for (cur = events; cur; cur = cur->next) {
1706 		VCalEvent *event = (VCalEvent *)cur->data;
1707 		time_t start, end, current;
1708 		gboolean warn = FALSE;
1709 
1710 		tzset();
1711 
1712 		start = icaltime_as_timet(icaltime_from_string(event->dtstart));
1713 		end = icaltime_as_timet(icaltime_from_string(event->dtend));
1714 		current = time(NULL);
1715 
1716 		if (start - current <= (vcalprefs.alert_delay*60)
1717 		&&  start - current + 60 > (vcalprefs.alert_delay*60)) {
1718 			warn = TRUE;
1719 		} else if (event->postponed - current <= (vcalprefs.alert_delay*60)
1720 		&&         event->postponed - current + 60 > (vcalprefs.alert_delay*60)) {
1721 			warn = TRUE;
1722 		}
1723 		if (warn) {
1724 			time_t tmpt = icaltime_as_timet((icaltime_from_string(event->dtstart)));
1725 			gchar *estart = NULL;
1726 			AlertValue aval;
1727 			int length = (end - start) / 60;
1728 			gchar *duration = NULL, *hours = NULL, *minutes = NULL;
1729 			gchar *message = NULL;
1730 			gchar *title = NULL;
1731 			gchar *label = NULL;
1732 			int postpone_min = 0;
1733 
1734 			tzset();
1735 
1736 			estart = g_strdup(ctime(&tmpt));
1737 
1738 			if (length >= 60)
1739 				hours = g_strdup_printf(ngettext("%d hour", "%d hours",
1740 						(length/60) > 1 ? 2 : 1), length/60);
1741 			if (length%60)
1742 				minutes = g_strdup_printf(ngettext("%d minute", "%d minutes",
1743 						length%60), length%60);
1744 
1745 			duration = g_strdup_printf("%s%s%s",
1746 					hours?hours:"",
1747 					hours && minutes ? " ":"",
1748 					minutes?minutes:"");
1749 
1750 			g_free(hours);
1751 			g_free(minutes);
1752 
1753 			title = g_strdup_printf(_("Upcoming event: %s"), event->summary);
1754 			message = g_strdup_printf(_("You have a meeting or event soon.\n"
1755 					 "It starts at %s and ends %s later.\n"
1756                      "Location: %s\n"
1757 					 "More information:\n\n"
1758 					 "%s"),
1759 						estart,
1760 						duration,
1761 						event->location?event->location:"",
1762 						event->description);
1763 
1764 			g_free(duration);
1765 			g_free(estart);
1766 
1767 			postpone_min = (vcalprefs.alert_delay/2 > 15) ? 15: (vcalprefs.alert_delay/2);
1768 			if (postpone_min == 0)
1769 				postpone_min = 1;
1770 
1771 			label = g_strdup_printf(ngettext("Remind me in %d minute", "Remind me in %d minutes",
1772 						 postpone_min > 1 ? 2:1),
1773 						 postpone_min);
1774 			aval = alertpanel_full(title, message,
1775 				   	label, GTK_STOCK_OK, NULL, ALERTFOCUS_FIRST, FALSE,
1776 				   	NULL, ALERT_NOTICE);
1777 			g_free(label);
1778 
1779 			g_free(title);
1780 			g_free(message);
1781 
1782 			if (aval == G_ALERTDEFAULT) {
1783 				if (event->postponed == 0)
1784 					event->postponed = start + (postpone_min*60);
1785 				else
1786 					event->postponed += (postpone_min*60);
1787 			} else {
1788 				event->postponed = (time_t)0;
1789 			}
1790 			vcal_manager_save_event(event, FALSE);
1791 		}
1792 
1793 		vcal_manager_free_event((VCalEvent *)cur->data);
1794 	}
1795 
1796 	g_slist_free(events);
1797 
1798 	return TRUE;
1799 }
1800 
multisync_export(void)1801 void multisync_export(void)
1802 {
1803 	GSList *list = NULL;
1804 	gchar *path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
1805 				"vcalendar", G_DIR_SEPARATOR_S,
1806 				"multisync", NULL);
1807 	GSList *files = NULL;
1808 	GSList *cur = NULL;
1809 	gchar *file = NULL;
1810 	gchar *tmp = NULL;
1811 	gint i = 0;
1812 	icalcomponent *calendar = NULL;
1813 	FILE *fp;
1814 
1815 	if (is_dir_exist(path) && remove_dir_recursive(path) < 0) {
1816 		g_free(path);
1817 		return;
1818 	}
1819 	if (make_dir(path) != 0) {
1820 		g_free(path);
1821 		return;
1822 	}
1823 
1824 	list = vcal_folder_get_waiting_events();
1825 	for (cur = list; cur; cur = cur->next) {
1826 		VCalEvent *event = (VCalEvent *)cur->data;
1827 		file = g_strdup_printf("multisync%"G_GSIZE_FORMAT"-%d",
1828 				time(NULL), i);
1829 
1830 		i++;
1831 
1832 		calendar =
1833         		icalcomponent_vanew(
1834         		    ICAL_VCALENDAR_COMPONENT,
1835 	        	    icalproperty_new_version("2.0"),
1836         		    icalproperty_new_prodid(
1837                 		 "-//Claws Mail//NONSGML Claws Mail Calendar//EN"),
1838 			    icalproperty_new_calscale("GREGORIAN"),
1839         		    (void*)0
1840         	    );
1841 		vcal_manager_event_dump(event, FALSE, FALSE, calendar, FALSE);
1842 		tmp = g_strconcat(path, G_DIR_SEPARATOR_S, file, NULL);
1843 		str_write_to_file(icalcomponent_as_ical_string(calendar), tmp, TRUE);
1844 		g_free(tmp);
1845 		files = g_slist_append(files, file);
1846 		vcal_manager_free_event(event);
1847 		icalcomponent_free(calendar);
1848 	}
1849 
1850 	g_slist_free(list);
1851 
1852 	file = g_strconcat(path, G_DIR_SEPARATOR_S, "backup_entries", NULL);
1853 	fp = claws_fopen(file, "wb");
1854 	g_free(file);
1855 	if (fp) {
1856 		for (cur = files; cur; cur = cur->next) {
1857 			file = (char *)cur->data;
1858 			if (fprintf(fp, "1 1 %s\n", file) < 0)
1859 				FILE_OP_ERROR(file, "fprintf");
1860 			g_free(file);
1861 		}
1862 		if (claws_safe_fclose(fp) == EOF)
1863 			FILE_OP_ERROR(file, "claws_fclose");
1864 	} else {
1865 		FILE_OP_ERROR(file, "claws_fopen");
1866 	}
1867 	g_free(path);
1868 	g_slist_free(files);
1869 }
1870 
vcal_meeting_export_calendar(const gchar * path,const gchar * user,const gchar * pass,gboolean automatic)1871 gboolean vcal_meeting_export_calendar(const gchar *path,
1872 				const gchar *user, const gchar *pass,
1873 				gboolean automatic)
1874 {
1875 	GSList *list = vcal_folder_get_waiting_events();
1876 	GSList *subs = NULL;
1877 	GSList *cur;
1878 	icalcomponent *calendar = NULL;
1879 	gchar *file = NULL;
1880 	gchar *tmpfile = get_tmp_file();
1881 	gchar *internal_file = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
1882 				"vcalendar", G_DIR_SEPARATOR_S,
1883 				"internal.ics", NULL);
1884 
1885 	gboolean res = TRUE;
1886 	long filesize = 0;
1887 
1888 	multisync_export();
1889 
1890 	if (vcalprefs.export_subs && vcalprefs.export_enable)
1891 		subs = vcal_folder_get_webcal_events();
1892 
1893 	if (g_slist_length(list) == 0 && g_slist_length(subs) == 0) {
1894 		g_slist_free(list);
1895 		g_slist_free(subs);
1896 		if (!automatic) {
1897 			alertpanel_full(_("Empty calendar"),
1898 					_("There is nothing to export."),
1899 				   	GTK_STOCK_OK, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
1900 			   	NULL, ALERT_NOTICE);
1901 			return FALSE;
1902 		} else {
1903 			str_write_to_file("", tmpfile, TRUE);
1904 			goto putfile;
1905 		}
1906 	}
1907 
1908 	calendar =
1909         	icalcomponent_vanew(
1910         	    ICAL_VCALENDAR_COMPONENT,
1911 	            icalproperty_new_version("2.0"),
1912         	    icalproperty_new_prodid(
1913                 	 "-//Claws Mail//NONSGML Claws Mail Calendar//EN"),
1914 		    icalproperty_new_calscale("GREGORIAN"),
1915         	    (void*)0
1916             );
1917 
1918 	for (cur = list; cur; cur = cur->next) {
1919 		VCalEvent *event = (VCalEvent *)cur->data;
1920 		vcal_manager_event_dump(event, FALSE, FALSE, calendar, FALSE);
1921 		vcal_manager_free_event(event);
1922 	}
1923 
1924 	if (str_write_to_file(icalcomponent_as_ical_string(calendar), internal_file, TRUE) < 0) {
1925 		g_warning("can't export internal cal");
1926 	}
1927 
1928 	g_free(internal_file);
1929 
1930 	for (cur = subs; cur; cur = cur->next) {
1931 		/* Not to be freed */
1932 		icalcomponent *event = (icalcomponent *)cur->data;
1933 		vcal_manager_icalevent_dump(event, NULL, calendar);
1934 	}
1935 
1936 	if (vcalprefs.export_enable || path == NULL) {
1937 		if (str_write_to_file(icalcomponent_as_ical_string(calendar), tmpfile, TRUE) < 0) {
1938 			alertpanel_error(_("Could not export the calendar."));
1939 			g_free(tmpfile);
1940 			icalcomponent_free(calendar);
1941 			g_slist_free(list);
1942 			g_slist_free(subs);
1943 			return FALSE;
1944 		}
1945 		filesize = strlen(icalcomponent_as_ical_string(calendar));
1946 	}
1947 
1948 	icalcomponent_free(calendar);
1949 
1950 putfile:
1951 	g_slist_free(list);
1952 	g_slist_free(subs);
1953 
1954 	if (!path && !automatic)
1955 		file = filesel_select_file_save(_("Export calendar to ICS"), NULL);
1956 	else
1957 		file = g_strdup(path);
1958 
1959 	if (automatic && (!path || strlen(path) == 0 || !vcalprefs.export_enable)) {
1960 		g_free(tmpfile);
1961 		g_free(file);
1962 		return TRUE;
1963 	}
1964 
1965 	if (file
1966 	&& strncmp(file, "http://", 7)
1967 	&& strncmp(file, "https://", 8)
1968 	&& strncmp(file, "webcal://", 9)
1969 	&& strncmp(file, "webcals://", 10)
1970 	&& strncmp(file, "ftp://", 6)) {
1971 		gchar *afile = NULL;
1972 		if (file[0] != G_DIR_SEPARATOR)
1973 			afile=g_strdup_printf("%s%s%s", get_home_dir(),
1974 					G_DIR_SEPARATOR_S, file);
1975 		else
1976 			afile=g_strdup(file);
1977 		if (move_file(tmpfile, afile, TRUE) != 0) {
1978 			log_error(LOG_PROTOCOL, _("Couldn't export calendar to '%s'\n"),
1979 				afile);
1980 			res = FALSE;
1981 		}
1982 		g_free(afile);
1983 		g_free(file);
1984 	} else if (file) {
1985 		FILE *fp = claws_fopen(tmpfile, "rb");
1986 		if (!strncmp(file, "webcal", 6)) {
1987 			gchar *tmp = g_strdup_printf("http%s", file+6);
1988 			g_free(file);
1989 			file = tmp;
1990 		}
1991 		if (fp) {
1992 			res = vcal_curl_put(file, fp, filesize, user, (pass != NULL ? pass : ""));
1993 			claws_fclose(fp);
1994 		}
1995 		g_free(file);
1996 	}
1997 	g_free(tmpfile);
1998 	return res;
1999 }
2000 
vcal_meeting_export_freebusy(const gchar * path,const gchar * user,const gchar * pass)2001 gboolean vcal_meeting_export_freebusy(const gchar *path, const gchar *user,
2002 				const gchar *pass)
2003 {
2004 	GSList *list = vcal_folder_get_waiting_events();
2005 	GSList *cur;
2006 	icalcomponent *calendar = NULL, *timezone = NULL, *tzc = NULL, *vfreebusy = NULL;
2007 	gchar *file = NULL;
2008 	gchar *tmpfile = get_tmp_file();
2009 	gchar *internal_file = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
2010 				"vcalendar", G_DIR_SEPARATOR_S,
2011 				"internal.ifb", NULL);
2012 	time_t whole_start = time(NULL);
2013 	time_t whole_end = whole_start + (60*60*24*365);
2014 	gboolean res = TRUE;
2015 	struct icaltimetype itt_start, itt_end;
2016 	long filesize = 0;
2017 
2018 	multisync_export();
2019 
2020 	calendar =
2021         	icalcomponent_vanew(
2022         	    ICAL_VCALENDAR_COMPONENT,
2023 	            icalproperty_new_version("2.0"),
2024         	    icalproperty_new_prodid(
2025                 	 "-//Claws Mail//NONSGML Claws Mail Calendar//EN"),
2026 		    icalproperty_new_calscale("GREGORIAN"),
2027         	    (void*)0
2028             );
2029 
2030 	timezone = icalcomponent_new(ICAL_VTIMEZONE_COMPONENT);
2031 
2032 	icalcomponent_add_property(timezone,
2033 		icalproperty_new_tzid("UTC"));
2034 
2035 	tzc = icalcomponent_new(ICAL_XSTANDARD_COMPONENT);
2036 	icalcomponent_add_property(tzc,
2037 		icalproperty_new_dtstart(
2038 			icaltime_from_string("19700101T000000")));
2039 	icalcomponent_add_property(tzc,
2040 		icalproperty_new_tzoffsetfrom(0.0));
2041 	icalcomponent_add_property(tzc,
2042 		icalproperty_new_tzoffsetto(0.0));
2043 	icalcomponent_add_property(tzc,
2044 		icalproperty_new_tzname("Greenwich meridian time"));
2045 
2046 	icalcomponent_add_component(timezone, tzc);
2047 
2048 	icalcomponent_add_component(calendar, timezone);
2049 
2050 	itt_start = icaltime_from_timet_with_zone(whole_start, FALSE, NULL);
2051 	itt_end = icaltime_from_timet_with_zone(whole_end, FALSE, NULL);
2052 	itt_start.second = itt_start.minute = itt_start.hour = 0;
2053 	itt_end.second = 59; itt_end.minute = 59; itt_end.hour = 23;
2054 
2055 
2056 	vfreebusy =
2057 	    icalcomponent_vanew(
2058                 ICAL_VFREEBUSY_COMPONENT,
2059 		icalproperty_vanew_dtstart(itt_start, 0),
2060 		icalproperty_vanew_dtend(itt_end, 0),
2061                 (void*)0
2062                 );
2063 
2064 	debug_print("DTSTART:%s\nDTEND:%s\n",
2065 		icaltime_as_ical_string(itt_start),
2066 		icaltime_as_ical_string(itt_end));
2067 
2068 	for (cur = list; cur; cur = cur->next) {
2069 		VCalEvent *event = (VCalEvent *)cur->data;
2070 		icalproperty *prop;
2071 		struct icalperiodtype ipt;
2072 
2073 		ipt.start = icaltime_from_string(event->dtstart);
2074 		ipt.end = icaltime_from_string(event->dtend);
2075 		ipt.duration = icaltime_subtract(ipt.end, ipt.start);
2076 		if (icaltime_as_timet(ipt.start) <= icaltime_as_timet(itt_end)
2077 		 && icaltime_as_timet(ipt.end) >= icaltime_as_timet(itt_start)) {
2078 			prop = icalproperty_new_freebusy(ipt);
2079 			icalcomponent_add_property(vfreebusy, prop);
2080 		}
2081 		vcal_manager_free_event(event);
2082 	}
2083 
2084 	icalcomponent_add_component(calendar, vfreebusy);
2085 
2086 	if (str_write_to_file(icalcomponent_as_ical_string(calendar), internal_file, TRUE) < 0) {
2087 		g_warning("can't export freebusy");
2088 	}
2089 
2090 	g_free(internal_file);
2091 
2092 	if (vcalprefs.export_freebusy_enable) {
2093 		if (str_write_to_file(icalcomponent_as_ical_string(calendar), tmpfile, TRUE) < 0) {
2094 			alertpanel_error(_("Could not export the freebusy info."));
2095 			g_free(tmpfile);
2096 			icalcomponent_free(calendar);
2097 			g_slist_free(list);
2098 			return FALSE;
2099 		}
2100 		filesize = strlen(icalcomponent_as_ical_string(calendar));
2101 	}
2102 
2103 	icalcomponent_free(calendar);
2104 	g_slist_free(list);
2105 
2106 	if ((!path || strlen(path) == 0 || !vcalprefs.export_freebusy_enable)) {
2107 		g_free(tmpfile);
2108 		return TRUE;
2109 	}
2110 	file = g_strdup(path);
2111 
2112 
2113 	if (file
2114 	&& strncmp(file, "http://", 7)
2115 	&& strncmp(file, "https://", 8)
2116 	&& strncmp(file, "webcal://", 9)
2117 	&& strncmp(file, "webcals://", 10)
2118 	&& strncmp(file, "ftp://", 6)) {
2119 		gchar *afile = NULL;
2120 		if (file[0] != G_DIR_SEPARATOR)
2121 			afile=g_strdup_printf("%s%s%s", get_home_dir(),
2122 					G_DIR_SEPARATOR_S, file);
2123 		else
2124 			afile=g_strdup(file);
2125 		if (move_file(tmpfile, file, TRUE) != 0) {
2126 			log_error(LOG_PROTOCOL, _("Couldn't export free/busy to '%s'\n"),
2127 				afile);
2128 			res = FALSE;
2129 		}
2130 		g_free(afile);
2131 		g_free(file);
2132 	} else if (file) {
2133 		FILE *fp = claws_fopen(tmpfile, "rb");
2134 		if (!strncmp(file, "webcal", 6)) {
2135 			gchar *tmp = g_strdup_printf("http%s", file+6);
2136 			g_free(file);
2137 			file = tmp;
2138 		}
2139 		if (fp) {
2140 			res = vcal_curl_put(file, fp, filesize, user, (pass != NULL ? pass : ""));
2141 			claws_fclose(fp);
2142 		}
2143 		g_free(file);
2144 	}
2145 	g_free(tmpfile);
2146 	return res;
2147 }
2148