2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
17 * JP Rosevear <jpr@ximian.com>
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
27 #include <glib/gi18n.h>
28 #include <libedataserver/e-time-utils.h>
30 #include <libical/ical.h>
31 #include <e-util/e-dialog-utils.h>
32 #include <libecal/e-cal-time-util.h>
33 #include <libecal/e-cal-util.h>
34 #include <libsoup/soup.h>
35 #include "itip-utils.h"
37 #include "dialogs/comp-editor-util.h"
39 #include <composer/e-msg-composer.h>
41 static const gchar
*itip_methods
[] = {
52 static icalproperty_method itip_methods_enum
[] = {
60 ICAL_METHOD_DECLINECOUNTER
,
63 static EAccountList
*accounts
= NULL
;
66 itip_addresses_get (void)
68 if (accounts
== NULL
) {
69 GConfClient
*gconf_client
= gconf_client_get_default ();
70 accounts
= e_account_list_new (gconf_client
);
71 g_object_unref (gconf_client
);
78 itip_addresses_get_default (void)
80 return (EAccount
*)e_account_list_get_default (itip_addresses_get ());
84 itip_organizer_is_user_ex (ECalComponent
*comp
, ECal
*client
, gboolean skip_cap_test
)
86 ECalComponentOrganizer organizer
;
88 gboolean user_org
= FALSE
;
90 if (!e_cal_component_has_organizer (comp
) || (!skip_cap_test
&& e_cal_get_static_capability (client
, CAL_STATIC_CAPABILITY_NO_ORGANIZER
)))
93 e_cal_component_get_organizer (comp
, &organizer
);
94 if (organizer
.value
!= NULL
) {
96 strip
= itip_strip_mailto (organizer
.value
);
98 if (e_cal_get_static_capability (client
, CAL_STATIC_CAPABILITY_ORGANIZER_NOT_EMAIL_ADDRESS
)) {
101 if (e_cal_get_cal_address (client
, &email
, NULL
) && !g_ascii_strcasecmp (email
, strip
)) {
111 user_org
= e_account_list_find (itip_addresses_get (), E_ACCOUNT_FIND_ID_ADDRESS
, strip
) != NULL
;
118 itip_organizer_is_user (ECalComponent
*comp
, ECal
*client
)
120 return itip_organizer_is_user_ex (comp
, client
, FALSE
);
124 itip_sentby_is_user (ECalComponent
*comp
, ECal
*client
)
126 ECalComponentOrganizer organizer
;
128 gboolean user_sentby
= FALSE
;
130 if (!e_cal_component_has_organizer (comp
) ||e_cal_get_static_capability (client
, CAL_STATIC_CAPABILITY_NO_ORGANIZER
))
133 e_cal_component_get_organizer (comp
, &organizer
);
134 if (organizer
.sentby
!= NULL
) {
135 strip
= itip_strip_mailto (organizer
.sentby
);
136 user_sentby
= e_account_list_find (itip_addresses_get (), E_ACCOUNT_FIND_ID_ADDRESS
, strip
) != NULL
;
142 static ECalComponentAttendee
*
143 get_attendee (GSList
*attendees
, gchar
*address
)
150 for (l
= attendees
; l
; l
= l
->next
) {
151 ECalComponentAttendee
*attendee
= l
->data
;
153 if (!g_ascii_strcasecmp (itip_strip_mailto (attendee
->value
), address
)) {
161 static ECalComponentAttendee
*
162 get_attendee_if_attendee_sentby_is_user (GSList
*attendees
, gchar
*address
)
166 for (l
= attendees
; l
; l
= l
->next
) {
167 ECalComponentAttendee
*attendee
= l
->data
;
169 if (attendee
->sentby
&& g_str_equal (itip_strip_mailto (attendee
->sentby
), address
)) {
178 html_new_lines_for (const gchar
*string
)
183 lines
= g_strsplit_set (string
, "\n", -1);
184 joined
= g_strjoinv ("<br>", lines
);
191 itip_get_comp_attendee (ECalComponent
*comp
, ECal
*client
)
197 ECalComponentAttendee
*attendee
= NULL
;
198 gchar
*address
= NULL
;
200 e_cal_component_get_attendee_list (comp
, &attendees
);
201 al
= itip_addresses_get ();
204 e_cal_get_cal_address (client
, &address
, NULL
);
206 if (address
&& *address
) {
207 attendee
= get_attendee (attendees
, address
);
210 gchar
*user_email
= g_strdup (itip_strip_mailto (attendee
->value
));
212 e_cal_component_free_attendee_list (attendees
);
217 attendee
= get_attendee_if_attendee_sentby_is_user (attendees
, address
);
220 gchar
*user_email
= g_strdup (itip_strip_mailto (attendee
->sentby
));
222 e_cal_component_free_attendee_list (attendees
);
231 for (it
= e_list_get_iterator ((EList
*)al
);
232 e_iterator_is_valid (it
);
233 e_iterator_next (it
)) {
234 a
= (EAccount
*) e_iterator_get (it
);
239 attendee
= get_attendee (attendees
, a
->id
->address
);
241 gchar
*user_email
= g_strdup (itip_strip_mailto (attendee
->value
));
243 e_cal_component_free_attendee_list (attendees
);
247 /* If the account was not found in the attendees list, then let's
248 check the 'sentby' fields of the attendees if we can find the account */
249 attendee
= get_attendee_if_attendee_sentby_is_user (attendees
, a
->id
->address
);
251 gchar
*user_email
= g_strdup (itip_strip_mailto (attendee
->sentby
));
253 e_cal_component_free_attendee_list (attendees
);
258 /* We could not find the attendee in the component, so just give the default
259 account address if the email address is not set in the backend */
260 /* FIXME do we have a better way ? */
261 a
= itip_addresses_get_default ();
262 address
= g_strdup ((a
!= NULL
) ? a
->id
->address
: "");
264 e_cal_component_free_attendee_list (attendees
);
269 itip_strip_mailto (const gchar
*address
)
274 if (!g_ascii_strncasecmp (address
, "mailto:", 7))
281 get_label (struct icaltimetype
*tt
,
282 gboolean use_24_hour_format
)
287 tmp_tm
= icaltimetype_to_tm (tt
);
289 e_time_format_date_and_time (
290 &tmp_tm
, use_24_hour_format
, FALSE
, FALSE
, buffer
, 1000);
292 return g_strdup (buffer
);
297 icalcomponent
*icomp
;
299 icalcomponent
*zones
;
303 foreach_tzid_callback (icalparameter
*param
, gpointer data
)
305 ItipUtilTZData
*tz_data
= data
;
307 icaltimezone
*zone
= NULL
;
308 icalcomponent
*vtimezone_comp
;
310 /* Get the TZID string from the parameter. */
311 tzid
= icalparameter_get_tzid (param
);
312 if (!tzid
|| g_hash_table_lookup (tz_data
->tzids
, tzid
))
315 /* Look for the timezone */
316 if (tz_data
->zones
!= NULL
)
317 zone
= icalcomponent_get_timezone (tz_data
->zones
, tzid
);
319 zone
= icaltimezone_get_builtin_timezone_from_tzid (tzid
);
320 if (zone
== NULL
&& tz_data
->client
!= NULL
)
321 e_cal_get_timezone (tz_data
->client
, tzid
, &zone
, NULL
);
325 /* Convert it to a string and add it to the hash. */
326 vtimezone_comp
= icaltimezone_get_component (zone
);
330 icalcomponent_add_component (tz_data
->icomp
, icalcomponent_new_clone (vtimezone_comp
));
331 g_hash_table_insert (tz_data
->tzids
, (gchar
*)tzid
, (gchar
*)tzid
);
334 static icalcomponent
*
335 comp_toplevel_with_zones (ECalComponentItipMethod method
, ECalComponent
*comp
, ECal
*client
, icalcomponent
*zones
)
337 icalcomponent
*top_level
, *icomp
;
340 ItipUtilTZData tz_data
;
342 top_level
= e_cal_util_new_top_level ();
344 prop
= icalproperty_new (ICAL_METHOD_PROPERTY
);
345 value
= icalvalue_new_method (itip_methods_enum
[method
]);
346 icalproperty_set_value (prop
, value
);
347 icalcomponent_add_property (top_level
, prop
);
349 icomp
= e_cal_component_get_icalcomponent (comp
);
350 icomp
= icalcomponent_new_clone (icomp
);
352 tz_data
.tzids
= g_hash_table_new (g_str_hash
, g_str_equal
);
353 tz_data
.icomp
= top_level
;
354 tz_data
.client
= client
;
355 tz_data
.zones
= zones
;
356 icalcomponent_foreach_tzid (icomp
, foreach_tzid_callback
, &tz_data
);
357 g_hash_table_destroy (tz_data
.tzids
);
359 icalcomponent_add_component (top_level
, icomp
);
365 users_has_attendee (GList
*users
, const gchar
*address
)
369 for (l
= users
; l
!= NULL
; l
= l
->next
) {
370 if (!g_ascii_strcasecmp (address
, l
->data
))
378 comp_from (ECalComponentItipMethod method
, ECalComponent
*comp
)
380 ECalComponentOrganizer organizer
;
381 ECalComponentAttendee
*attendee
;
384 gchar
*sender
= NULL
;
387 case E_CAL_COMPONENT_METHOD_PUBLISH
:
390 case E_CAL_COMPONENT_METHOD_REQUEST
:
391 return itip_get_comp_attendee (comp
, NULL
);
393 case E_CAL_COMPONENT_METHOD_REPLY
:
394 sender
= itip_get_comp_attendee (comp
, NULL
);
397 if (!e_cal_component_has_attendees (comp
))
400 case E_CAL_COMPONENT_METHOD_CANCEL
:
402 case E_CAL_COMPONENT_METHOD_ADD
:
404 e_cal_component_get_organizer (comp
, &organizer
);
405 if (organizer
.value
== NULL
) {
406 e_notice (NULL
, GTK_MESSAGE_ERROR
,
407 _("An organizer must be set."));
410 return g_strdup (itip_strip_mailto (organizer
.value
));
413 if (!e_cal_component_has_attendees (comp
))
416 e_cal_component_get_attendee_list (comp
, &attendees
);
417 attendee
= attendees
->data
;
418 if (attendee
->value
!= NULL
)
419 from
= g_strdup (itip_strip_mailto (attendee
->value
));
422 e_cal_component_free_attendee_list (attendees
);
428 static EDestination
**
429 comp_to_list (ECalComponentItipMethod method
, ECalComponent
*comp
, GList
*users
, gboolean reply_all
, const GSList
*only_attendees
)
431 ECalComponentOrganizer organizer
;
432 GSList
*attendees
, *l
;
433 GPtrArray
*array
= NULL
;
434 EDestination
*destination
;
436 gchar
*sender
= NULL
;
440 EDestination
**destinations
;
444 case E_CAL_COMPONENT_METHOD_REQUEST
:
445 case E_CAL_COMPONENT_METHOD_CANCEL
:
446 e_cal_component_get_attendee_list (comp
, &attendees
);
447 len
= g_slist_length (attendees
);
449 e_notice (NULL
, GTK_MESSAGE_ERROR
,
450 _("At least one attendee is necessary"));
451 e_cal_component_free_attendee_list (attendees
);
455 e_cal_component_get_organizer (comp
, &organizer
);
456 if (organizer
.value
== NULL
) {
457 e_notice (NULL
, GTK_MESSAGE_ERROR
,
458 _("An organizer must be set."));
462 array
= g_ptr_array_new ();
464 sender
= itip_get_comp_attendee (comp
, NULL
);
466 for (l
= attendees
; l
!= NULL
; l
= l
->next
) {
467 ECalComponentAttendee
*att
= l
->data
;
469 if (att
->cutype
!= ICAL_CUTYPE_INDIVIDUAL
&& att
->cutype
!= ICAL_CUTYPE_GROUP
)
471 else if (users_has_attendee (users
, att
->value
))
473 else if (att
->sentby
&& users_has_attendee (users
, att
->sentby
))
475 else if (!g_ascii_strcasecmp (att
->value
, organizer
.value
))
477 else if (att
->sentby
&& !g_ascii_strcasecmp (att
->sentby
, organizer
.sentby
))
479 else if (!g_ascii_strcasecmp (itip_strip_mailto (att
->value
), sender
))
481 else if (att
->status
== ICAL_PARTSTAT_DELEGATED
&& (att
->delto
&& *att
->delto
)
482 && !(att
->rsvp
) && method
== E_CAL_COMPONENT_METHOD_REQUEST
)
484 else if (only_attendees
&& !comp_editor_have_in_new_attendees_lst (only_attendees
, itip_strip_mailto (att
->value
)))
487 destination
= e_destination_new ();
489 e_destination_set_name (destination
, att
->cn
);
490 e_destination_set_email (
491 destination
, itip_strip_mailto (att
->value
));
492 g_ptr_array_add (array
, destination
);
495 e_cal_component_free_attendee_list (attendees
);
498 case E_CAL_COMPONENT_METHOD_REPLY
:
501 e_cal_component_get_attendee_list (comp
, &attendees
);
502 len
= g_slist_length (attendees
);
507 array
= g_ptr_array_new ();
509 e_cal_component_get_organizer (comp
, &organizer
);
510 sender
= itip_get_comp_attendee (comp
, NULL
);
512 for (l
= attendees
; l
!= NULL
; l
= l
->next
) {
513 ECalComponentAttendee
*att
= l
->data
;
515 if (att
->cutype
!= ICAL_CUTYPE_INDIVIDUAL
&& att
->cutype
!= ICAL_CUTYPE_GROUP
)
517 else if (only_attendees
&& !comp_editor_have_in_new_attendees_lst (only_attendees
, itip_strip_mailto (att
->value
)))
520 destination
= e_destination_new ();
522 e_destination_set_name (destination
, att
->cn
);
523 e_destination_set_email (
524 destination
, itip_strip_mailto (att
->value
));
525 g_ptr_array_add (array
, destination
);
529 e_cal_component_free_attendee_list (attendees
);
532 array
= g_ptr_array_new ();
534 destination
= e_destination_new ();
535 e_cal_component_get_organizer (comp
, &organizer
);
537 e_destination_set_email (
538 destination
, itip_strip_mailto (organizer
.value
));
539 g_ptr_array_add (array
, destination
);
543 case E_CAL_COMPONENT_METHOD_ADD
:
544 case E_CAL_COMPONENT_METHOD_REFRESH
:
545 case E_CAL_COMPONENT_METHOD_COUNTER
:
546 case E_CAL_COMPONENT_METHOD_DECLINECOUNTER
:
547 e_cal_component_get_organizer (comp
, &organizer
);
548 if (organizer
.value
== NULL
) {
549 e_notice (NULL
, GTK_MESSAGE_ERROR
,
550 _("An organizer must be set."));
554 array
= g_ptr_array_new ();
556 destination
= e_destination_new ();
557 if (organizer
.cn
!= NULL
)
558 e_destination_set_name (destination
, organizer
.cn
);
559 e_destination_set_email (
560 destination
, itip_strip_mailto (organizer
.value
));
561 g_ptr_array_add (array
, destination
);
563 /* send the status to delegatee to the delegate also*/
564 e_cal_component_get_attendee_list (comp
, &attendees
);
565 sender
= itip_get_comp_attendee (comp
, NULL
);
567 for (l
= attendees
; l
!= NULL
; l
= l
->next
) {
568 ECalComponentAttendee
*att
= l
->data
;
570 if (att
->cutype
!= ICAL_CUTYPE_INDIVIDUAL
&& att
->cutype
!= ICAL_CUTYPE_GROUP
)
573 if (!g_ascii_strcasecmp (itip_strip_mailto (att
->value
), sender
) || (att
->sentby
&& !g_ascii_strcasecmp (itip_strip_mailto (att
->sentby
), sender
))) {
575 if (!(att
->delfrom
&& *att
->delfrom
))
578 destination
= e_destination_new ();
579 e_destination_set_email (
580 destination
, itip_strip_mailto (att
->delfrom
));
581 g_ptr_array_add (array
, destination
);
585 e_cal_component_free_attendee_list (attendees
);
588 case E_CAL_COMPONENT_METHOD_PUBLISH
:
592 array
= g_ptr_array_new ();
594 for (list
= users
; list
!= NULL
; list
= list
->next
) {
595 destination
= e_destination_new ();
596 e_destination_set_email (destination
, list
->data
);
597 g_ptr_array_add (array
, destination
);
609 g_ptr_array_add (array
, NULL
);
610 convert
.pdata
= g_ptr_array_free (array
, FALSE
);
612 return convert
.destinations
;
616 comp_subject (ECalComponentItipMethod method
, ECalComponent
*comp
)
618 ECalComponentText caltext
;
619 const gchar
*description
, *prefix
= NULL
;
623 ECalComponentAttendee
*a
= NULL
;
625 e_cal_component_get_summary (comp
, &caltext
);
626 if (caltext
.value
!= NULL
)
627 description
= caltext
.value
;
629 switch (e_cal_component_get_vtype (comp
)) {
630 case E_CAL_COMPONENT_EVENT
:
631 description
= _("Event information");
633 case E_CAL_COMPONENT_TODO
:
634 description
= _("Task information");
636 case E_CAL_COMPONENT_JOURNAL
:
637 description
= _("Memo information");
639 case E_CAL_COMPONENT_FREEBUSY
:
640 description
= _("Free/Busy information");
643 description
= _("Calendar information");
648 case E_CAL_COMPONENT_METHOD_PUBLISH
:
649 case E_CAL_COMPONENT_METHOD_REQUEST
:
650 /* FIXME: If this is an update to a previous
651 * PUBLISH or REQUEST, then
652 prefix = U_("Updated");
656 case E_CAL_COMPONENT_METHOD_REPLY
:
657 e_cal_component_get_attendee_list (comp
, &alist
);
658 sender
= itip_get_comp_attendee (comp
, NULL
);
661 for (l
= alist
; l
!= NULL
; l
= l
->next
) {
663 if ((sender
&& *sender
) && (g_ascii_strcasecmp (itip_strip_mailto (a
->value
), sender
) || (a
->sentby
&& g_ascii_strcasecmp (itip_strip_mailto (a
->sentby
), sender
))))
672 case ICAL_PARTSTAT_ACCEPTED
:
673 /* Translators: This is part of the subject
674 * line of a meeting request or update email.
675 * The full subject line would be:
676 * "Accepted: Meeting Name". */
677 prefix
= C_("Meeting", "Accepted");
679 case ICAL_PARTSTAT_TENTATIVE
:
680 /* Translators: This is part of the subject
681 * line of a meeting request or update email.
682 * The full subject line would be:
683 * "Tentatively Accepted: Meeting Name". */
684 prefix
= C_("Meeting", "Tentatively Accepted");
686 case ICAL_PARTSTAT_DECLINED
:
687 /* Translators: This is part of the subject
688 * line of a meeting request or update email.
689 * The full subject line would be:
690 * "Declined: Meeting Name". */
691 prefix
= C_("Meeting", "Declined");
693 case ICAL_PARTSTAT_DELEGATED
:
694 /* Translators: This is part of the subject
695 * line of a meeting request or update email.
696 * The full subject line would be:
697 * "Delegated: Meeting Name". */
698 prefix
= C_("Meeting", "Delegated");
703 e_cal_component_free_attendee_list (alist
);
707 case E_CAL_COMPONENT_METHOD_ADD
:
708 /* Translators: This is part of the subject line of a
709 * meeting request or update email. The full subject
710 * line would be: "Updated: Meeting Name". */
711 prefix
= C_("Meeting", "Updated");
714 case E_CAL_COMPONENT_METHOD_CANCEL
:
715 /* Translators: This is part of the subject line of a
716 * meeting request or update email. The full subject
717 * line would be: "Cancel: Meeting Name". */
718 prefix
= C_("Meeting", "Cancel");
721 case E_CAL_COMPONENT_METHOD_REFRESH
:
722 /* Translators: This is part of the subject line of a
723 * meeting request or update email. The full subject
724 * line would be: "Refresh: Meeting Name". */
725 prefix
= C_("Meeting", "Refresh");
728 case E_CAL_COMPONENT_METHOD_COUNTER
:
729 /* Translators: This is part of the subject line of a
730 * meeting request or update email. The full subject
731 * line would be: "Counter-proposal: Meeting Name". */
732 prefix
= C_("Meeting", "Counter-proposal");
735 case E_CAL_COMPONENT_METHOD_DECLINECOUNTER
:
736 /* Translators: This is part of the subject line of a
737 * meeting request or update email. The full subject
738 * line would be: "Declined: Meeting Name". */
739 prefix
= C_("Meeting", "Declined");
747 subject
= g_strdup_printf ("%s: %s", prefix
, description
);
749 subject
= g_strdup (description
);
755 comp_content_type (ECalComponent
*comp
, ECalComponentItipMethod method
)
757 return g_strdup_printf (
758 "text/calendar; name=\"%s\"; charset=utf-8; METHOD=%s",
759 e_cal_component_get_vtype (comp
) == E_CAL_COMPONENT_FREEBUSY
?
760 "freebusy.ifb" : "calendar.ics", itip_methods
[method
]);
764 comp_filename (ECalComponent
*comp
)
766 if (e_cal_component_get_vtype (comp
) == E_CAL_COMPONENT_FREEBUSY
)
767 return "freebusy.ifb";
769 return "calendar.ics";
773 comp_description (ECalComponent
*comp
,
774 gboolean use_24_hour_format
)
777 ECalComponentDateTime dt
;
778 gchar
*start
= NULL
, *end
= NULL
;
780 switch (e_cal_component_get_vtype (comp
)) {
781 case E_CAL_COMPONENT_EVENT
:
782 description
= g_strdup (_("Event information"));
784 case E_CAL_COMPONENT_TODO
:
785 description
= g_strdup (_("Task information"));
787 case E_CAL_COMPONENT_JOURNAL
:
788 description
= g_strdup (_("Memo information"));
790 case E_CAL_COMPONENT_FREEBUSY
:
791 e_cal_component_get_dtstart (comp
, &dt
);
793 start
= get_label (dt
.value
, use_24_hour_format
);
794 e_cal_component_free_datetime (&dt
);
796 e_cal_component_get_dtend (comp
, &dt
);
798 end
= get_label (dt
.value
, use_24_hour_format
);
799 e_cal_component_free_datetime (&dt
);
801 if (start
!= NULL
&& end
!= NULL
)
802 description
= g_strdup_printf (
803 _("Free/Busy information (%s to %s)"),
806 description
= g_strdup (_("Free/Busy information"));
811 description
= g_strdup (_("iCalendar information"));
819 comp_server_send (ECalComponentItipMethod method
, ECalComponent
*comp
, ECal
*client
,
820 icalcomponent
*zones
, GList
**users
)
822 icalcomponent
*top_level
, *returned_icalcomp
= NULL
;
823 gboolean retval
= TRUE
;
824 GError
*error
= NULL
;
826 top_level
= comp_toplevel_with_zones (method
, comp
, client
, zones
);
827 if (!e_cal_send_objects (client
, top_level
, users
, &returned_icalcomp
, &error
)) {
828 /* FIXME Really need a book problem status code */
829 if (error
->code
!= E_CALENDAR_STATUS_OK
) {
830 if (error
->code
== E_CALENDAR_STATUS_OBJECT_ID_ALREADY_EXISTS
) {
831 e_notice (NULL
, GTK_MESSAGE_ERROR
, _("Unable to book a resource, the new event collides with some other."));
833 gchar
*msg
= g_strconcat (_("Unable to book a resource, error: "), error
->message
, NULL
);
834 e_notice (NULL
, GTK_MESSAGE_ERROR
, msg
);
842 g_clear_error (&error
);
844 if (returned_icalcomp
)
845 icalcomponent_free (returned_icalcomp
);
846 icalcomponent_free (top_level
);
852 comp_limit_attendees (ECalComponent
*comp
)
854 icalcomponent
*icomp
;
856 gboolean found
= FALSE
, match
= FALSE
;
857 GSList
*l
, *list
= NULL
;
859 icomp
= e_cal_component_get_icalcomponent (comp
);
861 for (prop
= icalcomponent_get_first_property (icomp
, ICAL_ATTENDEE_PROPERTY
);
863 prop
= icalcomponent_get_next_property (icomp
, ICAL_ATTENDEE_PROPERTY
))
866 gchar
*attendee_text
;
867 icalparameter
*param
;
868 const gchar
*attendee_sentby
;
869 gchar
*attendee_sentby_text
= NULL
;
871 /* If we've already found something, just erase the rest */
873 list
= g_slist_prepend (list
, prop
);
877 attendee
= icalproperty_get_value_as_string_r (prop
);
881 attendee_text
= g_strdup (itip_strip_mailto (attendee
));
883 attendee_text
= g_strstrip (attendee_text
);
884 found
= match
= e_account_list_find (itip_addresses_get (), E_ACCOUNT_FIND_ID_ADDRESS
, attendee_text
) != NULL
;
887 param
= icalproperty_get_first_parameter (prop
, ICAL_SENTBY_PARAMETER
);
889 attendee_sentby
= icalparameter_get_sentby (param
);
890 attendee_sentby_text
= g_strdup (itip_strip_mailto (attendee_sentby
));
891 attendee_sentby_text
= g_strstrip (attendee_sentby_text
);
892 found
= match
= e_account_list_find (itip_addresses_get (), E_ACCOUNT_FIND_ID_ADDRESS
, attendee_sentby_text
) != NULL
;
896 g_free (attendee_text
);
897 g_free (attendee_sentby_text
);
900 list
= g_slist_prepend (list
, prop
);
903 for (l
= list
; l
!= NULL
; l
= l
->next
) {
906 icalcomponent_remove_property (icomp
, prop
);
907 icalproperty_free (prop
);
915 comp_sentby (ECalComponent
*comp
, ECal
*client
)
917 ECalComponentOrganizer organizer
;
918 GSList
* attendees
, *l
;
921 e_cal_component_get_organizer (comp
, &organizer
);
922 if (!organizer
.value
) {
923 EAccount
*a
= itip_addresses_get_default ();
925 organizer
.value
= g_strdup_printf ("MAILTO:%s", a
->id
->address
);
926 organizer
.sentby
= NULL
;
927 organizer
.cn
= a
->id
->name
;
928 organizer
.language
= NULL
;
930 e_cal_component_set_organizer (comp
, &organizer
);
931 g_free ((gchar
*) organizer
.value
);
936 e_cal_component_get_attendee_list (comp
, &attendees
);
937 user
= itip_get_comp_attendee (comp
, client
);
938 for (l
= attendees
; l
; l
= l
->next
) {
939 ECalComponentAttendee
*a
= l
->data
;
941 if (!g_ascii_strcasecmp (itip_strip_mailto (a
->value
), user
) || (a
->sentby
&& !g_ascii_strcasecmp (itip_strip_mailto (a
->sentby
), user
))) {
947 if (!itip_organizer_is_user (comp
, client
) && !itip_sentby_is_user (comp
, client
)) {
948 EAccount
*a
= itip_addresses_get_default ();
950 organizer
.value
= g_strdup (organizer
.value
);
951 organizer
.sentby
= g_strdup_printf ("MAILTO:%s", a
->id
->address
);
952 organizer
.cn
= g_strdup (organizer
.cn
);
953 organizer
.language
= g_strdup (organizer
.language
);
955 e_cal_component_set_organizer (comp
, &organizer
);
957 g_free ((gchar
*)organizer
.value
);
958 g_free ((gchar
*)organizer
.sentby
);
959 g_free ((gchar
*)organizer
.cn
);
960 g_free ((gchar
*)organizer
.language
);
963 static ECalComponent
*
964 comp_minimal (ECalComponent
*comp
, gboolean attendee
)
966 ECalComponent
*clone
;
967 icalcomponent
*icomp
, *icomp_clone
;
969 ECalComponentOrganizer organizer
;
972 struct icaltimetype itt
;
973 ECalComponentRange recur_id
;
975 clone
= e_cal_component_new ();
976 e_cal_component_set_new_vtype (clone
, e_cal_component_get_vtype (comp
));
981 e_cal_component_get_attendee_list (comp
, &attendees
);
982 e_cal_component_set_attendee_list (clone
, attendees
);
984 if (!comp_limit_attendees (clone
)) {
985 e_notice (NULL
, GTK_MESSAGE_ERROR
,
986 _("You must be an attendee of the event."));
991 itt
= icaltime_from_timet_with_zone (time (NULL
), FALSE
,
992 icaltimezone_get_utc_timezone ());
993 e_cal_component_set_dtstamp (clone
, &itt
);
995 e_cal_component_get_organizer (comp
, &organizer
);
996 if (organizer
.value
== NULL
)
998 e_cal_component_set_organizer (clone
, &organizer
);
1000 e_cal_component_get_uid (comp
, &uid
);
1001 e_cal_component_set_uid (clone
, uid
);
1003 e_cal_component_get_comment_list (comp
, &comments
);
1004 if (g_slist_length (comments
) <= 1) {
1005 e_cal_component_set_comment_list (clone
, comments
);
1007 GSList
*l
= comments
;
1009 comments
= g_slist_remove_link (comments
, l
);
1010 e_cal_component_set_comment_list (clone
, l
);
1011 e_cal_component_free_text_list (l
);
1013 e_cal_component_free_text_list (comments
);
1015 e_cal_component_get_recurid (comp
, &recur_id
);
1016 if (recur_id
.datetime
.value
!= NULL
)
1017 e_cal_component_set_recurid (clone
, &recur_id
);
1019 icomp
= e_cal_component_get_icalcomponent (comp
);
1020 icomp_clone
= e_cal_component_get_icalcomponent (clone
);
1021 for (prop
= icalcomponent_get_first_property (icomp
, ICAL_X_PROPERTY
);
1023 prop
= icalcomponent_get_next_property (icomp
, ICAL_X_PROPERTY
))
1027 p
= icalproperty_new_clone (prop
);
1028 icalcomponent_add_property (icomp_clone
, p
);
1031 e_cal_component_rescan (clone
);
1036 g_object_unref (clone
);
1041 strip_x_microsoft_props (ECalComponent
*comp
)
1043 GSList
*lst
= NULL
, *l
;
1044 icalcomponent
*icalcomp
;
1045 icalproperty
*icalprop
;
1047 g_return_if_fail (comp
!= NULL
);
1049 icalcomp
= e_cal_component_get_icalcomponent (comp
);
1050 g_return_if_fail (icalcomp
!= NULL
);
1052 for (icalprop
= icalcomponent_get_first_property (icalcomp
, ICAL_X_PROPERTY
);
1054 icalprop
= icalcomponent_get_next_property (icalcomp
, ICAL_X_PROPERTY
)) {
1055 const gchar
*x_name
= icalproperty_get_x_name (icalprop
);
1057 if (x_name
&& g_ascii_strncasecmp (x_name
, "X-MICROSOFT-", 12) == 0)
1058 lst
= g_slist_prepend (lst
, icalprop
);
1061 for (l
= lst
; l
!= NULL
; l
= l
->next
) {
1063 icalcomponent_remove_property (icalcomp
, icalprop
);
1064 icalproperty_free (icalprop
);
1070 static ECalComponent
*
1071 comp_compliant (ECalComponentItipMethod method
,
1072 ECalComponent
*comp
,
1074 icalcomponent
*zones
,
1075 icaltimezone
*default_zone
,
1076 gboolean strip_alarms
)
1078 ECalComponent
*clone
, *temp_clone
;
1079 struct icaltimetype itt
;
1081 clone
= e_cal_component_clone (comp
);
1082 itt
= icaltime_from_timet_with_zone (time (NULL
), FALSE
,
1083 icaltimezone_get_utc_timezone ());
1084 e_cal_component_set_dtstamp (clone
, &itt
);
1086 /* Make UNTIL date a datetime in a simple recurrence */
1087 if (e_cal_component_has_recurrences (clone
)
1088 && e_cal_component_has_simple_recurrence (clone
)) {
1090 struct icalrecurrencetype
*r
;
1092 e_cal_component_get_rrule_list (clone
, &rrule_list
);
1093 r
= rrule_list
->data
;
1095 if (!icaltime_is_null_time (r
->until
) && r
->until
.is_date
) {
1096 ECalComponentDateTime dt
;
1097 icaltimezone
*from_zone
= NULL
, *to_zone
;
1099 e_cal_component_get_dtstart (clone
, &dt
);
1101 if (dt
.value
->is_date
) {
1102 from_zone
= default_zone
;
1103 } else if (dt
.tzid
== NULL
) {
1104 from_zone
= icaltimezone_get_utc_timezone ();
1107 from_zone
= icalcomponent_get_timezone (zones
, dt
.tzid
);
1108 if (from_zone
== NULL
)
1109 from_zone
= icaltimezone_get_builtin_timezone_from_tzid (dt
.tzid
);
1110 if (from_zone
== NULL
&& client
!= NULL
)
1111 /* FIXME Error checking */
1112 e_cal_get_timezone (client
, dt
.tzid
, &from_zone
, NULL
);
1115 to_zone
= icaltimezone_get_utc_timezone ();
1117 r
->until
.hour
= dt
.value
->hour
;
1118 r
->until
.minute
= dt
.value
->minute
;
1119 r
->until
.second
= dt
.value
->second
;
1120 r
->until
.is_date
= FALSE
;
1122 icaltimezone_convert_time (&r
->until
, from_zone
, to_zone
);
1123 r
->until
.is_utc
= TRUE
;
1125 e_cal_component_free_datetime (&dt
);
1126 e_cal_component_set_rrule_list (clone
, rrule_list
);
1127 e_cal_component_abort_sequence (clone
);
1130 e_cal_component_free_recur_list (rrule_list
);
1133 /* We delete incoming alarms if requested, even this helps with outlook */
1135 e_cal_component_remove_all_alarms (clone
);
1137 /* Always strip procedure alarms, because of security */
1140 uids
= e_cal_component_get_alarm_uids (clone
);
1142 for (l
= uids
; l
; l
= l
->next
) {
1143 ECalComponentAlarm
*alarm
;
1144 ECalComponentAlarmAction action
= E_CAL_COMPONENT_ALARM_UNKNOWN
;
1146 alarm
= e_cal_component_get_alarm (clone
, (const gchar
*)l
->data
);
1148 e_cal_component_alarm_get_action (alarm
, &action
);
1149 e_cal_component_alarm_free (alarm
);
1151 if (action
== E_CAL_COMPONENT_ALARM_PROCEDURE
)
1152 e_cal_component_remove_alarm (clone
, (const gchar
*)l
->data
);
1156 cal_obj_uid_list_free (uids
);
1159 strip_x_microsoft_props (clone
);
1161 /* Strip X-LIC-ERROR stuff */
1162 e_cal_component_strip_errors (clone
);
1164 /* Comply with itip spec */
1166 case E_CAL_COMPONENT_METHOD_PUBLISH
:
1167 comp_sentby (clone
, client
);
1168 e_cal_component_set_attendee_list (clone
, NULL
);
1170 case E_CAL_COMPONENT_METHOD_REQUEST
:
1171 comp_sentby (clone
, client
);
1173 case E_CAL_COMPONENT_METHOD_CANCEL
:
1174 comp_sentby (clone
, client
);
1176 case E_CAL_COMPONENT_METHOD_REPLY
:
1178 case E_CAL_COMPONENT_METHOD_ADD
:
1180 case E_CAL_COMPONENT_METHOD_REFRESH
:
1181 /* Need to remove almost everything */
1182 temp_clone
= comp_minimal (clone
, TRUE
);
1183 g_object_unref (clone
);
1186 case E_CAL_COMPONENT_METHOD_COUNTER
:
1188 case E_CAL_COMPONENT_METHOD_DECLINECOUNTER
:
1189 /* Need to remove almost everything */
1190 temp_clone
= comp_minimal (clone
, FALSE
);
1191 g_object_unref (clone
);
1202 append_cal_attachments (EMsgComposer
*composer
,
1203 ECalComponent
*comp
,
1204 GSList
*attach_list
)
1206 struct CalMimeAttach
*mime_attach
;
1209 for (l
= attach_list
; l
; l
= l
->next
) {
1210 CamelMimePart
*attachment
;
1212 mime_attach
= (struct CalMimeAttach
*) l
->data
;
1214 attachment
= camel_mime_part_new ();
1215 camel_mime_part_set_content (
1216 attachment
, mime_attach
->encoded_data
,
1217 mime_attach
->length
, mime_attach
->content_type
);
1218 if (mime_attach
->content_id
)
1219 camel_mime_part_set_content_id (attachment
, mime_attach
->content_id
);
1220 if (mime_attach
->filename
!= NULL
)
1221 camel_mime_part_set_filename (
1222 attachment
, mime_attach
->filename
);
1223 if (mime_attach
->description
!= NULL
)
1224 camel_mime_part_set_description (
1225 attachment
, mime_attach
->description
);
1226 if (mime_attach
->disposition
)
1227 camel_mime_part_set_disposition (
1228 attachment
, "inline");
1230 camel_mime_part_set_disposition (
1231 attachment
, "attachment");
1232 e_msg_composer_attach (composer
, attachment
);
1233 g_object_unref (attachment
);
1235 g_free (mime_attach
->filename
);
1236 g_free (mime_attach
->content_type
);
1237 g_free (mime_attach
->content_id
);
1238 g_free (mime_attach
->description
);
1239 g_free (mime_attach
->encoded_data
);
1240 g_free (mime_attach
);
1243 g_slist_free (attach_list
);
1247 find_enabled_account (EAccountList
*accounts
, const gchar
*id_address
)
1250 EAccount
*account
= NULL
;
1252 g_return_val_if_fail (accounts
!= NULL
, NULL
);
1257 for (it
= e_list_get_iterator ((EList
*)accounts
);
1258 e_iterator_is_valid (it
);
1259 e_iterator_next (it
)) {
1260 account
= (EAccount
*)e_iterator_get (it
);
1265 && account
->id
->address
1266 && g_ascii_strcasecmp (account
->id
->address
, id_address
) == 0)
1276 setup_from (ECalComponentItipMethod method
, ECalComponent
*comp
, ECal
*client
, EComposerHeaderTable
*table
)
1278 EAccountList
*accounts
;
1280 accounts
= e_composer_header_table_get_account_list (table
);
1282 EAccount
*account
= NULL
;
1284 /* always use organizer's email when user is an organizer */
1285 if (itip_organizer_is_user (comp
, client
)) {
1286 ECalComponentOrganizer organizer
= {0};
1288 e_cal_component_get_organizer (comp
, &organizer
);
1289 if (organizer
.value
!= NULL
) {
1290 account
= find_enabled_account (accounts
, itip_strip_mailto (organizer
.value
));
1295 gchar
*from
= comp_from (method
, comp
);
1298 account
= find_enabled_account (accounts
, from
);
1304 e_composer_header_table_set_account (table
, account
);
1309 itip_send_comp (ECalComponentItipMethod method
,
1310 ECalComponent
*send_comp
,
1312 icalcomponent
*zones
,
1313 GSList
*attachments_list
,
1315 gboolean strip_alarms
,
1316 gboolean only_new_attendees
)
1319 EShellSettings
*shell_settings
;
1320 EMsgComposer
*composer
;
1321 EComposerHeaderTable
*table
;
1322 EDestination
**destinations
;
1323 ECalComponent
*comp
= NULL
;
1324 icalcomponent
*top_level
= NULL
;
1325 icaltimezone
*default_zone
;
1326 gchar
*ical_string
= NULL
;
1327 gchar
*content_type
= NULL
;
1328 gchar
*subject
= NULL
;
1329 gboolean use_24_hour_format
;
1330 gboolean retval
= FALSE
;
1332 /* FIXME Pass this in. */
1333 shell
= e_shell_get_default ();
1334 shell_settings
= e_shell_get_shell_settings (shell
);
1336 default_zone
= e_shell_settings_get_pointer (
1337 shell_settings
, "cal-timezone");
1339 use_24_hour_format
= e_shell_settings_get_boolean (
1340 shell_settings
, "cal-use-24-hour-format");
1342 /* check whether backend could handle auto-saving requests/updates */
1343 if (method
!= E_CAL_COMPONENT_METHOD_PUBLISH
&& e_cal_get_save_schedules (client
))
1346 /* Give the server a chance to manipulate the comp */
1347 if (method
!= E_CAL_COMPONENT_METHOD_PUBLISH
) {
1348 if (!comp_server_send (method
, send_comp
, client
, zones
, &users
))
1352 /* check whether backend could handle sending requests/updates */
1353 if (method
!= E_CAL_COMPONENT_METHOD_PUBLISH
&& e_cal_get_static_capability (client
, CAL_STATIC_CAPABILITY_CREATE_MESSAGES
)) {
1355 g_list_foreach (users
, (GFunc
) g_free
, NULL
);
1356 g_list_free (users
);
1361 /* Tidy up the comp */
1362 comp
= comp_compliant (
1363 method
, send_comp
, client
, zones
, default_zone
, strip_alarms
);
1369 destinations
= comp_to_list (method
, comp
, users
, FALSE
, only_new_attendees
? g_object_get_data (G_OBJECT (send_comp
), "new-attendees") : NULL
);
1370 if (method
!= E_CAL_COMPONENT_METHOD_PUBLISH
) {
1371 if (destinations
== NULL
) {
1372 /* We sent them all via the server */
1378 /* Subject information */
1379 subject
= comp_subject (method
, comp
);
1381 composer
= e_msg_composer_new (shell
);
1382 table
= e_msg_composer_get_header_table (composer
);
1384 setup_from (method
, send_comp
, client
, table
);
1385 e_composer_header_table_set_subject (table
, subject
);
1386 e_composer_header_table_set_destinations_to (table
, destinations
);
1388 e_destination_freev (destinations
);
1391 content_type
= comp_content_type (comp
, method
);
1393 top_level
= comp_toplevel_with_zones (method
, comp
, client
, zones
);
1394 ical_string
= icalcomponent_as_ical_string_r (top_level
);
1396 if (e_cal_component_get_vtype (comp
) == E_CAL_COMPONENT_EVENT
) {
1397 e_msg_composer_set_body (composer
, ical_string
, content_type
);
1399 CamelMimePart
*attachment
;
1400 const gchar
*filename
;
1404 filename
= comp_filename (comp
);
1405 description
= comp_description (comp
, use_24_hour_format
);
1407 body
= camel_text_to_html (
1408 description
, CAMEL_MIME_FILTER_TOHTML_PRE
, 0);
1409 e_msg_composer_set_body_text (composer
, body
, -1);
1412 attachment
= camel_mime_part_new ();
1413 camel_mime_part_set_content (
1414 attachment
, ical_string
,
1415 strlen (ical_string
), content_type
);
1416 if (filename
!= NULL
&& *filename
!= '\0')
1417 camel_mime_part_set_filename (attachment
, filename
);
1418 if (description
!= NULL
&& *description
!= '\0')
1419 camel_mime_part_set_description (attachment
, description
);
1420 camel_mime_part_set_disposition (attachment
, "inline");
1421 e_msg_composer_attach (composer
, attachment
);
1422 g_object_unref (attachment
);
1424 g_free (description
);
1427 append_cal_attachments (composer
, comp
, attachments_list
);
1429 if ((method
== E_CAL_COMPONENT_METHOD_PUBLISH
) && !users
)
1430 gtk_widget_show (GTK_WIDGET (composer
));
1432 e_msg_composer_send (composer
);
1438 g_object_unref (comp
);
1439 if (top_level
!= NULL
)
1440 icalcomponent_free (top_level
);
1443 g_list_foreach (users
, (GFunc
) g_free
, NULL
);
1444 g_list_free (users
);
1447 g_free (content_type
);
1449 g_free (ical_string
);
1455 reply_to_calendar_comp (ECalComponentItipMethod method
,
1456 ECalComponent
*send_comp
,
1459 icalcomponent
*zones
,
1460 GSList
*attachments_list
)
1463 EShellSettings
*shell_settings
;
1464 EMsgComposer
*composer
;
1465 EComposerHeaderTable
*table
;
1466 EDestination
**destinations
;
1467 ECalComponent
*comp
= NULL
;
1468 icalcomponent
*top_level
= NULL
;
1469 icaltimezone
*default_zone
;
1470 GList
*users
= NULL
;
1471 gchar
*subject
= NULL
;
1472 gchar
*ical_string
= NULL
;
1473 gboolean retval
= FALSE
;
1475 /* FIXME Pass this in. */
1476 shell
= e_shell_get_default ();
1477 shell_settings
= e_shell_get_shell_settings (shell
);
1479 default_zone
= e_shell_settings_get_pointer (
1480 shell_settings
, "cal-timezone");
1482 /* Tidy up the comp */
1483 comp
= comp_compliant (
1484 method
, send_comp
, client
, zones
, default_zone
, TRUE
);
1489 destinations
= comp_to_list (method
, comp
, users
, reply_all
, NULL
);
1491 /* Subject information */
1492 subject
= comp_subject (method
, comp
);
1494 composer
= e_msg_composer_new (shell
);
1495 table
= e_msg_composer_get_header_table (composer
);
1497 setup_from (method
, send_comp
, client
, table
);
1498 e_composer_header_table_set_subject (table
, subject
);
1499 e_composer_header_table_set_destinations_to (table
, destinations
);
1501 e_destination_freev (destinations
);
1503 top_level
= comp_toplevel_with_zones (method
, comp
, client
, zones
);
1504 ical_string
= icalcomponent_as_ical_string_r (top_level
);
1506 if (e_cal_component_get_vtype (comp
) == E_CAL_COMPONENT_EVENT
) {
1509 gchar
*orig_from
= NULL
;
1510 const gchar
*description
= NULL
;
1511 gchar
*subject
= NULL
;
1512 const gchar
*location
= NULL
;
1514 gchar
*html_description
= NULL
;
1515 GSList
*text_list
= NULL
;
1516 ECalComponentOrganizer organizer
;
1517 ECalComponentText text
;
1518 ECalComponentDateTime dtstart
;
1519 icaltimezone
*start_zone
= NULL
;
1522 e_cal_component_get_description_list (comp
, &text_list
);
1525 ECalComponentText text
= *((ECalComponentText
*)text_list
->data
);
1527 description
= text
.value
;
1534 e_cal_component_free_text_list (text_list
);
1536 e_cal_component_get_summary (comp
, &text
);
1538 subject
= g_strdup (text
.value
);
1540 e_cal_component_get_organizer (comp
, &organizer
);
1541 if (organizer
.value
)
1542 orig_from
= g_strdup (itip_strip_mailto (organizer
.value
));
1544 e_cal_component_get_location (comp
, &location
);
1546 location
= "Unspecified";
1548 e_cal_component_get_dtstart (comp
, &dtstart
);
1549 if (dtstart
.value
) {
1550 start_zone
= icaltimezone_get_builtin_timezone_from_tzid (dtstart
.tzid
);
1552 if (!e_cal_get_timezone (client
, dtstart
.tzid
, &start_zone
, NULL
))
1553 g_warning ("Couldn't get timezone from server: %s", dtstart
.tzid
? dtstart
.tzid
: "");
1556 if (!start_zone
|| dtstart
.value
->is_date
)
1557 start_zone
= default_zone
;
1559 start
= icaltime_as_timet_with_zone (*dtstart
.value
, start_zone
);
1560 time
= g_strdup (ctime (&start
));
1563 body
= g_string_new ("<br><br><hr><br><b>______ Original Appointment ______ </b><br><br><table>");
1565 if (orig_from
&& *orig_from
)
1566 g_string_append_printf (body
,
1567 "<tr><td><b>From</b></td>"
1568 "<td>:</td><td>%s</td></tr>", orig_from
);
1572 g_string_append_printf (body
,
1573 "<tr><td><b>Subject</b></td>"
1574 "<td>:</td><td>%s</td></tr>", subject
);
1577 g_string_append_printf (body
,
1578 "<tr><td><b>Location</b></td>"
1579 "<td>:</td><td>%s</td></tr>", location
);
1582 g_string_append_printf (body
,
1583 "<tr><td><b>Time</b></td>"
1584 "<td>:</td><td>%s</td></tr>", time
);
1587 g_string_append_printf (body
, "</table><br>");
1589 html_description
= html_new_lines_for (description
);
1590 g_string_append (body
, html_description
);
1591 g_free (html_description
);
1593 e_msg_composer_set_body_text (composer
, body
->str
, -1);
1594 g_string_free (body
, TRUE
);
1597 gtk_widget_show (GTK_WIDGET (composer
));
1604 g_object_unref (comp
);
1605 if (top_level
!= NULL
)
1606 icalcomponent_free (top_level
);
1609 g_list_foreach (users
, (GFunc
) g_free
, NULL
);
1610 g_list_free (users
);
1614 g_free (ical_string
);
1619 itip_publish_begin (ECalComponent
*pub_comp
, ECal
*client
,
1620 gboolean cloned
, ECalComponent
**clone
)
1622 icalcomponent
*icomp
=NULL
, *icomp_clone
= NULL
;
1625 if (e_cal_component_get_vtype (pub_comp
) == E_CAL_COMPONENT_FREEBUSY
) {
1628 *clone
= e_cal_component_clone (pub_comp
);
1631 icomp
= e_cal_component_get_icalcomponent (pub_comp
);
1632 icomp_clone
= e_cal_component_get_icalcomponent (*clone
);
1633 for (prop
= icalcomponent_get_first_property (icomp
,
1634 ICAL_FREEBUSY_PROPERTY
);
1636 prop
= icalcomponent_get_next_property (icomp
,
1637 ICAL_FREEBUSY_PROPERTY
))
1641 p
= icalproperty_new_clone (prop
);
1642 icalcomponent_add_property (icomp_clone
, p
);
1651 fb_sort (struct icalperiodtype
*ipt
, gint fb_count
)
1655 if (ipt
== NULL
|| fb_count
== 0)
1658 for (i
= 0; i
< fb_count
-1; i
++) {
1659 for (j
= i
+1; j
< fb_count
; j
++) {
1660 struct icalperiodtype temp
;
1662 if (icaltime_compare (ipt
[i
].start
, ipt
[j
].start
) < 0)
1665 if (icaltime_compare (ipt
[i
].start
, ipt
[j
].start
) == 0) {
1666 if (icaltime_compare (ipt
[i
].end
,
1677 static icalcomponent
*
1678 comp_fb_normalize (icalcomponent
*icomp
)
1680 icalcomponent
*iclone
;
1681 icalproperty
*prop
, *p
;
1682 const gchar
*uid
, *comment
;
1683 struct icaltimetype itt
;
1684 gint fb_count
, i
= 0, j
;
1685 struct icalperiodtype
*ipt
;
1687 iclone
= icalcomponent_new (ICAL_VFREEBUSY_COMPONENT
);
1689 prop
= icalcomponent_get_first_property (icomp
,
1690 ICAL_ORGANIZER_PROPERTY
);
1692 p
= icalproperty_new_clone (prop
);
1693 icalcomponent_add_property (iclone
, p
);
1696 itt
= icalcomponent_get_dtstart (icomp
);
1697 icalcomponent_set_dtstart (iclone
, itt
);
1699 itt
= icalcomponent_get_dtend (icomp
);
1700 icalcomponent_set_dtend (iclone
, itt
);
1702 fb_count
= icalcomponent_count_properties (icomp
,
1703 ICAL_FREEBUSY_PROPERTY
);
1704 ipt
= g_new0 (struct icalperiodtype
, fb_count
+1);
1706 for (prop
= icalcomponent_get_first_property (icomp
,
1707 ICAL_FREEBUSY_PROPERTY
);
1709 prop
= icalcomponent_get_next_property (icomp
,
1710 ICAL_FREEBUSY_PROPERTY
))
1712 ipt
[i
] = icalproperty_get_freebusy (prop
);
1716 fb_sort (ipt
, fb_count
);
1718 for (j
= 0; j
<= fb_count
-1; j
++) {
1719 icalparameter
*param
;
1721 prop
= icalproperty_new_freebusy (ipt
[j
]);
1722 param
= icalparameter_new_fbtype (ICAL_FBTYPE_BUSY
);
1723 icalproperty_add_parameter (prop
, param
);
1724 icalcomponent_add_property (iclone
, prop
);
1728 /* Should I strip this RFC 2446 says there must not be a UID
1729 if the METHOD is PUBLISH?? */
1730 uid
= icalcomponent_get_uid (icomp
);
1732 icalcomponent_set_uid (iclone
, uid
);
1734 itt
= icaltime_from_timet_with_zone (time (NULL
), FALSE
,
1735 icaltimezone_get_utc_timezone ());
1736 icalcomponent_set_dtstamp (iclone
, itt
);
1738 prop
= icalcomponent_get_first_property (icomp
, ICAL_URL_PROPERTY
);
1740 p
= icalproperty_new_clone (prop
);
1741 icalcomponent_add_property (iclone
, p
);
1744 comment
= icalcomponent_get_comment (icomp
);
1746 icalcomponent_set_comment (iclone
, comment
);
1748 for (prop
= icalcomponent_get_first_property (icomp
, ICAL_X_PROPERTY
);
1750 prop
= icalcomponent_get_next_property (icomp
, ICAL_X_PROPERTY
))
1752 p
= icalproperty_new_clone (prop
);
1753 icalcomponent_add_property (iclone
, p
);
1757 /* this will never be reached */
1758 g_object_unref (iclone
);
1763 itip_publish_comp (ECal
*client
, gchar
*uri
, gchar
*username
,
1764 gchar
*password
, ECalComponent
**pub_comp
)
1766 icalcomponent
*toplevel
= NULL
, *icalcomp
= NULL
;
1767 icalcomponent
*icomp
= NULL
;
1768 SoupSession
*session
;
1771 gchar
*ical_string
= NULL
;
1773 toplevel
= e_cal_util_new_top_level ();
1774 icalcomponent_set_method (toplevel
, ICAL_METHOD_PUBLISH
);
1776 e_cal_component_set_url (*pub_comp
, uri
);
1778 icalcomp
= e_cal_component_get_icalcomponent (*pub_comp
);
1780 icomp
= comp_fb_normalize (icalcomp
);
1782 icalcomponent_add_component (toplevel
, icomp
);
1784 /* Publish the component */
1785 session
= soup_session_async_new ();
1787 real_uri
= soup_uri_new (uri
);
1788 if (!real_uri
|| !real_uri
->host
) {
1789 g_warning (G_STRLOC
": Invalid URL: %s", uri
);
1790 g_object_unref (session
);
1794 soup_uri_set_user (real_uri
, username
);
1795 soup_uri_set_password (real_uri
, password
);
1797 /* build the message */
1798 msg
= soup_message_new_from_uri (SOUP_METHOD_PUT
, real_uri
);
1799 soup_uri_free (real_uri
);
1801 g_warning (G_STRLOC
": Could not build SOAP message");
1802 g_object_unref (session
);
1806 soup_message_set_flags (msg
, SOUP_MESSAGE_NO_REDIRECT
);
1807 ical_string
= icalcomponent_as_ical_string_r (toplevel
);
1808 soup_message_set_request (msg
, "text/calendar", SOUP_MEMORY_TEMPORARY
,
1809 ical_string
, strlen (ical_string
));
1811 /* send message to server */
1812 soup_session_send_message (session
, msg
);
1813 if (!SOUP_STATUS_IS_SUCCESSFUL (msg
->status_code
)) {
1814 g_warning(G_STRLOC
": Could not publish Free/Busy: %d: %s",
1816 msg
->reason_phrase
);
1817 g_object_unref (msg
);
1818 g_object_unref (session
);
1819 g_free (ical_string
);
1823 g_object_unref (msg
);
1824 g_object_unref (session
);
1825 g_free (ical_string
);
1831 check_time (const struct icaltimetype tmval
, gboolean can_null_time
)
1833 if (icaltime_is_null_time (tmval
))
1834 return can_null_time
;
1836 return icaltime_is_valid_time (tmval
) &&
1837 tmval
.month
>= 1 && tmval
.month
<= 12 &&
1838 tmval
.day
>= 1 && tmval
.day
<= 31 &&
1839 tmval
.hour
>= 0 && tmval
.hour
< 24 &&
1840 tmval
.minute
>= 0 && tmval
.minute
< 60 &&
1841 tmval
.second
>= 0 && tmval
.second
< 60;
1844 /* returns whether the passed-in icalcomponent is valid or not. It does some sanity checks on values too. */
1846 is_icalcomp_valid (icalcomponent
*icalcomp
)
1849 icalcomponent_is_valid (icalcomp
) &&
1850 check_time (icalcomponent_get_dtstart (icalcomp
), FALSE
) &&
1851 check_time (icalcomponent_get_dtend (icalcomp
), TRUE
);