Exemplo n.º 1
0
/*
	ICALENDAR Reading functions
 */
GNOKII_API char *gn_calnote2icalstr(gn_calnote *calnote)
{
	ical_string str;

#ifdef HAVE_LIBICAL
	icalcomponent *pIcal = NULL, *vevent;
	struct icaltimetype stime = {0}, etime = {0};
	char compuid[64];

	memset(&str, 0, sizeof (str));

	/* In at least some Nokia phones it is possible to skip the year of
	   birth, in this case year == 0xffff, so we set it to the arbitrary
	   value of 1800 */

	stime.year = (calnote->time.year == 0xffff ? 1800 : calnote->time.year);
	stime.month = calnote->time.month;
	stime.day = calnote->time.day;
	stime.hour = calnote->time.hour;
	stime.minute = calnote->time.minute;
	stime.second = calnote->time.second;

	stime.is_daylight = 1;

	snprintf(compuid, sizeof(compuid), "guid.gnokii.org_%d_%d", calnote->location, rand());

	vevent = icalcomponent_vanew(ICAL_VEVENT_COMPONENT,
				     icalproperty_new_dtstart(stime),
				     icalproperty_new_uid(compuid),
				     icalproperty_new_categories("GNOKII"),
				     0);
	if (!vevent) {
		dprintf("ERROR in icalcomponent_vanew() creating VEVENT\n");
		return NULL;
	}

	if (calnote->end_time.year) {
		etime.year = (calnote->end_time.year == 0xffff ? 1800 : calnote->end_time.year);
		etime.month = calnote->end_time.month;
		etime.day = calnote->end_time.day;
		etime.hour = calnote->end_time.hour;
		etime.minute = calnote->end_time.minute;
		etime.second = calnote->end_time.second;
		etime.is_daylight = 1;

		icalcomponent_add_property(vevent, icalproperty_new_dtend(etime));
	}

	/* TODO: should the strings be configurable? */
	switch(calnote->type) {
	case GN_CALNOTE_MEMO:
		icalcomponent_add_property(vevent, icalproperty_new_categories("MISCELLANEOUS"));
		icalcomponent_add_property(vevent, icalproperty_new_summary(calnote->text));
		break;
	case GN_CALNOTE_REMINDER:
		icalcomponent_add_property(vevent, icalproperty_new_categories("REMINDER"));
		icalcomponent_add_property(vevent, icalproperty_new_summary(calnote->text));
		break;
	case GN_CALNOTE_CALL:
		icalcomponent_add_property(vevent, icalproperty_new_categories("PHONE CALL"));
		icalcomponent_add_property(vevent, icalproperty_new_summary(calnote->phone_number));
		icalcomponent_add_property(vevent, icalproperty_new_description(calnote->text));
		break;
	case GN_CALNOTE_MEETING:
		icalcomponent_add_property(vevent, icalproperty_new_categories("MEETING"));
		icalcomponent_add_property(vevent, icalproperty_new_summary(calnote->text));
		if (calnote->mlocation[0])
			icalcomponent_add_property(vevent, icalproperty_new_location(calnote->mlocation));
		break;
	case GN_CALNOTE_BIRTHDAY:
		icalcomponent_add_property(vevent, icalproperty_new_categories("ANNIVERSARY"));
		icalcomponent_add_property(vevent, icalproperty_new_summary(calnote->text));
		stime.is_date = 1;
		calnote->recurrence = GN_CALNOTE_YEARLY;
		break;
	default:
		icalcomponent_add_property(vevent, icalproperty_new_categories("UNKNOWN"));
		icalcomponent_add_property(vevent, icalproperty_new_summary(calnote->text));
		break;
	}

	if (calnote->recurrence) {
		char rrule[64];
		char *freq;
		int interval = 1;

		switch (calnote->recurrence) {
		case GN_CALNOTE_NEVER:
			goto norecurrence;
		case GN_CALNOTE_DAILY:
			freq = "DAILY";
			break;
		case GN_CALNOTE_WEEKLY:
			freq = "WEEKLY";
			break;
		case GN_CALNOTE_2WEEKLY:
			freq = "WEEKLY";
			interval = 2;
			break;
		case GN_CALNOTE_MONTHLY:
			freq = "MONTHLY";
			break;
		case GN_CALNOTE_YEARLY:
			freq = "YEARLY";
			break;
		default:
			freq = "HOURLY";
			interval = calnote->recurrence;
			break;
		}
		if (calnote->type == GN_CALNOTE_BIRTHDAY)
			snprintf(rrule, sizeof(rrule), "FREQ=YEARLY;INTERVAL=1;BYMONTH=%d", stime.month);
		else if (calnote->occurrences == 0)
			snprintf(rrule, sizeof(rrule), "FREQ=%s;INTERVAL=%d", freq, interval);
		else
			snprintf(rrule, sizeof(rrule), "FREQ=%s;COUNT=%d;INTERVAL=%d", freq, calnote->occurrences, interval);
		icalcomponent_add_property(vevent, icalproperty_new_rrule(icalrecurrencetype_from_string(rrule)));
	}
norecurrence:

	if (calnote->alarm.enabled) {
		icalcomponent *valarm;
		struct icaltriggertype trig;

		trig.time.year = (calnote->alarm.timestamp.year == 0xffff ? 1800 : calnote->alarm.timestamp.year);
		trig.time.month = calnote->alarm.timestamp.month;
		trig.time.day = calnote->alarm.timestamp.day;
		trig.time.hour = calnote->alarm.timestamp.hour;
		trig.time.minute = calnote->alarm.timestamp.minute;
		trig.time.second = calnote->alarm.timestamp.second;
		trig.time.is_daylight = 1;

		valarm = icalcomponent_new_valarm();

		icalcomponent_add_property(valarm, icalproperty_new_trigger(trig));
		/* FIXME: with ICAL_ACTION_DISPLAY a DESCRIPTION property is mandatory */
		icalcomponent_add_property(valarm, icalproperty_new_action(calnote->alarm.tone ? ICAL_ACTION_AUDIO : ICAL_ACTION_DISPLAY));

		icalcomponent_add_component(vevent, valarm);
	}

	pIcal = icalcomponent_vanew(ICAL_VCALENDAR_COMPONENT,
				    icalproperty_new_version("2.0"),
				    icalproperty_new_prodid(get_prodid()),
				    vevent,
				    0);

	if (pIcal) {
		char *icalstrbuf = NULL;
		const char *icalstr = icalcomponent_as_ical_string(pIcal);

		/* conversion to UTF-8 */
		if (string_base64(icalstr)) {
			int icalstrlen = strlen(icalstr);
			icalstrbuf = malloc(icalstrlen * 2 + 1);
			utf8_encode(icalstrbuf, icalstrlen * 2, icalstr, icalstrlen);

			icalstr = icalstrbuf;
		}
		ical_append_printf(&str, "%s\n", icalstr);
		dprintf("%s\n", icalstr);
		if (icalstrbuf)
			free(icalstrbuf);

		icalcomponent_free(pIcal);
		pIcal = NULL;
	} else {
		dprintf("ERROR in icalcomponent_vanew() creating VCALENDAR\n");
	}
	return str.str;
#else
	memset(&str, 0, sizeof (str));

	ical_append_printf(&str, "BEGIN:VCALENDAR\r\n");
	ical_append_printf(&str, "VERSION:1.0\r\n");
	ical_append_printf(&str, "BEGIN:VEVENT\r\n");
	ical_append_printf(&str, "CATEGORIES:");
	switch (calnote->type) {
	case GN_CALNOTE_MEMO:
		ical_append_printf(&str, "MISCELLANEOUS\r\n");
		break;
	case GN_CALNOTE_REMINDER:
		ical_append_printf(&str, "REMINDER\r\n");
		break;
	case GN_CALNOTE_CALL: 
		ical_append_printf(&str, "PHONE CALL\r\n");
		ical_append_printf(&str, "SUMMARY:%s\r\n", calnote->phone_number);
		ical_append_printf(&str, "DESCRIPTION:%s\r\n", calnote->text);
		break; 
	case GN_CALNOTE_MEETING: 
		ical_append_printf(&str, "MEETING\r\n"); 
		if (calnote->mlocation[0])
			ical_append_printf(&str, "LOCATION:%s\r\n", calnote->mlocation);
		break; 
	case GN_CALNOTE_BIRTHDAY: 
		ical_append_printf(&str, "SPECIAL OCCASION\r\n"); 
		break; 
	default: 
		ical_append_printf(&str, "UNKNOWN\r\n"); 
		break; 
	} 
	if (calnote->type != GN_CALNOTE_CALL)
		ical_append_printf(&str, "SUMMARY:%s\r\n", calnote->text);
	ical_append_printf(&str, "DTSTART:%04d%02d%02dT%02d%02d%02d\r\n", calnote->time.year,
		calnote->time.month, calnote->time.day, calnote->time.hour, 
		calnote->time.minute, calnote->time.second); 
	if (calnote->end_time.year) {
		ical_append_printf(&str, "DTEND:%04d%02d%02dT%02d%02d%02d\r\n", calnote->end_time.year, 
			calnote->end_time.month, calnote->end_time.day, calnote->end_time.hour, 
			calnote->end_time.minute, calnote->end_time.second); 
	}
	if (calnote->alarm.enabled) {
		ical_append_printf(&str, "%sALARM:%04d%02d%02dT%02d%02d%02d\r\n",
		(calnote->alarm.tone ? "A" : "D"),
		calnote->alarm.timestamp.year, 
		calnote->alarm.timestamp.month, calnote->alarm.timestamp.day, calnote->alarm.timestamp.hour, 
		calnote->alarm.timestamp.minute, calnote->alarm.timestamp.second); 
	} 
	switch (calnote->recurrence) { 
	case GN_CALNOTE_NEVER: 
		break; 
	case GN_CALNOTE_DAILY: 
		calnote->occurrences ?
			ical_append_printf(&str, "RRULE:FREQ=DAILY\r\n") :
			ical_append_printf(&str, "RRULE:FREQ=DAILY;COUNT=%d\r\n", calnote->occurrences);
		break; 
	case GN_CALNOTE_WEEKLY: 
		calnote->occurrences ?
			ical_append_printf(&str, "RRULE:FREQ=WEEKLY\r\n") :
			ical_append_printf(&str, "RRULE:FREQ=WEEKLY;COUNT=%d\r\n", calnote->occurrences);
		break; 
	case GN_CALNOTE_2WEEKLY: 
		calnote->occurrences ?
			ical_append_printf(&str, "RRULE:FREQ=WEEKLY;INTERVAL=2\r\n") :
			ical_append_printf(&str, "RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=%d\r\n", calnote->occurrences);
		break; 
	case GN_CALNOTE_MONTHLY: 
		calnote->occurrences ?
			ical_append_printf(&str, "RRULE:FREQ=MONTHLY\r\n") :
			ical_append_printf(&str, "RRULE:FREQ=MONTHLY;COUNT=%d\r\n", calnote->occurrences);
		break; 
	case GN_CALNOTE_YEARLY: 
		calnote->occurrences ?
			ical_append_printf(&str, "RRULE:FREQ=YEARLY\r\n") :
			ical_append_printf(&str, "RRULE:FREQ=YEARLY;COUNT=%d\r\n", calnote->occurrences);
		break; 
	default: 
		calnote->occurrences ?
			ical_append_printf(&str, "RRULE:FREQ=HOURLY;INTERVAL=%d\r\n", calnote->recurrence) :
			ical_append_printf(&str, "RRULE:FREQ=HOURLY;INTERVAL=%d;COUNT=%d\r\n", calnote->recurrence, calnote->occurrences);
		break; 
	} 
	ical_append_printf(&str, "END:VEVENT\r\n"); 
	ical_append_printf(&str, "END:VCALENDAR\r\n");
	return str.str;
#endif /* HAVE_LIBICAL */
}
Exemplo n.º 2
0
int main(int c, char *argv[]){

    icalset *clusterin, *clusterout = NULL;
    icalcomponent *itr;
    int count=0;
    int tostdout = 0;

    if(c < 2 || c > 3){
	usage(argv[0]);
	exit(1);
    }

    if (c == 2){
	tostdout = 1;
    }


    /*icalerror_set_error_state(ICAL_PARSE_ERROR, ICAL_ERROR_NONFATAL);*/

#ifdef SIGALRM
    signal(SIGALRM,sig_alrm);
    alarm(10);
#endif
    clusterin = icalfileset_new(argv[1]);
#ifdef SIGALRM
    alarm(0);
#endif
    if (clusterin == 0){
	printf("Could not open input cluster \"%s\"\n",argv[1]);
	if(icalerrno!= ICAL_NO_ERROR){
          printf("Error: %s\n",icalerror_strerror(icalerrno));
        }
	exit(1);
    }

    if (!tostdout){
#ifdef SIGALRM
        alarm(10);
#endif
	clusterout = icalfileset_new(argv[2]);
#ifdef SIGALRM
	alarm(0);
#endif
	if (clusterout == 0){
	    printf("Could not open output cluster \"%s\"\n",argv[2]);
	    exit(1);
	}
    }


    for (itr = icalset_get_first_component(clusterin);
	 itr != 0;
	 itr = icalset_get_next_component(clusterin)){

        icalerror_set_error_state(ICAL_BADARG_ERROR, ICAL_ERROR_NONFATAL);
	icalrestriction_check(itr);
        icalerror_set_error_state(ICAL_BADARG_ERROR, ICAL_ERROR_DEFAULT);

	if (itr != 0){

	    if(tostdout){

		printf("--------------\n%s\n",icalcomponent_as_ical_string(itr));

	    } else {

		icalfileset_add_component(clusterout,
					  icalcomponent_new_clone(itr));
	    }
	    
	    count++;

	} else {
	    printf("Got NULL component");
	}
    }


    printf("Transfered %d components\n",count);

    icalset_free(clusterin);

    if (!tostdout){
	icalfileset_mark(clusterout);
	icalset_free(clusterout);
    }

     return 0;
}
Exemplo n.º 3
0
int main()
{
    icalarray *timezones;
    icaltimezone *zone, *utc_zone;
    char *zone_location;
    size_t i;
    int ret = 0;
    unsigned int total_failed = 0;
    unsigned int total_okay = 0;
    unsigned int percent_failed = 0;
    int verbose = 0;

    int day;
    time_t start_time;
    struct tm start_tm;
    time_t curr_time;
    struct tm curr_tm;
    struct icaltimetype curr_tt;
    int failed = 0;
    int curr_failed;
    int zonedef_printed = 0;
#if !defined(HAVE_SETENV)
    static char new_tz[256];
#endif

    set_zone_directory("../../zoneinfo");
    icaltimezone_set_tzid_prefix("/softwarestudio.org/");

    timezones = icaltimezone_get_builtin_timezones();
    utc_zone = icaltimezone_get_utc_timezone();

    /* for all known time zones... */
    for (i = 0; i < timezones->num_elements; i++) {
        zone = (icaltimezone *)icalarray_element_at(timezones, i);
        zone_location = (char *)icaltimezone_get_location(zone);
        if (!zone_location)
            continue;

        /*
         * select this location for glibc: needs support for TZ=<location>
         * which is not POSIX
         */
#if defined(HAVE_SETENV)
        setenv("TZ", zone_location, 1);
#else
        new_tz[0] = '\0';
        strncat(new_tz, "TZ=", 255);
        strncat(new_tz, zone_location, 255 - strlen(new_tz));
        putenv(new_tz);
#endif
        tzset();
        /*
         * determine current local time and date: always use midday in
         * the current zone and first day of first month in the year
         */
        start_time = time(NULL);
        localtime_r(&start_time, &start_tm);
        start_tm.tm_hour = 12;
        start_tm.tm_min = 0;
        start_tm.tm_sec = 0;
        start_tm.tm_mday = 1;
        start_tm.tm_mon = 0;
        start_time = mktime(&start_tm);

        /* check time conversion for the next 365 days */
        for (day = 0, curr_time = start_time; day < 365; day++, curr_time += 24 * 60 * 60) {
            /* determine date/time with glibc */
            localtime_r(&curr_time, &curr_tm);
            /* determine date/time with libical */
            curr_tt = icaltime_from_timet_with_zone(curr_time, 0, utc_zone);
            curr_tt.zone = utc_zone;    /* workaround: icaltime_from_timet_with_zone()
                                           should do this, but doesn't! */
            curr_tt = icaltime_convert_to_zone(curr_tt, zone);

            /* compare... */
            curr_failed =
                curr_tm.tm_year + 1900 != curr_tt.year ||
                curr_tm.tm_mon + 1 != curr_tt.month ||
                curr_tm.tm_mday != curr_tt.day ||
                curr_tm.tm_hour != curr_tt.hour ||
                curr_tm.tm_min != curr_tt.minute ||
                curr_tm.tm_sec != curr_tt.second;

            /* only print first failed day and first day which is okay again */
            if (verbose || curr_failed != failed) {
                struct tm utc_tm;

                if (!gmtime_r(&curr_time, &utc_tm))
                    memset(&utc_tm, 0, sizeof(utc_tm));

                printf(
                    "%s: day %03d: %s: %04d-%02d-%02d %02d:%02d:%02d UTC = "
                    "libc %04d-%02d-%02d %02d:%02d:%02d dst %d",
                    zone_location, day,
                    verbose ? (curr_failed ? "failed" : "okay") : (curr_failed ? "first failed" :
                                                                   "okay again"),
                    utc_tm.tm_year + 1900, utc_tm.tm_mon + 1, utc_tm.tm_mday, utc_tm.tm_hour,
                    utc_tm.tm_min, utc_tm.tm_sec, curr_tm.tm_year + 1900, curr_tm.tm_mon + 1,
                    curr_tm.tm_mday, curr_tm.tm_hour, curr_tm.tm_min, curr_tm.tm_sec,
                    curr_tm.tm_isdst);
                if (curr_failed) {
                    printf(" != libical %04d-%02d-%02d %02d:%02d:%02d dst %d",
                        curr_tt.year,
                        curr_tt.month,
                        curr_tt.day,
                        curr_tt.hour,
                        curr_tt.minute,
                        curr_tt.second,
                        curr_tt.is_daylight);
                    ret = 1;
                }
                printf("\n");
                failed = curr_failed;

                if (!zonedef_printed) {
                    icalcomponent *comp = icaltimezone_get_component(zone);

                    if (comp) {
                        printf("%s\n", icalcomponent_as_ical_string(comp));
                    }
                    zonedef_printed = 1;
                }
            }

            if (curr_failed) {
                total_failed++;
            } else {
                total_okay++;
            }
        }
    }

    if (total_failed || total_okay) {
        percent_failed = total_failed * 100 / (total_failed + total_okay);
        printf(" *** Summary: %lu zones tested, %u days failed, %u okay => %u%% failed ***\n",
               (unsigned long)timezones->num_elements, total_failed, total_okay, percent_failed);

        if (!icaltzutil_get_exact_vtimezones_support()) {
            if (!percent_failed) {
                ret = 0;
                printf(" *** Expect some small error rate with inter-operable vtimezones *** \n");
            }
       }
    }

    icaltimezone_free_builtin_timezones();
    return ret;
}
Exemplo n.º 4
0
int main(int argc, char *argv[])
{
    FILE *f;
    int c;

#if !defined(HAVE_UNISTD_H)
    extern char *optarg;
    extern int optopt;
#endif
    int errflg = 0;
    char *program_name;

    struct options
    {
        int normal;
        int stress;
        int base64;
        int qp;
        int sleep;
        int count;
        char *input_file;
    } opt;

    memset(&opt, 0, sizeof(opt));

    program_name = (char *)strrchr((char *)argv[0], '/');
    program_name++;

    while ((c = getopt(argc, argv, "nsbqi:S:c:")) != -1) {
        switch (c) {
        case 'i':{
                /* Input comes from named file */
                opt.input_file = strdup(optarg);
                break;
            }
        case 'n':{
                /* Normal */

                if (opt.stress + opt.base64 + opt.qp != 0) {
                    fprintf(stderr, "%s: Use only one of  n,s,b and q\n", program_name);
                }
                opt.normal = 1;
                break;
            }
        case 's':{
                /* Stress-test */
                if (opt.base64 + opt.normal + opt.qp != 0) {
                    fprintf(stderr, "%s: Use only one of  n,s,b and q\n", program_name);
                }
                opt.stress = 1;
                break;
            }
        case 'b':{
                /* test base64 decoding */
                if (opt.stress + opt.normal + opt.qp != 0) {
                    fprintf(stderr, "%s: Use only one of  n,s,b and q\n", program_name);
                }
                opt.base64 = 1;
                break;
            }
        case 'q':{
                /* test quoted-printable decoding */
                if (opt.stress + opt.base64 + opt.normal != 0) {
                    fprintf(stderr, "%s: Use only one of  n,s,b and q\n", program_name);
                }
                opt.qp = 1;
                break;
            }
        case 'S':{
                /* sleep at end of run */
                opt.sleep = atoi(optarg);
                break;
            }

        case 'c':{
                /* number of iterations of stress test */
                opt.count = atoi(optarg);
                break;
            }

        case ':':{
                /* Option given without an operand */
                fprintf(stderr, "%s: Option -%c requires an operand\n", program_name, optopt);
                errflg++;
                break;
            }
        case '?':{
                errflg++;
            }
        }
    }

    if (errflg > 0) {
        fprintf(stderr, "Usage: %s [-n|-s|-b|-q] [-i input_file]\n", program_name);
        exit(1);
    }

    if (opt.stress + opt.base64 + opt.normal + opt.qp == 0) {
        fprintf(stderr, "%s: Must have one of n,s,b or q\n", program_name);
    }

    if (opt.input_file) {
        f = fopen(opt.input_file, "r");
        if (f == 0) {
            fprintf(stderr, "Could not open input file \"%s\"\n", opt.input_file);
            exit(1);
        }
    } else {
        f = stdin;
    }

    if (opt.normal == 1) {
        icalcomponent *c;

        c = icalmime_parse(read_stream, f);

        printf("%s\n", icalcomponent_as_ical_string(c));

        icalcomponent_free(c);

    } else if (opt.stress == 1) {
        /* Read file in by lines, then randomize the lines into a
           string buffer */

        char *array[1024];
        char temp[1024];
        char *buf;
        unsigned int i, j;
        unsigned int last, non_rand, rand_lines, r;
        size_t size;
        icalcomponent *c;
        struct slg_data
        {
            char *pos;
            char *str;
        } d;

        size = 0;
        for (i = 0; i < 1024 && !feof(f); ++i) {
            if (fgets(temp, 1024, f) != NULL) {
                array[i] = strdup(temp);
                size += strlen(temp);
            } else {
                break;
            }
        }
        last = i;

        assert(size > 0);
        buf = malloc(size * 2);
        assert(buf != 0);

        for (j = 0; j < (unsigned int)opt.count; j++) {

            srand(j);
            memset(buf, 0, size * 2);
            /* First insert some non-randomized lines */
            non_rand = (unsigned int)(((float)rand() / (float)RAND_MAX) * last);
            for (i = 0; i < last && i < non_rand; i++) {
                strcat(buf, array[i]);
            }

            /* Then, insert some lines at random */

            rand_lines = last - non_rand;

            for (i = 0; i < rand_lines; i++) {
                srand(i);
                r = (unsigned int)(((float)rand() / (float)RAND_MAX) * rand_lines);
                strcat(buf, array[r + non_rand]);
            }

            d.pos = 0;
            d.str = buf;

            c = icalmime_parse(icalparser_string_line_generator, &d);

            printf("%s\n", icalcomponent_as_ical_string(c));

            icalcomponent_free(c);
        }

        free(buf);

        for (i = 0; i < last; i++) {
            free(array[i]);
        }

    } else if (opt.qp == 1) {
        char str[4096];
        char conv[4096];

        memset(str, 0, 4096);

        while (!feof(f) && fgets(str, 4096, f) != 0) {
            size_t size;

            size = strlen(str);
            memset(conv, 0, 4096);
            (void)decode_quoted_printable(conv, str, &size);

            conv[size] = '\0';
            printf("%s", conv);
            memset(str, 0, 4096);
        }
    } else if (opt.base64 == 1) {
        char str[4096];
        char conv[4096];

        memset(str, 0, 4096);

        while (!feof(f) && fgets(str, 4096, f) != 0) {
            size_t size;

            size = strlen(str);
            memset(conv, 0, 4096);
            (void)decode_base64(conv, str, &size);

            conv[size] = '\0';
            printf("%s", conv);
            memset(str, 0, 4096);
        }
    }

    if (opt.sleep != 0) {
        sleep((unsigned int)opt.sleep);
    }

    if (opt.input_file != 0) {
        free(opt.input_file);
    }

    icalmemory_free_ring();

    return 0;
}
Exemplo n.º 5
0
void test_classify(void)
{
    icalcomponent *c, *match;
    int i = 0;
    int error_count = 0;

    /* Open up the two storage files, one for the incomming components,
       one for the calendar */
    icalfileset_options options = { O_RDONLY, 0644, 0, NULL };
    icalset *incoming = icalset_new(ICAL_FILE_SET, TEST_DATADIR "/incoming.ics", &options);
    icalset *cal = icalset_new(ICAL_FILE_SET, TEST_DATADIR "/calendar.ics", &options);
    icalset *f = icalset_new(ICAL_FILE_SET, TEST_DATADIR "/classify.ics", &options);

    ok("opening file classify.ics", (f != 0));
    ok("opening file calendar.ics", (cal != 0));
    ok("opening file incoming.ics", (incoming != 0));

    /* some basic tests.. */
    if (f) {
        c = icalset_get_first_component(f);
        match = icalset_get_next_component(f);

        ok("test two vcalendars for SEQUENCE with icalclassify()",
           (icalclassify(c, match, "*****@*****.**") == ICAL_XLICCLASS_REQUESTRESCHEDULE));

        icalset_free(f);
    }

    assert(incoming != 0);
    assert(cal != 0);

    /* Iterate through all of the incoming components */
    for (c = icalset_get_first_component(incoming); c != 0;
         c = icalset_get_next_component(incoming)) {

        icalproperty_xlicclass class;
        icalcomponent *match = 0;
        const char *this_uid;
        const char *this_note = get_note(c);
        const char *expected_result = get_expect(c);
        const char *actual_result;
        char msg[128];

        i++;

        /* Check this component against the restrictions imposed by
           iTIP. An errors will be inserted as X-LIC-ERROR properties
           in the component. The Parser will also insert errors if it
           cannot parse the component */
        icalcomponent_check_restrictions(c);

        /* If there are any errors, print out the component */

        error_count = icalcomponent_count_errors(c);
        snprintf(msg, sizeof(msg), "%s - parsing", this_note);
        int_is(msg, error_count, 0);

        if (error_count != 0) {
            if (VERBOSE) {
                printf("----- Component has errors ------- \n%s-----------------\n",
                       icalcomponent_as_ical_string(c));
            }
        }

        /* Use one of the icalcomponent convenience routines to get
           the UID. This routine will save you from having to use
           icalcomponent_get_inner(),
           icalcomponent_get_first_property(), checking the return
           value, and then calling icalproperty_get_uid. There are
           several other convenience routines for DTSTART, DTEND,
           DURATION, SUMMARY, METHOD, and COMMENT */
        this_uid = icalcomponent_get_uid(c);

        if (this_uid != 0) {
            /* Look in the calendar for a component with the same UID
               as the incomming component. We should reall also be
               checking the RECURRENCE-ID. Another way to do this
               operation is to us icalset_find_match(), which does use
               the RECURRENCE-ID. */
            match = icalset_fetch(cal, this_uid);
        }

        /* Classify the incoming component. The third argument is the
           calid of the user who owns the calendar. In a real program,
           you would probably switch() on the class. */
        class = icalclassify(c, match, "*****@*****.**");
        /** eventually test this too.. **/
        (void)get_note(match);
        actual_result = icalproperty_enum_to_string(class);
        snprintf(msg, sizeof(msg), "expecting %s", expected_result);
        str_is(msg, expected_result, actual_result);

        if (VERBOSE) {
            printf("Test %d\n"
                   "Incoming:      %s\n"
                   "Matched:       %s\n"
                   "Classification: %s\n\n",
            i, this_note, get_note(match), icalproperty_enum_to_string(class));
        }
    }

    icalset_free(incoming);
    icalset_free(cal);
}
/* Create a new component */
void create_new_component()
{
    icalcomponent* calendar;
    icalcomponent* timezone;
    icalcomponent* tzc;
    icalcomponent* event;
    struct icaltimetype atime = icaltime_from_timet( 1023398689, 0);
    struct icaldatetimeperiodtype rtime;
    icalproperty* property;
    char *calendar_as_string;

    rtime.period.start = icaltime_from_timet( 1023398689,0);
    rtime.period.end = icaltime_from_timet( 1023409689,0);
    rtime.period.end.hour++;
    rtime.time = icaltime_null_time();

    /* Create calendar and add properties */
    calendar = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);

    
    icalcomponent_add_property(
	calendar,
	icalproperty_new_version("2.0")
	);
    
    icalcomponent_add_property(
	calendar,
	icalproperty_new_prodid("-//RDU Software//NONSGML HandCal//EN")
	);
    
    /* Create a timezone object and add it to the calendar */

    timezone = icalcomponent_new(ICAL_VTIMEZONE_COMPONENT);

    icalcomponent_add_property(
	timezone,
	icalproperty_new_tzid("America/New_York")
	);

    /* Add a sub-component of the timezone */
    tzc = icalcomponent_new(ICAL_XDAYLIGHT_COMPONENT);

    icalcomponent_add_property(
	tzc, 
	icalproperty_new_dtstart(atime)
	);

    icalcomponent_add_property(
	tzc, 
	icalproperty_new_rdate(rtime)
	);
	    
    icalcomponent_add_property(
	tzc, 
	icalproperty_new_tzoffsetfrom(-5*3600)
	);

    icalcomponent_add_property(
	tzc, 
	icalproperty_new_tzoffsetto(-4*3600)
	);

    icalcomponent_add_property(
	tzc, 
	icalproperty_new_tzname("EST")
	);

    icalcomponent_add_component(timezone,tzc);

    icalcomponent_add_component(calendar,timezone);

    /* Add a second subcomponent */
    tzc = icalcomponent_new(ICAL_XSTANDARD_COMPONENT);

    icalcomponent_add_property(
	tzc, 
	icalproperty_new_dtstart(atime)
	);

    icalcomponent_add_property(
	tzc, 
	icalproperty_new_rdate(rtime)
	);
	    
    icalcomponent_add_property(
	tzc, 
	icalproperty_new_tzoffsetfrom(-4*3600)
	);

    icalcomponent_add_property(
	tzc, 
	icalproperty_new_tzoffsetto(-5*3600)
	);

    icalcomponent_add_property(
	tzc, 
	icalproperty_new_tzname("EST")
	);

    icalcomponent_add_component(timezone,tzc);

    /* Add an event */

    event = icalcomponent_new(ICAL_VEVENT_COMPONENT);

    icalcomponent_add_property(
	event,
	icalproperty_new_dtstamp(atime)
	);

    icalcomponent_add_property(
	event,
	icalproperty_new_uid("guid-1.host1.com")
	);

    /* add a property that has parameters */
    property = icalproperty_new_organizer("*****@*****.**");
    
    icalproperty_add_parameter(
	property,
	icalparameter_new_role(ICAL_ROLE_CHAIR)
	);

    icalcomponent_add_property(event,property);

    /* add another property that has parameters */
    property = icalproperty_new_attendee("*****@*****.**");
    
    icalproperty_add_parameter(
	property,
	icalparameter_new_role(ICAL_ROLE_REQPARTICIPANT)
	);

    icalproperty_add_parameter(
	property,
	icalparameter_new_rsvp(ICAL_RSVP_TRUE)
	);

    icalproperty_add_parameter(
	property,
	icalparameter_new_cutype(ICAL_CUTYPE_GROUP)
	);

    icalcomponent_add_property(event,property);


    /* more properties */

    icalcomponent_add_property(
	event,
	icalproperty_new_description("Project XYZ Review Meeting")
	);

    icalcomponent_add_property(
	event,
	icalproperty_new_categories("MEETING")
	);

    icalcomponent_add_property(
	event,
	icalproperty_new_class(ICAL_CLASS_PRIVATE)
	);
    
    icalcomponent_add_property(
	event,
	icalproperty_new_created(atime)
	);

    icalcomponent_add_property(
	event,
	icalproperty_new_summary("XYZ Project Review")
	);


    property = icalproperty_new_dtstart(atime);
    
    icalproperty_add_parameter(
	property,
	icalparameter_new_tzid("America/New_York")
	);

    icalcomponent_add_property(event,property);


    property = icalproperty_new_dtend(atime);
    
    icalproperty_add_parameter(
	property,
	icalparameter_new_tzid("America/New_York")
	);

    icalcomponent_add_property(event,property);

    icalcomponent_add_property(
	event,
	icalproperty_new_location("1CP Conference Room 4350")
	);

    icalcomponent_add_component(calendar,event);
    
    calendar_as_string = icalcomponent_as_ical_string(calendar);

    is("build large, complex component", 
       calendar_as_string,
       create_new_component_str);

    if (VERBOSE && calendar)
      printf("%s\n",icalcomponent_as_ical_string(calendar));


    if (calendar)
      icalcomponent_free(calendar);

}
void create_new_component_with_va_args()
{

    icalcomponent* calendar;
    struct icaltimetype atime = icaltime_from_timet( time(0),0);
    struct icaldatetimeperiodtype rtime;
    
    rtime.period.start = icaltime_from_timet( time(0),0);
    rtime.period.end = icaltime_from_timet( time(0),0);
    rtime.period.end.hour++;
    rtime.time = icaltime_null_time();

    calendar = 
	icalcomponent_vanew(
	    ICAL_VCALENDAR_COMPONENT,
	    icalproperty_new_version("2.0"),
	    icalproperty_new_prodid("-//RDU Software//NONSGML HandCal//EN"),
	    icalcomponent_vanew(
		ICAL_VTIMEZONE_COMPONENT,
		icalproperty_new_tzid("America/New_York"),
		icalcomponent_vanew(
		    ICAL_XDAYLIGHT_COMPONENT,
		    icalproperty_new_dtstart(atime),
		    icalproperty_new_rdate(rtime),
		    icalproperty_new_tzoffsetfrom(-4.0),
		    icalproperty_new_tzoffsetto(-5.0),
		    icalproperty_new_tzname("EST"),
		    NULL
		    ),
		icalcomponent_vanew(
		    ICAL_XSTANDARD_COMPONENT,
		    icalproperty_new_dtstart(atime),
		    icalproperty_new_rdate(rtime),
		    icalproperty_new_tzoffsetfrom(-5.0),
		    icalproperty_new_tzoffsetto(-4.0),
		    icalproperty_new_tzname("EST"),
		    NULL
		    ),
		NULL
		),
	    icalcomponent_vanew(
		ICAL_VEVENT_COMPONENT,
		icalproperty_new_dtstamp(atime),
		icalproperty_new_uid("guid-1.host1.com"),
		icalproperty_vanew_organizer(
		    "*****@*****.**",
		    icalparameter_new_role(ICAL_ROLE_CHAIR),
		    NULL
		    ),
		icalproperty_vanew_attendee(
		    "*****@*****.**",
		    icalparameter_new_role(ICAL_ROLE_REQPARTICIPANT),
		    icalparameter_new_rsvp(ICAL_RSVP_TRUE),
		    icalparameter_new_cutype(ICAL_CUTYPE_GROUP),
		    NULL
		    ),
		icalproperty_new_description("Project XYZ Review Meeting"),
		icalproperty_new_categories("MEETING"),
		icalproperty_new_class(ICAL_CLASS_PUBLIC),
		icalproperty_new_created(atime),
		icalproperty_new_summary("XYZ Project Review"),
		icalproperty_vanew_dtstart(
		    atime,
		    icalparameter_new_tzid("America/New_York"),
		    NULL
		    ),
		icalproperty_vanew_dtend(
		    atime,
		    icalparameter_new_tzid("America/New_York"),
		    NULL
		    ),
		icalproperty_new_location("1CP Conference Room 4350"),
		NULL
		),
	    NULL
	    );

    ok("creating a complex vcalendar", (calendar != NULL));
    if (VERBOSE && calendar)
      printf("%s\n",icalcomponent_as_ical_string(calendar));

    icalcomponent_free(calendar);

}
Exemplo n.º 8
0
/** Sync cache changes to the server and unmark them.
 *
 * @param cb 3E calendar backend.
 *
 * @return TRUE on success.
 *
 * @todo Conflict resolution.
 */
