From 5e5e1de764de6b705c12275dc652b1a36ba98fdd Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Mon, 27 Jul 2009 17:34:13 +0200 Subject: Bug #420513 - Be able to notify about meeting only new attendees --- calendar/gui/dialogs/comp-editor-util.c | 132 ++++++++++++++++++++++++++++++++ calendar/gui/dialogs/comp-editor-util.h | 6 ++ calendar/gui/dialogs/comp-editor.c | 23 ++++-- calendar/gui/dialogs/comp-editor.h | 3 +- calendar/gui/dialogs/event-editor.c | 5 +- calendar/gui/dialogs/event-page.c | 15 +++- calendar/gui/dialogs/send-comp.c | 81 ++++++++++++++------ calendar/gui/dialogs/send-comp.h | 2 +- calendar/gui/dialogs/task-editor.c | 2 +- calendar/gui/dialogs/task-page.c | 10 ++- 10 files changed, 240 insertions(+), 39 deletions(-) (limited to 'calendar/gui/dialogs') diff --git a/calendar/gui/dialogs/comp-editor-util.c b/calendar/gui/dialogs/comp-editor-util.c index 697e8bda7f..d8e05ca0df 100644 --- a/calendar/gui/dialogs/comp-editor-util.c +++ b/calendar/gui/dialogs/comp-editor-util.c @@ -35,6 +35,8 @@ #include "e-util/e-binding.h" #include "widgets/misc/e-dateedit.h" #include "../calendar-config.h" +#include "../e-date-edit-config.h" +#include "../itip-utils.h" #include "comp-editor-util.h" @@ -347,3 +349,133 @@ comp_editor_strip_categories (const gchar *categories) return new_categories; } + +static GSList * +manage_new_attendees (const GSList *lst, const gchar *eml, gboolean add) +{ + GSList *copy = NULL; + const GSList *l; + gboolean found = FALSE; + + g_return_val_if_fail (eml != NULL, NULL); + + for (l = lst; l; l = l->next) { + const gchar *eml2 = l->data; + + if (!eml2) + continue; + + if (g_ascii_strcasecmp (eml, eml2) == 0) { + found = TRUE; + if (add) + copy = g_slist_append (copy, g_strdup (eml2)); + } else { + copy = g_slist_append (copy, g_strdup (eml2)); + } + } + + if (!found && add) { + copy = g_slist_append (copy, g_strdup (eml)); + } + + return copy; +} + +static void +free_slist_strs (gpointer data) +{ + GSList *lst = data; + + if (lst) { + g_slist_foreach (lst, (GFunc) g_free, NULL); + g_slist_free (lst); + } +} + +/** + * comp_editor_manage_new_attendees: + * Manages the 'new-attendees' string of new attendees of the component. + * @param comp: The component. + * @param ma: An attendee. + * @param add: TRUE to add attendee's email to new-attendees, FALSE to remove from it. + * + * @note The list is just string of emails separated by ';' + **/ +void +comp_editor_manage_new_attendees (ECalComponent *comp, EMeetingAttendee *ma, gboolean add) +{ + const gchar *eml; + + g_return_if_fail (comp != NULL); + g_return_if_fail (ma != NULL); + + eml = e_meeting_attendee_get_address (ma); + if (eml) + eml = itip_strip_mailto (eml); + g_return_if_fail (eml != NULL); + + g_object_set_data_full (G_OBJECT (comp), "new-attendees", manage_new_attendees (g_object_get_data (G_OBJECT (comp), "new-attendees"), eml, add), free_slist_strs); +} + +/** + * comp_editor_copy_new_attendees: + * Copies "new-attendees" information from src to des component. + * @param des: Component, to copy to. + * @param src: Component, to copy from. + **/ +void +comp_editor_copy_new_attendees (ECalComponent *des, ECalComponent *src) +{ + GSList *copy = NULL, *l; + + g_return_if_fail (src != NULL); + g_return_if_fail (des != NULL); + + for (l = g_object_get_data (G_OBJECT (src), "new-attendees"); l; l = l->next) { + copy = g_slist_append (copy, g_strdup (l->data)); + } + + g_object_set_data_full (G_OBJECT (des), "new-attendees", copy, free_slist_strs); +} + +/** + * comp_editor_have_in_new_attendees: + * @param comp: Component with the "new-attendees" possibly set. + * @param ma: Meeting attendee to check. + * @return Whether ma is present in the list of new attendees of the comp. + **/ +gboolean +comp_editor_have_in_new_attendees (ECalComponent *comp, EMeetingAttendee *ma) +{ + const gchar *eml; + + g_return_val_if_fail (comp != NULL, FALSE); + g_return_val_if_fail (ma != NULL, FALSE); + + eml = e_meeting_attendee_get_address (ma); + if (eml) + eml = itip_strip_mailto (eml); + g_return_val_if_fail (eml != NULL, FALSE); + + return comp_editor_have_in_new_attendees_lst (g_object_get_data (G_OBJECT (comp), "new-attendees"), eml); +} + +/** + * comp_editor_have_in_new_attendees_lst: + * Same as @ref comp_editor_have_in_new_attendees only parameters are direct GSList and string. + **/ +gboolean +comp_editor_have_in_new_attendees_lst (const GSList *new_attendees, const gchar *eml) +{ + const GSList *l; + + if (!eml) + return FALSE; + + for (l = new_attendees; l; l = l->next) { + if (l->data && g_ascii_strcasecmp (eml, l->data) == 0) + return TRUE; + } + + return FALSE; +} diff --git a/calendar/gui/dialogs/comp-editor-util.h b/calendar/gui/dialogs/comp-editor-util.h index 96638aabd0..ec481fa457 100644 --- a/calendar/gui/dialogs/comp-editor-util.h +++ b/calendar/gui/dialogs/comp-editor-util.h @@ -28,6 +28,7 @@ #include #include #include "comp-editor-page.h" +#include "../e-meeting-attendee.h" void comp_editor_dates (CompEditorPageDates *date, ECalComponent *comp); void comp_editor_free_dates (CompEditorPageDates *dates); @@ -43,4 +44,9 @@ struct tm comp_editor_get_current_time (GtkObject *object, gpointer data); gchar *comp_editor_strip_categories (const gchar *categories); +void comp_editor_manage_new_attendees (ECalComponent *comp, EMeetingAttendee *ma, gboolean add); +void comp_editor_copy_new_attendees (ECalComponent *des, ECalComponent *src); +gboolean comp_editor_have_in_new_attendees (ECalComponent *comp, EMeetingAttendee *ma); +gboolean comp_editor_have_in_new_attendees_lst (const GSList *new_attendees, const gchar *eml); + #endif diff --git a/calendar/gui/dialogs/comp-editor.c b/calendar/gui/dialogs/comp-editor.c index 6f74f73248..100a1615fb 100644 --- a/calendar/gui/dialogs/comp-editor.c +++ b/calendar/gui/dialogs/comp-editor.c @@ -60,6 +60,7 @@ #include "cancel-comp.h" #include "recur-comp.h" #include "comp-editor.h" +#include "comp-editor-util.h" #include "../e-cal-popup.h" #include "../calendar-config-keys.h" #include "cal-attachment-select-file.h" @@ -406,6 +407,7 @@ save_comp (CompEditor *editor) timezones = g_hash_table_new (g_str_hash, g_str_equal); clone = e_cal_component_clone (priv->comp); + comp_editor_copy_new_attendees (clone, priv->comp); for (l = priv->pages; l != NULL; l = l->next) { if (!comp_editor_page_fill_component (l->data, clone)) { g_object_unref (clone); @@ -535,7 +537,7 @@ save_comp_with_send (CompEditor *editor) { CompEditorPrivate *priv; CompEditorFlags flags; - gboolean send; + gboolean send, delegated, only_new_attendees = FALSE; gboolean delegate; gboolean strip_alarms = TRUE; @@ -557,7 +559,13 @@ save_comp_with_send (CompEditor *editor) if (!save_comp (editor)) return FALSE; - if ((delegate && !e_cal_get_save_schedules (priv->client)) || (send && send_component_dialog ((GtkWindow *) editor, priv->client, priv->comp, !priv->existing_org, &strip_alarms))) { + delegated = delegate && !e_cal_get_save_schedules (priv->client); + if (delegated || (send && send_component_dialog ((GtkWindow *) editor, priv->client, priv->comp, !priv->existing_org, &strip_alarms, !priv->existing_org ? NULL : &only_new_attendees))) { + if (delegated) + only_new_attendees = FALSE; + + comp_editor_set_flags (editor, (comp_editor_get_flags (editor) & (~COMP_EDITOR_SEND_TO_NEW_ATTENDEES_ONLY)) | (only_new_attendees ? COMP_EDITOR_SEND_TO_NEW_ATTENDEES_ONLY : 0)); + if ((itip_organizer_is_user (priv->comp, priv->client) || itip_sentby_is_user (priv->comp, priv->client))) { if (e_cal_component_get_vtype (priv->comp) == E_CAL_COMPONENT_JOURNAL) return comp_editor_send_comp (editor, E_CAL_COMPONENT_METHOD_PUBLISH, strip_alarms); @@ -2491,8 +2499,10 @@ real_edit_comp (CompEditor *editor, ECalComponent *comp) priv->comp = NULL; } - if (comp) + if (comp) { priv->comp = e_cal_component_clone (comp); + comp_editor_copy_new_attendees (priv->comp, comp); + } priv->existing_org = e_cal_component_has_organizer (comp); priv->warned = FALSE; @@ -2598,6 +2608,8 @@ real_send_comp (CompEditor *editor, ECalComponentItipMethod method, gboolean str if (!send_comp) send_comp = e_cal_component_clone (priv->comp); + comp_editor_copy_new_attendees (send_comp, priv->comp); + if (e_cal_component_get_vtype (send_comp) == E_CAL_COMPONENT_JOURNAL) get_users_from_memo_comp (send_comp, &users); @@ -2612,7 +2624,7 @@ real_send_comp (CompEditor *editor, ECalComponentItipMethod method, gboolean str if (!e_cal_component_has_attachments (priv->comp) || e_cal_get_static_capability (priv->client, CAL_STATIC_CAPABILITY_CREATE_MESSAGES)) { if (itip_send_comp (method, send_comp, priv->client, - NULL, NULL, users, strip_alarms)) { + NULL, NULL, users, strip_alarms, priv->flags & COMP_EDITOR_SEND_TO_NEW_ATTENDEES_ONLY)) { g_object_unref (send_comp); return TRUE; } @@ -2637,7 +2649,7 @@ real_send_comp (CompEditor *editor, ECalComponentItipMethod method, gboolean str } if (itip_send_comp (method, send_comp, priv->client, - NULL, mime_attach_list, users, strip_alarms)) { + NULL, mime_attach_list, users, strip_alarms, priv->flags & COMP_EDITOR_SEND_TO_NEW_ATTENDEES_ONLY)) { gboolean saved = save_comp (editor); g_object_unref (send_comp); @@ -2707,6 +2719,7 @@ comp_editor_get_current_comp (CompEditor *editor, gboolean *correct) priv = editor->priv; comp = e_cal_component_clone (priv->comp); + comp_editor_copy_new_attendees (comp, priv->comp); if (priv->changed) { for (l = priv->pages; l != NULL; l = l->next) all_ok = comp_editor_page_fill_component (l->data, comp) && all_ok; diff --git a/calendar/gui/dialogs/comp-editor.h b/calendar/gui/dialogs/comp-editor.h index 6753635b1a..0edb2cc8eb 100644 --- a/calendar/gui/dialogs/comp-editor.h +++ b/calendar/gui/dialogs/comp-editor.h @@ -84,7 +84,8 @@ typedef enum { COMP_EDITOR_DELEGATE = 1<<2, COMP_EDITOR_USER_ORG = 1<<3, COMP_EDITOR_IS_ASSIGNED = 1<<4, - COMP_EDITOR_IS_SHARED = 1 << 5 + COMP_EDITOR_IS_SHARED = 1 << 5, + COMP_EDITOR_SEND_TO_NEW_ATTENDEES_ONLY = 1 << 6 } CompEditorFlags; GType comp_editor_get_type (void); diff --git a/calendar/gui/dialogs/event-editor.c b/calendar/gui/dialogs/event-editor.c index 94006a961c..c4908158d6 100644 --- a/calendar/gui/dialogs/event-editor.c +++ b/calendar/gui/dialogs/event-editor.c @@ -655,10 +655,11 @@ event_editor_send_comp (CompEditor *editor, ECalComponentItipMethod method, gboo client = e_meeting_store_get_client (priv->model); result = itip_send_comp (E_CAL_COMPONENT_METHOD_CANCEL, comp, - client, NULL, NULL, NULL, strip_alarms); + client, NULL, NULL, NULL, strip_alarms, FALSE); g_object_unref (comp); - return result; + if (!result) + return result; } parent: diff --git a/calendar/gui/dialogs/event-page.c b/calendar/gui/dialogs/event-page.c index caafdf1ab1..c48fe3cb79 100644 --- a/calendar/gui/dialogs/event-page.c +++ b/calendar/gui/dialogs/event-page.c @@ -957,6 +957,7 @@ event_page_fill_widgets (CompEditorPage *page, ECalComponent *comp) /* Component for cancellation */ priv->comp = e_cal_component_clone (comp); + comp_editor_copy_new_attendees (priv->comp, comp); e_cal_component_get_summary (comp, &text); e_dialog_editable_set (priv->summary, text.value); @@ -1171,6 +1172,8 @@ event_page_fill_component (CompEditorPage *page, ECalComponent *comp) text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->description)); + comp_editor_copy_new_attendees (comp, priv->comp); + /* Summary */ str = e_dialog_editable_get (priv->summary); @@ -1706,7 +1709,7 @@ existing_attendee (EMeetingAttendee *ia, ECalComponent *comp) if (attendee->sentby) sentby = itip_strip_mailto (attendee->sentby); - if ((address && !g_ascii_strcasecmp (ia_address, address)) || (sentby && !g_ascii_strcasecmp (ia_sentby, sentby))) { + if ((address && !g_ascii_strcasecmp (ia_address, address)) || (sentby && ia_sentby&& !g_ascii_strcasecmp (ia_sentby, sentby))) { e_cal_component_free_attendee_list (attendees); return TRUE; } @@ -1755,7 +1758,8 @@ remove_attendee (EventPage *epage, EMeetingAttendee *ia) while (ia != NULL) { EMeetingAttendee *ib = NULL; - if (existing_attendee (ia, priv->comp)) { + /* do not add to deleted_attendees if user removed new attendee */ + if (existing_attendee (ia, priv->comp) && !comp_editor_have_in_new_attendees (priv->comp, ia)) { g_object_ref (ia); g_ptr_array_add (priv->deleted_attendees, ia); } @@ -1763,6 +1767,7 @@ remove_attendee (EventPage *epage, EMeetingAttendee *ia) if (e_meeting_attendee_get_delto (ia) != NULL) ib = e_meeting_store_find_attendee (priv->model, e_meeting_attendee_get_delto (ia), NULL); + comp_editor_manage_new_attendees (priv->comp, ia, FALSE); e_meeting_list_view_remove_attendee_from_name_selector (priv->list_view, ia); e_meeting_store_remove_attendee (priv->model, ia); @@ -1851,8 +1856,10 @@ attendee_added_cb (EMeetingListView *emlv, client = comp_editor_get_client (editor); flags = comp_editor_get_flags (editor); - if (!(flags & COMP_EDITOR_DELEGATE)) + if (!(flags & COMP_EDITOR_DELEGATE)) { + comp_editor_manage_new_attendees (priv->comp, ia, TRUE); return; + } if (existing_attendee (ia, priv->comp)) { e_meeting_store_remove_attendee (priv->model, ia); @@ -1867,7 +1874,7 @@ attendee_added_cb (EMeetingListView *emlv, e_meeting_attendee_set_delto (delegator, g_strdup (e_meeting_attendee_get_address (ia))); - e_meeting_attendee_set_delfrom (ia, g_strdup (delegator_id)); + e_meeting_attendee_set_delfrom (ia, g_strdup_printf ("MAILTO:%s", delegator_id)); gtk_widget_set_sensitive (priv->invite, FALSE); gtk_widget_set_sensitive (priv->add, FALSE); gtk_widget_set_sensitive (priv->edit, FALSE); diff --git a/calendar/gui/dialogs/send-comp.c b/calendar/gui/dialogs/send-comp.c index c11dadf853..64e0ce0d84 100644 --- a/calendar/gui/dialogs/send-comp.c +++ b/calendar/gui/dialogs/send-comp.c @@ -32,6 +32,17 @@ +static gboolean +component_has_new_attendees (ECalComponent *comp) +{ + g_return_val_if_fail (comp != NULL, FALSE); + + if (!e_cal_component_has_attendees (comp)) + return FALSE; + + return g_object_get_data (G_OBJECT (comp), "new-attendees") != NULL; +} + static gboolean have_nonprocedural_alarm (ECalComponent *comp) { @@ -64,6 +75,25 @@ have_nonprocedural_alarm (ECalComponent *comp) return FALSE; } +static GtkWidget * +add_checkbox (GtkBox *where, const gchar *caption) +{ + GtkWidget *checkbox, *align; + + g_return_val_if_fail (where != NULL, NULL); + g_return_val_if_fail (caption != NULL, NULL); + + checkbox = gtk_check_button_new_with_mnemonic (caption); + align = gtk_alignment_new (0.0, 0.5, 0.0, 0.0); + gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 12, 12); + gtk_container_add (GTK_CONTAINER (align), checkbox); + gtk_widget_show (checkbox); + gtk_box_pack_start (where, align, TRUE, TRUE, 2); + gtk_widget_show (align); + + return checkbox; +} + /** * send_component_dialog: * @@ -73,10 +103,12 @@ have_nonprocedural_alarm (ECalComponent *comp) * Return value: TRUE if the user clicked Yes, FALSE otherwise. **/ gboolean -send_component_dialog (GtkWindow *parent, ECal *client, ECalComponent *comp, gboolean new, gboolean *strip_alarms) +send_component_dialog (GtkWindow *parent, ECal *client, ECalComponent *comp, gboolean new, gboolean *strip_alarms, gboolean *only_new_attendees) { ECalComponentVType vtype; const gchar *id; + GtkWidget *dialog, *sa_checkbox = NULL, *ona_checkbox = NULL; + gboolean res; if (strip_alarms) *strip_alarms = TRUE; @@ -108,32 +140,37 @@ send_component_dialog (GtkWindow *parent, ECal *client, ECalComponent *comp, gbo return FALSE; } - if (strip_alarms && have_nonprocedural_alarm (comp)) { - GtkWidget *dialog, *checkbox, *align; - gboolean res; + if (only_new_attendees && !component_has_new_attendees (comp)) { + /* do not show the check if there is no new attendee and + set as all attendees are required to be notified */ + *only_new_attendees = FALSE; - dialog = e_error_new (parent, id, NULL); - checkbox = gtk_check_button_new_with_label (_("Send my alarms with this event")); - align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); - gtk_container_add (GTK_CONTAINER (align), checkbox); - gtk_widget_show (checkbox); - gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 6); - gtk_widget_show (align); + /* pretend it as being passed NULL to simplify code below */ + only_new_attendees = NULL; + } - res = gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES; + if (strip_alarms && !have_nonprocedural_alarm (comp)) { + /* pretend it as being passed NULL to simplify code below */ + strip_alarms = NULL; + } - if (res) - *strip_alarms = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbox)); + dialog = e_error_new (parent, id, NULL); - gtk_widget_destroy (GTK_WIDGET (dialog)); + if (strip_alarms) + sa_checkbox = add_checkbox (GTK_BOX (GTK_DIALOG (dialog)->vbox), _("Send my alarms with this event")); + if (only_new_attendees) + ona_checkbox = add_checkbox (GTK_BOX (GTK_DIALOG (dialog)->vbox), _("Notify new attendees _only")); - return res; - } else { - if (e_error_run (parent, id, NULL) == GTK_RESPONSE_YES) - return TRUE; - else - return FALSE; - } + res = gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES; + + if (res && strip_alarms) + *strip_alarms = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (sa_checkbox)); + if (only_new_attendees) + *only_new_attendees = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ona_checkbox)); + + gtk_widget_destroy (GTK_WIDGET (dialog)); + + return res; } gboolean diff --git a/calendar/gui/dialogs/send-comp.h b/calendar/gui/dialogs/send-comp.h index 63644bd52a..83f356b142 100644 --- a/calendar/gui/dialogs/send-comp.h +++ b/calendar/gui/dialogs/send-comp.h @@ -28,7 +28,7 @@ #include #include -gboolean send_component_dialog (GtkWindow *parent, ECal *client, ECalComponent *comp, gboolean new, gboolean *strip_alarms); +gboolean send_component_dialog (GtkWindow *parent, ECal *client, ECalComponent *comp, gboolean new, gboolean *strip_alarms, gboolean *only_new_attendees); gboolean send_component_prompt_subject (GtkWindow *parent, ECal *client, ECalComponent *comp); #endif diff --git a/calendar/gui/dialogs/task-editor.c b/calendar/gui/dialogs/task-editor.c index a309a51d91..37cf357fe9 100644 --- a/calendar/gui/dialogs/task-editor.c +++ b/calendar/gui/dialogs/task-editor.c @@ -480,7 +480,7 @@ task_editor_send_comp (CompEditor *editor, ECalComponentItipMethod method, gbool client = e_meeting_store_get_client (priv->model); result = itip_send_comp (E_CAL_COMPONENT_METHOD_CANCEL, comp, - client, NULL, NULL, NULL, strip_alarms); + client, NULL, NULL, NULL, strip_alarms, FALSE); g_object_unref (comp); if (!result) diff --git a/calendar/gui/dialogs/task-page.c b/calendar/gui/dialogs/task-page.c index 2e60ff5069..90a9f46b8c 100644 --- a/calendar/gui/dialogs/task-page.c +++ b/calendar/gui/dialogs/task-page.c @@ -493,6 +493,7 @@ task_page_fill_widgets (CompEditorPage *page, ECalComponent *comp) /* Component for cancellation */ priv->comp = e_cal_component_clone (comp); + comp_editor_copy_new_attendees (priv->comp, comp); /* Clean the screen */ clear_widgets (tpage); @@ -1021,7 +1022,7 @@ existing_attendee (EMeetingAttendee *ia, ECalComponent *comp) if (attendee->sentby) sentby = itip_strip_mailto (attendee->sentby); - if ((address && !g_ascii_strcasecmp (ia_address, address)) || (sentby && !g_ascii_strcasecmp (ia_sentby, sentby))) { + if ((address && !g_ascii_strcasecmp (ia_address, address)) || (sentby && ia_sentby && !g_ascii_strcasecmp (ia_sentby, sentby))) { e_cal_component_free_attendee_list (attendees); return TRUE; } @@ -1067,7 +1068,7 @@ remove_attendee (TaskPage *page, EMeetingAttendee *ia) while (ia != NULL) { EMeetingAttendee *ib = NULL; - if (existing_attendee (ia, priv->comp)) { + if (existing_attendee (ia, priv->comp) && !comp_editor_have_in_new_attendees (priv->comp, ia)) { g_object_ref (ia); g_ptr_array_add (priv->deleted_attendees, ia); } @@ -1075,6 +1076,7 @@ remove_attendee (TaskPage *page, EMeetingAttendee *ia) if (e_meeting_attendee_get_delto (ia) != NULL) ib = e_meeting_store_find_attendee (priv->model, e_meeting_attendee_get_delto (ia), NULL); + comp_editor_manage_new_attendees (priv->comp, ia, FALSE); e_meeting_list_view_remove_attendee_from_name_selector (priv->list_view, ia); e_meeting_store_remove_attendee (priv->model, ia); @@ -1163,8 +1165,10 @@ attendee_added_cb (EMeetingListView *emlv, client = comp_editor_get_client (editor); flags = comp_editor_get_flags (editor); - if (!(flags & COMP_EDITOR_DELEGATE)) + if (!(flags & COMP_EDITOR_DELEGATE)) { + comp_editor_manage_new_attendees (priv->comp, ia, TRUE); return; + } if (existing_attendee (ia, priv->comp)) e_meeting_store_remove_attendee (priv->model, ia); -- cgit v1.2.3