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