gboolean e_cal_backend_3e_sync_cache_to_server(ECalBackend3e *cb)
{
    GError *local_err = NULL;
    GSList *components, *iter;

    if (!e_cal_backend_3e_open_connection(cb, &local_err))
    {
        g_warning("Sync failed. Can't open connection to the 3e server. (%s)", local_err ? local_err->message : "Unknown error");
        g_clear_error(&local_err);
        return FALSE;
    }

    g_static_rw_lock_reader_lock(&cb->priv->cache_lock);
    components = e_cal_backend_store_get_components(cb->priv->store);
    g_static_rw_lock_reader_unlock(&cb->priv->cache_lock);

    for (iter = components; iter && !e_cal_backend_3e_sync_should_stop(cb); iter = iter->next)
    {
        ECalComponent *comp = E_CAL_COMPONENT(iter->data);
        ECalComponent *remote_comp;
        ECalComponentId *id = e_cal_component_get_id(comp);
        ECalComponentVType type = e_cal_component_get_vtype (comp);
        ECalComponentCacheState state = e_cal_component_get_cache_state(comp);

        /* remove client properties before sending component to the server */
        e_cal_component_set_outofsync (comp, FALSE);
        e_cal_component_set_cache_state(comp, E_CAL_COMPONENT_CACHE_STATE_NONE);

        remote_comp = e_cal_component_clone(comp);
        char *remote_object = e_cal_component_get_as_string(remote_comp);
        char *object = e_cal_component_get_as_string(comp);

        if (type == E_CAL_COMPONENT_EVENT && !e_cal_backend_3e_convert_attachment_uris_to_remote(cb, remote_comp))
            goto next;

        if (type == E_CAL_COMPONENT_EVENT && (state == E_CAL_COMPONENT_CACHE_STATE_CREATED || state == E_CAL_COMPONENT_CACHE_STATE_MODIFIED))
        {
            if (!e_cal_backend_3e_upload_attachments(cb, remote_comp, &local_err))
            {
                e_cal_backend_notify_gerror_error(E_CAL_BACKEND(cb), "3e attachemnts sync failure", local_err);
                g_clear_error(&local_err);
                goto next;
            }

            /* add timezone */
            const icaltimezone *zone = NULL;
            ECalComponentDateTime datetime;

            e_cal_component_get_dtstart (comp, &datetime);
            g_static_rw_lock_reader_lock (&cb->priv->cache_lock);
            zone = e_cal_backend_store_get_timezone (cb->priv->store, datetime.tzid);
            g_static_rw_lock_reader_unlock (&cb->priv->cache_lock);
            e_cal_component_free_datetime (&datetime);

            if (zone)
            {
                icalcomponent *zone_comp = icaltimezone_get_component (zone);
                char *object = icalcomponent_as_ical_string (zone_comp);

                ESClient_addObject (cb->priv->conn, cb->priv->calspec, object, &local_err);
                if (local_err)
                    g_clear_error (&local_err);
            }
        }

        switch (state)
        {
        case E_CAL_COMPONENT_CACHE_STATE_CREATED:
        {
            ESClient_addObject(cb->priv->conn, cb->priv->calspec, remote_object, &local_err);
            if (local_err)
            {
                e_cal_backend_notify_gerror_error(E_CAL_BACKEND(cb), "3e sync failure", local_err);
                g_clear_error(&local_err);
                break;
            }

            char *new_object = e_cal_component_get_as_string(comp);
            e_cal_backend_notify_object_modified(E_CAL_BACKEND(cb), object, new_object);
            g_free(new_object);

            g_static_rw_lock_writer_lock(&cb->priv->cache_lock);
            e_cal_backend_store_put_component(cb->priv->store, comp);
            g_static_rw_lock_writer_unlock(&cb->priv->cache_lock);
            break;
        }

        case E_CAL_COMPONENT_CACHE_STATE_MODIFIED:
        {
            ESClient_updateObject(cb->priv->conn, cb->priv->calspec, remote_object, &local_err);
            if (local_err)
            {
                e_cal_backend_notify_gerror_error(E_CAL_BACKEND(cb), "3e sync failure", local_err);
                g_clear_error(&local_err);
                break;
            }

            char *new_object = e_cal_component_get_as_string(comp);
            e_cal_backend_notify_object_modified(E_CAL_BACKEND(cb), object, new_object);
            g_free(new_object);

            g_static_rw_lock_writer_lock(&cb->priv->cache_lock);
            e_cal_backend_store_put_component(cb->priv->store, comp);
            g_static_rw_lock_writer_unlock(&cb->priv->cache_lock);
            break;
        }

        case E_CAL_COMPONENT_CACHE_STATE_REMOVED:
        {
            char *oid = id->rid ? g_strdup_printf("%s@%s", id->uid, id->rid) : g_strdup(id->uid);
            ESClient_deleteObject(cb->priv->conn, cb->priv->calspec, oid, &local_err);
            g_free(oid);
            if (local_err)
            {
                // ignore the error if component doesn't exist anymore
                if (local_err->code == ES_XMLRPC_ERROR_UNKNOWN_COMPONENT)
                {
                    g_clear_error(&local_err);
                    local_err = NULL;
                }
                else 
                {
                    e_cal_backend_notify_gerror_error(E_CAL_BACKEND(cb), "3e sync failure", local_err);
                    g_clear_error(&local_err);
                    break;
                }
            }

            g_static_rw_lock_writer_lock(&cb->priv->cache_lock);
            e_cal_backend_store_remove_component(cb->priv->store, id->uid, id->rid);
            g_static_rw_lock_writer_unlock(&cb->priv->cache_lock);
            break;
        }

        case E_CAL_COMPONENT_CACHE_STATE_NONE:
        default:
            break;
        }

next:
        g_object_unref(comp);
        g_object_unref(remote_comp);
        e_cal_component_free_id(id);
        g_free(object);
        g_free(remote_object);
    }

    g_slist_free(components);

    e_cal_backend_3e_close_connection(cb);

    return TRUE;
}
Exemplo n.º 9
0
int main(int argc, char *argv[])
{
    icalset *cin;
    struct icaltimetype next;
    icalcomponent *itr;
    icalproperty *desc, *dtstart, *rrule;
    struct icalrecurrencetype recur;
    icalrecur_iterator* ritr;
    time_t tt;
    char* file;

    icalerror_set_error_state(ICAL_PARSE_ERROR, ICAL_ERROR_NONFATAL);

#ifndef WIN32
    signal(SIGALRM,sig_alrm);
#endif

    if (argc <= 1) {
        file = "../../test-data/recur.txt";
    } else if (argc == 2) {
        file = argv[1];
    } else {
        fprintf(stderr,"usage: recur [input file]\n");
        exit(1);
    }

#ifndef WIN32
    alarm(300); /* to get file lock */
#endif
    cin = icalfileset_new(file);
#ifndef WIN32
    alarm(0);
#endif

    if(cin == 0) {
        fprintf(stderr,"recur: can't open file %s\n",file);
        exit(1);
    }


    for (itr = icalfileset_get_first_component(cin);
            itr != 0;
            itr = icalfileset_get_next_component(cin)) {

        struct icaltimetype start = icaltime_from_timet(1,0);
        struct icaltimetype end = icaltime_today();



        desc = icalcomponent_get_first_property(itr,ICAL_DESCRIPTION_PROPERTY);
        dtstart = icalcomponent_get_first_property(itr,ICAL_DTSTART_PROPERTY);
        rrule = icalcomponent_get_first_property(itr,ICAL_RRULE_PROPERTY);

        if (desc == 0 || dtstart == 0 || rrule == 0) {
            printf("\n******** Error in input component ********\n");
            printf("The following component is malformed:\n %s\n",
                   icalcomponent_as_ical_string(itr));
            continue;
        }

        printf("\n\n#### %s\n",icalproperty_get_description(desc));
        printf("#### %s\n",icalvalue_as_ical_string(icalproperty_get_value(rrule)));
        recur = icalproperty_get_rrule(rrule);
        start = icalproperty_get_dtstart(dtstart);

        ritr = icalrecur_iterator_new(recur,start);

        tt = icaltime_as_timet(start);

        printf("#### %s\n",ctime(&tt ));

        icalrecur_iterator_free(ritr);

        for(ritr = icalrecur_iterator_new(recur,start),
                next = icalrecur_iterator_next(ritr);
                !icaltime_is_null_time(next);
                next = icalrecur_iterator_next(ritr)) {

            tt = icaltime_as_timet(next);

            printf("  %s",ctime(&tt ));

        }
        icalrecur_iterator_free(ritr);

        icalcomponent_foreach_recurrence(itr, start, end,
                                         recur_callback, NULL);



    }

    icalset_free(cin);

    icaltimezone_free_builtin_timezones();

    icalmemory_free_ring();

    free_zone_directory();

    return 0;
}
/**
 * e_cal_check_timezones:
 * @comp:     a VCALENDAR containing a list of
 *            VTIMEZONE and arbitrary other components, in
 *            arbitrary order: these other components are
 *            modified by this call
 * @comps:    a list of icalcomponent instances which
 *            also have to be patched; may be NULL
 * @tzlookup: a callback function which is called to retrieve
 *            a calendar's VTIMEZONE definition; the returned
 *            definition is *not* freed by e_cal_check_timezones()
 *            (to be compatible with e_cal_get_timezone());
 *            NULL indicates that no such timezone exists
 *            or an error occurred
 * @custom:   an arbitrary pointer which is passed through to
 *            the tzlookup function
 * @error:    an error description in case of a failure
 *
 * This function cleans up VEVENT, VJOURNAL, VTODO and VTIMEZONE
 * items which are to be imported into Evolution.
 *
 * Using VTIMEZONE definitions is problematic because they cannot be
 * updated properly when timezone definitions change. They are also
 * incomplete (for compatibility reason only one set of rules for
 * summer saving changes can be included, even if different rules
 * apply in different years). This function looks for matches of the
 * used TZIDs against system timezones and replaces such TZIDs with
 * the corresponding system timezone. This works for TZIDs containing
 * a location (found via a fuzzy string search) and for Outlook TZIDs
 * (via a hard-coded lookup table).
 *
 * Some programs generate broken meeting invitations with TZID, but
 * without including the corresponding VTIMEZONE. Importing such
 * invitations unchanged causes problems later on (meeting displayed
 * incorrectly, #e_cal_get_component_as_string fails). The situation
 * where this occurred in the past (found by a SyncEvolution user) is
 * now handled via the location based mapping.
 *
 * If this mapping fails, this function also deals with VTIMEZONE
 * conflicts: such conflicts occur when the calendar already contains
 * an old VTIMEZONE definition with the same TZID, but different
 * summer saving rules. Replacing the VTIMEZONE potentially breaks
 * displaying of old events, whereas not replacing it breaks the new
 * events (the behavior in Evolution <= 2.22.1).
 *
 * The way this problem is resolved is by renaming the new VTIMEZONE
 * definition until the TZID is unique. A running count is appended to
 * the TZID. All items referencing the renamed TZID are adapted
 * accordingly.
 *
 * Return value: TRUE if successful, FALSE otherwise.
 */
