Exemple #1
0
int main(int argc, char *argv[]) {
    struct icalrecurrencetype recur;
    icalrecur_iterator *ritr;
    struct icaltimetype dtstart, next;
    char *icr = "FREQ=WEEKLY;INTERVAL=2;COUNT=6;BYDAY=WE,SA,SU";
    char *dtstr = "20081217T133000";
    int howmany = 1;

    if (argc > 0) {
        icr = argv[1];
    }
    if (argc > 1) {
        howmany = atoi(argv[2]);
    }
    if (argc > 2) {
        dtstr = argv[3];
    }
        
    dtstart = icaltime_from_string(dtstr);
    recur = icalrecurrencetype_from_string(icr);
    ritr = icalrecur_iterator_new(recur, dtstart);

    printf("Using rule: %s\n", icr);
    printf("Iterating %d occurrences beginning from %s\n", howmany, dtstr);

    if (ritr) {
        while (howmany-- && !icaltime_is_null_time(next)) {
            next = icalrecur_iterator_next(ritr);
            printf("%s\n", icaltime_as_ical_string_r(next));
        }
    } else {
        printf("Error: %d\n", icalerrno);
    }
}
Exemple #2
0
/**
 * @brief
 * 	Get the occurrence as defined by the given recurrence rule,
 * 	index, and start time. This function assumes that the
 * 	time dtsart passed in is the one to start the occurrence from.
 *
 * @par	NOTE: This function should be made reentrant such that
 * 	it can be looped over without having to loop over every occurrence
 * 	over and over again.
 *
 * @param[in] rrule - The recurrence rule as defined by the user
 * @param[in] dtstart - The start time from which to start
 * @param[in] tz - The timezone associated to the recurrence rule
 * @param[in] idx - The index of the occurrence to start counting from
 *
 * @return 	time_t
 * @retval	The date of the next occurrence or -1 if the date exceeds libical's
 * 		Unix time in 2038
 *
 */
time_t
get_occurrence(char *rrule, time_t dtstart, char *tz, int idx)
{


#ifdef LIBICAL
	struct icalrecurrencetype rt;
	struct icaltimetype start;
	icaltimezone *localzone;
	struct icaltimetype next;
	struct icalrecur_iterator_impl *itr;
	int i;
	time_t next_occr = dtstart;

	if (rrule == NULL)
		return dtstart;

	if (tz == NULL)
		return -1;

	icalerror_clear_errno();

	icalerror_set_error_state(ICAL_PARSE_ERROR, ICAL_ERROR_NONFATAL);
#ifdef LIBICAL_API2
    icalerror_set_errors_are_fatal(0);
#else
    icalerror_errors_are_fatal = 0;
#endif
    localzone = icaltimezone_get_builtin_timezone(tz);

	if (localzone == NULL)
		return -1;

	rt = icalrecurrencetype_from_string(rrule);

	start = icaltime_from_timet_with_zone(dtstart, 0, NULL);
	icaltimezone_convert_time(&start, icaltimezone_get_utc_timezone(), localzone);
	next = start;

	itr = (struct icalrecur_iterator_impl*) icalrecur_iterator_new(rt, start);
	/* Skip as many occurrences as specified by idx */
	for (i = 0; i < idx && !icaltime_is_null_time(next); i++)
		next = icalrecur_iterator_next(itr);

	if (!icaltime_is_null_time(next)) {
		icaltimezone_convert_time(&next, localzone,
			icaltimezone_get_utc_timezone());
		next_occr = icaltime_as_timet(next);
	}
	else next_occr = -1; /* If reached end of possible date-time return -1 */

		icalrecur_iterator_free(itr);

	return next_occr;

#else

	return dtstart;
#endif
}
Exemple #3
0
/**
 * @brief
 * 	Returns the number of occurrences defined by a recurrence rule.
 *
 * @par	The total number of occurrences is currently limited to a hardcoded
 * 	3 years limit from the current date.
 *
 * @par	NOTE: Determine whether 3 years limit is the right way to go about setting
 * 	a limit on the total number of occurrences.
 *
 * @param[in] rrule - The recurrence rule as defined by the user
 * @param[in] tt - The start time of the first occurrence
 * @param[in] tz - The timezone associated to the recurrence rule
 *
 * @return	int
 * @retval 	the total number of occurrences
 *
 */
