Example #1
0
static void
dates_date_change (DatesData *data, int direction)
{
    icaltimetype *time, *oldtime;
	
    oldtime = (icaltimetype *)dates_view_get_date (data->view);
    time = g_new (icaltimetype, 1);
    g_memmove (time, oldtime, sizeof (icaltimetype));

    if (data->zoom == 16)
	time->year += direction;
    else if (data->zoom >= 11) {
	int days;
	time->month += direction;
	if (time->month > 12) {
	    time->month = 1;
	    time->year++;
	} else if (time->month < 1) {
	    time->month = 12;
	    time->year--;
	}
	days = icaltime_days_in_month (time->month, time->year);
	if (time->day > days) time->day = days;
    } else if (data->zoom >= 8)
	icaltime_adjust (time, direction * 7, 0, 0, 0);
    else
	icaltime_adjust (time, direction, 0, 0, 0);
	
    if (time->year < 1900)
        goto out;
    dates_view_set_date (data->view, time);
	
out:    g_free (time);
}
Example #2
0
/**
 * calendar_config_get_hide_completed_tasks_sexp:
 *
 * @get_completed: Whether to form subexpression that
 * gets completed or not completed tasks.
 * Returns the subexpression to use to filter out completed tasks according
 * to the config settings. The returned sexp should be freed.
 **/
char*
calendar_config_get_hide_completed_tasks_sexp (gboolean get_completed)
{
	char *sexp = NULL;

	if (calendar_config_get_hide_completed_tasks ()) {
		CalUnits units;
		gint value;

		units = calendar_config_get_hide_completed_tasks_units ();
		value = calendar_config_get_hide_completed_tasks_value ();

		if (value == 0) {
			/* If the value is 0, we want to hide completed tasks
			   immediately, so we filter out all complete/incomplete tasks.*/
			if (!get_completed)
				sexp = g_strdup ("(not is-completed?)");
			else
				sexp = g_strdup ("(is-completed?)");
		} else {
			char *isodate;
			icaltimezone *zone;
			struct icaltimetype tt;
			time_t t;

			/* Get the current time, and subtract the appropriate
			   number of days/hours/minutes. */
			zone = calendar_config_get_icaltimezone ();
			tt = icaltime_current_time_with_zone (zone);

			switch (units) {
			case CAL_DAYS:
				icaltime_adjust (&tt, -value, 0, 0, 0);
				break;
			case CAL_HOURS:
				icaltime_adjust (&tt, 0, -value, 0, 0);
				break;
			case CAL_MINUTES:
				icaltime_adjust (&tt, 0, 0, -value, 0);
				break;
			default:
				g_return_val_if_reached (NULL);
			}

			t = icaltime_as_timet_with_zone (tt, zone);

			/* Convert the time to an ISO date string, and build
			   the query sub-expression. */
			isodate = isodate_from_time_t (t);
			if (!get_completed)
				sexp = g_strdup_printf ("(not (completed-before? (make-time \"%s\")))", isodate);
			else
				sexp = g_strdup_printf ("(completed-before? (make-time \"%s\"))", isodate);
			g_free (isodate);
		}
	}

	return sexp;
}
static gboolean
execute_search (GcalShellSearchProvider *search_provider)
{
  GcalShellSearchProviderPrivate *priv;

  guint i;
  gchar *search_query;

  icaltimezone *zone;
  time_t range_start, range_end;

  priv = search_provider->priv;

  if (!gcal_manager_load_completed (priv->manager))
    return TRUE;

  zone = gcal_manager_get_system_timezone (priv->manager);
  priv->pending_search->date = icaltime_current_time_with_zone (zone);
  icaltime_adjust (&(priv->pending_search->date), -7, 0, 0, 0); /* -1 weeks from today */
  range_start = icaltime_as_timet_with_zone (priv->pending_search->date, zone);

  icaltime_adjust (&(priv->pending_search->date), 21 * 2, 0, 0, 0); /* +3 weeks from today */
  range_end = icaltime_as_timet_with_zone (priv->pending_search->date, zone);

  gcal_manager_set_shell_search_subscriber (priv->manager, E_CAL_DATA_MODEL_SUBSCRIBER (search_provider),
                                            range_start, range_end);

  search_query = g_strdup_printf ("(or (contains? \"summary\" \"%s\") (contains? \"description\" \"%s\"))",
                                  priv->pending_search->terms[0], priv->pending_search->terms[0]);
  for (i = 1; i < g_strv_length (priv->pending_search->terms); i++)
    {
      gchar *complete_query;
      gchar *second_query = g_strdup_printf ("(or (contains? \"summary\" \"%s\") (contains? \"description\" \"%s\"))",
                                             priv->pending_search->terms[0], priv->pending_search->terms[0]);
      complete_query = g_strdup_printf ("(and %s %s)", search_query, second_query);

      g_free (second_query);
      g_free (search_query);

      search_query = complete_query;
    }

  gcal_manager_set_shell_search_query (priv->manager,  search_query);
  g_free (search_query);

  priv->scheduled_search_id = 0;
  g_application_hold (g_application_get_default ());
  return FALSE;
}
Example #4
0
/**
 * e_cal_util_construct_instance:
 * @icalcomp: A recurring #icalcomponent
 * @rid: The RECURRENCE-ID to construct a component for
 *
 * This checks that @rid indicates a valid recurrence of @icalcomp, and
 * if so, generates a copy of @comp containing a RECURRENCE-ID of @rid.
 *
 * Returns: the instance, or %NULL.
 **/
icalcomponent *
e_cal_util_construct_instance (icalcomponent *icalcomp,
                               struct icaltimetype rid)
{
	struct instance_data instance;
	struct icaltimetype start, end;

	g_return_val_if_fail (icalcomp != NULL, NULL);

	/* Make sure this is really recurring */
	if (!icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY) &&
	    !icalcomponent_get_first_property (icalcomp, ICAL_RDATE_PROPERTY))
		return NULL;

	/* Make sure the specified instance really exists */
	start = icaltime_convert_to_zone (rid, icaltimezone_get_utc_timezone ());
	end = start;
	icaltime_adjust (&end, 0, 0, 0, 1);

	instance.start = icaltime_as_timet (start);
	instance.found = FALSE;
	icalcomponent_foreach_recurrence (icalcomp, start, end,
					  check_instance, &instance);
	if (!instance.found)
		return NULL;

	/* Make the instance */
	icalcomp = icalcomponent_new_clone (icalcomp);
	icalcomponent_set_recurrenceid (icalcomp, rid);

	return icalcomp;
}
Example #5
0
/**
 *      Reset all of the time components to be in their normal ranges. For
 *      instance, given a time with minutes=70, the minutes will be reduces
 *      to 10, and the hour incremented. This allows the caller to do
 *      arithmetic on times without worrying about overflow or
 *      underflow.
 *
 *      Implementation note: we call icaltime_adjust() with no adjustment.
 */