gboolean e_cal_check_timezones(icalcomponent *comp,
                               GList *comps,
                               icaltimezone *(*tzlookup)(const char *tzid,
                                                         const void *custom,
                                                         GError **error),
                               const void *custom,
                               GError **error)
{
    gboolean success = TRUE;
    icalcomponent *subcomp = NULL;
    icaltimezone *zone = icaltimezone_new();
    char *key = NULL, *value = NULL;
    char *buffer = NULL;
    char *zonestr = NULL;
    char *tzid = NULL;
    GList *l;

    /** a hash from old to new tzid; strings dynamically allocated */
    GHashTable *mapping = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);

    /** a hash of all system time zone IDs which have to be added; strings are shared with mapping hash */
    GHashTable *systemtzids = g_hash_table_new(g_str_hash, g_str_equal);

    *error = NULL;

    if (!mapping || !zone) {
        goto nomem;
    }

    /* iterate over all VTIMEZONE definitions */
    subcomp = icalcomponent_get_first_component(comp,
                                                ICAL_VTIMEZONE_COMPONENT);
    while (subcomp) {
        if (icaltimezone_set_component(zone, subcomp)) {
            g_free(tzid);
            tzid = g_strdup(icaltimezone_get_tzid(zone));
            if (tzid) {
                const char *newtzid = e_cal_match_tzid(tzid);
                if (newtzid) {
                    /* matched against system time zone */
                    g_free(key);
                    key = g_strdup(tzid);
                    if (!key) {
                        goto nomem;
                    }

                    g_free(value);
                    value = g_strdup(newtzid);
                    if (!value) {
                        goto nomem;
                    }

                    g_hash_table_insert(mapping, key, value);
                    g_hash_table_insert(systemtzids, value, NULL);
                    key =
                        value = NULL;
                } else {
                    zonestr = ical_strdup(icalcomponent_as_ical_string(subcomp));

                    /* check for collisions with existing timezones */
                    int counter;
                    for (counter = 0;
                         counter < 100 /* sanity limit */;
                         counter++) {
                        icaltimezone *existing_zone;

                        if (counter) {
                            g_free(value);
                            value = g_strdup_printf("%s %d", tzid, counter);
                        }
                        existing_zone = tzlookup(counter ? value : tzid,
                                                 custom,
                                                 error);
                        if (!existing_zone) {
                            if (*error) {
                                goto failed;
                            } else {
                                break;
                            }
                        }
                        g_free(buffer);
                        buffer = ical_strdup(icalcomponent_as_ical_string(icaltimezone_get_component(existing_zone)));

                        if (counter) {
                            char *fulltzid = g_strdup_printf("TZID:%s", value);
                            size_t baselen = strlen("TZID:") + strlen(tzid);
                            size_t fulllen = strlen(fulltzid);
                            char *tzidprop;
                            /*
                             * Map TZID with counter suffix back to basename.
                             */
                            tzidprop = strstr(buffer, fulltzid);
                            if (tzidprop) {
                                memmove(tzidprop + baselen,
                                        tzidprop + fulllen,
                                        strlen(tzidprop + fulllen) + 1);
                            }
                            g_free(fulltzid);
                        }
                            

                        /*
                         * If the strings are identical, then the
                         * VTIMEZONE definitions are identical.  If
                         * they are not identical, then VTIMEZONE
                         * definitions might still be semantically
                         * correct and we waste some space by
                         * needlesly duplicating the VTIMEZONE. This
                         * is expected to occur rarely (if at all) in
                         * practice.
                         */
                        if (!strcmp(zonestr, buffer)) {
                            break;
                        }
                    }

                    if (!counter) {
                        /* does not exist, nothing to do */
                    } else {
                        /* timezone renamed */
                        icalproperty *prop = icalcomponent_get_first_property(subcomp,
                                                                              ICAL_TZID_PROPERTY);
                        while (prop) {
                            icalproperty_set_value_from_string(prop, value, "NO");
                            prop = icalcomponent_get_next_property(subcomp,
                                                                   ICAL_ANY_PROPERTY);
                        }
                        g_free(key);
                        key = g_strdup(tzid);
                        g_hash_table_insert(mapping, key, value);
                        key =
                            value = NULL;
                    }
                }
            }
        }

        subcomp = icalcomponent_get_next_component(comp,
                                                   ICAL_VTIMEZONE_COMPONENT);
    }

    /*
     * now replace all TZID parameters in place
     */
    subcomp = icalcomponent_get_first_component(comp,
                                                ICAL_ANY_COMPONENT);
    while (subcomp) {
        /*
         * Leave VTIMEZONE unchanged, iterate over properties of
         * everything else.
         *
         * Note that no attempt is made to remove unused VTIMEZONE
         * definitions. That would just make the code more complex for
         * little additional gain. However, newly used time zones are
         * added below.
         */
        patch_tzids (subcomp, mapping);
        subcomp = icalcomponent_get_next_component(comp,
                                                   ICAL_ANY_COMPONENT);
    }

    for (l = comps; l; l = l->next) {
        patch_tzids (l->data, mapping);
    }

    /*
     * add system time zones that we mapped to: adding them ensures
     * that the VCALENDAR remains consistent
     */
    g_hash_table_foreach(systemtzids, addsystemtz, comp);
    
    goto done;
 nomem:
    /* set gerror for "out of memory" if possible, otherwise abort via g_error() */
    *error = g_error_new(E_CALENDAR_ERROR, E_CALENDAR_STATUS_OTHER_ERROR, "out of memory");
    if (!*error) {
        g_error("e_cal_check_timezones(): out of memory, cannot proceed - sorry!");
    }
 failed:
    /* gerror should have been set already */
    success = FALSE;
 done:
    if (mapping) {
        g_hash_table_destroy(mapping);
    }
    if (systemtzids) {
        g_hash_table_destroy(systemtzids);
    }
    if (zone) {
        icaltimezone_free(zone, 1);
    }
    g_free(tzid);
    g_free(zonestr);
    g_free(buffer);
    g_free(key);
    g_free(value);
    
    return success;
}