int
get_num_occurrences(char *rrule, time_t dtstart, char *tz)
{


#ifdef LIBICAL
	struct icalrecurrencetype rt;
	struct icaltimetype start;
	icaltimezone *localzone;
	struct icaltimetype next;
	struct icalrecur_iterator_impl *itr;
	time_t now;
	time_t date_limit;
	int num_resv = 0;

	/* if any of the argument is NULL, we are dealing with
	 * advance reservation, so return 1 occurrence */
	if (rrule == NULL || tz == NULL)
		return 1;

	icalerror_clear_errno();

	icalerror_set_error_state(ICAL_PARSE_ERROR, ICAL_ERROR_NONFATAL);
	icalerror_errors_are_fatal = 0;
	localzone = icaltimezone_get_builtin_timezone(tz);

	if (localzone == NULL)
		return 0;

	now = time((time_t *)0);
	date_limit = now + DATE_LIMIT;

	rt = icalrecurrencetype_from_string(rrule);

	start = icaltime_from_timet(dtstart, 0);
	icaltimezone_convert_time(&start, icaltimezone_get_utc_timezone(), localzone);

	itr = (struct icalrecur_iterator_impl*) icalrecur_iterator_new(rt, start);

	next = icalrecur_iterator_next(itr);

	/* Compute the total number of occurrences.
	 * Breaks out if the total number of allowed occurrences is exceeded */
	while (!icaltime_is_null_time(next) &&
		(icaltime_as_timet(next) < date_limit)) {
		num_resv++;
		next = icalrecur_iterator_next(itr);
	}
	icalrecur_iterator_free(itr);

	return num_resv;
#else

	if (rrule == NULL)
		return 1;

	return 0;
#endif
}
VALUE occurrences( VALUE self, VALUE dtstart, VALUE dtend, VALUE rrule ) {
  char * _rrule;
  struct icaltimetype start, end;
  time_t tt;
  VALUE  tv_sec, occurr = rb_ary_new();

  /* Get method ID for Time.tv_sec */
  ID time_tv_sec  = rb_intern( "tv_sec" );
  ID to_string    = rb_intern( "to_string" );

  if( TYPE( rrule ) != T_STRING && rb_respond_to( rrule, to_string ) )
    rrule = rb_funcall( rrule, to_string, 0 );

  Check_Type(rrule, T_STRING);
  _rrule = RSTRING(rrule)->ptr;

  dtstart = to_time( dtstart, "dtstart" );
  dtend   = to_time( dtend,   "dtend" );

  /* Apply .tv_sec to our Time objects (if they are Times ...) */
  tv_sec = rb_funcall( dtstart, time_tv_sec, 0 );
  tt     = NUM2INT( tv_sec );
  start  = icaltime_from_timet( tt, 0 );

  tv_sec = rb_funcall( dtend, time_tv_sec, 0 );
  tt     = NUM2INT( tv_sec );
  end    = icaltime_from_timet( tt, 0 );

  icalerror_clear_errno();
  icalerror_set_error_state( ICAL_MALFORMEDDATA_ERROR, ICAL_ERROR_NONFATAL);

  struct icalrecurrencetype recur = icalrecurrencetype_from_string( _rrule );
  if( icalerrno != ICAL_NO_ERROR ) {
    rb_raise(rb_eArgError, "Malformed RRule");
    return Qnil;
  }

  icalrecur_iterator* ritr = icalrecur_iterator_new( recur, start );

  while(1) {
    struct icaltimetype next = icalrecur_iterator_next(ritr);

    if( icaltime_is_null_time(next) || ( icaltime_compare( next, end ) > 0 ) ) {
      icalrecur_iterator_free(ritr);
      return occurr;
    }

    rb_ary_push( occurr, rb_time_new( icaltime_as_timet( next ), 0 ) );
  };

  icalrecur_iterator_free(ritr);
  return occurr;
}
int main()
{

	const char *rrule = "FREQ=DAILY;UNTIL=20080820T143500Z"; 
	icaltimetype dtstart = icaltime_from_timet(time(0) - (2*24*3600), 0);
	time_t viewend;

	struct icalrecurrencetype recur;
	time_t utc_tim;
	time_t dtst_utc;
	bool loopexit = false;

	recur = icalrecurrencetype_from_string(rrule);

	printf ("date is given by %d:%d:%d\n\n", dtstart.year, dtstart.month, dtstart.day);
	
	dtst_utc = icaltime_as_timet(dtstart);
	icalrecur_iterator *ritr;
	ritr = icalrecur_iterator_new(recur, dtstart);


	struct icaltimetype next;
	next = icalrecur_iterator_next(ritr);

	while ((!icaltime_is_null_time(next)) && (!loopexit)) {

		utc_tim = icaltime_as_timet(next);

		if (time (0) < utc_tim)
		{
			printf ("Recurrent time : %s\n", ctime(&utc_tim));
			loopexit = true;
		}

		next = icalrecur_iterator_next(ritr);
	}

	icalrecur_iterator_free(ritr);
}
Exemple #6
0
/*
 * Construct an iCalendar property value from XML content.
 */
