Skip to content

Commit

Permalink
Always convert iCalendar strings to use UTC
Browse files Browse the repository at this point in the history
To simplify the timezone handling, times like DTSTART are now
always converted to UTC and old schedules are migrated to this
new format.
  • Loading branch information
timopollmeier committed Oct 8, 2019
1 parent b0ccdbd commit ef6d5d6
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 65 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ include (CPack)

## Variables

set (GVMD_DATABASE_VERSION 220)
set (GVMD_DATABASE_VERSION 221)

set (GVMD_SCAP_DATABASE_VERSION 15)

Expand Down
83 changes: 83 additions & 0 deletions src/manage_migrators.c
Original file line number Diff line number Diff line change
Expand Up @@ -1481,6 +1481,88 @@ migrate_219_to_220 ()
return 0;
}

/**
* @brief Convert iCalendar strings of schedules to new format for version 221.
*
* @param[in] trash Whether to convert the trash table.
*/
static void convert_schedules_221 (gboolean trash)
{
iterator_t schedules;

init_iterator (&schedules,
"SELECT id, icalendar, uuid FROM %s;",
trash ? "schedules_trash" : "schedules");

while (next (&schedules))
{
schedule_t schedule;
const char *ical_string, *schedule_id;
icalcomponent *ical_component;
gchar *error_out;

error_out = NULL;
schedule = iterator_int64 (&schedules, 0);
ical_string = iterator_string (&schedules, 1);
schedule_id = iterator_string (&schedules, 2);

ical_component = icalendar_from_string (ical_string, &error_out);
if (ical_component == NULL)
g_warning ("Error converting schedule %s: %s", schedule_id, error_out);
else
{
gchar *quoted_ical;

quoted_ical
= sql_quote (icalcomponent_as_ical_string (ical_component));

sql ("UPDATE %s SET icalendar = '%s' WHERE id = %llu",
trash ? "schedules_trash" : "schedules",
quoted_ical,
schedule);

g_free (quoted_ical);
}

g_free (error_out);
}

cleanup_iterator (&schedules);
}

/**
* @brief Migrate the database from version 220 to version 221.
*
* @return 0 success, -1 error.
*/
int
migrate_220_to_221 ()
{
sql_begin_immediate ();

/* Ensure that the database is currently version 220. */

if (manage_db_version () != 220)
{
sql_rollback ();
return -1;
}

/* Update the database. */

/* Convert iCalendar strings of all schedules */
convert_schedules_221 (FALSE);
convert_schedules_221 (TRUE);

/* Set the database version to 221. */

set_db_version (221);

sql_commit ();

return 0;
}

#undef UPDATE_DASHBOARD_SETTINGS

/**
Expand All @@ -1507,6 +1589,7 @@ static migrator_t database_migrators[] = {
{218, migrate_217_to_218},
{219, migrate_218_to_219},
{220, migrate_219_to_220},
{221, migrate_220_to_221},
/* End marker. */
{-1, NULL}};

Expand Down
7 changes: 3 additions & 4 deletions src/manage_sql.c
Original file line number Diff line number Diff line change
Expand Up @@ -44392,7 +44392,7 @@ create_schedule (const char* name, const char *comment,
{
ical_component = icalendar_from_old_schedule_data
(first_time, period, period_months, duration,
byday_mask, zone);
byday_mask);
quoted_ical = sql_quote (icalcomponent_as_ical_string (ical_component));
}

