Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / calendar / backends / groupwise / e-cal-backend-groupwise-utils.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* 
3  * Authors : 
4  *  JP Rosevear <jpr@ximian.com>
5  *  Rodrigo Moya <rodrigo@ximian.com>
6  *  Harish Krishnaswamy <kharish@novell.com>
7  *  Copyright 2003, Novell, Inc.
8  *
9  * This program is free software; you can redistribute it and/or 
10  * modify it under the terms of version 2 of the GNU Lesser General Public 
11  * License as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21  * USA
22  */
23
24 #include <config.h>
25
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31
32 #ifndef O_BINARY
33 #define O_BINARY 0
34 #endif
35
36 #include <glib.h>
37 #include <glib/gi18n.h>
38 #include <glib/gstdio.h>
39
40 #include <libgnomevfs/gnome-vfs-mime-utils.h>
41 #include <e-gw-connection.h>
42 #include <e-gw-message.h>
43 #include <libecal/e-cal-recur.h>
44 #include <libecal/e-cal-time-util.h>
45 #include <libsoup/soup-misc.h>
46 #include "e-cal-backend-groupwise-utils.h"
47 #include "libedataserver/e-source-list.h"
48
49 static gboolean 
50 get_recur_instance (ECalComponent *comp, time_t instance_start, time_t instance_end, gpointer data)
51 {
52         GSList **recur_dates = (GSList **) data;
53         char *rdate;
54
55         rdate = isodate_from_time_t (instance_start);
56         /* convert this into a date */
57         rdate[8] ='\0';
58         *recur_dates = g_slist_append (*recur_dates, rdate);
59         return TRUE;
60 }
61
62 static icaltimezone *
63 resolve_tzid_cb (const char *tzid, gpointer data)
64 {
65         /* do nothing.. since we are interested only in the event date */
66         return NULL;
67 }
68
69 const char *
70 e_cal_component_get_gw_id (ECalComponent *comp)
71 {
72         icalproperty *prop;     
73         
74         prop = icalcomponent_get_first_property (e_cal_component_get_icalcomponent (comp),
75                                                  ICAL_X_PROPERTY);
76         while (prop) {
77                 const char *x_name, *x_val;
78
79                 x_name = icalproperty_get_x_name (prop);
80                 x_val = icalproperty_get_x (prop);
81                 if (!strcmp (x_name, "X-GWRECORDID")) {
82                         return x_val;
83                 }
84
85                 prop = icalcomponent_get_next_property (e_cal_component_get_icalcomponent (comp),
86                                                         ICAL_X_PROPERTY);
87         }
88         return NULL;
89 }
90
91 static void 
92 set_categories_for_gw_item (EGwItem *item, GSList *category_names, ECalBackendGroupwise *cbgw)
93 {
94         GHashTable *categories_by_name, *categories_by_id;
95         EGwConnection *cnc;
96         GList *category_ids;
97         char *id;
98         int status;
99
100         category_ids = NULL;
101         id = NULL;
102
103         categories_by_name = e_cal_backend_groupwise_get_categories_by_name (cbgw);
104         categories_by_id = e_cal_backend_groupwise_get_categories_by_id (cbgw);
105         cnc = e_cal_backend_groupwise_get_connection (cbgw);
106         
107         g_return_if_fail (categories_by_id != NULL || categories_by_name != NULL || cnc != NULL);
108         
109         for (; category_names != NULL; category_names = g_slist_next (category_names)) {
110                      if (!category_names->data || strlen(category_names->data) == 0 )
111                              continue;
112                      id = g_hash_table_lookup (categories_by_name, category_names->data);
113                      if (id)
114                             category_ids = g_list_append (category_ids, g_strdup (id));
115                      else {
116                              EGwItem *category_item;
117                             category_item = e_gw_item_new_empty();
118                              e_gw_item_set_item_type (category_item,  E_GW_ITEM_TYPE_CATEGORY);
119                              e_gw_item_set_category_name (category_item, category_names->data);
120                              status = e_gw_connection_create_item (cnc, category_item, &id);
121                              if (status == E_GW_CONNECTION_STATUS_OK && id != NULL) {
122                                      char **components = g_strsplit (id, "@", -1);
123                                      char *temp_id = components[0];
124     
125                                      g_hash_table_insert (categories_by_name, g_strdup (category_names->data), g_strdup(temp_id));
126                                      g_hash_table_insert (categories_by_id, g_strdup(temp_id), g_strdup (category_names->data));
127                                      category_ids = g_list_append (category_ids, g_strdup(temp_id));
128                                      g_free (id);
129                                      g_strfreev(components);
130                              }
131                              g_object_unref (category_item);
132                      }
133              }
134              e_gw_item_set_categories (item, category_ids);
135 }
136
137 static void
138 add_send_options_data_to_item (EGwItem *item, ECalComponent *comp, icaltimezone *default_zone)
139 {
140         const char *x_val;
141         const char *x_name;
142         icalcomponent *icalcomp;
143         icalproperty *icalprop;
144         struct icaltimetype temp;
145         gboolean sendoptions_set = FALSE;
146         icaltimezone *utc;
147
148         utc = icaltimezone_get_utc_timezone ();
149         icalcomp = e_cal_component_get_icalcomponent (comp);
150         icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
151
152         while (icalprop) {
153
154                 x_name = icalproperty_get_x_name (icalprop);
155                 
156                 if (!strcmp (x_name, "X-EVOLUTION-OPTIONS-PRIORITY")) {
157                         sendoptions_set = TRUE;
158                         x_val = icalproperty_get_x (icalprop);
159                         switch (atoi (x_val)) {
160                                 case 1:  e_gw_item_set_priority (item, E_GW_ITEM_PRIORITY_HIGH);
161                                          break;
162                                 case 2:  e_gw_item_set_priority (item, E_GW_ITEM_PRIORITY_STANDARD);
163                                          break;
164                                 case 3:  e_gw_item_set_priority (item, E_GW_ITEM_PRIORITY_LOW);
165                                          break;
166                                 default: e_gw_item_set_priority (item, NULL);
167                                          break;
168                         }
169                 } else if (!strcmp (x_name, "X-EVOLUTION-OPTIONS-REPLY")) {
170                         e_gw_item_set_reply_request (item, TRUE);
171                         x_val = icalproperty_get_x (icalprop);
172                         if (strcmp (x_val, "convenient")) {
173                                 const char *value;
174                                 int i = atoi (x_val);
175                                 temp = icaltime_current_time_with_zone (default_zone ? default_zone : utc);
176                                 icaltime_adjust (&temp, i, 0, 0, 0);
177                                 icaltime_set_timezone (&temp, default_zone);
178                                 temp = icaltime_convert_to_zone (temp, utc);
179                                 value = icaltime_as_ical_string (temp);
180                                 e_gw_item_set_reply_within (item, (char *) value);      
181                         }
182                 } else if (!strcmp (x_name, "X-EVOLUTION-OPTIONS-EXPIRE")) {
183                         const char *expire = NULL;
184                         x_val = icalproperty_get_x (icalprop);
185                         temp = icaltime_current_time_with_zone (default_zone ? default_zone : utc);
186                         icaltime_adjust (&temp, atoi (x_val), 0, 0, 0); 
187                         icaltime_set_timezone (&temp, default_zone);
188                         temp = icaltime_convert_to_zone (temp, utc);
189                         expire = icaltime_as_ical_string (temp);
190                         e_gw_item_set_expires (item, (char *) expire);
191
192                 } else if (!strcmp (x_name, "X-EVOLUTION-OPTIONS-DELAY")) {
193                         const char *delay = NULL;
194                         x_val = icalproperty_get_x (icalprop);
195                         temp = icaltime_from_string (x_val);
196                         icaltime_set_timezone (&temp, default_zone);
197                         temp = icaltime_convert_to_zone (temp, utc);
198                         delay = icaltime_as_ical_string (temp);
199                         e_gw_item_set_delay_until (item, (char *) delay);
200                                         
201                 } else if (!strcmp (x_name, "X-EVOLUTION-OPTIONS-TRACKINFO")) {
202                         sendoptions_set = TRUE;
203                         x_val = icalproperty_get_x (icalprop);
204                         switch (atoi (x_val)) {
205                                 case 1: e_gw_item_set_track_info (item, E_GW_ITEM_DELIVERED);
206                                         break;
207                                 case 2: e_gw_item_set_track_info (item, E_GW_ITEM_DELIVERED_OPENED);
208                                         break;
209                                 case 3: e_gw_item_set_track_info (item, E_GW_ITEM_ALL);
210                                         break;
211                                 default: e_gw_item_set_track_info (item, E_GW_ITEM_NONE);
212                                          break;
213                         }
214                 } else if (!strcmp (x_name, "X-EVOLUTION-OPTIONS-OPENED")) {
215                         int i = 0;
216                         x_val = icalproperty_get_x (icalprop);
217                         i = atoi (x_val);
218                         switch (i) {
219                                 case 0: e_gw_item_set_notify_opened (item, E_GW_ITEM_NOTIFY_NONE);
220                                         break;
221                                 case 1: e_gw_item_set_notify_opened (item, E_GW_ITEM_NOTIFY_MAIL);
222                         }
223                         
224                 } else if (!strcmp (x_name, "X-EVOLUTION-OPTIONS-ACCEPTED")) {
225                         int i = 0;
226                         x_val = icalproperty_get_x (icalprop);
227                         i = atoi (x_val);
228                         switch (i) {
229                                 case 0: e_gw_item_set_notify_accepted (item, E_GW_ITEM_NOTIFY_NONE);
230                                         break;
231                                 case 1: e_gw_item_set_notify_accepted (item, E_GW_ITEM_NOTIFY_MAIL);
232                         }
233
234                 } else if (!strcmp (x_name, "X-EVOLUTION-OPTIONS-DECLINED")) {
235                         int i = 0;
236                         x_val = icalproperty_get_x (icalprop);
237                         i = atoi (x_val);
238                         switch (i) {
239                                 case 0: e_gw_item_set_notify_declined (item, E_GW_ITEM_NOTIFY_NONE);
240                                         break;
241                                 case 1: e_gw_item_set_notify_declined (item, E_GW_ITEM_NOTIFY_MAIL);
242                         }
243
244                 } else if (!strcmp (x_name, "X-EVOLUTION-OPTIONS-COMPLETED")) {
245                         int i = 0;
246                         x_val = icalproperty_get_x (icalprop);
247                         i = atoi (x_val);
248                         switch (i) {
249                                 case 0: e_gw_item_set_notify_completed (item, E_GW_ITEM_NOTIFY_NONE);
250                                         break;
251                                 case 1: e_gw_item_set_notify_completed (item, E_GW_ITEM_NOTIFY_MAIL);
252                         }
253                 }
254
255                 icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY);
256         }
257
258         e_gw_item_set_sendoptions (item, sendoptions_set);
259
260 }
261
262 static void
263 e_cal_backend_groupwise_set_attachments_from_comp (ECalComponent *comp,
264                 EGwItem *item)
265 {
266         GSList *attach_list = NULL, *attach_file_list = NULL;
267         GSList *l;
268
269         e_cal_component_get_attachment_list (comp, &attach_file_list);
270         
271         for (l = attach_file_list; l ; l = l->next) {
272                 
273                 EGwItemAttachment *attach_item;
274                 char *file_contents, *encoded_data;
275                 guint file_len;
276                 char *attach_filename_full, *filename;
277                 const char *uid;
278
279                 attach_filename_full = g_filename_from_uri ((char *)l->data, NULL, NULL);
280                 if (!g_file_get_contents (attach_filename_full, &file_contents, &file_len, NULL)) {
281                         g_message ("DEBUG: could not read %s\n", attach_filename_full);
282                         g_free (attach_filename_full);
283                         continue;
284                 }
285
286                 /* Extract the simple file name from the
287                  * attach_filename_full which is of the form
288                  * file://<path>/compuid-<simple filename> 
289                  */
290                 e_cal_component_get_uid (comp, &uid);
291                 filename = g_strrstr (attach_filename_full, uid);               
292                 if (filename == NULL) {
293                         g_message ("DEBUG: This is an invalid attachment file\n");
294                         g_free (attach_filename_full);
295                         g_free (file_contents);
296                         continue;
297                 }
298
299                 attach_item = g_new0 (EGwItemAttachment, 1);
300                 /* FIXME the member does not follow the naming convention.
301                  * Should be fixed in e-gw-item*/
302                 attach_item->contentType = g_strdup (gnome_vfs_get_mime_type (attach_filename_full));
303                 g_free (attach_filename_full);
304
305                 attach_item->name = g_strdup (filename + strlen(uid) + 1);
306                 /* do a base64 encoding so it can be embedded in a soap
307                  * message */
308                 encoded_data = soup_base64_encode (file_contents, file_len);
309                 attach_item->data = encoded_data;
310                 attach_item->size = strlen (encoded_data); 
311
312                 g_free (file_contents);
313                 attach_list = g_slist_append (attach_list, attach_item);
314         }
315
316         e_gw_item_set_attach_id_list (item, attach_list);
317 }
318
319 /* Returns the icalproperty for the Attendee associted with email id */
320 static icalproperty *
321 get_attendee_prop (icalcomponent *icalcomp, const char *attendee)
322 {
323         icalproperty *prop;     
324
325         for (prop = icalcomponent_get_first_property (icalcomp, ICAL_ATTENDEE_PROPERTY);
326                         prop;
327                         prop = icalcomponent_get_next_property (icalcomp, ICAL_ATTENDEE_PROPERTY)) {
328                 const char *att = icalproperty_get_attendee (prop);
329
330                 if (!g_ascii_strcasecmp (att, attendee)) {
331                         return prop;
332                 }
333         }
334
335         return NULL;
336 }
337
338 /* get_attendee_list from cal comp and convert into
339  * egwitemrecipient and set it on recipient_list*/
340 static void
341 set_attendees_to_item (EGwItem *item, ECalComponent *comp, icaltimezone *default_zone, gboolean delegate, const char *user_email)
342 {
343         if (e_cal_component_get_vtype (comp) == E_CAL_COMPONENT_JOURNAL) {
344                 if  (e_cal_component_has_organizer (comp)) {
345                         icalcomponent *icalcomp = e_cal_component_get_icalcomponent (comp);
346                         icalproperty *icalprop;
347                         GSList *recipient_list = NULL;
348                         const char *attendees = NULL;
349                         char **emails, **iter;
350
351                         for (icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY); icalprop; 
352                                         icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY)) {
353                                 if (g_str_equal (icalproperty_get_x_name (icalprop), "X-EVOLUTION-RECIPIENTS")) {
354                                         break;
355                                 }
356                         }
357
358                         if (icalprop)    {
359                                 attendees = icalproperty_get_x (icalprop);
360                                 emails = g_strsplit (attendees, ";", -1);
361
362                                 iter = emails;
363                                 while (*iter) {
364                                         EGwItemRecipient *recipient;
365
366                                         recipient = g_new0 (EGwItemRecipient, 1);
367
368                                         recipient->email = g_strdup (*iter);
369                                         recipient->type = E_GW_ITEM_RECIPIENT_TO;
370
371                                         recipient_list = g_slist_prepend (recipient_list, recipient);
372                                         iter++;
373                                 }
374
375                                 e_gw_item_set_recipient_list (item, recipient_list);
376
377                                 g_strfreev (emails);
378                                 icalcomponent_remove_property (icalcomp, icalprop);
379                                 icalproperty_free (icalprop);
380                         }
381                 }
382         } else if (e_cal_component_has_attendees (comp)) {
383                 GSList *attendee_list, *recipient_list = NULL, *al;
384
385                 e_cal_component_get_attendee_list (comp, &attendee_list);       
386                 for (al = attendee_list; al != NULL; al = al->next) {
387                         ECalComponentAttendee *attendee = (ECalComponentAttendee *) al->data;
388                         EGwItemRecipient *recipient;
389                                 
390                         if (delegate && (g_str_equal (attendee->value + 7, user_email) || !(attendee->delfrom && *attendee->delfrom)))
391                                 continue;               
392                         
393                         if (delegate) {
394                                 icalproperty *prop = get_attendee_prop (e_cal_component_get_icalcomponent (comp), 
395                                                 attendee->value);
396                                 if (prop) 
397                                         icalproperty_remove_parameter_by_kind (prop, ICAL_DELEGATEDFROM_PARAMETER);
398                         }
399         
400                         recipient = g_new0 (EGwItemRecipient, 1);
401
402                         /* len (MAILTO:) + 1 = 7 */
403                         recipient->email = g_strdup (attendee->value + 7);
404                         if (attendee->cn != NULL)
405                                 recipient->display_name = g_strdup (attendee->cn);
406                         if (attendee->role == ICAL_ROLE_REQPARTICIPANT) 
407                                 recipient->type = E_GW_ITEM_RECIPIENT_TO;
408                         else if (attendee->role == ICAL_ROLE_OPTPARTICIPANT)
409                                 recipient->type = E_GW_ITEM_RECIPIENT_CC;
410                         else recipient->type = E_GW_ITEM_RECIPIENT_NONE;
411
412                         if (attendee->status == ICAL_PARTSTAT_ACCEPTED)
413                                 recipient->status = E_GW_ITEM_STAT_ACCEPTED;
414                         else if (attendee->status == ICAL_PARTSTAT_DECLINED)
415                                 recipient->status = E_GW_ITEM_STAT_DECLINED;
416                         else 
417                                 recipient->status = E_GW_ITEM_STAT_NONE;
418
419                         recipient_list = g_slist_append (recipient_list, recipient);
420                 }
421
422                 e_cal_component_free_attendee_list(attendee_list);
423         
424                 /* recipient_list shouldn't be freed. Look into the function below. */
425                 e_gw_item_set_recipient_list (item, recipient_list);
426         }
427         
428         if (e_cal_component_has_organizer (comp)) {
429                 /* Send Options */
430                 add_send_options_data_to_item (item, comp, default_zone);
431         }
432                 
433         if (!delegate && e_cal_component_has_organizer (comp)) {
434                 ECalComponentOrganizer cal_organizer;
435                 EGwItemOrganizer *organizer = NULL;
436
437                 e_cal_component_get_organizer (comp, &cal_organizer);
438                 organizer = g_new0 (EGwItemOrganizer, 1);
439                 organizer->display_name = g_strdup (cal_organizer.cn);
440                 organizer->email = g_strdup (cal_organizer.value + 7);
441                 e_gw_item_set_organizer (item, organizer);
442         }
443
444 }
445
446 static void
447 set_rrule_from_comp (ECalComponent *comp, EGwItem *item, ECalBackendGroupwise *cbgw)
448 {
449
450         EGwItemRecurrenceRule *item_rrule;
451         struct icalrecurrencetype *ical_recur;
452         GSList *rrule_list = NULL, *exdate_list;
453         int i;
454
455         item_rrule = g_new0 (EGwItemRecurrenceRule, 1);
456         e_cal_component_get_rrule_list (comp, &rrule_list);
457         if (rrule_list) {
458                 /* assumes only one rrule is present  */
459                 ical_recur = (struct icalrecurrencetype *) rrule_list->data;
460                 
461                 g_message ("DEBUG: Processing rule\n%s\n", icalrecurrencetype_as_string (ical_recur));
462                 /*set the data */
463                 switch (ical_recur->freq) {
464                         case ICAL_DAILY_RECURRENCE :
465                                 item_rrule->frequency = E_GW_ITEM_RECURRENCE_FREQUENCY_DAILY;
466                                 break;
467                         case ICAL_WEEKLY_RECURRENCE:
468                                 item_rrule->frequency = E_GW_ITEM_RECURRENCE_FREQUENCY_WEEKLY;
469                                 break;
470                         case ICAL_MONTHLY_RECURRENCE:
471                                 item_rrule->frequency = E_GW_ITEM_RECURRENCE_FREQUENCY_MONTHLY;
472                                 break;
473                         case ICAL_YEARLY_RECURRENCE:
474                                 item_rrule->frequency = E_GW_ITEM_RECURRENCE_FREQUENCY_YEARLY;
475                                 break;
476                         default:
477                                 break;
478                 }
479                 if (ical_recur->count != 0)
480                         item_rrule->count = ical_recur->count;
481                 else
482                         item_rrule->until =  g_strdup (icaltime_as_ical_string (ical_recur->until)); 
483
484                 item_rrule->interval = ical_recur->interval;
485
486                 /*xxx -byday, bymonthday and byyearday not handled FIXME*/
487                 for (i = 0; i < ICAL_BY_DAY_SIZE; i++)
488                         item_rrule->by_day[i] = ical_recur->by_day[i];
489                 for (i = 0; i < ICAL_BY_MONTHDAY_SIZE; i++)
490                         item_rrule->by_month_day[i] = ical_recur->by_month_day[i];
491                 for (i = 0; i < ICAL_BY_YEARDAY_SIZE; i++)
492                         item_rrule->by_year_day[i] = ical_recur->by_year_day[i];
493                 for (i = 0; i < ICAL_BY_MONTH_SIZE; i++)
494                         item_rrule->by_month[i] = ical_recur->by_month[i];
495
496                 e_gw_item_set_rrule (item, item_rrule);
497
498                 /* set exceptions */
499                 if (e_cal_component_has_exdates (comp)) {
500                         GSList *l, *item_exdate_list = NULL;
501                         icaltimezone *default_zone, *utc;
502                         struct icaltimetype itt_utc;
503                         
504
505                         e_cal_component_get_exdate_list (comp, &exdate_list);
506                         default_zone = e_cal_backend_groupwise_get_default_zone (cbgw);
507                         utc = icaltimezone_get_utc_timezone ();
508                         for (l = exdate_list; l ; l = l->next) {
509                                 ECalComponentDateTime *dt = (ECalComponentDateTime *) l->data; 
510                                 if (dt->value) {
511                                         if (!icaltime_get_timezone (*(dt->value)))
512                                                 icaltime_set_timezone (dt->value, default_zone ? default_zone : utc);
513                                         itt_utc = icaltime_convert_to_zone (*dt->value, utc);
514                                         item_exdate_list = g_slist_append (item_exdate_list, g_strdup (icaltime_as_ical_string (itt_utc)));
515                                 }
516                         }                       
517                         e_gw_item_set_exdate_list (item, item_exdate_list);
518                         e_cal_component_free_exdate_list (exdate_list);
519                 }
520         } 
521 }
522
523 static EGwItem *
524 set_properties_from_cal_component (EGwItem *item, ECalComponent *comp, ECalBackendGroupwise *cbgw)
525 {
526         const char *uid, *location;
527         ECalComponentDateTime dt;
528         ECalComponentClassification classif;
529         ECalComponentTransparency transp;
530         ECalComponentText text;
531         int *priority;
532         GSList *categories;
533         GSList *slist, *sl;
534         icaltimezone *default_zone, *utc;
535         struct icaltimetype itt_utc;
536         
537         default_zone = e_cal_backend_groupwise_get_default_zone (cbgw);
538         utc = icaltimezone_get_utc_timezone ();
539
540         /* first set specific properties */
541         switch (e_cal_component_get_vtype (comp)) {
542         case E_CAL_COMPONENT_EVENT :
543                 e_gw_item_set_item_type (item, E_GW_ITEM_TYPE_APPOINTMENT);
544
545                 /* transparency */
546                 e_cal_component_get_transparency (comp, &transp);
547                 if (transp == E_CAL_COMPONENT_TRANSP_OPAQUE)
548                         e_gw_item_set_accept_level (item, E_GW_ITEM_ACCEPT_LEVEL_BUSY);
549                 else
550                         e_gw_item_set_accept_level (item, E_GW_ITEM_ACCEPT_LEVEL_FREE);
551
552                 /* location */
553                 e_cal_component_get_location (comp, &location);
554                 e_gw_item_set_place (item, location);
555
556                 /* categories */
557                 e_cal_component_get_categories_list (comp, &categories);
558                 set_categories_for_gw_item (item, categories, cbgw);
559
560                 /* alarms */
561                 if (e_cal_component_has_alarms (comp)) {
562                         ECalComponentAlarm *alarm;
563                         ECalComponentAlarmTrigger trigger;
564                         int duration;
565                         GList *l = e_cal_component_get_alarm_uids (comp);
566
567                         alarm = e_cal_component_get_alarm (comp, l->data);
568                         e_cal_component_alarm_get_trigger (alarm, &trigger);
569                         duration = abs (icaldurationtype_as_int (trigger.u.rel_duration));
570                         e_gw_item_set_trigger (item, duration);
571                 }
572                 
573                 
574
575                 /* end date */
576                 e_cal_component_get_dtend (comp, &dt);
577                 if (dt.value) {
578                         if (!icaltime_get_timezone (*dt.value))
579                                 icaltime_set_timezone (dt.value, default_zone ? default_zone : utc);
580                         itt_utc = icaltime_convert_to_zone (*dt.value, utc);
581                         e_gw_item_set_end_date (item, icaltime_as_ical_string (itt_utc));
582                 }
583
584                 break;
585
586         case E_CAL_COMPONENT_TODO :
587                 e_gw_item_set_item_type (item, E_GW_ITEM_TYPE_TASK);
588
589                 /* due date */
590                 e_cal_component_get_due (comp, &dt);
591                 if (dt.value) {
592                         if (!icaltime_get_timezone (*dt.value))
593                                 icaltime_set_timezone (dt.value, default_zone);
594                         itt_utc = icaltime_convert_to_zone (*dt.value, utc);
595                         e_gw_item_set_due_date (item, icaltime_as_ical_string (itt_utc));
596                 }
597                 
598                         /* priority */
599                  priority = NULL;
600                  e_cal_component_get_priority (comp, &priority);
601                  if (priority && *priority) {
602                          if (*priority >= 7)
603                                  e_gw_item_set_task_priority (item, E_GW_ITEM_PRIORITY_LOW);
604                          else if (*priority >= 5)
605                                  e_gw_item_set_task_priority (item, E_GW_ITEM_PRIORITY_STANDARD);
606                          else if (*priority >= 1)
607                                  e_gw_item_set_task_priority (item, E_GW_ITEM_PRIORITY_HIGH);
608                          else
609                                  e_gw_item_set_task_priority (item, NULL);
610
611                          e_cal_component_free_priority (priority);
612                  }
613           
614                         /* completed */
615                 e_cal_component_get_completed (comp, &dt.value);
616                 if (dt.value) {
617                         e_gw_item_set_completed (item, TRUE);
618                 } else
619                         e_gw_item_set_completed (item, FALSE);
620
621                 break;
622         case E_CAL_COMPONENT_JOURNAL:
623                 e_gw_item_set_item_type (item, E_GW_ITEM_TYPE_NOTE);
624                 break;
625         default :
626                 g_object_unref (item);
627                 return NULL;
628         }
629
630         /* set common properties */
631         /* GW server ID */
632         e_gw_item_set_id (item, e_cal_component_get_gw_id (comp));
633         
634         
635         /* UID */
636         e_cal_component_get_uid (comp, &uid);
637         e_gw_item_set_icalid (item, uid);
638
639         /* subject */
640         e_cal_component_get_summary (comp, &text);
641         e_gw_item_set_subject (item, text.value);
642
643         /* description */
644         e_cal_component_get_description_list (comp, &slist);
645         if (slist) {
646                 GString *str = g_string_new ("");
647
648                 for (sl = slist; sl != NULL; sl = sl->next) {
649                         ECalComponentText *pt = sl->data;
650
651                         if (pt && pt->value)
652                                 str = g_string_append (str, pt->value);
653                 }
654
655                 e_gw_item_set_message (item, (const char *) str->str);
656
657                 g_string_free (str, TRUE);
658                 e_cal_component_free_text_list (slist);
659         }
660
661
662         /* start date */
663         e_cal_component_get_dtstart (comp, &dt);
664         if (dt.value) {
665                 if (!icaltime_get_timezone (*dt.value))
666                         icaltime_set_timezone (dt.value, default_zone);
667                 itt_utc = icaltime_convert_to_zone (*dt.value, utc);
668                 e_gw_item_set_start_date (item, icaltime_as_ical_string (itt_utc));
669         } else if (e_gw_item_get_item_type (item) == E_GW_ITEM_TYPE_APPOINTMENT) {
670                 /* appointments need the start date property */
671                 g_object_unref (item);
672                 return NULL;
673         }
674         
675         /* all day event */
676         if (dt.value && dt.value->is_date && e_gw_item_get_item_type (item) == E_GW_ITEM_TYPE_APPOINTMENT)
677                 e_gw_item_set_is_allday_event (item, TRUE);
678         
679         /* creation date */
680         e_cal_component_get_created (comp, &dt.value);
681         if (dt.value) {
682                 if (!icaltime_get_timezone (*dt.value))
683                         icaltime_set_timezone (dt.value, default_zone);
684                 itt_utc = icaltime_convert_to_zone (*dt.value, utc); 
685                 e_gw_item_set_creation_date (item, icaltime_as_ical_string (itt_utc));
686         } else {
687                 struct icaltimetype itt;
688
689                 e_cal_component_get_dtstamp (comp, &itt);
690                 e_gw_item_set_creation_date (item, icaltime_as_ical_string (itt));
691         }
692
693         /* classification */
694         e_cal_component_get_classification (comp, &classif);
695         switch (classif) {
696         case E_CAL_COMPONENT_CLASS_PUBLIC :
697                 e_gw_item_set_classification (item, E_GW_ITEM_CLASSIFICATION_PUBLIC);
698                 break;
699         case E_CAL_COMPONENT_CLASS_PRIVATE :
700                 e_gw_item_set_classification (item, E_GW_ITEM_CLASSIFICATION_PRIVATE);
701                 break;
702         case E_CAL_COMPONENT_CLASS_CONFIDENTIAL :
703                 e_gw_item_set_classification (item, E_GW_ITEM_CLASSIFICATION_CONFIDENTIAL);
704                 break;
705         default :
706                 e_gw_item_set_classification (item, NULL);
707         }
708
709
710         set_attendees_to_item (item, comp, default_zone, FALSE, NULL);
711         
712         /* check if recurrences exist and update the item */
713         if (e_cal_component_has_recurrences (comp)) {
714                 if (e_cal_component_has_rrules (comp))
715                         set_rrule_from_comp (comp, item, cbgw);
716                 else {
717
718                         GSList *recur_dates = NULL;
719                         
720                         if (dt.tzid)
721                                 e_cal_recur_generate_instances (comp, -1, -1,get_recur_instance, &recur_dates, resolve_tzid_cb, NULL, (icaltimezone *) default_zone);           
722                         else 
723                                 e_cal_recur_generate_instances (comp, -1, -1,get_recur_instance, &recur_dates, resolve_tzid_cb, NULL, utc);             
724
725                         recur_dates = g_slist_delete_link (recur_dates, recur_dates);
726                         
727                         e_gw_item_set_recurrence_dates (item, recur_dates);
728                 }
729         }
730         
731         /* attachments */
732         if (e_cal_component_has_attachments (comp)) {
733                 e_cal_backend_groupwise_set_attachments_from_comp (comp, item); 
734         }
735         
736         return item;
737 }
738
739 EGwItem *
740 e_gw_item_new_from_cal_component (const char *container, ECalBackendGroupwise *cbgw, ECalComponent *comp)
741 {
742         EGwItem *item;
743
744         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
745
746         item = e_gw_item_new_empty ();
747         e_gw_item_set_container_id (item, container);
748         return set_properties_from_cal_component (item, comp, cbgw);
749 }
750
751 /* Set the attendee list and send options to EGwItem */
752 EGwItem *
753 e_gw_item_new_for_delegate_from_cal (ECalBackendGroupwise *cbgw, ECalComponent *comp)
754 {
755         EGwItem *item;
756         icaltimezone *default_zone;
757         const char *user_email;
758    
759         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
760         default_zone = e_cal_backend_groupwise_get_default_zone (cbgw);
761         item = e_gw_item_new_empty ();
762         e_gw_item_set_id (item, e_cal_component_get_gw_id (comp));
763         user_email = e_gw_connection_get_user_email (e_cal_backend_groupwise_get_connection (cbgw));
764
765         set_attendees_to_item (item, comp, default_zone, TRUE, user_email);
766         add_send_options_data_to_item (item, comp, default_zone);
767
768         return item;
769 }
770
771 /* Fetch data from the server and unencode it to the actual data 
772  * and populate the attach_data
773  */
774 static gboolean
775 get_attach_data_from_server (EGwItemAttachment *attach_item, ECalBackendGroupwise *cbgw)
776 {
777         EGwConnection *cnc;
778         EGwConnectionStatus status;
779         char *data = NULL;
780         int len;
781
782         cnc = e_cal_backend_groupwise_get_connection (cbgw);
783         g_return_val_if_fail (E_IS_GW_CONNECTION (cnc), E_GW_CONNECTION_STATUS_INVALID_CONNECTION);
784
785         status = e_gw_connection_get_attachment (cnc, attach_item->id, 0, -1, (const char **) &data, &len); 
786
787         if (status != E_GW_CONNECTION_STATUS_OK ) {
788                 g_warning ("Failed to read the attachment from the server\n");
789                 return FALSE;
790         }
791         attach_item->data = data;
792         attach_item->size = len;
793
794         return TRUE;
795 }
796
797 static void
798 set_attachments_to_cal_component (EGwItem *item, ECalComponent *comp, ECalBackendGroupwise *cbgw)
799 {
800         GSList *fetch_list = NULL, *l;
801         GSList *comp_attachment_list = NULL;
802         const char *uid;
803         char *attach_file_url;
804         
805         fetch_list = e_gw_item_get_attach_id_list (item);
806         if (fetch_list == NULL)
807                 return; /* No attachments exist */
808
809         e_cal_component_get_uid (comp, &uid);
810         for (l = fetch_list; l ; l = l->next) {
811                 int fd;
812                 EGwItemAttachment *attach_item;
813                 char *attach_data = NULL;
814                 struct stat st;
815                 char *filename;
816
817                 attach_item = (EGwItemAttachment *) l->data;
818                 attach_file_url = g_strconcat (e_cal_backend_groupwise_get_local_attachments_store (cbgw), 
819                          "/", uid, "-", attach_item->name, NULL);
820
821                 filename = g_filename_from_uri (attach_file_url, NULL, NULL);
822                 if (g_stat (filename, &st) == -1) {
823                         if (!get_attach_data_from_server (attach_item, cbgw)) {
824                                 g_free (filename);
825                                 return; /* Could not get the attachment from the server */
826                         }
827                         fd = g_open (filename, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600);
828                         if (fd == -1) { 
829                                 /* skip gracefully */
830                                 g_warning ("DEBUG: could not serialize attachments\n");
831                         } else if (write (fd, attach_item->data, attach_item->size) == -1) {
832                                 /* skip gracefully */
833                                 g_warning ("DEBUG: attachment write failed.\n");
834                         }
835                         g_free (attach_data);
836                         if (fd != -1)
837                                 close (fd);
838                 }
839                 g_free (filename);
840
841                 comp_attachment_list = g_slist_append (comp_attachment_list, attach_file_url);
842         }
843
844         e_cal_component_set_attachment_list (comp, comp_attachment_list);
845
846 }
847
848 static void
849 set_default_alarms (ECalComponent *comp)
850 {
851
852         GConfClient *gconf = gconf_client_get_default ();
853
854         if (gconf_client_get_bool (gconf, CALENDAR_CONFIG_DEFAULT_REMINDER, NULL)) {
855
856                         ECalComponentAlarm *acomp;
857                         int interval;
858                         char * units;
859                         enum {
860                                 DAYS,
861                                 HOURS,
862                                 MINUTES
863                         } duration;     
864                         ECalComponentAlarmTrigger trigger;
865
866                         interval = gconf_client_get_int (gconf, CALENDAR_CONFIG_DEFAULT_REMINDER_INTERVAL, NULL);
867                         units = gconf_client_get_string (gconf, CALENDAR_CONFIG_DEFAULT_REMINDER_UNITS, NULL);
868
869                         if (units == NULL) 
870                                 duration = MINUTES;
871                         else {
872                                 if (!strcmp (units, "days"))
873                                         duration = DAYS;
874                                 else if (!strcmp (units, "hours"))
875                                         duration = HOURS;
876                                 else
877                                         duration = MINUTES;
878                                 g_free (units);
879                         }
880                         acomp = e_cal_component_alarm_new ();
881
882                         e_cal_component_alarm_set_action (acomp, E_CAL_COMPONENT_ALARM_DISPLAY);
883
884                         trigger.type = E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START;
885                         memset (&trigger.u.rel_duration, 0, sizeof (trigger.u.rel_duration));
886
887                         trigger.u.rel_duration.is_neg = TRUE;
888
889                         switch (duration) {
890                         case MINUTES:
891                                 trigger.u.rel_duration.minutes = interval;
892                                 break;
893                         case HOURS:     
894                                 trigger.u.rel_duration.hours = interval;
895                                 break;
896                         case DAYS:      
897                                 trigger.u.rel_duration.days = interval;
898                                 break;
899                         default:
900                                 e_cal_component_alarm_free (acomp);
901                                 g_object_unref (gconf);
902                                 return;
903                         }
904
905                         e_cal_component_alarm_set_trigger (acomp, trigger);
906                         e_cal_component_add_alarm (comp, acomp);
907
908                         e_cal_component_alarm_free (acomp);
909                 }
910                 g_object_unref (gconf);
911 }
912
913
914 ECalComponent *
915 e_gw_item_to_cal_component (EGwItem *item, ECalBackendGroupwise *cbgw)
916 {
917         ECalComponent *comp;
918         ECalComponentText text;
919         ECalComponentDateTime dt;
920         const char *description, *uid;
921         char *t, *name;
922         GList *category_ids;
923         GSList *categories;
924         GHashTable *categories_by_id;
925         gboolean is_allday;
926         icaltimezone *default_zone;
927
928         struct icaltimetype itt, itt_utc;
929         int priority;
930         int percent;
931         int alarm_duration;
932         GSList *recipient_list, *rl, *attendee_list = NULL;
933         EGwItemOrganizer *organizer;
934         EGwItemType item_type;
935
936         default_zone = e_cal_backend_groupwise_get_default_zone (cbgw);
937         categories_by_id = e_cal_backend_groupwise_get_categories_by_id (cbgw);
938
939         g_return_val_if_fail (E_IS_GW_ITEM (item), NULL);
940
941         comp = e_cal_component_new ();
942
943         item_type = e_gw_item_get_item_type (item);
944
945         if (item_type == E_GW_ITEM_TYPE_APPOINTMENT)
946                 e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_EVENT);
947         else if (item_type == E_GW_ITEM_TYPE_TASK)
948                 e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_TODO);
949         else if (item_type == E_GW_ITEM_TYPE_NOTE)
950                 e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_JOURNAL);
951         else {
952                 g_object_unref (comp);
953                 return NULL;
954         }
955
956         /* set common properties */
957         /* GW server ID */
958         description = e_gw_item_get_id (item);
959         if (description) {
960                 icalproperty *icalprop;
961
962                 icalprop = icalproperty_new_x (description);
963                 icalproperty_set_x_name (icalprop, "X-GWRECORDID");
964                 icalcomponent_add_property (e_cal_component_get_icalcomponent (comp), icalprop);
965         }
966
967         
968         if (e_gw_item_get_reply_request (item)) {
969                 char *reply_within; 
970                 const char *mess = e_gw_item_get_message (item);
971                 char *value;
972
973                 reply_within = e_gw_item_get_reply_within (item);
974                 if (reply_within) {
975                         time_t t;
976                         char *temp;
977
978                         t = e_gw_connection_get_date_from_string (reply_within);
979                         temp = ctime (&t);
980                         temp [strlen (temp)-1] = '\0';
981                         value = g_strconcat (N_("Reply Requested: by "), temp, "\n\n", mess ? mess : "", NULL);
982                         e_gw_item_set_message (item, (const char *) value);
983                         g_free (value);
984
985                 } else {
986                         value = g_strconcat (N_("Reply Requested: When convenient"), "\n\n", mess ? mess : "", NULL);
987                         e_gw_item_set_message (item, (const char *) value);
988                         g_free (value);
989                 }
990         }
991
992         /* summary */
993         text.value = e_gw_item_get_subject (item);
994         text.altrep = NULL;
995         e_cal_component_set_summary (comp, &text);
996
997         /* description */
998         description = e_gw_item_get_message (item);
999         if (description) {
1000                 GSList l;
1001
1002                 text.value = description;
1003                 text.altrep = NULL;
1004                 l.data = &text;
1005                 l.next = NULL;
1006
1007                 e_cal_component_set_description_list (comp, &l);
1008         }
1009
1010         /* creation date */
1011         t = e_gw_item_get_creation_date (item);
1012         if (t) {
1013                 itt_utc = icaltime_from_string (t);
1014                 if (!icaltime_get_timezone (itt_utc))
1015                         icaltime_set_timezone (&itt_utc, icaltimezone_get_utc_timezone());
1016                 if (default_zone) {
1017                         itt = icaltime_convert_to_zone (itt_utc, default_zone); 
1018                         icaltime_set_timezone (&itt, default_zone);
1019                         e_cal_component_set_created (comp, &itt);
1020                         e_cal_component_set_dtstamp (comp, &itt);
1021
1022                 } else {
1023                         e_cal_component_set_created (comp, &itt_utc);
1024                         e_cal_component_set_dtstamp (comp, &itt_utc);
1025                 }
1026         }
1027         g_free (t);
1028         
1029         /* categories */
1030         category_ids = e_gw_item_get_categories (item);
1031         categories = NULL;
1032         if (category_ids && categories_by_id) {
1033                 for (; category_ids != NULL; category_ids = g_list_next (category_ids)) {
1034                         name = g_hash_table_lookup (categories_by_id, category_ids->data);
1035                         if (name)
1036                                 categories = g_slist_append (categories, name);
1037                 }
1038                 if (categories) {
1039                         e_cal_component_set_categories_list (comp,categories);
1040                         g_slist_free (categories);
1041                 }
1042         }
1043
1044         /* all day event */
1045         is_allday = e_gw_item_get_is_allday_event (item);       
1046
1047         /* start date */
1048         /* should i duplicate here ? */
1049         t = e_gw_item_get_start_date (item);
1050         if (t) {
1051                 itt_utc = icaltime_from_string (t);
1052                 
1053                 if (!is_allday && (item_type != E_GW_ITEM_TYPE_NOTE)) {
1054                         if (!icaltime_get_timezone (itt_utc))
1055                                 icaltime_set_timezone (&itt_utc, icaltimezone_get_utc_timezone());
1056                         if (default_zone) {
1057                                 itt = icaltime_convert_to_zone (itt_utc, default_zone); 
1058                                 icaltime_set_timezone (&itt, default_zone);
1059                                 dt.value = &itt;
1060                                 dt.tzid = icaltimezone_get_tzid (default_zone);
1061                         } else {
1062                                 dt.value = &itt_utc;
1063                                 dt.tzid = g_strdup ("UTC");
1064                         }
1065                 } else {
1066                         dt.value = &itt_utc;
1067                         dt.tzid = NULL;
1068                         dt.value->is_date = 1;
1069                 }       
1070
1071                 e_cal_component_set_dtstart (comp, &dt);
1072         } else 
1073                 return NULL;
1074         
1075         /* UID */
1076         if (e_gw_item_get_recurrence_key (item) != 0) {
1077
1078                 ECalComponentRange *recur_id;
1079                 char *recur_key = g_strdup_printf ("%d", e_gw_item_get_recurrence_key (item));
1080
1081                 e_cal_component_set_uid (comp, (const char *) recur_key);
1082                 g_free (recur_key);
1083
1084                 /* set the recurrence id and the X-GW-RECORDID  too */
1085                 recur_id = g_new0 (ECalComponentRange, 1);
1086                 recur_id->type = E_CAL_COMPONENT_RANGE_SINGLE;
1087                 recur_id->datetime = dt;
1088                 e_cal_component_set_recurid (comp, recur_id);
1089         } else {
1090
1091                 uid = e_gw_item_get_icalid (item);
1092                 if (uid)
1093                         e_cal_component_set_uid (comp, e_gw_item_get_icalid (item));
1094                 else {
1095                         g_object_unref (comp);
1096                         return NULL;
1097                 }
1098         }
1099                 
1100         g_free (t);
1101
1102         /* classification */
1103         description = e_gw_item_get_classification (item);
1104         if (description) {
1105                 if (strcmp (description, E_GW_ITEM_CLASSIFICATION_PUBLIC) == 0)
1106                         e_cal_component_set_classification (comp, E_CAL_COMPONENT_CLASS_PUBLIC);
1107                 else if (strcmp (description, E_GW_ITEM_CLASSIFICATION_PRIVATE) == 0)
1108                         e_cal_component_set_classification (comp, E_CAL_COMPONENT_CLASS_PRIVATE);
1109                 else if (strcmp (description, E_GW_ITEM_CLASSIFICATION_CONFIDENTIAL) == 0)
1110                         e_cal_component_set_classification (comp, E_CAL_COMPONENT_CLASS_CONFIDENTIAL);
1111                 else
1112                         e_cal_component_set_classification (comp, E_CAL_COMPONENT_CLASS_NONE);
1113         } else
1114                 e_cal_component_set_classification (comp, E_CAL_COMPONENT_CLASS_NONE);
1115
1116         if (item_type != E_GW_ITEM_TYPE_NOTE) {
1117                 recipient_list = e_gw_item_get_recipient_list (item);
1118                 if (recipient_list != NULL) {
1119                         for (rl = recipient_list; rl != NULL; rl = rl->next) {
1120                                 EGwItemRecipient *recipient = (EGwItemRecipient *) rl->data;
1121                                 ECalComponentAttendee *attendee = g_new0 (ECalComponentAttendee, 1);
1122
1123                                 attendee->cn = g_strdup (recipient->display_name);
1124                                 attendee->value = g_strconcat("MAILTO:", recipient->email, NULL);
1125                                 if (recipient->type == E_GW_ITEM_RECIPIENT_TO)
1126                                         attendee->role = ICAL_ROLE_REQPARTICIPANT;
1127                                 else if (recipient->type == E_GW_ITEM_RECIPIENT_CC || recipient->type == E_GW_ITEM_RECIPIENT_BC)
1128                                         attendee->role = ICAL_ROLE_OPTPARTICIPANT;
1129                                 else 
1130                                         attendee->role = ICAL_ROLE_NONE;
1131                                 /* FIXME  needs a server fix on the interface 
1132                                  * for getting cutype and the status */
1133                                 attendee->cutype = ICAL_CUTYPE_INDIVIDUAL;
1134
1135                                 if (recipient->status == E_GW_ITEM_STAT_ACCEPTED) {
1136                                         const char *accept_level = e_gw_item_get_accept_level (item);
1137
1138                                         if(accept_level && !strcmp (e_gw_item_get_accept_level (item),"Tentative"))
1139                                                 attendee->status = ICAL_PARTSTAT_TENTATIVE;
1140                                         else
1141                                                 attendee->status = ICAL_PARTSTAT_ACCEPTED;
1142                                 }
1143                                 else if (recipient->status == E_GW_ITEM_STAT_DECLINED)
1144                                         attendee->status = ICAL_PARTSTAT_DECLINED;
1145                                 else
1146                                         attendee->status = ICAL_PARTSTAT_NEEDSACTION;   
1147
1148
1149                                 attendee_list = g_slist_append (attendee_list, attendee);                               
1150                         }
1151
1152                         e_cal_component_set_attendee_list (comp, attendee_list);
1153                 }
1154         }
1155
1156         /* set organizer if it exists */
1157         organizer = e_gw_item_get_organizer (item);
1158         if (organizer) {
1159                 ECalComponentOrganizer *cal_organizer;
1160                 
1161                 cal_organizer = g_new0 (ECalComponentOrganizer, 1);
1162                 cal_organizer->cn = g_strdup (organizer->display_name);
1163                 cal_organizer->value = g_strconcat("MAILTO:", organizer->email, NULL);
1164                 e_cal_component_set_organizer (comp, cal_organizer);
1165         }
1166
1167         /* set attachments, if any */
1168         set_attachments_to_cal_component (item, comp, cbgw);
1169
1170         /* set specific properties */
1171         switch (item_type) {
1172         case E_GW_ITEM_TYPE_APPOINTMENT :
1173                 /* transparency */
1174                 description = e_gw_item_get_accept_level (item);
1175                 if (description &&
1176                     (!strcmp (description, E_GW_ITEM_ACCEPT_LEVEL_BUSY) ||
1177                      !strcmp (description, E_GW_ITEM_ACCEPT_LEVEL_OUT_OF_OFFICE)))
1178                         e_cal_component_set_transparency (comp, E_CAL_COMPONENT_TRANSP_OPAQUE);
1179                 else
1180                         e_cal_component_set_transparency (comp, E_CAL_COMPONENT_TRANSP_TRANSPARENT);
1181
1182                 /* location */
1183                 e_cal_component_set_location (comp, e_gw_item_get_place (item));
1184
1185                 /* end date */
1186                 t = e_gw_item_get_end_date (item);
1187                 if (t) {
1188                         itt_utc = icaltime_from_string (t);
1189
1190                         if (!is_allday) {
1191                                 if (!icaltime_get_timezone (itt_utc))
1192                                         icaltime_set_timezone (&itt_utc, icaltimezone_get_utc_timezone());
1193                                 if (default_zone) {
1194                                         itt = icaltime_convert_to_zone (itt_utc, default_zone); 
1195                                         icaltime_set_timezone (&itt, default_zone);
1196                                         dt.value = &itt;
1197                                         dt.tzid = icaltimezone_get_tzid (default_zone);
1198                                 } else {
1199                                         dt.value = &itt_utc;
1200                                         dt.tzid = g_strdup ("UTC");
1201                                 }
1202                         } else {
1203                                 dt.value = &itt_utc;
1204                                 dt.tzid = NULL;
1205                                 dt.value->is_date = 1;
1206                         }
1207
1208                         e_cal_component_set_dtend (comp, &dt);
1209                 }
1210
1211
1212                 /* alarms*/
1213                 /* we negate the value as GW supports only "before" the start of event alarms */
1214                 alarm_duration = 0 - e_gw_item_get_trigger (item);
1215                 if (alarm_duration != 0) {
1216                         ECalComponentAlarm *alarm;
1217                         ECalComponentAlarmTrigger trigger;
1218                         
1219                         alarm = e_cal_component_alarm_new ();
1220                         e_cal_component_alarm_set_action (alarm, E_CAL_COMPONENT_ALARM_DISPLAY);
1221                         trigger.type = E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START;
1222                         trigger.u.rel_duration = icaldurationtype_from_int (alarm_duration);
1223                         e_cal_component_alarm_set_trigger (alarm, trigger);
1224                         e_cal_component_add_alarm (comp, alarm);
1225
1226                 } else 
1227                         set_default_alarms (comp);
1228
1229                 break;
1230         case E_GW_ITEM_TYPE_TASK :
1231                 /* due date */
1232                 t = e_gw_item_get_due_date (item);
1233                 if (t) {
1234                         itt_utc = icaltime_from_string (t);
1235                         if (!icaltime_get_timezone (itt_utc))
1236                                 icaltime_set_timezone (&itt_utc, icaltimezone_get_utc_timezone());
1237                         if (default_zone) {
1238                                 itt = icaltime_convert_to_zone (itt_utc, default_zone); 
1239                                 icaltime_set_timezone (&itt, default_zone);
1240                                 dt.value = &itt;
1241                                 dt.tzid = icaltimezone_get_tzid (default_zone);
1242                         } else {
1243                                 dt.value = &itt_utc;
1244                                 dt.tzid = g_strdup ("UTC");
1245                         }
1246                         e_cal_component_set_due (comp, &dt);
1247                 }
1248                 /* priority */
1249                 description = e_gw_item_get_task_priority (item);
1250                 if (description) {
1251                         if (!strcmp (description, E_GW_ITEM_PRIORITY_STANDARD))
1252                                 priority = 5;
1253                         else if (!strcmp (description, E_GW_ITEM_PRIORITY_HIGH))
1254                                 priority = 3;
1255                         else
1256                                 priority = 7;
1257                 } else
1258                         priority = 7;
1259
1260                 e_cal_component_set_priority (comp, &priority);
1261
1262                 /* EGwItem's completed is a boolean */
1263                 if (e_gw_item_get_completed (item)) {
1264                         percent = 100;
1265                         
1266                         t = e_gw_item_get_completed_date (item);
1267                         if (t) {
1268                                 itt_utc = icaltime_from_string (t);
1269                                 if (!icaltime_get_timezone (itt_utc))
1270                                         icaltime_set_timezone (&itt_utc, icaltimezone_get_utc_timezone());
1271                                 if (default_zone) {
1272                                         itt = icaltime_convert_to_zone (itt_utc, default_zone); 
1273                                         icaltime_set_timezone (&itt, default_zone);
1274                                         e_cal_component_set_completed (comp, &itt);
1275                                 } else 
1276                                         e_cal_component_set_completed (comp, &itt_utc);
1277                         } else {
1278                                 /* We are setting the completion date as the current time due to
1279                                    the absence of completion element in the soap interface for posted
1280                                    tasks */
1281                                 itt = icaltime_today ();
1282                                 e_cal_component_set_completed (comp,&itt);
1283                         }
1284                 } else 
1285                         percent =0;
1286                 e_cal_component_set_percent (comp, &percent);
1287
1288                 break;
1289         case E_GW_ITEM_TYPE_NOTE:
1290                 break;
1291         default :
1292                 return NULL;
1293         }
1294
1295         e_cal_component_commit_sequence (comp);
1296
1297         return comp;
1298 }
1299
1300 EGwConnectionStatus
1301 e_gw_connection_send_appointment (ECalBackendGroupwise *cbgw, const char *container, ECalComponent *comp, icalproperty_method method, gboolean all_instances, ECalComponent **created_comp, icalparameter_partstat *pstatus)
1302 {
1303         EGwConnection *cnc;
1304         EGwConnectionStatus status;
1305         icalparameter_partstat partstat;
1306         char *item_id = NULL;
1307         const char *gw_id;
1308         const char *recurrence_key = NULL;
1309         gboolean need_to_get = FALSE, decline = FALSE;
1310         ECalComponentVType type;
1311
1312         cnc = e_cal_backend_groupwise_get_connection (cbgw);
1313         g_return_val_if_fail (E_IS_GW_CONNECTION (cnc), E_GW_CONNECTION_STATUS_INVALID_CONNECTION);
1314         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), E_GW_CONNECTION_STATUS_INVALID_OBJECT);
1315
1316         e_cal_component_commit_sequence (comp);
1317         type = e_cal_component_get_vtype (comp);
1318
1319         gw_id = e_cal_component_get_gw_id (comp);
1320
1321         switch  (type) {
1322
1323                 case E_CAL_COMPONENT_EVENT: 
1324                 case E_CAL_COMPONENT_TODO:
1325                 case E_CAL_COMPONENT_JOURNAL:
1326                         if (!g_str_has_suffix (gw_id, container)) {
1327                                 item_id = g_strconcat (e_cal_component_get_gw_id (comp), GW_EVENT_TYPE_ID, container, NULL);
1328                                 need_to_get = TRUE;
1329                                 
1330                         }
1331                         else 
1332                                 item_id = g_strdup (gw_id);
1333                         break;
1334                 default:
1335                         return E_GW_CONNECTION_STATUS_INVALID_OBJECT;
1336         }
1337
1338         if (all_instances)
1339                 e_cal_component_get_uid (comp, &recurrence_key);
1340
1341         /*FIXME - remove this once the server returns us the same iCalid in both interfaces */
1342
1343         if (need_to_get) {
1344                 EGwItem *item = NULL;
1345                  
1346                 status = e_gw_connection_get_item (cnc, container, item_id, "recipients message recipientStatus attachments default", &item);
1347                 if (status == E_GW_CONNECTION_STATUS_OK)
1348                         *created_comp = e_gw_item_to_cal_component (item, cbgw);
1349
1350                 g_object_unref (item);
1351         }
1352
1353         if (type == E_CAL_COMPONENT_JOURNAL) {
1354                 icalcomponent *icalcomp = e_cal_component_get_icalcomponent (comp);
1355                 icalproperty *icalprop;
1356
1357                 icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
1358                 while (icalprop) {
1359                         const char *x_name;
1360
1361                         x_name = icalproperty_get_x_name (icalprop);
1362                         if (!strcmp (x_name, "X-GW-DECLINED")) {
1363                                 decline = TRUE;
1364                                 *pstatus = ICAL_PARTSTAT_DECLINED;
1365                                 break;
1366                         }
1367                         icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY);
1368                 }
1369         }
1370
1371         switch (method) {
1372         case ICAL_METHOD_REQUEST:
1373                 /* get attendee here and add the list along. */
1374                 if (e_cal_component_has_attendees (comp)) {
1375                         GSList *attendee_list, *l;
1376                         const char *email_id;
1377                         ECalComponentAttendee  *attendee = NULL, *tmp;
1378
1379                         
1380                         e_cal_component_get_attendee_list (comp, &attendee_list);
1381                         for (l = attendee_list; l ; l = g_slist_next (l)) {
1382                                 tmp = (ECalComponentAttendee *) (l->data);
1383                                 email_id = tmp->value;
1384                                 
1385                                 if (!g_ascii_strncasecmp (email_id, "mailto:", 7))
1386                                         email_id += 7;
1387
1388                                 if (!g_ascii_strcasecmp (email_id, e_gw_connection_get_user_email (cnc))) {
1389                                         attendee = tmp;
1390                                         break;
1391                                 }
1392                         }
1393                         if (attendee) {
1394                                 partstat = attendee->status;
1395                         }
1396                         else {
1397                                 status = E_GW_CONNECTION_STATUS_INVALID_OBJECT;
1398                                 break;
1399                         }
1400                         if (attendee_list)
1401                                 e_cal_component_free_attendee_list (attendee_list);
1402                         
1403                 }
1404                 else {
1405                         status = E_GW_CONNECTION_STATUS_INVALID_OBJECT;
1406                         break;
1407                 }
1408                 *pstatus = partstat;
1409                 switch (partstat) {
1410                 ECalComponentTransparency transp;
1411                         
1412                 case ICAL_PARTSTAT_ACCEPTED: 
1413                         e_cal_component_get_transparency (comp, &transp);
1414                         if (transp == E_CAL_COMPONENT_TRANSP_OPAQUE)  {
1415                                 if (all_instances)
1416                                         status = e_gw_connection_accept_request (cnc, item_id, "Busy",  NULL, recurrence_key);
1417                                 else
1418                                         status = e_gw_connection_accept_request (cnc, item_id, "Busy", NULL, NULL);
1419                         }
1420                         else {
1421                                 if (all_instances)
1422                                         status = e_gw_connection_accept_request (cnc, item_id, "Free",  NULL, recurrence_key);
1423                                 else
1424                                         status = e_gw_connection_accept_request (cnc, item_id, "Free", NULL, NULL);
1425                         }
1426                         break;
1427                 case ICAL_PARTSTAT_DECLINED:
1428                         if (all_instances)
1429                                 status = e_gw_connection_decline_request (cnc, item_id, NULL, recurrence_key);
1430                         else
1431                                 status = e_gw_connection_decline_request (cnc, item_id, NULL, NULL);
1432                         
1433                         break;
1434                 case ICAL_PARTSTAT_TENTATIVE:
1435                         if (all_instances)
1436                                 status = e_gw_connection_accept_request (cnc, item_id, "Tentative", NULL, recurrence_key);
1437                         else
1438                                 status = e_gw_connection_accept_request (cnc, item_id, "Tentative", NULL, NULL);
1439                         break;
1440                 case ICAL_PARTSTAT_COMPLETED:
1441                         status = e_gw_connection_complete_request (cnc, item_id);
1442
1443                 default :
1444                         status = E_GW_CONNECTION_STATUS_INVALID_OBJECT;
1445         
1446                 }
1447
1448                 break;
1449
1450         case ICAL_METHOD_CANCEL:
1451                 status = e_gw_connection_retract_request (cnc, item_id, NULL, FALSE, FALSE);
1452                 break;
1453         case ICAL_METHOD_PUBLISH:
1454                 if (decline)
1455                         status = e_gw_connection_decline_request (cnc, item_id, NULL, NULL);
1456                 else
1457                         status = e_gw_connection_accept_request (cnc, item_id, "Free",  NULL, NULL);
1458                 break;
1459         default:
1460                 return E_GW_CONNECTION_STATUS_INVALID_OBJECT;
1461         }
1462         
1463         return status;
1464 }
1465
1466 EGwConnectionStatus
1467 e_gw_connection_create_appointment (EGwConnection *cnc, const char *container, ECalBackendGroupwise *cbgw, ECalComponent *comp, GSList **id_list)
1468 {
1469         EGwItem *item;
1470         EGwConnectionStatus status;
1471         icalproperty *icalprop;
1472         gboolean move_cal = FALSE;
1473         icalcomponent *icalcomp;
1474         char *id = NULL;
1475
1476         g_return_val_if_fail (E_IS_GW_CONNECTION (cnc), E_GW_CONNECTION_STATUS_INVALID_CONNECTION);
1477         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), E_GW_CONNECTION_STATUS_INVALID_OBJECT);
1478
1479         icalcomp = e_cal_component_get_icalcomponent (comp);
1480
1481         icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
1482         while (icalprop) {
1483                 const char *x_name;
1484
1485                 x_name = icalproperty_get_x_name (icalprop);
1486                 if (!strcmp (x_name, "X-EVOLUTION-MOVE-CALENDAR")) {
1487                         move_cal = TRUE;
1488                         break;
1489                 }
1490
1491                 icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY);
1492         }
1493
1494         item = e_gw_item_new_from_cal_component (container, cbgw, comp);
1495         e_gw_item_set_container_id (item, container);
1496         if (!move_cal)
1497                 status = e_gw_connection_send_item (cnc, item, id_list);
1498         else {
1499                 e_gw_item_set_source (item, "personal");
1500                 status = e_gw_connection_create_item (cnc, item, &id);
1501                 *id_list = g_slist_append (*id_list, id);
1502         }
1503         g_object_unref (item);
1504
1505         return status;
1506 }
1507
1508 static EGwConnectionStatus
1509 start_freebusy_session (EGwConnection *cnc, GList *users, 
1510                time_t start, time_t end, const char **session)
1511 {
1512         SoupSoapMessage *msg;
1513         SoupSoapResponse *response;
1514         EGwConnectionStatus status;
1515         SoupSoapParameter *param;
1516         GList *l;
1517         icaltimetype icaltime;
1518         icaltimezone *utc;
1519         const char *start_date, *end_date;
1520
1521         if (users == NULL)
1522                 return E_GW_CONNECTION_STATUS_INVALID_OBJECT;
1523
1524         /* build the SOAP message */
1525         msg = e_gw_message_new_with_header (e_gw_connection_get_uri (cnc),
1526                                             e_gw_connection_get_session_id (cnc),
1527                                             "startFreeBusySessionRequest");
1528         /* FIXME users is just a buch of user names - associate it with uid,
1529          * email id apart from the name*/
1530         
1531         soup_soap_message_start_element (msg, "users", NULL, NULL); 
1532         for ( l = users; l != NULL; l = g_list_next (l)) {
1533                 soup_soap_message_start_element (msg, "user", NULL, NULL); 
1534                 e_gw_message_write_string_parameter (msg, "email", NULL, l->data);
1535                 soup_soap_message_end_element (msg);
1536         }
1537
1538         soup_soap_message_end_element (msg);
1539
1540
1541         utc = icaltimezone_get_utc_timezone ();
1542         icaltime = icaltime_from_timet_with_zone (start, FALSE, utc);
1543         start_date = icaltime_as_ical_string (icaltime);
1544         
1545         icaltime = icaltime_from_timet_with_zone (end, FALSE, utc);
1546         end_date = icaltime_as_ical_string (icaltime);
1547                 
1548         e_gw_message_write_string_parameter (msg, "startDate", NULL, start_date);
1549         e_gw_message_write_string_parameter (msg, "endDate", NULL, end_date);
1550         
1551         e_gw_message_write_footer (msg);
1552
1553         /* send message to server */
1554         response = e_gw_connection_send_message (cnc, msg);
1555         if (!response) {
1556                 g_object_unref (msg);
1557                 return E_GW_CONNECTION_STATUS_NO_RESPONSE;
1558         }
1559
1560         status = e_gw_connection_parse_response_status (response);
1561         if (status != E_GW_CONNECTION_STATUS_OK)
1562         {
1563                 g_object_unref (msg);
1564                 g_object_unref (response);
1565                 return status;
1566         }
1567         
1568         /* if status is OK - parse result, return the list */
1569         param = soup_soap_response_get_first_parameter_by_name (response, "freeBusySessionId");
1570         if (!param) {
1571                 g_object_unref (response);
1572                 g_object_unref (msg);
1573                 return E_GW_CONNECTION_STATUS_INVALID_RESPONSE;
1574         }
1575         
1576         *session = soup_soap_parameter_get_string_value (param); 
1577         /* free memory */
1578         g_object_unref (response);
1579         g_object_unref (msg);
1580
1581         return status;
1582 }
1583
1584 static EGwConnectionStatus 
1585 close_freebusy_session (EGwConnection *cnc, const char *session)
1586 {
1587         SoupSoapMessage *msg;
1588         SoupSoapResponse *response;
1589         EGwConnectionStatus status;
1590
1591         /* build the SOAP message */
1592         msg = e_gw_message_new_with_header (e_gw_connection_get_uri (cnc),
1593                                             e_gw_connection_get_session_id (cnc),
1594                                             "closeFreeBusySessionRequest");
1595         e_gw_message_write_string_parameter (msg, "freeBusySessionId", NULL, session);
1596         e_gw_message_write_footer (msg);
1597
1598         /* send message to server */
1599         response = e_gw_connection_send_message (cnc, msg);
1600         if (!response) {
1601                 g_object_unref (msg);
1602                 return E_GW_CONNECTION_STATUS_NO_RESPONSE;
1603         }
1604
1605         status = e_gw_connection_parse_response_status (response);
1606
1607         g_object_unref (msg);
1608         g_object_unref (response);
1609         return status;
1610 }
1611
1612 EGwConnectionStatus
1613 e_gw_connection_get_freebusy_info (EGwConnection *cnc, GList *users, time_t start, time_t end, GList **freebusy, icaltimezone *default_zone)
1614 {
1615         SoupSoapMessage *msg;
1616         SoupSoapResponse *response;
1617         EGwConnectionStatus status;
1618         SoupSoapParameter *param, *subparam, *param_outstanding;
1619         const char *session, *outstanding = NULL;
1620         gboolean resend_request = TRUE;
1621         int request_iteration = 0;
1622
1623         g_return_val_if_fail (E_IS_GW_CONNECTION (cnc), E_GW_CONNECTION_STATUS_INVALID_CONNECTION);
1624
1625         /* Perform startFreeBusySession */
1626         status = start_freebusy_session (cnc, users, start, end, &session); 
1627         /*FIXME log error messages  */
1628         if (status != E_GW_CONNECTION_STATUS_OK)
1629                 return status;
1630
1631         resend :
1632         while (resend_request) {
1633
1634         /* getFreeBusy */
1635         /* build the SOAP message */
1636         msg = e_gw_message_new_with_header (e_gw_connection_get_uri (cnc),
1637                                             e_gw_connection_get_session_id (cnc),
1638                                             "getFreeBusyRequest");
1639         e_gw_message_write_string_parameter (msg, "freeBusySessionId", NULL, session);
1640         e_gw_message_write_footer (msg);
1641
1642         /* send message to server */
1643         response = e_gw_connection_send_message (cnc, msg);
1644         if (!response) {
1645                 g_object_unref (msg);
1646                 return E_GW_CONNECTION_STATUS_NO_RESPONSE;
1647         }
1648
1649         status = e_gw_connection_parse_response_status (response);
1650         if (status != E_GW_CONNECTION_STATUS_OK) {
1651                 g_object_unref (msg);
1652                 g_object_unref (response);
1653                 return status;
1654         }
1655
1656         param = soup_soap_response_get_first_parameter_by_name (response, "freeBusyStats");
1657         if (!param) {
1658                 g_object_unref (response);
1659                 g_object_unref (msg);
1660                 return E_GW_CONNECTION_STATUS_INVALID_RESPONSE;
1661         }
1662
1663         param_outstanding = soup_soap_parameter_get_first_child_by_name (param, "outstanding");
1664         if (param_outstanding)
1665                 outstanding = soup_soap_parameter_get_string_value (param_outstanding);
1666         /* Try 12 times - this is approximately 2 minutes of time to
1667          * obtain the free/busy information from the server */
1668         if (outstanding && strcmp (outstanding, "0") && (request_iteration < 12)) {
1669                 request_iteration++;
1670                 g_object_unref (msg);
1671                 g_object_unref (response);
1672                 g_usleep (10000000);
1673                 goto resend;
1674         }
1675
1676         /* FIXME  the FreeBusyStats are not used currently.  */
1677         param = soup_soap_response_get_first_parameter_by_name (response, "freeBusyInfo");
1678         if (!param) {
1679                 g_object_unref (response);
1680                 g_object_unref (msg);
1681                 return E_GW_CONNECTION_STATUS_INVALID_RESPONSE;
1682         }
1683
1684         resend_request = FALSE;
1685
1686         for (subparam = soup_soap_parameter_get_first_child_by_name (param, "user");
1687              subparam != NULL;
1688              subparam = soup_soap_parameter_get_next_child_by_name (subparam, "user")) {
1689                 SoupSoapParameter *param_blocks, *subparam_block, *tmp;
1690                 const char *uuid = NULL, *email = NULL, *name = NULL;
1691                 ECalComponent *comp;
1692                 ECalComponentAttendee attendee;
1693                 GSList *attendee_list = NULL;
1694                 icalcomponent *icalcomp = NULL;
1695                 
1696                 tmp = soup_soap_parameter_get_first_child_by_name (subparam, "email");
1697                 if (tmp)
1698                         email = soup_soap_parameter_get_string_value (tmp);
1699                 tmp = soup_soap_parameter_get_first_child_by_name (subparam, "uuid");
1700                 if (tmp)
1701                         uuid = soup_soap_parameter_get_string_value (tmp);
1702                 tmp = soup_soap_parameter_get_first_child_by_name (subparam, "displayName");
1703                 if (tmp)
1704                         name = soup_soap_parameter_get_string_value (tmp);
1705
1706                 comp = e_cal_component_new ();
1707                 e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_FREEBUSY); 
1708                 e_cal_component_commit_sequence (comp);
1709                 icalcomp = e_cal_component_get_icalcomponent (comp);
1710                 
1711                 memset (&attendee, 0, sizeof (ECalComponentAttendee));
1712                 if (name)
1713                         attendee.cn = name;
1714                 if (email)
1715                         attendee.value = email;
1716                 
1717                 attendee.cutype = ICAL_CUTYPE_INDIVIDUAL;
1718                 attendee.role = ICAL_ROLE_REQPARTICIPANT;
1719                 attendee.status = ICAL_PARTSTAT_NEEDSACTION;
1720
1721                 /* XXX the uuid is not currently used. hence it is
1722                  * discarded */
1723
1724                 attendee_list = g_slist_append (attendee_list, &attendee);      
1725
1726                 e_cal_component_set_attendee_list (comp, attendee_list);
1727
1728                 
1729                 param_blocks = soup_soap_parameter_get_first_child_by_name (subparam, "blocks");
1730                 if (!param_blocks) {
1731                         g_object_unref (response);
1732                         g_object_unref (msg);
1733                         return E_GW_CONNECTION_STATUS_INVALID_RESPONSE;
1734                 }
1735         
1736                 for (subparam_block = soup_soap_parameter_get_first_child_by_name (param_blocks, "block");
1737                      subparam_block != NULL;
1738                      subparam_block = soup_soap_parameter_get_next_child_by_name (subparam_block, "block")) {
1739
1740                         /* process each block and create ECal free/busy components.*/ 
1741                         SoupSoapParameter *tmp;
1742                         struct icalperiodtype ipt;
1743                         icalproperty *icalprop;
1744                         icaltimetype itt;
1745                         time_t t;
1746                         const char *start, *end, *accept_level;
1747                         
1748                         memset (&ipt, 0, sizeof (struct icalperiodtype));
1749                         tmp = soup_soap_parameter_get_first_child_by_name (subparam_block, "startDate");
1750                         if (tmp) {
1751                                 start = soup_soap_parameter_get_string_value (tmp);
1752                                 t = e_gw_connection_get_date_from_string (start);
1753                                 itt = icaltime_from_timet_with_zone (t, 0, default_zone ? default_zone : NULL);
1754                                 ipt.start = itt;
1755                         }        
1756
1757                         tmp = soup_soap_parameter_get_first_child_by_name (subparam_block, "endDate");
1758                         if (tmp) {
1759                                 end = soup_soap_parameter_get_string_value (tmp);
1760                                 t = e_gw_connection_get_date_from_string (end);
1761                                 itt = icaltime_from_timet_with_zone (t, 0, default_zone ? default_zone : NULL);
1762                                 ipt.end = itt;
1763                         }
1764                         icalprop = icalproperty_new_freebusy (ipt);
1765
1766                         tmp = soup_soap_parameter_get_first_child_by_name (subparam_block, "acceptLevel");
1767                         if (tmp) {
1768                                 accept_level = soup_soap_parameter_get_string_value (tmp);
1769                                 if (!strcmp (accept_level, "Busy"))
1770                                         icalproperty_set_parameter_from_string (icalprop, "FBTYPE", "BUSY");
1771                                 else if (!strcmp (accept_level, "Tentative"))
1772                                         icalproperty_set_parameter_from_string (icalprop, "FBTYPE", "BUSYTENTATIVE");
1773                                 else if (!strcmp (accept_level, "OutOfOffice"))
1774                                         icalproperty_set_parameter_from_string (icalprop, "FBTYPE", "BUSYUNAVAILABLE");
1775                                 else if (!strcmp (accept_level, "Free"))
1776                                         icalproperty_set_parameter_from_string (icalprop, "FBTYPE", "FREE");
1777                                                         }
1778                         icalcomponent_add_property(icalcomp, icalprop);
1779
1780                 }
1781
1782                 e_cal_component_commit_sequence (comp);
1783                 *freebusy = g_list_append (*freebusy, e_cal_component_get_as_string (comp));
1784                 g_object_unref (comp);
1785         }
1786
1787         g_object_unref (msg);
1788         g_object_unref (response);
1789
1790         } /* end of while loop */
1791
1792         /* closeFreeBusySession*/
1793         return close_freebusy_session (cnc, session);
1794 }
1795
1796 #define SET_DELTA(fieldname) G_STMT_START{                                                                \
1797         fieldname = e_gw_item_get_##fieldname (item);                                                       \
1798         cache_##fieldname = e_gw_item_get_##fieldname (cache_item);                                           \
1799         if ( cache_##fieldname ) {                                                                            \
1800                 if (!fieldname )                                                                               \
1801                         e_gw_item_set_change (item, E_GW_ITEM_CHANGE_TYPE_DELETE, #fieldname, (gpointer) cache_##fieldname );\
1802                 else if (strcmp ( fieldname, cache_##fieldname ))                                               \
1803                         e_gw_item_set_change (item, E_GW_ITEM_CHANGE_TYPE_UPDATE, #fieldname, (gpointer) fieldname );\
1804         }                                                                                                 \
1805         else if ( fieldname )                                                                               \
1806                 e_gw_item_set_change (item, E_GW_ITEM_CHANGE_TYPE_ADD, #fieldname, (gpointer) fieldname );           \
1807         }G_STMT_END
1808
1809 static void 
1810 set_categories_changes (EGwItem *new_item, EGwItem *old_item)
1811 {
1812         GList *old_category_list;
1813         GList *new_category_list;
1814         GList *temp, *old_categories_copy, *added_categories = NULL;
1815         gboolean categories_matched;
1816         char *category1, *category2;
1817         old_category_list = e_gw_item_get_categories (old_item);
1818         new_category_list = e_gw_item_get_categories (new_item);
1819         if (old_category_list && new_category_list) {
1820                 old_categories_copy = g_list_copy (old_category_list);
1821                 for ( ; new_category_list != NULL; new_category_list = g_list_next (new_category_list)) {
1822                         
1823                         category1  = new_category_list->data;
1824                         temp = old_category_list;
1825                         categories_matched  = FALSE;
1826                         for(; temp != NULL; temp = g_list_next (temp)) {
1827                                 category2 = temp->data;
1828                                 if ( g_str_equal (category1, category2)) {
1829                                         categories_matched = TRUE;
1830                                         old_categories_copy = g_list_remove (old_categories_copy, category2);
1831                                         break;
1832                                 }
1833                                 
1834                         }
1835                         if (!categories_matched)
1836                                 added_categories = g_list_append (added_categories, category1);
1837                 }
1838                 
1839                 e_gw_item_set_change (new_item, E_GW_ITEM_CHANGE_TYPE_ADD, "categories", added_categories);
1840                 e_gw_item_set_change (new_item, E_GW_ITEM_CHANGE_TYPE_DELETE, "categories", old_categories_copy);
1841
1842         } else if (!new_category_list && old_category_list) {
1843                 e_gw_item_set_change (new_item,  E_GW_ITEM_CHANGE_TYPE_DELETE, "categories", old_category_list);
1844         } else if (new_category_list && !old_category_list) {
1845                 e_gw_item_set_change (new_item, E_GW_ITEM_CHANGE_TYPE_ADD, "categories", new_category_list);
1846         }
1847
1848 }
1849
1850 void
1851 e_gw_item_set_changes (EGwItem *item, EGwItem *cache_item)
1852 {
1853         const char *subject, *cache_subject;
1854         const char *message, *cache_message;
1855         const char *classification, *cache_classification;
1856         const char *accept_level, *cache_accept_level;
1857         const char *place, *cache_place;
1858         const char *task_priority, *cache_task_priority;
1859         int trigger, cache_trigger;
1860         char *due_date, *cache_due_date;
1861         char *start_date, *cache_start_date;
1862         char *end_date, *cache_end_date;
1863         gboolean is_allday, cache_is_allday;
1864
1865         /* TODO assert the types of the items are the same */
1866
1867         SET_DELTA(subject);
1868         SET_DELTA(message);
1869         SET_DELTA(classification);
1870
1871         
1872         SET_DELTA(start_date);
1873         set_categories_changes (item, cache_item);
1874         /*FIXME  recipient_list modifications need go here after server starts
1875          * supporting retraction */
1876         if (e_gw_item_get_item_type (item) == E_GW_ITEM_TYPE_APPOINTMENT) {
1877
1878                 SET_DELTA(end_date);
1879                 SET_DELTA(accept_level);
1880                 SET_DELTA(place);
1881                 trigger = e_gw_item_get_trigger (item);
1882                 cache_trigger = e_gw_item_get_trigger (cache_item);
1883                 if (cache_trigger) {                                                                            
1884                         if (!trigger)                                                                               
1885                                 e_gw_item_set_change (item, E_GW_ITEM_CHANGE_TYPE_DELETE, "alarm", &cache_trigger);
1886                         else if (trigger != cache_trigger)
1887                                 e_gw_item_set_change (item, E_GW_ITEM_CHANGE_TYPE_UPDATE, "alarm", &trigger);
1888                 }                                                                                                 
1889                 else if (trigger)                                                                               
1890                         e_gw_item_set_change (item, E_GW_ITEM_CHANGE_TYPE_ADD, "alarm", &trigger);
1891                 is_allday = e_gw_item_get_is_allday_event (item);
1892                 cache_is_allday = e_gw_item_get_is_allday_event (cache_item);
1893
1894                 if ((is_allday && !cache_is_allday) || (!is_allday && cache_is_allday))
1895                         e_gw_item_set_change (item, E_GW_ITEM_CHANGE_TYPE_UPDATE, "allDayEvent", &is_allday);
1896         }
1897         else if ( e_gw_item_get_item_type (item) == E_GW_ITEM_TYPE_TASK) {
1898                 SET_DELTA(due_date);
1899                 SET_DELTA(task_priority);
1900         }
1901 }
1902
1903
1904 static void 
1905 add_return_value (EGwSendOptionsReturnNotify track, ESource *source, char *notify)
1906 {
1907         char *value;
1908         
1909         switch (track) {
1910                 case E_GW_RETURN_NOTIFY_MAIL:
1911                         value =  g_strdup ("mail");
1912                         break;
1913                 default:
1914                         value = g_strdup ("none");              
1915         }
1916         
1917         e_source_set_property (source, notify, value);
1918         g_free (value), value = NULL;
1919 }
1920
1921 gboolean
1922 e_cal_backend_groupwise_store_settings (GwSettings *hold)
1923 {
1924         ECalBackendGroupwise *cbgw;
1925         EGwSendOptions *opts;
1926         EGwSendOptionsGeneral *gopts;
1927         EGwSendOptionsStatusTracking *sopts;
1928         icaltimetype tt;
1929         icalcomponent_kind kind;
1930         GConfClient *gconf = gconf_client_get_default ();
1931         ESource *source;
1932         ESourceList *source_list;
1933         const char *uid;
1934         char *value;
1935
1936         cbgw = hold->cbgw;
1937         opts = hold->opts;
1938         source = e_cal_backend_get_source (E_CAL_BACKEND (cbgw));
1939         kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbgw)); 
1940
1941         /* TODO implement send options for Notes */
1942         if (kind == ICAL_VJOURNAL_COMPONENT)
1943                 return FALSE;
1944
1945         gopts = e_gw_sendoptions_get_general_options (opts);
1946         if (kind == ICAL_VEVENT_COMPONENT) {
1947                 source_list = e_source_list_new_for_gconf (gconf, "/apps/evolution/calendar/sources");
1948                 sopts = e_gw_sendoptions_get_status_tracking_options (opts, "calendar");
1949         } else {
1950                 source_list = e_source_list_new_for_gconf (gconf, "/apps/evolution/tasks/sources");
1951                 sopts = e_gw_sendoptions_get_status_tracking_options (opts, "task");
1952         } 
1953         
1954         uid = e_source_peek_uid (source);
1955         source = e_source_list_peek_source_by_uid (source_list, uid);
1956         if (gopts) {
1957                 /* priority */
1958                 switch (gopts->priority) {
1959                         case E_GW_PRIORITY_HIGH:
1960                                 value = g_strdup ("high");
1961                                 break;
1962                         case E_GW_PRIORITY_STANDARD:
1963                                 value = g_strdup ("standard");
1964                                 break;
1965                         case E_GW_PRIORITY_LOW:
1966                                 value =  g_strdup ("low");
1967                                 break;
1968                         default:
1969                                 value = g_strdup ("undefined");
1970                 }
1971                 e_source_set_property (source, "priority", value);
1972                 g_free (value), value = NULL;
1973
1974                 /* Reply Requested */
1975                 if (gopts->reply_enabled) {
1976                         if (gopts->reply_convenient)
1977                                 value = g_strdup ("convinient");
1978                         else 
1979                                 value = g_strdup_printf ("%d",gopts->reply_within);
1980                 } else
1981                         value = g_strdup ("none");
1982                 e_source_set_property (source, "reply-requested", value);
1983                 g_free (value), value = NULL;
1984
1985                 /* Delay delivery */
1986                 if (gopts->delay_enabled) {
1987                         const char *value;
1988                         tt = icaltime_today ();
1989                         icaltime_adjust (&tt, gopts->delay_until, 0, 0, 0);
1990                         value = icaltime_as_ical_string (tt);
1991                 } else
1992                         value = g_strdup ("none");
1993                 e_source_set_property (source, "delay-delivery", value);
1994                 g_free (value), value = NULL;
1995
1996                 /* Expiration date */
1997                 if (gopts->expiration_enabled)
1998                         value =  g_strdup_printf ("%d", gopts->expire_after);
1999                 else
2000                         value = g_strdup ("none");
2001                 e_source_set_property (source, "expiration", value);
2002                 g_free (value), value = NULL;
2003         }
2004
2005         if (sopts) {
2006                 /* status tracking */
2007                 if (sopts->tracking_enabled) {
2008                         switch (sopts->track_when) {
2009                                 case E_GW_DELIVERED :
2010                                         value = g_strdup ("delivered");
2011                                         break;
2012                                 case E_GW_DELIVERED_OPENED:
2013                                         value = g_strdup ("delivered-opened");
2014                                         break;
2015                                 default:
2016                                         value = g_strdup ("all");
2017                         }
2018                 } else
2019                         value = g_strdup ("none");
2020                 e_source_set_property (source, "status-tracking", value);
2021                 g_free (value), value = NULL;
2022
2023                 add_return_value (sopts->opened, source, "return-open"); 
2024                 add_return_value (sopts->accepted, source, "return-accept"); 
2025                 add_return_value (sopts->declined, source, "return-decline"); 
2026                 add_return_value (sopts->completed, source, "return-complete"); 
2027         }       
2028
2029         e_source_list_sync (source_list, NULL);
2030
2031         g_object_unref (hold->opts);
2032         g_free (hold);
2033
2034         g_object_unref (gconf);
2035         g_object_unref (source_list);
2036
2037         return FALSE;
2038 }
2039
2040 gboolean
2041 e_cal_backend_groupwise_utils_check_delegate (ECalComponent *comp, const char *email)
2042 {
2043         icalproperty *prop;     
2044         icalcomponent *icalcomp = e_cal_component_get_icalcomponent (comp);
2045         
2046         /*TODO remove the argument email */
2047         prop = icalcomponent_get_first_property (icalcomp,
2048                                                  ICAL_X_PROPERTY);
2049         while (prop) {
2050                 const char *x_name, *x_val;
2051
2052                 x_name = icalproperty_get_x_name (prop);
2053                 x_val = icalproperty_get_x (prop);
2054                 if (!strcmp (x_name, "X-EVOLUTION-DELEGATED")) {
2055                         icalcomponent_remove_property (icalcomp, prop);
2056                         return TRUE;
2057                 }
2058
2059                 prop = icalcomponent_get_next_property (e_cal_component_get_icalcomponent (comp),
2060                                                         ICAL_X_PROPERTY);
2061         }
2062  
2063         return FALSE;
2064
2065 }
2066