static icalvalue *xml_element_to_icalvalue(xmlNodePtr xtype,
        icalvalue_kind kind)
{
    icalvalue *value = NULL;
    xmlNodePtr node;
    xmlChar *content = NULL;

    switch (kind) {

    case ICAL_GEO_VALUE: {
        struct icalgeotype geo;

        node = xmlFirstElementChild(xtype);
        if (!node) {
            syslog(LOG_WARNING, "Missing <latitude> XML element");
            break;
        }
        else if (xmlStrcmp(node->name, BAD_CAST "latitude")) {
            syslog(LOG_WARNING,
                   "Expected <latitude> XML element, received %s", node->name);
            break;
        }

        content = xmlNodeGetContent(node);
        geo.lat = atof((const char *) content);

        node = xmlNextElementSibling(node);
        if (!node) {
            syslog(LOG_WARNING, "Missing <longitude> XML element");
            break;
        }
        else if (xmlStrcmp(node->name, BAD_CAST "longitude")) {
            syslog(LOG_WARNING,
                   "Expected <longitude> XML element, received %s", node->name);
            break;
        }

        xmlFree(content);
        content = xmlNodeGetContent(node);
        geo.lon = atof((const char *) content);

        value = icalvalue_new_geo(geo);

        break;
    }

    case ICAL_PERIOD_VALUE: {
        struct icalperiodtype p;

        p.start = p.end = icaltime_null_time();
        p.duration = icaldurationtype_from_int(0);

        node = xmlFirstElementChild(xtype);
        if (!node) {
            syslog(LOG_WARNING, "Missing <start> XML element");
            break;
        }
        else if (xmlStrcmp(node->name, BAD_CAST "start")) {
            syslog(LOG_WARNING,
                   "Expected <start> XML element, received %s", node->name);
            break;
        }

        content = xmlNodeGetContent(node);
        p.start = icaltime_from_string((const char *) content);
        if (icaltime_is_null_time(p.start)) break;

        node = xmlNextElementSibling(node);
        if (!node) {
            syslog(LOG_WARNING, "Missing <end> / <duration> XML element");
            break;
        }
        else if (!xmlStrcmp(node->name, BAD_CAST "end")) {
            xmlFree(content);
            content = xmlNodeGetContent(node);
            p.end = icaltime_from_string((const char *) content);
            if (icaltime_is_null_time(p.end)) break;
        }
        else if (!xmlStrcmp(node->name, BAD_CAST "duration")) {
            xmlFree(content);
            content = xmlNodeGetContent(node);
            p.duration = icaldurationtype_from_string((const char *) content);
            if (icaldurationtype_as_int(p.duration) == 0) break;
        }
        else {
            syslog(LOG_WARNING,
                   "Expected <end> / <duration> XML element, received %s",
                   node->name);
            break;
        }

        value = icalvalue_new_period(p);

        break;
    }

    case ICAL_RECUR_VALUE: {
        struct buf rrule = BUF_INITIALIZER;
        struct hash_table byrules;
        struct icalrecurrencetype rt;
        char *sep = "";

        construct_hash_table(&byrules, 10, 1);

        /* create an iCal RRULE string from xCal <recur> sub-elements */
        for (node = xmlFirstElementChild(xtype); node;
                node = xmlNextElementSibling(node)) {

            content = xmlNodeGetContent(node);
            if (!xmlStrncmp(node->name, BAD_CAST "by", 2)) {
                /* BY* rules can have a list of values -
                   assemble them using a hash table */
                struct buf *vals =
                    hash_lookup((const char *) node->name, &byrules);

                if (vals) {
                    /* append this value to existing list */
                    buf_printf(vals, ",%s", (char *) content);
                }
                else {
                    /* create new list with this valiue */
                    vals = xzmalloc(sizeof(struct buf));
                    buf_setcstr(vals, (char *) content);
                    hash_insert((char *) node->name, vals, &byrules);
                }
            }
            else {
                /* single value rpart */
                buf_printf(&rrule, "%s%s=%s", sep,
                           ucase((char *) node->name), (char *) content);
                sep = ";";
            }

            xmlFree(content);
            content = NULL;
        }

        /* append the BY* rules to RRULE buffer */
        hash_enumerate(&byrules,
                       (void (*)(const char*, void*, void*)) &append_byrule,
                       &rrule);
        free_hash_table(&byrules, NULL);

        /* parse our iCal RRULE string */
        rt = icalrecurrencetype_from_string(buf_cstring(&rrule));
        buf_free(&rrule);

        if (rt.freq != ICAL_NO_RECURRENCE) value = icalvalue_new_recur(rt);

        break;
    }

    case ICAL_REQUESTSTATUS_VALUE: {
        struct icalreqstattype rst = { ICAL_UNKNOWN_STATUS, NULL, NULL };
        short maj, min;

        node = xmlFirstElementChild(xtype);
        if (!node) {
            syslog(LOG_WARNING, "Missing <code> XML element");
            break;
        }
        else if (xmlStrcmp(node->name, BAD_CAST "code")) {
            syslog(LOG_WARNING,
                   "Expected <code> XML element, received %s", node->name);
            break;
        }

        content = xmlNodeGetContent(node);
        if (sscanf((const char *) content, "%hd.%hd", &maj, &min) == 2) {
            rst.code = icalenum_num_to_reqstat(maj, min);
        }
        if (rst.code == ICAL_UNKNOWN_STATUS) {
            syslog(LOG_WARNING, "Unknown request-status code");
            break;
        }

        node = xmlNextElementSibling(node);
        if (!node) {
            syslog(LOG_WARNING, "Missing <description> XML element");
            break;
        }
        else if (xmlStrcmp(node->name, BAD_CAST "description")) {
            syslog(LOG_WARNING,
                   "Expected <description> XML element, received %s",
                   node->name);
            break;
        }

        xmlFree(content);
        content = xmlNodeGetContent(node);
        rst.desc = (const char *) content;

        node = xmlNextElementSibling(node);
        if (node) {
            if (xmlStrcmp(node->name, BAD_CAST "data")) {
                syslog(LOG_WARNING,
                       "Expected <data> XML element, received %s", node->name);
                break;
            }

            xmlFree(content);
            content = xmlNodeGetContent(node);
            rst.debug = (const char *) content;
        }

        value = icalvalue_new_requeststatus(rst);
        break;
    }

    case ICAL_UTCOFFSET_VALUE: {
        int n, utcoffset, hours, minutes, seconds = 0;
        char sign;

        content = xmlNodeGetContent(xtype);
        n = sscanf((const char *) content, "%c%02d:%02d:%02d",
                   &sign, &hours, &minutes, &seconds);

        if (n < 3) {
            syslog(LOG_WARNING, "Unexpected utc-offset format");
            break;
        }

        utcoffset = hours*3600 + minutes*60 + seconds;

        if (sign == '-') utcoffset = -utcoffset;

        value = icalvalue_new_utcoffset(utcoffset);
        break;
    }

    default:
        content = xmlNodeGetContent(xtype);
        value = icalvalue_new_from_string(kind, (const char *) content);
        break;
    }

    if (content) xmlFree(content);

    return value;
}
Exemple #7
0
/*
 * Construct an iCalendar property value from a JSON object.
 */