Expand Down Expand Up @@ -45427,7 +45427,7 @@ modify_schedule (const char *schedule_id, const char *name, const char *comment,

/* Update basic data */
quoted_comment = comment ? sql_quote (comment) : NULL;
quoted_timezone = timezone ? sql_quote (zone) : NULL;
quoted_timezone = zone ? sql_quote (zone) : NULL;

sql ("UPDATE schedules SET"
" name = %s%s%s,"
Expand Down Expand Up @@ -45596,8 +45596,7 @@ modify_schedule (const char *schedule_id, const char *name, const char *comment,
ical_component = icalendar_from_old_schedule_data
(real_first_time,
real_period, real_period_months,
real_duration, real_byday,
real_timezone);
real_duration, real_byday);
quoted_icalendar
= sql_quote (icalcomponent_as_ical_string (ical_component));

Expand Down
96 changes: 38 additions & 58 deletions src/manage_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -734,20 +734,17 @@ icalendar_timezone_from_tzid (const char *tzid)
* @param[in] period_months The period in months.
* @param[in] duration The duration in seconds.
* @param[in] byday_mask The byday mask.
* @param[in] zone The timezone id / city name.
*
* @return The generated iCalendar component.
*/
icalcomponent *
icalendar_from_old_schedule_data (time_t first_time,
time_t period, time_t period_months,
time_t duration,
int byday_mask,
const char *zone)
int byday_mask)
{
gchar *uid;
icalcomponent *ical_new, *vevent;
icaltimezone *ical_timezone;
icaltimetype dtstart, dtstamp;
int has_recurrence;
struct icalrecurrencetype recurrence;
Expand All @@ -774,15 +771,9 @@ icalendar_from_old_schedule_data (time_t first_time,
icalcomponent_set_dtstamp (vevent, dtstamp);

// Get timezone and set first start time
if (zone)
{
ical_timezone = icalendar_timezone_from_tzid (zone);
}
else
{
ical_timezone = NULL;
}
dtstart = icaltime_from_timet_with_zone (first_time, 0, ical_timezone);
dtstart = icaltime_from_timet_with_zone (first_time, 0,
icaltimezone_get_utc_timezone ());

icalcomponent_set_dtstart (vevent, dtstart);

// Get recurrence rule if applicable
Expand Down Expand Up @@ -874,21 +865,19 @@ icalendar_from_old_schedule_data (time_t first_time,
* @brief Simplify an VEVENT iCal component.
*
* @param[in] vevent The VEVENT component to simplify.
* @param[in] used_tzids GHashTable to collect ids of the used timezones.
* @param[out] error Output of iCal errors or warnings.
* @param[out] warnings_buffer GString buffer to write warnings to.
*
* @return A newly allocated, simplified VEVENT component.
*/
static icalcomponent *
icalendar_simplify_vevent (icalcomponent *vevent, GHashTable *used_tzids,
icalendar_simplify_vevent (icalcomponent *vevent,
gchar **error, GString *warnings_buffer)
{
icalproperty *error_prop;
gchar *uid;
icalcomponent *vevent_simplified;
icaltimetype dtstart, dtstamp;
const char *start_tzid;
icaltimetype original_dtstart, dtstart, dtstamp;
struct icaldurationtype duration;
icalproperty *rrule_prop, *rdate_prop, *exdate_prop, *exrule_prop;

Expand All @@ -908,33 +897,36 @@ icalendar_simplify_vevent (icalcomponent *vevent, GHashTable *used_tzids,
}

// Get mandatory first start time
dtstart = icalcomponent_get_dtstart (vevent);
if (icaltime_is_null_time (dtstart))
original_dtstart = icalcomponent_get_dtstart (vevent);
if (icaltime_is_null_time (original_dtstart))
{
if (error)
*error = g_strdup_printf ("VEVENT must have a dtstart property");
return NULL;
}

// Get timezone id used in start time
start_tzid = icaltime_get_tzid (dtstart);
if (start_tzid && used_tzids)
g_hash_table_add (used_tzids, g_strdup (start_tzid));
dtstart = icaltime_convert_to_zone (original_dtstart,
icaltimezone_get_utc_timezone ());

// Get duration or try to calculate it from end time
duration = icalcomponent_get_duration (vevent);
if (icaldurationtype_is_null_duration (duration))
{
icaltimetype dtend;
dtend = icalcomponent_get_dtend (vevent);
icaltimetype original_dtend;
original_dtend = icalcomponent_get_dtend (vevent);

if (icaltime_is_null_time (dtend))
if (icaltime_is_null_time (original_dtend))
{
duration = icaldurationtype_null_duration ();
}
else
{
duration = icaltime_subtract (dtend, dtstart);
icaltimetype dtend_utc;
dtend_utc
= icaltime_convert_to_zone (original_dtend,
icaltimezone_get_utc_timezone ());

duration = icaltime_subtract (dtend_utc, dtstart);
}
}

Expand Down Expand Up @@ -982,11 +974,15 @@ icalendar_simplify_vevent (icalcomponent *vevent, GHashTable *used_tzids,
new_datetimeperiod.period = icalperiodtype_null_period ();
if (icalperiodtype_is_null_period (old_datetimeperiod.period))
{
new_datetimeperiod.time = old_datetimeperiod.time;
new_datetimeperiod.time
= icaltime_convert_to_zone (old_datetimeperiod.time,
icaltimezone_get_utc_timezone ());
}
else
{
new_datetimeperiod.time = old_datetimeperiod.period.start;
new_datetimeperiod.time
= icaltime_convert_to_zone (old_datetimeperiod.period.start,
icaltimezone_get_utc_timezone ());
}
new_rdate = icalproperty_new_rdate (new_datetimeperiod);
icalcomponent_add_property (vevent_simplified, new_rdate);
Expand All @@ -1000,9 +996,15 @@ icalendar_simplify_vevent (icalcomponent *vevent, GHashTable *used_tzids,
ICAL_EXDATE_PROPERTY);
while (exdate_prop)
{
icaltimetype original_exdate_time, exdate_time;
icalproperty *prop_clone;

prop_clone = icalproperty_new_clone (exdate_prop);
original_exdate_time = icalproperty_get_exdate (exdate_prop);
exdate_time
= icaltime_convert_to_zone (original_exdate_time,
icaltimezone_get_utc_timezone ());

prop_clone = icalproperty_new_exdate (exdate_time);
icalcomponent_add_property (vevent_simplified, prop_clone);

exdate_prop
Expand Down Expand Up @@ -1033,7 +1035,6 @@ icalendar_simplify_vevent (icalcomponent *vevent, GHashTable *used_tzids,
icalcomponent_free (ical_parsed); \
icalcomponent_free (ical_new); \
g_string_free (warnings_buffer, TRUE); \
g_hash_table_destroy (tzids); \
return NULL; \
} \
while (0)
Expand All @@ -1051,13 +1052,10 @@ icalendar_from_string (const char *ical_string, gchar **error)
{
icalcomponent *ical_new, *ical_parsed;
icalproperty *error_prop;
GHashTable *tzids;
GString *warnings_buffer;
int vevent_count = 0;
int other_component_count = 0;
icalcompiter ical_iter;
GHashTableIter tzids_iter;
gchar *tzid;

// Parse the iCalendar string
ical_parsed = icalcomponent_new_from_string (ical_string);
Expand All @@ -1083,7 +1081,6 @@ icalendar_from_string (const char *ical_string, gchar **error)

// Create buffers and new VCALENDAR
warnings_buffer = g_string_new ("");
tzids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);

ical_new = icalcomponent_new_vcalendar ();
icalcomponent_add_property (ical_new, icalproperty_new_version ("2.0"));
Expand Down Expand Up @@ -1114,7 +1111,9 @@ icalendar_from_string (const char *ical_string, gchar **error)
if (vevent_count == 0)
{
new_vevent = icalendar_simplify_vevent
(subcomp, tzids, error, warnings_buffer);
(subcomp,
error,
warnings_buffer);
if (new_vevent == NULL)
ICAL_RETURN_ERROR (*error);
icalcomponent_add_component (ical_new, new_vevent);
Expand Down Expand Up @@ -1169,8 +1168,9 @@ icalendar_from_string (const char *ical_string, gchar **error)
{
icalcomponent *new_vevent;

new_vevent = icalendar_simplify_vevent (ical_parsed, tzids,
error, warnings_buffer);
new_vevent = icalendar_simplify_vevent (ical_parsed,
error,
warnings_buffer);
if (new_vevent == NULL)
ICAL_RETURN_ERROR (*error);
icalcomponent_add_component (ical_new, new_vevent);
Expand All @@ -1183,26 +1183,6 @@ icalendar_from_string (const char *ical_string, gchar **error)
break;
}

g_hash_table_iter_init (&tzids_iter, tzids);
while (g_hash_table_iter_next (&tzids_iter, (gpointer*)(&tzid), NULL))
{
icaltimezone *tz;
tz = icalcomponent_get_timezone (ical_parsed, tzid);
if (tz)
{
icalcomponent *tz_component;

tz_component = icaltimezone_get_component (tz);
if (tz_component)
{
icalcomponent *tz_component_copy;
tz_component_copy = icalcomponent_new_clone (tz_component);
icalcomponent_add_component (ical_new, tz_component_copy);
}
}
}

g_hash_table_destroy (tzids);
icalcomponent_free (ical_parsed);

if (error)
Expand Down
3 changes: 1 addition & 2 deletions src/manage_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ int
hosts_str_contains (const char *, const char *, int);

icalcomponent *
icalendar_from_old_schedule_data (time_t, time_t, time_t, time_t, int,
const char *);
icalendar_from_old_schedule_data (time_t, time_t, time_t, time_t, int);

icalcomponent *
icalendar_from_string (const char *, gchar **);
Expand Down

0 comments on commit ef6d5d6

Please sign in to comment.