struct icaltimetype icaltime_normalize(const struct icaltimetype tt)
{
    struct icaltimetype ret = tt;

    icaltime_adjust(&ret, 0, 0, 0, 0);
    return ret;
}
/**
 * time_add_day_with_zone:
 * @time: A time_t value.
 * @days: Number of days to add.
 * @zone: Timezone to use.
 *
 * Adds or subtracts a number of days to/from the given time_t value, using
 * the given timezone.
 * NOTE: this function is only here to make the transition to the timezone
 * functions easier. New code should use icaltimetype values and
 * icaltime_adjust() to add or subtract days, hours, minutes & seconds.
 *
 * Return value: a time_t value containing @time plus the days added.
 */
time_t
time_add_day_with_zone (time_t time, int days, icaltimezone *zone)
{
	struct icaltimetype tt;

	/* Convert to an icaltimetype. */
	tt = icaltime_from_timet_with_zone (time, FALSE, zone);

	/* Add/subtract the number of days. */
	icaltime_adjust (&tt, days, 0, 0, 0);

	/* Convert back to a time_t. */
	return icaltime_as_timet_with_zone (tt, zone);
}
void
icaltimezone_convert_time		(struct icaltimetype *tt,
					 icaltimezone	*from_zone,
					 icaltimezone	*to_zone)
{
    int utc_offset, is_daylight;

    /* If the time is a DATE value or both timezones are the same, or we are
       converting a floating time, we don't need to do anything. */
    if (icaltime_is_date(*tt) || from_zone == to_zone || from_zone == NULL)
	return;

    /* Convert the time to UTC by getting the UTC offset and subtracting it. */
    utc_offset = icaltimezone_get_utc_offset (from_zone, tt, NULL);
    icaltime_adjust (tt, 0, 0, 0, -utc_offset);

    /* Now we convert the time to the new timezone by getting the UTC offset
       of our UTC time and adding it. */       
    utc_offset = icaltimezone_get_utc_offset_of_utc_time (to_zone, tt,
							  &is_daylight);
    tt->is_daylight = is_daylight;
    icaltime_adjust (tt, 0, 0, 0, utc_offset);
}
Example #8
0
NS_IMETHODIMP
calDateTime::GetEndOfWeek(calIDateTime ** aResult)
{
    NS_ENSURE_ARG_POINTER(aResult);

    icaltimetype icalt;
    ToIcalTime(&icalt);
    int day_of_week = icaltime_day_of_week(icalt);
    if (day_of_week < 7)
        icaltime_adjust(&icalt, 7 - day_of_week, 0, 0, 0);
    icalt.is_date = 1;

    calDateTime * const cdt = new calDateTime(&icalt, mTimezone);
    CAL_ENSURE_MEMORY(cdt);
    NS_ADDREF(*aResult = cdt);
    return NS_OK;
}
Example #9
0
/**
 * e_cal_util_split_at_instance:
 * @icalcomp: A (recurring) #icalcomponent
 * @rid: The base RECURRENCE-ID to remove
 * @master_dtstart: The DTSTART of the master object
 *
 * Splits a recurring @icalcomp into two at time @rid. The returned icalcomponent
 * is modified @icalcomp which contains recurrences beginning at @rid, inclusive.
 * The instance identified by @rid should exist. The @master_dtstart can be
 * a null time, then it is read from the @icalcomp.
 *
 * Use e_cal_util_remove_instances() with E_CAL_OBJ_MOD_THIS_AND_FUTURE mode
 * on the @icalcomp to remove the overlapping interval from it, if needed.
 *
 * Returns: the split icalcomponent, or %NULL.
 *
 * Since: 3.16
 **/
icalcomponent *
e_cal_util_split_at_instance (icalcomponent *icalcomp,
			      struct icaltimetype rid,
			      struct icaltimetype master_dtstart)
{
	icalproperty *prop;
	struct instance_data instance;
	struct icaltimetype start, end;
	struct icaldurationtype duration;
	GSList *remove_props = NULL, *link;

	g_return_val_if_fail (icalcomp != NULL, NULL);
	g_return_val_if_fail (!icaltime_is_null_time (rid), NULL);

