2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU Lesser General Public License as published by
4 * the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful, but
7 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
8 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * You should have received a copy of the GNU Lesser General Public License
12 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 * JP Rosevear <jpr@ximian.com>
18 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
22 #include "evolution-config.h"
25 #include <glib/gi18n-lib.h>
26 #include <libical/ical.h>
27 #include <libsoup/soup.h>
29 #include <composer/e-msg-composer.h>
30 #include <libedataserver/libedataserver.h>
32 #include "calendar-config.h"
33 #include "comp-util.h"
35 #include "itip-utils.h"
39 static const gchar
*itip_methods
[] = {
50 static icalproperty_method itip_methods_enum
[] = {
58 ICAL_METHOD_DECLINECOUNTER
,
62 * itip_get_default_name_and_address:
63 * @registry: an #ESourceRegistry
64 * @name: return location for the user's real name, or %NULL
65 * @address: return location for the user's email address, or %NULL
67 * Returns the real name and email address of the default mail identity,
68 * if available. If no default mail identity is available, @name and
69 * @address are set to %NULL and the function returns %FALSE.
71 * Returns: %TRUE if @name and/or @address were set
74 itip_get_default_name_and_address (ESourceRegistry
*registry
,
79 ESourceExtension
*extension
;
80 const gchar
*extension_name
;
83 source
= e_source_registry_ref_default_mail_identity (registry
);
86 extension_name
= E_SOURCE_EXTENSION_MAIL_IDENTITY
;
87 extension
= e_source_get_extension (source
, extension_name
);
90 *name
= e_source_mail_identity_dup_name (
91 E_SOURCE_MAIL_IDENTITY (extension
));
94 *address
= e_source_mail_identity_dup_address (
95 E_SOURCE_MAIL_IDENTITY (extension
));
97 g_object_unref (source
);
115 sort_identities_by_email_cb (gconstpointer ptr1
,
118 const gchar
**pv1
= (const gchar
**) ptr1
, **pv2
= (const gchar
**) ptr2
;
119 const gchar
*addr1
, *addr2
;
122 if (!pv1
|| !*pv1
|| !pv2
|| !*pv2
) {
130 addr1
= strchr (*pv1
, '<');
131 addr2
= strchr (*pv2
, '<');
142 res
= g_ascii_strcasecmp (addr1
, addr2
);
144 if (!res
&& addr1
!= *pv1
&& addr2
!= *pv2
)
145 res
= g_ascii_strcasecmp (*pv1
, *pv2
);
151 * itip_get_user_identities:
152 * @registry: an #ESourceRegistry
154 * Returns a %NULL-terminated array of name + address strings based on
155 * registered mail identities. Free the returned array with g_strfreev().
157 * Returns: an %NULL-terminated array of mail identity strings
160 itip_get_user_identities (ESourceRegistry
*registry
)
163 const gchar
*extension_name
;
164 GPtrArray
*identities
;
166 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry
), NULL
);
168 extension_name
= E_SOURCE_EXTENSION_MAIL_IDENTITY
;
170 list
= e_source_registry_list_enabled (registry
, extension_name
);
172 identities
= g_ptr_array_sized_new (g_list_length (list
) + 1);
174 for (link
= list
; link
!= NULL
; link
= g_list_next (link
)) {
175 ESource
*source
= E_SOURCE (link
->data
);
176 ESourceMailIdentity
*extension
;
177 const gchar
*name
, *address
;
180 if (!e_util_identity_can_send (registry
, source
))
183 extension
= e_source_get_extension (source
, extension_name
);
185 name
= e_source_mail_identity_get_name (extension
);
186 address
= e_source_mail_identity_get_address (extension
);
189 g_ptr_array_add (identities
, camel_internet_address_format_address (name
, address
));
191 aliases
= e_source_mail_identity_dup_aliases (extension
);
192 if (aliases
&& *aliases
) {
193 CamelInternetAddress
*inet_address
;
196 inet_address
= camel_internet_address_new ();
197 len
= camel_address_decode (CAMEL_ADDRESS (inet_address
), aliases
);
199 for (ii
= 0; ii
< len
; ii
++) {
200 const gchar
*alias_name
= NULL
, *alias_address
= NULL
;
202 if (camel_internet_address_get (inet_address
, ii
, &alias_name
, &alias_address
) &&
203 alias_address
&& *alias_address
) {
204 if (!alias_name
|| !*alias_name
)
207 g_ptr_array_add (identities
, camel_internet_address_format_address (alias_name
, alias_address
));
215 g_list_free_full (list
, (GDestroyNotify
) g_object_unref
);
217 g_ptr_array_sort (identities
, sort_identities_by_email_cb
);
219 /* NULL-terminated array */
220 g_ptr_array_add (identities
, NULL
);
222 return (gchar
**) g_ptr_array_free (identities
, FALSE
);
226 * itip_get_fallback_identity:
227 * @registry: an #ESourceRegistry
229 * Returns a name + address string taken from the default mail identity,
230 * but only if the corresponding account is enabled. If the account is
231 * disabled, the function returns %NULL. This is meant to be used as a
232 * fallback identity for organizers. Free the returned string with
235 * Returns: a fallback mail identity, or %NULL
238 itip_get_fallback_identity (ESourceRegistry
*registry
)
241 ESourceMailIdentity
*mail_identity
;
242 const gchar
*extension_name
;
243 const gchar
*address
;
245 gchar
*identity
= NULL
;
247 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry
), NULL
);
249 source
= e_source_registry_ref_default_mail_identity (registry
);
254 if (!e_source_registry_check_enabled (registry
, source
)) {
255 g_object_unref (source
);
259 extension_name
= E_SOURCE_EXTENSION_MAIL_IDENTITY
;
260 mail_identity
= e_source_get_extension (source
, extension_name
);
262 name
= e_source_mail_identity_get_name (mail_identity
);
263 address
= e_source_mail_identity_get_address (mail_identity
);
266 identity
= camel_internet_address_format_address (name
, address
);
268 g_object_unref (source
);
274 * itip_address_is_user:
275 * @registry: an #ESourceRegistry
276 * @address: an email address
278 * Looks for a registered mail identity with a matching email address.
280 * Returns: %TRUE if a match was found, %FALSE if not
283 itip_address_is_user (ESourceRegistry
*registry
,
284 const gchar
*address
)
287 const gchar
*extension_name
;
288 gboolean match
= FALSE
;
290 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry
), FALSE
);
291 g_return_val_if_fail (address
!= NULL
, FALSE
);
293 extension_name
= E_SOURCE_EXTENSION_MAIL_IDENTITY
;
295 list
= e_source_registry_list_sources (registry
, extension_name
);
297 for (iter
= list
; iter
&& !match
; iter
= g_list_next (iter
)) {
298 ESource
*source
= E_SOURCE (iter
->data
);
299 ESourceMailIdentity
*extension
;
301 const gchar
*id_address
;
303 extension
= e_source_get_extension (source
, extension_name
);
304 id_address
= e_source_mail_identity_get_address (extension
);
306 if (id_address
&& g_ascii_strcasecmp (address
, id_address
) == 0) {
311 aliases
= e_source_mail_identity_get_aliases_as_hash_table (extension
);
313 match
= g_hash_table_contains (aliases
, address
);
314 g_hash_table_destroy (aliases
);
318 g_list_free_full (list
, (GDestroyNotify
) g_object_unref
);
324 itip_organizer_is_user (ESourceRegistry
*registry
,
326 ECalClient
*cal_client
)
328 return itip_organizer_is_user_ex (registry
, comp
, cal_client
, FALSE
);
332 itip_organizer_is_user_ex (ESourceRegistry
*registry
,
334 ECalClient
*cal_client
,
335 gboolean skip_cap_test
)
337 ECalComponentOrganizer organizer
;
339 gboolean user_org
= FALSE
;
341 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry
), FALSE
);
343 if (!e_cal_component_has_organizer (comp
) ||
344 (!skip_cap_test
&& e_client_check_capability (
345 E_CLIENT (cal_client
), CAL_STATIC_CAPABILITY_NO_ORGANIZER
)))
348 e_cal_component_get_organizer (comp
, &organizer
);
349 if (organizer
.value
!= NULL
) {
352 strip
= itip_strip_mailto (organizer
.value
);
354 if (e_client_get_backend_property_sync (E_CLIENT (cal_client
),
355 CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS
,
356 &email
, NULL
, NULL
) &&
357 email
&& g_ascii_strcasecmp (email
, strip
) == 0) {
365 if (e_client_check_capability (E_CLIENT (cal_client
), CAL_STATIC_CAPABILITY_ORGANIZER_NOT_EMAIL_ADDRESS
)) {
369 user_org
= itip_address_is_user (registry
, strip
);
376 itip_sentby_is_user (ESourceRegistry
*registry
,
378 ECalClient
*cal_client
)
380 ECalComponentOrganizer organizer
;
382 gboolean user_sentby
= FALSE
;
384 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry
), FALSE
);
386 if (!e_cal_component_has_organizer (comp
) ||
387 e_client_check_capability (
388 E_CLIENT (cal_client
), CAL_STATIC_CAPABILITY_NO_ORGANIZER
))
391 e_cal_component_get_organizer (comp
, &organizer
);
392 if (organizer
.sentby
!= NULL
) {
393 strip
= itip_strip_mailto (organizer
.sentby
);
394 user_sentby
= itip_address_is_user (registry
, strip
);
401 itip_has_any_attendees (ECalComponent
*comp
)
403 ECalComponentOrganizer organizer
;
404 ECalComponentAttendee
*attendee
;
405 GSList
*attendees
= NULL
;
408 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp
), FALSE
);
410 if (!e_cal_component_has_attendees (comp
))
413 e_cal_component_get_attendee_list (comp
, &attendees
);
419 /* More than one attendee */
420 if (attendees
->next
) {
421 e_cal_component_free_attendee_list (attendees
);
425 /* Exactly one attendee, check if it's not the organizer */
426 attendee
= attendees
->data
;
428 g_return_val_if_fail (attendee
!= NULL
, FALSE
);
430 if (!e_cal_component_has_organizer (comp
)) {
431 e_cal_component_free_attendee_list (attendees
);
435 e_cal_component_get_organizer (comp
, &organizer
);
437 res
= attendee
->value
&& (!organizer
.value
||
438 g_ascii_strcasecmp (itip_strip_mailto (attendee
->value
), itip_strip_mailto (organizer
.value
)) != 0);
440 e_cal_component_free_attendee_list (attendees
);
445 static ECalComponentAttendee
*
446 get_attendee (GSList
*attendees
,
447 const gchar
*address
,
455 for (l
= attendees
; l
; l
= l
->next
) {
456 ECalComponentAttendee
*attendee
= l
->data
;
457 const gchar
*nomailto
;
459 nomailto
= itip_strip_mailto (attendee
->value
);
460 if (!nomailto
|| !*nomailto
)
463 if ((address
&& g_ascii_strcasecmp (nomailto
, address
) == 0) ||
464 (aliases
&& g_hash_table_contains (aliases
, nomailto
))) {
472 static ECalComponentAttendee
*
473 get_attendee_if_attendee_sentby_is_user (GSList
*attendees
,
474 const gchar
*address
,
479 for (l
= attendees
; l
; l
= l
->next
) {
480 ECalComponentAttendee
*attendee
= l
->data
;
481 const gchar
*nomailto
;
483 nomailto
= itip_strip_mailto (attendee
->sentby
);
484 if (!nomailto
|| !*nomailto
)
487 if ((address
&& g_ascii_strcasecmp (nomailto
, address
) == 0) ||
488 (aliases
&& g_hash_table_contains (aliases
, nomailto
))) {
497 html_new_lines_for (const gchar
*string
)
502 lines
= g_strsplit_set (string
, "\n", -1);
503 joined
= g_strjoinv ("<br>", lines
);
510 itip_get_comp_attendee (ESourceRegistry
*registry
,
512 ECalClient
*cal_client
)
516 ECalComponentAttendee
*attendee
= NULL
;
518 const gchar
*extension_name
;
519 gchar
*address
= NULL
;
521 e_cal_component_get_attendee_list (comp
, &attendees
);
524 e_client_get_backend_property_sync (
525 E_CLIENT (cal_client
),
526 CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS
,
527 &address
, NULL
, NULL
);
529 if (address
!= NULL
&& *address
!= '\0') {
530 attendee
= get_attendee (attendees
, address
, NULL
);
535 user_email
= g_strdup (
536 itip_strip_mailto (attendee
->value
));
537 e_cal_component_free_attendee_list (attendees
);
543 attendee
= get_attendee_if_attendee_sentby_is_user (attendees
, address
, NULL
);
545 if (attendee
!= NULL
) {
548 user_email
= g_strdup (
549 itip_strip_mailto (attendee
->sentby
));
550 e_cal_component_free_attendee_list (attendees
);
560 extension_name
= E_SOURCE_EXTENSION_MAIL_IDENTITY
;
561 list
= e_source_registry_list_enabled (registry
, extension_name
);
563 for (link
= list
; link
!= NULL
; link
= g_list_next (link
)) {
564 ESourceMailIdentity
*extension
;
567 source
= E_SOURCE (link
->data
);
569 extension_name
= E_SOURCE_EXTENSION_MAIL_IDENTITY
;
570 extension
= e_source_get_extension (source
, extension_name
);
572 address
= e_source_mail_identity_dup_address (extension
);
574 aliases
= e_source_mail_identity_get_aliases_as_hash_table (extension
);
576 attendee
= get_attendee (attendees
, address
, aliases
);
577 if (attendee
!= NULL
) {
580 user_email
= g_strdup (itip_strip_mailto (attendee
->value
));
581 e_cal_component_free_attendee_list (attendees
);
584 g_hash_table_destroy (aliases
);
587 g_list_free_full (list
, g_object_unref
);
592 /* If the account was not found in the attendees list, then
593 * let's check the 'sentby' fields of the attendees if we can
594 * find the account. */
595 attendee
= get_attendee_if_attendee_sentby_is_user (attendees
, address
, aliases
);
599 user_email
= g_strdup (itip_strip_mailto (attendee
->sentby
));
600 e_cal_component_free_attendee_list (attendees
);
603 g_hash_table_destroy (aliases
);
606 g_list_free_full (list
, g_object_unref
);
612 g_hash_table_destroy (aliases
);
616 g_list_free_full (list
, g_object_unref
);
618 /* We could not find the attendee in the component, so just give
619 * the default account address if the email address is not set in
621 /* FIXME do we have a better way ? */
622 itip_get_default_name_and_address (registry
, NULL
, &address
);
624 e_cal_component_free_attendee_list (attendees
);
627 address
= g_strdup ("");
633 itip_strip_mailto (const gchar
*address
)
638 if (!g_ascii_strncasecmp (address
, "mailto:", 7))
645 get_label (struct icaltimetype
*tt
,
646 gboolean use_24_hour_format
)
651 tmp_tm
= icaltimetype_to_tm (tt
);
653 e_time_format_date_and_time (
654 &tmp_tm
, use_24_hour_format
, FALSE
, FALSE
, buffer
, 1000);
656 return g_strdup (buffer
);
661 icalcomponent
*icomp
;
663 icalcomponent
*zones
;
667 foreach_tzid_callback (icalparameter
*param
,
670 ItipUtilTZData
*tz_data
= data
;
672 icaltimezone
*zone
= NULL
;
673 icalcomponent
*vtimezone_comp
;
675 /* Get the TZID string from the parameter. */
676 tzid
= icalparameter_get_tzid (param
);
677 if (!tzid
|| g_hash_table_lookup (tz_data
->tzids
, tzid
))
680 /* Look for the timezone */
681 if (tz_data
->zones
!= NULL
)
682 zone
= icalcomponent_get_timezone (tz_data
->zones
, tzid
);
684 zone
= icaltimezone_get_builtin_timezone_from_tzid (tzid
);
685 if (zone
== NULL
&& tz_data
->client
!= NULL
)
686 e_cal_client_get_timezone_sync (tz_data
->client
, tzid
, &zone
, NULL
, NULL
);
690 /* Convert it to a string and add it to the hash. */
691 vtimezone_comp
= icaltimezone_get_component (zone
);
695 icalcomponent_add_component (
696 tz_data
->icomp
, icalcomponent_new_clone (vtimezone_comp
));
697 g_hash_table_insert (tz_data
->tzids
, (gchar
*) tzid
, (gchar
*) tzid
);
700 static icalcomponent
*
701 comp_toplevel_with_zones (ECalComponentItipMethod method
,
702 const GSList
*ecomps
,
703 ECalClient
*cal_client
,
704 icalcomponent
*zones
)
706 icalcomponent
*top_level
, *icomp
;
709 ItipUtilTZData tz_data
;
712 top_level
= e_cal_util_new_top_level ();
714 prop
= icalproperty_new (ICAL_METHOD_PROPERTY
);
715 value
= icalvalue_new_method (itip_methods_enum
[method
]);
716 icalproperty_set_value (prop
, value
);
717 icalcomponent_add_property (top_level
, prop
);
719 tz_data
.tzids
= g_hash_table_new (g_str_hash
, g_str_equal
);
720 tz_data
.icomp
= top_level
;
721 tz_data
.client
= cal_client
;
722 tz_data
.zones
= zones
;
724 for (link
= (GSList
*) ecomps
; link
; link
= g_slist_next (link
)) {
725 icomp
= e_cal_component_get_icalcomponent (link
->data
);
726 icomp
= icalcomponent_new_clone (icomp
);
728 icalcomponent_foreach_tzid (icomp
, foreach_tzid_callback
, &tz_data
);
730 icalcomponent_add_component (top_level
, icomp
);
733 g_hash_table_destroy (tz_data
.tzids
);
739 users_has_attendee (const GSList
*users
,
740 const gchar
*address
)
744 for (l
= users
; l
!= NULL
; l
= l
->next
) {
745 if (!g_ascii_strcasecmp (address
, l
->data
))
753 comp_from (ECalComponentItipMethod method
,
755 ESourceRegistry
*registry
,
758 ECalComponentOrganizer organizer
;
759 ECalComponentAttendee
*attendee
;
762 gchar
*sender
= NULL
;
765 case E_CAL_COMPONENT_METHOD_PUBLISH
:
766 case E_CAL_COMPONENT_METHOD_REQUEST
:
767 return itip_get_comp_attendee (registry
, comp
, NULL
);
769 case E_CAL_COMPONENT_METHOD_REPLY
:
770 sender
= itip_get_comp_attendee (registry
, comp
, NULL
);
773 if (!e_cal_component_has_attendees (comp
))
775 /* coverity[fallthrough] */
777 case E_CAL_COMPONENT_METHOD_CANCEL
:
779 case E_CAL_COMPONENT_METHOD_ADD
:
781 e_cal_component_get_organizer (comp
, &organizer
);
782 if (organizer
.value
== NULL
) {
784 NULL
, GTK_MESSAGE_ERROR
,
785 _("An organizer must be set."));
789 *from_name
= g_strdup (organizer
.cn
);
790 return g_strdup (itip_strip_mailto (organizer
.value
));
793 if (!e_cal_component_has_attendees (comp
))
796 e_cal_component_get_attendee_list (comp
, &attendees
);
797 attendee
= attendees
->data
;
798 if (attendee
->value
!= NULL
) {
799 from
= g_strdup (itip_strip_mailto (attendee
->value
));
801 *from_name
= g_strdup (attendee
->cn
);
804 e_cal_component_free_attendee_list (attendees
);
810 static EDestination
**
811 comp_to_list (ESourceRegistry
*registry
,
812 ECalComponentItipMethod method
,
816 const GSList
*only_attendees
)
818 ECalComponentOrganizer organizer
;
819 GSList
*attendees
, *l
;
820 GPtrArray
*array
= NULL
;
821 EDestination
*destination
;
823 gchar
*sender
= NULL
;
827 EDestination
**destinations
;
831 case E_CAL_COMPONENT_METHOD_REQUEST
:
832 case E_CAL_COMPONENT_METHOD_CANCEL
:
833 e_cal_component_get_attendee_list (comp
, &attendees
);
834 len
= g_slist_length (attendees
);
837 NULL
, GTK_MESSAGE_ERROR
,
838 _("At least one attendee is necessary"));
839 e_cal_component_free_attendee_list (attendees
);
843 e_cal_component_get_organizer (comp
, &organizer
);
844 if (organizer
.value
== NULL
) {
846 NULL
, GTK_MESSAGE_ERROR
,
847 _("An organizer must be set."));
851 array
= g_ptr_array_new ();
853 sender
= itip_get_comp_attendee (registry
, comp
, NULL
);
855 for (l
= attendees
; l
!= NULL
; l
= l
->next
) {
856 ECalComponentAttendee
*att
= l
->data
;
858 /* Bugfix: 688711 - Varadhan
859 * Resource is also considered as a "attendee". If the respective backend
860 * is able to successfully book resources automagically, it will appear
861 * in the users list and thereby won't get added to the list of destinations
862 * to send the meeting invite, otherwise, as a safety measure, a meeting
863 * invite will be sent to the resources as well. */
864 if (att
->cutype
!= ICAL_CUTYPE_INDIVIDUAL
&&
865 att
->cutype
!= ICAL_CUTYPE_GROUP
&&
866 att
->cutype
!= ICAL_CUTYPE_RESOURCE
&&
867 att
->cutype
!= ICAL_CUTYPE_UNKNOWN
)
869 else if (users_has_attendee (users
, att
->value
))
871 else if (att
->sentby
&&
872 users_has_attendee (users
, att
->sentby
))
874 else if (!g_ascii_strcasecmp (
875 att
->value
, organizer
.value
))
877 else if (att
->sentby
&& !g_ascii_strcasecmp (
878 att
->sentby
, organizer
.sentby
))
880 else if (!g_ascii_strcasecmp (
881 itip_strip_mailto (att
->value
), sender
))
883 else if (att
->status
== ICAL_PARTSTAT_DELEGATED
&&
884 (att
->delto
&& *att
->delto
) && !(att
->rsvp
) &&
885 method
== E_CAL_COMPONENT_METHOD_REQUEST
)
887 else if (only_attendees
&&
888 !cal_comp_util_have_in_new_attendees (
889 only_attendees
, itip_strip_mailto (att
->value
)))
892 destination
= e_destination_new ();
894 e_destination_set_name (destination
, att
->cn
);
895 e_destination_set_email (
896 destination
, itip_strip_mailto (att
->value
));
897 g_ptr_array_add (array
, destination
);
900 e_cal_component_free_attendee_list (attendees
);
903 case E_CAL_COMPONENT_METHOD_REPLY
:
906 e_cal_component_get_attendee_list (comp
, &attendees
);
907 len
= g_slist_length (attendees
);
912 array
= g_ptr_array_new ();
914 sender
= itip_get_comp_attendee (registry
, comp
, NULL
);
916 e_cal_component_get_organizer (comp
, &organizer
);
917 if (organizer
.value
&& (!sender
|| g_ascii_strcasecmp (
918 itip_strip_mailto (organizer
.value
), sender
) != 0)) {
919 destination
= e_destination_new ();
920 e_destination_set_email (
922 itip_strip_mailto (organizer
.value
));
924 e_destination_set_name (destination
, organizer
.cn
);
925 g_ptr_array_add (array
, destination
);
928 for (l
= attendees
; l
!= NULL
; l
= l
->next
) {
929 ECalComponentAttendee
*att
= l
->data
;
933 else if (att
->cutype
!= ICAL_CUTYPE_INDIVIDUAL
&&
934 att
->cutype
!= ICAL_CUTYPE_GROUP
&&
935 att
->cutype
!= ICAL_CUTYPE_UNKNOWN
)
937 else if (only_attendees
&&
938 !cal_comp_util_have_in_new_attendees (
939 only_attendees
, itip_strip_mailto (att
->value
)))
941 else if (organizer
.value
&&
942 g_ascii_strcasecmp (att
->value
, organizer
.value
) == 0)
944 else if (sender
&& g_ascii_strcasecmp (
945 itip_strip_mailto (att
->value
), sender
) == 0)
948 destination
= e_destination_new ();
950 e_destination_set_name (destination
, att
->cn
);
951 e_destination_set_email (
952 destination
, itip_strip_mailto (att
->value
));
953 g_ptr_array_add (array
, destination
);
957 e_cal_component_free_attendee_list (attendees
);
960 array
= g_ptr_array_new ();
962 destination
= e_destination_new ();
963 e_cal_component_get_organizer (comp
, &organizer
);
965 e_destination_set_name (destination
, organizer
.cn
);
967 e_destination_set_email (
968 destination
, itip_strip_mailto (organizer
.value
));
969 g_ptr_array_add (array
, destination
);
973 case E_CAL_COMPONENT_METHOD_ADD
:
974 case E_CAL_COMPONENT_METHOD_REFRESH
:
975 case E_CAL_COMPONENT_METHOD_COUNTER
:
976 case E_CAL_COMPONENT_METHOD_DECLINECOUNTER
:
977 e_cal_component_get_organizer (comp
, &organizer
);
978 if (organizer
.value
== NULL
) {
980 NULL
, GTK_MESSAGE_ERROR
,
981 _("An organizer must be set."));
985 array
= g_ptr_array_new ();
987 destination
= e_destination_new ();
988 if (organizer
.cn
!= NULL
)
989 e_destination_set_name (destination
, organizer
.cn
);
990 e_destination_set_email (
991 destination
, itip_strip_mailto (organizer
.value
));
992 g_ptr_array_add (array
, destination
);
994 /* send the status to delegatee to the delegate also*/
995 e_cal_component_get_attendee_list (comp
, &attendees
);
996 sender
= itip_get_comp_attendee (registry
, comp
, NULL
);
998 for (l
= attendees
; l
!= NULL
; l
= l
->next
) {
999 ECalComponentAttendee
*att
= l
->data
;
1001 if (att
->cutype
!= ICAL_CUTYPE_INDIVIDUAL
&&
1002 att
->cutype
!= ICAL_CUTYPE_GROUP
&&
1003 att
->cutype
!= ICAL_CUTYPE_UNKNOWN
)
1006 if (!g_ascii_strcasecmp (
1007 itip_strip_mailto (att
->value
), sender
) ||
1008 (att
->sentby
&& !g_ascii_strcasecmp (
1009 itip_strip_mailto (att
->sentby
), sender
))) {
1011 if (!(att
->delfrom
&& *att
->delfrom
))
1014 destination
= e_destination_new ();
1015 e_destination_set_email (
1016 destination
, itip_strip_mailto (att
->delfrom
));
1017 g_ptr_array_add (array
, destination
);
1021 e_cal_component_free_attendee_list (attendees
);
1024 case E_CAL_COMPONENT_METHOD_PUBLISH
:
1028 array
= g_ptr_array_new ();
1030 for (list
= users
; list
!= NULL
; list
= list
->next
) {
1031 destination
= e_destination_new ();
1032 e_destination_set_email (destination
, list
->data
);
1033 g_ptr_array_add (array
, destination
);
1045 g_ptr_array_add (array
, NULL
);
1046 convert
.pdata
= g_ptr_array_free (array
, FALSE
);
1048 return convert
.destinations
;
1052 comp_subject (ESourceRegistry
*registry
,
1053 ECalComponentItipMethod method
,
1054 ECalComponent
*comp
)
1056 ECalComponentText caltext
;
1057 const gchar
*description
, *prefix
= NULL
;
1061 ECalComponentAttendee
*a
= NULL
;
1063 e_cal_component_get_summary (comp
, &caltext
);
1064 if (caltext
.value
!= NULL
)
1065 description
= caltext
.value
;
1067 switch (e_cal_component_get_vtype (comp
)) {
1068 case E_CAL_COMPONENT_EVENT
:
1069 description
= _("Event information");
1071 case E_CAL_COMPONENT_TODO
:
1072 description
= _("Task information");
1074 case E_CAL_COMPONENT_JOURNAL
:
1075 description
= _("Memo information");
1077 case E_CAL_COMPONENT_FREEBUSY
:
1078 description
= _("Free/Busy information");
1081 description
= _("Calendar information");
1086 case E_CAL_COMPONENT_METHOD_PUBLISH
:
1087 case E_CAL_COMPONENT_METHOD_REQUEST
:
1088 /* FIXME: If this is an update to a previous
1089 * PUBLISH or REQUEST, then
1090 prefix = U_("Updated");
1094 case E_CAL_COMPONENT_METHOD_REPLY
:
1095 e_cal_component_get_attendee_list (comp
, &alist
);
1096 sender
= itip_get_comp_attendee (registry
, comp
, NULL
);
1099 for (l
= alist
; l
!= NULL
; l
= l
->next
) {
1101 if ((sender
&& *sender
) && (g_ascii_strcasecmp (
1102 itip_strip_mailto (a
->value
), sender
) ||
1103 (a
->sentby
&& g_ascii_strcasecmp (
1104 itip_strip_mailto (a
->sentby
), sender
))))
1112 switch (a
->status
) {
1113 case ICAL_PARTSTAT_ACCEPTED
:
1114 /* Translators: This is part of the subject
1115 * line of a meeting request or update email.
1116 * The full subject line would be:
1117 * "Accepted: Meeting Name". */
1118 prefix
= C_("Meeting", "Accepted");
1120 case ICAL_PARTSTAT_TENTATIVE
:
1121 /* Translators: This is part of the subject
1122 * line of a meeting request or update email.
1123 * The full subject line would be:
1124 * "Tentatively Accepted: Meeting Name". */
1125 prefix
= C_("Meeting", "Tentatively Accepted");
1127 case ICAL_PARTSTAT_DECLINED
:
1128 /* Translators: This is part of the subject
1129 * line of a meeting request or update email.
1130 * The full subject line would be:
1131 * "Declined: Meeting Name". */
1132 prefix
= C_("Meeting", "Declined");
1134 case ICAL_PARTSTAT_DELEGATED
:
1135 /* Translators: This is part of the subject
1136 * line of a meeting request or update email.
1137 * The full subject line would be:
1138 * "Delegated: Meeting Name". */
1139 prefix
= C_("Meeting", "Delegated");
1144 e_cal_component_free_attendee_list (alist
);
1148 case E_CAL_COMPONENT_METHOD_ADD
:
1149 /* Translators: This is part of the subject line of a
1150 * meeting request or update email. The full subject
1151 * line would be: "Updated: Meeting Name". */
1152 prefix
= C_("Meeting", "Updated");
1155 case E_CAL_COMPONENT_METHOD_CANCEL
:
1156 /* Translators: This is part of the subject line of a
1157 * meeting request or update email. The full subject
1158 * line would be: "Cancel: Meeting Name". */
1159 prefix
= C_("Meeting", "Cancel");
1162 case E_CAL_COMPONENT_METHOD_REFRESH
:
1163 /* Translators: This is part of the subject line of a
1164 * meeting request or update email. The full subject
1165 * line would be: "Refresh: Meeting Name". */
1166 prefix
= C_("Meeting", "Refresh");
1169 case E_CAL_COMPONENT_METHOD_COUNTER
:
1170 /* Translators: This is part of the subject line of a
1171 * meeting request or update email. The full subject
1172 * line would be: "Counter-proposal: Meeting Name". */
1173 prefix
= C_("Meeting", "Counter-proposal");
1176 case E_CAL_COMPONENT_METHOD_DECLINECOUNTER
:
1177 /* Translators: This is part of the subject line of a
1178 * meeting request or update email. The full subject
1179 * line would be: "Declined: Meeting Name". */
1180 prefix
= C_("Meeting", "Declined");
1188 subject
= g_strdup_printf ("%s: %s", prefix
, description
);
1190 subject
= g_strdup (description
);
1196 comp_content_type (ECalComponent
*comp
,
1197 ECalComponentItipMethod method
)
1201 if (e_cal_component_get_vtype (comp
) == E_CAL_COMPONENT_FREEBUSY
)
1202 name
= "freebusy.ifb";
1204 name
= "calendar.ics";
1206 return g_strdup_printf (
1207 "text/calendar; name=\"%s\"; charset=utf-8; METHOD=%s",
1208 name
, itip_methods
[method
]);
1211 static const gchar
*
1212 comp_filename (ECalComponent
*comp
)
1214 if (e_cal_component_get_vtype (comp
) == E_CAL_COMPONENT_FREEBUSY
)
1215 return "freebusy.ifb";
1217 return "calendar.ics";
1221 comp_description (ECalComponent
*comp
,
1222 gboolean use_24_hour_format
)
1225 ECalComponentDateTime dt
;
1226 gchar
*start
= NULL
, *end
= NULL
;
1228 switch (e_cal_component_get_vtype (comp
)) {
1229 case E_CAL_COMPONENT_EVENT
:
1230 description
= g_strdup (_("Event information"));
1232 case E_CAL_COMPONENT_TODO
:
1233 description
= g_strdup (_("Task information"));
1235 case E_CAL_COMPONENT_JOURNAL
:
1236 description
= g_strdup (_("Memo information"));
1238 case E_CAL_COMPONENT_FREEBUSY
:
1239 e_cal_component_get_dtstart (comp
, &dt
);
1241 start
= get_label (dt
.value
, use_24_hour_format
);
1242 e_cal_component_free_datetime (&dt
);
1244 e_cal_component_get_dtend (comp
, &dt
);
1246 end
= get_label (dt
.value
, use_24_hour_format
);
1247 e_cal_component_free_datetime (&dt
);
1249 if (start
!= NULL
&& end
!= NULL
)
1250 description
= g_strdup_printf (
1251 _("Free/Busy information (%s to %s)"),
1254 description
= g_strdup (_("Free/Busy information"));
1259 description
= g_strdup (_("iCalendar information"));
1267 comp_server_send_sync (ECalComponentItipMethod method
,
1268 const GSList
*ecomps
,
1269 ECalClient
*cal_client
,
1270 icalcomponent
*zones
,
1272 GCancellable
*cancellable
,
1275 icalcomponent
*top_level
, *returned_icalcomp
= NULL
;
1276 gboolean retval
= TRUE
;
1277 GError
*local_error
= NULL
;
1279 top_level
= comp_toplevel_with_zones (method
, ecomps
, cal_client
, zones
);
1280 d (printf ("itip-utils.c: comp_server_send_sync: calling e_cal_send_objects... \n"));
1282 e_cal_client_send_objects_sync (
1283 cal_client
, top_level
, users
,
1284 &returned_icalcomp
, cancellable
, &local_error
);
1286 if (g_error_matches (local_error
, E_CAL_CLIENT_ERROR
, E_CAL_CLIENT_ERROR_OBJECT_ID_ALREADY_EXISTS
)) {
1287 g_propagate_error (error
, g_error_new (local_error
->domain
, local_error
->code
,
1288 _("Unable to book a resource, the new event collides with some other.")));
1289 g_clear_error (&local_error
);
1292 } else if (local_error
!= NULL
) {
1293 g_prefix_error (&local_error
, "%s", _("Unable to book a resource, error: "));
1294 g_propagate_error (error
, local_error
);
1298 if (returned_icalcomp
!= NULL
)
1299 icalcomponent_free (returned_icalcomp
);
1300 icalcomponent_free (top_level
);
1306 comp_limit_attendees (ESourceRegistry
*registry
,
1307 ECalComponent
*comp
)
1309 icalcomponent
*icomp
;
1311 gboolean found
= FALSE
, match
= FALSE
;
1312 GSList
*l
, *list
= NULL
;
1314 icomp
= e_cal_component_get_icalcomponent (comp
);
1316 for (prop
= icalcomponent_get_first_property (icomp
, ICAL_ATTENDEE_PROPERTY
);
1318 prop
= icalcomponent_get_next_property (icomp
, ICAL_ATTENDEE_PROPERTY
))
1321 gchar
*attendee_text
;
1322 icalparameter
*param
;
1323 const gchar
*attendee_sentby
;
1324 gchar
*attendee_sentby_text
= NULL
;
1326 /* If we've already found something, just erase the rest */
1328 list
= g_slist_prepend (list
, prop
);
1332 attendee
= icalproperty_get_value_as_string_r (prop
);
1336 attendee_text
= g_strdup (itip_strip_mailto (attendee
));
1338 attendee_text
= g_strstrip (attendee_text
);
1339 found
= match
= itip_address_is_user (registry
, attendee_text
);
1342 param
= icalproperty_get_first_parameter (prop
, ICAL_SENTBY_PARAMETER
);
1345 icalparameter_get_sentby (param
);
1347 itip_strip_mailto (attendee_sentby
);
1348 attendee_sentby_text
=
1349 g_strstrip (g_strdup (attendee_sentby
));
1350 found
= match
= itip_address_is_user (
1351 registry
, attendee_sentby_text
);
1355 g_free (attendee_text
);
1356 g_free (attendee_sentby_text
);
1359 list
= g_slist_prepend (list
, prop
);
1362 for (l
= list
; l
!= NULL
; l
= l
->next
) {
1365 icalcomponent_remove_property (icomp
, prop
);
1366 icalproperty_free (prop
);
1368 g_slist_free (list
);
1374 comp_sentby (ECalComponent
*comp
,
1375 ECalClient
*cal_client
,
1376 ESourceRegistry
*registry
)
1378 ECalComponentOrganizer organizer
;
1379 GSList
* attendees
, *l
;
1384 itip_get_default_name_and_address (registry
, &name
, &address
);
1386 e_cal_component_get_organizer (comp
, &organizer
);
1387 if (!organizer
.value
&& name
!= NULL
&& address
!= NULL
) {
1388 organizer
.value
= g_strdup_printf ("MAILTO:%s", address
);
1389 organizer
.sentby
= NULL
;
1390 organizer
.cn
= name
;
1391 organizer
.language
= NULL
;
1393 e_cal_component_set_organizer (comp
, &organizer
);
1394 g_free ((gchar
*) organizer
.value
);
1401 e_cal_component_get_attendee_list (comp
, &attendees
);
1402 user
= itip_get_comp_attendee (registry
, comp
, cal_client
);
1403 for (l
= attendees
; l
; l
= l
->next
) {
1404 ECalComponentAttendee
*a
= l
->data
;
1406 if (!g_ascii_strcasecmp (
1407 itip_strip_mailto (a
->value
), user
) ||
1408 (a
->sentby
&& !g_ascii_strcasecmp (
1409 itip_strip_mailto (a
->sentby
), user
))) {
1418 if (!itip_organizer_is_user (registry
, comp
, cal_client
) &&
1419 !itip_sentby_is_user (registry
, comp
, cal_client
) &&
1421 organizer
.value
= g_strdup (organizer
.value
);
1422 organizer
.sentby
= g_strdup_printf ("MAILTO:%s", address
);
1423 organizer
.cn
= g_strdup (organizer
.cn
);
1424 organizer
.language
= g_strdup (organizer
.language
);
1426 e_cal_component_set_organizer (comp
, &organizer
);
1428 g_free ((gchar
*) organizer
.value
);
1429 g_free ((gchar
*) organizer
.sentby
);
1430 g_free ((gchar
*) organizer
.cn
);
1431 g_free ((gchar
*) organizer
.language
);
1438 static ECalComponent
*
1439 comp_minimal (ESourceRegistry
*registry
,
1440 ECalComponent
*comp
,
1443 ECalComponent
*clone
;
1444 icalcomponent
*icomp
, *icomp_clone
;
1446 ECalComponentOrganizer organizer
;
1449 struct icaltimetype itt
;
1450 ECalComponentRange recur_id
;
1452 clone
= e_cal_component_new ();
1453 e_cal_component_set_new_vtype (clone
, e_cal_component_get_vtype (comp
));
1458 e_cal_component_get_attendee_list (comp
, &attendees
);
1459 e_cal_component_set_attendee_list (clone
, attendees
);
1461 if (!comp_limit_attendees (registry
, clone
)) {
1463 NULL
, GTK_MESSAGE_ERROR
,
1464 _("You must be an attendee of the event."));
1469 itt
= icaltime_from_timet_with_zone (
1471 icaltimezone_get_utc_timezone ());
1472 e_cal_component_set_dtstamp (clone
, &itt
);
1474 e_cal_component_get_organizer (comp
, &organizer
);
1475 if (organizer
.value
== NULL
)
1477 e_cal_component_set_organizer (clone
, &organizer
);
1479 e_cal_component_get_uid (comp
, &uid
);
1480 e_cal_component_set_uid (clone
, uid
);
1482 e_cal_component_get_comment_list (comp
, &comments
);
1483 if (g_slist_length (comments
) <= 1) {
1484 e_cal_component_set_comment_list (clone
, comments
);
1486 GSList
*l
= comments
;
1488 comments
= g_slist_remove_link (comments
, l
);
1489 e_cal_component_set_comment_list (clone
, l
);
1490 e_cal_component_free_text_list (l
);
1492 e_cal_component_free_text_list (comments
);
1494 e_cal_component_get_recurid (comp
, &recur_id
);
1495 if (recur_id
.datetime
.value
!= NULL
)
1496 e_cal_component_set_recurid (clone
, &recur_id
);
1498 icomp
= e_cal_component_get_icalcomponent (comp
);
1499 icomp_clone
= e_cal_component_get_icalcomponent (clone
);
1500 for (prop
= icalcomponent_get_first_property (icomp
, ICAL_X_PROPERTY
);
1502 prop
= icalcomponent_get_next_property (icomp
, ICAL_X_PROPERTY
))
1506 p
= icalproperty_new_clone (prop
);
1507 icalcomponent_add_property (icomp_clone
, p
);
1510 e_cal_component_rescan (clone
);
1515 g_object_unref (clone
);
1520 strip_x_microsoft_props (ECalComponent
*comp
)
1522 GSList
*lst
= NULL
, *l
;
1523 icalcomponent
*icalcomp
;
1524 icalproperty
*icalprop
;
1526 g_return_if_fail (comp
!= NULL
);
1528 icalcomp
= e_cal_component_get_icalcomponent (comp
);
1529 g_return_if_fail (icalcomp
!= NULL
);
1531 for (icalprop
= icalcomponent_get_first_property (icalcomp
, ICAL_X_PROPERTY
);
1533 icalprop
= icalcomponent_get_next_property (icalcomp
, ICAL_X_PROPERTY
)) {
1534 const gchar
*x_name
= icalproperty_get_x_name (icalprop
);
1536 if (x_name
&& g_ascii_strncasecmp (x_name
, "X-MICROSOFT-", 12) == 0)
1537 lst
= g_slist_prepend (lst
, icalprop
);
1540 for (l
= lst
; l
!= NULL
; l
= l
->next
) {
1542 icalcomponent_remove_property (icalcomp
, icalprop
);
1543 icalproperty_free (icalprop
);
1549 static ECalComponent
*
1550 comp_compliant_one (ESourceRegistry
*registry
,
1551 ECalComponentItipMethod method
,
1552 ECalComponent
*comp
,
1554 icalcomponent
*zones
,
1555 icaltimezone
*default_zone
,
1556 gboolean strip_alarms
)
1558 ECalComponent
*clone
, *temp_clone
;
1559 struct icaltimetype itt
;
1561 clone
= e_cal_component_clone (comp
);
1562 itt
= icaltime_from_timet_with_zone (
1564 icaltimezone_get_utc_timezone ());
1565 e_cal_component_set_dtstamp (clone
, &itt
);
1567 /* Make UNTIL date a datetime in a simple recurrence */
1568 if (e_cal_component_has_recurrences (clone
)
1569 && e_cal_component_has_simple_recurrence (clone
)) {
1571 struct icalrecurrencetype
*r
;
1573 e_cal_component_get_rrule_list (clone
, &rrule_list
);
1574 r
= rrule_list
->data
;
1576 if (!icaltime_is_null_time (r
->until
) && r
->until
.is_date
) {
1577 ECalComponentDateTime dt
;
1578 icaltimezone
*from_zone
= NULL
, *to_zone
;
1580 e_cal_component_get_dtstart (clone
, &dt
);
1582 if (dt
.value
->is_date
) {
1583 from_zone
= default_zone
;
1584 } else if (dt
.tzid
== NULL
) {
1585 from_zone
= icaltimezone_get_utc_timezone ();
1588 from_zone
= icalcomponent_get_timezone (zones
, dt
.tzid
);
1589 if (from_zone
== NULL
)
1590 from_zone
= icaltimezone_get_builtin_timezone_from_tzid (dt
.tzid
);
1591 if (from_zone
== NULL
&& client
!= NULL
)
1592 /* FIXME Error checking */
1593 e_cal_client_get_timezone_sync (
1595 &from_zone
, NULL
, NULL
);
1598 to_zone
= icaltimezone_get_utc_timezone ();
1600 r
->until
.hour
= dt
.value
->hour
;
1601 r
->until
.minute
= dt
.value
->minute
;
1602 r
->until
.second
= dt
.value
->second
;
1603 r
->until
.is_date
= FALSE
;
1605 icaltimezone_convert_time (&r
->until
, from_zone
, to_zone
);
1606 r
->until
.zone
= to_zone
;
1608 e_cal_component_free_datetime (&dt
);
1609 e_cal_component_set_rrule_list (clone
, rrule_list
);
1610 e_cal_component_abort_sequence (clone
);
1613 e_cal_component_free_recur_list (rrule_list
);
1616 /* We delete incoming alarms if requested, even this helps with outlook */
1618 e_cal_component_remove_all_alarms (clone
);
1620 /* Always strip procedure alarms, because of security */
1623 uids
= e_cal_component_get_alarm_uids (clone
);
1625 for (l
= uids
; l
; l
= l
->next
) {
1626 ECalComponentAlarm
*alarm
;
1627 ECalComponentAlarmAction action
= E_CAL_COMPONENT_ALARM_UNKNOWN
;
1629 alarm
= e_cal_component_get_alarm (clone
, (const gchar
*) l
->data
);
1631 e_cal_component_alarm_get_action (alarm
, &action
);
1632 e_cal_component_alarm_free (alarm
);
1634 if (action
== E_CAL_COMPONENT_ALARM_PROCEDURE
)
1635 e_cal_component_remove_alarm (clone
, (const gchar
*) l
->data
);
1639 cal_obj_uid_list_free (uids
);
1642 strip_x_microsoft_props (clone
);
1644 /* Strip X-LIC-ERROR stuff */
1645 e_cal_component_strip_errors (clone
);
1647 /* Comply with itip spec */
1649 case E_CAL_COMPONENT_METHOD_PUBLISH
:
1650 comp_sentby (clone
, client
, registry
);
1651 e_cal_component_set_attendee_list (clone
, NULL
);
1653 case E_CAL_COMPONENT_METHOD_REQUEST
:
1654 comp_sentby (clone
, client
, registry
);
1656 case E_CAL_COMPONENT_METHOD_CANCEL
:
1657 comp_sentby (clone
, client
, registry
);
1659 case E_CAL_COMPONENT_METHOD_REPLY
:
1661 case E_CAL_COMPONENT_METHOD_ADD
:
1663 case E_CAL_COMPONENT_METHOD_REFRESH
:
1664 /* Need to remove almost everything */
1665 temp_clone
= comp_minimal (registry
, clone
, TRUE
);
1666 g_object_unref (clone
);
1669 case E_CAL_COMPONENT_METHOD_COUNTER
:
1671 case E_CAL_COMPONENT_METHOD_DECLINECOUNTER
:
1672 /* Need to remove almost everything */
1673 temp_clone
= comp_minimal (registry
, clone
, FALSE
);
1674 g_object_unref (clone
);
1685 comp_compliant (ESourceRegistry
*registry
,
1686 ECalComponentItipMethod method
,
1688 gboolean unref_orig_ecomp
,
1690 icalcomponent
*zones
,
1691 icaltimezone
*default_zone
,
1692 gboolean strip_alarms
)
1699 for (link
= ecomps
; link
; link
= g_slist_next (link
)) {
1700 ECalComponent
*original_comp
= link
->data
, *new_comp
;
1702 new_comp
= comp_compliant_one (registry
, method
, original_comp
, client
, zones
, default_zone
, strip_alarms
);
1704 cal_comp_util_copy_new_attendees (new_comp
, original_comp
);
1706 if (unref_orig_ecomp
)
1707 g_object_unref (original_comp
);
1709 link
->data
= new_comp
;
1719 itip_cal_mime_attach_free (gpointer ptr
)
1721 struct CalMimeAttach
*mime_attach
= ptr
;
1724 g_free (mime_attach
->filename
);
1725 g_free (mime_attach
->content_type
);
1726 g_free (mime_attach
->content_id
);
1727 g_free (mime_attach
->description
);
1728 g_free (mime_attach
->encoded_data
);
1729 g_free (mime_attach
);
1734 append_cal_attachments (EMsgComposer
*composer
,
1735 GSList
*attach_list
)
1737 struct CalMimeAttach
*mime_attach
;
1740 for (l
= attach_list
; l
; l
= l
->next
) {
1741 CamelMimePart
*attachment
;
1743 mime_attach
= (struct CalMimeAttach
*) l
->data
;
1745 attachment
= camel_mime_part_new ();
1746 camel_mime_part_set_content (
1747 attachment
, mime_attach
->encoded_data
,
1748 mime_attach
->length
, mime_attach
->content_type
);
1749 if (mime_attach
->content_id
)
1750 camel_mime_part_set_content_id (
1751 attachment
, mime_attach
->content_id
);
1752 if (mime_attach
->filename
!= NULL
)
1753 camel_mime_part_set_filename (
1754 attachment
, mime_attach
->filename
);
1755 if (mime_attach
->description
!= NULL
)
1756 camel_mime_part_set_description (
1757 attachment
, mime_attach
->description
);
1758 if (mime_attach
->disposition
)
1759 camel_mime_part_set_disposition (
1760 attachment
, "inline");
1762 camel_mime_part_set_disposition (
1763 attachment
, "attachment");
1764 e_msg_composer_attach (composer
, attachment
);
1765 g_object_unref (attachment
);
1768 g_slist_free_full (attach_list
, itip_cal_mime_attach_free
);
1772 find_enabled_identity (ESourceRegistry
*registry
,
1773 const gchar
*id_address
)
1776 ESource
*mail_identity
= NULL
;
1777 const gchar
*extension_name
;
1779 if (id_address
== NULL
)
1782 extension_name
= E_SOURCE_EXTENSION_MAIL_IDENTITY
;
1783 list
= e_source_registry_list_enabled (registry
, extension_name
);
1785 for (link
= list
; link
!= NULL
; link
= g_list_next (link
)) {
1786 ESource
*source
= E_SOURCE (link
->data
);
1787 ESourceMailIdentity
*extension
;
1788 GHashTable
*aliases
;
1789 const gchar
*address
;
1791 extension
= e_source_get_extension (source
, extension_name
);
1792 address
= e_source_mail_identity_get_address (extension
);
1794 if (address
&& g_ascii_strcasecmp (address
, id_address
) == 0) {
1795 mail_identity
= g_object_ref (source
);
1799 aliases
= e_source_mail_identity_get_aliases_as_hash_table (extension
);
1801 if (g_hash_table_contains (aliases
, id_address
))
1802 mail_identity
= g_object_ref (source
);
1803 g_hash_table_destroy (aliases
);
1810 g_list_free_full (list
, (GDestroyNotify
) g_object_unref
);
1812 return mail_identity
;
1816 get_identity_uid_for_from (EShell
*shell
,
1817 ECalComponentItipMethod method
,
1818 ECalComponent
*comp
,
1819 ECalClient
*cal_client
,
1820 gchar
**identity_name
,
1821 gchar
**identity_address
)
1823 EClientCache
*client_cache
;
1824 ESourceRegistry
*registry
;
1825 ESource
*source
= NULL
;
1826 gchar
*identity_uid
= NULL
;
1828 client_cache
= e_shell_get_client_cache (shell
);
1829 registry
= e_client_cache_ref_registry (client_cache
);
1831 /* always use organizer's email when user is an organizer */
1832 if (itip_organizer_is_user (registry
, comp
, cal_client
)) {
1833 ECalComponentOrganizer organizer
= {0};
1835 e_cal_component_get_organizer (comp
, &organizer
);
1836 if (organizer
.value
!= NULL
) {
1837 source
= find_enabled_identity (
1839 itip_strip_mailto (organizer
.value
));
1843 *identity_name
= g_strdup (organizer
.cn
);
1844 if (identity_address
)
1845 *identity_address
= g_strdup (itip_strip_mailto (organizer
.value
));
1850 if (source
== NULL
) {
1851 gchar
*from
= comp_from (method
, comp
, registry
, identity_name
);
1854 source
= find_enabled_identity (registry
, from
);
1856 if (identity_address
)
1857 *identity_address
= g_strdup (from
);
1864 if (source
!= NULL
) {
1865 identity_uid
= g_strdup (e_source_get_uid (source
));
1867 g_object_unref (source
);
1870 g_object_unref (registry
);
1872 return identity_uid
;
1876 master_first_cmp (gconstpointer ptr1
,
1879 ECalComponent
*comp1
= (ECalComponent
*) ptr1
;
1880 ECalComponent
*comp2
= (ECalComponent
*) ptr2
;
1881 icalcomponent
*icomp1
= comp1
? e_cal_component_get_icalcomponent (comp1
) : NULL
;
1882 icalcomponent
*icomp2
= comp2
? e_cal_component_get_icalcomponent (comp2
) : NULL
;
1883 gboolean has_rid1
, has_rid2
;
1885 has_rid1
= (icomp1
&& icalcomponent_get_first_property (icomp1
, ICAL_RECURRENCEID_PROPERTY
)) ? 1 : 0;
1886 has_rid2
= (icomp2
&& icalcomponent_get_first_property (icomp2
, ICAL_RECURRENCEID_PROPERTY
)) ? 1 : 0;
1888 if (has_rid1
== has_rid2
)
1889 return g_strcmp0 (icomp1
? icalcomponent_get_uid (icomp1
) : NULL
,
1890 icomp2
? icalcomponent_get_uid (icomp2
) : NULL
);
1899 ESourceRegistry
*registry
;
1900 ECalComponentItipMethod method
;
1901 GSList
*send_comps
; /* ECalComponent * */
1902 ECalClient
*cal_client
;
1903 icalcomponent
*zones
;
1904 GSList
*attachments_list
;
1906 gboolean strip_alarms
;
1907 gboolean only_new_attendees
;
1908 gboolean ensure_master_object
;
1913 GError
*async_error
;
1914 } ItipSendComponentData
;
1917 itip_send_component_data_free (gpointer ptr
)
1919 ItipSendComponentData
*isc
= ptr
;
1922 g_clear_object (&isc
->registry
);
1923 g_slist_free_full (isc
->send_comps
, g_object_unref
);
1924 g_clear_object (&isc
->cal_client
);
1925 g_clear_error (&isc
->async_error
);
1927 icalcomponent_free (isc
->zones
);
1928 g_slist_free_full (isc
->attachments_list
, itip_cal_mime_attach_free
); /* CamelMimePart */
1929 g_slist_free_full (isc
->users
, g_free
);
1935 itip_send_component_begin (ItipSendComponentData
*isc
,
1936 GCancellable
*cancellable
,
1939 g_return_if_fail (isc
!= NULL
);
1941 isc
->completed
= FALSE
;
1943 if (isc
->method
!= E_CAL_COMPONENT_METHOD_PUBLISH
&& e_cal_client_check_save_schedules (isc
->cal_client
)) {
1944 isc
->success
= TRUE
;
1945 isc
->completed
= TRUE
;
1949 if (isc
->ensure_master_object
&& isc
->send_comps
) {
1950 /* Ensure we send the master object with its detached instances, not the instance only */
1951 GSList
*ecalcomps
= NULL
;
1952 const gchar
*uid
= NULL
;
1954 e_cal_component_get_uid (isc
->send_comps
->data
, &uid
);
1956 if (e_cal_client_get_objects_for_uid_sync (isc
->cal_client
, uid
, &ecalcomps
, cancellable
, NULL
) && ecalcomps
) {
1957 GSList
*old_send_comps
= isc
->send_comps
;
1959 isc
->send_comps
= g_slist_sort (ecalcomps
, master_first_cmp
);
1961 cal_comp_util_copy_new_attendees (isc
->send_comps
->data
, old_send_comps
->data
);
1963 g_slist_free_full (old_send_comps
, g_object_unref
);
1967 /* Give the server a chance to manipulate the comp */
1968 if (isc
->method
!= E_CAL_COMPONENT_METHOD_PUBLISH
) {
1969 d (printf ("itip-utils.c: itip_send_component_begin: calling comp_server_send_sync... \n"));
1970 if (!comp_server_send_sync (isc
->method
, isc
->send_comps
, isc
->cal_client
, isc
->zones
, &isc
->users
, cancellable
, error
)) {
1971 isc
->success
= FALSE
;
1972 isc
->completed
= TRUE
;
1977 /* check whether backend could handle sending requests/updates */
1978 if (isc
->method
!= E_CAL_COMPONENT_METHOD_PUBLISH
&&
1979 e_client_check_capability (E_CLIENT (isc
->cal_client
), CAL_STATIC_CAPABILITY_CREATE_MESSAGES
)) {
1980 isc
->success
= TRUE
;
1981 isc
->completed
= TRUE
;
1985 typedef struct _CreateComposerData
{
1986 gchar
*identity_uid
;
1987 gchar
*identity_name
;
1988 gchar
*identity_address
;
1989 EDestination
**destinations
;
1992 gchar
*content_type
;
1993 gchar
*event_body_text
;
1994 GSList
*attachments_list
;
1995 GSList
*send_comps
; /* ECalComponent * */
1997 } CreateComposerData
;
2000 itip_send_component_composer_created_cb (GObject
*source_object
,
2001 GAsyncResult
*result
,
2004 CreateComposerData
*ccd
= user_data
;
2005 EComposerHeaderTable
*table
;
2006 EMsgComposer
*composer
;
2007 GSettings
*settings
;
2008 gboolean use_24hour_format
;
2009 GError
*error
= NULL
;
2011 g_return_if_fail (ccd
!= NULL
);
2013 composer
= e_msg_composer_new_finish (result
, &error
);
2015 g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC
, error
->message
);
2016 g_clear_error (&error
);
2020 settings
= e_util_ref_settings ("org.gnome.evolution.calendar");
2021 use_24hour_format
= g_settings_get_boolean (settings
, "use-24hour-format");
2022 g_object_unref (settings
);
2024 table
= e_msg_composer_get_header_table (composer
);
2026 if (ccd
->identity_uid
)
2027 e_composer_header_table_set_identity_uid (table
, ccd
->identity_uid
, ccd
->identity_name
, ccd
->identity_address
);
2029 e_composer_header_table_set_subject (table
, ccd
->subject
);
2030 e_composer_header_table_set_destinations_to (table
, ccd
->destinations
);
2032 if (e_cal_component_get_vtype (ccd
->send_comps
->data
) == E_CAL_COMPONENT_EVENT
) {
2033 if (ccd
->event_body_text
)
2034 e_msg_composer_set_body_text (composer
, ccd
->event_body_text
, TRUE
);
2036 e_msg_composer_set_body (composer
, ccd
->ical_string
, ccd
->content_type
);
2038 CamelMimePart
*attachment
;
2039 const gchar
*filename
;
2043 filename
= comp_filename (ccd
->send_comps
->data
);
2044 description
= comp_description (ccd
->send_comps
->data
, use_24hour_format
);
2046 body
= camel_text_to_html (description
, CAMEL_MIME_FILTER_TOHTML_PRE
, 0);
2047 e_msg_composer_set_body_text (composer
, body
, TRUE
);
2050 attachment
= camel_mime_part_new ();
2051 camel_mime_part_set_content (
2052 attachment
, ccd
->ical_string
,
2053 strlen (ccd
->ical_string
), ccd
->content_type
);
2054 if (filename
!= NULL
&& *filename
!= '\0')
2055 camel_mime_part_set_filename (attachment
, filename
);
2056 if (description
!= NULL
&& *description
!= '\0')
2057 camel_mime_part_set_description (attachment
, description
);
2058 camel_mime_part_set_disposition (attachment
, "inline");
2059 e_msg_composer_attach (composer
, attachment
);
2060 g_object_unref (attachment
);
2062 g_free (description
);
2065 append_cal_attachments (composer
, ccd
->attachments_list
);
2066 ccd
->attachments_list
= NULL
;
2069 gtk_widget_show (GTK_WIDGET (composer
));
2071 e_msg_composer_send (composer
);
2073 e_destination_freev (ccd
->destinations
);
2074 g_slist_free_full (ccd
->send_comps
, g_object_unref
);
2075 g_free (ccd
->identity_uid
);
2076 g_free (ccd
->identity_name
);
2077 g_free (ccd
->identity_address
);
2078 g_free (ccd
->subject
);
2079 g_free (ccd
->ical_string
);
2080 g_free (ccd
->content_type
);
2081 g_free (ccd
->event_body_text
);
2086 itip_send_component_complete (ItipSendComponentData
*isc
)
2088 CreateComposerData
*ccd
;
2089 EDestination
**destinations
;
2091 icalcomponent
*top_level
= NULL
;
2092 icaltimezone
*default_zone
;
2093 gchar
*identity_uid
, *identity_name
= NULL
, *identity_address
= NULL
;
2095 g_return_if_fail (isc
!= NULL
);
2100 isc
->success
= FALSE
;
2102 default_zone
= calendar_config_get_icaltimezone ();
2104 shell
= e_shell_get_default ();
2106 identity_uid
= get_identity_uid_for_from (shell
, isc
->method
, isc
->send_comps
->data
, isc
->cal_client
, &identity_name
, &identity_address
);
2108 /* Tidy up the comp */
2109 if (!comp_compliant (isc
->registry
, isc
->method
, isc
->send_comps
, TRUE
, isc
->cal_client
, isc
->zones
, default_zone
, isc
->strip_alarms
)) {
2110 g_free (identity_uid
);
2111 g_free (identity_name
);
2112 g_free (identity_address
);
2117 destinations
= comp_to_list (
2118 isc
->registry
, isc
->method
, isc
->send_comps
->data
, isc
->users
, FALSE
,
2119 isc
->only_new_attendees
? g_object_get_data (
2120 G_OBJECT (isc
->send_comps
->data
), "new-attendees") : NULL
);
2121 if (isc
->method
!= E_CAL_COMPONENT_METHOD_PUBLISH
) {
2122 if (destinations
== NULL
) {
2123 /* We sent them all via the server */
2124 isc
->success
= TRUE
;
2125 g_free (identity_uid
);
2126 g_free (identity_name
);
2127 g_free (identity_address
);
2132 top_level
= comp_toplevel_with_zones (isc
->method
, isc
->send_comps
, isc
->cal_client
, isc
->zones
);
2134 ccd
= g_new0 (CreateComposerData
, 1);
2135 ccd
->identity_uid
= identity_uid
;
2136 ccd
->identity_name
= identity_name
;
2137 ccd
->identity_address
= identity_address
;
2138 ccd
->destinations
= destinations
;
2139 ccd
->subject
= comp_subject (isc
->registry
, isc
->method
, isc
->send_comps
->data
);
2140 ccd
->ical_string
= icalcomponent_as_ical_string_r (top_level
);
2141 ccd
->content_type
= comp_content_type (isc
->send_comps
->data
, isc
->method
);
2142 ccd
->event_body_text
= NULL
;
2143 ccd
->attachments_list
= isc
->attachments_list
;
2144 ccd
->send_comps
= isc
->send_comps
;
2145 ccd
->show_only
= isc
->method
== E_CAL_COMPONENT_METHOD_PUBLISH
&& !isc
->users
;
2147 isc
->attachments_list
= NULL
;
2148 isc
->send_comps
= NULL
;
2150 e_msg_composer_new (shell
, itip_send_component_composer_created_cb
, ccd
);
2152 isc
->success
= TRUE
;
2155 if (top_level
!= NULL
)
2156 icalcomponent_free (top_level
);
2160 itip_send_component_complete_and_free (gpointer ptr
)
2162 ItipSendComponentData
*isc
= ptr
;
2165 itip_send_component_complete (isc
);
2166 itip_send_component_data_free (isc
);
2171 itip_send_component_thread (EAlertSinkThreadJobData
*job_data
,
2173 GCancellable
*cancellable
,
2176 ItipSendComponentData
*isc
= user_data
;
2178 g_return_if_fail (isc
!= NULL
);
2180 itip_send_component_begin (isc
, cancellable
, error
);
2184 itip_send_component_with_model (ECalModel
*model
,
2185 ECalComponentItipMethod method
,
2186 ECalComponent
*send_comp
,
2187 ECalClient
*cal_client
,
2188 icalcomponent
*zones
,
2189 GSList
*attachments_list
,
2191 gboolean strip_alarms
,
2192 gboolean only_new_attendees
,
2193 gboolean ensure_master_object
)
2195 ESourceRegistry
*registry
;
2196 ECalDataModel
*data_model
;
2198 const gchar
*alert_ident
= NULL
;
2199 const gchar
*description
= NULL
;
2200 gchar
*display_name
;
2201 GCancellable
*cancellable
;
2202 ItipSendComponentData
*isc
;
2204 g_return_if_fail (E_IS_CAL_MODEL (model
));
2205 g_return_if_fail (E_IS_CAL_CLIENT (cal_client
));
2207 switch (e_cal_client_get_source_type (cal_client
)) {
2208 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS
:
2209 description
= _("Sending an event");
2210 alert_ident
= "calendar:failed-send-event";
2212 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS
:
2213 description
= _("Sending a memo");
2214 alert_ident
= "calendar:failed-send-memo";
2216 case E_CAL_CLIENT_SOURCE_TYPE_TASKS
:
2217 description
= _("Sending a task");
2218 alert_ident
= "calendar:failed-send-task";
2221 g_warn_if_reached ();
2225 registry
= e_cal_model_get_registry (model
);
2226 data_model
= e_cal_model_get_data_model (model
);
2227 source
= e_client_get_source (E_CLIENT (cal_client
));
2229 isc
= g_new0 (ItipSendComponentData
, 1);
2230 isc
->registry
= g_object_ref (registry
);
2231 isc
->method
= method
;
2232 isc
->send_comps
= g_slist_prepend (NULL
, g_object_ref (send_comp
));
2233 isc
->cal_client
= g_object_ref (cal_client
);
2235 isc
->zones
= icalcomponent_new_clone (zones
);
2237 isc
->attachments_list
= attachments_list
;
2241 isc
->users
= g_slist_copy (users
);
2242 for (link
= isc
->users
; link
; link
= g_slist_next (link
)) {
2243 link
->data
= g_strdup (link
->data
);
2246 isc
->strip_alarms
= strip_alarms
;
2247 isc
->only_new_attendees
= only_new_attendees
;
2248 isc
->ensure_master_object
= ensure_master_object
;
2249 isc
->success
= FALSE
;
2250 isc
->completed
= FALSE
;
2252 display_name
= e_util_get_source_full_name (registry
, source
);
2253 cancellable
= e_cal_data_model_submit_thread_job (data_model
, description
, alert_ident
,
2254 display_name
, itip_send_component_thread
,
2255 isc
, itip_send_component_complete_and_free
);
2257 g_clear_object (&cancellable
);
2258 g_free (display_name
);
2262 itip_send_comp_sync (ESourceRegistry
*registry
,
2263 ECalComponentItipMethod method
,
2264 ECalComponent
*send_comp
,
2265 ECalClient
*cal_client
,
2266 icalcomponent
*zones
,
2267 GSList
*attachments_list
,
2269 gboolean strip_alarms
,
2270 gboolean only_new_attendees
,
2271 GCancellable
*cancellable
,
2274 ItipSendComponentData isc
;
2276 memset (&isc
, 0, sizeof (ItipSendComponentData
));
2278 isc
.registry
= registry
;
2279 isc
.method
= method
;
2280 isc
.send_comps
= g_slist_prepend (NULL
, g_object_ref (send_comp
));
2281 isc
.cal_client
= cal_client
;
2283 isc
.attachments_list
= attachments_list
;
2285 isc
.strip_alarms
= strip_alarms
;
2286 isc
.only_new_attendees
= only_new_attendees
;
2288 isc
.completed
= FALSE
;
2289 isc
.success
= FALSE
;
2291 itip_send_component_begin (&isc
, cancellable
, error
);
2292 itip_send_component_complete (&isc
);
2294 g_slist_free_full (isc
.send_comps
, g_object_unref
);
2295 g_slist_free_full (isc
.users
, g_free
);
2301 itip_send_component_task_thread (GTask
*task
,
2302 gpointer source_object
,
2304 GCancellable
*cancellable
)
2306 ItipSendComponentData
*isc
= task_data
;
2308 g_return_if_fail (isc
!= NULL
);
2310 itip_send_component_begin (isc
, cancellable
, &isc
->async_error
);
2314 itip_send_component (ESourceRegistry
*registry
,
2315 ECalComponentItipMethod method
,
2316 ECalComponent
*send_comp
,
2317 ECalClient
*cal_client
,
2318 icalcomponent
*zones
,
2319 GSList
*attachments_list
,
2321 gboolean strip_alarms
,
2322 gboolean only_new_attendees
,
2323 gboolean ensure_master_object
,
2324 GCancellable
*cancellable
,
2325 GAsyncReadyCallback callback
,
2329 ItipSendComponentData
*isc
;
2331 isc
= g_new0 (ItipSendComponentData
, 1);
2332 isc
->registry
= g_object_ref (registry
);
2333 isc
->method
= method
;
2334 isc
->send_comps
= g_slist_prepend (NULL
, g_object_ref (send_comp
));
2335 isc
->cal_client
= g_object_ref (cal_client
);
2337 isc
->zones
= icalcomponent_new_clone (zones
);
2338 isc
->attachments_list
= attachments_list
;
2342 isc
->users
= g_slist_copy (users
);
2343 for (link
= isc
->users
; link
; link
= g_slist_next (link
)) {
2344 link
->data
= g_strdup (link
->data
);
2347 isc
->strip_alarms
= strip_alarms
;
2348 isc
->only_new_attendees
= only_new_attendees
;
2349 isc
->ensure_master_object
= ensure_master_object
;
2351 isc
->completed
= FALSE
;
2352 isc
->success
= FALSE
;
2354 task
= g_task_new (NULL
, cancellable
, callback
, user_data
);
2355 g_task_set_task_data (task
, isc
, itip_send_component_data_free
);
2356 g_task_set_source_tag (task
, itip_send_component
);
2357 g_task_run_in_thread (task
, itip_send_component_task_thread
);
2358 g_object_unref (task
);
2362 itip_send_component_finish (GAsyncResult
*result
,
2365 ItipSendComponentData
*isc
;
2367 isc
= g_task_get_task_data (G_TASK (result
));
2369 g_return_val_if_fail (isc
!= NULL
, FALSE
);
2370 g_return_val_if_fail (g_async_result_is_tagged (result
, itip_send_component
), FALSE
);
2372 itip_send_component_complete (isc
);
2374 if (isc
->async_error
) {
2375 g_propagate_error (error
, isc
->async_error
);
2376 isc
->async_error
= NULL
;
2379 return isc
->success
;
2383 reply_to_calendar_comp (ESourceRegistry
*registry
,
2384 ECalComponentItipMethod method
,
2385 ECalComponent
*send_comp
,
2386 ECalClient
*cal_client
,
2388 icalcomponent
*zones
,
2389 GSList
*attachments_list
)
2392 icalcomponent
*top_level
= NULL
;
2393 icaltimezone
*default_zone
;
2394 gboolean retval
= FALSE
;
2395 gchar
*identity_uid
, *identity_name
= NULL
, *identity_address
= NULL
;
2397 CreateComposerData
*ccd
;
2399 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry
), FALSE
);
2401 /* FIXME Pass this in. */
2402 shell
= e_shell_get_default ();
2404 default_zone
= calendar_config_get_icaltimezone ();
2406 ecomps
= g_slist_prepend (NULL
, send_comp
);
2408 identity_uid
= get_identity_uid_for_from (shell
, method
, send_comp
, cal_client
, &identity_name
, &identity_address
);
2410 /* Tidy up the comp */
2411 if (!comp_compliant (registry
, method
, ecomps
, FALSE
, cal_client
, zones
, default_zone
, TRUE
)) {
2412 g_free (identity_uid
);
2413 g_free (identity_name
);
2414 g_free (identity_address
);
2418 top_level
= comp_toplevel_with_zones (method
, ecomps
, cal_client
, zones
);
2420 ccd
= g_new0 (CreateComposerData
, 1);
2421 ccd
->identity_uid
= identity_uid
;
2422 ccd
->identity_name
= identity_name
;
2423 ccd
->identity_address
= identity_address
;
2424 ccd
->destinations
= comp_to_list (registry
, method
, ecomps
->data
, NULL
, reply_all
, NULL
);
2425 ccd
->subject
= comp_subject (registry
, method
, ecomps
->data
);
2426 ccd
->ical_string
= icalcomponent_as_ical_string_r (top_level
);
2427 ccd
->send_comps
= ecomps
;
2428 ccd
->show_only
= TRUE
;
2430 if (e_cal_component_get_vtype (ecomps
->data
) == E_CAL_COMPONENT_EVENT
) {
2431 ECalComponent
*comp
= ecomps
->data
;
2433 gchar
*orig_from
= NULL
;
2434 const gchar
*description
= NULL
;
2435 gchar
*subject
= NULL
;
2436 const gchar
*location
= NULL
;
2438 gchar
*html_description
= NULL
;
2439 GSList
*text_list
= NULL
;
2440 ECalComponentOrganizer organizer
;
2441 ECalComponentText text
;
2442 ECalComponentDateTime dtstart
;
2443 icaltimezone
*start_zone
= NULL
;
2446 e_cal_component_get_description_list (comp
, &text_list
);
2449 ECalComponentText text
= *((ECalComponentText
*) text_list
->data
);
2451 description
= text
.value
;
2458 e_cal_component_free_text_list (text_list
);
2460 e_cal_component_get_summary (comp
, &text
);
2462 subject
= g_strdup (text
.value
);
2464 e_cal_component_get_organizer (comp
, &organizer
);
2465 if (organizer
.value
)
2466 orig_from
= g_strdup (itip_strip_mailto (organizer
.value
));
2468 e_cal_component_get_location (comp
, &location
);
2470 location
= "Unspecified";
2472 e_cal_component_get_dtstart (comp
, &dtstart
);
2473 if (dtstart
.value
) {
2474 start_zone
= icaltimezone_get_builtin_timezone_from_tzid (dtstart
.tzid
);
2475 if (!start_zone
&& dtstart
.tzid
) {
2476 GError
*error
= NULL
;
2478 e_cal_client_get_timezone_sync (
2479 cal_client
, dtstart
.tzid
,
2480 &start_zone
, NULL
, &error
);
2482 if (error
!= NULL
) {
2484 "%s: Couldn't get timezone '%s' from server: %s",
2486 dtstart
.tzid
? dtstart
.tzid
: "",
2488 g_error_free (error
);
2492 if (!start_zone
|| dtstart
.value
->is_date
)
2493 start_zone
= default_zone
;
2495 start
= icaltime_as_timet_with_zone (*dtstart
.value
, start_zone
);
2496 time
= g_strdup (ctime (&start
));
2499 body
= g_string_new (
2500 "<br><br><hr><br><b>"
2501 "______ Original Appointment ______ "
2502 "</b><br><br><table>");
2504 if (orig_from
&& *orig_from
)
2505 g_string_append_printf (
2507 "<tr><td><b>From</b></td>"
2508 "<td>:</td><td>%s</td></tr>", orig_from
);
2512 g_string_append_printf (
2514 "<tr><td><b>Subject</b></td>"
2515 "<td>:</td><td>%s</td></tr>", subject
);
2518 g_string_append_printf (
2520 "<tr><td><b>Location</b></td>"
2521 "<td>:</td><td>%s</td></tr>", location
);
2524 g_string_append_printf (
2526 "<tr><td><b>Time</b></td>"
2527 "<td>:</td><td>%s</td></tr>", time
);
2530 g_string_append_printf (body
, "</table><br>");
2532 html_description
= html_new_lines_for (description
);
2533 g_string_append (body
, html_description
);
2534 g_free (html_description
);
2536 ccd
->event_body_text
= g_string_free (body
, FALSE
);
2539 e_msg_composer_new (shell
, itip_send_component_composer_created_cb
, ccd
);
2545 if (top_level
!= NULL
)
2546 icalcomponent_free (top_level
);
2552 itip_publish_begin (ECalComponent
*pub_comp
,
2553 ECalClient
*cal_client
,
2555 ECalComponent
**clone
)
2557 icalcomponent
*icomp
= NULL
, *icomp_clone
= NULL
;
2560 if (e_cal_component_get_vtype (pub_comp
) == E_CAL_COMPONENT_FREEBUSY
) {
2563 *clone
= e_cal_component_clone (pub_comp
);
2566 icomp
= e_cal_component_get_icalcomponent (pub_comp
);
2567 icomp_clone
= e_cal_component_get_icalcomponent (*clone
);
2568 for (prop
= icalcomponent_get_first_property (icomp
,
2569 ICAL_FREEBUSY_PROPERTY
);
2571 prop
= icalcomponent_get_next_property (
2573 ICAL_FREEBUSY_PROPERTY
))
2577 p
= icalproperty_new_clone (prop
);
2578 icalcomponent_add_property (icomp_clone
, p
);
2587 check_time (const struct icaltimetype tmval
,
2588 gboolean can_null_time
)
2590 if (icaltime_is_null_time (tmval
))
2591 return can_null_time
;
2593 return icaltime_is_valid_time (tmval
) &&
2594 tmval
.month
>= 1 && tmval
.month
<= 12 &&
2595 tmval
.day
>= 1 && tmval
.day
<= 31 &&
2596 tmval
.hour
>= 0 && tmval
.hour
< 24 &&
2597 tmval
.minute
>= 0 && tmval
.minute
< 60 &&
2598 tmval
.second
>= 0 && tmval
.second
< 60;
2601 /* Returns whether the passed-in icalcomponent is valid or not.
2602 * It does some sanity checks on values too. */
2604 is_icalcomp_valid (icalcomponent
*icalcomp
)
2606 if (!icalcomp
|| !icalcomponent_is_valid (icalcomp
))
2609 switch (icalcomponent_isa (icalcomp
)) {
2610 case ICAL_VEVENT_COMPONENT
:
2611 return check_time (icalcomponent_get_dtstart (icalcomp
), FALSE
) &&
2612 check_time (icalcomponent_get_dtend (icalcomp
), TRUE
);
2613 case ICAL_VTODO_COMPONENT
:
2614 return check_time (icalcomponent_get_dtstart (icalcomp
), TRUE
) &&
2615 check_time (icalcomponent_get_due (icalcomp
), TRUE
);
2616 case ICAL_VJOURNAL_COMPONENT
:
2617 return check_time (icalcomponent_get_dtstart (icalcomp
), TRUE
) &&
2618 check_time (icalcomponent_get_dtend (icalcomp
), TRUE
);
2627 itip_component_has_recipients (ECalComponent
*comp
)
2629 GSList
*attendees
= NULL
;
2630 ECalComponentAttendee
*attendee
;
2631 ECalComponentOrganizer organizer
;
2632 gboolean res
= FALSE
;
2634 g_return_val_if_fail (comp
!= NULL
, FALSE
);
2636 e_cal_component_get_organizer (comp
, &organizer
);
2637 e_cal_component_get_attendee_list (comp
, &attendees
);
2640 if (organizer
.value
&& e_cal_component_get_vtype (comp
) == E_CAL_COMPONENT_JOURNAL
) {
2641 /* memos store recipients in an extra property */
2642 icalcomponent
*icalcomp
;
2643 icalproperty
*icalprop
;
2645 icalcomp
= e_cal_component_get_icalcomponent (comp
);
2647 for (icalprop
= icalcomponent_get_first_property (icalcomp
, ICAL_X_PROPERTY
);
2649 icalprop
= icalcomponent_get_next_property (icalcomp
, ICAL_X_PROPERTY
)) {
2650 const gchar
*x_name
;
2652 x_name
= icalproperty_get_x_name (icalprop
);
2654 if (g_str_equal (x_name
, "X-EVOLUTION-RECIPIENTS")) {
2655 const gchar
*str_recipients
= icalproperty_get_x (icalprop
);
2657 res
= str_recipients
&& g_ascii_strcasecmp (organizer
.value
, str_recipients
) != 0;
2666 if (g_slist_length (attendees
) > 1 || !e_cal_component_has_organizer (comp
)) {
2667 e_cal_component_free_attendee_list (attendees
);
2671 attendee
= attendees
->data
;
2673 res
= organizer
.value
&& attendee
&& attendee
->value
&& g_ascii_strcasecmp (organizer
.value
, attendee
->value
) != 0;
2675 e_cal_component_free_attendee_list (attendees
);