2000-02-16 Russell Steinthal <rms39@columbia.edu> * calobj.[ch], eventedit.c, main.c: Change iCalObject.organizer from char* to iCalPerson* * calobj.[ch]: Change iCalObject.related from list of char* to list of iCalRelation*; assorted related fixes * icalendar.c: interface between libical and the gnomecal internal representation svn path=/trunk/; revision=1791
1609 lines
33 KiB
C
1609 lines
33 KiB
C
/*
|
|
* Calendar objects implementations.
|
|
* Copyright (C) 1998 the Free Software Foundation
|
|
*
|
|
* Authors:
|
|
* Miguel de Icaza (miguel@gnu.org)
|
|
* Federico Mena (quartic@gimp.org)
|
|
*/
|
|
#include <config.h>
|
|
#include <string.h>
|
|
#include <glib.h>
|
|
#include <ctype.h>
|
|
#include <unistd.h>
|
|
#include "calobj.h"
|
|
#include "timeutil.h"
|
|
#include "../libversit/vcc.h"
|
|
|
|
extern CalendarAlarm alarm_defaults[4];
|
|
|
|
static char *
|
|
ical_gen_uid (void)
|
|
{
|
|
static char *hostname;
|
|
time_t t = time (NULL);
|
|
static int serial;
|
|
|
|
if (!hostname){
|
|
char buffer [128];
|
|
|
|
if ((gethostname (buffer, sizeof (buffer)-1) == 0) &&
|
|
(buffer [0] != 0))
|
|
hostname = g_strdup (buffer);
|
|
else
|
|
hostname = g_strdup ("localhost");
|
|
}
|
|
|
|
return g_strdup_printf (
|
|
"%s-%d-%d-%d-%d@%s",
|
|
isodate_from_time_t (t),
|
|
getpid (),
|
|
getgid (),
|
|
getppid (),
|
|
serial++,
|
|
hostname);
|
|
}
|
|
|
|
iCalObject *
|
|
ical_object_new (void)
|
|
{
|
|
iCalObject *ico;
|
|
|
|
ico = g_new0 (iCalObject, 1);
|
|
|
|
ico->seq = -1;
|
|
ico->dtstamp = time (NULL);
|
|
ico->uid = ical_gen_uid ();
|
|
|
|
ico->pilot_id = 0;
|
|
ico->pilot_status = ICAL_PILOT_SYNC_MOD;
|
|
|
|
return ico;
|
|
}
|
|
|
|
static void
|
|
default_alarm (iCalObject *ical, CalendarAlarm *alarm, char *def_mail, enum AlarmType type)
|
|
{
|
|
alarm->type = type;
|
|
alarm->enabled = alarm_defaults[type].enabled;
|
|
alarm->count = alarm_defaults[type].count;
|
|
alarm->units = alarm_defaults[type].units;
|
|
if (alarm_defaults[type].data)
|
|
alarm->data = g_strdup (alarm_defaults[type].data);
|
|
else
|
|
alarm->data = g_strdup ("");
|
|
}
|
|
|
|
iCalObject *
|
|
ical_new (char *comment, char *organizer, char *summary)
|
|
{
|
|
iCalObject *ico;
|
|
|
|
ico = ical_object_new ();
|
|
|
|
ico->comment = g_strdup (comment);
|
|
ico->organizer = g_new0 (iCalPerson, 1);
|
|
ico->organizer->addr = g_strdup (organizer);
|
|
ico->summary = g_strdup (summary);
|
|
ico->class = g_strdup ("PUBLIC");
|
|
ico->status = g_strdup ("NEEDS ACTION");
|
|
|
|
default_alarm (ico, &ico->dalarm, organizer, ALARM_DISPLAY);
|
|
default_alarm (ico, &ico->palarm, organizer, ALARM_PROGRAM);
|
|
default_alarm (ico, &ico->malarm, organizer, ALARM_MAIL);
|
|
default_alarm (ico, &ico->aalarm, organizer, ALARM_AUDIO);
|
|
|
|
return ico;
|
|
}
|
|
|
|
static void
|
|
my_free (gpointer data, gpointer user_dat_ignored)
|
|
{
|
|
g_free (data);
|
|
}
|
|
|
|
static void
|
|
list_free (GList *list)
|
|
{
|
|
g_list_foreach (list, my_free, 0);
|
|
g_list_free (list);
|
|
}
|
|
|
|
#define free_if_defined(x) if (x){ g_free (x); x = 0; }
|
|
#define lfree_if_defined(x) if (x){ list_free (x); x = 0; }
|
|
void
|
|
ical_object_destroy (iCalObject *ico)
|
|
{
|
|
/* Regular strings */
|
|
free_if_defined (ico->comment);
|
|
free_if_defined (ico->organizer);
|
|
free_if_defined (ico->summary);
|
|
free_if_defined (ico->uid);
|
|
free_if_defined (ico->status);
|
|
free_if_defined (ico->class);
|
|
free_if_defined (ico->url);
|
|
free_if_defined (ico->recur);
|
|
|
|
/* Lists */
|
|
lfree_if_defined (ico->exdate);
|
|
lfree_if_defined (ico->categories);
|
|
lfree_if_defined (ico->resources);
|
|
lfree_if_defined (ico->related);
|
|
lfree_if_defined (ico->attach);
|
|
|
|
/* Alarms */
|
|
g_free (ico->dalarm.data);
|
|
g_free (ico->palarm.data);
|
|
g_free (ico->malarm.data);
|
|
g_free (ico->aalarm.data);
|
|
|
|
g_free (ico);
|
|
}
|
|
|
|
static GList *
|
|
set_list (char *str)
|
|
{
|
|
GList *list = 0;
|
|
char *s;
|
|
|
|
for (s = strtok (str, ";"); s; s = strtok (NULL, ";"))
|
|
list = g_list_prepend (list, g_strdup (s));
|
|
|
|
return list;
|
|
}
|
|
|
|
static GList *
|
|
set_date_list (char *str)
|
|
{
|
|
GList *list = 0;
|
|
char *s;
|
|
|
|
for (s = strtok (str, ";,"); s; s = strtok (NULL, ";,")){
|
|
time_t *t = g_new (time_t, 1);
|
|
|
|
while (*s && isspace (*s))
|
|
s++;
|
|
*t = time_from_isodate (s);
|
|
list = g_list_prepend (list, t);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
void
|
|
ical_object_add_exdate (iCalObject *o, time_t t)
|
|
{
|
|
time_t *pt = g_new (time_t, 1);
|
|
|
|
*pt = t;
|
|
o->exdate = g_list_prepend (o->exdate, pt);
|
|
}
|
|
|
|
static void
|
|
ignore_space(char **str)
|
|
{
|
|
while (**str && isspace (**str))
|
|
(*str)++;
|
|
}
|
|
|
|
static void
|
|
skip_numbers (char **str)
|
|
{
|
|
while (**str){
|
|
ignore_space (str);
|
|
if (!isdigit (**str))
|
|
return;
|
|
while (**str && isdigit (**str))
|
|
(*str)++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
weekdaylist (iCalObject *o, char **str)
|
|
{
|
|
int i;
|
|
struct {
|
|
char first_letter, second_letter;
|
|
int index;
|
|
} days [] = {
|
|
{ 'S', 'U', 0 },
|
|
{ 'M', 'O', 1 },
|
|
{ 'T', 'U', 2 },
|
|
{ 'W', 'E', 3 },
|
|
{ 'T', 'H', 4 },
|
|
{ 'F', 'R', 5 },
|
|
{ 'S', 'A', 6 }
|
|
};
|
|
|
|
ignore_space (str);
|
|
do {
|
|
for (i = 0; i < 7; i++){
|
|
if (**str == days [i].first_letter && *(*str+1) == days [i].second_letter){
|
|
o->recur->weekday |= 1 << i;
|
|
*str += 2;
|
|
if (**str == ' ')
|
|
(*str)++;
|
|
}
|
|
}
|
|
} while (isalpha (**str));
|
|
|
|
if (o->recur->weekday == 0){
|
|
struct tm tm = *localtime (&o->dtstart);
|
|
|
|
o->recur->weekday = 1 << tm.tm_wday;
|
|
}
|
|
}
|
|
|
|
static void
|
|
weekdaynum (iCalObject *o, char **str)
|
|
{
|
|
int i;
|
|
struct {
|
|
char first_letter, second_letter;
|
|
int index;
|
|
} days [] = {
|
|
{ 'S', 'U', 0 },
|
|
{ 'M', 'O', 1 },
|
|
{ 'T', 'U', 2 },
|
|
{ 'W', 'E', 3 },
|
|
{ 'T', 'H', 4 },
|
|
{ 'F', 'R', 5 },
|
|
{ 'S', 'A', 6 }
|
|
};
|
|
|
|
ignore_space (str);
|
|
do {
|
|
for (i = 0; i < 7; i++){
|
|
if (**str == days [i].first_letter && *(*str+1) == days [i].second_letter){
|
|
o->recur->weekday = i;
|
|
*str += 2;
|
|
if (**str == ' ')
|
|
(*str)++;
|
|
}
|
|
}
|
|
} while (isalpha (**str));
|
|
}
|
|
|
|
static void
|
|
ocurrencelist (iCalObject *o, char **str)
|
|
{
|
|
char *p;
|
|
|
|
ignore_space (str);
|
|
p = *str;
|
|
if (!isdigit (*p))
|
|
return;
|
|
|
|
if (!(*p >= '1' && *p <= '5'))
|
|
return;
|
|
|
|
if (!(*(p+1) == '+' || *(p+1) == '-'))
|
|
return;
|
|
|
|
o->recur->u.month_pos = (*p-'0') * (*(p+1) == '+' ? 1 : -1);
|
|
*str += 2;
|
|
}
|
|
|
|
#if 0
|
|
|
|
static void
|
|
daynumber (iCalObject *o, char **str)
|
|
{
|
|
int val = 0;
|
|
char *p = *str;
|
|
|
|
ignore_space (str);
|
|
if (strcmp (p, "LD")){
|
|
o->recur->u.month_day = DAY_LASTDAY;
|
|
*str += 2;
|
|
return;
|
|
}
|
|
|
|
if (!(isdigit (*p)))
|
|
return;
|
|
|
|
while (**str && isdigit (**str)){
|
|
val = val * 10 + (**str - '0');
|
|
(*str)++;
|
|
}
|
|
|
|
if (**str == '+')
|
|
(*str)++;
|
|
|
|
if (**str == '-')
|
|
val *= -1;
|
|
o->recur->u.month_day = val;
|
|
}
|
|
|
|
#endif
|
|
|
|
static void
|
|
daynumberlist (iCalObject *o, char **str)
|
|
{
|
|
int first = 0;
|
|
int val = 0;
|
|
|
|
ignore_space (str);
|
|
|
|
while (**str){
|
|
if (!isdigit (**str))
|
|
return;
|
|
while (**str && isdigit (**str)){
|
|
val = 10 * val + (**str - '0');
|
|
(*str)++;
|
|
}
|
|
if (!first){
|
|
/*
|
|
* Some broken applications set this to zero
|
|
*/
|
|
if (val == 0){
|
|
struct tm day = *localtime (&o->dtstart);
|
|
|
|
val = day.tm_mday;
|
|
}
|
|
o->recur->u.month_day = val;
|
|
first = 1;
|
|
val = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
load_recur_weekly (iCalObject *o, char **str)
|
|
{
|
|
weekdaylist (o, str);
|
|
}
|
|
|
|
static void
|
|
load_recur_monthly_pos (iCalObject *o, char **str)
|
|
{
|
|
ocurrencelist (o, str);
|
|
weekdaynum (o, str);
|
|
}
|
|
|
|
static void
|
|
load_recur_monthly_day (iCalObject *o, char **str)
|
|
{
|
|
daynumberlist (o, str);
|
|
}
|
|
|
|
static void
|
|
load_recur_yearly_month (iCalObject *o, char **str)
|
|
{
|
|
/* Skip as we do not support multiple months and we do expect
|
|
* the dtstart to agree with the value on this field
|
|
*/
|
|
skip_numbers (str);
|
|
}
|
|
|
|
static void
|
|
load_recur_yearly_day (iCalObject *o, char **str)
|
|
{
|
|
/* Skip as we do not support multiple days and we do expect
|
|
* the dtstart to agree with the value on this field
|
|
*
|
|
* FIXME: we should support every-n-years
|
|
*/
|
|
skip_numbers (str);
|
|
}
|
|
|
|
static void
|
|
duration (iCalObject *o, char **str)
|
|
{
|
|
unsigned int duration = 0;
|
|
|
|
ignore_space (str);
|
|
if (**str != '#')
|
|
return;
|
|
(*str)++;
|
|
while (**str && isdigit (**str)){
|
|
duration = duration * 10 + (**str - '0');
|
|
(*str)++;
|
|
}
|
|
o->recur->duration = duration;
|
|
}
|
|
|
|
static void
|
|
enddate (iCalObject *o, char **str)
|
|
{
|
|
ignore_space (str);
|
|
if (isdigit (**str)){
|
|
o->recur->_enddate = time_from_isodate (*str);
|
|
*str += 16;
|
|
}
|
|
}
|
|
|
|
static int
|
|
load_recurrence (iCalObject *o, char *str)
|
|
{
|
|
enum RecurType type;
|
|
int interval = 0;
|
|
|
|
type = -1;
|
|
switch (*str++){
|
|
case 'D':
|
|
type = RECUR_DAILY;
|
|
break;
|
|
|
|
case 'W':
|
|
type = RECUR_WEEKLY;
|
|
break;
|
|
|
|
case 'M':
|
|
if (*str == 'P')
|
|
type = RECUR_MONTHLY_BY_POS;
|
|
else if (*str == 'D')
|
|
type = RECUR_MONTHLY_BY_DAY;
|
|
str++;
|
|
break;
|
|
|
|
case 'Y':
|
|
if (*str == 'M')
|
|
type = RECUR_YEARLY_BY_MONTH;
|
|
else if (*str == 'D')
|
|
type = RECUR_YEARLY_BY_DAY;
|
|
str++;
|
|
break;
|
|
}
|
|
if (type == -1)
|
|
return 0;
|
|
|
|
o->recur = g_new0 (Recurrence, 1);
|
|
o->recur->type = type;
|
|
ignore_space (&str);
|
|
|
|
/* Get the interval */
|
|
for (;*str && isdigit (*str);str++)
|
|
interval = interval * 10 + (*str-'0');
|
|
|
|
if (interval == 0)
|
|
interval = 1;
|
|
|
|
o->recur->interval = interval;
|
|
|
|
/* this is the default per the spec */
|
|
o->recur->duration = 2;
|
|
|
|
ignore_space (&str);
|
|
|
|
switch (type){
|
|
case RECUR_DAILY:
|
|
break;
|
|
case RECUR_WEEKLY:
|
|
load_recur_weekly (o, &str);
|
|
break;
|
|
case RECUR_MONTHLY_BY_POS:
|
|
load_recur_monthly_pos (o, &str);
|
|
break;
|
|
case RECUR_MONTHLY_BY_DAY:
|
|
load_recur_monthly_day (o, &str);
|
|
break;
|
|
case RECUR_YEARLY_BY_MONTH:
|
|
load_recur_yearly_month (o, &str);
|
|
break;
|
|
case RECUR_YEARLY_BY_DAY:
|
|
load_recur_yearly_day (o, &str);
|
|
break;
|
|
default:
|
|
g_warning ("Unimplemented recurrence type %d", (int) type);
|
|
break;
|
|
}
|
|
duration (o, &str);
|
|
enddate (o, &str);
|
|
|
|
/* Compute the enddate */
|
|
if (o->recur->_enddate == 0){
|
|
if (o->recur->duration != 0){
|
|
ical_object_compute_end (o);
|
|
} else
|
|
o->recur->enddate = 0;
|
|
} else {
|
|
o->recur->enddate = o->recur->_enddate;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#define is_a_prop_of(obj,prop) isAPropertyOf (obj,prop)
|
|
#define str_val(obj) the_str = fakeCString (vObjectUStringZValue (obj))
|
|
#define has(obj,prop) (vo = isAPropertyOf (obj, prop))
|
|
|
|
/*
|
|
* FIXME: This is loosing precission. Enhanec the thresholds
|
|
*/
|
|
#define HOURS(n) (n*(60*60))
|
|
|
|
static void
|
|
setup_alarm_at (iCalObject *ico, CalendarAlarm *alarm, char *iso_time, VObject *vo)
|
|
{
|
|
time_t alarm_time = time_from_isodate (iso_time);
|
|
time_t base = ico->dtstart;
|
|
int d = difftime (base, alarm_time);
|
|
VObject *a;
|
|
char *the_str;
|
|
|
|
alarm->enabled = 1;
|
|
if (d > HOURS (2)){
|
|
if (d > HOURS (48)){
|
|
alarm->count = d / HOURS (24);
|
|
alarm->units = ALARM_DAYS;
|
|
} else {
|
|
alarm->count = d / (60*60);
|
|
alarm->units = ALARM_HOURS;
|
|
}
|
|
} else {
|
|
alarm->count = d / 60;
|
|
alarm->units = ALARM_MINUTES;
|
|
}
|
|
|
|
if ((a = is_a_prop_of (vo, VCSnoozeTimeProp))){
|
|
alarm->snooze_secs = isodiff_to_secs (str_val (a));
|
|
free (the_str);
|
|
}
|
|
|
|
if ((a = is_a_prop_of (vo, VCRepeatCountProp))){
|
|
alarm->snooze_repeat = atoi (str_val (a));
|
|
free (the_str);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Duplicates an iCalObject. Implementation is a grand hack
|
|
*/
|
|
iCalObject *
|
|
ical_object_duplicate (iCalObject *o)
|
|
{
|
|
VObject *vo;
|
|
iCalObject *new;
|
|
|
|
/* FIXME!!!!! The UID needs to change!!! */
|
|
|
|
vo = ical_object_to_vobject (o);
|
|
switch (o->type){
|
|
case ICAL_EVENT:
|
|
new = ical_object_create_from_vobject (vo, VCEventProp);
|
|
break;
|
|
case ICAL_TODO:
|
|
new = ical_object_create_from_vobject (vo, VCTodoProp);
|
|
break;
|
|
default:
|
|
new = NULL;
|
|
}
|
|
|
|
cleanVObject (vo);
|
|
return new;
|
|
}
|
|
|
|
/* FIXME: we need to load the recurrence properties */
|
|
iCalObject *
|
|
ical_object_create_from_vobject (VObject *o, const char *object_name)
|
|
{
|
|
time_t now = time (NULL);
|
|
iCalObject *ical;
|
|
VObject *vo, *a;
|
|
VObjectIterator i;
|
|
char *the_str;
|
|
|
|
ical = g_new0 (iCalObject, 1);
|
|
|
|
if (strcmp (object_name, VCEventProp) == 0)
|
|
ical->type = ICAL_EVENT;
|
|
else if (strcmp (object_name, VCTodoProp) == 0)
|
|
ical->type = ICAL_TODO;
|
|
else {
|
|
g_free (ical);
|
|
return 0;
|
|
}
|
|
|
|
/* uid */
|
|
if (has (o, VCUniqueStringProp)){
|
|
ical->uid = g_strdup (str_val (vo));
|
|
free (the_str);
|
|
} else {
|
|
ical->uid = ical_gen_uid ();
|
|
}
|
|
|
|
/* seq */
|
|
if (has (o, VCSequenceProp)){
|
|
ical->seq = atoi (str_val (vo));
|
|
free (the_str);
|
|
} else
|
|
ical->seq = 0;
|
|
|
|
/* dtstart */
|
|
if (has (o, VCDTstartProp)){
|
|
ical->dtstart = time_from_isodate (str_val (vo));
|
|
free (the_str);
|
|
} else
|
|
ical->dtstart = 0;
|
|
|
|
/* dtend */
|
|
ical->dtend = 0; /* default value */
|
|
if (ical->type == ICAL_EVENT){
|
|
if (has (o, VCDTendProp)){
|
|
ical->dtend = time_from_isodate (str_val (vo));
|
|
free (the_str);
|
|
}
|
|
} else if (ical->type == ICAL_TODO){
|
|
if (has (o, VCDueProp)){
|
|
ical->dtend = time_from_isodate (str_val (vo));
|
|
free (the_str);
|
|
}
|
|
}
|
|
|
|
/* dcreated */
|
|
if (has (o, VCDCreatedProp)){
|
|
ical->created = time_from_isodate (str_val (vo));
|
|
free (the_str);
|
|
}
|
|
|
|
/* completed */
|
|
if (has (o, VCCompletedProp)){
|
|
ical->completed = time_from_isodate (str_val (vo));
|
|
free (the_str);
|
|
}
|
|
|
|
/* last_mod */
|
|
if (has (o, VCLastModifiedProp)){
|
|
ical->last_mod = time_from_isodate (str_val (vo));
|
|
free (the_str);
|
|
} else
|
|
ical->last_mod = now;
|
|
|
|
/* exdate */
|
|
if (has (o, VCExpDateProp)){
|
|
ical->exdate = set_date_list (str_val (vo));
|
|
free (the_str);
|
|
}
|
|
|
|
/* description/comment */
|
|
if (has (o, VCDescriptionProp)){
|
|
ical->comment = g_strdup (str_val (vo));
|
|
free (the_str);
|
|
}
|
|
|
|
/* summary */
|
|
if (has (o, VCSummaryProp)){
|
|
ical->summary = g_strdup (str_val (vo));
|
|
free (the_str);
|
|
} else
|
|
ical->summary = g_strdup ("");
|
|
|
|
/* status */
|
|
if (has (o, VCStatusProp)){
|
|
ical->status = g_strdup (str_val (vo));
|
|
free (the_str);
|
|
} else
|
|
ical->status = g_strdup ("NEEDS ACTION");
|
|
|
|
if (has (o, VCClassProp)){
|
|
ical->class = g_strdup (str_val (vo));
|
|
free (the_str);
|
|
} else
|
|
ical->class = g_strdup ("PUBLIC");
|
|
|
|
/* categories */
|
|
if (has (o, VCCategoriesProp)){
|
|
ical->categories = set_list (str_val (vo));
|
|
free (the_str);
|
|
}
|
|
|
|
/* resources */
|
|
if (has (o, VCResourcesProp)){
|
|
ical->resources = set_list (str_val (vo));
|
|
free (the_str);
|
|
}
|
|
|
|
/* priority */
|
|
if (has (o, VCPriorityProp)){
|
|
ical->priority = atoi (str_val (vo));
|
|
free (the_str);
|
|
}
|
|
|
|
/* tranparency */
|
|
if (has (o, VCTranspProp)){
|
|
ical->transp = atoi (str_val (vo)) ? ICAL_TRANSPARENT : ICAL_OPAQUE;
|
|
free (the_str);
|
|
}
|
|
|
|
/* Organizer */
|
|
if (has (o, VCOrgNameProp)){
|
|
ical->organizer = g_new0 (iCalPerson, 1);
|
|
ical->organizer->addr = g_strdup (str_val (vo));
|
|
free (the_str);
|
|
}
|
|
|
|
/* related */
|
|
if (has (o, VCRelatedToProp)){
|
|
char *str;
|
|
char *s;
|
|
iCalRelation *rel;
|
|
str = str_val (vo);
|
|
for (s = strtok (str, ";"); s; s = strtok (NULL, ";")) {
|
|
rel = g_new0 (iCalRelation, 1);
|
|
rel->uid = g_strdup (s);
|
|
rel->reltype = g_strdup ("PARENT");
|
|
ical->related = g_list_prepend (ical->related, rel);
|
|
}
|
|
free (the_str);
|
|
}
|
|
|
|
/* attach */
|
|
initPropIterator (&i, o);
|
|
while (moreIteration (&i)){
|
|
vo = nextVObject (&i);
|
|
if (strcmp (vObjectName (vo), VCAttachProp) == 0){
|
|
ical->attach = g_list_prepend (ical->attach, g_strdup (str_val (vo)));
|
|
free (the_str);
|
|
}
|
|
}
|
|
|
|
/* url */
|
|
if (has (o, VCURLProp)){
|
|
ical->url = g_strdup (str_val (vo));
|
|
free (the_str);
|
|
}
|
|
|
|
/* dalarm */
|
|
ical->dalarm.type = ALARM_DISPLAY;
|
|
ical->dalarm.enabled = 0;
|
|
if (has (o, VCDAlarmProp)){
|
|
if ((a = is_a_prop_of (vo, VCRunTimeProp))){
|
|
setup_alarm_at (ical, &ical->dalarm, str_val (a), vo);
|
|
free (the_str);
|
|
}
|
|
}
|
|
|
|
/* aalarm */
|
|
ical->aalarm.type = ALARM_AUDIO;
|
|
ical->aalarm.enabled = 0;
|
|
if (has (o, VCAAlarmProp)){
|
|
if ((a = is_a_prop_of (vo, VCRunTimeProp))){
|
|
setup_alarm_at (ical, &ical->aalarm, str_val (a), vo);
|
|
free (the_str);
|
|
}
|
|
}
|
|
|
|
/* palarm */
|
|
ical->palarm.type = ALARM_PROGRAM;
|
|
ical->palarm.enabled = 0;
|
|
if (has (o, VCPAlarmProp)){
|
|
ical->palarm.type = ALARM_PROGRAM;
|
|
if ((a = is_a_prop_of (vo, VCRunTimeProp))){
|
|
setup_alarm_at (ical, &ical->palarm, str_val (a), vo);
|
|
free (the_str);
|
|
|
|
if ((a = is_a_prop_of (vo, VCProcedureNameProp))){
|
|
ical->palarm.data = g_strdup (str_val (a));
|
|
free (the_str);
|
|
} else
|
|
ical->palarm.data = g_strdup ("");
|
|
}
|
|
}
|
|
|
|
/* malarm */
|
|
ical->malarm.type = ALARM_MAIL;
|
|
ical->malarm.enabled = 0;
|
|
if (has (o, VCMAlarmProp)){
|
|
ical->malarm.type = ALARM_MAIL;
|
|
if ((a = is_a_prop_of (vo, VCRunTimeProp))){
|
|
setup_alarm_at (ical, &ical->malarm, str_val (a), vo);
|
|
free (the_str);
|
|
|
|
if ((a = is_a_prop_of (vo, VCEmailAddressProp))){
|
|
ical->malarm.data = g_strdup (str_val (a));
|
|
free (the_str);
|
|
} else
|
|
ical->malarm.data = g_strdup ("");
|
|
}
|
|
}
|
|
|
|
/* rrule */
|
|
if (has (o, VCRRuleProp)){
|
|
if (!load_recurrence (ical, str_val (vo))) {
|
|
ical_object_destroy (ical);
|
|
return NULL;
|
|
}
|
|
free (the_str);
|
|
}
|
|
|
|
/*
|
|
* Pilot
|
|
*/
|
|
if (has (o, XPilotIdProp)){
|
|
ical->pilot_id = atoi (str_val (vo));
|
|
free (the_str);
|
|
} else
|
|
ical->pilot_id = 0;
|
|
|
|
if (has (o, XPilotStatusProp)){
|
|
ical->pilot_status = atoi (str_val (vo));
|
|
free (the_str);
|
|
} else
|
|
ical->pilot_status = ICAL_PILOT_SYNC_MOD;
|
|
|
|
return ical;
|
|
}
|
|
|
|
static char *
|
|
to_str (int num)
|
|
{
|
|
static char buf [40];
|
|
|
|
sprintf (buf, "%d", num);
|
|
return buf;
|
|
}
|
|
|
|
/*
|
|
* stores a GList in the property.
|
|
*/
|
|
static void
|
|
store_list (VObject *o, char *prop, GList *values)
|
|
{
|
|
GList *l;
|
|
int len;
|
|
char *result, *p;
|
|
|
|
for (len = 0, l = values; l; l = l->next)
|
|
len += strlen (l->data) + 1;
|
|
|
|
result = g_malloc (len);
|
|
|
|
for (p = result, l = values; l; l = l->next) {
|
|
int len = strlen (l->data);
|
|
|
|
strcpy (p, l->data);
|
|
|
|
if (l->next) {
|
|
p [len] = ';';
|
|
p += len+1;
|
|
} else
|
|
p += len;
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
addPropValue (o, prop, result);
|
|
g_free (result);
|
|
}
|
|
|
|
static void
|
|
store_rel_list (VObject *o, char *prop, GList *values)
|
|
{
|
|
GList *l;
|
|
int len;
|
|
char *result, *p;
|
|
|
|
for (len = 0, l = values; l; l = l->next)
|
|
len += strlen (((iCalRelation*)(l->data))->uid) + 1;
|
|
|
|
result = g_malloc (len);
|
|
|
|
for (p = result, l = values; l; l = l->next) {
|
|
int len = strlen (((iCalRelation*)(l->data))->uid);
|
|
|
|
strcpy (p, ((iCalRelation*)(l->data))->uid);
|
|
|
|
if (l->next) {
|
|
p [len] = ';';
|
|
p += len+1;
|
|
} else
|
|
p += len;
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
addPropValue (o, prop, result);
|
|
g_free (result);
|
|
}
|
|
|
|
static void
|
|
store_date_list (VObject *o, char *prop, GList *values)
|
|
{
|
|
GList *l;
|
|
int size, len;
|
|
char *s, *p;
|
|
|
|
size = g_list_length (values);
|
|
s = p = g_malloc ((size * 17 + 1) * sizeof (char));
|
|
|
|
for (l = values; l; l = l->next){
|
|
strcpy (s, isodate_from_time_t (*(time_t *)l->data));
|
|
len = strlen (s);
|
|
s [len] = ',';
|
|
s += len + 1;
|
|
}
|
|
s--;
|
|
*s = 0;
|
|
addPropValue (o, prop, p);
|
|
g_free (p);
|
|
}
|
|
|
|
static char *recur_type_name [] = { "D", "W", "MP", "MD", "YM", "YD" };
|
|
static char *recur_day_list [] = { "SU", "MO", "TU","WE", "TH", "FR", "SA" };
|
|
static char *alarm_names [] = { VCMAlarmProp, VCPAlarmProp, VCDAlarmProp, VCAAlarmProp };
|
|
|
|
static VObject *
|
|
save_alarm (VObject *o, CalendarAlarm *alarm, iCalObject *ical)
|
|
{
|
|
VObject *alarm_object;
|
|
struct tm tm;
|
|
time_t alarm_time;
|
|
|
|
if (!alarm->enabled)
|
|
return NULL;
|
|
tm = *localtime (&ical->dtstart);
|
|
switch (alarm->units){
|
|
case ALARM_MINUTES:
|
|
tm.tm_min -= alarm->count;
|
|
break;
|
|
|
|
case ALARM_HOURS:
|
|
tm.tm_hour -= alarm->count;
|
|
break;
|
|
|
|
case ALARM_DAYS:
|
|
tm.tm_mday -= alarm->count;
|
|
break;
|
|
}
|
|
|
|
alarm_time = mktime (&tm);
|
|
alarm_object = addProp (o, alarm_names [alarm->type]);
|
|
addPropValue (alarm_object, VCRunTimeProp, isodate_from_time_t (alarm_time));
|
|
|
|
if (alarm->snooze_secs)
|
|
addPropValue (alarm_object, VCSnoozeTimeProp, isodiff_from_secs (alarm->snooze_secs));
|
|
else
|
|
addPropValue (alarm_object, VCSnoozeTimeProp, "");
|
|
|
|
if (alarm->snooze_repeat){
|
|
char buf [20];
|
|
|
|
sprintf (buf, "%d", alarm->snooze_repeat);
|
|
addPropValue (alarm_object, VCRepeatCountProp, buf);
|
|
} else
|
|
addPropValue (alarm_object, VCRepeatCountProp, "");
|
|
return alarm_object;
|
|
}
|
|
|
|
VObject *
|
|
ical_object_to_vobject (iCalObject *ical)
|
|
{
|
|
VObject *o, *alarm, *s;
|
|
GList *l;
|
|
|
|
if (ical->type == ICAL_EVENT)
|
|
o = newVObject (VCEventProp);
|
|
else
|
|
o = newVObject (VCTodoProp);
|
|
|
|
/* uid */
|
|
if (ical->uid)
|
|
addPropValue (o, VCUniqueStringProp, ical->uid);
|
|
|
|
/* seq */
|
|
addPropValue (o, VCSequenceProp, to_str (ical->seq));
|
|
|
|
/* dtstart */
|
|
addPropValue (o, VCDTstartProp, isodate_from_time_t (ical->dtstart));
|
|
|
|
/* dtend */
|
|
if (ical->type == ICAL_EVENT){
|
|
addPropValue (o, VCDTendProp, isodate_from_time_t (ical->dtend));
|
|
} else if (ical->type == ICAL_TODO){
|
|
addPropValue (o, VCDueProp, isodate_from_time_t (ical->dtend));
|
|
}
|
|
|
|
/* dcreated */
|
|
addPropValue (o, VCDCreatedProp, isodate_from_time_t (ical->created));
|
|
|
|
/* completed */
|
|
if (ical->completed)
|
|
addPropValue (o, VCDTendProp, isodate_from_time_t (ical->completed));
|
|
|
|
/* last_mod */
|
|
addPropValue (o, VCLastModifiedProp, isodate_from_time_t (ical->last_mod));
|
|
|
|
/* exdate */
|
|
if (ical->exdate)
|
|
store_date_list (o, VCExpDateProp, ical->exdate);
|
|
|
|
/* description/comment */
|
|
if (ical->comment && strlen (ical->comment)){
|
|
s = addPropValue (o, VCDescriptionProp, ical->comment);
|
|
if (strchr (ical->comment, '\n'))
|
|
addProp (s, VCQuotedPrintableProp);
|
|
}
|
|
|
|
/* summary */
|
|
if (strlen (ical->summary)){
|
|
s = addPropValue (o, VCSummaryProp, ical->summary);
|
|
if (strchr (ical->summary, '\n'))
|
|
addProp (s, VCQuotedPrintableProp);
|
|
} else {
|
|
addPropValue (o, VCSummaryProp, _("Appointment"));
|
|
}
|
|
|
|
/* status */
|
|
addPropValue (o, VCStatusProp, ical->status);
|
|
|
|
/* class */
|
|
addPropValue (o, VCClassProp, ical->class);
|
|
|
|
/* categories */
|
|
if (ical->categories)
|
|
store_list (o, VCCategoriesProp, ical->categories);
|
|
|
|
/* resources */
|
|
if (ical->resources)
|
|
store_list (o, VCCategoriesProp, ical->resources);
|
|
|
|
/* priority */
|
|
addPropValue (o, VCPriorityProp, to_str (ical->priority));
|
|
|
|
/* transparency */
|
|
addPropValue (o, VCTranspProp, to_str (ical->transp));
|
|
|
|
/* Owner/organizer */
|
|
if (ical->organizer && ical->organizer->addr)
|
|
addPropValue (o, VCOrgNameProp, ical->organizer->addr);
|
|
|
|
/* related */
|
|
if (ical->related)
|
|
store_rel_list (o, VCRelatedToProp, ical->related);
|
|
|
|
/* attach */
|
|
for (l = ical->attach; l; l = l->next)
|
|
addPropValue (o, VCAttachProp, l->data);
|
|
|
|
/* url */
|
|
if (ical->url)
|
|
addPropValue (o, VCURLProp, ical->url);
|
|
|
|
if (ical->recur){
|
|
char result [256];
|
|
char buffer [80];
|
|
int i;
|
|
|
|
sprintf (result, "%s%d ", recur_type_name [ical->recur->type], ical->recur->interval);
|
|
switch (ical->recur->type){
|
|
case RECUR_DAILY:
|
|
break;
|
|
|
|
case RECUR_WEEKLY:
|
|
for (i = 0; i < 7; i++){
|
|
if (ical->recur->weekday & (1 << i)){
|
|
sprintf (buffer, "%s ", recur_day_list [i]);
|
|
strcat (result, buffer);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case RECUR_MONTHLY_BY_POS: {
|
|
int nega = ical->recur->u.month_pos < 0;
|
|
|
|
sprintf (buffer, "%d%s ", nega ? -ical->recur->u.month_pos : ical->recur->u.month_pos,
|
|
nega ? "-" : "+");
|
|
strcat (result, buffer);
|
|
/* the gui is set up for a single day, not a set here in this case */
|
|
sprintf (buffer, "%s ", recur_day_list [ical->recur->weekday]);
|
|
strcat (result, buffer);
|
|
}
|
|
break;
|
|
|
|
case RECUR_MONTHLY_BY_DAY:
|
|
sprintf (buffer, "%d ", ical->recur->u.month_pos);
|
|
strcat (result, buffer);
|
|
break;
|
|
|
|
case RECUR_YEARLY_BY_MONTH:
|
|
break;
|
|
|
|
case RECUR_YEARLY_BY_DAY:
|
|
break;
|
|
}
|
|
if (ical->recur->_enddate == 0)
|
|
sprintf (buffer, "#%d ",ical->recur->duration);
|
|
else
|
|
sprintf (buffer, "%s ", isodate_from_time_t (ical->recur->_enddate));
|
|
strcat (result, buffer);
|
|
addPropValue (o, VCRRuleProp, result);
|
|
}
|
|
|
|
save_alarm (o, &ical->aalarm, ical);
|
|
save_alarm (o, &ical->dalarm, ical);
|
|
|
|
if ((alarm = save_alarm (o, &ical->palarm, ical)))
|
|
addPropValue (alarm, VCProcedureNameProp, ical->palarm.data);
|
|
if ((alarm = save_alarm (o, &ical->malarm, ical)))
|
|
addPropValue (alarm, VCEmailAddressProp, ical->malarm.data);
|
|
|
|
/* Pilot */
|
|
{
|
|
char buffer [20];
|
|
|
|
sprintf (buffer, "%d", ical->pilot_id);
|
|
addPropValue (o, XPilotIdProp, buffer);
|
|
sprintf (buffer, "%d", ical->pilot_status);
|
|
addPropValue (o, XPilotStatusProp, buffer);
|
|
}
|
|
|
|
return o;
|
|
}
|
|
|
|
void
|
|
ical_foreach (GList *events, calendarfn fn, void *closure)
|
|
{
|
|
for (; events; events = events->next){
|
|
iCalObject *ical = events->data;
|
|
|
|
(*fn) (ical, ical->dtstart, ical->dtend, closure);
|
|
}
|
|
}
|
|
|
|
static int
|
|
is_date_in_list (GList *list, struct tm *date)
|
|
{
|
|
struct tm tm;
|
|
|
|
for (; list; list = list->next){
|
|
time_t *timep = list->data;
|
|
|
|
tm = *localtime (timep);
|
|
if (date->tm_mday == tm.tm_mday &&
|
|
date->tm_mon == tm.tm_mon &&
|
|
date->tm_year == tm.tm_year){
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
generate (iCalObject *ico, time_t reference, calendarfn cb, void *closure)
|
|
{
|
|
struct tm dt_start, dt_end, ref;
|
|
time_t s_t, e_t;
|
|
|
|
dt_start = *localtime (&ico->dtstart);
|
|
dt_end = *localtime (&ico->dtend);
|
|
ref = *localtime (&reference);
|
|
|
|
dt_start.tm_mday = ref.tm_mday;
|
|
dt_start.tm_mon = ref.tm_mon;
|
|
dt_start.tm_year = ref.tm_year;
|
|
|
|
dt_end.tm_mday = ref.tm_mday;
|
|
dt_end.tm_mon = ref.tm_mon;
|
|
dt_end.tm_year = ref.tm_year;
|
|
|
|
|
|
if (ref.tm_isdst > dt_start.tm_isdst){
|
|
dt_start.tm_hour--;
|
|
dt_end.tm_hour--;
|
|
} else if (ref.tm_isdst < dt_start.tm_isdst){
|
|
dt_start.tm_hour++;
|
|
dt_end.tm_hour++;
|
|
}
|
|
|
|
s_t = mktime (&dt_start);
|
|
|
|
if (ico->exdate && is_date_in_list (ico->exdate, &dt_start))
|
|
return 1;
|
|
|
|
e_t = mktime (&dt_end);
|
|
|
|
if ((s_t == -1) || (e_t == -1)) {
|
|
g_warning ("Produced invalid dates!\n");
|
|
return 0;
|
|
}
|
|
|
|
return (*cb) (ico, s_t, e_t, closure);
|
|
}
|
|
|
|
int
|
|
ical_object_get_first_weekday (int weekday_mask)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 7; i++)
|
|
if (weekday_mask & (1 << i))
|
|
return i;
|
|
|
|
return -1;
|
|
}
|
|
|
|
#define time_in_range(t, a, b) ((t >= a) && (b ? (t < b) : 1))
|
|
#define recur_in_range(t, r) (r->enddate ? (t < r->enddate) : 1)
|
|
|
|
/*
|
|
* Generate every possible event. Invokes the callback routine for
|
|
* every occurrence of the event in the [START, END] time interval.
|
|
*
|
|
* If END is zero, the event is generated forever.
|
|
* The callback routine is expected to return 0 when no further event
|
|
* generation is requested.
|
|
*/
|
|
void
|
|
ical_object_generate_events (iCalObject *ico, time_t start, time_t end, calendarfn cb, void *closure)
|
|
{
|
|
time_t current;
|
|
int first_week_day;
|
|
|
|
/* If there is no recurrence, just check ranges */
|
|
|
|
if (!ico->recur) {
|
|
if ((end && (ico->dtstart < end) && (ico->dtend > start))
|
|
|| ((end == 0) && (ico->dtend > start))) {
|
|
time_t ev_s, ev_e;
|
|
|
|
/* Clip range */
|
|
|
|
ev_s = MAX (ico->dtstart, start);
|
|
ev_e = MIN (ico->dtend, end);
|
|
|
|
(* cb) (ico, ev_s, ev_e, closure);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* The event has a recurrence rule -- check that we will generate at least one instance */
|
|
|
|
if (end != 0) {
|
|
if (ico->dtstart > end)
|
|
return;
|
|
|
|
if (!IS_INFINITE (ico->recur) && (ico->recur->enddate < start))
|
|
return;
|
|
}
|
|
|
|
/* Generate the instances */
|
|
|
|
current = ico->dtstart;
|
|
|
|
switch (ico->recur->type) {
|
|
case RECUR_DAILY:
|
|
do {
|
|
if (time_in_range (current, start, end) && recur_in_range (current, ico->recur))
|
|
if (!generate (ico, current, cb, closure))
|
|
return;
|
|
|
|
/* Advance */
|
|
|
|
current = time_add_day (current, ico->recur->interval);
|
|
|
|
if (current == -1) {
|
|
g_warning ("RECUR_DAILY: time_add_day() returned invalid time");
|
|
return;
|
|
}
|
|
} while ((current < end) || (end == 0));
|
|
|
|
break;
|
|
|
|
case RECUR_WEEKLY:
|
|
do {
|
|
struct tm tm;
|
|
|
|
tm = *localtime (¤t);
|
|
|
|
if (time_in_range (current, start, end) && recur_in_range (current, ico->recur)) {
|
|
/* Weekdays to recur on are specified as a bitmask */
|
|
if (ico->recur->weekday & (1 << tm.tm_wday)) {
|
|
if (!generate (ico, current, cb, closure))
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Advance by day for scanning the week or by interval at week end */
|
|
|
|
if (tm.tm_wday == 6)
|
|
current = time_add_day (current, (ico->recur->interval - 1) * 7 + 1);
|
|
else
|
|
current = time_add_day (current, 1);
|
|
|
|
if (current == -1) {
|
|
g_warning ("RECUR_WEEKLY: time_add_day() returned invalid time\n");
|
|
return;
|
|
}
|
|
} while (current < end || (end == 0));
|
|
|
|
break;
|
|
|
|
case RECUR_MONTHLY_BY_POS:
|
|
/* FIXME: We only deal with positives now */
|
|
if (ico->recur->u.month_pos < 0) {
|
|
g_warning ("RECUR_MONTHLY_BY_POS does not support negative positions yet");
|
|
return;
|
|
}
|
|
|
|
if (ico->recur->u.month_pos == 0)
|
|
return;
|
|
|
|
first_week_day = /* ical_object_get_first_weekday (ico->recur->weekday); */
|
|
ico->recur->weekday; /* the i/f only lets you choose a single day of the week! */
|
|
|
|
/* This should not happen, but take it into account */
|
|
if (first_week_day == -1) {
|
|
g_warning ("ical_object_get_first_weekday() returned -1");
|
|
return;
|
|
}
|
|
|
|
do {
|
|
struct tm tm;
|
|
time_t t;
|
|
int week_day_start;
|
|
|
|
tm = *localtime (¤t);
|
|
tm.tm_mday = 1;
|
|
t = mktime (&tm);
|
|
tm = *localtime (&t);
|
|
week_day_start = tm.tm_wday;
|
|
|
|
tm.tm_mday = (7 * (ico->recur->u.month_pos - ((week_day_start <= first_week_day ) ? 1 : 0))
|
|
- (week_day_start - first_week_day) + 1);
|
|
if( tm.tm_mday > 31 )
|
|
{
|
|
tm.tm_mday = 1;
|
|
tm.tm_mon += ico->recur->interval;
|
|
current = mktime (&tm);
|
|
continue;
|
|
}
|
|
|
|
switch( tm.tm_mon )
|
|
{
|
|
case 3:
|
|
case 5:
|
|
case 8:
|
|
case 10:
|
|
if( tm.tm_mday > 30 )
|
|
{
|
|
tm.tm_mday = 1;
|
|
tm.tm_mon += ico->recur->interval;
|
|
current = mktime (&tm);
|
|
continue;
|
|
}
|
|
break;
|
|
case 1:
|
|
if( ((tm.tm_year+1900)%4) == 0
|
|
&& ((tm.tm_year+1900)%400) != 100
|
|
&& ((tm.tm_year+1900)%400) != 200
|
|
&& ((tm.tm_year+1900)%400) != 300 )
|
|
{
|
|
|
|
if( tm.tm_mday > 29 )
|
|
{
|
|
tm.tm_mday = 1;
|
|
tm.tm_mon += ico->recur->interval;
|
|
current = mktime (&tm);
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( tm.tm_mday > 28 )
|
|
{
|
|
tm.tm_mday = 1;
|
|
tm.tm_mon += ico->recur->interval;
|
|
current = mktime (&tm);
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
t = mktime (&tm);
|
|
|
|
if (time_in_range (t, start, end) && recur_in_range (current, ico->recur))
|
|
if (!generate (ico, t, cb, closure))
|
|
return;
|
|
|
|
/* Advance by the appropriate number of months */
|
|
|
|
current = mktime (&tm);
|
|
|
|
tm.tm_mday = 1;
|
|
tm.tm_mon += ico->recur->interval;
|
|
current = mktime (&tm);
|
|
|
|
if (current == -1) {
|
|
g_warning ("RECUR_MONTHLY_BY_DAY: mktime error\n");
|
|
return;
|
|
}
|
|
} while ((current < end) || (end == 0));
|
|
|
|
break;
|
|
|
|
case RECUR_MONTHLY_BY_DAY:
|
|
do {
|
|
struct tm tm;
|
|
time_t t;
|
|
int p;
|
|
|
|
tm = *localtime (¤t);
|
|
|
|
p = tm.tm_mday;
|
|
tm.tm_mday = ico->recur->u.month_day;
|
|
t = mktime (&tm);
|
|
if (time_in_range (t, start, end) && recur_in_range (current, ico->recur))
|
|
if (!generate (ico, t, cb, closure))
|
|
return;
|
|
|
|
/* Advance by the appropriate number of months */
|
|
|
|
tm.tm_mday = p;
|
|
tm.tm_mon += ico->recur->interval;
|
|
current = mktime (&tm);
|
|
|
|
if (current == -1) {
|
|
g_warning ("RECUR_MONTHLY_BY_DAY: mktime error\n");
|
|
return;
|
|
}
|
|
} while (current < end || (end == 0));
|
|
|
|
break;
|
|
|
|
case RECUR_YEARLY_BY_MONTH:
|
|
case RECUR_YEARLY_BY_DAY:
|
|
do {
|
|
if (time_in_range (current, start, end) && recur_in_range (current, ico->recur))
|
|
if (!generate (ico, current, cb, closure))
|
|
return;
|
|
|
|
/* Advance */
|
|
|
|
current = time_add_year (current, ico->recur->interval);
|
|
} while (current < end || (end == 0));
|
|
|
|
break;
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
}
|
|
|
|
static int
|
|
duration_callback (iCalObject *ico, time_t start, time_t end, void *closure)
|
|
{
|
|
int *count = closure;
|
|
struct tm tm;
|
|
|
|
tm = *localtime (&start);
|
|
|
|
(*count)++;
|
|
if (ico->recur->duration == *count) {
|
|
ico->recur->enddate = time_day_end (end);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* Computes ico->recur->enddate from ico->recur->duration */
|
|
void
|
|
ical_object_compute_end (iCalObject *ico)
|
|
{
|
|
int count = 0;
|
|
|
|
g_return_if_fail (ico->recur != NULL);
|
|
|
|
ico->recur->_enddate = 0;
|
|
ico->recur->enddate = 0;
|
|
ical_object_generate_events (ico, ico->dtstart, 0, duration_callback, &count);
|
|
}
|
|
|
|
int
|
|
alarm_compute_offset (CalendarAlarm *a)
|
|
{
|
|
if (!a->enabled)
|
|
return -1;
|
|
switch (a->units){
|
|
case ALARM_MINUTES:
|
|
a->offset = a->count * 60;
|
|
break;
|
|
case ALARM_HOURS:
|
|
a->offset = a->count * 3600;
|
|
break;
|
|
case ALARM_DAYS:
|
|
a->offset = a->count * 24 * 3600;
|
|
}
|
|
return a->offset;
|
|
}
|
|
|
|
iCalObject *
|
|
ical_object_new_from_string (const char *vcal_string)
|
|
{
|
|
iCalObject *ical = NULL;
|
|
VObject *cal, *event;
|
|
VObjectIterator i;
|
|
const char *object_name;
|
|
|
|
cal = Parse_MIME (vcal_string, strlen (vcal_string));
|
|
|
|
initPropIterator (&i, cal);
|
|
|
|
while (moreIteration (&i)){
|
|
event = nextVObject (&i);
|
|
|
|
object_name = vObjectName (event);
|
|
|
|
if (strcmp (object_name, VCEventProp) == 0){
|
|
ical = ical_object_create_from_vobject (event, object_name);
|
|
break;
|
|
}
|
|
}
|
|
|
|
cleanVObject (cal);
|
|
cleanStrTbl ();
|
|
|
|
return ical;
|
|
}
|
|
|
|
/**
|
|
* ical_object_find_in_string:
|
|
* @uid: Unique identifier of the sought object.
|
|
* @vcalobj: String representation of a complete calendar object.
|
|
* @ico: The resulting #iCalObject is stored here.
|
|
*
|
|
* Parses a complete vCalendar object string and tries to find the calendar
|
|
* object that matches the specified @uid. If found, it stores the resulting
|
|
* #iCalObject in the @ico parameter.
|
|
*
|
|
* Return value: A result code depending on whether the parse and search were
|
|
* successful.
|
|
**/
|
|
CalObjFindStatus
|
|
ical_object_find_in_string (const char *uid, const char *vcalobj, iCalObject **ico)
|
|
{
|
|
VObject *vcal;
|
|
VObjectIterator i;
|
|
CalObjFindStatus status;
|
|
|
|
g_return_val_if_fail (uid != NULL, CAL_OBJ_FIND_SYNTAX_ERROR);
|
|
g_return_val_if_fail (vcalobj != NULL, CAL_OBJ_FIND_SYNTAX_ERROR);
|
|
g_return_val_if_fail (ico != NULL, CAL_OBJ_FIND_SYNTAX_ERROR);
|
|
|
|
*ico = NULL;
|
|
status = CAL_OBJ_FIND_NOT_FOUND;
|
|
|
|
vcal = Parse_MIME (vcalobj, strlen (vcalobj));
|
|
|
|
if (!vcal)
|
|
return CAL_OBJ_FIND_SYNTAX_ERROR;
|
|
|
|
initPropIterator (&i, vcal);
|
|
|
|
while (moreIteration (&i)) {
|
|
VObject *vobj;
|
|
VObject *uid_prop;
|
|
char *the_str;
|
|
|
|
vobj = nextVObject (&i);
|
|
|
|
uid_prop = isAPropertyOf (vobj, VCUniqueStringProp);
|
|
if (!uid_prop)
|
|
continue;
|
|
|
|
/* str_val() sets the_str to the string representation of the
|
|
* property.
|
|
*/
|
|
str_val (uid_prop);
|
|
|
|
if (strcmp (the_str, uid) == 0) {
|
|
const char *object_name;
|
|
|
|
object_name = vObjectName (vobj);
|
|
*ico = ical_object_create_from_vobject (vobj, object_name);
|
|
|
|
if (*ico)
|
|
status = CAL_OBJ_FIND_SUCCESS;
|
|
}
|
|
|
|
free (the_str);
|
|
|
|
if (status == CAL_OBJ_FIND_SUCCESS)
|
|
break;
|
|
}
|
|
|
|
cleanVObject (vcal);
|
|
cleanStrTbl ();
|
|
|
|
return status;
|
|
}
|