From 29cefd995861e28b8f77005374efbc2f787ac655 Mon Sep 17 00:00:00 2001 From: Chenthill Palanisamy Date: Mon, 20 Jun 2005 17:16:25 +0000 Subject: Delegate support for personal calendar svn path=/trunk/; revision=29552 --- calendar/ChangeLog | 39 +++++++++ calendar/gui/dialogs/comp-editor.c | 68 +++++++++++++--- calendar/gui/dialogs/event-editor.c | 37 ++++----- calendar/gui/dialogs/meeting-page.c | 71 ++++++++++++++--- calendar/gui/e-cal-popup.c | 85 +++++++++++++++++--- calendar/gui/e-calendar-view.c | 55 +++++++++++-- calendar/gui/e-meeting-list-view.c | 43 ++++++++-- calendar/gui/e-meeting-list-view.h | 3 + calendar/gui/itip-utils.c | 155 ++++++++++++++++++++++++++++++++++-- calendar/gui/itip-utils.h | 2 + 10 files changed, 490 insertions(+), 68 deletions(-) (limited to 'calendar') diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 020a748859..a6d6886dac 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,42 @@ +2005-06-20 Chenthill Palanisamy + + * gui/dialogs/comp-editor.c (save_comp_with_send), + (real_edit_comp), (set_attendees_for_delegation), (real_send_comp): + If a meeting is delegated. Send a Request to the delegate and a + reply to the organizer. + * gui/dialogs/event-editor.c: (event_editor_edit_comp): Add the + delegator alone in the meeting editor for personal calendar. + (event_editor_send_comp), (show_meeting): Show the scheduling + page if the meeting is being delegated. + * gui/dialogs/meeting-page.c: (clear_widgets), + (meeting_page_fill_widgets), (meeting_page_fill_component), + (add_clicked_cb), (remove_attendee), (remove_clicked_cb), + (init_widgets), (attendee_added_cb), (meeting_page_construct): + Do not allow only non-attendees to be added as delegatees. + While sending the delegated item remove the other attendees. + Allow only one delegate to be added for personal calendar. + * gui/e-cal-popup.c: (get_attendee_prop), (is_delegated) + (e_cal_popup_target_new_select):Disabled + the popup menu item if the meeting is already delegated. + * gui/e-cal-popup.h: Added a new mask to check if the meeting + is already delegated. + * gui/e-calendar-view.c: (set_attendee_status_for_delegate), + (on_delegate): Change the status of the attendee to delegated. + Set the new mask for the delegate popup menu item. + * gui/e-meeting-list-view.c: (e_meeting_list_view_class_init), + (attendee_edited_cb): Added a new signal to identify the attendee + added in meeting page. Do not remove the attendee if the user + modifies the existing email id to NULL value. + * gui/e-meeting-list-view.h: Added the notification signal. + * gui/itip-utils.h: Added a new function to get our email id + from the list of attendees. + * gui/itip-utils.c (get_attendee), (itip_get_comp_attendee), + (comp_from), (comp_to_list), (comp_subject), (comp_sentby), + (itip_send_comp): Send udpates to delegator only + if the rsvp is enabled. Set the status of the attendee + properly in the REPLY method, since there will two attendees + unlike the updating attendee status. + 2005-06-18 Tor Lillqvist * gui/GNOME_Evolution_Calendar.server.in.in diff --git a/calendar/gui/dialogs/comp-editor.c b/calendar/gui/dialogs/comp-editor.c index 495de600be..abd16741c4 100644 --- a/calendar/gui/dialogs/comp-editor.c +++ b/calendar/gui/dialogs/comp-editor.c @@ -731,19 +731,26 @@ save_comp_with_send (CompEditor *editor) { CompEditorPrivate *priv; gboolean send; + gboolean delegate; priv = editor->priv; - + send = priv->changed && priv->needs_send; + delegate = priv->flags & COMP_EDITOR_DELEGATE; if (!save_comp (editor)) return FALSE; - if (send && send_component_dialog ((GtkWindow *) editor, priv->client, priv->comp, !priv->existing_org)) { + if (delegate || (send && send_component_dialog ((GtkWindow *) editor, priv->client, priv->comp, !priv->existing_org))) { if (itip_organizer_is_user (priv->comp, priv->client)) return comp_editor_send_comp (editor, E_CAL_COMPONENT_METHOD_REQUEST); - else - return comp_editor_send_comp (editor, E_CAL_COMPONENT_METHOD_REPLY); + else { + if (!comp_editor_send_comp (editor, E_CAL_COMPONENT_METHOD_REQUEST)) + return FALSE; + + if (delegate) + return comp_editor_send_comp (editor, E_CAL_COMPONENT_METHOD_REPLY); + } } return TRUE; @@ -1801,6 +1808,9 @@ real_edit_comp (CompEditor *editor, ECalComponent *comp) e_cal_get_local_attachment_store (priv->client)); cal_attachment_bar_set_comp_uid (priv->attachment_bar, g_strdup (uid)); + if (!itip_organizer_is_user (comp, priv->client)) + comp_editor_sensitize_attachment_bar (editor, FALSE); + fill_widgets (editor); priv->changed =FALSE; @@ -1808,20 +1818,58 @@ real_edit_comp (CompEditor *editor, ECalComponent *comp) listen_for_changes (editor); } +/* TODO These functions should be available in e-cal-component.c */ +static void +set_attendees_for_delegation (ECalComponent *comp, const char *address, ECalComponentItipMethod method) +{ + GSList *attendees, *l, *new; + icalproperty *prop; + icalparameter *param; + icalcomponent *icalcomp; + + icalcomp = e_cal_component_get_icalcomponent (comp); + + for (prop = icalcomponent_get_first_property (icalcomp, ICAL_ATTENDEE_PROPERTY); + prop; + prop = icalcomponent_get_next_property (icalcomp, ICAL_ATTENDEE_PROPERTY)) { + const char *attendee = icalproperty_get_attendee (prop); + const char *delfrom; + + param = icalproperty_get_first_parameter(prop, ICAL_DELEGATEDFROM_PARAMETER); + delfrom = icalparameter_get_delegatedfrom (param); + if (!(g_str_equal (itip_strip_mailto (attendee), address) || + ((delfrom && *delfrom) && + g_str_equal (itip_strip_mailto (delfrom), address)))) { + icalcomponent_remove_property (icalcomp, prop); + } + + } + +} static gboolean real_send_comp (CompEditor *editor, ECalComponentItipMethod method) { CompEditorPrivate *priv; - ECalComponent *tmp_comp; + ECalComponent *tmp_comp, *send_comp; + char *address = NULL; g_return_val_if_fail (editor != NULL, FALSE); g_return_val_if_fail (IS_COMP_EDITOR (editor), FALSE); priv = editor->priv; + send_comp = e_cal_component_clone (priv->comp); + /* The user updates the delegated status to the Organizer, so remove all other attendees */ + if ((priv->flags & COMP_EDITOR_DELEGATE)) { + address = itip_get_comp_attendee (send_comp, priv->client); + + if (address) + set_attendees_for_delegation (send_comp, address, method); + } + if (!e_cal_component_has_attachments (priv->comp)) { - if (itip_send_comp (method, priv->comp, priv->client, + if (itip_send_comp (method, send_comp, priv->client, NULL, NULL)) { #if 0 tmp_comp = priv->comp; @@ -1830,20 +1878,19 @@ real_send_comp (CompEditor *editor, ECalComponentItipMethod method) g_object_unref (tmp_comp); comp_editor_set_changed (editor, TRUE); - save_comp (editor); #endif + save_comp (editor); + g_object_unref (send_comp); return TRUE; } } else { /* Clone the component with attachments set to CID:... */ - ECalComponent *send_comp; int num_attachments, i; GSList *attach_list = NULL; GSList *mime_attach_list; - send_comp = e_cal_component_clone (priv->comp); num_attachments = e_cal_component_get_num_attachments (send_comp); for (i = 0; i < num_attachments ; i++) { @@ -1865,9 +1912,10 @@ real_send_comp (CompEditor *editor, ECalComponentItipMethod method) g_object_unref (send_comp); return TRUE; } - g_object_unref (send_comp); } + g_object_unref (send_comp); + g_free (address); comp_editor_set_changed (editor, TRUE); return FALSE; diff --git a/calendar/gui/dialogs/event-editor.c b/calendar/gui/dialogs/event-editor.c index 72b4d8246b..01ec3936f1 100644 --- a/calendar/gui/dialogs/event-editor.c +++ b/calendar/gui/dialogs/event-editor.c @@ -208,6 +208,7 @@ event_editor_edit_comp (CompEditor *editor, ECalComponent *comp) EventEditor *ee; EventEditorPrivate *priv; ECalComponentOrganizer organizer; + gboolean delegate; ECal *client; GSList *attendees = NULL; @@ -215,17 +216,13 @@ event_editor_edit_comp (CompEditor *editor, ECalComponent *comp) priv = ee->priv; priv->updating = TRUE; - - - client = comp_editor_get_e_cal (COMP_EDITOR (editor)); - if (priv->is_meeting && itip_organizer_is_user (comp, client)) { - COMP_EDITOR_PAGE (priv->event_page)->flags |= COMP_EDITOR_PAGE_USER_ORG; - COMP_EDITOR_PAGE (priv->recur_page)->flags |= COMP_EDITOR_PAGE_USER_ORG; - } - + delegate = (comp_editor_get_flags (COMP_EDITOR (editor)) & COMP_EDITOR_DELEGATE); + if (COMP_EDITOR_CLASS (event_editor_parent_class)->edit_comp) COMP_EDITOR_CLASS (event_editor_parent_class)->edit_comp (editor, comp); + client = comp_editor_get_e_cal (COMP_EDITOR (editor)); + /* Get meeting related stuff */ e_cal_component_get_organizer (comp, &organizer); e_cal_component_get_attendee_list (comp, &attendees); @@ -243,8 +240,9 @@ event_editor_edit_comp (CompEditor *editor, ECalComponent *comp) } else { GSList *l; int row; - const char *user_email; - + char *user_email; + + user_email = itip_get_comp_attendee (comp, client); if (!priv->meeting_shown) { comp_editor_append_page (COMP_EDITOR (ee), COMP_EDITOR_PAGE (priv->sched_page), @@ -254,16 +252,21 @@ event_editor_edit_comp (CompEditor *editor, ECalComponent *comp) _("Invitations")); } - if (! (comp_editor_get_flags (COMP_EDITOR (editor)) & COMP_EDITOR_DELEGATE)) { + if (!(delegate && e_cal_get_static_capability (client, CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY))) { for (l = attendees; l != NULL; l = l->next) { ECalComponentAttendee *ca = l->data; EMeetingAttendee *ia; - + + if (delegate && !g_str_equal (itip_strip_mailto (ca->value), user_email)) + continue; + ia = E_MEETING_ATTENDEE (e_meeting_attendee_new_from_e_cal_component_attendee (ca)); - /* If we aren't the organizer or the attendee is just delegating, don't allow editing */ + /* If we aren't the organizer or the attendee is just delegated, don't allow editing */ if (!comp_editor_get_user_org (editor) || e_meeting_attendee_is_set_delto (ia)) e_meeting_attendee_set_edit_level (ia, E_MEETING_ATTENDEE_EDIT_NONE); + + e_meeting_store_add_attendee (priv->model, ia); g_object_unref(ia); @@ -299,9 +302,6 @@ event_editor_edit_comp (CompEditor *editor, ECalComponent *comp) e_cal_component_free_attendee_list (attendees); comp_editor_set_needs_send (COMP_EDITOR (ee), priv->meeting_shown && itip_organizer_is_user (comp, client)); - if (e_cal_component_has_organizer (comp) && (COMP_EDITOR_PAGE (priv->event_page)->flags & - COMP_EDITOR_PAGE_MEETING)) - comp_editor_sensitize_attachment_bar (editor, itip_organizer_is_user (comp, client)); priv->updating = FALSE; } @@ -332,6 +332,8 @@ event_editor_send_comp (CompEditor *editor, ECalComponentItipMethod method) if (!result) return FALSE; + else + return TRUE; } parent: @@ -428,8 +430,7 @@ show_meeting (EventEditor *ee) } if (comp_editor_get_flags (COMP_EDITOR (ee)) & COMP_EDITOR_DELEGATE) comp_editor_show_page (COMP_EDITOR (ee), COMP_EDITOR_PAGE (priv->meet_page)); - if (comp_editor_get_existing_org (COMP_EDITOR (ee)) && !comp_editor_get_user_org (COMP_EDITOR (ee))) - comp_editor_remove_page (COMP_EDITOR (ee), COMP_EDITOR_PAGE (priv->sched_page)); + } void diff --git a/calendar/gui/dialogs/meeting-page.c b/calendar/gui/dialogs/meeting-page.c index 263a415f41..93ae8353b5 100644 --- a/calendar/gui/dialogs/meeting-page.c +++ b/calendar/gui/dialogs/meeting-page.c @@ -101,7 +101,7 @@ static GtkWidget *meeting_page_get_widget (CompEditorPage *page); static void meeting_page_focus_main_widget (CompEditorPage *page); static gboolean meeting_page_fill_widgets (CompEditorPage *page, ECalComponent *comp); static gboolean meeting_page_fill_component (CompEditorPage *page, ECalComponent *comp); - +static void attendee_added_cb (EMeetingListView *emlv, EMeetingAttendee *attendee, gpointer user_data); G_DEFINE_TYPE (MeetingPage, meeting_page, TYPE_COMP_EDITOR_PAGE); /* Class initialization function for the task page */ @@ -304,7 +304,7 @@ clear_widgets (MeetingPage *mpage) } if (e_cal_get_static_capability (COMP_EDITOR_PAGE (mpage)->client, CAL_STATIC_CAPABILITY_NO_ORGANIZER)) { - gtk_label_set_label (GTK_LABEL (priv->org_label), _("From:")); + gtk_label_set_markup (GTK_LABEL (priv->org_label), _("From:")); gtk_widget_hide (priv->existing_organizer_btn); } @@ -371,7 +371,9 @@ meeting_page_fill_widgets (CompEditorPage *page, ECalComponent *comp) /* Component for cancellation */ priv->comp = e_cal_component_clone (comp); - + + priv->user_add = itip_get_comp_attendee (comp, COMP_EDITOR_PAGE (mpage)->client); + /* If there is an existing organizer show it properly */ if (e_cal_component_has_organizer (comp)) { e_cal_component_get_organizer (comp, &organizer); @@ -401,7 +403,7 @@ meeting_page_fill_widgets (CompEditorPage *page, ECalComponent *comp) priv->user_org = FALSE; } - if (e_cal_get_static_capability (COMP_EDITOR_PAGE (mpage)->client, CAL_STATIC_CAPABILITY_NO_ORGANIZER)) + if (e_cal_get_static_capability (COMP_EDITOR_PAGE (mpage)->client, CAL_STATIC_CAPABILITY_NO_ORGANIZER) && (COMP_EDITOR_PAGE (mpage)->flags & COMP_EDITOR_PAGE_DELEGATE)) string = g_strdup (priv->user_add); else if ( organizer.cn != NULL) string = g_strdup_printf ("%s <%s>", organizer.cn, strip); @@ -495,6 +497,18 @@ meeting_page_fill_component (CompEditorPage *page, ECalComponent *comp) EMeetingAttendee *ia = g_ptr_array_index (attendees, i); ECalComponentAttendee *ca; + /* Remove the duplicate user from the component if present */ + if (e_meeting_attendee_is_set_delto (ia)) { + for (l = attendee_list; l; l = l->next) { + ECalComponentAttendee *a = l->data; + + if (g_str_equal (a->value, e_meeting_attendee_get_address (ia))) { + attendee_list = g_slist_remove (attendee_list, l->data); + break; + } + } + } + ca = e_meeting_attendee_as_e_cal_component_attendee (ia); attendee_list = g_slist_append (attendee_list, ca); @@ -635,7 +649,7 @@ add_clicked_cb (GtkButton *btn, MeetingPage *mpage) attendee = e_meeting_store_add_attendee_with_defaults (mpage->priv->model); if (COMP_EDITOR_PAGE (mpage)->flags & COMP_EDITOR_PAGE_DELEGATE) { - e_meeting_attendee_set_delfrom (attendee, g_strdup (mpage->priv->user_add)); + e_meeting_attendee_set_delfrom (attendee, g_strdup_printf ("MAILTO:%s", mpage->priv->user_add)); } e_meeting_list_view_edit (mpage->priv->list_view, attendee); @@ -674,6 +688,7 @@ remove_attendee (MeetingPage *mpage, EMeetingAttendee *ia) { MeetingPagePrivate *priv; int pos = 0; + gboolean delegate = (COMP_EDITOR_PAGE (mpage)->flags & COMP_EDITOR_PAGE_DELEGATE); priv = mpage->priv; @@ -691,7 +706,9 @@ remove_attendee (MeetingPage *mpage, EMeetingAttendee *ia) ib = e_meeting_store_find_attendee (priv->model, e_meeting_attendee_get_delfrom (ia), &pos); if (ib != NULL) { e_meeting_attendee_set_delto (ib, NULL); - e_meeting_attendee_set_edit_level (ib, E_MEETING_ATTENDEE_EDIT_FULL); + + if (!delegate) + e_meeting_attendee_set_edit_level (ib, E_MEETING_ATTENDEE_EDIT_FULL); } } @@ -710,7 +727,7 @@ remove_attendee (MeetingPage *mpage, EMeetingAttendee *ia) ia = ib; } - + sensitize_widgets (mpage); } @@ -751,6 +768,8 @@ remove_clicked_cb (GtkButton *btn, MeetingPage *mpage) g_free (address); if (!ia) return; + else if (e_meeting_attendee_get_edit_level (ia) != E_MEETING_ATTENDEE_EDIT_FULL) + return; remove_attendee (mpage, ia); @@ -803,6 +822,39 @@ init_widgets (MeetingPage *mpage) /* Contacts button */ g_signal_connect(priv->invite, "clicked", G_CALLBACK (invite_cb), mpage); + + /* Meeting List View */ + g_signal_connect (priv->list_view, "attendee_added", G_CALLBACK (attendee_added_cb), mpage); +} + +static void +attendee_added_cb (EMeetingListView *emlv, EMeetingAttendee *ia, gpointer user_data) +{ + MeetingPage *mpage = MEETING_PAGE (user_data); + MeetingPagePrivate *priv; + gboolean delegate = (COMP_EDITOR_PAGE (mpage)->flags & COMP_EDITOR_PAGE_DELEGATE); + + priv = mpage->priv; + + if (delegate) { + if (existing_attendee (ia, priv->comp)) + e_meeting_store_remove_attendee (priv->model, ia); + else { + if (!e_cal_get_static_capability (COMP_EDITOR_PAGE(mpage)->client, + CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY)) { + const char *delegator_id = e_meeting_attendee_get_delfrom (ia); + EMeetingAttendee *delegator; + + delegator = e_meeting_store_find_attendee (priv->model, delegator_id, NULL); + e_meeting_attendee_set_delto (delegator, + g_strdup (e_meeting_attendee_get_address (ia))); + + gtk_widget_set_sensitive (priv->invite, FALSE); + gtk_widget_set_sensitive (priv->add, FALSE); + } + } + } + } static void @@ -953,11 +1005,6 @@ meeting_page_construct (MeetingPage *mpage, EMeetingStore *ems, } } - if (backend_address) - priv->user_add = backend_address; - else - priv->user_add = g_strdup (a->id->address); - g_object_unref(it); if (address_strings) diff --git a/calendar/gui/e-cal-popup.c b/calendar/gui/e-cal-popup.c index 5dc4462833..3ecddd0bb4 100644 --- a/calendar/gui/e-cal-popup.c +++ b/calendar/gui/e-cal-popup.c @@ -109,6 +109,60 @@ ECalPopup *e_cal_popup_new(const char *menuid) return eabp; } +static icalproperty * +get_attendee_prop (icalcomponent *icalcomp, const char *address) +{ + + icalproperty *prop; + + if (!(address && *address)) + return NULL; + + for (prop = icalcomponent_get_first_property (icalcomp, ICAL_ATTENDEE_PROPERTY); + prop; + prop = icalcomponent_get_next_property (icalcomp, ICAL_ATTENDEE_PROPERTY)) { + const char *attendee = icalproperty_get_attendee (prop); + + if (g_str_equal (itip_strip_mailto (attendee), address)) { + return prop; + } + } + return NULL; +} + +static gboolean +is_delegated (icalcomponent *icalcomp, char *user_email) +{ + icalproperty *prop; + icalparameter *param; + const char *delto = NULL; + + prop = get_attendee_prop (icalcomp, user_email); + + if (prop) { + param = icalproperty_get_first_parameter (prop, ICAL_DELEGATEDTO_PARAMETER); + delto = icalparameter_get_delegatedto (param); + } else + return FALSE; + + prop = get_attendee_prop (icalcomp, itip_strip_mailto (delto)); + + if (prop) { + const char *delfrom; + icalparameter_partstat status; + + param = icalproperty_get_first_parameter (prop, ICAL_DELEGATEDFROM_PARAMETER); + delfrom = icalparameter_get_delegatedfrom (param); + param = icalproperty_get_first_parameter (prop, ICAL_PARTSTAT_PARAMETER); + status = icalparameter_get_partstat (param); + if ((delfrom && *delfrom) && g_str_equal (itip_strip_mailto (delfrom), user_email) + && status != ICAL_PARTSTAT_DECLINED) + return TRUE; + } + + return FALSE; +} + /** * e_cal_popup_target_new_select: * @eabp: @@ -127,18 +181,22 @@ e_cal_popup_target_new_select(ECalPopup *eabp, struct _ECalModel *model, GPtrArr ECalPopupTargetSelect *t = e_popup_target_new(&eabp->popup, E_CAL_POPUP_TARGET_SELECT, sizeof(*t)); guint32 mask = ~0; ECal *client; - gboolean read_only; + gboolean read_only, user_org = FALSE; /* FIXME: This is duplicated in e-cal-menu */ t->model = model; g_object_ref(t->model); t->events = events; - + if (t->events->len == 0) { client = e_cal_model_get_default_client(t->model); } else { ECalModelComponent *comp_data = (ECalModelComponent *)t->events->pdata[0]; + ECalComponent *comp; + + comp = e_cal_component_new (); + e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp)); mask &= ~E_CAL_POPUP_SELECT_ANY; if (t->events->len == 1) @@ -163,28 +221,37 @@ e_cal_popup_target_new_select(ECalPopup *eabp, struct _ECalModel *model, GPtrArr mask &= ~E_CAL_POPUP_SELECT_MEETING; if (e_cal_util_component_has_organizer (comp_data->icalcomp)) { - ECalComponent *comp; - comp = e_cal_component_new (); - e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp)); - if (!itip_organizer_is_user (comp, comp_data->client)) + if (itip_organizer_is_user (comp, comp_data->client)) { mask &= ~E_CAL_POPUP_SELECT_ORGANIZER; + user_org = TRUE; + } - g_object_unref (comp); } else { /* organiser is synonym for owner in this case */ mask &= ~(E_CAL_POPUP_SELECT_ORGANIZER|E_CAL_POPUP_SELECT_NOTMEETING); } client = comp_data->client; + + if (e_cal_get_static_capability (client, CAL_STATIC_CAPABILITY_DELEGATE_SUPPORTED)) { + char *user_email = itip_get_comp_attendee (comp, client); + + if (e_cal_get_static_capability (client, CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY)) + mask &= ~E_CAL_POPUP_SELECT_DELEGATABLE; + else if (!user_org && !is_delegated (comp_data->icalcomp, user_email)) + mask &= ~E_CAL_POPUP_SELECT_DELEGATABLE; + + g_object_unref (comp); + + } } e_cal_is_read_only(client, &read_only, NULL); if (!read_only) mask &= ~E_CAL_POPUP_SELECT_EDITABLE; - if (e_cal_get_static_capability (client, CAL_STATIC_CAPABILITY_DELEGATE_SUPPORTED)) - mask &= ~E_CAL_POPUP_SELECT_DELEGATABLE; + if (!e_cal_get_static_capability (client, CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT) && !e_cal_get_static_capability (client, CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK)) diff --git a/calendar/gui/e-calendar-view.c b/calendar/gui/e-calendar-view.c index 46acc4bf7d..d37ef722f6 100644 --- a/calendar/gui/e-calendar-view.c +++ b/calendar/gui/e-calendar-view.c @@ -1248,27 +1248,63 @@ on_meeting (EPopup *ep, EPopupItem *pitem, void *data) } static void -set_attendee_status_for_delegate (icalcomponent *icalcomp, const char *email_id, ECal *client) +set_attendee_status_for_delegate (icalcomponent *icalcomp, ECal *client) { icalproperty *prop; + icalparameter *param; + char *address = NULL; + ECalComponent *comp; + gboolean found = FALSE; + + comp = e_cal_component_new (); + e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp)); + + address = itip_get_comp_attendee (comp, client); - if (!email_id) - return; for (prop = icalcomponent_get_first_property (icalcomp, ICAL_ATTENDEE_PROPERTY); prop; prop = icalcomponent_get_next_property (icalcomp, ICAL_ATTENDEE_PROPERTY)) { const char *attendee = icalproperty_get_attendee (prop); - if (g_str_equal (attendee + 7, email_id)) { - icalparameter *param; + if (g_str_equal (itip_strip_mailto (attendee), address)) { + param = icalparameter_new_role (ICAL_ROLE_NONPARTICIPANT); + icalproperty_set_parameter (prop, param); param = icalparameter_new_partstat (ICAL_PARTSTAT_DELEGATED); icalproperty_set_parameter (prop, param); + + found = TRUE; break; } } + + /* We couldn find the attendee in the component, so add a new attendee */ + if (!found) { + char *temp = g_strdup_printf ("MAILTO:%s", address); + + prop = icalproperty_new_attendee ((const char *) temp); + icalcomponent_add_property (icalcomp, prop); + + param = icalparameter_new_partstat (ICAL_PARTSTAT_DELEGATED); + icalproperty_add_parameter (prop, param); + + param = icalparameter_new_role (ICAL_ROLE_NONPARTICIPANT); + icalproperty_add_parameter (prop, param); + + param = icalparameter_new_cutype (ICAL_CUTYPE_INDIVIDUAL); + icalproperty_add_parameter (prop, param); + + param = icalparameter_new_rsvp (ICAL_RSVP_TRUE); + icalproperty_add_parameter (prop, param); + + g_free (temp); + } + + + g_free (address); + g_object_unref (comp); } static void @@ -1277,6 +1313,7 @@ on_delegate (EPopup *ep, EPopupItem *pitem, void *data) ECalendarView *cal_view = data; GList *selected; guint32 flags; + icalcomponent *clone; selected = e_calendar_view_get_selected_events (cal_view); if (selected) { @@ -1284,12 +1321,14 @@ on_delegate (EPopup *ep, EPopupItem *pitem, void *data) char *address; e_cal_get_cal_address (event->comp_data->client, &address, NULL); - set_attendee_status_for_delegate (event->comp_data->icalcomp, address, event->comp_data->client); + clone = icalcomponent_new_clone (event->comp_data->icalcomp); + set_attendee_status_for_delegate (clone, event->comp_data->client); flags |= COMP_EDITOR_MEETING | COMP_EDITOR_DELEGATE; - open_event_with_flags (cal_view, event->comp_data->client, event->comp_data->icalcomp, flags); + open_event_with_flags (cal_view, event->comp_data->client, clone, flags); + icalcomponent_free (clone); g_list_free (selected); } } @@ -1478,7 +1517,7 @@ static EPopupItem ecv_child_items [] = { { E_POPUP_ITEM, "41.copyto", N_("Cop_y to Calendar..."), on_copy_to, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING }, { E_POPUP_ITEM, "42.moveto", N_("Mo_ve to Calendar..."), on_move_to, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE }, - { E_POPUP_ITEM, "43.delegate", N_("_Delegate Meeting..."), on_delegate, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE | E_CAL_POPUP_SELECT_DELEGATABLE }, + { E_POPUP_ITEM, "43.delegate", N_("_Delegate Meeting..."), on_delegate, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE | E_CAL_POPUP_SELECT_DELEGATABLE | E_CAL_POPUP_SELECT_MEETING}, { E_POPUP_ITEM, "44.schedule", N_("_Schedule Meeting..."), on_meeting, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE | E_CAL_POPUP_SELECT_NOTMEETING }, { E_POPUP_ITEM, "45.forward", N_("_Forward as iCalendar..."), on_forward, NULL, "stock_mail-forward", 0, E_CAL_POPUP_SELECT_NOTEDITING }, diff --git a/calendar/gui/e-meeting-list-view.c b/calendar/gui/e-meeting-list-view.c index d834a3cf49..3e91bea40c 100644 --- a/calendar/gui/e-meeting-list-view.c +++ b/calendar/gui/e-meeting-list-view.c @@ -56,6 +56,14 @@ struct _EMeetingListViewPrivate { #define BUF_SIZE 1024 +/* Signal IDs */ +enum { + ATTENDEE_ADDED, + LAST_SIGNAL +}; + +static guint e_meeting_list_view_signals[LAST_SIGNAL] = { 0 }; + static void name_selector_dialog_close_cb (ENameSelectorDialog *dialog, gint response, gpointer data); static char *sections[] = {N_("Chair Persons"), @@ -101,6 +109,16 @@ e_meeting_list_view_class_init (EMeetingListViewClass *klass) object_class = G_OBJECT_CLASS (klass); object_class->finalize = e_meeting_list_view_finalize; + + e_meeting_list_view_signals [ATTENDEE_ADDED] = + g_signal_new ("attendee_added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMeetingListViewClass, attendee_added), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); } @@ -209,6 +227,7 @@ attendee_edited_cb (GtkCellRenderer *renderer, const gchar *path, GList *address GtkTreePath *treepath = gtk_tree_path_new_from_string (path); int row = gtk_tree_path_get_indices (treepath)[0]; EMeetingAttendee *existing_attendee; + gboolean removed = FALSE; existing_attendee = e_meeting_store_find_attendee_at_row (model, row); @@ -219,8 +238,8 @@ attendee_edited_cb (GtkCellRenderer *renderer, const gchar *path, GList *address for (l = addresses, m = names; l && m; l = l->next, m = m->next) { char *name = m->data, *email = l->data; - if (!((name && *name) || (email && *email))) - continue; + if (!((name && *name) || (email && *email))) + continue; if (e_meeting_store_find_attendee (model, email, NULL) != NULL) continue; @@ -237,26 +256,40 @@ attendee_edited_cb (GtkCellRenderer *renderer, const gchar *path, GList *address } } - if (existing_attendee) + if (existing_attendee) { + removed = TRUE; e_meeting_store_remove_attendee (model, existing_attendee); + } } else if (g_list_length (addresses) == 1) { char *name = names->data, *email = addresses->data; int existing_row; if (!((name && *name) || (email && *email)) || ((e_meeting_store_find_attendee (model, email, &existing_row) != NULL) && existing_row != row)){ - if (existing_attendee) + if (existing_attendee) { + removed = TRUE; e_meeting_store_remove_attendee (model, existing_attendee); + } } else { value_edited (view, E_MEETING_STORE_ADDRESS_COL, path, email); value_edited (view, E_MEETING_STORE_CN_COL, path, name); } } else { - if (existing_attendee) + if (existing_attendee) { + const char *address = e_meeting_attendee_get_address (existing_attendee); + + if (address && *address) + return; + + removed = TRUE; e_meeting_store_remove_attendee (model, existing_attendee); + } } gtk_tree_path_free (treepath); + + if (!removed) + g_signal_emit_by_name (G_OBJECT (view), "attendee_added", (gpointer) existing_attendee); } static void diff --git a/calendar/gui/e-meeting-list-view.h b/calendar/gui/e-meeting-list-view.h index 6fc433b82c..9c17725aa1 100644 --- a/calendar/gui/e-meeting-list-view.h +++ b/calendar/gui/e-meeting-list-view.h @@ -47,6 +47,9 @@ struct _EMeetingListView { struct _EMeetingListViewClass { GtkTreeViewClass parent_class; + + /* Notification Signals */ + void (*attendee_added) (EMeetingListView *emlv, EMeetingAttendee *attendee); }; GType e_meeting_list_view_get_type (void); diff --git a/calendar/gui/itip-utils.c b/calendar/gui/itip-utils.c index fa76efe579..517e3cad97 100644 --- a/calendar/gui/itip-utils.c +++ b/calendar/gui/itip-utils.c @@ -138,7 +138,81 @@ itip_sentby_is_user (ECalComponent *comp) return user_sentby; } - + +static ECalComponentAttendee * +get_attendee (GSList *attendees, char *address) +{ + GSList *l; + + for (l = attendees; l; l = l->next) { + ECalComponentAttendee *attendee = l->data; + + if (g_str_equal (itip_strip_mailto (attendee->value), address)) { + return attendee; + } + } + + return NULL; +} + +char * +itip_get_comp_attendee (ECalComponent *comp, ECal *client) +{ + GSList *attendees; + EAccountList *al; + EAccount *a; + EIterator *it; + ECalComponentAttendee *attendee = NULL; + char *address = NULL; + + e_cal_component_get_attendee_list (comp, &attendees); + al = itip_addresses_get (); + + if (client) + e_cal_get_cal_address (client, &address, NULL); + + if (address && *address) { + attendee = get_attendee (attendees, address); + + if (attendee) { + char *user_email = g_strdup (itip_strip_mailto (attendee->value)); + + e_cal_component_free_attendee_list (attendees); + g_free (address); + return user_email; + } + } + + for (it = e_list_get_iterator((EList *)al); + e_iterator_is_valid(it); + e_iterator_next(it)) { + a = (EAccount *) e_iterator_get(it); + + if (!a->enabled) + continue; + + attendee = get_attendee (attendees, a->id->address); + if (attendee) { + char *user_email = g_strdup (itip_strip_mailto (attendee->value)); + + e_cal_component_free_attendee_list (attendees); + g_free (address); + return user_email; + } + } + + /* We could not find the attendee in the component, so just give the default + account address if the email address is not set in the backend */ + /* FIXME do we have a better way ? */ + if (!(address && *address)) { + a = itip_addresses_get_default (); + address = g_strdup (a->id->address); + } + + e_cal_component_free_attendee_list (attendees); + return address; +} + const gchar * itip_strip_mailto (const gchar *address) { @@ -256,14 +330,22 @@ comp_from (ECalComponentItipMethod method, ECalComponent *comp) ECalComponentAttendee *attendee; GSList *attendees; CORBA_char *str; + char *sender = NULL; switch (method) { case E_CAL_COMPONENT_METHOD_PUBLISH: return CORBA_string_dup (""); case E_CAL_COMPONENT_METHOD_REQUEST: + sender = itip_get_comp_attendee (comp, NULL); + if (sender) { + str = CORBA_string_dup (sender); + g_free (sender); + return str; + } case E_CAL_COMPONENT_METHOD_CANCEL: - case E_CAL_COMPONENT_METHOD_ADD: + case E_CAL_COMPONENT_METHOD_ADD: + e_cal_component_get_organizer (comp, &organizer); if (organizer.value == NULL) { e_notice (NULL, GTK_MESSAGE_ERROR, @@ -294,6 +376,7 @@ comp_to_list (ECalComponentItipMethod method, ECalComponent *comp, GList *users) ECalComponentOrganizer organizer; GSList *attendees, *l; gint len; + char *sender = NULL; switch (method) { case E_CAL_COMPONENT_METHOD_REQUEST: @@ -318,6 +401,7 @@ comp_to_list (ECalComponentItipMethod method, ECalComponent *comp, GList *users) _("An organizer must be set.")); return NULL; } + sender = itip_get_comp_attendee (comp, NULL); for (l = attendees; l != NULL; l = l->next) { ECalComponentAttendee *att = l->data; @@ -326,6 +410,12 @@ comp_to_list (ECalComponentItipMethod method, ECalComponent *comp, GList *users) continue; else if (!g_strcasecmp (att->value, organizer.value)) continue; + else if (!g_strcasecmp (itip_strip_mailto (att->value), sender)) + continue; + else if (att->status == ICAL_PARTSTAT_DELEGATED && (att->delto && *att->delto) + && !(att->rsvp) && method == E_CAL_COMPONENT_METHOD_REQUEST) + continue; + recipient = &(to_list->_buffer[to_list->_length]); if (att->cn) @@ -336,6 +426,7 @@ comp_to_list (ECalComponentItipMethod method, ECalComponent *comp, GList *users) to_list->_length++; } + g_free (sender); e_cal_component_free_attendee_list (attendees); break; @@ -351,19 +442,42 @@ comp_to_list (ECalComponentItipMethod method, ECalComponent *comp, GList *users) return NULL; } - len = 1; + len = 2; to_list = GNOME_Evolution_Composer_RecipientList__alloc (); to_list->_maximum = len; - to_list->_length = len; + to_list->_length = 0; to_list->_buffer = CORBA_sequence_GNOME_Evolution_Composer_Recipient_allocbuf (len); recipient = &(to_list->_buffer[0]); + to_list->_length++; if (organizer.cn != NULL) recipient->name = CORBA_string_dup (organizer.cn); else recipient->name = CORBA_string_dup (""); recipient->address = CORBA_string_dup (itip_strip_mailto (organizer.value)); + + /* send the status to delegatee to the delegate also*/ + e_cal_component_get_attendee_list (comp, &attendees); + sender = itip_get_comp_attendee (comp, NULL); + + for (l = attendees; l != NULL; l = l->next) { + ECalComponentAttendee *att = l->data; + + if (!g_strcasecmp (itip_strip_mailto (att->value), sender)){ + + if (!(att->delfrom && *att->delfrom)) + break; + + recipient = &(to_list->_buffer[to_list->_length]); + recipient->name = CORBA_string_dup (""); + recipient->address = CORBA_string_dup (itip_strip_mailto (att->delfrom)); + to_list->_length++; + } + + } + e_cal_component_free_attendee_list (attendees); + break; default: @@ -381,8 +495,10 @@ comp_subject (ECalComponentItipMethod method, ECalComponent *comp) { ECalComponentText caltext; const char *description, *prefix = NULL; - GSList *alist; + GSList *alist, *l; CORBA_char *subject; + char *sender; + ECalComponentAttendee *a; e_cal_component_get_summary (comp, &caltext); if (caltext.value != NULL) @@ -413,8 +529,18 @@ comp_subject (ECalComponentItipMethod method, ECalComponent *comp) case E_CAL_COMPONENT_METHOD_REPLY: e_cal_component_get_attendee_list (comp, &alist); + sender = itip_get_comp_attendee (comp, NULL); + if (sender) { + + for (l = alist; l != NULL ; l = l->next) { + a = l->data; + if ((sender && *sender) && g_str_equal (itip_strip_mailto (a->value), sender)) + break; + } + g_free (sender); + } + if (alist != NULL) { - ECalComponentAttendee *a = alist->data; switch (a->status) { case ICAL_PARTSTAT_ACCEPTED: @@ -426,6 +552,9 @@ comp_subject (ECalComponentItipMethod method, ECalComponent *comp) case ICAL_PARTSTAT_DECLINED: prefix = _("Declined"); break; + case ICAL_PARTSTAT_DELEGATED: + prefix = _("Delegated"); + break; default: break; } @@ -614,6 +743,8 @@ static void comp_sentby (ECalComponent *comp, ECal *client) { ECalComponentOrganizer organizer; + GList * attendees, *l; + char *user = NULL; e_cal_component_get_organizer (comp, &organizer); if (!organizer.value) { @@ -630,6 +761,17 @@ comp_sentby (ECalComponent *comp, ECal *client) return; } + e_cal_component_get_attendee_list (comp, &attendees); + user = itip_get_comp_attendee (comp, client); + for (l = attendees; l; l = l->next) { + ECalComponentAttendee *a = l->data; + + if (g_str_equal (itip_strip_mailto (a->value), user)) { + g_free (user); + return; + } + } + if (!itip_organizer_is_user (comp, client) && !itip_sentby_is_user (comp)) { EAccount *a = itip_addresses_get_default (); @@ -961,6 +1103,7 @@ itip_send_comp (ECalComponentItipMethod method, ECalComponent *send_comp, top_level = comp_toplevel_with_zones (method, comp, client, zones); ical_string = icalcomponent_as_ical_string (top_level); + if (e_cal_component_get_vtype (comp) == E_CAL_COMPONENT_EVENT) { GNOME_Evolution_Composer_setBody (composer_server, ical_string, content_type, &ev); } else { diff --git a/calendar/gui/itip-utils.h b/calendar/gui/itip-utils.h index bfbd4ab6fc..39e4f6d099 100644 --- a/calendar/gui/itip-utils.h +++ b/calendar/gui/itip-utils.h @@ -28,6 +28,8 @@ gboolean itip_sentby_is_user (ECalComponent *comp); const gchar *itip_strip_mailto (const gchar *address); +char *itip_get_comp_attendee (ECalComponent *comp, ECal *client); + gboolean itip_send_comp (ECalComponentItipMethod method, ECalComponent *comp, ECal *client, icalcomponent *zones, GSList *attachments_list); -- cgit v1.2.3