2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2022 Colin Leroy <colin@colino.net> and
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.
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.
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.
23 #include "claws-features.h"
28 #include <glib/gi18n.h>
35 #include <libical/ical.h>
37 #include <gdk/gdkkeysyms.h>
38 #include <curl/curl.h>
39 #include <curl/curlver.h>
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"
52 #include "alertpanel.h"
53 #include "addr_compl.h"
57 #include "file-utils.h"
73 GtkWidget
*avail_evtbox
;
76 GtkWidget
*start_time
;
81 GtkWidget
*description
;
83 GtkWidget
*attendees_vbox
;
86 GSList
*avail_accounts
;
87 GtkWidget
*total_avail_evtbox
;
88 GtkWidget
*total_avail_img
;
89 GtkWidget
*total_avail_msg
;
90 PrefsAccount
*account
;
94 struct _VCalAttendee
{
96 GtkWidget
*remove_btn
;
102 GtkWidget
*avail_evtbox
;
103 GtkWidget
*avail_img
;
104 gchar
*cached_contents
;
108 static GdkCursor
*watch_cursor
= NULL
;
110 VCalAttendee
*attendee_add(VCalMeeting
*meet
, gchar
*address
, gchar
*name
, gchar
*partstat
, gchar
*cutype
, gboolean first
);
113 #define TABLE_ADD_LINE(label_text, widget, do_space) { \
114 gchar *tmpstr = g_strdup_printf("<span weight=\"bold\">%s</span>", \
115 label_text?label_text:""); \
116 GtkWidget *label = NULL; \
117 GtkWidget *spacer = NULL; \
118 GtkWidget *s_hbox = NULL; \
120 spacer = gtk_label_new(""); \
121 gtk_widget_set_size_request(spacer, 18, 16); \
122 s_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); \
123 gtk_box_pack_start(GTK_BOX(s_hbox), spacer, FALSE, FALSE, 0); \
124 gtk_box_pack_start(GTK_BOX(s_hbox), widget, TRUE, TRUE, 0); \
127 label = gtk_label_new(tmpstr); \
129 gtk_label_set_use_markup (GTK_LABEL (label), TRUE); \
130 gtk_label_set_xalign (GTK_LABEL(label), 1.0); \
131 gtk_grid_attach(GTK_GRID(meet->table), label, 0, i, 1, 1); \
132 gtk_grid_attach(GTK_GRID(meet->table), do_space?s_hbox:widget, \
134 gtk_widget_set_hexpand(do_space?s_hbox:widget, TRUE); \
135 gtk_widget_set_halign(do_space?s_hbox:widget, GTK_ALIGN_FILL); \
136 if (GTK_IS_LABEL(widget)) { \
137 gtk_label_set_use_markup(GTK_LABEL (widget), TRUE); \
138 gtk_label_set_xalign(GTK_LABEL(widget), 0.0); \
139 gtk_label_set_yalign(GTK_LABEL(widget), 0.0); \
140 gtk_label_set_line_wrap(GTK_LABEL(widget), TRUE); \
144 gtk_grid_attach(GTK_GRID(meet->table), do_space?s_hbox:widget, \
146 gtk_widget_set_hexpand(do_space?s_hbox:widget, TRUE); \
147 gtk_widget_set_halign(do_space?s_hbox:widget, GTK_ALIGN_FILL); \
152 #define TABLE_ADD_LINE(label_text, widget, do_space, intable1) { \
153 gchar *tmpstr = g_strdup_printf("<span weight=\"bold\">%s</span>", \
154 label_text?label_text:""); \
155 GtkWidget *label = NULL; \
156 GtkWidget *spacer = NULL; \
157 GtkWidget *s_hbox = NULL; \
159 spacer = gtk_label_new(""); \
160 gtk_widget_set_size_request(spacer, 18, 16); \
161 s_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); \
162 gtk_box_pack_start(GTK_BOX(s_hbox), spacer, FALSE, FALSE, 0); \
163 gtk_box_pack_start(GTK_BOX(s_hbox), widget, TRUE, TRUE, 0); \
166 label = gtk_label_new(tmpstr); \
168 gtk_label_set_use_markup (GTK_LABEL (label), TRUE); \
169 gtk_label_set_xalign (GTK_LABEL(label), 1.0); \
171 gtk_grid_attach(GTK_GRID(meet->table1), label, \
175 gtk_grid_attach(GTK_GRID(meet->table2), label, \
179 gtk_grid_attach(GTK_GRID(meet->table1), \
180 do_space?s_hbox:widget, 1, i, 1, 1); \
183 gtk_grid_attach(GTK_GRID(meet->table2), \
184 do_space?s_hbox:widget, 1, i, 1, 1); \
186 if (GTK_IS_LABEL(widget)) { \
187 gtk_label_set_use_markup(GTK_LABEL (widget), TRUE); \
188 gtk_label_set_xalign(GTK_LABEL(widget), 0.0); \
189 gtk_label_set_yalign(GTK_LABEL(widget), 0.0); \
190 gtk_label_set_line_wrap(GTK_LABEL(widget), TRUE); \
195 gtk_grid_attach(GTK_GRID(meet->table1), \
196 do_space?s_hbox:widget, 0, i, 1, 1); \
197 gtk_widget_set_hexpand(do_space?s_hbox:widget, TRUE); \
198 gtk_widget_set_halign(do_space?s_hbox:widget, \
202 gtk_grid_attach(GTK_GRID(meet->table2), \
203 do_space?s_hbox:widget, 0, i, 1, 1); \
204 gtk_widget_set_hexpand(do_space?s_hbox:widget, TRUE); \
205 gtk_widget_set_halign(do_space?s_hbox:widget, \
220 static gboolean
avail_btn_can_be_sensitive(void)
222 if (vcalprefs
.freebusy_get_url
== NULL
223 || *vcalprefs
.freebusy_get_url
== '\0')
229 static gint
get_dtdate(const gchar
*str
, gint field
)
231 time_t t
= icaltime_as_timet((icaltime_from_string(str
)));
241 lt
= localtime_r(&t
, &buft
);
247 return lt
->tm_mon
+ 1;
249 return lt
->tm_year
+ 1900;
259 static void set_watch_cursor(GdkWindow
*window
)
261 cm_return_if_fail(window
!= NULL
);
264 watch_cursor
= gdk_cursor_new_for_display(
265 gdk_window_get_display(window
), GDK_WATCH
);
269 static gboolean
add_btn_cb(GtkButton
*widget
, gpointer data
)
271 VCalAttendee
*attendee
= (VCalAttendee
*)data
;
272 attendee_add(attendee
->meet
, NULL
, NULL
, NULL
, NULL
, FALSE
);
276 static gboolean
remove_btn_cb(GtkButton
*widget
, gpointer data
)
278 VCalAttendee
*attendee
= (VCalAttendee
*)data
;
279 gtk_container_remove(GTK_CONTAINER(attendee
->meet
->attendees_vbox
), attendee
->hbox
);
280 attendee
->meet
->attendees
= g_slist_remove(attendee
->meet
->attendees
, attendee
);
282 g_free(attendee
->status
);
287 VCalAttendee
*attendee_add(VCalMeeting
*meet
, gchar
*address
, gchar
*name
, gchar
*partstat
, gchar
*cutype
, gboolean first
)
289 GtkWidget
*att_hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 6);
290 VCalAttendee
*attendee
= g_new0(VCalAttendee
, 1);
292 attendee
->address
= gtk_entry_new();
293 attendee
->cutype
= gtk_combo_box_text_new();
294 attendee
->avail_evtbox
= gtk_event_box_new();
295 attendee
->avail_img
= gtk_image_new_from_icon_name
296 ("dialog-warning", GTK_ICON_SIZE_SMALL_TOOLBAR
);
298 gtk_widget_show(attendee
->address
);
299 gtk_widget_show(attendee
->cutype
);
300 gtk_widget_show(attendee
->avail_evtbox
);
302 CLAWS_SET_TIP(attendee
->address
, _("Use <tab> to autocomplete from addressbook"));
303 gtk_widget_set_size_request(attendee
->avail_evtbox
, 18, 16);
304 gtk_event_box_set_visible_window(GTK_EVENT_BOX(attendee
->avail_evtbox
), FALSE
);
305 gtk_container_add (GTK_CONTAINER(attendee
->avail_evtbox
), attendee
->avail_img
);
308 gchar
*str
= g_strdup_printf("%s%s%s%s",
309 (name
&& strlen(name
))?name
:"",
310 (name
&& strlen(name
))?" <":"",
312 (name
&& strlen(name
))?">":"");
313 gtk_entry_set_text(GTK_ENTRY(attendee
->address
), str
);
318 attendee
->status
= g_strdup(partstat
);
320 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(attendee
->cutype
), _("Individual"));
321 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(attendee
->cutype
), _("Group"));
322 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(attendee
->cutype
), _("Resource"));
323 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(attendee
->cutype
), _("Room"));
325 gtk_combo_box_set_active(GTK_COMBO_BOX(attendee
->cutype
), 0);
328 if (!strcmp(cutype
, "group"))
329 gtk_combo_box_set_active(GTK_COMBO_BOX(attendee
->cutype
), 1);
330 if (!strcmp(cutype
, "resource"))
331 gtk_combo_box_set_active(GTK_COMBO_BOX(attendee
->cutype
), 2);
332 if (!strcmp(cutype
, "room"))
333 gtk_combo_box_set_active(GTK_COMBO_BOX(attendee
->cutype
), 3);
336 attendee
->add_btn
= gtk_button_new_with_label(_("Add..."));
337 attendee
->remove_btn
= gtk_button_new_with_label(_("Remove"));
338 attendee
->meet
= meet
;
339 attendee
->hbox
= att_hbox
;
341 gtk_widget_show(attendee
->add_btn
);
342 gtk_widget_show(attendee
->remove_btn
);
343 gtk_widget_show(attendee
->hbox
);
345 gtk_box_pack_start(GTK_BOX(attendee
->hbox
), attendee
->avail_evtbox
, FALSE
, FALSE
, 0);
346 gtk_widget_set_sensitive(attendee
->remove_btn
, !first
);
347 meet
->attendees
= g_slist_append(meet
->attendees
, attendee
);
349 g_signal_connect(G_OBJECT(attendee
->remove_btn
), "clicked",
350 G_CALLBACK(remove_btn_cb
), attendee
);
351 g_signal_connect(G_OBJECT(attendee
->add_btn
), "clicked",
352 G_CALLBACK(add_btn_cb
), attendee
);
354 gtk_box_pack_start(GTK_BOX(att_hbox
), attendee
->address
, FALSE
, FALSE
, 0);
355 gtk_box_pack_start(GTK_BOX(att_hbox
), attendee
->cutype
, FALSE
, FALSE
, 0);
356 gtk_box_pack_start(GTK_BOX(att_hbox
), attendee
->add_btn
, FALSE
, FALSE
, 0);
357 gtk_box_pack_start(GTK_BOX(att_hbox
), attendee
->remove_btn
, FALSE
, FALSE
, 0);
358 gtk_box_pack_start(GTK_BOX(meet
->attendees_vbox
), att_hbox
, FALSE
, FALSE
, 0);
359 address_completion_register_entry(GTK_ENTRY(attendee
->address
), FALSE
);
361 gtk_widget_set_size_request(attendee
->address
, 320, -1);
363 gtk_widget_set_size_request(attendee
->address
, 220, -1);
368 static gchar
*get_organizer(VCalMeeting
*meet
)
370 int index
= gtk_combo_box_get_active(GTK_COMBO_BOX(meet
->who
));
372 GSList
*cur
= meet
->avail_accounts
;
373 while (i
< index
&& cur
&& cur
->data
) {
374 debug_print("%d:skipping %s\n",i
,((PrefsAccount
*)(cur
->data
))->address
);
378 if (cur
&& cur
->data
)
379 return g_strdup(((PrefsAccount
*)(cur
->data
))->address
);
384 static gchar
*get_organizer_name(VCalMeeting
*meet
)
386 int index
= gtk_combo_box_get_active(GTK_COMBO_BOX(meet
->who
));
388 GSList
*cur
= meet
->avail_accounts
;
389 while (i
< index
&& cur
&& cur
->data
) {
390 debug_print("%d:skipping %s\n",i
,((PrefsAccount
*)(cur
->data
))->address
);
394 if (cur
&& cur
->data
)
395 return g_strdup(((PrefsAccount
*)(cur
->data
))->name
);
400 static int get_current_gmt_offset(void)
402 time_t now
= time(NULL
);
412 gmtime_r(& now
, & gmt
);
413 localtime_r(& now
, & local
);
416 return mktime(&local
)-mktime(&gmt
);
419 static int get_gmt_offset_at_time(time_t then
)
430 gmtime_r(& then
, & gmt
);
431 localtime_r(& then
, & local
);
434 return mktime(&local
)-mktime(&gmt
);
437 static gchar
*get_date(VCalMeeting
*meet
, int start
)
452 lt
= localtime_r(&t
, &buft
);
454 gtk_calendar_get_date(GTK_CALENDAR(start
? meet
->start_c
: meet
->end_c
), &y
, &m
, &d
);
457 lt
->tm_year
= y
- 1900;
463 gtkut_time_select_get_time(GTK_COMBO_BOX(meet
->start_time
), <
->tm_hour
, <
->tm_min
);
465 gtkut_time_select_get_time(GTK_COMBO_BOX(meet
->end_time
), <
->tm_hour
, <
->tm_min
);
468 debug_print("%d %d %d, %d:%d\n", lt
->tm_mday
, lt
->tm_mon
, lt
->tm_year
, lt
->tm_hour
, lt
->tm_min
);
471 dst_offset
= get_current_gmt_offset() - get_gmt_offset_at_time(t
);
472 debug_print("DST change offset to apply to time %d\n", dst_offset
);
474 debug_print("%s\n", ctime(&t
));
475 return g_strdup(icaltime_as_ical_string(icaltime_from_timet_with_zone(t
, FALSE
, NULL
)));
478 static gchar
*get_location(VCalMeeting
*meet
)
480 return gtk_editable_get_chars(GTK_EDITABLE(meet
->location
),0, -1);
483 static gchar
*get_summary(VCalMeeting
*meet
)
485 return gtk_editable_get_chars(GTK_EDITABLE(meet
->summary
),0, -1);
488 static gchar
*get_description(VCalMeeting
*meet
)
490 GtkTextBuffer
*buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(meet
->description
));
491 GtkTextIter start
, end
;
493 gtk_text_buffer_get_start_iter(buffer
, &start
);
494 gtk_text_buffer_get_end_iter(buffer
, &end
);
495 return gtk_text_buffer_get_text(buffer
, &start
, &end
, FALSE
);
498 void vcal_meeting_free(VCalMeeting
*meet
)
500 debug_print("freeing meeting\n");
502 address_completion_end(meet
->window
);
503 g_slist_free(meet
->avail_accounts
);
504 g_slist_free(meet
->attendees
);
508 static void destroy_meeting_cb(GtkWidget
*widget
, gpointer data
)
510 VCalMeeting
*meet
= (VCalMeeting
*)data
;
511 vcal_meeting_free(meet
);
514 static void vcal_destroy(VCalMeeting
*meet
)
516 GtkTextBuffer
*buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(meet
->description
));
517 gtk_text_buffer_remove_selection_clipboard(buffer
, gtk_clipboard_get(GDK_SELECTION_PRIMARY
));
518 gtk_widget_destroy(meet
->window
);
521 static gboolean
meeting_key_pressed(GtkWidget
*widget
,
525 VCalMeeting
*meet
= (VCalMeeting
*)data
;
527 if (event
&& event
->keyval
== GDK_KEY_Escape
) {
533 static void meeting_end_changed(GtkWidget
*widget
, gpointer data
);
535 static void meeting_start_changed(GtkWidget
*widget
, gpointer data
)
537 VCalMeeting
*meet
= (VCalMeeting
*)data
;
540 time_t start_t
, end_t
;
543 if (!gtkut_time_select_get_time(GTK_COMBO_BOX(meet
->start_time
), &start_lt
.tm_hour
, &start_lt
.tm_min
))
547 start_t
= time(NULL
);
555 localtime_r(&start_t
, &start_lt
);
556 localtime_r(&end_t
, &end_lt
);
558 gtk_calendar_get_date(GTK_CALENDAR(meet
->start_c
), &y
, &m
, &d
);
559 start_lt
.tm_mday
= d
; start_lt
.tm_mon
= m
; start_lt
.tm_year
= y
- 1900;
561 start_t
= mktime(&start_lt
);
562 debug_print("start %s\n", ctime(&start_t
));
564 gtk_calendar_get_date(GTK_CALENDAR(meet
->end_c
), &y
, &m
, &d
);
565 end_lt
.tm_mday
= d
; end_lt
.tm_mon
= m
; end_lt
.tm_year
= y
- 1900;
567 gtkut_time_select_get_time(GTK_COMBO_BOX(meet
->end_time
), &end_lt
.tm_hour
, &end_lt
.tm_min
);
569 end_t
= mktime(&end_lt
);
571 debug_print("end %s\n", ctime(&end_t
));
573 if (end_t
> start_t
) {
577 end_t
= start_t
+ 3600;
583 localtime_r(&end_t
, &end_lt
);
584 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
);
586 g_signal_handlers_block_by_func(gtk_bin_get_child(GTK_BIN(meet
->end_time
)), meeting_end_changed
, meet
);
587 g_signal_handlers_block_by_func(meet
->end_c
, meeting_end_changed
, meet
);
589 gtk_calendar_select_day(GTK_CALENDAR(meet
->end_c
), end_lt
.tm_mday
);
591 gtk_calendar_select_month(GTK_CALENDAR(meet
->end_c
),
593 end_lt
.tm_year
+ 1900);
595 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->end_time
), end_lt
.tm_hour
, end_lt
.tm_min
);
597 g_signal_handlers_unblock_by_func(gtk_bin_get_child(GTK_BIN(meet
->end_time
)), meeting_end_changed
, meet
);
598 g_signal_handlers_unblock_by_func(meet
->end_c
, meeting_end_changed
, meet
);
601 static void meeting_end_changed(GtkWidget
*widget
, gpointer data
)
603 VCalMeeting
*meet
= (VCalMeeting
*)data
;
606 time_t start_t
, end_t
;
609 if (!gtkut_time_select_get_time(GTK_COMBO_BOX(meet
->end_time
), &end_lt
.tm_hour
, &end_lt
.tm_min
))
611 start_t
= time(NULL
);
622 localtime_r(&start_t
, &start_lt
);
623 localtime_r(&end_t
, &end_lt
);
625 gtk_calendar_get_date(GTK_CALENDAR(meet
->start_c
), &y
, &m
, &d
);
626 start_lt
.tm_mday
= d
; start_lt
.tm_mon
= m
; start_lt
.tm_year
= y
- 1900;
627 gtkut_time_select_get_time(GTK_COMBO_BOX(meet
->start_time
), &start_lt
.tm_hour
, &start_lt
.tm_min
);
629 start_t
= mktime(&start_lt
);
630 debug_print("start %s\n", ctime(&start_t
));
632 gtk_calendar_get_date(GTK_CALENDAR(meet
->end_c
), &y
, &m
, &d
);
633 end_lt
.tm_mday
= d
; end_lt
.tm_mon
= m
; end_lt
.tm_year
= y
- 1900;
635 end_t
= mktime(&end_lt
);
637 debug_print("end %s\n", ctime(&end_t
));
639 if (end_t
> start_t
) {
643 start_t
= end_t
- 3600;
651 localtime_r(&start_t
, &start_lt
);
652 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
);
654 g_signal_handlers_block_by_func(gtk_bin_get_child(GTK_BIN(meet
->start_time
)), meeting_start_changed
, meet
);
655 g_signal_handlers_block_by_func(meet
->start_c
, meeting_start_changed
, meet
);
657 gtk_calendar_select_day(GTK_CALENDAR(meet
->start_c
), start_lt
.tm_mday
);
659 gtk_calendar_select_month(GTK_CALENDAR(meet
->start_c
),
661 start_lt
.tm_year
+ 1900);
663 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->start_time
), start_lt
.tm_hour
, start_lt
.tm_min
);
665 g_signal_handlers_unblock_by_func(gtk_bin_get_child(GTK_BIN(meet
->start_time
)), meeting_start_changed
, meet
);
666 g_signal_handlers_unblock_by_func(meet
->start_c
, meeting_start_changed
, meet
);
669 static void att_update_icon(VCalMeeting
*meet
, VCalAttendee
*attendee
, gint avail
, gchar
*text
)
671 const gchar
*icon
= "dialog-information";
674 case 0: icon
= "dialog-warning"; break;
675 case 1: icon
= "dialog-information"; break;
676 default: icon
= "dialog-question"; break;
678 if (!gtk_entry_get_text(GTK_ENTRY(attendee
->address
))
679 || strlen(gtk_entry_get_text(GTK_ENTRY(attendee
->address
)))==0) {
680 if (attendee
->avail_img
) {
681 gtk_widget_hide(attendee
->avail_img
);
683 CLAWS_SET_TIP(attendee
->avail_evtbox
, NULL
);
684 } else if (attendee
->avail_img
) {
685 gtk_image_set_from_icon_name
686 (GTK_IMAGE(attendee
->avail_img
),
688 GTK_ICON_SIZE_SMALL_TOOLBAR
);
689 gtk_widget_show(attendee
->avail_img
);
690 CLAWS_SET_TIP(attendee
->avail_evtbox
, text
);
694 gboolean
attendee_available(VCalAttendee
*attendee
, const gchar
*dtstart
, const gchar
*dtend
, const gchar
*contents
)
696 icalcomponent
*toplvl
, *vfreebusy
;
697 icalproperty
*busyprop
;
698 struct icaltimetype start
= icaltime_from_string(dtstart
);
699 struct icaltimetype end
= icaltime_from_string(dtend
);
700 gboolean result
= TRUE
;
703 if (contents
== NULL
)
706 toplvl
= icalcomponent_new_from_string((gchar
*)contents
);
711 vfreebusy
= icalcomponent_get_first_component(toplvl
, ICAL_VFREEBUSY_COMPONENT
);
712 while (vfreebusy
&& icalcomponent_isa(vfreebusy
) != ICAL_VFREEBUSY_COMPONENT
)
713 vfreebusy
= icalcomponent_get_next_component(toplvl
, ICAL_VFREEBUSY_COMPONENT
);
716 busyprop
= icalcomponent_get_first_property(vfreebusy
, ICAL_FREEBUSY_PROPERTY
);
718 struct icalperiodtype ipt
= icalproperty_get_freebusy(busyprop
);
720 if ( icaltime_compare(start
, ipt
.end
) >= 0 || icaltime_compare(end
, ipt
.start
) <= 0 ) {
726 busyprop
= icalcomponent_get_next_property(vfreebusy
, ICAL_FREEBUSY_PROPERTY
);
730 icalcomponent_free(toplvl
);
734 static gchar
*get_avail_msg(const gchar
*unavailable_persons
, gboolean multiple
,
735 gboolean short_version
, gint offset_before
, gint offset_after
)
737 gchar
*msg
, *intro
= NULL
, *outro
= NULL
, *before
= NULL
, *after
= NULL
;
740 intro
= g_strdup(_("The following people are busy at the time of your planned meeting:\n- "));
741 else if (!strcmp(unavailable_persons
, _("You")))
742 intro
= g_strdup(_("You are busy at the time of your planned meeting"));
744 intro
= g_strdup_printf(_("%s is busy at the time of your planned meeting"), unavailable_persons
);
745 if (offset_before
== 3600)
746 before
= g_strdup_printf(_("%d hour sooner"), offset_before
/3600);
747 else if (offset_before
> 3600 && offset_before
%3600 == 0)
748 before
= g_strdup_printf(_("%d hours sooner"), offset_before
/3600);
749 else if (offset_before
> 3600)
750 before
= g_strdup_printf(_("%d hours and %d minutes sooner"), offset_before
/3600, (offset_before
%3600)/60);
751 else if (offset_before
== 1800)
752 before
= g_strdup_printf(_("%d minutes sooner"), offset_before
/60);
756 if (offset_after
== 3600)
757 after
= g_strdup_printf(_("%d hour later"), offset_after
/3600);
758 else if (offset_after
> 3600 && offset_after
%3600 == 0)
759 after
= g_strdup_printf(_("%d hours later"), offset_after
/3600);
760 else if (offset_after
> 3600)
761 after
= g_strdup_printf(_("%d hours and %d minutes later"), offset_after
/3600, (offset_after
%3600)/60);
762 else if (offset_after
== 1800)
763 after
= g_strdup_printf(_("%d minutes later"), offset_after
/60);
769 outro
= g_strdup_printf(_("\n\nEveryone would be available %s or %s."), before
, after
);
770 else if (before
|| after
)
771 outro
= g_strdup_printf(_("\n\nEveryone would be available %s."), before
?before
:after
);
773 outro
= g_strdup_printf(_("\n\nIt isn't possible to have this meeting with everyone "
774 "in the previous or next 6 hours."));
778 outro
= g_markup_printf_escaped(_("would be available %s or %s"), before
, after
);
779 else if (before
|| after
)
780 outro
= g_markup_printf_escaped(_("would be available %s"), before
?before
:after
);
782 outro
= g_strdup_printf(_("not available"));
785 outro
= g_markup_printf_escaped(_(", but would be available %s or %s."), before
, after
);
786 else if (before
|| after
)
787 outro
= g_markup_printf_escaped(_(", but would be available %s."), before
?before
:after
);
789 outro
= g_strdup_printf(_(", and isn't available "
790 "in the previous or next 6 hours."));
793 if (multiple
&& short_version
)
794 msg
= g_strconcat(outro
+2, NULL
);
796 msg
= g_strconcat(intro
, unavailable_persons
, outro
, NULL
);
797 else if (short_version
)
798 msg
= g_strdup(outro
);
800 msg
= g_strconcat(intro
, outro
, NULL
);
808 static gboolean
find_availability(const gchar
*dtstart
, const gchar
*dtend
, GSList
*attendees
, gboolean for_send
, VCalMeeting
*meet
)
811 gint offset
= -1800, offset_before
= 0, offset_after
= 0;
812 gboolean found
= FALSE
;
813 gchar
*unavailable_persons
= NULL
;
815 struct icaltimetype start
= icaltime_from_string(dtstart
);
816 struct icaltimetype end
= icaltime_from_string(dtend
);
817 AlertValue val
= G_ALERTALTERNATE
;
819 GHashTable
*avail_table_avail
= g_hash_table_new(NULL
, g_direct_equal
);
820 GHashTable
*avail_table_before
= g_hash_table_new(NULL
, g_direct_equal
);
821 GHashTable
*avail_table_after
= g_hash_table_new(NULL
, g_direct_equal
);
823 for (cur
= attendees
; cur
; cur
= cur
->next
) {
824 VCalAttendee
*attendee
= (VCalAttendee
*)cur
->data
;
825 if (!attendee_available(attendee
, icaltime_as_ical_string(start
), icaltime_as_ical_string(end
),
826 attendee
->cached_contents
)) {
830 mail
= g_strdup(_("You"));
832 mail
= gtk_editable_get_chars(GTK_EDITABLE(attendee
->address
), 0, -1);
834 if (unavailable_persons
== NULL
) {
835 unavailable_persons
= g_markup_printf_escaped("%s", mail
);
837 gchar
*tmp
= g_markup_printf_escaped("%s,\n- %s", unavailable_persons
, mail
);
838 g_free(unavailable_persons
);
839 unavailable_persons
= tmp
;
843 att_update_icon(meet
, attendee
, 0, _("not available"));
845 if (attendee
->cached_contents
!= NULL
)
846 att_update_icon(meet
, attendee
, 1, _("available"));
848 att_update_icon(meet
, attendee
, 2, _("Free/busy retrieval failed"));
850 g_hash_table_insert(avail_table_avail
, attendee
, GINT_TO_POINTER(1));
855 while (!found
&& offset
>= -3600*6) {
857 struct icaltimetype new_start
= icaltime_from_timet_with_zone(icaltime_as_timet(start
)+offset
, FALSE
, NULL
);
858 struct icaltimetype new_end
= icaltime_from_timet_with_zone(icaltime_as_timet(end
)+offset
, FALSE
, NULL
);
859 for (cur
= attendees
; cur
; cur
= cur
->next
) {
860 VCalAttendee
*attendee
= (VCalAttendee
*)cur
->data
;
861 debug_print("trying %s - %s (offset %d)\n",
862 icaltime_as_ical_string(new_start
), icaltime_as_ical_string(new_end
), offset
);
863 if (!attendee_available(attendee
, icaltime_as_ical_string(new_start
), icaltime_as_ical_string(new_end
),
864 attendee
->cached_contents
)) {
868 if (!g_hash_table_lookup(avail_table_before
, attendee
)
869 && !g_hash_table_lookup(avail_table_avail
, attendee
))
870 g_hash_table_insert(avail_table_before
, attendee
, GINT_TO_POINTER(-offset
));
875 offset_before
= -offset
;
881 while (!found
&& offset
<= 3600*6) {
883 struct icaltimetype new_start
= icaltime_from_timet_with_zone(icaltime_as_timet(start
)+offset
, FALSE
, NULL
);
884 struct icaltimetype new_end
= icaltime_from_timet_with_zone(icaltime_as_timet(end
)+offset
, FALSE
, NULL
);
885 for (cur
= attendees
; cur
; cur
= cur
->next
) {
886 VCalAttendee
*attendee
= (VCalAttendee
*)cur
->data
;
887 debug_print("trying %s - %s (offset %d)\n",
888 icaltime_as_ical_string(new_start
), icaltime_as_ical_string(new_end
), offset
);
889 if (!attendee_available(attendee
, icaltime_as_ical_string(new_start
), icaltime_as_ical_string(new_end
),
890 attendee
->cached_contents
)) {
894 if (!g_hash_table_lookup(avail_table_after
, attendee
)
895 && !g_hash_table_lookup(avail_table_avail
, attendee
))
896 g_hash_table_insert(avail_table_after
, attendee
, GINT_TO_POINTER(offset
));
901 offset_after
= offset
;
907 for (cur
= attendees
; cur
; cur
= cur
->next
) {
908 VCalAttendee
*attendee
= (VCalAttendee
*)cur
->data
;
909 gint ok
= GPOINTER_TO_INT(g_hash_table_lookup(avail_table_avail
, attendee
));
910 gint o_before
= GPOINTER_TO_INT(g_hash_table_lookup(avail_table_before
, attendee
));
911 gint o_after
= GPOINTER_TO_INT(g_hash_table_lookup(avail_table_after
, attendee
));
912 if (!o_before
&& !o_after
&& !ok
) {
913 att_update_icon(meet
, attendee
, 0, _("not available"));
914 } else if ((o_before
!= 0 || o_after
!= 0) && !ok
) {
916 msg
= get_avail_msg(_("You"), FALSE
, TRUE
, o_before
, o_after
);
918 msg
= get_avail_msg(gtk_entry_get_text(GTK_ENTRY(attendee
->address
)), FALSE
, TRUE
, o_before
, o_after
);
919 att_update_icon(meet
, attendee
, 0, msg
);
924 g_hash_table_destroy(avail_table_before
);
925 g_hash_table_destroy(avail_table_after
);
928 msg
= get_avail_msg(unavailable_persons
, (total
> 1), FALSE
, offset_before
, offset_after
);
930 val
= alertpanel_full(_("Not everyone is available"), msg
,
931 NULL
, _("_Cancel"), NULL
, _("Send anyway"),
932 NULL
, NULL
, ALERTFOCUS_FIRST
,
933 FALSE
, NULL
, ALERT_QUESTION
);
936 msg
= get_avail_msg(unavailable_persons
, TRUE
, TRUE
, offset_before
, offset_after
);
937 g_free(unavailable_persons
);
938 gtk_image_set_from_icon_name
939 (GTK_IMAGE(meet
->total_avail_img
),
941 GTK_ICON_SIZE_SMALL_TOOLBAR
);
942 gtk_widget_show(meet
->total_avail_img
);
943 gtk_label_set_text(GTK_LABEL(meet
->total_avail_msg
), _("Not everyone is available. "
944 "See tooltips for more info..."));
945 CLAWS_SET_TIP(meet
->total_avail_evtbox
, msg
);
947 return (val
== G_ALERTALTERNATE
);
950 static gboolean
check_attendees_availability(VCalMeeting
*meet
, gboolean tell_if_ok
, gboolean for_send
)
954 gchar
*real_url
= NULL
;
956 gchar
*change_user
= NULL
, *change_dom
= NULL
;
957 gchar
*dtstart
= NULL
;
959 gboolean find_avail
= FALSE
;
960 gboolean res
= TRUE
, uncertain
= FALSE
;
961 gchar
*organizer
= NULL
;
962 VCalAttendee
*dummy_org
= NULL
;
963 gchar
*internal_ifb
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
964 "vcalendar", G_DIR_SEPARATOR_S
,
965 "internal.ifb", NULL
);
966 gboolean local_only
= FALSE
;
970 if (vcalprefs
.freebusy_get_url
== NULL
971 || *vcalprefs
.freebusy_get_url
== '\0') {
974 real_url
= g_strdup(vcalprefs
.freebusy_get_url
);
977 while (strchr(tmp
, '%')) {
978 tmp
= strchr(tmp
, '%')+1;
981 if (num_format
> 2) {
982 g_warning("wrong format in %s!", real_url
);
984 g_free(internal_ifb
);
989 if (strstr(real_url
, "%u") != NULL
) {
990 change_user
= strstr(real_url
, "%u");
991 *(strstr(real_url
, "%u")+1) = 's';
993 if (strstr(real_url
, "%d") != NULL
) {
994 change_dom
= strstr(real_url
, "%d");
995 *(strstr(real_url
, "%d")+1) = 's';
997 debug_print("url format %s\n", real_url
);
999 dtstart
= get_date(meet
, TRUE
);
1000 dtend
= get_date(meet
, FALSE
);
1002 /* hack to check our own avail. */
1003 organizer
= get_organizer(meet
);
1004 dummy_org
= g_new0(VCalAttendee
, 1);
1005 dummy_org
->address
= gtk_entry_new();
1006 dummy_org
->avail_img
= meet
->avail_img
;
1007 dummy_org
->avail_evtbox
= meet
->avail_evtbox
;
1008 dummy_org
->org
= TRUE
;
1009 gtk_entry_set_text(GTK_ENTRY(dummy_org
->address
), organizer
);
1011 dummy_org
->cached_contents
= file_read_to_str(internal_ifb
);
1012 g_free(internal_ifb
);
1015 meet
->attendees
= g_slist_prepend(meet
->attendees
, dummy_org
);
1016 attlist
= meet
->attendees
;
1018 attlist
= g_slist_prepend(NULL
, dummy_org
);
1021 gtk_widget_set_sensitive(meet
->save_btn
, FALSE
);
1022 gtk_widget_set_sensitive(meet
->avail_btn
, FALSE
);
1024 gdkwin
= gtk_widget_get_window(meet
->window
);
1025 if (gdkwin
!= NULL
) {
1026 set_watch_cursor(gdkwin
);
1027 gdk_window_set_cursor(gdkwin
, watch_cursor
);
1030 for (cur
= attlist
; cur
&& cur
->data
; cur
= cur
->next
) {
1031 VCalAttendee
*attendee
= (VCalAttendee
*)cur
->data
;
1032 gchar
*email
= gtk_editable_get_chars(GTK_EDITABLE(attendee
->address
), 0, -1);
1033 gchar
*remail
, *user
, *domain
;
1034 gchar
*contents
= NULL
;
1036 if (*email
== '\0') {
1038 att_update_icon(meet
, attendee
, 0, NULL
);
1043 remail
= g_strdup(email
);
1045 extract_address(remail
);
1046 if (strrchr(remail
, ' '))
1047 user
= g_strdup(strrchr(remail
, ' ')+1);
1049 user
= g_strdup(remail
);
1050 if (strchr(user
, '@')) {
1051 domain
= g_strdup(strchr(user
, '@')+1);
1052 *(strchr(user
, '@')) = '\0';
1054 domain
= g_strdup("");
1057 if (change_user
&& change_dom
) {
1058 if (change_user
< change_dom
)
1059 tmp
= g_strdup_printf(real_url
, user
, domain
);
1061 tmp
= g_strdup_printf(real_url
, domain
, user
);
1062 } else if (change_user
) {
1063 tmp
= g_strdup_printf(real_url
, user
);
1064 } else if (change_dom
) {
1065 tmp
= g_strdup_printf(real_url
, domain
);
1067 tmp
= g_strdup(real_url
);
1071 debug_print("url to get %s\n", tmp
);
1074 if (attendee
->cached_contents
!= NULL
) {
1075 contents
= attendee
->cached_contents
;
1076 attendee
->cached_contents
= NULL
;
1077 } else if (!local_only
) {
1078 if (strncmp(tmp
, "http://", 7)
1079 && strncmp(tmp
, "https://", 8)
1080 && strncmp(tmp
, "webcal://", 9)
1081 && strncmp(tmp
, "webcals://", 10)
1082 && strncmp(tmp
, "ftp://", 6)
1083 && strncmp(tmp
, "ftps://", 7)
1084 && strncmp(tmp
, "sftp://", 7))
1085 contents
= file_read_to_str(tmp
);
1087 gchar
*label
= g_strdup_printf(_("Fetching planning for %s..."), email
);
1088 if (!strncmp(tmp
, "webcal", 6)) {
1089 gchar
*tmp2
= g_strdup_printf("http%s", tmp
+6);
1093 contents
= vcal_curl_read(tmp
, label
, FALSE
, NULL
);
1103 if (contents
== NULL
) {
1105 att_update_icon(meet
, attendee
, 2, _("Free/busy retrieval failed"));
1109 if (!attendee_available(attendee
, dtstart
, dtend
, contents
)) {
1111 debug_print("not available!\n");
1113 debug_print("available!\n");
1114 att_update_icon(meet
, attendee
, 1, _("Available"));
1116 attendee
->cached_contents
= contents
;
1122 res
= find_availability((dtstart
), (dtend
), attlist
, for_send
, meet
);
1127 alertpanel_notice(_("Everyone is available."));
1128 else if (!uncertain
) {
1129 gtk_image_set_from_icon_name
1130 (GTK_IMAGE(meet
->total_avail_img
),
1131 "dialog-information",
1132 GTK_ICON_SIZE_SMALL_TOOLBAR
);
1133 gtk_widget_show(meet
->total_avail_img
);
1134 gtk_label_set_text(GTK_LABEL(meet
->total_avail_msg
), _("Everyone is available."));
1135 CLAWS_SET_TIP(meet
->total_avail_evtbox
, NULL
);
1137 gtk_image_set_from_icon_name
1138 (GTK_IMAGE(meet
->total_avail_img
),
1140 GTK_ICON_SIZE_SMALL_TOOLBAR
);
1141 gtk_widget_show(meet
->total_avail_img
);
1142 gtk_label_set_text(GTK_LABEL(meet
->total_avail_msg
), _("Everyone is available."));
1143 CLAWS_SET_TIP(meet
->total_avail_evtbox
, _("Everyone seems available, but some free/busy information failed to be retrieved."));
1148 for (cur
= attlist
; cur
&& cur
->data
; cur
= cur
->next
) {
1149 VCalAttendee
*attendee
= (VCalAttendee
*)cur
->data
;
1150 g_free(attendee
->cached_contents
);
1151 attendee
->cached_contents
= NULL
;
1153 gtk_widget_set_sensitive(meet
->save_btn
, TRUE
);
1154 gtk_widget_set_sensitive(meet
->avail_btn
, avail_btn_can_be_sensitive());
1157 gdk_window_set_cursor(gdkwin
, NULL
);
1160 meet
->attendees
= g_slist_remove(meet
->attendees
, dummy_org
);
1162 g_slist_free(attlist
);
1163 gtk_widget_destroy(dummy_org
->address
);
1174 static gboolean
check_avail_cb(GtkButton
*widget
, gpointer data
)
1176 VCalMeeting
*meet
= (VCalMeeting
*)data
;
1177 check_attendees_availability(meet
, TRUE
, FALSE
);
1181 static gboolean
send_meeting_cb(GtkButton
*widget
, gpointer data
)
1183 VCalMeeting
*meet
= (VCalMeeting
*)data
;
1185 gchar
*organizer
= NULL
;
1186 gchar
*organizer_name
= NULL
;
1187 gchar
*dtstart
= NULL
;
1188 gchar
*dtend
= NULL
;
1190 gchar
*location
= NULL
;
1191 gchar
*summary
= NULL
;
1192 gchar
*description
= NULL
;
1193 VCalEvent
*event
= NULL
;
1195 PrefsAccount
*account
= NULL
;
1196 gboolean res
= FALSE
;
1197 gboolean found_att
= FALSE
;
1198 Folder
*folder
= folder_find_from_name (PLUGIN_NAME
, vcal_folder_get_class());
1199 gboolean redisp
= FALSE
;
1202 if (meet
->uid
== NULL
&& meet
->visible
&&
1203 !check_attendees_availability(meet
, FALSE
, TRUE
)) {
1208 MainWindow
*mainwin
= mainwindow_get_mainwindow();
1209 if (mainwin
->summaryview
->folder_item
== folder
->inbox
) {
1211 summary_show(mainwin
->summaryview
, NULL
, FALSE
);
1214 gtk_widget_set_sensitive(meet
->save_btn
, FALSE
);
1215 gtk_widget_set_sensitive(meet
->avail_btn
, FALSE
);
1217 gdkwin
= gtk_widget_get_window(meet
->window
);
1218 if (gdkwin
!= NULL
) {
1219 set_watch_cursor(gdkwin
);
1220 gdk_window_set_cursor(gdkwin
, watch_cursor
);
1223 organizer
= get_organizer(meet
);
1224 account
= account_find_from_address(organizer
, FALSE
);
1226 if(account
== NULL
) {
1227 debug_print("can't get account from address %s\n", organizer
);
1232 organizer_name
= get_organizer_name(meet
);
1235 uid
= g_strdup(meet
->uid
);
1237 uid
= prefs_account_generate_msgid(account
);
1240 dtstart
= get_date(meet
, TRUE
);
1241 dtend
= get_date(meet
, FALSE
);
1242 location
= get_location(meet
);
1243 summary
= get_summary(meet
);
1244 description
= get_description(meet
);
1246 event
= vcal_manager_new_event(uid
, organizer
, organizer_name
, location
, summary
, description
,
1247 dtstart
, dtend
, NULL
, tzid
, NULL
, meet
->method
,
1249 ICAL_VEVENT_COMPONENT
);
1251 vcal_manager_update_answer(event
, organizer
, organizer_name
,
1252 ICAL_PARTSTAT_ACCEPTED
,
1253 ICAL_CUTYPE_INDIVIDUAL
);
1255 for (cur
= meet
->attendees
; cur
&& cur
->data
; cur
= cur
->next
) {
1256 VCalAttendee
*attendee
= (VCalAttendee
*)cur
->data
;
1257 gchar
*email
= gtk_editable_get_chars(GTK_EDITABLE(attendee
->address
), 0, -1);
1259 gchar
*orig_email
= email
;
1261 enum icalparameter_cutype cutype
= ICAL_CUTYPE_INDIVIDUAL
;
1262 enum icalparameter_partstat status
= ICAL_PARTSTAT_NEEDSACTION
;
1264 index
= gtk_combo_box_get_active(GTK_COMBO_BOX(attendee
->cutype
));
1266 cutype
= ICAL_CUTYPE_INDIVIDUAL
+ index
;
1267 if (attendee
->status
) {
1268 if(!strcmp(attendee
->status
, "accepted"))
1269 status
= ICAL_PARTSTAT_ACCEPTED
;
1270 if(!strcmp(attendee
->status
, "tentatively accepted"))
1271 status
= ICAL_PARTSTAT_TENTATIVE
;
1272 if(!strcmp(attendee
->status
, "declined"))
1273 status
= ICAL_PARTSTAT_DECLINED
;
1274 g_free(attendee
->status
);
1276 if (strlen(email
)) {
1277 if (strstr(email
, " <")) {
1279 email
= strstr(email
," <") + 2;
1280 *(strstr(name
," <")) = '\0';
1281 if (strstr(email
, ">"))
1282 *(strstr(email
, ">")) = '\0';
1285 vcal_manager_update_answer(event
, email
, name
,
1288 found_att
= strcmp(email
, organizer
);
1294 res
= vcal_manager_request(account
, event
);
1299 g_free(organizer_name
);
1302 g_free(description
);
1305 vcal_manager_free_event(event
);
1307 gtk_widget_set_sensitive(meet
->save_btn
, TRUE
);
1308 gtk_widget_set_sensitive(meet
->avail_btn
, avail_btn_can_be_sensitive());
1310 gdk_window_set_cursor(gdkwin
, NULL
);
1315 alertpanel_error(_("Could not send the meeting invitation.\n"
1316 "Check the recipients."));
1320 folder_item_scan(folder
->inbox
);
1322 if (folder
&& redisp
) {
1323 MainWindow
*mainwin
= mainwindow_get_mainwindow();
1324 summary_show(mainwin
->summaryview
, folder
->inbox
, FALSE
);
1330 static VCalMeeting
*vcal_meeting_create_real(VCalEvent
*event
, gboolean visible
)
1332 VCalMeeting
*meet
= g_new0(VCalMeeting
, 1);
1333 GtkTextBuffer
*buffer
= NULL
;
1334 GtkWidget
*date_hbox
, *date_vbox
, *save_hbox
, *label
, *hbox
;
1337 GtkWidget
*scrolledwin
;
1340 GtkWidget
*notebook
;
1341 GtkWidget
*maemo_vbox0
;
1344 meet
->visible
= visible
;
1346 meet
->window
= gtkut_window_new(GTK_WINDOW_TOPLEVEL
, "vcal_meeting_gtk");
1347 #ifndef GENERIC_UMPC
1348 meet
->table
= gtk_grid_new();
1350 meet
->table1
= gtk_grid_new();
1351 meet
->table2
= gtk_grid_new();
1353 meet
->who
= gtk_combo_box_text_new();
1355 meet
->start_c
= gtk_calendar_new();
1356 meet
->end_c
= gtk_calendar_new();
1358 meet
->avail_evtbox
= gtk_event_box_new();
1359 meet
->avail_img
= gtk_image_new_from_icon_name
1360 ("dialog-warning", GTK_ICON_SIZE_SMALL_TOOLBAR
);
1362 meet
->start_time
= gtkut_time_select_combo_new();
1364 meet
->end_time
= gtkut_time_select_combo_new();
1366 meet
->location
= gtk_entry_new();
1367 meet
->summary
= gtk_entry_new();
1368 meet
->description
= gtk_text_view_new();
1369 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(meet
->description
));
1370 gtk_text_view_set_editable(GTK_TEXT_VIEW(meet
->description
), TRUE
);
1371 gtk_text_buffer_add_selection_clipboard(buffer
, gtk_clipboard_get(GDK_SELECTION_PRIMARY
));
1373 scrolledwin
= gtk_scrolled_window_new(NULL
, NULL
);
1374 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin
),
1375 GTK_POLICY_AUTOMATIC
,
1376 GTK_POLICY_AUTOMATIC
);
1377 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin
),
1379 gtk_container_add(GTK_CONTAINER(scrolledwin
), meet
->description
);
1382 meet
->uid
= g_strdup(event
->uid
);
1383 meet
->sequence
= event
->sequence
+ 1;
1384 meet
->method
= (event
->method
== ICAL_METHOD_CANCEL
?
1385 ICAL_METHOD_CANCEL
:ICAL_METHOD_REQUEST
);
1387 gtk_entry_set_text(GTK_ENTRY(meet
->location
), event
->location
);
1388 gtk_entry_set_text(GTK_ENTRY(meet
->summary
), event
->summary
);
1389 gtk_text_buffer_set_text(buffer
, event
->description
, -1);
1391 meet
->method
= ICAL_METHOD_REQUEST
;
1393 meet
->save_btn
= gtk_button_new_with_label(_("Save & Send"));
1394 meet
->avail_btn
= gtk_button_new_with_label(_("Check availability"));
1396 meet
->total_avail_evtbox
= gtk_event_box_new();
1397 meet
->total_avail_img
= gtk_image_new_from_icon_name
1398 ("dialog-warning", GTK_ICON_SIZE_SMALL_TOOLBAR
);
1399 meet
->total_avail_msg
= gtk_label_new("");
1401 gtk_widget_set_size_request(meet
->total_avail_evtbox
, 18, 16);
1402 gtk_event_box_set_visible_window(GTK_EVENT_BOX(meet
->total_avail_evtbox
), FALSE
);
1403 gtk_container_add (GTK_CONTAINER(meet
->total_avail_evtbox
), meet
->total_avail_img
);
1405 g_signal_connect(G_OBJECT(meet
->save_btn
), "clicked",
1406 G_CALLBACK(send_meeting_cb
), meet
);
1408 g_signal_connect(G_OBJECT(meet
->avail_btn
), "clicked",
1409 G_CALLBACK(check_avail_cb
), meet
);
1411 g_signal_connect(G_OBJECT(meet
->window
), "destroy",
1412 G_CALLBACK(destroy_meeting_cb
), meet
);
1413 g_signal_connect(G_OBJECT(meet
->window
), "key_press_event",
1414 G_CALLBACK(meeting_key_pressed
), meet
);
1417 gtk_widget_set_size_request(meet
->description
, -1, 100);
1418 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(meet
->description
), GTK_WRAP_WORD
);
1420 if (!event
|| (event
&& !event
->dtstart
&& !event
->dtend
)) {
1421 time_t t
= time (NULL
)+ 3600;
1422 struct tm buft1
, buft2
;
1423 struct tm
*lt
= localtime_r (&t
, &buft1
);
1425 gtk_calendar_select_day(GTK_CALENDAR(meet
->start_c
),
1427 gtk_calendar_select_month(GTK_CALENDAR(meet
->start_c
),
1428 lt
->tm_mon
, lt
->tm_year
+ 1900);
1430 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->start_time
), lt
->tm_hour
, 0);
1433 lt
= localtime_r(&t
, &buft2
);
1435 gtk_calendar_select_day(GTK_CALENDAR(meet
->end_c
),
1437 gtk_calendar_select_month(GTK_CALENDAR(meet
->end_c
),
1438 lt
->tm_mon
, lt
->tm_year
+ 1900);
1440 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->end_time
), lt
->tm_hour
, 0);
1442 gtk_calendar_select_day(GTK_CALENDAR(meet
->start_c
),
1443 get_dtdate(event
->dtstart
, DAY
));
1444 gtk_calendar_select_day(GTK_CALENDAR(meet
->end_c
),
1445 get_dtdate(event
->dtend
, DAY
));
1447 gtk_calendar_select_month(GTK_CALENDAR(meet
->start_c
),
1448 get_dtdate(event
->dtstart
, MONTH
)-1,
1449 get_dtdate(event
->dtstart
, YEAR
));
1450 gtk_calendar_select_month(GTK_CALENDAR(meet
->end_c
),
1451 get_dtdate(event
->dtend
, MONTH
)-1,
1452 get_dtdate(event
->dtend
, YEAR
));
1454 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->start_time
),
1455 get_dtdate(event
->dtstart
, HOUR
),
1456 get_dtdate(event
->dtstart
, MINUTE
));
1458 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->end_time
),
1459 get_dtdate(event
->dtend
, HOUR
),
1460 get_dtdate(event
->dtend
, MINUTE
));
1463 g_signal_connect(G_OBJECT(meet
->start_c
), "day-selected",
1464 G_CALLBACK(meeting_start_changed
), meet
);
1465 g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN(meet
->start_time
))),
1467 G_CALLBACK(meeting_start_changed
),
1470 g_signal_connect(G_OBJECT(meet
->end_c
), "day-selected",
1471 G_CALLBACK(meeting_end_changed
), meet
);
1472 g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN(meet
->end_time
))),
1474 G_CALLBACK(meeting_end_changed
),
1477 #ifndef GENERIC_UMPC
1478 gtk_widget_set_size_request(meet
->start_time
, 80, -1);
1479 gtk_widget_set_size_request(meet
->end_time
, 80, -1);
1481 gtk_widget_set_size_request(meet
->start_time
, 120, -1);
1482 gtk_widget_set_size_request(meet
->end_time
, 120, -1);
1485 date_hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 6);
1486 date_vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 6);
1487 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 6);
1488 label
= gtk_label_new(g_strconcat("<b>",_("Starts at:"),"</b> ",NULL
));
1489 gtk_label_set_xalign(GTK_LABEL(label
), 0.0);
1490 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1492 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
1493 gtk_box_pack_start(GTK_BOX(hbox
), meet
->start_time
, FALSE
, FALSE
, 0);
1494 label
= gtk_label_new(g_strconcat("<b> ",_("on:"),"</b>",NULL
));
1495 gtk_label_set_xalign(GTK_LABEL(label
), 0.0);
1496 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1497 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
1498 gtk_box_pack_start(GTK_BOX(date_vbox
), hbox
, FALSE
, FALSE
, 0);
1499 gtk_box_pack_start(GTK_BOX(date_vbox
), meet
->start_c
, FALSE
, FALSE
, 0);
1500 gtk_box_pack_start(GTK_BOX(date_hbox
), date_vbox
, FALSE
, FALSE
, 0);
1502 #ifndef GENERIC_UMPC
1503 label
= gtk_label_new(" ");
1505 label
= gtk_label_new("");
1507 gtk_label_set_xalign(GTK_LABEL(label
), 0.0);
1508 gtk_box_pack_start(GTK_BOX(date_hbox
), label
, TRUE
, TRUE
, 0);
1510 date_vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 6);
1511 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 6);
1512 label
= gtk_label_new(g_strconcat("<b>",_("Ends at:"),"</b> ", NULL
));
1513 gtk_label_set_xalign(GTK_LABEL(label
), 0.0);
1514 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1516 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
1517 gtk_box_pack_start(GTK_BOX(hbox
), meet
->end_time
, FALSE
, FALSE
, 0);
1518 label
= gtk_label_new(g_strconcat("<b> ",_("on:"),"</b>",NULL
));
1519 gtk_label_set_xalign(GTK_LABEL(label
), 0.0);
1520 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1521 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
1522 gtk_box_pack_start(GTK_BOX(date_vbox
), hbox
, FALSE
, FALSE
, 0);
1523 gtk_box_pack_start(GTK_BOX(date_vbox
), meet
->end_c
, FALSE
, FALSE
, 0);
1524 gtk_box_pack_start(GTK_BOX(date_hbox
), date_vbox
, FALSE
, FALSE
, 0);
1526 meet
->attendees_vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 6);
1527 gtk_widget_show_all(meet
->attendees_vbox
);
1529 attendee_add(meet
, NULL
, NULL
, NULL
, NULL
, TRUE
);
1531 gboolean firstadd
= TRUE
;
1532 GSList
*list
= vcal_manager_get_answers_emails(event
);
1533 while (list
&& list
->data
) {
1534 gchar
*address
= (gchar
*)list
->data
;
1535 gchar
*name
= vcal_manager_get_attendee_name(event
, address
);
1536 gchar
*answer
= vcal_manager_get_reply_text_for_attendee(event
, address
);
1537 gchar
*type
= vcal_manager_get_cutype_text_for_attendee(event
, address
);
1538 if (strcmp(event
->organizer
, address
)) {
1539 attendee_add(meet
, address
, name
, answer
, type
, firstadd
);
1548 if (firstadd
== TRUE
)
1549 attendee_add(meet
, NULL
, NULL
, NULL
, NULL
, TRUE
);
1553 gtk_window_set_title(GTK_WINDOW(meet
->window
), _("New meeting"));
1555 gchar
*title
= g_strdup_printf(_("%s - Edit meeting"),
1557 gtk_window_set_title(GTK_WINDOW(meet
->window
), title
);
1560 address_completion_start(meet
->window
);
1562 accounts
= account_get_list();
1563 g_return_val_if_fail(accounts
!= NULL
, NULL
);
1565 for (i
= 0; accounts
!= NULL
; accounts
= accounts
->next
) {
1566 PrefsAccount
*ac
= (PrefsAccount
*)accounts
->data
;
1568 if (ac
->protocol
== A_NNTP
) {
1571 if (!event
&& ac
== account_get_cur_account()) {
1574 else if (event
&& !strcmp(ac
->address
, event
->organizer
))
1577 meet
->avail_accounts
= g_slist_append(meet
->avail_accounts
, ac
);
1580 s
= g_strdup_printf("%s: %s <%s>",
1582 ac
->name
, ac
->address
);
1584 s
= g_strdup_printf("%s: %s",
1585 ac
->account_name
, ac
->address
);
1587 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(meet
->who
), s
);
1591 gtk_combo_box_set_active(GTK_COMBO_BOX(meet
->who
), num
);
1593 save_hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 6);
1594 gtk_box_pack_start(GTK_BOX(save_hbox
), meet
->save_btn
, FALSE
, FALSE
, 0);
1595 gtk_box_pack_start(GTK_BOX(save_hbox
), meet
->avail_btn
, FALSE
, FALSE
, 0);
1596 gtk_box_pack_start(GTK_BOX(save_hbox
), meet
->total_avail_evtbox
, FALSE
, FALSE
, 0);
1597 gtk_box_pack_start(GTK_BOX(save_hbox
), meet
->total_avail_msg
, FALSE
, FALSE
, 0);
1599 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 6);
1600 gtk_box_pack_start(GTK_BOX(hbox
), meet
->avail_evtbox
, FALSE
, FALSE
, 0);
1601 gtk_box_pack_start(GTK_BOX(hbox
), meet
->who
, TRUE
, TRUE
, 0);
1603 gtk_widget_set_size_request(meet
->avail_evtbox
, 18, 16);
1604 gtk_event_box_set_visible_window(GTK_EVENT_BOX(meet
->avail_evtbox
), FALSE
);
1605 gtk_container_add (GTK_CONTAINER(meet
->avail_evtbox
), meet
->avail_img
);
1607 #ifndef GENERIC_UMPC
1608 TABLE_ADD_LINE(_("Organizer:"), hbox
, FALSE
);
1609 TABLE_ADD_LINE(_("Summary:"), meet
->summary
, TRUE
);
1610 TABLE_ADD_LINE(_("Time:"), date_hbox
, TRUE
);
1611 TABLE_ADD_LINE(_("Location:"), meet
->location
, TRUE
);
1612 TABLE_ADD_LINE(_("Description:"), scrolledwin
, TRUE
);
1613 TABLE_ADD_LINE(_("Attendees:"), meet
->attendees_vbox
, FALSE
);
1614 TABLE_ADD_LINE("", save_hbox
, TRUE
);
1616 gtk_widget_set_size_request(meet
->window
, -1, -1);
1617 gtk_container_add(GTK_CONTAINER(meet
->window
), meet
->table
);
1619 TABLE_ADD_LINE(_("Organizer:"), hbox
, FALSE
, TRUE
);
1620 TABLE_ADD_LINE(_("Summary:"), meet
->summary
, TRUE
, TRUE
);
1621 TABLE_ADD_LINE(_("Location:"), meet
->location
, FALSE
, TRUE
);
1622 TABLE_ADD_LINE(_("Description:"), scrolledwin
, TRUE
, TRUE
);
1623 TABLE_ADD_LINE(_("Attendees:"), meet
->attendees_vbox
, FALSE
, TRUE
);
1624 TABLE_ADD_LINE("", date_hbox
, TRUE
, FALSE
);
1626 notebook
= gtk_notebook_new ();
1627 gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook
), FALSE
);
1628 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
),
1630 gtk_label_new_with_mnemonic(_("Event:")));
1632 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
),
1634 gtk_label_new_with_mnemonic(_("Time:")));
1635 gtk_widget_show (notebook
);
1637 maemo_vbox0
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 3);
1638 gtk_box_pack_start(GTK_BOX(maemo_vbox0
), notebook
, TRUE
, TRUE
, 0);
1639 gtk_box_pack_start(GTK_BOX(maemo_vbox0
), save_hbox
, FALSE
, FALSE
, 0);
1641 gtk_widget_set_size_request(meet
->window
, -1, -1);
1642 gtk_container_add (GTK_CONTAINER (meet
->window
), maemo_vbox0
);
1644 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(meet
->window
));
1648 gtk_widget_show_all(meet
->window
);
1649 for (cur
= meet
->attendees
; cur
; cur
= cur
->next
) {
1650 gtk_widget_hide(((VCalAttendee
*)cur
->data
)->avail_img
);
1652 gtk_widget_hide(meet
->avail_img
);
1653 gtk_widget_hide(meet
->total_avail_img
);
1654 gtk_widget_set_sensitive(meet
->avail_btn
, avail_btn_can_be_sensitive());
1660 VCalMeeting
*vcal_meeting_create(VCalEvent
*event
)
1662 return vcal_meeting_create_real(event
, TRUE
);
1665 VCalMeeting
*vcal_meeting_create_with_start(VCalEvent
*event
, struct tm
*sdate
)
1667 VCalMeeting
*meet
= vcal_meeting_create(event
);
1669 gtk_calendar_select_day(GTK_CALENDAR(meet
->start_c
),
1671 gtk_calendar_select_day(GTK_CALENDAR(meet
->end_c
),
1674 gtk_calendar_select_month(GTK_CALENDAR(meet
->start_c
),
1675 sdate
->tm_mon
, sdate
->tm_year
+1900);
1676 gtk_calendar_select_month(GTK_CALENDAR(meet
->end_c
),
1677 sdate
->tm_mon
, sdate
->tm_year
+1900);
1679 if (sdate
->tm_hour
!= 0) {
1680 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->start_time
), sdate
->tm_hour
, 0);
1682 if (sdate
->tm_hour
< 23) {
1683 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->end_time
), sdate
->tm_hour
+1, 0);
1685 struct tm tm_tomorrow
;
1687 tm_tomorrow
.tm_mday
= sdate
->tm_mday
;
1688 tm_tomorrow
.tm_mon
= sdate
->tm_mon
;
1689 tm_tomorrow
.tm_wday
= sdate
->tm_wday
;
1690 tm_tomorrow
.tm_year
= sdate
->tm_year
+1900;
1691 tm_tomorrow
.tm_hour
= sdate
->tm_hour
;
1692 orage_move_day(&tm_tomorrow
, +1);
1693 gtk_calendar_select_day(GTK_CALENDAR(meet
->end_c
),
1694 tm_tomorrow
.tm_mday
);
1695 gtk_calendar_select_month(GTK_CALENDAR(meet
->end_c
),
1696 tm_tomorrow
.tm_mon
, tm_tomorrow
.tm_year
);
1698 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->end_time
), 0, 0);
1704 VCalMeeting
*vcal_meeting_create_hidden(VCalEvent
*event
)
1706 return vcal_meeting_create_real(event
, FALSE
);
1709 gboolean
vcal_meeting_send(VCalMeeting
*meet
)
1711 return send_meeting_cb(NULL
, meet
);
1714 gboolean
vcal_meeting_alert_check(gpointer data
)
1716 GSList
*events
= NULL
, *cur
= NULL
;
1718 if (!vcalprefs
.alert_enable
)
1721 events
= vcal_folder_get_waiting_events();
1723 for (cur
= events
; cur
; cur
= cur
->next
) {
1724 VCalEvent
*event
= (VCalEvent
*)cur
->data
;
1725 time_t start
, end
, current
;
1726 gboolean warn
= FALSE
;
1730 start
= icaltime_as_timet(icaltime_from_string(event
->dtstart
));
1731 end
= icaltime_as_timet(icaltime_from_string(event
->dtend
));
1732 current
= time(NULL
);
1734 if (start
- current
<= (vcalprefs
.alert_delay
*60)
1735 && start
- current
+ 60 > (vcalprefs
.alert_delay
*60)) {
1737 } else if (event
->postponed
- current
<= (vcalprefs
.alert_delay
*60)
1738 && event
->postponed
- current
+ 60 > (vcalprefs
.alert_delay
*60)) {
1742 time_t tmpt
= icaltime_as_timet((icaltime_from_string(event
->dtstart
)));
1743 gchar
*estart
= NULL
;
1745 int length
= (end
- start
) / 60;
1746 gchar
*duration
= NULL
, *hours
= NULL
, *minutes
= NULL
;
1747 gchar
*message
= NULL
;
1748 gchar
*title
= NULL
;
1749 gchar
*label
= NULL
;
1750 int postpone_min
= 0;
1754 estart
= g_strdup(ctime(&tmpt
));
1757 hours
= g_strdup_printf(ngettext("%d hour", "%d hours",
1758 (length
/60) > 1 ? 2 : 1), length
/60);
1760 minutes
= g_strdup_printf(ngettext("%d minute", "%d minutes",
1761 length
%60), length
%60);
1763 duration
= g_strdup_printf("%s%s%s",
1765 hours
&& minutes
? " ":"",
1766 minutes
?minutes
:"");
1771 title
= g_strdup_printf(_("Upcoming event: %s"), event
->summary
);
1772 message
= g_strdup_printf(_("You have a meeting or event soon.\n"
1773 "It starts at %s and ends %s later.\n"
1775 "More information:\n\n"
1779 event
->location
?event
->location
:"",
1780 event
->description
);
1785 postpone_min
= (vcalprefs
.alert_delay
/2 > 15) ? 15: (vcalprefs
.alert_delay
/2);
1786 if (postpone_min
== 0)
1789 label
= g_strdup_printf(ngettext("Remind me in %d minute", "Remind me in %d minutes",
1790 postpone_min
> 1 ? 2:1),
1792 aval
= alertpanel_full(title
, message
,
1793 NULL
, label
, NULL
, _("_OK"), NULL
, NULL
,
1794 ALERTFOCUS_FIRST
, FALSE
, NULL
, ALERT_NOTICE
);
1800 if (aval
== G_ALERTDEFAULT
) {
1801 if (event
->postponed
== 0)
1802 event
->postponed
= start
+ (postpone_min
*60);
1804 event
->postponed
+= (postpone_min
*60);
1806 event
->postponed
= (time_t)0;
1808 vcal_manager_save_event(event
, FALSE
);
1811 vcal_manager_free_event((VCalEvent
*)cur
->data
);
1814 g_slist_free(events
);
1819 void multisync_export(void)
1821 GSList
*list
= NULL
;
1822 gchar
*path
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
1823 "vcalendar", G_DIR_SEPARATOR_S
,
1825 GSList
*files
= NULL
;
1829 icalcomponent
*calendar
= NULL
;
1832 if (is_dir_exist(path
) && remove_dir_recursive(path
) < 0) {
1836 if (make_dir(path
) != 0) {
1841 list
= vcal_folder_get_waiting_events();
1842 for (cur
= list
; cur
; cur
= cur
->next
) {
1844 VCalEvent
*event
= (VCalEvent
*)cur
->data
;
1845 gchar
*file
= g_strdup_printf("multisync%"CM_TIME_FORMAT
"-%d",
1851 icalcomponent_vanew(
1852 ICAL_VCALENDAR_COMPONENT
,
1853 icalproperty_new_version("2.0"),
1854 icalproperty_new_prodid(
1855 "-//Claws Mail//NONSGML Claws Mail Calendar//EN"),
1856 icalproperty_new_calscale("GREGORIAN"),
1859 vcal_manager_event_dump(event
, FALSE
, FALSE
, calendar
, FALSE
);
1860 tmp
= g_strconcat(path
, G_DIR_SEPARATOR_S
, file
, NULL
);
1861 str_write_to_file(icalcomponent_as_ical_string(calendar
), tmp
, TRUE
);
1863 files
= g_slist_append(files
, file
);
1864 vcal_manager_free_event(event
);
1865 icalcomponent_free(calendar
);
1870 backup_file
= g_strconcat(path
, G_DIR_SEPARATOR_S
, "backup_entries", NULL
);
1871 fp
= claws_fopen(backup_file
, "wb");
1873 for (cur
= files
; cur
; cur
= cur
->next
) {
1874 gchar
* file
= (char *)cur
->data
;
1875 if (fprintf(fp
, "1 1 %s\n", file
) < 0)
1876 FILE_OP_ERROR(file
, "fprintf");
1879 if (claws_safe_fclose(fp
) == EOF
)
1880 FILE_OP_ERROR(backup_file
, "claws_fclose");
1882 FILE_OP_ERROR(backup_file
, "claws_fopen");
1884 g_free(backup_file
);
1886 g_slist_free(files
);
1889 gboolean
vcal_meeting_export_calendar(const gchar
*path
,
1890 const gchar
*user
, const gchar
*pass
,
1893 GSList
*list
= vcal_folder_get_waiting_events();
1894 GSList
*subs
= NULL
;
1896 icalcomponent
*calendar
= NULL
;
1898 gchar
*tmpfile
= get_tmp_file();
1899 gchar
*internal_file
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
1900 "vcalendar", G_DIR_SEPARATOR_S
,
1901 "internal.ics", NULL
);
1903 gboolean res
= TRUE
;
1908 if (vcalprefs
.export_subs
&& vcalprefs
.export_enable
)
1909 subs
= vcal_folder_get_webcal_events();
1911 if (g_slist_length(list
) == 0 && g_slist_length(subs
) == 0) {
1915 alertpanel_full(_("Empty calendar"),
1916 _("There is nothing to export."),
1917 NULL
, _("_OK"), NULL
, NULL
, NULL
, NULL
,
1918 ALERTFOCUS_FIRST
, FALSE
, NULL
, ALERT_NOTICE
);
1920 g_free(internal_file
);
1923 str_write_to_file("", tmpfile
, TRUE
);
1929 icalcomponent_vanew(
1930 ICAL_VCALENDAR_COMPONENT
,
1931 icalproperty_new_version("2.0"),
1932 icalproperty_new_prodid(
1933 "-//Claws Mail//NONSGML Claws Mail Calendar//EN"),
1934 icalproperty_new_calscale("GREGORIAN"),
1938 for (cur
= list
; cur
; cur
= cur
->next
) {
1939 VCalEvent
*event
= (VCalEvent
*)cur
->data
;
1940 vcal_manager_event_dump(event
, FALSE
, FALSE
, calendar
, FALSE
);
1941 vcal_manager_free_event(event
);
1944 if (str_write_to_file(icalcomponent_as_ical_string(calendar
), internal_file
, TRUE
) < 0) {
1945 g_warning("can't export internal cal");
1948 for (cur
= subs
; cur
; cur
= cur
->next
) {
1949 /* Not to be freed */
1950 icalcomponent
*event
= (icalcomponent
*)cur
->data
;
1951 vcal_manager_icalevent_dump(event
, NULL
, calendar
);
1954 if (vcalprefs
.export_enable
|| path
== NULL
) {
1955 if (str_write_to_file(icalcomponent_as_ical_string(calendar
), tmpfile
, TRUE
) < 0) {
1956 alertpanel_error(_("Could not export the calendar."));
1958 icalcomponent_free(calendar
);
1963 filesize
= strlen(icalcomponent_as_ical_string(calendar
));
1966 icalcomponent_free(calendar
);
1969 g_free(internal_file
);
1973 if (automatic
&& (!path
|| strlen(path
) == 0 || !vcalprefs
.export_enable
)) {
1978 if (!path
&& !automatic
)
1979 file
= filesel_select_file_save(_("Export calendar to ICS"), NULL
);
1981 file
= g_strdup(path
);
1984 && strncmp(file
, "http://", 7)
1985 && strncmp(file
, "https://", 8)
1986 && strncmp(file
, "webcal://", 9)
1987 && strncmp(file
, "webcals://", 10)
1988 && strncmp(file
, "ftp://", 6)) {
1990 if (file
[0] != G_DIR_SEPARATOR
)
1991 afile
= g_strdup_printf("%s%s%s", get_home_dir(),
1992 G_DIR_SEPARATOR_S
, file
);
1994 afile
= g_strdup(file
);
1995 if (move_file(tmpfile
, afile
, TRUE
) != 0) {
1996 log_error(LOG_PROTOCOL
, _("Couldn't export calendar to '%s'\n"),
2002 FILE *fp
= claws_fopen(tmpfile
, "rb");
2003 if (!strncmp(file
, "webcal", 6)) {
2004 gchar
*tmp
= g_strdup_printf("http%s", file
+6);
2009 res
= vcal_curl_put(file
, fp
, filesize
, user
, (pass
!= NULL
? pass
: ""));
2019 gboolean
vcal_meeting_export_freebusy(const gchar
*path
, const gchar
*user
,
2022 GSList
*list
= vcal_folder_get_waiting_events();
2024 icalcomponent
*calendar
= NULL
, *timezone
= NULL
, *tzc
= NULL
, *vfreebusy
= NULL
;
2026 gchar
*tmpfile
= get_tmp_file();
2027 gchar
*internal_file
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
2028 "vcalendar", G_DIR_SEPARATOR_S
,
2029 "internal.ifb", NULL
);
2030 time_t whole_start
= time(NULL
);
2031 time_t whole_end
= whole_start
+ (60*60*24*365);
2032 gboolean res
= TRUE
;
2033 struct icaltimetype itt_start
, itt_end
;
2039 icalcomponent_vanew(
2040 ICAL_VCALENDAR_COMPONENT
,
2041 icalproperty_new_version("2.0"),
2042 icalproperty_new_prodid(
2043 "-//Claws Mail//NONSGML Claws Mail Calendar//EN"),
2044 icalproperty_new_calscale("GREGORIAN"),
2048 timezone
= icalcomponent_new(ICAL_VTIMEZONE_COMPONENT
);
2050 icalcomponent_add_property(timezone
,
2051 icalproperty_new_tzid("UTC"));
2053 tzc
= icalcomponent_new(ICAL_XSTANDARD_COMPONENT
);
2054 icalcomponent_add_property(tzc
,
2055 icalproperty_new_dtstart(
2056 icaltime_from_string("19700101T000000")));
2057 icalcomponent_add_property(tzc
,
2058 icalproperty_new_tzoffsetfrom(0.0));
2059 icalcomponent_add_property(tzc
,
2060 icalproperty_new_tzoffsetto(0.0));
2061 icalcomponent_add_property(tzc
,
2062 icalproperty_new_tzname("Greenwich meridian time"));
2064 icalcomponent_add_component(timezone
, tzc
);
2066 icalcomponent_add_component(calendar
, timezone
);
2068 itt_start
= icaltime_from_timet_with_zone(whole_start
, FALSE
, NULL
);
2069 itt_end
= icaltime_from_timet_with_zone(whole_end
, FALSE
, NULL
);
2070 itt_start
.second
= itt_start
.minute
= itt_start
.hour
= 0;
2071 itt_end
.second
= 59; itt_end
.minute
= 59; itt_end
.hour
= 23;
2075 icalcomponent_vanew(
2076 ICAL_VFREEBUSY_COMPONENT
,
2077 icalproperty_vanew_dtstart(itt_start
, 0),
2078 icalproperty_vanew_dtend(itt_end
, 0),
2082 debug_print("DTSTART:%s\nDTEND:%s\n",
2083 icaltime_as_ical_string(itt_start
),
2084 icaltime_as_ical_string(itt_end
));
2086 for (cur
= list
; cur
; cur
= cur
->next
) {
2087 VCalEvent
*event
= (VCalEvent
*)cur
->data
;
2089 struct icalperiodtype ipt
;
2091 ipt
.start
= icaltime_from_string(event
->dtstart
);
2092 ipt
.end
= icaltime_from_string(event
->dtend
);
2093 ipt
.duration
= icaltime_subtract(ipt
.end
, ipt
.start
);
2094 if (icaltime_as_timet(ipt
.start
) <= icaltime_as_timet(itt_end
)
2095 && icaltime_as_timet(ipt
.end
) >= icaltime_as_timet(itt_start
)) {
2096 prop
= icalproperty_new_freebusy(ipt
);
2097 icalcomponent_add_property(vfreebusy
, prop
);
2099 vcal_manager_free_event(event
);
2102 icalcomponent_add_component(calendar
, vfreebusy
);
2104 if (str_write_to_file(icalcomponent_as_ical_string(calendar
), internal_file
, TRUE
) < 0) {
2105 g_warning("can't export freebusy");
2108 g_free(internal_file
);
2110 if (vcalprefs
.export_freebusy_enable
) {
2111 if (str_write_to_file(icalcomponent_as_ical_string(calendar
), tmpfile
, TRUE
) < 0) {
2112 alertpanel_error(_("Could not export the freebusy info."));
2114 icalcomponent_free(calendar
);
2118 filesize
= strlen(icalcomponent_as_ical_string(calendar
));
2121 icalcomponent_free(calendar
);
2124 if ((!path
|| strlen(path
) == 0 || !vcalprefs
.export_freebusy_enable
)) {
2129 file
= g_strdup(path
);
2132 && strncmp(file
, "http://", 7)
2133 && strncmp(file
, "https://", 8)
2134 && strncmp(file
, "webcal://", 9)
2135 && strncmp(file
, "webcals://", 10)
2136 && strncmp(file
, "ftp://", 6)) {
2138 if (file
[0] != G_DIR_SEPARATOR
)
2139 afile
= g_strdup_printf("%s%s%s", get_home_dir(),
2140 G_DIR_SEPARATOR_S
, file
);
2142 afile
= g_strdup(file
);
2143 if (move_file(tmpfile
, file
, TRUE
) != 0) {
2144 log_error(LOG_PROTOCOL
, _("Couldn't export free/busy to '%s'\n"),
2150 FILE *fp
= claws_fopen(tmpfile
, "rb");
2151 if (!strncmp(file
, "webcal", 6)) {
2152 gchar
*tmp
= g_strdup_printf("http%s", file
+6);
2157 res
= vcal_curl_put(file
, fp
, filesize
, user
, (pass
!= NULL
? pass
: ""));