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
;
96 struct _VCalAttendee
{
98 GtkWidget
*remove_btn
;
104 GtkWidget
*avail_evtbox
;
105 GtkWidget
*avail_img
;
106 gchar
*cached_contents
;
110 static GdkCursor
*watch_cursor
= NULL
;
112 VCalAttendee
*attendee_add(VCalMeeting
*meet
, gchar
*address
, gchar
*name
, gchar
*partstat
, gchar
*cutype
, gboolean first
);
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; \
122 spacer = gtk_label_new(""); \
123 gtk_widget_set_size_request(spacer, 18, 16); \
124 s_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 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); \
129 label = gtk_label_new(tmpstr); \
131 gtk_label_set_use_markup (GTK_LABEL (label), TRUE); \
132 gtk_label_set_xalign (GTK_LABEL(label), 1.0); \
133 gtk_grid_attach(GTK_GRID(meet->table), label, 0, i, 1, 1); \
134 gtk_grid_attach(GTK_GRID(meet->table), do_space?s_hbox:widget, \
136 gtk_widget_set_hexpand(do_space?s_hbox:widget, TRUE); \
137 gtk_widget_set_halign(do_space?s_hbox:widget, GTK_ALIGN_FILL); \
138 if (GTK_IS_LABEL(widget)) { \
139 gtk_label_set_use_markup(GTK_LABEL (widget), TRUE); \
140 gtk_label_set_xalign(GTK_LABEL(widget), 0.0); \
141 gtk_label_set_yalign(GTK_LABEL(widget), 0.0); \
142 gtk_label_set_line_wrap(GTK_LABEL(widget), TRUE); \
146 gtk_grid_attach(GTK_GRID(meet->table), do_space?s_hbox:widget, \
148 gtk_widget_set_hexpand(do_space?s_hbox:widget, TRUE); \
149 gtk_widget_set_halign(do_space?s_hbox:widget, GTK_ALIGN_FILL); \
154 #define TABLE_ADD_LINE(label_text, widget, do_space, intable1) { \
155 gchar *tmpstr = g_strdup_printf("<span weight=\"bold\">%s</span>", \
156 label_text?label_text:""); \
157 GtkWidget *label = NULL; \
158 GtkWidget *spacer = NULL; \
159 GtkWidget *s_hbox = NULL; \
161 spacer = gtk_label_new(""); \
162 gtk_widget_set_size_request(spacer, 18, 16); \
163 s_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); \
164 gtk_box_pack_start(GTK_BOX(s_hbox), spacer, FALSE, FALSE, 0); \
165 gtk_box_pack_start(GTK_BOX(s_hbox), widget, TRUE, TRUE, 0); \
168 label = gtk_label_new(tmpstr); \
170 gtk_label_set_use_markup (GTK_LABEL (label), TRUE); \
171 gtk_label_set_xalign (GTK_LABEL(label), 1.0); \
173 gtk_grid_attach(GTK_GRID(meet->table1), label, \
177 gtk_grid_attach(GTK_GRID(meet->table2), label, \
181 gtk_grid_attach(GTK_GRID(meet->table1), \
182 do_space?s_hbox:widget, 1, i, 1, 1); \
185 gtk_grid_attach(GTK_GRID(meet->table2), \
186 do_space?s_hbox:widget, 1, i, 1, 1); \
188 if (GTK_IS_LABEL(widget)) { \
189 gtk_label_set_use_markup(GTK_LABEL (widget), TRUE); \
190 gtk_label_set_xalign(GTK_LABEL(widget), 0.0); \
191 gtk_label_set_yalign(GTK_LABEL(widget), 0.0); \
192 gtk_label_set_line_wrap(GTK_LABEL(widget), TRUE); \
197 gtk_grid_attach(GTK_GRID(meet->table1), \
198 do_space?s_hbox:widget, 0, i, 1, 1); \
199 gtk_widget_set_hexpand(do_space?s_hbox:widget, TRUE); \
200 gtk_widget_set_halign(do_space?s_hbox:widget, \
204 gtk_grid_attach(GTK_GRID(meet->table2), \
205 do_space?s_hbox:widget, 0, i, 1, 1); \
206 gtk_widget_set_hexpand(do_space?s_hbox:widget, TRUE); \
207 gtk_widget_set_halign(do_space?s_hbox:widget, \
222 static gboolean
avail_btn_can_be_sensitive(void)
224 if (vcalprefs
.freebusy_get_url
== NULL
225 || *vcalprefs
.freebusy_get_url
== '\0')
231 static gint
get_dtdate(const gchar
*str
, gint field
)
233 time_t t
= icaltime_as_timet((icaltime_from_string(str
)));
243 lt
= localtime_r(&t
, &buft
);
249 return lt
->tm_mon
+ 1;
251 return lt
->tm_year
+ 1900;
261 static void set_watch_cursor(GdkWindow
*window
)
263 cm_return_if_fail(window
!= NULL
);
266 watch_cursor
= gdk_cursor_new_for_display(
267 gdk_window_get_display(window
), GDK_WATCH
);
271 static gboolean
add_btn_cb(GtkButton
*widget
, gpointer data
)
273 VCalAttendee
*attendee
= (VCalAttendee
*)data
;
274 attendee_add(attendee
->meet
, NULL
, NULL
, NULL
, NULL
, FALSE
);
278 static gboolean
remove_btn_cb(GtkButton
*widget
, gpointer data
)
280 VCalAttendee
*attendee
= (VCalAttendee
*)data
;
281 gtk_container_remove(GTK_CONTAINER(attendee
->meet
->attendees_vbox
), attendee
->hbox
);
282 attendee
->meet
->attendees
= g_slist_remove(attendee
->meet
->attendees
, attendee
);
284 g_free(attendee
->status
);
289 VCalAttendee
*attendee_add(VCalMeeting
*meet
, gchar
*address
, gchar
*name
, gchar
*partstat
, gchar
*cutype
, gboolean first
)
291 GtkWidget
*att_hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 6);
292 VCalAttendee
*attendee
= g_new0(VCalAttendee
, 1);
294 attendee
->address
= gtk_entry_new();
295 attendee
->cutype
= gtk_combo_box_text_new();
296 attendee
->avail_evtbox
= gtk_event_box_new();
297 attendee
->avail_img
= gtk_image_new_from_icon_name
298 ("dialog-warning", GTK_ICON_SIZE_SMALL_TOOLBAR
);
300 gtk_widget_show(attendee
->address
);
301 gtk_widget_show(attendee
->cutype
);
302 gtk_widget_show(attendee
->avail_evtbox
);
304 CLAWS_SET_TIP(attendee
->address
, _("Use <tab> to autocomplete from addressbook"));
305 gtk_widget_set_size_request(attendee
->avail_evtbox
, 18, 16);
306 gtk_event_box_set_visible_window(GTK_EVENT_BOX(attendee
->avail_evtbox
), FALSE
);
307 gtk_container_add (GTK_CONTAINER(attendee
->avail_evtbox
), attendee
->avail_img
);
310 gchar
*str
= g_strdup_printf("%s%s%s%s",
311 (name
&& strlen(name
))?name
:"",
312 (name
&& strlen(name
))?" <":"",
314 (name
&& strlen(name
))?">":"");
315 gtk_entry_set_text(GTK_ENTRY(attendee
->address
), str
);
320 attendee
->status
= g_strdup(partstat
);
322 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(attendee
->cutype
), _("Individual"));
323 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(attendee
->cutype
), _("Group"));
324 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(attendee
->cutype
), _("Resource"));
325 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(attendee
->cutype
), _("Room"));
327 gtk_combo_box_set_active(GTK_COMBO_BOX(attendee
->cutype
), 0);
330 if (!strcmp(cutype
, "group"))
331 gtk_combo_box_set_active(GTK_COMBO_BOX(attendee
->cutype
), 1);
332 if (!strcmp(cutype
, "resource"))
333 gtk_combo_box_set_active(GTK_COMBO_BOX(attendee
->cutype
), 2);
334 if (!strcmp(cutype
, "room"))
335 gtk_combo_box_set_active(GTK_COMBO_BOX(attendee
->cutype
), 3);
338 attendee
->add_btn
= gtk_button_new_with_label(_("Add..."));
339 attendee
->remove_btn
= gtk_button_new_with_label(_("Remove"));
340 attendee
->meet
= meet
;
341 attendee
->hbox
= att_hbox
;
343 gtk_widget_show(attendee
->add_btn
);
344 gtk_widget_show(attendee
->remove_btn
);
345 gtk_widget_show(attendee
->hbox
);
347 gtk_box_pack_start(GTK_BOX(attendee
->hbox
), attendee
->avail_evtbox
, FALSE
, FALSE
, 0);
348 gtk_widget_set_sensitive(attendee
->remove_btn
, !first
);
349 meet
->attendees
= g_slist_append(meet
->attendees
, attendee
);
351 g_signal_connect(G_OBJECT(attendee
->remove_btn
), "clicked",
352 G_CALLBACK(remove_btn_cb
), attendee
);
353 g_signal_connect(G_OBJECT(attendee
->add_btn
), "clicked",
354 G_CALLBACK(add_btn_cb
), attendee
);
356 gtk_box_pack_start(GTK_BOX(att_hbox
), attendee
->address
, FALSE
, FALSE
, 0);
357 gtk_box_pack_start(GTK_BOX(att_hbox
), attendee
->cutype
, FALSE
, FALSE
, 0);
358 gtk_box_pack_start(GTK_BOX(att_hbox
), attendee
->add_btn
, FALSE
, FALSE
, 0);
359 gtk_box_pack_start(GTK_BOX(att_hbox
), attendee
->remove_btn
, FALSE
, FALSE
, 0);
360 gtk_box_pack_start(GTK_BOX(meet
->attendees_vbox
), att_hbox
, FALSE
, FALSE
, 0);
361 address_completion_register_entry(GTK_ENTRY(attendee
->address
), FALSE
);
363 gtk_widget_set_size_request(attendee
->address
, 320, -1);
365 gtk_widget_set_size_request(attendee
->address
, 220, -1);
370 static gchar
*get_organizer(VCalMeeting
*meet
)
372 int index
= gtk_combo_box_get_active(GTK_COMBO_BOX(meet
->who
));
374 GSList
*cur
= meet
->avail_accounts
;
375 while (i
< index
&& cur
&& cur
->data
) {
376 debug_print("%d:skipping %s\n",i
,((PrefsAccount
*)(cur
->data
))->address
);
380 if (cur
&& cur
->data
)
381 return g_strdup(((PrefsAccount
*)(cur
->data
))->address
);
386 static gchar
*get_organizer_name(VCalMeeting
*meet
)
388 int index
= gtk_combo_box_get_active(GTK_COMBO_BOX(meet
->who
));
390 GSList
*cur
= meet
->avail_accounts
;
391 while (i
< index
&& cur
&& cur
->data
) {
392 debug_print("%d:skipping %s\n",i
,((PrefsAccount
*)(cur
->data
))->address
);
396 if (cur
&& cur
->data
)
397 return g_strdup(((PrefsAccount
*)(cur
->data
))->name
);
402 static int get_current_gmt_offset(void)
404 time_t now
= time(NULL
);
414 gmtime_r(& now
, & gmt
);
415 localtime_r(& now
, & local
);
418 return mktime(&local
)-mktime(&gmt
);
421 static int get_gmt_offset_at_time(time_t then
)
432 gmtime_r(& then
, & gmt
);
433 localtime_r(& then
, & local
);
436 return mktime(&local
)-mktime(&gmt
);
439 static gchar
*get_date(VCalMeeting
*meet
, int start
)
454 lt
= localtime_r(&t
, &buft
);
456 gtk_calendar_get_date(GTK_CALENDAR(start
? meet
->start_c
: meet
->end_c
), &y
, &m
, &d
);
459 lt
->tm_year
= y
- 1900;
465 gtkut_time_select_get_time(GTK_COMBO_BOX(meet
->start_time
), <
->tm_hour
, <
->tm_min
);
467 gtkut_time_select_get_time(GTK_COMBO_BOX(meet
->end_time
), <
->tm_hour
, <
->tm_min
);
470 debug_print("%d %d %d, %d:%d\n", lt
->tm_mday
, lt
->tm_mon
, lt
->tm_year
, lt
->tm_hour
, lt
->tm_min
);
473 dst_offset
= get_current_gmt_offset() - get_gmt_offset_at_time(t
);
474 debug_print("DST change offset to apply to time %d\n", dst_offset
);
476 debug_print("%s\n", ctime(&t
));
477 return g_strdup(icaltime_as_ical_string(icaltime_from_timet_with_zone(t
, FALSE
, NULL
)));
480 static gchar
*get_location(VCalMeeting
*meet
)
482 return gtk_editable_get_chars(GTK_EDITABLE(meet
->location
),0, -1);
485 static gchar
*get_summary(VCalMeeting
*meet
)
487 return gtk_editable_get_chars(GTK_EDITABLE(meet
->summary
),0, -1);
490 static gchar
*get_description(VCalMeeting
*meet
)
492 GtkTextBuffer
*buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(meet
->description
));
493 GtkTextIter start
, end
;
495 gtk_text_buffer_get_start_iter(buffer
, &start
);
496 gtk_text_buffer_get_end_iter(buffer
, &end
);
497 return gtk_text_buffer_get_text(buffer
, &start
, &end
, FALSE
);
500 void vcal_meeting_free(VCalMeeting
*meet
)
502 debug_print("freeing meeting\n");
504 address_completion_end(meet
->window
);
505 g_slist_free(meet
->avail_accounts
);
506 g_slist_free(meet
->attendees
);
510 static void destroy_meeting_cb(GtkWidget
*widget
, gpointer data
)
512 VCalMeeting
*meet
= (VCalMeeting
*)data
;
513 vcal_meeting_free(meet
);
516 static void vcal_destroy(VCalMeeting
*meet
)
518 GtkTextBuffer
*buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(meet
->description
));
519 gtk_text_buffer_remove_selection_clipboard(buffer
, gtk_clipboard_get(GDK_SELECTION_PRIMARY
));
520 gtk_widget_destroy(meet
->window
);
523 static gboolean
meeting_key_pressed(GtkWidget
*widget
,
527 VCalMeeting
*meet
= (VCalMeeting
*)data
;
529 if (event
&& event
->keyval
== GDK_KEY_Escape
) {
535 static void meeting_end_changed(GtkWidget
*widget
, gpointer data
);
537 static void meeting_start_changed(GtkWidget
*widget
, gpointer data
)
539 VCalMeeting
*meet
= (VCalMeeting
*)data
;
542 time_t start_t
, end_t
;
545 if (!gtkut_time_select_get_time(GTK_COMBO_BOX(meet
->start_time
), &start_lt
.tm_hour
, &start_lt
.tm_min
))
549 start_t
= time(NULL
);
557 localtime_r(&start_t
, &start_lt
);
558 localtime_r(&end_t
, &end_lt
);
560 gtk_calendar_get_date(GTK_CALENDAR(meet
->start_c
), &y
, &m
, &d
);
561 start_lt
.tm_mday
= d
; start_lt
.tm_mon
= m
; start_lt
.tm_year
= y
- 1900;
563 start_t
= mktime(&start_lt
);
564 debug_print("start %s\n", ctime(&start_t
));
566 gtk_calendar_get_date(GTK_CALENDAR(meet
->end_c
), &y
, &m
, &d
);
567 end_lt
.tm_mday
= d
; end_lt
.tm_mon
= m
; end_lt
.tm_year
= y
- 1900;
569 gtkut_time_select_get_time(GTK_COMBO_BOX(meet
->end_time
), &end_lt
.tm_hour
, &end_lt
.tm_min
);
571 end_t
= mktime(&end_lt
);
573 debug_print("end %s\n", ctime(&end_t
));
575 if (end_t
> start_t
) {
579 end_t
= start_t
+ 3600;
585 localtime_r(&end_t
, &end_lt
);
586 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
);
588 g_signal_handlers_block_by_func(gtk_bin_get_child(GTK_BIN(meet
->end_time
)), meeting_end_changed
, meet
);
589 g_signal_handlers_block_by_func(meet
->end_c
, meeting_end_changed
, meet
);
591 gtk_calendar_select_day(GTK_CALENDAR(meet
->end_c
), end_lt
.tm_mday
);
593 gtk_calendar_select_month(GTK_CALENDAR(meet
->end_c
),
595 end_lt
.tm_year
+ 1900);
597 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->end_time
), end_lt
.tm_hour
, end_lt
.tm_min
);
599 g_signal_handlers_unblock_by_func(gtk_bin_get_child(GTK_BIN(meet
->end_time
)), meeting_end_changed
, meet
);
600 g_signal_handlers_unblock_by_func(meet
->end_c
, meeting_end_changed
, meet
);
603 static void meeting_end_changed(GtkWidget
*widget
, gpointer data
)
605 VCalMeeting
*meet
= (VCalMeeting
*)data
;
608 time_t start_t
, end_t
;
611 if (!gtkut_time_select_get_time(GTK_COMBO_BOX(meet
->end_time
), &end_lt
.tm_hour
, &end_lt
.tm_min
))
613 start_t
= time(NULL
);
624 localtime_r(&start_t
, &start_lt
);
625 localtime_r(&end_t
, &end_lt
);
627 gtk_calendar_get_date(GTK_CALENDAR(meet
->start_c
), &y
, &m
, &d
);
628 start_lt
.tm_mday
= d
; start_lt
.tm_mon
= m
; start_lt
.tm_year
= y
- 1900;
629 gtkut_time_select_get_time(GTK_COMBO_BOX(meet
->start_time
), &start_lt
.tm_hour
, &start_lt
.tm_min
);
631 start_t
= mktime(&start_lt
);
632 debug_print("start %s\n", ctime(&start_t
));
634 gtk_calendar_get_date(GTK_CALENDAR(meet
->end_c
), &y
, &m
, &d
);
635 end_lt
.tm_mday
= d
; end_lt
.tm_mon
= m
; end_lt
.tm_year
= y
- 1900;
637 end_t
= mktime(&end_lt
);
639 debug_print("end %s\n", ctime(&end_t
));
641 if (end_t
> start_t
) {
645 start_t
= end_t
- 3600;
653 localtime_r(&start_t
, &start_lt
);
654 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
);
656 g_signal_handlers_block_by_func(gtk_bin_get_child(GTK_BIN(meet
->start_time
)), meeting_start_changed
, meet
);
657 g_signal_handlers_block_by_func(meet
->start_c
, meeting_start_changed
, meet
);
659 gtk_calendar_select_day(GTK_CALENDAR(meet
->start_c
), start_lt
.tm_mday
);
661 gtk_calendar_select_month(GTK_CALENDAR(meet
->start_c
),
663 start_lt
.tm_year
+ 1900);
665 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->start_time
), start_lt
.tm_hour
, start_lt
.tm_min
);
667 g_signal_handlers_unblock_by_func(gtk_bin_get_child(GTK_BIN(meet
->start_time
)), meeting_start_changed
, meet
);
668 g_signal_handlers_unblock_by_func(meet
->start_c
, meeting_start_changed
, meet
);
671 static void att_update_icon(VCalMeeting
*meet
, VCalAttendee
*attendee
, gint avail
, gchar
*text
)
673 const gchar
*icon
= "dialog-information";
676 case 0: icon
= "dialog-warning"; break;
677 case 1: icon
= "dialog-information"; break;
678 default: icon
= "dialog-question"; break;
680 if (!gtk_entry_get_text(GTK_ENTRY(attendee
->address
))
681 || strlen(gtk_entry_get_text(GTK_ENTRY(attendee
->address
)))==0) {
682 if (attendee
->avail_img
) {
683 gtk_widget_hide(attendee
->avail_img
);
685 CLAWS_SET_TIP(attendee
->avail_evtbox
, NULL
);
686 } else if (attendee
->avail_img
) {
687 gtk_image_set_from_icon_name
688 (GTK_IMAGE(attendee
->avail_img
),
690 GTK_ICON_SIZE_SMALL_TOOLBAR
);
691 gtk_widget_show(attendee
->avail_img
);
692 CLAWS_SET_TIP(attendee
->avail_evtbox
, text
);
696 gboolean
attendee_available(VCalAttendee
*attendee
, const gchar
*dtstart
, const gchar
*dtend
, const gchar
*contents
)
698 icalcomponent
*toplvl
, *vfreebusy
;
699 icalproperty
*busyprop
;
700 struct icaltimetype start
= icaltime_from_string(dtstart
);
701 struct icaltimetype end
= icaltime_from_string(dtend
);
702 gboolean result
= TRUE
;
705 if (contents
== NULL
)
708 toplvl
= icalcomponent_new_from_string((gchar
*)contents
);
713 vfreebusy
= icalcomponent_get_first_component(toplvl
, ICAL_VFREEBUSY_COMPONENT
);
714 while (vfreebusy
&& icalcomponent_isa(vfreebusy
) != ICAL_VFREEBUSY_COMPONENT
)
715 vfreebusy
= icalcomponent_get_next_component(toplvl
, ICAL_VFREEBUSY_COMPONENT
);
718 busyprop
= icalcomponent_get_first_property(vfreebusy
, ICAL_FREEBUSY_PROPERTY
);
720 struct icalperiodtype ipt
= icalproperty_get_freebusy(busyprop
);
722 if ( icaltime_compare(start
, ipt
.end
) >= 0 || icaltime_compare(end
, ipt
.start
) <= 0 ) {
728 busyprop
= icalcomponent_get_next_property(vfreebusy
, ICAL_FREEBUSY_PROPERTY
);
732 icalcomponent_free(toplvl
);
736 static gchar
*get_avail_msg(const gchar
*unavailable_persons
, gboolean multiple
,
737 gboolean short_version
, gint offset_before
, gint offset_after
)
739 gchar
*msg
, *intro
= NULL
, *outro
= NULL
, *before
= NULL
, *after
= NULL
;
742 intro
= g_strdup(_("The following people are busy at the time of your planned meeting:\n- "));
743 else if (!strcmp(unavailable_persons
, _("You")))
744 intro
= g_strdup(_("You are busy at the time of your planned meeting"));
746 intro
= g_strdup_printf(_("%s is busy at the time of your planned meeting"), unavailable_persons
);
747 if (offset_before
== 3600)
748 before
= g_strdup_printf(_("%d hour sooner"), offset_before
/3600);
749 else if (offset_before
> 3600 && offset_before
%3600 == 0)
750 before
= g_strdup_printf(_("%d hours sooner"), offset_before
/3600);
751 else if (offset_before
> 3600)
752 before
= g_strdup_printf(_("%d hours and %d minutes sooner"), offset_before
/3600, (offset_before
%3600)/60);
753 else if (offset_before
== 1800)
754 before
= g_strdup_printf(_("%d minutes sooner"), offset_before
/60);
758 if (offset_after
== 3600)
759 after
= g_strdup_printf(_("%d hour later"), offset_after
/3600);
760 else if (offset_after
> 3600 && offset_after
%3600 == 0)
761 after
= g_strdup_printf(_("%d hours later"), offset_after
/3600);
762 else if (offset_after
> 3600)
763 after
= g_strdup_printf(_("%d hours and %d minutes later"), offset_after
/3600, (offset_after
%3600)/60);
764 else if (offset_after
== 1800)
765 after
= g_strdup_printf(_("%d minutes later"), offset_after
/60);
771 outro
= g_strdup_printf(_("\n\nEveryone would be available %s or %s."), before
, after
);
772 else if (before
|| after
)
773 outro
= g_strdup_printf(_("\n\nEveryone would be available %s."), before
?before
:after
);
775 outro
= g_strdup_printf(_("\n\nIt isn't possible to have this meeting with everyone "
776 "in the previous or next 6 hours."));
780 outro
= g_markup_printf_escaped(_("would be available %s or %s"), before
, after
);
781 else if (before
|| after
)
782 outro
= g_markup_printf_escaped(_("would be available %s"), before
?before
:after
);
784 outro
= g_strdup_printf(_("not available"));
787 outro
= g_markup_printf_escaped(_(", but would be available %s or %s."), before
, after
);
788 else if (before
|| after
)
789 outro
= g_markup_printf_escaped(_(", but would be available %s."), before
?before
:after
);
791 outro
= g_strdup_printf(_(", and isn't available "
792 "in the previous or next 6 hours."));
795 if (multiple
&& short_version
)
796 msg
= g_strconcat(outro
+2, NULL
);
798 msg
= g_strconcat(intro
, unavailable_persons
, outro
, NULL
);
799 else if (short_version
)
800 msg
= g_strdup(outro
);
802 msg
= g_strconcat(intro
, outro
, NULL
);
810 static gboolean
find_availability(const gchar
*dtstart
, const gchar
*dtend
, GSList
*attendees
, gboolean for_send
, VCalMeeting
*meet
)
813 gint offset
= -1800, offset_before
= 0, offset_after
= 0;
814 gboolean found
= FALSE
;
815 gchar
*unavailable_persons
= NULL
;
817 struct icaltimetype start
= icaltime_from_string(dtstart
);
818 struct icaltimetype end
= icaltime_from_string(dtend
);
819 AlertValue val
= G_ALERTALTERNATE
;
821 GHashTable
*avail_table_avail
= g_hash_table_new(NULL
, g_direct_equal
);
822 GHashTable
*avail_table_before
= g_hash_table_new(NULL
, g_direct_equal
);
823 GHashTable
*avail_table_after
= g_hash_table_new(NULL
, g_direct_equal
);
825 for (cur
= attendees
; cur
; cur
= cur
->next
) {
826 VCalAttendee
*attendee
= (VCalAttendee
*)cur
->data
;
827 if (!attendee_available(attendee
, icaltime_as_ical_string(start
), icaltime_as_ical_string(end
),
828 attendee
->cached_contents
)) {
832 mail
= g_strdup(_("You"));
834 mail
= gtk_editable_get_chars(GTK_EDITABLE(attendee
->address
), 0, -1);
836 if (unavailable_persons
== NULL
) {
837 unavailable_persons
= g_markup_printf_escaped("%s", mail
);
839 gchar
*tmp
= g_markup_printf_escaped("%s,\n- %s", unavailable_persons
, mail
);
840 g_free(unavailable_persons
);
841 unavailable_persons
= tmp
;
845 att_update_icon(meet
, attendee
, 0, _("not available"));
847 if (attendee
->cached_contents
!= NULL
)
848 att_update_icon(meet
, attendee
, 1, _("available"));
850 att_update_icon(meet
, attendee
, 2, _("Free/busy retrieval failed"));
852 g_hash_table_insert(avail_table_avail
, attendee
, GINT_TO_POINTER(1));
857 while (!found
&& offset
>= -3600*6) {
859 struct icaltimetype new_start
= icaltime_from_timet_with_zone(icaltime_as_timet(start
)+offset
, FALSE
, NULL
);
860 struct icaltimetype new_end
= icaltime_from_timet_with_zone(icaltime_as_timet(end
)+offset
, FALSE
, NULL
);
861 for (cur
= attendees
; cur
; cur
= cur
->next
) {
862 VCalAttendee
*attendee
= (VCalAttendee
*)cur
->data
;
863 debug_print("trying %s - %s (offset %d)\n",
864 icaltime_as_ical_string(new_start
), icaltime_as_ical_string(new_end
), offset
);
865 if (!attendee_available(attendee
, icaltime_as_ical_string(new_start
), icaltime_as_ical_string(new_end
),
866 attendee
->cached_contents
)) {
870 if (!g_hash_table_lookup(avail_table_before
, attendee
)
871 && !g_hash_table_lookup(avail_table_avail
, attendee
))
872 g_hash_table_insert(avail_table_before
, attendee
, GINT_TO_POINTER(-offset
));
877 offset_before
= -offset
;
883 while (!found
&& offset
<= 3600*6) {
885 struct icaltimetype new_start
= icaltime_from_timet_with_zone(icaltime_as_timet(start
)+offset
, FALSE
, NULL
);
886 struct icaltimetype new_end
= icaltime_from_timet_with_zone(icaltime_as_timet(end
)+offset
, FALSE
, NULL
);
887 for (cur
= attendees
; cur
; cur
= cur
->next
) {
888 VCalAttendee
*attendee
= (VCalAttendee
*)cur
->data
;
889 debug_print("trying %s - %s (offset %d)\n",
890 icaltime_as_ical_string(new_start
), icaltime_as_ical_string(new_end
), offset
);
891 if (!attendee_available(attendee
, icaltime_as_ical_string(new_start
), icaltime_as_ical_string(new_end
),
892 attendee
->cached_contents
)) {
896 if (!g_hash_table_lookup(avail_table_after
, attendee
)
897 && !g_hash_table_lookup(avail_table_avail
, attendee
))
898 g_hash_table_insert(avail_table_after
, attendee
, GINT_TO_POINTER(offset
));
903 offset_after
= offset
;
909 for (cur
= attendees
; cur
; cur
= cur
->next
) {
910 VCalAttendee
*attendee
= (VCalAttendee
*)cur
->data
;
911 gint ok
= GPOINTER_TO_INT(g_hash_table_lookup(avail_table_avail
, attendee
));
912 gint o_before
= GPOINTER_TO_INT(g_hash_table_lookup(avail_table_before
, attendee
));
913 gint o_after
= GPOINTER_TO_INT(g_hash_table_lookup(avail_table_after
, attendee
));
914 if (!o_before
&& !o_after
&& !ok
) {
915 att_update_icon(meet
, attendee
, 0, _("not available"));
916 } else if ((o_before
!= 0 || o_after
!= 0) && !ok
) {
918 msg
= get_avail_msg(_("You"), FALSE
, TRUE
, o_before
, o_after
);
920 msg
= get_avail_msg(gtk_entry_get_text(GTK_ENTRY(attendee
->address
)), FALSE
, TRUE
, o_before
, o_after
);
921 att_update_icon(meet
, attendee
, 0, msg
);
926 g_hash_table_destroy(avail_table_before
);
927 g_hash_table_destroy(avail_table_after
);
930 msg
= get_avail_msg(unavailable_persons
, (total
> 1), FALSE
, offset_before
, offset_after
);
932 val
= alertpanel_full(_("Not everyone is available"), msg
,
933 NULL
, _("_Cancel"), NULL
, _("Send anyway"),
934 NULL
, NULL
, ALERTFOCUS_FIRST
,
935 FALSE
, NULL
, ALERT_QUESTION
);
938 msg
= get_avail_msg(unavailable_persons
, TRUE
, TRUE
, offset_before
, offset_after
);
939 g_free(unavailable_persons
);
940 gtk_image_set_from_icon_name
941 (GTK_IMAGE(meet
->total_avail_img
),
943 GTK_ICON_SIZE_SMALL_TOOLBAR
);
944 gtk_widget_show(meet
->total_avail_img
);
945 gtk_label_set_text(GTK_LABEL(meet
->total_avail_msg
), _("Not everyone is available. "
946 "See tooltips for more info..."));
947 CLAWS_SET_TIP(meet
->total_avail_evtbox
, msg
);
949 return (val
== G_ALERTALTERNATE
);
952 static gboolean
check_attendees_availability(VCalMeeting
*meet
, gboolean tell_if_ok
, gboolean for_send
)
956 gchar
*real_url
= NULL
;
958 gchar
*change_user
= NULL
, *change_dom
= NULL
;
959 gchar
*dtstart
= NULL
;
961 gboolean find_avail
= FALSE
;
962 gboolean res
= TRUE
, uncertain
= FALSE
;
963 gchar
*organizer
= NULL
;
964 VCalAttendee
*dummy_org
= NULL
;
965 gchar
*internal_ifb
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
966 "vcalendar", G_DIR_SEPARATOR_S
,
967 "internal.ifb", NULL
);
968 gboolean local_only
= FALSE
;
972 if (vcalprefs
.freebusy_get_url
== NULL
973 || *vcalprefs
.freebusy_get_url
== '\0') {
976 real_url
= g_strdup(vcalprefs
.freebusy_get_url
);
979 while (strchr(tmp
, '%')) {
980 tmp
= strchr(tmp
, '%')+1;
983 if (num_format
> 2) {
984 g_warning("wrong format in %s!", real_url
);
986 g_free(internal_ifb
);
991 if (strstr(real_url
, "%u") != NULL
) {
992 change_user
= strstr(real_url
, "%u");
993 *(strstr(real_url
, "%u")+1) = 's';
995 if (strstr(real_url
, "%d") != NULL
) {
996 change_dom
= strstr(real_url
, "%d");
997 *(strstr(real_url
, "%d")+1) = 's';
999 debug_print("url format %s\n", real_url
);
1001 dtstart
= get_date(meet
, TRUE
);
1002 dtend
= get_date(meet
, FALSE
);
1004 /* hack to check our own avail. */
1005 organizer
= get_organizer(meet
);
1006 dummy_org
= g_new0(VCalAttendee
, 1);
1007 dummy_org
->address
= gtk_entry_new();
1008 dummy_org
->avail_img
= meet
->avail_img
;
1009 dummy_org
->avail_evtbox
= meet
->avail_evtbox
;
1010 dummy_org
->org
= TRUE
;
1011 gtk_entry_set_text(GTK_ENTRY(dummy_org
->address
), organizer
);
1013 dummy_org
->cached_contents
= file_read_to_str(internal_ifb
);
1014 g_free(internal_ifb
);
1017 meet
->attendees
= g_slist_prepend(meet
->attendees
, dummy_org
);
1018 attlist
= meet
->attendees
;
1020 attlist
= g_slist_prepend(NULL
, dummy_org
);
1023 gtk_widget_set_sensitive(meet
->save_btn
, FALSE
);
1024 gtk_widget_set_sensitive(meet
->avail_btn
, FALSE
);
1026 gdkwin
= gtk_widget_get_window(meet
->window
);
1027 if (gdkwin
!= NULL
) {
1028 set_watch_cursor(gdkwin
);
1029 gdk_window_set_cursor(gdkwin
, watch_cursor
);
1032 for (cur
= attlist
; cur
&& cur
->data
; cur
= cur
->next
) {
1033 VCalAttendee
*attendee
= (VCalAttendee
*)cur
->data
;
1034 gchar
*email
= gtk_editable_get_chars(GTK_EDITABLE(attendee
->address
), 0, -1);
1035 gchar
*remail
, *user
, *domain
;
1036 gchar
*contents
= NULL
;
1038 if (*email
== '\0') {
1040 att_update_icon(meet
, attendee
, 0, NULL
);
1045 remail
= g_strdup(email
);
1047 extract_address(remail
);
1048 if (strrchr(remail
, ' '))
1049 user
= g_strdup(strrchr(remail
, ' ')+1);
1051 user
= g_strdup(remail
);
1052 if (strchr(user
, '@')) {
1053 domain
= g_strdup(strchr(user
, '@')+1);
1054 *(strchr(user
, '@')) = '\0';
1056 domain
= g_strdup("");
1059 if (change_user
&& change_dom
) {
1060 if (change_user
< change_dom
)
1061 tmp
= g_strdup_printf(real_url
, user
, domain
);
1063 tmp
= g_strdup_printf(real_url
, domain
, user
);
1064 } else if (change_user
) {
1065 tmp
= g_strdup_printf(real_url
, user
);
1066 } else if (change_dom
) {
1067 tmp
= g_strdup_printf(real_url
, domain
);
1069 tmp
= g_strdup(real_url
);
1073 debug_print("url to get %s\n", tmp
);
1076 if (attendee
->cached_contents
!= NULL
) {
1077 contents
= attendee
->cached_contents
;
1078 attendee
->cached_contents
= NULL
;
1079 } else if (!local_only
) {
1080 if (strncmp(tmp
, "http://", 7)
1081 && strncmp(tmp
, "https://", 8)
1082 && strncmp(tmp
, "webcal://", 9)
1083 && strncmp(tmp
, "webcals://", 10)
1084 && strncmp(tmp
, "ftp://", 6)
1085 && strncmp(tmp
, "ftps://", 7)
1086 && strncmp(tmp
, "sftp://", 7))
1087 contents
= file_read_to_str(tmp
);
1089 gchar
*label
= g_strdup_printf(_("Fetching planning for %s..."), email
);
1090 if (!strncmp(tmp
, "webcal", 6)) {
1091 gchar
*tmp2
= g_strdup_printf("http%s", tmp
+6);
1095 contents
= vcal_curl_read(tmp
, label
, FALSE
, NULL
);
1105 if (contents
== NULL
) {
1107 att_update_icon(meet
, attendee
, 2, _("Free/busy retrieval failed"));
1111 if (!attendee_available(attendee
, dtstart
, dtend
, contents
)) {
1113 debug_print("not available!\n");
1115 debug_print("available!\n");
1116 att_update_icon(meet
, attendee
, 1, _("Available"));
1118 attendee
->cached_contents
= contents
;
1124 res
= find_availability((dtstart
), (dtend
), attlist
, for_send
, meet
);
1129 alertpanel_notice(_("Everyone is available."));
1130 else if (!uncertain
) {
1131 gtk_image_set_from_icon_name
1132 (GTK_IMAGE(meet
->total_avail_img
),
1133 "dialog-information",
1134 GTK_ICON_SIZE_SMALL_TOOLBAR
);
1135 gtk_widget_show(meet
->total_avail_img
);
1136 gtk_label_set_text(GTK_LABEL(meet
->total_avail_msg
), _("Everyone is available."));
1137 CLAWS_SET_TIP(meet
->total_avail_evtbox
, NULL
);
1139 gtk_image_set_from_icon_name
1140 (GTK_IMAGE(meet
->total_avail_img
),
1142 GTK_ICON_SIZE_SMALL_TOOLBAR
);
1143 gtk_widget_show(meet
->total_avail_img
);
1144 gtk_label_set_text(GTK_LABEL(meet
->total_avail_msg
), _("Everyone is available."));
1145 CLAWS_SET_TIP(meet
->total_avail_evtbox
, _("Everyone seems available, but some free/busy information failed to be retrieved."));
1150 for (cur
= attlist
; cur
&& cur
->data
; cur
= cur
->next
) {
1151 VCalAttendee
*attendee
= (VCalAttendee
*)cur
->data
;
1152 g_free(attendee
->cached_contents
);
1153 attendee
->cached_contents
= NULL
;
1155 gtk_widget_set_sensitive(meet
->save_btn
, TRUE
);
1156 gtk_widget_set_sensitive(meet
->avail_btn
, avail_btn_can_be_sensitive());
1159 gdk_window_set_cursor(gdkwin
, NULL
);
1162 meet
->attendees
= g_slist_remove(meet
->attendees
, dummy_org
);
1164 g_slist_free(attlist
);
1165 gtk_widget_destroy(dummy_org
->address
);
1176 static gboolean
check_avail_cb(GtkButton
*widget
, gpointer data
)
1178 VCalMeeting
*meet
= (VCalMeeting
*)data
;
1179 check_attendees_availability(meet
, TRUE
, FALSE
);
1183 static gboolean
send_meeting_cb(GtkButton
*widget
, gpointer data
)
1185 VCalMeeting
*meet
= (VCalMeeting
*)data
;
1187 gchar
*organizer
= NULL
;
1188 gchar
*organizer_name
= NULL
;
1189 gchar
*dtstart
= NULL
;
1190 gchar
*dtend
= NULL
;
1192 gchar
*location
= NULL
;
1193 gchar
*summary
= NULL
;
1194 gchar
*description
= NULL
;
1195 VCalEvent
*event
= NULL
;
1197 PrefsAccount
*account
= NULL
;
1198 gboolean res
= FALSE
;
1199 gboolean found_att
= FALSE
;
1200 Folder
*folder
= folder_find_from_name (PLUGIN_NAME
, vcal_folder_get_class());
1201 gboolean redisp
= FALSE
;
1204 if (meet
->uid
== NULL
&& meet
->visible
&&
1205 !check_attendees_availability(meet
, FALSE
, TRUE
)) {
1210 MainWindow
*mainwin
= mainwindow_get_mainwindow();
1211 if (mainwin
->summaryview
->folder_item
== folder
->inbox
) {
1213 summary_show(mainwin
->summaryview
, NULL
, FALSE
);
1216 gtk_widget_set_sensitive(meet
->save_btn
, FALSE
);
1217 gtk_widget_set_sensitive(meet
->avail_btn
, FALSE
);
1219 gdkwin
= gtk_widget_get_window(meet
->window
);
1220 if (gdkwin
!= NULL
) {
1221 set_watch_cursor(gdkwin
);
1222 gdk_window_set_cursor(gdkwin
, watch_cursor
);
1225 organizer
= get_organizer(meet
);
1226 account
= account_find_from_address(organizer
, FALSE
);
1228 if(account
== NULL
) {
1229 debug_print("can't get account from address %s\n", organizer
);
1234 organizer_name
= get_organizer_name(meet
);
1237 uid
= g_strdup(meet
->uid
);
1239 uid
= prefs_account_generate_msgid(account
);
1242 dtstart
= get_date(meet
, TRUE
);
1243 dtend
= get_date(meet
, FALSE
);
1244 location
= get_location(meet
);
1245 summary
= get_summary(meet
);
1246 description
= get_description(meet
);
1248 if (meet
->created
== NULL
) {
1249 meet
->created
= g_strdup(icaltime_as_ical_string(icaltime_from_timet_with_zone(time(NULL
), FALSE
, NULL
)));
1251 if (meet
->last_modified
== NULL
) {
1252 meet
->last_modified
= g_strdup(icaltime_as_ical_string(icaltime_from_timet_with_zone(time(NULL
), FALSE
, NULL
)));
1254 event
= vcal_manager_new_event(uid
, organizer
, organizer_name
, location
, summary
, description
,
1255 dtstart
, dtend
, NULL
, tzid
, NULL
, meet
->method
,
1257 meet
->created
, meet
->last_modified
, ICAL_VEVENT_COMPONENT
);
1259 vcal_manager_update_answer(event
, organizer
, organizer_name
,
1260 ICAL_PARTSTAT_ACCEPTED
,
1261 ICAL_CUTYPE_INDIVIDUAL
);
1263 for (cur
= meet
->attendees
; cur
&& cur
->data
; cur
= cur
->next
) {
1264 VCalAttendee
*attendee
= (VCalAttendee
*)cur
->data
;
1265 gchar
*email
= gtk_editable_get_chars(GTK_EDITABLE(attendee
->address
), 0, -1);
1267 gchar
*orig_email
= email
;
1269 enum icalparameter_cutype cutype
= ICAL_CUTYPE_INDIVIDUAL
;
1270 enum icalparameter_partstat status
= ICAL_PARTSTAT_NEEDSACTION
;
1272 index
= gtk_combo_box_get_active(GTK_COMBO_BOX(attendee
->cutype
));
1274 cutype
= ICAL_CUTYPE_INDIVIDUAL
+ index
;
1275 if (attendee
->status
) {
1276 if(!strcmp(attendee
->status
, "accepted"))
1277 status
= ICAL_PARTSTAT_ACCEPTED
;
1278 if(!strcmp(attendee
->status
, "tentatively accepted"))
1279 status
= ICAL_PARTSTAT_TENTATIVE
;
1280 if(!strcmp(attendee
->status
, "declined"))
1281 status
= ICAL_PARTSTAT_DECLINED
;
1282 g_free(attendee
->status
);
1284 if (strlen(email
)) {
1285 if (strstr(email
, " <")) {
1287 email
= strstr(email
," <") + 2;
1288 *(strstr(name
," <")) = '\0';
1289 if (strstr(email
, ">"))
1290 *(strstr(email
, ">")) = '\0';
1293 vcal_manager_update_answer(event
, email
, name
,
1296 found_att
= strcmp(email
, organizer
);
1302 res
= vcal_manager_request(account
, event
);
1307 g_free(organizer_name
);
1310 g_free(description
);
1313 vcal_manager_free_event(event
);
1315 gtk_widget_set_sensitive(meet
->save_btn
, TRUE
);
1316 gtk_widget_set_sensitive(meet
->avail_btn
, avail_btn_can_be_sensitive());
1318 gdk_window_set_cursor(gdkwin
, NULL
);
1323 alertpanel_error(_("Could not send the meeting invitation.\n"
1324 "Check the recipients."));
1328 folder_item_scan(folder
->inbox
);
1330 if (folder
&& redisp
) {
1331 MainWindow
*mainwin
= mainwindow_get_mainwindow();
1332 summary_show(mainwin
->summaryview
, folder
->inbox
, FALSE
);
1338 static VCalMeeting
*vcal_meeting_create_real(VCalEvent
*event
, gboolean visible
)
1340 VCalMeeting
*meet
= g_new0(VCalMeeting
, 1);
1341 GtkTextBuffer
*buffer
= NULL
;
1342 GtkWidget
*date_hbox
, *date_vbox
, *save_hbox
, *label
, *hbox
;
1345 GtkWidget
*scrolledwin
;
1348 GtkWidget
*notebook
;
1349 GtkWidget
*maemo_vbox0
;
1352 meet
->visible
= visible
;
1354 meet
->window
= gtkut_window_new(GTK_WINDOW_TOPLEVEL
, "vcal_meeting_gtk");
1355 #ifndef GENERIC_UMPC
1356 meet
->table
= gtk_grid_new();
1358 meet
->table1
= gtk_grid_new();
1359 meet
->table2
= gtk_grid_new();
1361 meet
->who
= gtk_combo_box_text_new();
1363 meet
->start_c
= gtk_calendar_new();
1364 meet
->end_c
= gtk_calendar_new();
1366 meet
->avail_evtbox
= gtk_event_box_new();
1367 meet
->avail_img
= gtk_image_new_from_icon_name
1368 ("dialog-warning", GTK_ICON_SIZE_SMALL_TOOLBAR
);
1370 meet
->start_time
= gtkut_time_select_combo_new();
1372 meet
->end_time
= gtkut_time_select_combo_new();
1374 meet
->location
= gtk_entry_new();
1375 meet
->summary
= gtk_entry_new();
1376 meet
->description
= gtk_text_view_new();
1377 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(meet
->description
));
1378 gtk_text_view_set_editable(GTK_TEXT_VIEW(meet
->description
), TRUE
);
1379 gtk_text_buffer_add_selection_clipboard(buffer
, gtk_clipboard_get(GDK_SELECTION_PRIMARY
));
1381 scrolledwin
= gtk_scrolled_window_new(NULL
, NULL
);
1382 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin
),
1383 GTK_POLICY_AUTOMATIC
,
1384 GTK_POLICY_AUTOMATIC
);
1385 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin
),
1387 gtk_container_add(GTK_CONTAINER(scrolledwin
), meet
->description
);
1390 meet
->uid
= g_strdup(event
->uid
);
1391 meet
->sequence
= event
->sequence
+ 1;
1392 meet
->created
= event
->created
? g_strdup(event
->created
) : NULL
;
1393 meet
->last_modified
= NULL
; /* Make sure to update modification time */
1395 meet
->method
= (event
->method
== ICAL_METHOD_CANCEL
?
1396 ICAL_METHOD_CANCEL
:ICAL_METHOD_REQUEST
);
1398 gtk_entry_set_text(GTK_ENTRY(meet
->location
), event
->location
);
1399 gtk_entry_set_text(GTK_ENTRY(meet
->summary
), event
->summary
);
1400 gtk_text_buffer_set_text(buffer
, event
->description
, -1);
1402 meet
->method
= ICAL_METHOD_REQUEST
;
1404 meet
->save_btn
= gtk_button_new_with_label(_("Save & Send"));
1405 meet
->avail_btn
= gtk_button_new_with_label(_("Check availability"));
1407 meet
->total_avail_evtbox
= gtk_event_box_new();
1408 meet
->total_avail_img
= gtk_image_new_from_icon_name
1409 ("dialog-warning", GTK_ICON_SIZE_SMALL_TOOLBAR
);
1410 meet
->total_avail_msg
= gtk_label_new("");
1412 gtk_widget_set_size_request(meet
->total_avail_evtbox
, 18, 16);
1413 gtk_event_box_set_visible_window(GTK_EVENT_BOX(meet
->total_avail_evtbox
), FALSE
);
1414 gtk_container_add (GTK_CONTAINER(meet
->total_avail_evtbox
), meet
->total_avail_img
);
1416 g_signal_connect(G_OBJECT(meet
->save_btn
), "clicked",
1417 G_CALLBACK(send_meeting_cb
), meet
);
1419 g_signal_connect(G_OBJECT(meet
->avail_btn
), "clicked",
1420 G_CALLBACK(check_avail_cb
), meet
);
1422 g_signal_connect(G_OBJECT(meet
->window
), "destroy",
1423 G_CALLBACK(destroy_meeting_cb
), meet
);
1424 g_signal_connect(G_OBJECT(meet
->window
), "key_press_event",
1425 G_CALLBACK(meeting_key_pressed
), meet
);
1428 gtk_widget_set_size_request(meet
->description
, -1, 100);
1429 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(meet
->description
), GTK_WRAP_WORD
);
1431 if (!event
|| (event
&& !event
->dtstart
&& !event
->dtend
)) {
1432 time_t t
= time (NULL
)+ 3600;
1433 struct tm buft1
, buft2
;
1434 struct tm
*lt
= localtime_r (&t
, &buft1
);
1436 gtk_calendar_select_day(GTK_CALENDAR(meet
->start_c
),
1438 gtk_calendar_select_month(GTK_CALENDAR(meet
->start_c
),
1439 lt
->tm_mon
, lt
->tm_year
+ 1900);
1441 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->start_time
), lt
->tm_hour
, 0);
1444 lt
= localtime_r(&t
, &buft2
);
1446 gtk_calendar_select_day(GTK_CALENDAR(meet
->end_c
),
1448 gtk_calendar_select_month(GTK_CALENDAR(meet
->end_c
),
1449 lt
->tm_mon
, lt
->tm_year
+ 1900);
1451 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->end_time
), lt
->tm_hour
, 0);
1453 gtk_calendar_select_day(GTK_CALENDAR(meet
->start_c
),
1454 get_dtdate(event
->dtstart
, DAY
));
1455 gtk_calendar_select_day(GTK_CALENDAR(meet
->end_c
),
1456 get_dtdate(event
->dtend
, DAY
));
1458 gtk_calendar_select_month(GTK_CALENDAR(meet
->start_c
),
1459 get_dtdate(event
->dtstart
, MONTH
)-1,
1460 get_dtdate(event
->dtstart
, YEAR
));
1461 gtk_calendar_select_month(GTK_CALENDAR(meet
->end_c
),
1462 get_dtdate(event
->dtend
, MONTH
)-1,
1463 get_dtdate(event
->dtend
, YEAR
));
1465 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->start_time
),
1466 get_dtdate(event
->dtstart
, HOUR
),
1467 get_dtdate(event
->dtstart
, MINUTE
));
1469 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->end_time
),
1470 get_dtdate(event
->dtend
, HOUR
),
1471 get_dtdate(event
->dtend
, MINUTE
));
1474 g_signal_connect(G_OBJECT(meet
->start_c
), "day-selected",
1475 G_CALLBACK(meeting_start_changed
), meet
);
1476 g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN(meet
->start_time
))),
1478 G_CALLBACK(meeting_start_changed
),
1481 g_signal_connect(G_OBJECT(meet
->end_c
), "day-selected",
1482 G_CALLBACK(meeting_end_changed
), meet
);
1483 g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN(meet
->end_time
))),
1485 G_CALLBACK(meeting_end_changed
),
1488 #ifndef GENERIC_UMPC
1489 gtk_widget_set_size_request(meet
->start_time
, 80, -1);
1490 gtk_widget_set_size_request(meet
->end_time
, 80, -1);
1492 gtk_widget_set_size_request(meet
->start_time
, 120, -1);
1493 gtk_widget_set_size_request(meet
->end_time
, 120, -1);
1496 date_hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 6);
1497 date_vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 6);
1498 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 6);
1499 label
= gtk_label_new(g_strconcat("<b>",_("Starts at:"),"</b> ",NULL
));
1500 gtk_label_set_xalign(GTK_LABEL(label
), 0.0);
1501 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1503 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
1504 gtk_box_pack_start(GTK_BOX(hbox
), meet
->start_time
, FALSE
, FALSE
, 0);
1505 label
= gtk_label_new(g_strconcat("<b> ",_("on:"),"</b>",NULL
));
1506 gtk_label_set_xalign(GTK_LABEL(label
), 0.0);
1507 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1508 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
1509 gtk_box_pack_start(GTK_BOX(date_vbox
), hbox
, FALSE
, FALSE
, 0);
1510 gtk_box_pack_start(GTK_BOX(date_vbox
), meet
->start_c
, FALSE
, FALSE
, 0);
1511 gtk_box_pack_start(GTK_BOX(date_hbox
), date_vbox
, FALSE
, FALSE
, 0);
1513 #ifndef GENERIC_UMPC
1514 label
= gtk_label_new(" ");
1516 label
= gtk_label_new("");
1518 gtk_label_set_xalign(GTK_LABEL(label
), 0.0);
1519 gtk_box_pack_start(GTK_BOX(date_hbox
), label
, TRUE
, TRUE
, 0);
1521 date_vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 6);
1522 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 6);
1523 label
= gtk_label_new(g_strconcat("<b>",_("Ends at:"),"</b> ", NULL
));
1524 gtk_label_set_xalign(GTK_LABEL(label
), 0.0);
1525 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1527 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
1528 gtk_box_pack_start(GTK_BOX(hbox
), meet
->end_time
, FALSE
, FALSE
, 0);
1529 label
= gtk_label_new(g_strconcat("<b> ",_("on:"),"</b>",NULL
));
1530 gtk_label_set_xalign(GTK_LABEL(label
), 0.0);
1531 gtk_label_set_use_markup(GTK_LABEL(label
), TRUE
);
1532 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
1533 gtk_box_pack_start(GTK_BOX(date_vbox
), hbox
, FALSE
, FALSE
, 0);
1534 gtk_box_pack_start(GTK_BOX(date_vbox
), meet
->end_c
, FALSE
, FALSE
, 0);
1535 gtk_box_pack_start(GTK_BOX(date_hbox
), date_vbox
, FALSE
, FALSE
, 0);
1537 meet
->attendees_vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 6);
1538 gtk_widget_show_all(meet
->attendees_vbox
);
1540 attendee_add(meet
, NULL
, NULL
, NULL
, NULL
, TRUE
);
1542 gboolean firstadd
= TRUE
;
1543 GSList
*list
= vcal_manager_get_answers_emails(event
);
1544 while (list
&& list
->data
) {
1545 gchar
*address
= (gchar
*)list
->data
;
1546 gchar
*name
= vcal_manager_get_attendee_name(event
, address
);
1547 gchar
*answer
= vcal_manager_get_reply_text_for_attendee(event
, address
);
1548 gchar
*type
= vcal_manager_get_cutype_text_for_attendee(event
, address
);
1549 if (strcmp(event
->organizer
, address
)) {
1550 attendee_add(meet
, address
, name
, answer
, type
, firstadd
);
1559 if (firstadd
== TRUE
)
1560 attendee_add(meet
, NULL
, NULL
, NULL
, NULL
, TRUE
);
1564 gtk_window_set_title(GTK_WINDOW(meet
->window
), _("New meeting"));
1566 gchar
*title
= g_strdup_printf(_("%s - Edit meeting"),
1568 gtk_window_set_title(GTK_WINDOW(meet
->window
), title
);
1571 address_completion_start(meet
->window
);
1573 accounts
= account_get_list();
1574 g_return_val_if_fail(accounts
!= NULL
, NULL
);
1576 for (i
= 0; accounts
!= NULL
; accounts
= accounts
->next
) {
1577 PrefsAccount
*ac
= (PrefsAccount
*)accounts
->data
;
1579 if (ac
->protocol
== A_NNTP
) {
1582 if (!event
&& ac
== account_get_cur_account()) {
1585 else if (event
&& !strcmp(ac
->address
, event
->organizer
))
1588 meet
->avail_accounts
= g_slist_append(meet
->avail_accounts
, ac
);
1591 s
= g_strdup_printf("%s: %s <%s>",
1593 ac
->name
, ac
->address
);
1595 s
= g_strdup_printf("%s: %s",
1596 ac
->account_name
, ac
->address
);
1598 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(meet
->who
), s
);
1602 gtk_combo_box_set_active(GTK_COMBO_BOX(meet
->who
), num
);
1604 save_hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 6);
1605 gtk_box_pack_start(GTK_BOX(save_hbox
), meet
->save_btn
, FALSE
, FALSE
, 0);
1606 gtk_box_pack_start(GTK_BOX(save_hbox
), meet
->avail_btn
, FALSE
, FALSE
, 0);
1607 gtk_box_pack_start(GTK_BOX(save_hbox
), meet
->total_avail_evtbox
, FALSE
, FALSE
, 0);
1608 gtk_box_pack_start(GTK_BOX(save_hbox
), meet
->total_avail_msg
, FALSE
, FALSE
, 0);
1610 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 6);
1611 gtk_box_pack_start(GTK_BOX(hbox
), meet
->avail_evtbox
, FALSE
, FALSE
, 0);
1612 gtk_box_pack_start(GTK_BOX(hbox
), meet
->who
, TRUE
, TRUE
, 0);
1614 gtk_widget_set_size_request(meet
->avail_evtbox
, 18, 16);
1615 gtk_event_box_set_visible_window(GTK_EVENT_BOX(meet
->avail_evtbox
), FALSE
);
1616 gtk_container_add (GTK_CONTAINER(meet
->avail_evtbox
), meet
->avail_img
);
1618 #ifndef GENERIC_UMPC
1619 TABLE_ADD_LINE(_("Organizer:"), hbox
, FALSE
);
1620 TABLE_ADD_LINE(_("Summary:"), meet
->summary
, TRUE
);
1621 TABLE_ADD_LINE(_("Time:"), date_hbox
, TRUE
);
1622 TABLE_ADD_LINE(_("Location:"), meet
->location
, TRUE
);
1623 TABLE_ADD_LINE(_("Description:"), scrolledwin
, TRUE
);
1624 TABLE_ADD_LINE(_("Attendees:"), meet
->attendees_vbox
, FALSE
);
1625 TABLE_ADD_LINE("", save_hbox
, TRUE
);
1627 gtk_widget_set_size_request(meet
->window
, -1, -1);
1628 gtk_container_add(GTK_CONTAINER(meet
->window
), meet
->table
);
1630 TABLE_ADD_LINE(_("Organizer:"), hbox
, FALSE
, TRUE
);
1631 TABLE_ADD_LINE(_("Summary:"), meet
->summary
, TRUE
, TRUE
);
1632 TABLE_ADD_LINE(_("Location:"), meet
->location
, FALSE
, TRUE
);
1633 TABLE_ADD_LINE(_("Description:"), scrolledwin
, TRUE
, TRUE
);
1634 TABLE_ADD_LINE(_("Attendees:"), meet
->attendees_vbox
, FALSE
, TRUE
);
1635 TABLE_ADD_LINE("", date_hbox
, TRUE
, FALSE
);
1637 notebook
= gtk_notebook_new ();
1638 gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook
), FALSE
);
1639 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
),
1641 gtk_label_new_with_mnemonic(_("Event:")));
1643 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
),
1645 gtk_label_new_with_mnemonic(_("Time:")));
1646 gtk_widget_show (notebook
);
1648 maemo_vbox0
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 3);
1649 gtk_box_pack_start(GTK_BOX(maemo_vbox0
), notebook
, TRUE
, TRUE
, 0);
1650 gtk_box_pack_start(GTK_BOX(maemo_vbox0
), save_hbox
, FALSE
, FALSE
, 0);
1652 gtk_widget_set_size_request(meet
->window
, -1, -1);
1653 gtk_container_add (GTK_CONTAINER (meet
->window
), maemo_vbox0
);
1655 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(meet
->window
));
1659 gtk_widget_show_all(meet
->window
);
1660 for (cur
= meet
->attendees
; cur
; cur
= cur
->next
) {
1661 gtk_widget_hide(((VCalAttendee
*)cur
->data
)->avail_img
);
1663 gtk_widget_hide(meet
->avail_img
);
1664 gtk_widget_hide(meet
->total_avail_img
);
1665 gtk_widget_set_sensitive(meet
->avail_btn
, avail_btn_can_be_sensitive());
1671 VCalMeeting
*vcal_meeting_create(VCalEvent
*event
)
1673 return vcal_meeting_create_real(event
, TRUE
);
1676 VCalMeeting
*vcal_meeting_create_with_start(VCalEvent
*event
, struct tm
*sdate
)
1678 VCalMeeting
*meet
= vcal_meeting_create(event
);
1680 gtk_calendar_select_day(GTK_CALENDAR(meet
->start_c
),
1682 gtk_calendar_select_day(GTK_CALENDAR(meet
->end_c
),
1685 gtk_calendar_select_month(GTK_CALENDAR(meet
->start_c
),
1686 sdate
->tm_mon
, sdate
->tm_year
+1900);
1687 gtk_calendar_select_month(GTK_CALENDAR(meet
->end_c
),
1688 sdate
->tm_mon
, sdate
->tm_year
+1900);
1690 if (sdate
->tm_hour
!= 0) {
1691 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->start_time
), sdate
->tm_hour
, 0);
1693 if (sdate
->tm_hour
< 23) {
1694 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->end_time
), sdate
->tm_hour
+1, 0);
1696 struct tm tm_tomorrow
;
1698 tm_tomorrow
.tm_mday
= sdate
->tm_mday
;
1699 tm_tomorrow
.tm_mon
= sdate
->tm_mon
;
1700 tm_tomorrow
.tm_wday
= sdate
->tm_wday
;
1701 tm_tomorrow
.tm_year
= sdate
->tm_year
+1900;
1702 tm_tomorrow
.tm_hour
= sdate
->tm_hour
;
1703 orage_move_day(&tm_tomorrow
, +1);
1704 gtk_calendar_select_day(GTK_CALENDAR(meet
->end_c
),
1705 tm_tomorrow
.tm_mday
);
1706 gtk_calendar_select_month(GTK_CALENDAR(meet
->end_c
),
1707 tm_tomorrow
.tm_mon
, tm_tomorrow
.tm_year
);
1709 gtkut_time_select_select_by_time(GTK_COMBO_BOX(meet
->end_time
), 0, 0);
1715 VCalMeeting
*vcal_meeting_create_hidden(VCalEvent
*event
)
1717 return vcal_meeting_create_real(event
, FALSE
);
1720 gboolean
vcal_meeting_send(VCalMeeting
*meet
)
1722 return send_meeting_cb(NULL
, meet
);
1725 gboolean
vcal_meeting_alert_check(gpointer data
)
1727 GSList
*events
= NULL
, *cur
= NULL
;
1729 if (!vcalprefs
.alert_enable
)
1732 events
= vcal_folder_get_waiting_events();
1734 for (cur
= events
; cur
; cur
= cur
->next
) {
1735 VCalEvent
*event
= (VCalEvent
*)cur
->data
;
1736 time_t start
, end
, current
;
1737 gboolean warn
= FALSE
;
1741 start
= icaltime_as_timet(icaltime_from_string(event
->dtstart
));
1742 end
= icaltime_as_timet(icaltime_from_string(event
->dtend
));
1743 current
= time(NULL
);
1745 if (start
- current
<= (vcalprefs
.alert_delay
*60)
1746 && start
- current
+ 60 > (vcalprefs
.alert_delay
*60)) {
1748 } else if (event
->postponed
- current
<= (vcalprefs
.alert_delay
*60)
1749 && event
->postponed
- current
+ 60 > (vcalprefs
.alert_delay
*60)) {
1753 time_t tmpt
= icaltime_as_timet((icaltime_from_string(event
->dtstart
)));
1754 gchar
*estart
= NULL
;
1756 int length
= (end
- start
) / 60;
1757 gchar
*duration
= NULL
, *hours
= NULL
, *minutes
= NULL
;
1758 gchar
*message
= NULL
;
1759 gchar
*title
= NULL
;
1760 gchar
*label
= NULL
;
1761 int postpone_min
= 0;
1765 estart
= g_strdup(ctime(&tmpt
));
1768 hours
= g_strdup_printf(ngettext("%d hour", "%d hours",
1769 (length
/60) > 1 ? 2 : 1), length
/60);
1771 minutes
= g_strdup_printf(ngettext("%d minute", "%d minutes",
1772 length
%60), length
%60);
1774 duration
= g_strdup_printf("%s%s%s",
1776 hours
&& minutes
? " ":"",
1777 minutes
?minutes
:"");
1782 title
= g_strdup_printf(_("Upcoming event: %s"), event
->summary
);
1783 message
= g_strdup_printf(_("You have a meeting or event soon.\n"
1784 "It starts at %s and ends %s later.\n"
1786 "More information:\n\n"
1790 event
->location
?event
->location
:"",
1791 event
->description
);
1796 postpone_min
= (vcalprefs
.alert_delay
/2 > 15) ? 15: (vcalprefs
.alert_delay
/2);
1797 if (postpone_min
== 0)
1800 label
= g_strdup_printf(ngettext("Remind me in %d minute", "Remind me in %d minutes",
1801 postpone_min
> 1 ? 2:1),
1803 aval
= alertpanel_full(title
, message
,
1804 NULL
, label
, NULL
, _("_OK"), NULL
, NULL
,
1805 ALERTFOCUS_FIRST
, FALSE
, NULL
, ALERT_NOTICE
);
1811 if (aval
== G_ALERTDEFAULT
) {
1812 if (event
->postponed
== 0)
1813 event
->postponed
= start
+ (postpone_min
*60);
1815 event
->postponed
+= (postpone_min
*60);
1817 event
->postponed
= (time_t)0;
1819 vcal_manager_save_event(event
, FALSE
);
1822 vcal_manager_free_event((VCalEvent
*)cur
->data
);
1825 g_slist_free(events
);
1830 void multisync_export(void)
1832 GSList
*list
= NULL
;
1833 gchar
*path
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
1834 "vcalendar", G_DIR_SEPARATOR_S
,
1836 GSList
*files
= NULL
;
1840 icalcomponent
*calendar
= NULL
;
1843 if (is_dir_exist(path
) && remove_dir_recursive(path
) < 0) {
1847 if (make_dir(path
) != 0) {
1852 list
= vcal_folder_get_waiting_events();
1853 for (cur
= list
; cur
; cur
= cur
->next
) {
1855 VCalEvent
*event
= (VCalEvent
*)cur
->data
;
1856 gchar
*file
= g_strdup_printf("multisync%"CM_TIME_FORMAT
"-%d",
1862 icalcomponent_vanew(
1863 ICAL_VCALENDAR_COMPONENT
,
1864 icalproperty_new_version("2.0"),
1865 icalproperty_new_prodid(
1866 "-//Claws Mail//NONSGML Claws Mail Calendar//EN"),
1867 icalproperty_new_calscale("GREGORIAN"),
1870 vcal_manager_event_dump(event
, FALSE
, FALSE
, calendar
, FALSE
);
1871 tmp
= g_strconcat(path
, G_DIR_SEPARATOR_S
, file
, NULL
);
1872 str_write_to_file(icalcomponent_as_ical_string(calendar
), tmp
, TRUE
);
1874 files
= g_slist_append(files
, file
);
1875 vcal_manager_free_event(event
);
1876 icalcomponent_free(calendar
);
1881 backup_file
= g_strconcat(path
, G_DIR_SEPARATOR_S
, "backup_entries", NULL
);
1882 fp
= claws_fopen(backup_file
, "wb");
1884 for (cur
= files
; cur
; cur
= cur
->next
) {
1885 gchar
* file
= (char *)cur
->data
;
1886 if (fprintf(fp
, "1 1 %s\n", file
) < 0)
1887 FILE_OP_ERROR(file
, "fprintf");
1890 if (claws_safe_fclose(fp
) == EOF
)
1891 FILE_OP_ERROR(backup_file
, "claws_fclose");
1893 FILE_OP_ERROR(backup_file
, "claws_fopen");
1895 g_free(backup_file
);
1897 g_slist_free(files
);
1900 gboolean
vcal_meeting_export_calendar(const gchar
*path
,
1901 const gchar
*user
, const gchar
*pass
,
1904 GSList
*list
= vcal_folder_get_waiting_events();
1905 GSList
*subs
= NULL
;
1907 icalcomponent
*calendar
= NULL
;
1909 gchar
*tmpfile
= get_tmp_file();
1910 gchar
*internal_file
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
1911 "vcalendar", G_DIR_SEPARATOR_S
,
1912 "internal.ics", NULL
);
1914 gboolean res
= TRUE
;
1919 if (vcalprefs
.export_subs
&& vcalprefs
.export_enable
)
1920 subs
= vcal_folder_get_webcal_events();
1922 if (g_slist_length(list
) == 0 && g_slist_length(subs
) == 0) {
1926 alertpanel_full(_("Empty calendar"),
1927 _("There is nothing to export."),
1928 NULL
, _("_OK"), NULL
, NULL
, NULL
, NULL
,
1929 ALERTFOCUS_FIRST
, FALSE
, NULL
, ALERT_NOTICE
);
1931 g_free(internal_file
);
1934 str_write_to_file("", tmpfile
, TRUE
);
1940 icalcomponent_vanew(
1941 ICAL_VCALENDAR_COMPONENT
,
1942 icalproperty_new_version("2.0"),
1943 icalproperty_new_prodid(
1944 "-//Claws Mail//NONSGML Claws Mail Calendar//EN"),
1945 icalproperty_new_calscale("GREGORIAN"),
1949 for (cur
= list
; cur
; cur
= cur
->next
) {
1950 VCalEvent
*event
= (VCalEvent
*)cur
->data
;
1951 vcal_manager_event_dump(event
, FALSE
, FALSE
, calendar
, FALSE
);
1952 vcal_manager_free_event(event
);
1955 if (str_write_to_file(icalcomponent_as_ical_string(calendar
), internal_file
, TRUE
) < 0) {
1956 g_warning("can't export internal cal");
1959 for (cur
= subs
; cur
; cur
= cur
->next
) {
1960 /* Not to be freed */
1961 icalcomponent
*event
= (icalcomponent
*)cur
->data
;
1962 vcal_manager_icalevent_dump(event
, NULL
, calendar
);
1965 if (vcalprefs
.export_enable
|| path
== NULL
) {
1966 if (str_write_to_file(icalcomponent_as_ical_string(calendar
), tmpfile
, TRUE
) < 0) {
1967 alertpanel_error(_("Could not export the calendar."));
1969 icalcomponent_free(calendar
);
1974 filesize
= strlen(icalcomponent_as_ical_string(calendar
));
1977 icalcomponent_free(calendar
);
1980 g_free(internal_file
);
1984 if (automatic
&& (!path
|| strlen(path
) == 0 || !vcalprefs
.export_enable
)) {
1989 if (!path
&& !automatic
)
1990 file
= filesel_select_file_save(_("Export calendar to ICS"), NULL
);
1992 file
= g_strdup(path
);
1995 && strncmp(file
, "http://", 7)
1996 && strncmp(file
, "https://", 8)
1997 && strncmp(file
, "webcal://", 9)
1998 && strncmp(file
, "webcals://", 10)
1999 && strncmp(file
, "ftp://", 6)) {
2001 if (file
[0] != G_DIR_SEPARATOR
)
2002 afile
= g_strdup_printf("%s%s%s", get_home_dir(),
2003 G_DIR_SEPARATOR_S
, file
);
2005 afile
= g_strdup(file
);
2006 if (move_file(tmpfile
, afile
, TRUE
) != 0) {
2007 log_error(LOG_PROTOCOL
, _("Couldn't export calendar to '%s'\n"),
2013 FILE *fp
= claws_fopen(tmpfile
, "rb");
2014 if (!strncmp(file
, "webcal", 6)) {
2015 gchar
*tmp
= g_strdup_printf("http%s", file
+6);
2020 res
= vcal_curl_put(file
, fp
, filesize
, user
, (pass
!= NULL
? pass
: ""));
2030 gboolean
vcal_meeting_export_freebusy(const gchar
*path
, const gchar
*user
,
2033 GSList
*list
= vcal_folder_get_waiting_events();
2035 icalcomponent
*calendar
= NULL
, *timezone
= NULL
, *tzc
= NULL
, *vfreebusy
= NULL
;
2037 gchar
*tmpfile
= get_tmp_file();
2038 gchar
*internal_file
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
2039 "vcalendar", G_DIR_SEPARATOR_S
,
2040 "internal.ifb", NULL
);
2041 time_t whole_start
= time(NULL
);
2042 time_t whole_end
= whole_start
+ (60*60*24*365);
2043 gboolean res
= TRUE
;
2044 struct icaltimetype itt_start
, itt_end
;
2050 icalcomponent_vanew(
2051 ICAL_VCALENDAR_COMPONENT
,
2052 icalproperty_new_version("2.0"),
2053 icalproperty_new_prodid(
2054 "-//Claws Mail//NONSGML Claws Mail Calendar//EN"),
2055 icalproperty_new_calscale("GREGORIAN"),
2059 timezone
= icalcomponent_new(ICAL_VTIMEZONE_COMPONENT
);
2061 icalcomponent_add_property(timezone
,
2062 icalproperty_new_tzid("UTC"));
2064 tzc
= icalcomponent_new(ICAL_XSTANDARD_COMPONENT
);
2065 icalcomponent_add_property(tzc
,
2066 icalproperty_new_dtstart(
2067 icaltime_from_string("19700101T000000")));
2068 icalcomponent_add_property(tzc
,
2069 icalproperty_new_tzoffsetfrom(0.0));
2070 icalcomponent_add_property(tzc
,
2071 icalproperty_new_tzoffsetto(0.0));
2072 icalcomponent_add_property(tzc
,
2073 icalproperty_new_tzname("Greenwich meridian time"));
2075 icalcomponent_add_component(timezone
, tzc
);
2077 icalcomponent_add_component(calendar
, timezone
);
2079 itt_start
= icaltime_from_timet_with_zone(whole_start
, FALSE
, NULL
);
2080 itt_end
= icaltime_from_timet_with_zone(whole_end
, FALSE
, NULL
);
2081 itt_start
.second
= itt_start
.minute
= itt_start
.hour
= 0;
2082 itt_end
.second
= 59; itt_end
.minute
= 59; itt_end
.hour
= 23;
2086 icalcomponent_vanew(
2087 ICAL_VFREEBUSY_COMPONENT
,
2088 icalproperty_vanew_dtstart(itt_start
, 0),
2089 icalproperty_vanew_dtend(itt_end
, 0),
2093 debug_print("DTSTART:%s\nDTEND:%s\n",
2094 icaltime_as_ical_string(itt_start
),
2095 icaltime_as_ical_string(itt_end
));
2097 for (cur
= list
; cur
; cur
= cur
->next
) {
2098 VCalEvent
*event
= (VCalEvent
*)cur
->data
;
2100 struct icalperiodtype ipt
;
2102 ipt
.start
= icaltime_from_string(event
->dtstart
);
2103 ipt
.end
= icaltime_from_string(event
->dtend
);
2104 ipt
.duration
= icaltime_subtract(ipt
.end
, ipt
.start
);
2105 if (icaltime_as_timet(ipt
.start
) <= icaltime_as_timet(itt_end
)
2106 && icaltime_as_timet(ipt
.end
) >= icaltime_as_timet(itt_start
)) {
2107 prop
= icalproperty_new_freebusy(ipt
);
2108 icalcomponent_add_property(vfreebusy
, prop
);
2110 vcal_manager_free_event(event
);
2113 icalcomponent_add_component(calendar
, vfreebusy
);
2115 if (str_write_to_file(icalcomponent_as_ical_string(calendar
), internal_file
, TRUE
) < 0) {
2116 g_warning("can't export freebusy");
2119 g_free(internal_file
);
2121 if (vcalprefs
.export_freebusy_enable
) {
2122 if (str_write_to_file(icalcomponent_as_ical_string(calendar
), tmpfile
, TRUE
) < 0) {
2123 alertpanel_error(_("Could not export the freebusy info."));
2125 icalcomponent_free(calendar
);
2129 filesize
= strlen(icalcomponent_as_ical_string(calendar
));
2132 icalcomponent_free(calendar
);
2135 if ((!path
|| strlen(path
) == 0 || !vcalprefs
.export_freebusy_enable
)) {
2140 file
= g_strdup(path
);
2143 && strncmp(file
, "http://", 7)
2144 && strncmp(file
, "https://", 8)
2145 && strncmp(file
, "webcal://", 9)
2146 && strncmp(file
, "webcals://", 10)
2147 && strncmp(file
, "ftp://", 6)) {
2149 if (file
[0] != G_DIR_SEPARATOR
)
2150 afile
= g_strdup_printf("%s%s%s", get_home_dir(),
2151 G_DIR_SEPARATOR_S
, file
);
2153 afile
= g_strdup(file
);
2154 if (move_file(tmpfile
, file
, TRUE
) != 0) {
2155 log_error(LOG_PROTOCOL
, _("Couldn't export free/busy to '%s'\n"),
2161 FILE *fp
= claws_fopen(tmpfile
, "rb");
2162 if (!strncmp(file
, "webcal", 6)) {
2163 gchar
*tmp
= g_strdup_printf("http%s", file
+6);
2168 res
= vcal_curl_put(file
, fp
, filesize
, user
, (pass
!= NULL
? pass
: ""));