	/* Make sure this is really recurring */
	if (!icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY) &&
	    !icalcomponent_get_first_property (icalcomp, ICAL_RDATE_PROPERTY))
		return NULL;

	/* Make sure the specified instance really exists */
	start = icaltime_convert_to_zone (rid, icaltimezone_get_utc_timezone ());
	end = start;
	icaltime_adjust (&end, 0, 0, 0, 1);

	instance.start = icaltime_as_timet (start);
	instance.found = FALSE;
	icalcomponent_foreach_recurrence (icalcomp, start, end,
					  check_instance, &instance);
	/* Make the copy */
	icalcomp = icalcomponent_new_clone (icalcomp);

	e_cal_util_remove_instances_ex (icalcomp, rid, E_CAL_OBJ_MOD_THIS_AND_PRIOR, TRUE, FALSE);

	start = rid;
	if (icaltime_is_null_time (master_dtstart))
		master_dtstart = icalcomponent_get_dtstart (icalcomp);
	duration = icalcomponent_get_duration (icalcomp);

	/* Expect that DTSTART and DTEND are already set when the instance could not be found */
	if (instance.found) {
		icalcomponent_set_dtstart (icalcomp, start);
		/* Update either DURATION or DTEND */
		if (icaltime_is_null_time (icalcomponent_get_dtend (icalcomp))) {
			icalcomponent_set_duration (icalcomp, duration);
		} else {
			end = start;
			if (duration.is_neg)
				icaltime_adjust (&end, -duration.days - 7 * duration.weeks, -duration.hours, -duration.minutes, -duration.seconds);
			else
				icaltime_adjust (&end, duration.days + 7 * duration.weeks, duration.hours, duration.minutes, duration.seconds);
			icalcomponent_set_dtend (icalcomp, end);
		}
	}

	/* any RRULE with 'count' should be shortened */
	for (prop = icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY);
	     prop;
	     prop = icalcomponent_get_next_property (icalcomp, ICAL_RRULE_PROPERTY)) {
		struct icaltimetype recur;
		struct icalrecurrencetype rule;

		rule = icalproperty_get_rrule (prop);

		if (rule.count != 0) {
			gint occurrences_count = 0;
			icalrecur_iterator *iter;

			iter = icalrecur_iterator_new (rule, master_dtstart);
			while (recur = icalrecur_iterator_next (iter), !icaltime_is_null_time (recur) && occurrences_count < rule.count) {
				if (icaltime_compare (recur, rid) >= 0)
					break;

				occurrences_count++;
			}

			icalrecur_iterator_free (iter);

			if (icaltime_is_null_time (recur)) {
				remove_props = g_slist_prepend (remove_props, prop);
			} else {
				rule.count -= occurrences_count;
				icalproperty_set_rrule (prop, rule);
				icalproperty_remove_parameter_by_name (prop, "X-EVOLUTION-ENDDATE");
			}
		}
	}

	for (link = remove_props; link; link = g_slist_next (link)) {
		prop = link->data;

		icalcomponent_remove_property (icalcomp, prop);
	}

	g_slist_free (remove_props);

	return icalcomp;
}
Example #10
0
static void
e_cal_util_remove_instances_ex (icalcomponent *icalcomp,
				struct icaltimetype rid,
				ECalObjModType mod,
				gboolean keep_rid,
				gboolean can_add_exrule)
{
	icalproperty *prop;
	struct icaltimetype itt, recur;
	struct icalrecurrencetype rule;
	icalrecur_iterator *iter;
	GSList *remove_props = NULL, *rrules = NULL, *link;

	g_return_if_fail (icalcomp != NULL);
	g_return_if_fail (mod != E_CAL_OBJ_MOD_ALL);

	/* First remove RDATEs and EXDATEs in the indicated range. */
	for (prop = icalcomponent_get_first_property (icalcomp, ICAL_RDATE_PROPERTY);
	     prop;
	     prop = icalcomponent_get_next_property (icalcomp, ICAL_RDATE_PROPERTY)) {
		struct icaldatetimeperiodtype period;

		period = icalproperty_get_rdate (prop);
		if (time_matches_rid (period.time, rid, mod) && (!keep_rid ||
		    icaltime_compare (period.time, rid) != 0))
			remove_props = g_slist_prepend (remove_props, prop);
	}
	for (prop = icalcomponent_get_first_property (icalcomp, ICAL_EXDATE_PROPERTY);
	     prop;
	     prop = icalcomponent_get_next_property (icalcomp, ICAL_EXDATE_PROPERTY)) {
		itt = icalproperty_get_exdate (prop);
		if (time_matches_rid (itt, rid, mod) && (!keep_rid ||
		    icaltime_compare (itt, rid) != 0))
			remove_props = g_slist_prepend (remove_props, prop);
	}

	for (link = remove_props; link; link = g_slist_next (link)) {
		prop = link->data;

		icalcomponent_remove_property (icalcomp, prop);
	}

	g_slist_free (remove_props);
	remove_props = NULL;

	/* If we're only removing one instance, just add an EXDATE. */
	if (mod == E_CAL_OBJ_MOD_THIS) {
		prop = icalproperty_new_exdate (rid);
		icalcomponent_add_property (icalcomp, prop);
		return;
	}

	/* Otherwise, iterate through RRULEs */
	/* FIXME: this may generate duplicate EXRULEs */
	for (prop = icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY);
	     prop;
	     prop = icalcomponent_get_next_property (icalcomp, ICAL_RRULE_PROPERTY)) {
		rrules = g_slist_prepend (rrules, prop);
	}

	for (link = rrules; link; link = g_slist_next (link)) {
		prop = link->data;
		rule = icalproperty_get_rrule (prop);

		iter = icalrecur_iterator_new (rule, rid);
		recur = icalrecur_iterator_next (iter);

		if (mod & E_CAL_OBJ_MOD_THIS_AND_FUTURE) {
			/* Truncate the rule at rid. */
			if (!icaltime_is_null_time (recur)) {
				/* Use count if it was used */
				if (rule.count > 0) {
					gint occurrences_count = 0;
					icalrecur_iterator *count_iter;
					struct icaltimetype count_recur;

					count_iter = icalrecur_iterator_new (rule, icalcomponent_get_dtstart (icalcomp));
					while (count_recur = icalrecur_iterator_next (count_iter), !icaltime_is_null_time (count_recur) && occurrences_count < rule.count) {
						if (icaltime_compare (count_recur, rid) >= 0)
							break;

						occurrences_count++;
					}

					icalrecur_iterator_free (count_iter);

					if (keep_rid && icaltime_compare (count_recur, rid) == 0)
						occurrences_count++;

					/* The caller should make sure that the remove will keep at least one instance */
					g_warn_if_fail (occurrences_count > 0);

					rule.count = occurrences_count;
				} else {
					if (keep_rid && icaltime_compare (recur, rid) == 0)
						rule.until = icaltime_add (rid, icalcomponent_get_duration (icalcomp));
					else
						rule.until = rid;
					icaltime_adjust (&rule.until, 0, 0, 0, -1);
				}

				icalproperty_set_rrule (prop, rule);
				icalproperty_remove_parameter_by_name (prop, "X-EVOLUTION-ENDDATE");
			}
		} else {
			/* (If recur == rid, skip to the next occurrence) */
			if (!keep_rid && icaltime_compare (recur, rid) == 0)
				recur = icalrecur_iterator_next (iter);

			/* If there is a recurrence after rid, add
			 * an EXRULE to block instances up to rid.
			 * Otherwise, just remove the RRULE.
			 */
			if (!icaltime_is_null_time (recur)) {
				if (can_add_exrule) {
					rule.count = 0;
					/* iCalendar says we should just use rid
					 * here, but Outlook/Exchange handle
					 * UNTIL incorrectly.
					 */
					if (keep_rid && icaltime_compare (recur, rid) == 0) {
						struct icaldurationtype duration = icalcomponent_get_duration (icalcomp);
						duration.is_neg = !duration.is_neg;
						rule.until = icaltime_add (rid, duration);
					} else
						rule.until = icaltime_add (rid, icalcomponent_get_duration (icalcomp));
					prop = icalproperty_new_exrule (rule);
					icalcomponent_add_property (icalcomp, prop);
				}
			} else {
				remove_props = g_slist_prepend (remove_props, prop);
			}
		}

		icalrecur_iterator_free (iter);
	}

	for (link = remove_props; link; link = g_slist_next (link)) {
		prop = link->data;

		icalcomponent_remove_property (icalcomp, prop);
	}

	g_slist_free (remove_props);
	g_slist_free (rrules);
}
Example #11
0
int main()
{
    icalarray *builtin_timezones;
    icaltimetype tt;
    int dd, hh, zz, tried = 0;
    long zz2 = -1;

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

    tt = icaltime_current_time_with_zone(icaltimezone_get_builtin_timezone("America/New_York"));

    tt.year = 2038;
    (void)icaltime_as_timet_with_zone(tt, icaltimezone_get_builtin_timezone("PST"));
    tried++;

    tt.year = 2050;
    (void)icaltime_as_timet_with_zone(tt, icaltimezone_get_builtin_timezone("PST"));
    tried++;

    tt.year = 1958;
    (void)icaltime_as_timet_with_zone(tt, icaltimezone_get_builtin_timezone("PST"));
    tried++;

    builtin_timezones = icaltimezone_get_builtin_timezones();
    printf("got %lu zones\n", (unsigned long)builtin_timezones->num_elements);
    if (builtin_timezones->num_elements == 0) {
      printf("YIKES. Try running from the build/bin directory\n");
      return(1);
    }

    for (zz = -1; zz < (int)builtin_timezones->num_elements; zz++) {
        icaltimezone *zone;

        if (zz < 0) {
            zone = icaltimezone_get_utc_timezone();
        } else {
            zone = icalarray_element_at(builtin_timezones, (size_t)zz);
        }

        tt = icaltime_current_time_with_zone(zone);

        for (dd = 0; dd < 370; dd += 17) {
            for (hh = 0; hh < 60 * 60 * 24; hh += 567) {
                int zz2cnt;

                icaltime_adjust(&tt, 0, 0, 0, 1);

                for (zz2cnt = 0; zz2cnt < 15; zz2cnt++) {
                    icaltimezone *zone2;

                    if (zz2 < 0) {
                        zone2 = icaltimezone_get_utc_timezone();
                    } else {
                        zone2 = icalarray_element_at(builtin_timezones, (size_t)zz2);
                    }

                    (void)icaltime_as_timet_with_zone(tt, zone2);
                    tried++;

                    zz2++;
                    if (zz2 >= (long)builtin_timezones->num_elements)
                        zz2 = -1;
                }
            }
        }

        printf("\r%lu %% done",
               (zz >= 0 ? zz : 0) * 100 / (unsigned long)builtin_timezones->num_elements);
        fflush(stdout);
    }

    printf("\ntried %d times\n", tried);
    return 0;
}
Example #12
0
static gboolean
do_mail_to_event (AsyncData *data)
{
	EClient *client;
	CamelFolder *folder = data->folder;
	GPtrArray *uids = data->uids;
	GError *error = NULL;

	client = e_client_cache_get_client_sync (data->client_cache,
		data->source, data->extension_name, 30, NULL, &error);

	/* Sanity check. */
	g_return_val_if_fail (
		((client != NULL) && (error == NULL)) ||
		((client == NULL) && (error != NULL)), TRUE);

	if (error != NULL) {
		report_error_idle (_("Cannot open calendar. %s"), error->message);
	} else if (e_client_is_readonly (E_CLIENT (client))) {
		switch (data->source_type) {
		case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
			report_error_idle (_("Selected calendar is read only, thus cannot create event there. Select other calendar, please."), NULL);
			break;
		case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
			report_error_idle (_("Selected task list is read only, thus cannot create task there. Select other task list, please."), NULL);
			break;
		case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
			report_error_idle (_("Selected memo list is read only, thus cannot create memo there. Select other memo list, please."), NULL);
			break;
		default:
			g_warn_if_reached ();
			break;
		}
	} else {
		gint i;
		ECalComponentDateTime dt, dt2;
		struct icaltimetype tt, tt2;
		struct _manage_comp *oldmc = NULL;

		#define cache_backend_prop(prop) { \
			gchar *val = NULL; \
			e_client_get_backend_property_sync (E_CLIENT (client), prop, &val, NULL, NULL); \
			g_free (val); \
		}

		/* precache backend properties, thus editor have them ready when needed */
		cache_backend_prop (CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS);
		cache_backend_prop (CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS);
		cache_backend_prop (CAL_BACKEND_PROPERTY_DEFAULT_OBJECT);
		e_client_get_capabilities (E_CLIENT (client));

		#undef cache_backend_prop

		/* set start day of the event as today, without time - easier than looking for a calendar's time zone */
		tt = icaltime_today ();
		dt.value = &tt;
		dt.tzid = NULL;

		tt2 = tt;
		icaltime_adjust (&tt2, 1, 0, 0, 0);
		dt2.value = &tt2;
		dt2.tzid = NULL;

		for (i = 0; i < (uids ? uids->len : 0); i++) {
			CamelMimeMessage *message;
			ECalComponent *comp;
			ECalComponentText text;
			icalproperty *icalprop;
			icalcomponent *icalcomp;
			struct _manage_comp *mc;

			/* retrieve the message from the CamelFolder */
			/* FIXME Not passing a GCancellable or GError. */
			message = camel_folder_get_message_sync (
				folder, g_ptr_array_index (uids, i),
				NULL, NULL);
			if (!message) {
				continue;
			}

			comp = e_cal_component_new ();

			switch (data->source_type) {
			case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
				e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_EVENT);
				break;
			case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
				e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_TODO);
				break;
			case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
				e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_JOURNAL);
				break;
			default:
				g_warn_if_reached ();
				break;
			}

			e_cal_component_set_uid (comp, camel_mime_message_get_message_id (message));
			e_cal_component_set_dtstart (comp, &dt);

			if (data->source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS) {
				/* make it an all-day event */
				e_cal_component_set_dtend (comp, &dt2);
			}

			/* set the summary */
			text.value = camel_mime_message_get_subject (message);
			text.altrep = NULL;
			e_cal_component_set_summary (comp, &text);

			/* set all fields */
			if (data->selected_text) {
				GSList sl;

				text.value = data->selected_text;
				text.altrep = NULL;
				sl.next = NULL;
				sl.data = &text;

				e_cal_component_set_description_list (comp, &sl);
			} else
				set_description (comp, message);

			if (data->with_attendees) {
				gchar *organizer;

				/* set actual user as organizer, to be able to change event's properties */
				organizer = set_organizer (comp, data->folder);
				set_attendees (comp, message, organizer);
				g_free (organizer);
			}

			/* set attachment files */
			set_attachments (E_CAL_CLIENT (client), comp, message);

			/* priority */
			set_priority (comp, CAMEL_MIME_PART (message));

			/* no need to increment a sequence number, this is a new component */
			e_cal_component_abort_sequence (comp);

			icalcomp = e_cal_component_get_icalcomponent (comp);

			icalprop = icalproperty_new_x ("1");
			icalproperty_set_x_name (icalprop, "X-EVOLUTION-MOVE-CALENDAR");
			icalcomponent_add_property (icalcomp, icalprop);

			mc = g_new0 (struct _manage_comp, 1);
			mc->client = g_object_ref (client);
			mc->comp = g_object_ref (comp);
			g_mutex_init (&mc->mutex);
			g_cond_init (&mc->cond);
			mc->mails_count = uids->len;
			mc->mails_done = i + 1; /* Current task */
			mc->editor_title = NULL;
			mc->can_continue = TRUE;

			if (oldmc) {
				/* Wait for user to quit the editor created in previous iteration
				 * before displaying next one */
				gboolean can_continue;
				g_mutex_lock (&oldmc->mutex);
				g_cond_wait (&oldmc->cond, &oldmc->mutex);
				g_mutex_unlock (&oldmc->mutex);
				can_continue = oldmc->can_continue;
				free_manage_comp_struct (oldmc);
				oldmc = NULL;

				if (!can_continue)
					break;
			}

			e_cal_client_get_object_sync (
				E_CAL_CLIENT (client),
				icalcomponent_get_uid (icalcomp),
				NULL, &mc->stored_comp, NULL, NULL);

			/* Prioritize ahead of GTK+ redraws. */
			g_idle_add_full (
				G_PRIORITY_HIGH_IDLE,
				(GSourceFunc) do_manage_comp_idle, mc, NULL);

			oldmc = mc;

			g_object_unref (comp);
			g_object_unref (message);

		}

		/* Wait for the last editor and then clean up */
		if (oldmc) {
			g_mutex_lock (&oldmc->mutex);
			g_cond_wait (&oldmc->cond, &oldmc->mutex);
			g_mutex_unlock (&oldmc->mutex);
			free_manage_comp_struct (oldmc);
		}
	}

	/* free memory */
	if (client != NULL)
		g_object_unref (client);
	g_ptr_array_unref (uids);
	g_object_unref (folder);

	g_object_unref (data->client_cache);
	g_object_unref (data->source);
	g_free (data->selected_text);
	g_free (data);
	data = NULL;

	if (error != NULL)
		g_error_free (error);

	return TRUE;
}
Example #13
0
static void
put_options_in_source (ESource *source,
                       EGwSendOptionsGeneral *gopts,
                       EGwSendOptionsStatusTracking *sopts)
{
	gchar *value;
	const gchar *val;
	icaltimetype tt;

	if (gopts) {
			/* priority */
		switch (gopts->priority) {
			case E_GW_PRIORITY_HIGH:
				value = g_strdup ("high");
				break;
			case E_GW_PRIORITY_STANDARD:
				value = g_strdup ("standard");
				break;
			case E_GW_PRIORITY_LOW:
				value =  g_strdup ("low");
				break;
			default:
				value = g_strdup ("undefined");
		}
		e_source_set_property (source, "priority", value);
		g_free (value), value = NULL;

			/* Reply Requested */
		/*TODO Fill the value if it is not "convinient" */
		if (gopts->reply_enabled) {
			if (gopts->reply_convenient)
				value = g_strdup ("convinient");
			else
				value = g_strdup_printf ("%d",gopts->reply_within);
		 } else
			value = g_strdup ("none");
		e_source_set_property (source, "reply-requested", value);
		g_free (value), value = NULL;

			/* Delay delivery */
		if (gopts->delay_enabled) {
				tt = icaltime_today ();
				icaltime_adjust (&tt, gopts->delay_until, 0, 0, 0);
				val = icaltime_as_ical_string_r (tt);
		} else
			val = "none";
		e_source_set_property (source, "delay-delivery", val);

			/* Expiration date */
		if (gopts->expiration_enabled)
			value =  g_strdup_printf ("%d", gopts->expire_after);
		else
			value = g_strdup ("none");
		e_source_set_property (source, "expiration", value);
		g_free (value), value = NULL;
	}

	if (sopts) {
			/* status tracking */
		if (sopts->tracking_enabled) {
			switch (sopts->track_when) {
				case E_GW_DELIVERED :
					value = g_strdup ("delivered");
					break;
				case E_GW_DELIVERED_OPENED:
					value = g_strdup ("delivered-opened");
					break;
				default:
					value = g_strdup ("all");
			}
		} else
			value = g_strdup ("none");
		e_source_set_property (source, "status-tracking", value);
		g_free (value), value = NULL;

		add_return_value (sopts->opened, source, "return-open");
		add_return_value (sopts->accepted, source, "return-accept");
		add_return_value (sopts->declined, source, "return-decline");
		add_return_value (sopts->completed, source, "return-complete");
	}
}
static ECellDateEditValue *
get_dtend (ECalModelCalendar *model,
           ECalModelComponent *comp_data)
{
	struct icaltimetype tt_end;

	if (!comp_data->dtend) {
		icalproperty *prop;
		icaltimezone *zone = NULL, *model_zone = NULL;
		gboolean got_zone = FALSE;

		prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_DTEND_PROPERTY);
		if (!prop)
			return NULL;

		tt_end = icalproperty_get_dtend (prop);

		if (icaltime_get_tzid (tt_end)
		    && e_cal_client_get_timezone_sync (comp_data->client, icaltime_get_tzid (tt_end), &zone, NULL, NULL))
			got_zone = TRUE;

		model_zone = e_cal_model_get_timezone (E_CAL_MODEL (model));

		if (got_zone) {
			tt_end = icaltime_from_timet_with_zone (comp_data->instance_end, tt_end.is_date, zone);
			if (model_zone)
				icaltimezone_convert_time (&tt_end, zone, model_zone);
		} else {
			tt_end = icaltime_from_timet_with_zone (
				comp_data->instance_end,
				tt_end.is_date, model_zone);
		}

		if (!icaltime_is_valid_time (tt_end) || icaltime_is_null_time (tt_end))
			return NULL;

		if (tt_end.is_date && icalcomponent_get_first_property (comp_data->icalcomp, ICAL_DTSTART_PROPERTY)) {
			struct icaltimetype tt_start;
			icaltimezone *start_zone = NULL;
			gboolean got_start_zone = FALSE;

			tt_start = icalproperty_get_dtstart (prop);

			if (icaltime_get_tzid (tt_start)
			    && e_cal_client_get_timezone_sync (comp_data->client, icaltime_get_tzid (tt_start), &start_zone, NULL, NULL))
				got_start_zone = TRUE;

			if (got_start_zone) {
				tt_start = icaltime_from_timet_with_zone (comp_data->instance_start, tt_start.is_date, start_zone);
				if (model_zone)
					icaltimezone_convert_time (&tt_start, start_zone, model_zone);
			} else {
				tt_start = icaltime_from_timet_with_zone (
					comp_data->instance_start,
					tt_start.is_date, model_zone);
			}

			icaltime_adjust (&tt_start, 1, 0, 0, 0);

			/* Decrease by a day only if the DTSTART will still be before, or the same as, DTEND */
			if (icaltime_compare (tt_start, tt_end) <= 0)
				icaltime_adjust (&tt_end, -1, 0, 0, 0);
		}

		comp_data->dtend = g_new0 (ECellDateEditValue, 1);
		comp_data->dtend->tt = tt_end;

		if (got_zone)
			comp_data->dtend->zone = zone;
		else
			comp_data->dtend->zone = NULL;
	}

	return e_cal_model_copy_cell_date_value (comp_data->dtend);
}
Example #15
0
static void
dump_local_times (icaltimezone *zone, FILE *fp)
{
  static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
			    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
  icaltimezone *utc_timezone;
  struct icaltimetype tt, tt_copy;
  struct tm tm, local_tm;
  time_t t;
  char tzstring[256], *location;
  int last_year_output = 0;
  int total_error = 0, total_error2 = 0;

  utc_timezone = icaltimezone_get_utc_timezone ();

  /* This is our UTC time that we will use to iterate over the period. */
  tt.year = DUMP_START_YEAR;
  tt.month = 1;
  tt.day = 1;
  tt.hour = 0;
  tt.minute = 0;
  tt.second = 0;
  tt.is_utc = 0;
  tt.is_date = 0;
  tt.zone = "";

  tm.tm_year = tt.year - 1900;
  tm.tm_mon = tt.month - 1;
  tm.tm_mday = tt.day;
  tm.tm_hour = tt.hour;
  tm.tm_min = tt.minute;
  tm.tm_sec = tt.second;
  tm.tm_isdst = -1;

  /* Convert it to a time_t by saying it is in UTC. */
  putenv ("TZ=UTC");
  t = mktime (&tm);

  location = icaltimezone_get_location (zone);
  sprintf (tzstring, "TZ=%s", location);

  /*printf ("Zone: %s\n", location);*/
  putenv (tzstring);

  /* Loop around converting the UTC time to local time, outputting it, and
     then adding on 15 minutes to the UTC time. */
  while (tt.year <= DUMP_END_YEAR) {
    if (tt.year > last_year_output) {
      last_year_output = tt.year;
#if 0
      printf ("  %i\n", last_year_output);
      fprintf (fp, "  %i\n", last_year_output);
#endif
    }

#if 1
    /* First use the Unix functions. */
    /* Now convert it to a local time in the given timezone. */
    local_tm = *localtime (&t);
#endif

#if 1
    /* Now use libical. */
    tt_copy = tt;
    icaltimezone_convert_time (&tt_copy, utc_timezone, zone);
#endif

#if 1
    if (local_tm.tm_year + 1900 != tt_copy.year
	|| local_tm.tm_mon + 1 != tt_copy.month
	|| local_tm.tm_mday != tt_copy.day
	|| local_tm.tm_hour != tt_copy.hour
	|| local_tm.tm_min != tt_copy.minute
	|| local_tm.tm_sec != tt_copy.second) {

      /* The error format is:

     ERROR: Original-UTC-Time  Local-Time-From-mktime  Local-Time-From-Libical

      */

      total_error++;

      fprintf (fp, "ERROR:%2i %s %04i %2i:%02i:%02i UTC",
	       tt.day, months[tt.month - 1], tt.year,
	       tt.hour, tt.minute, tt.second);
      fprintf (fp, " ->%2i %s %04i %2i:%02i:%02i",
	       local_tm.tm_mday, months[local_tm.tm_mon],
	       local_tm.tm_year + 1900,
	       local_tm.tm_hour, local_tm.tm_min, local_tm.tm_sec);
      fprintf (fp, " Us:%2i %s %04i %2i:%02i:%02i\n",
	       tt_copy.day, months[tt_copy.month - 1], tt_copy.year,
	       tt_copy.hour, tt_copy.minute, tt_copy.second);
    }
#endif

    /* Now convert it back, and check we get the original time. */
    icaltimezone_convert_time (&tt_copy, zone, utc_timezone);
    if (tt.year != tt_copy.year
	|| tt.month != tt_copy.month
	|| tt.day != tt_copy.day
	|| tt.hour != tt_copy.hour
	|| tt.minute != tt_copy.minute
	|| tt.second != tt_copy.second) {

      total_error2++;

      fprintf (fp, "ERROR 2: %2i %s %04i %2i:%02i:%02i UTC",
	       tt.day, months[tt.month - 1], tt.year,
	       tt.hour, tt.minute, tt.second);
      fprintf (fp, " Us:%2i %s %04i %2i:%02i:%02i UTC\n",
	       tt_copy.day, months[tt_copy.month - 1], tt_copy.year,
	       tt_copy.hour, tt_copy.minute, tt_copy.second);
    }


    /* Increment the time. */
    icaltime_adjust (&tt, 0, 0, 15, 0);

    /* We assume leap seconds are not included in time_t values, which should
       be true on POSIX systems. */
    t += 15 * 60;
  }

  printf ("Zone: %40s  Errors: %i (%i)\n", icaltimezone_get_location (zone),
	  total_error, total_error2);
}
Example #16
0
static void
add_event_to_day_array (GcalYearView  *year_view,
                        GcalEventData *event_data,
                        GList        **days_widgets_array,
                        gint           days_span)
{
  GcalYearViewPrivate *priv;
  GtkWidget *child_widget;

  const icaltimetype *dt_start, *dt_end;
  icaltimetype date, second_date;

  gint i;
  gboolean child_widget_used = FALSE;

  priv = year_view->priv;
  child_widget = gcal_event_widget_new_from_data (event_data);
  gcal_event_widget_set_read_only (GCAL_EVENT_WIDGET (child_widget),
                                   gcal_manager_is_client_writable (priv->manager, event_data->source));

  dt_start = gcal_event_widget_peek_start_date (GCAL_EVENT_WIDGET (child_widget));
  dt_end = gcal_event_widget_peek_end_date (GCAL_EVENT_WIDGET (child_widget));

  /* normalize date on each new event */
  date = *(priv->start_selected_date);
  second_date = *(priv->start_selected_date);
  second_date.hour = 23;
  second_date.minute = 59;

  /* marking and cloning */
  for (i = 0; i < days_span; i++)
    {
      GtkWidget *cloned_child = child_widget;
      gint start_comparison, end_comparison;

      if (i != 0)
        {
          icaltime_adjust (&date, 1, 0, 0, 0);
          icaltime_adjust (&second_date, 1, 0, 0, 0);
        }

      start_comparison = icaltime_compare_date (dt_start, &date);
      if (start_comparison <= 0)
        {
          if (child_widget_used)
            cloned_child = gcal_event_widget_clone (GCAL_EVENT_WIDGET (child_widget));
          else
            child_widget_used = TRUE;
        }
      else
        {
          cloned_child = NULL;
        }

      if (cloned_child != NULL)
        {
          days_widgets_array[i] = g_list_insert_sorted (days_widgets_array[i],
                                                        cloned_child,
                                                        (GCompareFunc) gcal_event_widget_compare_for_single_day);

          end_comparison = icaltime_compare_date (&second_date, dt_end);
          /* XXX: hack ensuring allday events with end_date a day after */
          if (end_comparison == -1 && second_date.year == dt_end->year && dt_end->is_date == 1)
            end_comparison = 0;

          if (start_comparison < 0 && end_comparison < 0)
            gtk_style_context_add_class (gtk_widget_get_style_context (cloned_child), "slanted");
          else if (start_comparison < 0)
            gtk_style_context_add_class (gtk_widget_get_style_context (cloned_child), "slanted-start");
          else if (end_comparison < 0)
            gtk_style_context_add_class (gtk_widget_get_style_context (cloned_child), "slanted-end");

          if (end_comparison == 0)
            break;
        }
    }
}
Example #17
0
static void
update_sidebar_headers (GtkListBoxRow *row,
                        GtkListBoxRow *before,
                        gpointer user_data)
{
  GcalYearViewPrivate *priv;
  GtkWidget *row_child, *before_child = NULL, *row_header = NULL;
  const icaltimetype *row_date, *before_date = NULL;
  icaltimetype date;
  gint row_shift, before_shift =-1;

  priv = GCAL_YEAR_VIEW (user_data)->priv;
  row_child = gtk_bin_get_child (GTK_BIN (row));
  if (row_child == NULL)
    return;
  row_date = gcal_event_widget_peek_start_date (GCAL_EVENT_WIDGET (row_child));
  row_shift = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (row_child), "shift"));
  if (before != NULL)
    {
      before_child = gtk_bin_get_child (GTK_BIN (before));
      before_date = gcal_event_widget_peek_start_date (GCAL_EVENT_WIDGET (before_child));
      before_shift = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (before_child), "shift"));
    }

  if (before_shift == -1 || before_shift != row_shift)
    {
      GtkWidget *label;
      gchar *label_str;

      row_header = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
      date = *(priv->start_selected_date);
      icaltime_adjust (&date, row_shift, 0, 0, 0);

      if (icaltime_compare_date (&date, priv->current_date) == 0)
        label_str = g_strdup (_("Today"));
      else
        label_str = g_strdup_printf ("%s %d", gcal_get_month_name (date.month  - 1), date.day);

      label = gtk_label_new (label_str);
      gtk_style_context_add_class (gtk_widget_get_style_context (label), "sidebar-header");
      g_object_set (label, "margin", 6, "halign", GTK_ALIGN_START, NULL);
      g_free (label_str);

      gtk_container_add (GTK_CONTAINER (row_header), label);
    }

  if (!gcal_event_widget_is_multiday (GCAL_EVENT_WIDGET (row_child)) &&
      !gcal_event_widget_get_all_day (GCAL_EVENT_WIDGET (row_child)) &&
      (before_date == NULL || before_date->hour != row_date->hour))
    {
      gchar *time;
      GtkWidget *label;

      if (priv->use_24h_format)
        time = g_strdup_printf ("%.2d:00", row_date->hour);
      else
        time = g_strdup_printf ("%.2d:00 %s", row_date->hour % 12, row_date->hour < 12 ? "AM" : "PM");

      label = gtk_label_new (time);
      gtk_style_context_add_class (gtk_widget_get_style_context (label), GTK_STYLE_CLASS_DIM_LABEL);
      g_object_set (label, "margin", 6, "halign", GTK_ALIGN_START, NULL);

      if (row_header == NULL)
        row_header = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);

      gtk_container_add (GTK_CONTAINER (row_header), label);
      gtk_container_add (GTK_CONTAINER (row_header), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));

      g_free (time);
    }

  if (row_header != NULL)
    gtk_widget_show_all (row_header);
  gtk_list_box_row_set_header (row, row_header);
}
static void
icaltimezone_expand_vtimezone		(icalcomponent	*comp,
					 int		 end_year,
					 icalarray	*changes)
{
    icaltimezonechange change;
    icalproperty *prop;
    struct icaltimetype dtstart, occ;
    struct icalrecurrencetype rrule;
    icalrecur_iterator* rrule_iterator;
    struct icaldatetimeperiodtype rdate;
    int found_dtstart = 0, found_tzoffsetto = 0, found_tzoffsetfrom = 0;
    int has_recurrence = 0;

    /* First we check if it is a STANDARD or DAYLIGHT component, and
       just return if it isn't. */
    if (icalcomponent_isa (comp) == ICAL_XSTANDARD_COMPONENT)
	change.is_daylight = 0;
    else if (icalcomponent_isa (comp) == ICAL_XDAYLIGHT_COMPONENT)
	change.is_daylight = 1;
    else 
	return;

    /* Step through each of the properties to find the DTSTART,
       TZOFFSETFROM and TZOFFSETTO. We can't expand recurrences here
       since we need these properties before we can do that. */
    prop = icalcomponent_get_first_property (comp, ICAL_ANY_PROPERTY);
    while (prop) {
	switch (icalproperty_isa (prop)) {
	case ICAL_DTSTART_PROPERTY:
	    dtstart = icalproperty_get_dtstart (prop);
	    found_dtstart = 1;
	    break;
	case ICAL_TZOFFSETTO_PROPERTY:
	    change.utc_offset = icalproperty_get_tzoffsetto (prop);
	    /*printf ("Found TZOFFSETTO: %i\n", change.utc_offset);*/
	    found_tzoffsetto = 1;
	    break;
	case ICAL_TZOFFSETFROM_PROPERTY:
	    change.prev_utc_offset = icalproperty_get_tzoffsetfrom (prop);
	    /*printf ("Found TZOFFSETFROM: %i\n", change.prev_utc_offset);*/
	    found_tzoffsetfrom = 1;
	    break;
	case ICAL_RDATE_PROPERTY:
	case ICAL_RRULE_PROPERTY:
	    has_recurrence = 1;
	    break;
	default:
	    /* Just ignore any other properties. */
	    break;
	}

	prop = icalcomponent_get_next_property (comp, ICAL_ANY_PROPERTY);
    }

    /* If we didn't find a DTSTART, TZOFFSETTO and TZOFFSETFROM we have to
       ignore the component. FIXME: Add an error property? */
    if (!found_dtstart || !found_tzoffsetto || !found_tzoffsetfrom)
	return;

#if 0
    printf ("\n Expanding component DTSTART (Y/M/D): %i/%i/%i %i:%02i:%02i\n",
	    dtstart.year, dtstart.month, dtstart.day,
	    dtstart.hour, dtstart.minute, dtstart.second);
#endif

    /* If the STANDARD/DAYLIGHT component has no recurrence data, we just add
       a single change for the DTSTART. */
    if (!has_recurrence) {
	change.year   = dtstart.year;
	change.month  = dtstart.month;
	change.day    = dtstart.day;
	change.hour   = dtstart.hour;
	change.minute = dtstart.minute;
	change.second = dtstart.second;

	/* Convert to UTC. */
	icaltimezone_adjust_change (&change, 0, 0, 0, -change.prev_utc_offset);

#if 0
	printf ("  Appending single DTSTART (Y/M/D): %i/%02i/%02i %i:%02i:%02i\n",
		change.year, change.month, change.day,
		change.hour, change.minute, change.second);
#endif

	/* Add the change to the array. */
	icalarray_append (changes, &change);
	return;
    }

    /* The component has recurrence data, so we expand that now. */
    prop = icalcomponent_get_first_property (comp, ICAL_ANY_PROPERTY);
    while (prop) {
#if 0
	printf ("Expanding property...\n");
#endif
	switch (icalproperty_isa (prop)) {
	case ICAL_RDATE_PROPERTY:
	    rdate = icalproperty_get_rdate (prop);
	    change.year   = rdate.time.year;
	    change.month  = rdate.time.month;
	    change.day    = rdate.time.day;
	    /* RDATEs with a DATE value inherit the time from
	       the DTSTART. */
	    if (icaltime_is_date(rdate.time)) {
		change.hour   = dtstart.hour;
		change.minute = dtstart.minute;
		change.second = dtstart.second;
	    } else {
		change.hour   = rdate.time.hour;
		change.minute = rdate.time.minute;
		change.second = rdate.time.second;

		/* The spec was a bit vague about whether RDATEs were in local
		   time or UTC so we support both to be safe. So if it is in
		   UTC we have to add the UTC offset to get a local time. */
		if (!icaltime_is_utc(rdate.time))
		    icaltimezone_adjust_change (&change, 0, 0, 0,
						-change.prev_utc_offset);
	    }

#if 0
	    printf ("  Appending RDATE element (Y/M/D): %i/%02i/%02i %i:%02i:%02i\n",
		    change.year, change.month, change.day,
		    change.hour, change.minute, change.second);
#endif

	    icalarray_append (changes, &change);
	    break;
	case ICAL_RRULE_PROPERTY:
	    rrule = icalproperty_get_rrule (prop);

	    /* If the rrule UNTIL value is set and is in UTC, we convert it to
	       a local time, since the recurrence code has no way to convert
	       it itself. */
	    if (!icaltime_is_null_time (rrule.until) && rrule.until.is_utc) {
#if 0
		printf ("  Found RRULE UNTIL in UTC.\n");
#endif

		/* To convert from UTC to a local time, we use the TZOFFSETFROM
		   since that is the offset from UTC that will be in effect
		   when each of the RRULE occurrences happens. */
		icaltime_adjust (&rrule.until, 0, 0, 0,
				 change.prev_utc_offset);
		rrule.until.is_utc = 0;
	    }

	    rrule_iterator = icalrecur_iterator_new (rrule, dtstart);
	    for (;;) {
		occ = icalrecur_iterator_next (rrule_iterator);
		if (occ.year > end_year || icaltime_is_null_time (occ))
		    break;

		change.year   = occ.year;
		change.month  = occ.month;
		change.day    = occ.day;
		change.hour   = occ.hour;
		change.minute = occ.minute;
		change.second = occ.second;

#if 0
		printf ("  Appending RRULE element (Y/M/D): %i/%02i/%02i %i:%02i:%02i\n",
			change.year, change.month, change.day,
			change.hour, change.minute, change.second);
#endif

		icaltimezone_adjust_change (&change, 0, 0, 0,
					    -change.prev_utc_offset);

		icalarray_append (changes, &change);
	    }

	    icalrecur_iterator_free (rrule_iterator);
	    break;
	default:
	    break;
	}

	prop = icalcomponent_get_next_property (comp, ICAL_ANY_PROPERTY);
    }
}