[Xfce4-commits] <orage:master> Added missing files.

Juha Kautto juha at xfce.org
Wed Sep 9 13:08:02 CEST 2009


Updating branch refs/heads/master
         to a3c5d30aa75ab587ff5406697bbc43b2e3af3d31 (commit)
       from 02d841558c61df4393c0da9c12584108caec5d28 (commit)

commit a3c5d30aa75ab587ff5406697bbc43b2e3af3d31
Author: Juha Kautto <juha at xfce.org>
Date:   Wed Sep 9 14:05:30 2009 +0300

    Added missing files.
    
    Forgot to add these.

 src/ical-archive.c |  538 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/ical-expimp.c  |  450 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 988 insertions(+), 0 deletions(-)

diff --git a/src/ical-archive.c b/src/ical-archive.c
new file mode 100644
index 0000000..3390247
--- /dev/null
+++ b/src/ical-archive.c
@@ -0,0 +1,538 @@
+/*      Orage - Calendar and alarm handler
+ *
+ * Copyright (c) 2005-2008 Juha Kautto  (juha at xfce.org)
+ * Copyright (c) 2003-2005 Mickael Graf (korbinus at xfce.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the 
+       Free Software Foundation
+       51 Franklin Street, 5th Floor
+       Boston, MA 02110-1301 USA
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <unistd.h>
+#include <time.h>
+#include <math.h>
+
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+#include <ical.h>
+#include <icalss.h>
+
+#include "orage-i18n.h"
+#include "functions.h"
+#include "mainbox.h"
+#include "reminder.h"
+#include "ical-code.h"
+#include "event-list.h"
+#include "appointment.h"
+#include "parameters.h"
+#include "interface.h"
+
+
+/*
+#define ORAGE_DEBUG 1
+*/
+
+
+
+/* this is in ical-code.c, too. ugly. should be in h file */
+typedef struct
+{
+    struct icaltimetype stime; /* start time */
+    struct icaltimetype etime; /* end time */
+    struct icaldurationtype duration;
+    struct icaltimetype ctime; /* completed time for VTODO appointmnets */
+    icalcomponent_kind ikind;  /* type of component, VEVENt, VTODO... */
+} xfical_period;
+
+/* in ical-code.c: */
+char *ic_get_char_timezone(icalproperty *p);
+struct icaltimetype ic_convert_to_timezone(struct icaltimetype t
+        , icalproperty *p);
+xfical_period ic_get_period(icalcomponent *c) ;
+gboolean ic_internal_file_open(icalcomponent **p_ical
+        , icalset **p_fical, gchar *file_icalpath, gboolean test);
+
+
+extern icalset *ic_fical;
+extern icalcomponent *ic_ical;
+#ifdef HAVE_ARCHIVE
+extern icalset *ic_afical;
+extern icalcomponent *ic_aical;
+#endif
+
+extern gboolean ic_file_modified; /* has any ical file been changed */
+
+
+#ifdef HAVE_ARCHIVE
+gboolean xfical_archive_open(void)
+{
+#undef P_N
+#define P_N "xfical_archive_open: "
+#ifdef ORAGE_DEBUG
+    orage_message(-100, P_N);
+#endif
+    if (!g_par.archive_limit)
+        return(FALSE);
+    if (!ORAGE_STR_EXISTS(g_par.archive_file))
+        return(FALSE);
+
+    return(ic_internal_file_open(&ic_aical, &ic_afical, g_par.archive_file
+            , FALSE));
+}
+#endif
+
+#ifdef HAVE_ARCHIVE
+void xfical_archive_close(void)
+{
+#undef  P_N 
+#define P_N "xfical_archive_close: "
+#ifdef ORAGE_DEBUG
+    orage_message(-100, P_N);
+#endif
+    if (!ORAGE_STR_EXISTS(g_par.archive_file))
+        return;
+
+    if (ic_afical == NULL)
+        orage_message(150, P_N "afical is NULL");
+    icalset_free(ic_afical);
+    ic_afical = NULL;
+}
+#endif
+
+static icalproperty *replace_repeating(icalcomponent *c, icalproperty *p
+        , icalproperty_kind k)
+{
+#undef P_N
+#define P_N "replace_repeating: "
+    icalproperty *s, *n;
+    const char *text;
+    const gint x_len = strlen("X-ORAGE-ORIG-");
+
+#ifdef ORAGE_DEBUG
+    orage_message(-300, P_N);
+#endif
+    text = g_strdup(icalproperty_as_ical_string(p));
+    n = icalproperty_new_from_string(text + x_len);
+    g_free((gchar *)text);
+    s = icalcomponent_get_first_property(c, k);
+    /* remove X-ORAGE-ORIG...*/
+    icalcomponent_remove_property(c, p);
+    /* remove old k (=either DTSTART or DTEND) */
+    icalcomponent_remove_property(c, s);
+    /* add new DTSTART or DTEND */
+    icalcomponent_add_property(c, n);
+    /* we need to start again from the first since we messed the order,
+     * but there are not so many X- propoerties that this is worth worring */
+    return(icalcomponent_get_first_property(c, ICAL_X_PROPERTY));
+}
+
+#ifdef HAVE_ARCHIVE
+static void xfical_icalcomponent_archive_normal(icalcomponent *e) 
+{
+#undef P_N
+#define P_N "xfical_icalcomponent_archive_normal: "
+    icalcomponent *d;
+
+#ifdef ORAGE_DEBUG
+    orage_message(-200, P_N);
+#endif
+    /* Add to the archive file */
+    d = icalcomponent_new_clone(e);
+    icalcomponent_add_component(ic_aical, d);
+
+    /* Remove from the main file */
+    icalcomponent_remove_component(ic_ical, e);
+}
+
+static void xfical_icalcomponent_archive_recurrent(icalcomponent *e
+        , struct tm *threshold, char *uid)
+{
+#undef P_N
+#define P_N "xfical_icalcomponent_archive_recurrent: "
+    struct icaltimetype sdate, edate, nsdate, nedate;
+    struct icalrecurrencetype rrule;
+    struct icaldurationtype duration;
+    icalrecur_iterator* ri;
+    gchar *stz_loc = NULL, *etz_loc = NULL;
+    const char *text;
+    char *text2;
+    icalproperty *p, *pdtstart, *pdtend;
+    icalproperty *p_orig, *p_origdtstart = NULL, *p_origdtend = NULL;
+    gboolean upd_edate = FALSE; 
+    gboolean has_orig_dtstart = FALSE, has_orig_dtend = FALSE;
+
+#ifdef ORAGE_DEBUG
+    orage_message(-200, P_N);
+#endif
+
+    /* We must not remove recurrent events, but just modify start- and
+     * enddates and actually only the date parts since time will stay.
+     * Note that we may need to remove limited recurrency events. We only
+     * add X-ORAGE-ORIG... dates if those are not there already.
+     */
+    sdate = icalcomponent_get_dtstart(e);
+    pdtstart = icalcomponent_get_first_property(e, ICAL_DTSTART_PROPERTY);
+    stz_loc = ic_get_char_timezone(pdtstart);
+    sdate = ic_convert_to_timezone(sdate, pdtstart);
+
+    edate = icalcomponent_get_dtend(e);
+    if (icaltime_is_null_time(edate)) {
+        edate = sdate;
+    }
+    pdtend = icalcomponent_get_first_property(e, ICAL_DTEND_PROPERTY);
+    if (pdtend) { /* we have DTEND, so we need to adjust it. */
+        etz_loc = ic_get_char_timezone(pdtend);
+        edate = ic_convert_to_timezone(edate, pdtend);
+        duration = icaltime_subtract(edate, sdate);
+        upd_edate = TRUE;
+    }
+    else { 
+        p = icalcomponent_get_first_property(e, ICAL_DURATION_PROPERTY);
+        if (p) /* we have DURATION, which does not need changes */
+            duration = icalproperty_get_duration(p);
+        else  /* neither duration, nor dtend, assume dtend=dtstart */
+            duration = icaltime_subtract(edate, sdate);
+    }
+    p_orig = icalcomponent_get_first_property(e, ICAL_X_PROPERTY);
+    while (p_orig) {
+        text = icalproperty_get_x_name(p_orig);
+        if (g_str_has_prefix(text, "X-ORAGE-ORIG-DTSTART")) {
+            if (has_orig_dtstart) {
+                /* This fixes bug which existed prior to 4.5.9.7: 
+                 * It was possible that multiple entries were generated. 
+                 * They are in order: oldest first. 
+                 * And we only need the oldest, so delete the rest */
+                orage_message(150, P_N "Corrupted X-ORAGE-ORIG-DTSTART setting. Fixing");
+                icalcomponent_remove_property(e, p_orig);
+                /* we need to start from scratch since counting may go wrong
+                 * bcause delete moves the pointer. */
+                has_orig_dtstart = FALSE;
+                has_orig_dtend = FALSE;
+                p_orig = icalcomponent_get_first_property(e, ICAL_X_PROPERTY);
+            }
+            else {
+                has_orig_dtstart = TRUE;
+                p_origdtstart = p_orig;
+                p_orig = icalcomponent_get_next_property(e, ICAL_X_PROPERTY);
+            }
+        }
+        else if (g_str_has_prefix(text, "X-ORAGE-ORIG-DTEND")) {
+            if (has_orig_dtend) {
+                orage_message(150, P_N "Corrupted X-ORAGE-ORIG-DTEND setting. Fixing");
+                icalcomponent_remove_property(e, p_orig);
+                has_orig_dtstart = FALSE;
+                has_orig_dtend = FALSE;
+                p_orig = icalcomponent_get_first_property(e, ICAL_X_PROPERTY);
+            }
+            else {
+                has_orig_dtend = TRUE;
+                p_origdtend = p_orig;
+                p_orig = icalcomponent_get_next_property(e, ICAL_X_PROPERTY);
+            }
+        }
+        else /* it was not our X-PROPERTY */
+            p_orig = icalcomponent_get_next_property(e, ICAL_X_PROPERTY);
+    }
+
+    p = icalcomponent_get_first_property(e, ICAL_RRULE_PROPERTY);
+    nsdate = icaltime_null_time();
+    rrule = icalproperty_get_rrule(p);
+    ri = icalrecur_iterator_new(rrule, sdate);
+
+    /* We must do a loop for finding the first occurence after the threshold */
+    for (nsdate = icalrecur_iterator_next(ri),
+            nedate = icaltime_add(nsdate, duration);
+         !icaltime_is_null_time(nsdate)
+         && (nedate.year*12 + nedate.month) 
+                < ((threshold->tm_year)*12 + threshold->tm_mon);
+         nsdate = icalrecur_iterator_next(ri),
+            nedate = icaltime_add(nsdate, duration)){
+    }
+    icalrecur_iterator_free(ri);
+
+    if (icaltime_is_null_time(nsdate)) { /* remove since it has ended */
+        orage_message(20, _("\tRecur ended, moving to archive file."));
+        if (has_orig_dtstart) 
+            replace_repeating(e, p_origdtstart, ICAL_DTSTART_PROPERTY);
+        if (has_orig_dtend) 
+            replace_repeating(e, p_origdtend, ICAL_DTEND_PROPERTY);
+        xfical_icalcomponent_archive_normal(e);
+    }
+    else { /* modify times*/
+        if (!has_orig_dtstart) {
+            text = g_strdup(icalproperty_as_ical_string(pdtstart));
+            text2 = g_strjoin(NULL, "X-ORAGE-ORIG-", text, NULL);
+            p = icalproperty_new_from_string(text2);
+            g_free((gchar *)text2);
+            g_free((gchar *)text);
+            icalcomponent_add_property(e, p);
+        }
+        icalcomponent_remove_property(e, pdtstart);
+        if (stz_loc == NULL)
+            icalcomponent_add_property(e, icalproperty_new_dtstart(nsdate));
+        else
+            icalcomponent_add_property(e
+                    , icalproperty_vanew_dtstart(nsdate
+                            , icalparameter_new_tzid(stz_loc)
+                            , 0));
+        if (upd_edate) {
+            if (!has_orig_dtend) {
+                text = g_strdup(icalproperty_as_ical_string(pdtend));
+                text2 = g_strjoin(NULL, "X-ORAGE-ORIG-", text, NULL);
+                p = icalproperty_new_from_string(text2);
+                g_free((gchar *)text2);
+                g_free((gchar *)text);
+                icalcomponent_add_property(e, p);
+            }
+            icalcomponent_remove_property(e, pdtend);
+            if (etz_loc == NULL)
+                icalcomponent_add_property(e, icalproperty_new_dtend(nedate));
+            else
+                icalcomponent_add_property(e
+                        , icalproperty_vanew_dtend(nedate
+                                , icalparameter_new_tzid(etz_loc)
+                                , 0));
+        }
+    }
+}
+
+gboolean xfical_archive(void)
+{
+#undef P_N
+#define P_N "xfical_archive: "
+    /*
+    struct icaltimetype sdate, edate;
+    */
+    xfical_period per;
+    icalcomponent *c, *c2;
+    icalproperty *p;
+    struct tm *threshold;
+    char *uid;
+
+#ifdef ORAGE_DEBUG
+    orage_message(-100, P_N);
+#endif
+    if (g_par.archive_limit == 0) {
+        orage_message(20, _("Archiving not enabled. Exiting"));
+        return(TRUE);
+    }
+    if (!xfical_file_open(FALSE) || !xfical_archive_open()) {
+        orage_message(250, P_N "file open error");
+        return(FALSE);
+    }
+    threshold = orage_localtime();
+    threshold->tm_mday = 1;
+    threshold->tm_year += 1900;
+    threshold->tm_mon += 1; /* convert from 0...11 to 1...12 */
+
+    threshold->tm_mon -= g_par.archive_limit;
+    if (threshold->tm_mon <= 0) {
+        threshold->tm_mon += 12;
+        threshold->tm_year--;
+    }
+
+    orage_message(20, _("Archiving threshold: %d month(s)")
+            , g_par.archive_limit);
+    /* yy mon day */
+    orage_message(20, _("\tArchiving events, which are older than: %04d-%02d-%02d")
+            , threshold->tm_year, threshold->tm_mon, threshold->tm_mday);
+
+    /* Check appointment file for items older than the threshold */
+    /* Note: remove moves the "c" pointer to next item, so we need to store it
+     *       first to process all of them or we end up skipping entries */
+    for (c = icalcomponent_get_first_component(ic_ical, ICAL_ANY_COMPONENT);
+         c != 0;
+         c = c2) {
+        c2 = icalcomponent_get_next_component(ic_ical, ICAL_ANY_COMPONENT);
+        /*
+        sdate = icalcomponent_get_dtstart(c);
+        edate = icalcomponent_get_dtend(c);
+        if (icaltime_is_null_time(edate)) {
+            edate = sdate;
+        }
+        */
+        per =  ic_get_period(c);
+        uid = (char *)icalcomponent_get_uid(c);
+        /* Items with endate before threshold => archived.
+         * Recurring events are marked in the main file by adding special
+         * X-ORAGE_ORIG-DTSTART/X-ORAGE_ORIG-DTEND to save the original
+         * start/end dates. Then start_date is changed. These are NOT
+         * written in archive file (unless of course they really have ended).
+         */
+        if ((per.etime.year*12 + per.etime.month) 
+            < (threshold->tm_year*12 + threshold->tm_mon)) {
+            orage_message(20, _("Archiving uid: %s"), uid);
+            /* FIXME: check VTODO completed before archiving it */
+            if (per.ikind == ICAL_VTODO_COMPONENT 
+                && ((per.ctime.year*12 + per.ctime.month) 
+                    < (per.stime.year*12 + per.stime.month))) {
+                /* VTODO not completed, do not archive */
+                orage_message(20, _("\tVTODO not complete; not archived"));
+            }
+            else {
+                p = icalcomponent_get_first_property(c, ICAL_RRULE_PROPERTY);
+                if (p) {  /*  it is recurrent event */
+                    orage_message(20, _("\tRecurring. End year: %04d, month: %02d, day: %02d")
+                        , per.etime.year, per.etime.month, per.etime.day);
+                    xfical_icalcomponent_archive_recurrent(c, threshold, uid);
+                }
+                else 
+                    xfical_icalcomponent_archive_normal(c);
+            }
+        }
+    }
+
+    ic_file_modified = TRUE;
+    icalset_mark(ic_afical);
+    icalset_commit(ic_afical);
+    xfical_archive_close();
+    icalset_mark(ic_fical);
+    icalset_commit(ic_fical);
+    xfical_file_close(FALSE);
+    orage_message(25, _("Archiving done\n"));
+    return(TRUE);
+}
+
+gboolean xfical_unarchive(void)
+{
+#undef P_N
+#define P_N "xfical_unarchive: "
+    icalcomponent *c, *d;
+    icalproperty *p;
+    const char *text;
+
+#ifdef ORAGE_DEBUG
+    orage_message(-100, P_N);
+#endif
+    /* PHASE 1: go through base orage file and remove "repeat" shortcuts */
+    orage_message(25, _("Starting archive removal."));
+    orage_message(20, _("\tPHASE 1: reset recurring appointments"));
+    if (!xfical_file_open(FALSE)) {
+        orage_message(250, P_N "file open error");
+        return(FALSE);
+    }
+
+    for (c = icalcomponent_get_first_component(ic_ical, ICAL_VEVENT_COMPONENT);
+         c != 0;
+         c = icalcomponent_get_next_component(ic_ical, ICAL_VEVENT_COMPONENT)) {
+         p = icalcomponent_get_first_property(c, ICAL_X_PROPERTY);
+         while (p) {
+            text = icalproperty_get_x_name(p);
+            if (g_str_has_prefix(text, "X-ORAGE-ORIG-DTSTART"))
+                p = replace_repeating(c, p, ICAL_DTSTART_PROPERTY);
+            else if (g_str_has_prefix(text, "X-ORAGE-ORIG-DTEND"))
+                p = replace_repeating(c, p, ICAL_DTEND_PROPERTY);
+            else /* it was not our X-PROPERTY */
+                p = icalcomponent_get_next_property(c, ICAL_X_PROPERTY);
+        }
+    }
+    /* PHASE 2: go through archive file and add everything back to base orage.
+     * After that delete the whole arch file */
+    orage_message(20, _("\tPHASE 2: return archived appointments"));
+    if (!xfical_archive_open()) {
+        /* we have risk to delete the data permanently, let's stop here */
+        orage_message(350, P_N "archive file open error");
+        /*
+        icalset_mark(ic_fical);
+        icalset_commit(ic_fical);
+        */
+        xfical_file_close(FALSE);
+        return(FALSE);
+    }
+    for (c = icalcomponent_get_first_component(ic_aical, ICAL_VEVENT_COMPONENT);
+         c != 0;
+         c = icalcomponent_get_next_component(ic_aical, ICAL_VEVENT_COMPONENT)) {
+    /* Add to the base file */
+        d = icalcomponent_new_clone(c);
+        icalcomponent_add_component(ic_ical, d);
+    }
+    xfical_archive_close();
+    if (g_remove(g_par.archive_file) == -1) {
+        orage_message(190, P_N "Failed to remove archive file %s", g_par.archive_file);
+    }
+    ic_file_modified = TRUE;
+    icalset_mark(ic_fical);
+    icalset_commit(ic_fical);
+    xfical_file_close(FALSE);
+    orage_message(25, _("Archive removal done\n"));
+    return(TRUE);
+}
+
+gboolean xfical_unarchive_uid(char *uid)
+{
+#undef P_N
+#define P_N "xfical_unarchive_uid: "
+    icalcomponent *c, *d;
+    gboolean key_found = FALSE;
+    const char *text;
+    char *ical_uid;
+
+#ifdef ORAGE_DEBUG
+    orage_message(-100, P_N);
+#endif
+    ical_uid = uid+4; /* skip file id (which is A00. now)*/
+    if (!xfical_file_open(FALSE) || !xfical_archive_open()) {
+        orage_message(250, P_N "file open error");
+        return(FALSE);
+    } 
+    for (c = icalcomponent_get_first_component(ic_aical, ICAL_ANY_COMPONENT);
+         c != 0 && !key_found;
+         c = icalcomponent_get_next_component(ic_aical, ICAL_ANY_COMPONENT)) {
+        text = icalcomponent_get_uid(c);
+        if (strcmp(text, ical_uid) == 0) { /* we found our uid (=event) */
+            /* Add to the base file */
+            d = icalcomponent_new_clone(c);
+            icalcomponent_add_component(ic_ical, d);
+            /* Remove from the archive file */
+            icalcomponent_remove_component(ic_aical, c);
+            key_found = TRUE;
+            ic_file_modified = TRUE;
+        }
+    }
+    icalset_mark(ic_afical);
+    icalset_commit(ic_afical);
+    xfical_archive_close();
+    icalset_mark(ic_fical);
+    icalset_commit(ic_fical);
+    xfical_file_close(FALSE);
+
+    return(TRUE);
+}
+#endif
diff --git a/src/ical-expimp.c b/src/ical-expimp.c
new file mode 100644
index 0000000..0705839
--- /dev/null
+++ b/src/ical-expimp.c
@@ -0,0 +1,450 @@
+/*      Orage - Calendar and alarm handler
+ *
+ * Copyright (c) 2005-2008 Juha Kautto  (juha at xfce.org)
+ * Copyright (c) 2003-2005 Mickael Graf (korbinus at xfce.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the 
+       Free Software Foundation
+       51 Franklin Street, 5th Floor
+       Boston, MA 02110-1301 USA
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <unistd.h>
+#include <time.h>
+#include <math.h>
+
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+#include <ical.h>
+#include <icalss.h>
+
+#include "orage-i18n.h"
+#include "functions.h"
+#include "mainbox.h"
+#include "reminder.h"
+#include "ical-code.h"
+#include "event-list.h"
+#include "appointment.h"
+#include "parameters.h"
+#include "interface.h"
+
+/*
+#define ORAGE_DEBUG 1
+*/
+
+
+
+/* in ical-code.c: */
+char *ic_generate_uid();
+
+extern icalset *ic_fical;
+extern icalcomponent *ic_ical;
+
+extern gboolean ic_file_modified; /* has any ical file been changed */
+
+typedef struct _foreign_ical_files
+{;
+    icalset *fical;
+    icalcomponent *ical;
+} ic_foreign_ical_files;
+
+extern ic_foreign_ical_files ic_f_ical[10];
+
+
+static gboolean add_event(icalcomponent *c)
+{
+#undef P_N
+#define P_N "add_event: "
+    icalcomponent *ca = NULL;
+    char *uid;
+
+#ifdef ORAGE_DEBUG
+    orage_message(-300, P_N);
+#endif
+    ca = icalcomponent_new_clone(c);
+    if ((uid = (char *)icalcomponent_get_uid(ca)) == NULL) {
+        uid = ic_generate_uid();
+        icalcomponent_add_property(ca,  icalproperty_new_uid(uid));
+        orage_message(15, "Generated UID %s", uid);
+        g_free(uid);
+
+    }
+    if (!xfical_file_open(FALSE)) {
+        orage_message(250, P_N "ical file open failed");
+        return(FALSE);
+    }
+    icalcomponent_add_component(ic_ical, ca);
+    ic_file_modified = TRUE;
+    icalset_mark(ic_fical);
+    icalset_commit(ic_fical);
+    xfical_file_close(FALSE);
+    return(TRUE);
+}
+
+/* pre process the file to rule out some features, which orage does not
+ * support so that we can do better conversion 
+ */
+static gboolean pre_format(char *file_name_in, char *file_name_out)
+{
+#undef P_N
+#define P_N "pre_format: "
+    gchar *text, *tmp, *tmp2, *tmp3;
+    gsize text_len;
+    GError *error = NULL;
+
+#ifdef ORAGE_DEBUG
+    orage_message(-200, P_N);
+#endif
+    orage_message(15, _("Starting import file preprocessing"));
+    if (!g_file_get_contents(file_name_in, &text, &text_len, &error)) {
+        orage_message(250, P_N "Could not open ical file (%s) error:%s"
+                , file_name_in, error->message);
+        g_error_free(error);
+        return(FALSE);
+    }
+    /***** Check utf8 coformtability *****/
+    if (!g_utf8_validate(text, -1, NULL)) {
+        orage_message(250, P_N "is not in utf8 format. Conversion needed.\n (Use iconv and convert it into UTF-8 and import it again.)\n");
+        return(FALSE);
+        /* we don't know the real characterset, so we can't convert
+        tmp = g_locale_to_utf8(text, -1, NULL, &cnt, NULL);
+        if (tmp) {
+            g_strlcpy(text, tmp, text_len);
+            g_free(tmp);
+        }*/
+    }
+
+    /***** 1: change DCREATED to CREATED *****/
+    for (tmp = g_strstr_len(text, text_len, "DCREATED:"); 
+         tmp != NULL;
+         tmp = g_strstr_len(tmp, strlen(tmp), "DCREATED:")) {
+        tmp2 = tmp+strlen("DCREATED:yyyymmddThhmmss");
+        if (*tmp2 == 'Z') {
+            /* it is already in UTC, so just fix the parameter name */
+            *tmp = ' ';
+        }
+        else {
+            /* needs to be converted to UTC also */
+            for (tmp3 = tmp; tmp3 < tmp2; tmp3++) {
+                *tmp3 = *(tmp3+1); 
+            }
+            *(tmp3-1) = 'Z'; /* this is 'bad'...but who cares...it is fast */
+        }
+        orage_message(15, _("... Patched DCREATED to be CREATED."));
+    }
+
+    /***** 2: change absolute timezones into libical format *****/
+    /* At least evolution uses absolute timezones.
+     * We assume format has /xxx/xxx/timezone and we should remove the
+     * extra /xxx/xxx/ from it */
+    for (tmp = g_strstr_len(text, text_len, ";TZID=/"); 
+         tmp != NULL;
+         tmp = g_strstr_len(tmp, strlen(tmp), ";TZID=/")) {
+        /* tmp = original TZID start
+         * tmp2 = end of line 
+         * tmp3 = current search and eventually the real tzid */
+        tmp = tmp+6; /* 6 = skip ";TZID=" */
+        if (!(tmp2 = g_strstr_len(tmp, 100, "\n"))) { /* no end of line */
+            orage_message(150, P_N "timezone patch failed 1. no end-of-line found: %s", tmp);
+            continue;
+        }
+        tmp3 = tmp;
+
+        tmp3++; /* skip '/' */
+        if (!(tmp3 = g_strstr_len(tmp3, tmp2-tmp3, "/"))) { /* no more '/' */
+            orage_message(150, P_N "timezone patch failed 2. no / found: %s", tmp);
+            continue;
+        }
+        tmp3++; /* skip '/' */
+        if (!(tmp3 = g_strstr_len(tmp3, tmp2-tmp3, "/"))) { /* no more '/' */
+            orage_message(150, P_N "timezone patch failed 3. no / found: %s", tmp);
+            continue;
+        }
+
+        /* we found the real tzid since we came here */
+        tmp3++; /* skip '/' */
+        /* move the real tzid (=tmp3) to the beginning (=tmp) */
+        for (; tmp3 < tmp2; tmp3++, tmp++)
+            *tmp = *tmp3;
+        /* fill the end of the line with spaces */
+        for (; tmp < tmp2; tmp++)
+            *tmp = ' ';
+        orage_message(15, _("... Patched timezone to Orage format."));
+    }
+
+    /***** All done: write file *****/
+    if (!g_file_set_contents(file_name_out, text, -1, NULL)) {
+        orage_message(250, P_N "Could not write ical file (%s)", file_name_out);
+        return(FALSE);
+    }
+    g_free(text);
+    orage_message(15, _("Import file preprocessing done"));
+    return(TRUE);
+}
+
+gboolean xfical_import_file(char *file_name)
+{
+#undef P_N
+#define P_N "xfical_import_file: "
+    icalset *file_ical = NULL;
+    char *ical_file_name = NULL;
+    icalcomponent *c1, *c2;
+    int cnt1 = 0, cnt2 = 0;
+
+#ifdef ORAGE_DEBUG
+    orage_message(-100, P_N);
+#endif
+    ical_file_name = g_strdup_printf("%s.orage", file_name);
+    if (!pre_format(file_name, ical_file_name)) {
+        return(FALSE);
+    }
+    if ((file_ical = icalset_new_file(ical_file_name)) == NULL) {
+        orage_message(250, P_N "Could not open ical file (%s) %s"
+                , ical_file_name, icalerror_strerror(icalerrno));
+        return(FALSE);
+    }
+    for (c1 = icalset_get_first_component(file_ical);
+         c1 != 0;
+         c1 = icalset_get_next_component(file_ical)) {
+        if (icalcomponent_isa(c1) == ICAL_VCALENDAR_COMPONENT) {
+            cnt1++;
+            for (c2=icalcomponent_get_first_component(c1, ICAL_ANY_COMPONENT);
+                 c2 != 0;
+                 c2=icalcomponent_get_next_component(c1, ICAL_ANY_COMPONENT)){
+                if ((icalcomponent_isa(c2) == ICAL_VEVENT_COMPONENT)
+                ||  (icalcomponent_isa(c2) == ICAL_VTODO_COMPONENT)
+                ||  (icalcomponent_isa(c2) == ICAL_VJOURNAL_COMPONENT)) {
+                    cnt2++;
+                    add_event(c2);
+                }
+                /* we ignore TIMEZONE component; Orage only uses internal
+                 * timezones from libical */
+                else if (icalcomponent_isa(c2) != ICAL_VTIMEZONE_COMPONENT)
+                    orage_message(140, P_N "unknown component %s %s"
+                            , icalcomponent_kind_to_string(
+                                    icalcomponent_isa(c2))
+                            , ical_file_name);
+            }
+
+        }
+        else
+            orage_message(140, P_N "unknown icalset component %s in %s"
+                    , icalcomponent_kind_to_string(icalcomponent_isa(c1))
+                    , ical_file_name);
+    }
+    if (cnt1 == 0) {
+        orage_message(150, P_N "No valid icalset components found");
+        return(FALSE);
+    }
+    if (cnt2 == 0) {
+        orage_message(150, P_N "No valid ical components found");
+        return(FALSE);
+    }
+
+    g_free(ical_file_name);
+    return(TRUE);
+}
+
+static gboolean export_prepare_write_file(char *file_name)
+{
+#undef P_N
+#define P_N "export_prepare_write_file: "
+    gchar *tmp;
+
+#ifdef ORAGE_DEBUG
+    orage_message(-200, P_N);
+#endif
+    if (strcmp(file_name, g_par.orage_file) == 0) {
+        orage_message(150, P_N "You do not want to overwrite Orage ical file! (%s)"
+                , file_name);
+        return(FALSE);
+    }
+    tmp = g_path_get_dirname(file_name);
+    if (g_mkdir_with_parents(tmp, 0755)) { /* octal */
+        orage_message(250, P_N "Could not create directories (%s)"
+                , file_name);
+        return(FALSE);
+    }
+    g_free(tmp);
+    if (g_remove(file_name) == -1) { /* note that it may not exist */
+        orage_message(150, P_N "Failed to remove export file %s", file_name);
+    }
+    return(TRUE);
+}
+
+static gboolean export_all(char *file_name)
+{
+#undef P_N
+#define P_N "export_all: "
+    gchar *text;
+    gsize text_len;
+
+#ifdef ORAGE_DEBUG
+    orage_message(-200, P_N);
+#endif
+    if (!export_prepare_write_file(file_name))
+        return(FALSE);
+    /* read Orage's ical file */
+    if (!g_file_get_contents(g_par.orage_file, &text, &text_len, NULL)) {
+        orage_message(250, P_N "Could not open Orage ical file (%s)"
+                , g_par.orage_file);
+        return(FALSE);
+    }
+    if (!g_file_set_contents(file_name, text, -1, NULL)) {
+        orage_message(150, P_N "Could not write file (%s)"
+                , file_name);
+        g_free(text);
+        return(FALSE);
+    }
+    g_free(text);
+    return(TRUE);
+}
+
+static void export_selected_uid(icalcomponent *base, gchar *uid_int
+        , icalcomponent *x_ical)
+{
+#undef P_N
+#define P_N "export_selected_uid: "
+    icalcomponent *c, *d;
+    gboolean key_found = FALSE;
+    gchar *uid_ical;
+
+#ifdef ORAGE_DEBUG
+    orage_message(-200, P_N);
+#endif
+    key_found = FALSE;
+    for (c = icalcomponent_get_first_component(base, ICAL_ANY_COMPONENT);
+         c != 0 && !key_found;
+         c = icalcomponent_get_next_component(base, ICAL_ANY_COMPONENT)) {
+        uid_ical = (char *)icalcomponent_get_uid(c);
+        if (strcmp(uid_int, uid_ical) == 0) { /* we found our uid */
+            d = icalcomponent_new_clone(c);
+            icalcomponent_add_component(x_ical, d);
+            key_found = TRUE;
+        }
+    }
+    if (!key_found)
+        orage_message(150, P_N "not found %s from Orage", uid_int);
+}
+
+static gboolean export_selected(char *file_name, char *uids)
+{
+#undef P_N
+#define P_N "export_selected: "
+    icalcomponent *x_ical = NULL;
+    icalset *x_fical = NULL;
+    gchar *uid, *uid_end, *uid_int;
+    gboolean more_uids;
+    int i;
+
+#ifdef ORAGE_DEBUG
+    orage_message(-200, P_N);
+#endif
+    if (!export_prepare_write_file(file_name))
+        return(FALSE);
+    if (!ORAGE_STR_EXISTS(uids)) {
+        orage_message(150, P_N "UID list is empty");
+        return(FALSE);
+    }
+    if (!ic_internal_file_open(&x_ical, &x_fical, file_name, FALSE)) {
+        orage_message(150, P_N "Failed to create export file %s"
+                , file_name);
+        return(FALSE);
+    }
+    if (!xfical_file_open(TRUE)) {
+        return(FALSE);
+    }
+
+    /* checks done, let's start the real work */
+    more_uids = TRUE;
+    for (uid = uids; more_uids; ) {
+        uid_int = uid+4;
+        uid_end = g_strstr_len((const gchar *)uid, strlen(uid), ",");
+        if (uid_end != NULL)
+            *uid_end = 0; /* uid ends here */
+        /* FIXME: proper messages to screen */
+        if (uid[0] == 'O') {
+            export_selected_uid(ic_ical, uid_int, x_ical);
+        }
+        else if (uid[0] == 'F') {
+            sscanf(uid, "F%02d", &i);
+            if (i < g_par.foreign_count && ic_f_ical[i].ical != NULL) {
+                export_selected_uid(ic_f_ical[i].ical, uid_int, x_ical);
+            }
+            else {
+                orage_message(250, P_N "unknown foreign file number %s", uid);
+                return(FALSE);
+            }
+
+        }
+        else {
+            orage_message(250, P_N "Unknown uid type %s", uid);
+        }
+        
+        if (uid_end != NULL)  /* we have more uids */
+            uid = uid_end+1;  /* next uid starts here */
+        else
+            more_uids = FALSE;
+    }
+
+    xfical_file_close(TRUE);
+    icalset_mark(x_fical);
+    icalset_commit(x_fical);
+    icalset_free(x_fical);
+    return(TRUE);
+}
+
+gboolean xfical_export_file(char *file_name, int type, char *uids)
+{
+#undef P_N
+#define P_N "xfical_export_file: "
+#ifdef ORAGE_DEBUG
+    orage_message(-100, P_N);
+#endif
+    if (type == 0) { /* copy the whole file */
+        return(export_all(file_name));
+    }
+    else if (type == 1) { /* copy only selected appointments */
+        return(export_selected(file_name, uids));
+    }
+    else {
+        orage_message(260, P_N "Unknown app count");
+        return(FALSE);
+    }
+}



More information about the Xfce4-commits mailing list