static icalvalue *json_object_to_icalvalue(json_t *jvalue,
                                           icalvalue_kind kind)
{
    icalvalue *value = NULL;
    int len, i;

    switch (kind) {
    case ICAL_BOOLEAN_VALUE:
        if (json_is_boolean(jvalue))
            value = icalvalue_new_integer(json_is_true(jvalue));
        else
            syslog(LOG_WARNING, "jCal boolean object expected");
        break;

    case ICAL_FLOAT_VALUE:
        if (json_is_real(jvalue))
            value = icalvalue_new_float((float) json_real_value(jvalue));
        else
            syslog(LOG_WARNING, "jCal double object expected");
        break;

    case ICAL_GEO_VALUE:
        /* MUST be an array of 2 doubles */
        if (json_is_array(jvalue) && (len = json_array_size(jvalue)) != 2) {

            for (i = 0;
                 i < len && json_is_real(json_array_get(jvalue, i));
                 i++);
            if (i == len) {
                struct icalgeotype geo;

                geo.lat =
                    json_real_value(json_array_get(jvalue, 0));
                geo.lon =
                    json_real_value(json_array_get(jvalue, 1));

                value = icalvalue_new_geo(geo);
            }
        }
        if (!value)
            syslog(LOG_WARNING, "jCal array object of 2 doubles expected");
        break;

    case ICAL_INTEGER_VALUE:
        if (json_is_integer(jvalue))
            value = icalvalue_new_integer((int) json_integer_value(jvalue));
        else if (json_is_string(jvalue))
            value = icalvalue_new_integer(atoi(json_string_value(jvalue)));
        else
            syslog(LOG_WARNING, "jCal integer object expected");
        break;

    case ICAL_RECUR_VALUE:
        if (json_is_object(jvalue)) {
            struct buf rrule = BUF_INITIALIZER;
            struct icalrecurrencetype rt;
            const char *key, *sep = "";
            json_t *val;

            /* create an iCal RRULE string from jCal 'recur' object */
            json_object_foreach(jvalue, key, val) {
                char *mykey = xstrdup(key);
                buf_printf(&rrule, "%s%s=", sep, ucase(mykey));
                buf_appendjson(&rrule, val);
                sep = ";";
                free(mykey);
            }

            /* parse our iCal RRULE string */
            rt = icalrecurrencetype_from_string(buf_cstring(&rrule));
            buf_free(&rrule);

            if (rt.freq != ICAL_NO_RECURRENCE) value = icalvalue_new_recur(rt);
        }
        else
Exemple #8
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 */
}
Exemple #9
0
/**
 * @brief
 * 	Check if a recurrence rule is valid and consistent.
 * 	The recurrence rule is verified against a start date and checks
 * 	that the frequency of the recurrence matches the duration of the
 * 	submitted reservation. If the duration of a reservation exceeds the
 * 	granularity of the frequency then an error message is displayed.
 *
 * @par The recurrence rule is checked to contain a COUNT or an UNTIL.
 *
 * @par	Note that the PBS_TZID environment variable HAS to be set for the occurrence's
 * 	dates to be correctly computed.
 *  
 * @param[in] rrule - The recurrence rule to unroll
 * @param[in] dtstart - The start time associated to the reservation (1st occurrence)
 * @param[in] dtend - The end time associated to the reservation (1st occurrence)
 * @param[in] duration - The duration of an occurrence. This is used when a reservation is
 *  			submitted using the -D (duration) param instead of an end time
 * @param[in] tz - The timezone associated to the recurrence rule
 * @param[in] err_code - A pointer to the error code to return. Codes are defined in pbs_error.h
 *
 * @return	int
 * @retval	The total number of occurrences that the recurrence rule and start date
 * 
 * 		define. 1 for an advance reservation.
 *
 */
int
check_rrule(char *rrule, time_t dtstart, time_t dtend, char *tz, int *err_code)
{


#ifdef LIBICAL  /* Standing Reservation Recurrence */
	int count = 1;
	struct icalrecurrencetype rt;
	struct icaltimetype start;
	struct icaltimetype next;
	struct icaltimetype first;
	struct icaltimetype prev;
	struct icalrecur_iterator_impl *itr;
	icaltimezone *localzone;
	int time_err = 0;
	int i;
	long min_occr_duration = -1;
	long tmp_occr_duration = 0;
	long duration;

	*err_code = 0;
	icalerror_clear_errno();

	icalerror_set_error_state(ICAL_PARSE_ERROR, ICAL_ERROR_NONFATAL);
	icalerror_errors_are_fatal = 0;

	if (tz == NULL || rrule == NULL)
		return 0;

	localzone = icaltimezone_get_builtin_timezone(tz);
	/* If the timezone info directory is not accessible
	 * then bail
	 */
	if (localzone == NULL) {
		*err_code = PBSE_BAD_ICAL_TZ;
		return 0;
	}

	rt = icalrecurrencetype_from_string(rrule);

	/* Check if by_day rules are defined and valid
	 * the first item in the array of by_* rule
	 * determines whether the item exists or not.
	 */
	for (i = 0; rt.by_day[i] < 8; i++) {
		if (rt.by_day[i] <= 0) {
			*err_code = PBSE_BAD_RRULE_SYNTAX;
			return 0;
		}
	}

	/* Check if by_hour rules are defined and valid
	 * the first item in the array of by_* rule
	 * determines whether the item exists or not.
	 */
	for (i = 0; rt.by_hour[i] < 25; i++) {
		if (rt.by_hour[i] < 0) {
			*err_code = PBSE_BAD_RRULE_SYNTAX;
			return 0;
		}
	}

	/* Check if the rest of the by_* rules are defined
	 * and valid.
	 * currently no support for
	 * BYMONTHDAY, BYYEARDAY, BYSECOND,
	 * BYMINUTE, BYWEEKNO, or BYSETPOS
	 *
	 */
	if (rt.by_second[0] < 61 || /* by_second is negative such as in -10 */
		rt.by_minute[0] < 61 ||  /* by_minute is negative such as in -10 */
		rt.by_year_day[0] < 367 || /* a year day is defined */
		rt.by_month_day[0] < 31 || /* a month day is defined */
		rt.by_week_no[0] < 52 ||  /* a week number is defined */
		rt.by_set_pos[0] < 367) { /* a set pos is defined */
		*err_code = PBSE_BAD_RRULE_SYNTAX;
		return 0;
	}


	/* Require that either a COUNT or UNTIL be passed. But not both. */
	if ((rt.count == 0 && icaltime_is_null_time(rt.until)) ||
		(rt.count != 0 && !icaltime_is_null_time(rt.until))) {
		*err_code = PBSE_BAD_RRULE_SYNTAX2; /* Undefined iCalendar synax. A valid COUNT or UNTIL is required */
		return 0;
	}

	start = icaltime_from_timet(dtstart, 0);
	icaltimezone_convert_time(&start, icaltimezone_get_utc_timezone(), localzone);

	itr = (struct icalrecur_iterator_impl*) icalrecur_iterator_new(rt, start);

	duration = dtend -dtstart;

	/* First check if the syntax of the iCalendar rule is valid */
	next = icalrecur_iterator_next(itr);

	/* Catch case where first occurrence date is in the past */
	if (icaltime_is_null_time(next)) {
		*err_code = PBSE_BADTSPEC;
		icalrecur_iterator_free(itr);
		return 0;
	}

	first = next;
	prev = first;

	for (next=icalrecur_iterator_next(itr); !icaltime_is_null_time(next); next=icalrecur_iterator_next(itr), count++) {
		/* The interval duration between two occurrences
		 * is the time between the end of an occurrence and the
		 * start of the next one
		 */
		tmp_occr_duration = icaltime_as_timet(next) - icaltime_as_timet(prev);

		/* Set the minimum time interval between occurrences */
		if (min_occr_duration == -1)
			min_occr_duration = tmp_occr_duration;
		else if (tmp_occr_duration > 0 &&
			tmp_occr_duration < min_occr_duration)
			min_occr_duration = tmp_occr_duration;

		prev = next;
	}
	/* clean up */
	icalrecur_iterator_free(itr);

	if (icalerrno != ICAL_NO_ERROR) {
		*err_code = PBSE_BAD_RRULE_SYNTAX; /*  Undefined iCalendar syntax */
		return 0;
	}

	/* Then check if the duration fits in the frequency rule */
	switch (rt.freq) {

		case ICAL_SECONDLY_RECURRENCE:
			{
				if (duration > 1) {
#ifdef NAS /* localmod 005 */
					icalerrno = ICAL_BADARG_ERROR;
#else
					icalerrno = 1;
#endif /* localmod 005 */
					*err_code = PBSE_BAD_RRULE_SECONDLY; /* SECONDLY recurrence duration cannot exceed 1 second */
					time_err++;
				}
				break;
			}
		case ICAL_MINUTELY_RECURRENCE:
			{
				if (duration > 60) {
#ifdef NAS /* localmod 005 */
					icalerrno = ICAL_BADARG_ERROR;
#else
					icalerrno = 1;
#endif /* localmod 005 */
					*err_code = PBSE_BAD_RRULE_MINUTELY; /* MINUTELY recurrence duration cannot exceed 1 minute */
					time_err++;
				}
				break;
			}
		case ICAL_HOURLY_RECURRENCE:
			{
				if (duration > (60*60)) {
#ifdef NAS /* localmod 005 */
					icalerrno = ICAL_BADARG_ERROR;
#else
					icalerrno =1;
#endif /* localmod 005 */
					*err_code = PBSE_BAD_RRULE_HOURLY; /* HOURLY recurrence duration cannot exceed 1 hour */
					time_err++;
				}
				break;
			}
		case ICAL_DAILY_RECURRENCE:
			{
				if (duration > (60*60*24)) {
#ifdef NAS /* localmod 005 */
					icalerrno = ICAL_BADARG_ERROR;
#else
					icalerrno = 1;
#endif /* localmod 005 */
					*err_code = PBSE_BAD_RRULE_DAILY; /* DAILY recurrence duration cannot exceed 24 hours */
					time_err++;
				}
				break;
			}
		case ICAL_WEEKLY_RECURRENCE:
			{
				if (duration > (60*60*24*7)) {
#ifdef NAS /* localmod 005 */
					icalerrno = ICAL_BADARG_ERROR;
#else
					icalerrno = 1;
#endif /* localmod 005 */
					*err_code = PBSE_BAD_RRULE_WEEKLY; /* WEEKLY recurrence duration cannot exceed 1 week */
					time_err++;
				}
				break;
			}
		case ICAL_MONTHLY_RECURRENCE:
			{
				if (duration > (60*60*24*30)) {
#ifdef NAS /* localmod 005 */
					icalerrno = ICAL_BADARG_ERROR;
#else
					icalerrno = 1;
#endif /* localmod 005 */
					*err_code = PBSE_BAD_RRULE_MONTHLY; /* MONTHLY recurrence duration cannot exceed 1 month */
					time_err++;
				}
				break;
			}
		case ICAL_YEARLY_RECURRENCE:
			{
				if (duration > (60*60*24*30*365)) {
#ifdef NAS /* localmod 005 */
					icalerrno = ICAL_BADARG_ERROR;
#else
					icalerrno = 1;
#endif /* localmod 005 */
					*err_code = PBSE_BAD_RRULE_YEARLY; /* YEARLY recurrence duration cannot exceed 1 year */
					time_err++;
				}
				break;
			}
		default:
			{
				icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
				return 0;
			}
	}

	if (time_err)
		return 0;

	/* If the requested reservation duration exceeds
	 * the occurrence's duration then print an error
	 * message and return */
	if (count != 1 && duration > min_occr_duration) {
		*err_code = PBSE_BADTSPEC; /*  Bad Time Specification(s) */
		return 0;
	}

	return count;

#else

	*err_code = PBSE_BAD_RRULE_SYNTAX; /* iCalendar is undefined */
	return 0;
#endif
}