436 lines
13 KiB
C
436 lines
13 KiB
C
/*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) version 3.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with the program; if not, see <http://www.gnu.org/licenses/>
|
|
*
|
|
*
|
|
* Authors:
|
|
* Johnny Jacob <johnnyjacob@gmail.com>
|
|
*
|
|
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
#include <string.h>
|
|
#include <glib.h>
|
|
#include <gtk/gtk.h>
|
|
#include <glib/gi18n.h>
|
|
#include <e-util/e-config.h>
|
|
#include <e-util/e-popup.h>
|
|
#include <mail/em-popup.h>
|
|
#include <mail/em-menu.h>
|
|
#include <mail/mail-ops.h>
|
|
#include <mail/mail-mt.h>
|
|
#include <mail/em-folder-view.h>
|
|
#include <mail/em-format-html-display.h>
|
|
#include <mail/em-utils.h>
|
|
#include "e-attachment-bar.h"
|
|
#include <camel/camel-vee-folder.h>
|
|
#include "e-util/e-error.h"
|
|
#include <libedataserverui/e-source-selector.h>
|
|
#include <libecal/e-cal.h>
|
|
#include <libical/icalvcal.h>
|
|
#include <calendar/common/authentication.h>
|
|
|
|
typedef struct {
|
|
ECal *client;
|
|
int source_type;
|
|
icalcomponent *icalcomp;
|
|
GtkWidget *window;
|
|
GtkWidget *selector;
|
|
} ICalImporterData;
|
|
|
|
|
|
static void import_ics (EPlugin *ep, EPopupTarget *t, void *data);
|
|
static icalcomponent* get_icalcomponent_from_file(char *filename);
|
|
static void prepare_events (icalcomponent *icalcomp, GList **vtodos);
|
|
static void prepare_tasks (icalcomponent *icalcomp, GList *vtodos);
|
|
static void import_items(ICalImporterData *icidata);
|
|
static gboolean update_objects (ECal *client, icalcomponent *icalcomp);
|
|
static void dialog_response_cb (GtkDialog *dialog, gint response_id, ICalImporterData *icidata);
|
|
static void ical_import_done(ICalImporterData *icidata);
|
|
static void init_widgets (char *path);
|
|
static icalcomponent_kind get_menu_type (void *data);
|
|
|
|
void org_gnome_evolution_import_ics_attachments (EPlugin *ep, EMPopupTargetAttachments *t);
|
|
void org_gnome_evolution_import_ics_part (EPlugin *ep, EMPopupTargetPart *t);
|
|
|
|
static void
|
|
popup_free (EPopup *ep, GSList *items, void *data)
|
|
{
|
|
g_slist_free (items);
|
|
}
|
|
|
|
static EPopupItem popup_calendar_items[] = {
|
|
{ E_POPUP_BAR, "25.display.00"},
|
|
{ E_POPUP_ITEM, "25.display.01", N_("_Import to Calendar"), (EPopupActivateFunc)import_ics, NULL, "stock_mail-import"}
|
|
};
|
|
|
|
static EPopupItem popup_tasks_items[] = {
|
|
{ E_POPUP_BAR, "25.display.00"},
|
|
{ E_POPUP_ITEM, "25.display.01", N_("_Import to Tasks"), (EPopupActivateFunc)import_ics, NULL, "stock_mail-import"}
|
|
};
|
|
|
|
|
|
void org_gnome_evolution_import_ics_attachments (EPlugin *ep, EMPopupTargetAttachments *t)
|
|
{
|
|
GSList *menus = NULL;
|
|
icalcomponent_kind kind;
|
|
int len = 0;
|
|
int i = 0;
|
|
CamelContentType *type;
|
|
|
|
len = g_slist_length(t->attachments);
|
|
|
|
if (len != 1)
|
|
return;
|
|
|
|
type = camel_data_wrapper_get_mime_type_field (((CamelDataWrapper *) ((EAttachment *) t->attachments->data)->body));
|
|
if (type && camel_content_type_is(type, "text", "calendar")) {
|
|
|
|
kind = get_menu_type (t);
|
|
|
|
if (kind == ICAL_VTODO_COMPONENT ) {
|
|
for (i = 0; i < sizeof (popup_tasks_items) / sizeof (popup_tasks_items[0]); i++)
|
|
menus = g_slist_prepend (menus, &popup_tasks_items[i]);
|
|
} else if ( kind == ICAL_VEVENT_COMPONENT) {
|
|
for (i = 0; i < sizeof (popup_calendar_items) / sizeof (popup_calendar_items[0]); i++)
|
|
menus = g_slist_prepend (menus, &popup_calendar_items[i]);
|
|
}
|
|
|
|
e_popup_add_items (t->target.popup, menus, NULL, popup_free, t);
|
|
}
|
|
}
|
|
|
|
void org_gnome_evolution_import_ics_part (EPlugin*ep, EMPopupTargetPart *t)
|
|
{
|
|
GSList *menus = NULL;
|
|
icalcomponent_kind kind;
|
|
int i = 0;
|
|
|
|
if (!camel_content_type_is(((CamelDataWrapper *) t->part)->mime_type, "text", "calendar"))
|
|
return;
|
|
|
|
kind = get_menu_type (t);
|
|
|
|
if (kind == ICAL_VTODO_COMPONENT ) {
|
|
for (i = 0; i < sizeof (popup_tasks_items) / sizeof (popup_tasks_items[0]); i++)
|
|
menus = g_slist_prepend (menus, &popup_tasks_items[i]);
|
|
} else if ( kind == ICAL_VEVENT_COMPONENT) {
|
|
for (i = 0; i < sizeof (popup_calendar_items) / sizeof (popup_calendar_items[0]); i++)
|
|
menus = g_slist_prepend (menus, &popup_calendar_items[i]);
|
|
}
|
|
|
|
e_popup_add_items (t->target.popup, menus, NULL, popup_free, t);
|
|
}
|
|
|
|
static icalcomponent_kind
|
|
get_menu_type (void *data)
|
|
{
|
|
CamelMimePart *part;
|
|
char *path;
|
|
icalcomponent *icalcomp, *subcomp;
|
|
icalcomponent_kind kind;
|
|
EPopupTarget *target = (EPopupTarget *) data;
|
|
|
|
if (target->type == EM_POPUP_TARGET_ATTACHMENTS)
|
|
part = ((EAttachment *) ((EMPopupTargetAttachments *) target)->attachments->data)->body;
|
|
else
|
|
part = ((EMPopupTargetPart *) target)->part;
|
|
|
|
path = em_utils_temp_save_part (NULL, part, FALSE);
|
|
|
|
icalcomp = get_icalcomponent_from_file (path);
|
|
|
|
subcomp = icalcomponent_get_inner(icalcomp);
|
|
kind = icalcomponent_isa (subcomp);
|
|
|
|
if (kind == ICAL_VTODO_COMPONENT ) {
|
|
return ICAL_VTODO_COMPONENT;
|
|
} else if ( kind == ICAL_VEVENT_COMPONENT) {
|
|
return ICAL_VEVENT_COMPONENT;
|
|
}
|
|
return ICAL_NO_COMPONENT;
|
|
}
|
|
|
|
static void
|
|
import_ics (EPlugin *ep, EPopupTarget *t, void *data)
|
|
{
|
|
CamelMimePart *part;
|
|
char *path;
|
|
EPopupTarget *target = (EPopupTarget *) data;
|
|
|
|
if (target->type == EM_POPUP_TARGET_ATTACHMENTS)
|
|
part = ((EAttachment *) ((EMPopupTargetAttachments *) target)->attachments->data)->body;
|
|
else
|
|
part = ((EMPopupTargetPart *) target)->part;
|
|
|
|
path = em_utils_temp_save_part (NULL, part, FALSE);
|
|
init_widgets(path);
|
|
}
|
|
|
|
static void
|
|
init_widgets(char *path)
|
|
{
|
|
|
|
GtkWidget *vbox, *hbox, *dialog;
|
|
icalcomponent_kind kind;
|
|
icalcomponent *subcomp;
|
|
GtkWidget *selector, *label;
|
|
ESourceList *source_list;
|
|
ESource *primary;
|
|
GtkWidget *scrolled;
|
|
ICalImporterData *icidata = g_malloc0(sizeof(*icidata));
|
|
GtkWidget *icon, *button;
|
|
char *label_str = NULL;
|
|
char *markup;
|
|
|
|
g_return_if_fail ( path != NULL);
|
|
dialog = gtk_dialog_new_with_buttons (_("Import ICS"),
|
|
NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
NULL);
|
|
icidata->window = dialog;
|
|
g_signal_connect (dialog,
|
|
"response",
|
|
G_CALLBACK (dialog_response_cb),
|
|
icidata);
|
|
|
|
vbox = GTK_DIALOG(dialog)->vbox;
|
|
hbox = gtk_hbox_new (FALSE, FALSE);
|
|
label = gtk_label_new(NULL);
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 6);
|
|
|
|
icidata->icalcomp = get_icalcomponent_from_file (path);
|
|
|
|
subcomp = icalcomponent_get_inner(icidata->icalcomp);
|
|
kind = icalcomponent_isa (subcomp);
|
|
|
|
if (kind == ICAL_VTODO_COMPONENT ) {
|
|
e_cal_get_sources (&source_list, E_CAL_SOURCE_TYPE_TODO, NULL);
|
|
label_str = _("Select Task List");
|
|
icidata->source_type = E_CAL_SOURCE_TYPE_TODO;
|
|
} else if ( kind == ICAL_VEVENT_COMPONENT) {
|
|
e_cal_get_sources (&source_list, E_CAL_SOURCE_TYPE_EVENT, NULL);
|
|
label_str = _("Select Calendar");
|
|
icidata->source_type = E_CAL_SOURCE_TYPE_EVENT;
|
|
}
|
|
|
|
markup = g_markup_printf_escaped ("<b>%s</b>", label_str);
|
|
gtk_label_set_markup (GTK_LABEL (label), markup);
|
|
g_free (markup);
|
|
hbox = gtk_hbox_new (FALSE, FALSE);
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 6);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 6);
|
|
|
|
selector = e_source_selector_new (source_list);
|
|
e_source_selector_show_selection (E_SOURCE_SELECTOR (selector), FALSE);
|
|
scrolled = gtk_scrolled_window_new(NULL, NULL);
|
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
gtk_container_add((GtkContainer *)scrolled, selector);
|
|
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), GTK_SHADOW_IN);
|
|
hbox = gtk_hbox_new (FALSE, FALSE);
|
|
gtk_box_pack_start (GTK_BOX (hbox), scrolled, TRUE, TRUE, 6);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 6);
|
|
icidata->selector = selector;
|
|
|
|
|
|
/* FIXME What if no sources? */
|
|
primary = e_source_list_peek_source_any (source_list);
|
|
e_source_selector_set_primary_selection (E_SOURCE_SELECTOR (selector), primary);
|
|
|
|
g_object_unref (source_list);
|
|
hbox = gtk_hbox_new (FALSE, FALSE);
|
|
icon = gtk_image_new_from_icon_name (
|
|
"stock_mail-import", GTK_ICON_SIZE_MENU);
|
|
gtk_box_pack_start (GTK_BOX(hbox), icon, FALSE, FALSE, 6);
|
|
label = gtk_label_new_with_mnemonic (_("_Import"));
|
|
gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 6);
|
|
gtk_widget_show(label);
|
|
button = gtk_button_new ();
|
|
gtk_container_add (GTK_CONTAINER (button), hbox);
|
|
gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_OK);
|
|
gtk_widget_grab_focus (button);
|
|
|
|
gtk_window_set_default_size (GTK_WINDOW (dialog), 210,340);
|
|
gtk_widget_show_all (dialog);
|
|
gtk_dialog_run (GTK_DIALOG (dialog));
|
|
gtk_widget_destroy (dialog);
|
|
}
|
|
|
|
static void
|
|
dialog_response_cb (GtkDialog *dialog, gint response_id, ICalImporterData *icidata)
|
|
{
|
|
switch (response_id) {
|
|
case GTK_RESPONSE_OK :
|
|
import_items(icidata);
|
|
break;
|
|
|
|
case GTK_RESPONSE_CANCEL :
|
|
case GTK_RESPONSE_DELETE_EVENT :
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* This removes all components except VEVENTs and VTIMEZONEs from the toplevel */
|
|
static void
|
|
prepare_events (icalcomponent *icalcomp, GList **vtodos)
|
|
{
|
|
icalcomponent *subcomp;
|
|
icalcompiter iter;
|
|
|
|
if (vtodos)
|
|
*vtodos = NULL;
|
|
|
|
iter = icalcomponent_begin_component (icalcomp, ICAL_ANY_COMPONENT);
|
|
while ((subcomp = icalcompiter_deref (&iter)) != NULL) {
|
|
icalcomponent_kind child_kind = icalcomponent_isa (subcomp);
|
|
if (child_kind != ICAL_VEVENT_COMPONENT
|
|
&& child_kind != ICAL_VTIMEZONE_COMPONENT) {
|
|
|
|
icalcompiter_next (&iter);
|
|
|
|
icalcomponent_remove_component (icalcomp, subcomp);
|
|
if (child_kind == ICAL_VTODO_COMPONENT && vtodos)
|
|
*vtodos = g_list_prepend (*vtodos, subcomp);
|
|
else
|
|
icalcomponent_free (subcomp);
|
|
} else {
|
|
icalcompiter_next (&iter);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* This removes all components except VTODOs and VTIMEZONEs from the toplevel
|
|
icalcomponent, and adds the given list of VTODO components. The list is
|
|
freed afterwards. */
|
|
static void
|
|
prepare_tasks (icalcomponent *icalcomp, GList *vtodos)
|
|
{
|
|
icalcomponent *subcomp;
|
|
GList *elem;
|
|
icalcompiter iter;
|
|
|
|
iter = icalcomponent_begin_component (icalcomp, ICAL_ANY_COMPONENT);
|
|
while ((subcomp = icalcompiter_deref (&iter)) != NULL) {
|
|
icalcomponent_kind child_kind = icalcomponent_isa (subcomp);
|
|
if (child_kind != ICAL_VTODO_COMPONENT
|
|
&& child_kind != ICAL_VTIMEZONE_COMPONENT) {
|
|
icalcompiter_next (&iter);
|
|
icalcomponent_remove_component (icalcomp, subcomp);
|
|
icalcomponent_free (subcomp);
|
|
} else {
|
|
icalcompiter_next (&iter);
|
|
}
|
|
}
|
|
|
|
for (elem = vtodos; elem; elem = elem->next) {
|
|
icalcomponent_add_component (icalcomp, elem->data);
|
|
}
|
|
g_list_free (vtodos);
|
|
}
|
|
|
|
static void
|
|
import_items(ICalImporterData *icidata)
|
|
{
|
|
ESource *source;
|
|
g_return_if_fail (icidata != NULL);
|
|
|
|
source = e_source_selector_peek_primary_selection ((ESourceSelector *)icidata->selector);
|
|
g_return_if_fail ( source != NULL);
|
|
|
|
icidata->client = auth_new_cal_from_source (source, icidata->source_type);
|
|
e_cal_open (icidata->client, FALSE, NULL);
|
|
|
|
switch (icidata->source_type) {
|
|
case E_CAL_SOURCE_TYPE_EVENT:
|
|
prepare_events (icidata->icalcomp, NULL);
|
|
if (!update_objects (icidata->client, icidata->icalcomp))
|
|
/* FIXME: e_error ... */;
|
|
break;
|
|
case E_CAL_SOURCE_TYPE_TODO:
|
|
prepare_tasks (icidata->icalcomp, NULL);
|
|
if (!update_objects (icidata->client, icidata->icalcomp))
|
|
/* FIXME: e_error ... */;
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
ical_import_done (icidata);
|
|
}
|
|
|
|
static gboolean
|
|
update_objects (ECal *client, icalcomponent *icalcomp)
|
|
{
|
|
icalcomponent_kind kind;
|
|
icalcomponent *vcal;
|
|
gboolean success = TRUE;
|
|
|
|
kind = icalcomponent_isa (icalcomp);
|
|
|
|
if (kind == ICAL_VTODO_COMPONENT || kind == ICAL_VEVENT_COMPONENT) {
|
|
vcal = e_cal_util_new_top_level ();
|
|
if (icalcomponent_get_method (icalcomp) == ICAL_METHOD_CANCEL)
|
|
icalcomponent_set_method (vcal, ICAL_METHOD_CANCEL);
|
|
else
|
|
icalcomponent_set_method (vcal, ICAL_METHOD_PUBLISH);
|
|
icalcomponent_add_component (vcal, icalcomponent_new_clone (icalcomp));
|
|
} else if (kind == ICAL_VCALENDAR_COMPONENT) {
|
|
vcal = icalcomponent_new_clone (icalcomp);
|
|
if (!icalcomponent_get_first_property (vcal, ICAL_METHOD_PROPERTY))
|
|
icalcomponent_set_method (vcal, ICAL_METHOD_PUBLISH);
|
|
} else
|
|
return FALSE;
|
|
|
|
if (!e_cal_receive_objects (client, vcal, NULL))
|
|
success = FALSE;
|
|
|
|
icalcomponent_free (vcal);
|
|
|
|
return success;
|
|
}
|
|
|
|
static void
|
|
ical_import_done(ICalImporterData *icidata)
|
|
{
|
|
g_object_unref (icidata->client);
|
|
icalcomponent_free (icidata->icalcomp);
|
|
g_free (icidata);
|
|
}
|
|
|
|
static icalcomponent *
|
|
get_icalcomponent_from_file(char *filename)
|
|
{
|
|
char *contents;
|
|
icalcomponent *icalcomp;
|
|
|
|
g_return_val_if_fail (filename != NULL, NULL);
|
|
|
|
if (!g_file_get_contents (filename, &contents, NULL, NULL)) {
|
|
g_free (filename);
|
|
return NULL;
|
|
}
|
|
g_free (filename);
|
|
|
|
icalcomp = e_cal_util_parse_ics_string (contents);
|
|
g_free (contents);
|
|
|
|
if (icalcomp) {
|
|
return icalcomp;
|
|
}
|
|
return NULL;
|
|
}
|