X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fevent.c;h=56cee1e077f80ddbbce69da8821537e9f0d3e82c;hb=e935238cffe442d3fa0b530774bc4b3dab934bf7;hp=3ea0806ff5774025242d439b944fb12c2b402f67;hpb=1a15381a3872b89ed3db91fa071147dcedf35871;p=citadel.git diff --git a/webcit/event.c b/webcit/event.c index 3ea0806ff..56cee1e07 100644 --- a/webcit/event.c +++ b/webcit/event.c @@ -1,23 +1,35 @@ /* - * $Id$ + * Editing calendar events. + * + * Copyright (c) 1996-2010 by the citadel.org team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/** - * \defgroup EditCal Editing calendar events. - * \ingroup Calendaring - */ -/*@{*/ + #include "webcit.h" #include "webserver.h" +#include "calendar.h" - -#ifdef WEBCIT_WITH_CALENDAR_SERVICE - -/** - * \brief Display an event by itself (for editing) - * \param supplied_vevent the event to edit - * \param msgnum reference on the citserver +/* + * Display an event by itself (for editing) + * supplied_vevent the event to edit + * msgnum reference on the citserver */ -void display_edit_individual_event(icalcomponent *supplied_vevent, long msgnum) { +void display_edit_individual_event(icalcomponent *supplied_vevent, long msgnum, char *from, + int unread, calview *calv) +{ icalcomponent *vevent; icalproperty *p; icalvalue *v; @@ -31,8 +43,85 @@ void display_edit_individual_event(icalcomponent *supplied_vevent, long msgnum) char attendee_string[SIZ]; char buf[SIZ]; int organizer_is_me = 0; - int i; + int i, j = 0; int sequence = 0; + char weekday_labels[7][32]; + char month_labels[12][32]; + long weekstart = 0; + icalproperty *rrule = NULL; + struct icalrecurrencetype recur; + char weekday_is_selected[7]; + int which_rrmonthtype_is_preselected = 0; + + int rrmday; + int rrmweekday; + + icaltimetype day1; + int weekbase; + int rrmweek; + int rrymweek; + int rrymweekday; + int rrymonth; + int which_rrend_is_preselected; + int which_rryeartype_is_preselected; + + + char *tabnames[3]; + const char *frequency_units[8]; + const char *ordinals[6]; + + frequency_units[0] = _("seconds"); + frequency_units[1] = _("minutes"); + frequency_units[2] = _("hours"); + frequency_units[3] = _("days"); + frequency_units[4] = _("weeks"); + frequency_units[5] = _("months"); + frequency_units[6] = _("years"); + frequency_units[7] = _("never"); + + + ordinals[0] = "0"; + ordinals[1] = _("first"); + ordinals[2] = _("second"); + ordinals[3] = _("third"); + ordinals[4] = _("fourth"); + ordinals[5] = _("fifth"); + + + tabnames[0] = _("Event"); + tabnames[1] = _("Attendees"); + tabnames[2] = _("Recurrence"); + + get_pref_long("weekstart", &weekstart, 17); + if (weekstart > 6) weekstart = 0; + + lprintf(9, "display_edit_individual_event(%ld) calview=%s year=%s month=%s day=%s\n", + msgnum, bstr("calview"), bstr("year"), bstr("month"), bstr("day") + ); + + /* populate the weekday names - begin */ + now = time(NULL); + localtime_r(&now, &tm_now); + while (tm_now.tm_wday != 0) { + now -= 86400L; + localtime_r(&now, &tm_now); + } + for (i=0; i<7; ++i) { + localtime_r(&now, &tm_now); + wc_strftime(weekday_labels[i], 32, "%A", &tm_now); + now += 86400L; + } + /* populate the weekday names - end */ + + /* populate the month names - begin */ + now = 259200L; /* 1970-jan-04 is the first Sunday ever */ + localtime_r(&now, &tm_now); + for (i=0; i<12; ++i) { + localtime_r(&now, &tm_now); + wc_strftime(month_labels[i], 32, "%B", &tm_now); + now += 2678400L; + } + /* populate the month names - end */ now = time(NULL); strcpy(organizer_string, ""); @@ -40,7 +129,11 @@ void display_edit_individual_event(icalcomponent *supplied_vevent, long msgnum) if (supplied_vevent != NULL) { vevent = supplied_vevent; - /** + + /* Convert all timestamps to UTC to make them easier to process. */ + ical_dezonify(vevent); + + /* * If we're looking at a fully encapsulated VCALENDAR * rather than a VEVENT component, attempt to use the first * relevant VEVENT subcomponent. If there is none, the @@ -51,8 +144,8 @@ void display_edit_individual_event(icalcomponent *supplied_vevent, long msgnum) if (icalcomponent_isa(vevent) == ICAL_VCALENDAR_COMPONENT) { display_edit_individual_event( icalcomponent_get_first_component( - vevent, ICAL_VEVENT_COMPONENT - ), msgnum + vevent, ICAL_VEVENT_COMPONENT), + msgnum, from, unread, NULL ); return; } @@ -62,107 +155,79 @@ void display_edit_individual_event(icalcomponent *supplied_vevent, long msgnum) created_new_vevent = 1; } - /** Learn the sequence */ + /* Learn the sequence */ p = icalcomponent_get_first_property(vevent, ICAL_SEQUENCE_PROPERTY); if (p != NULL) { sequence = icalproperty_get_sequence(p); } - /** Begin output */ + /* Begin output */ output_headers(1, 1, 2, 0, 0, 0); - wprintf("
\n" - "
" - ""); - wprintf(_("Add or edit an event")); - wprintf("" - "
\n" - "
\n
\n" - ); - - wprintf("\n" - ); - + wc_printf("
\n"); + wc_printf("

"); + wc_printf(_("Add or edit an event")); + wc_printf("

"); + wc_printf("
\n"); - wprintf("
" - "\n"); + end_tab(0, 3); - /** Attendees */ - wprintf("
\n"); + wc_printf("
\n"); /************************************************************ * Uncomment this to see the UID in calendar events for debugging - wprintf("UID == "); + wc_printf("UID == "); p = icalcomponent_get_first_property(vevent, ICAL_UID_PROPERTY); if (p != NULL) { escputs((char *)icalproperty_get_comment(p)); } - wprintf("
\n"); - wprintf("SEQUENCE == %d
\n", sequence); + wc_printf("
\n"); + wc_printf("SEQUENCE == %d
\n", sequence); *************************************************************/ - wprintf("
\n"); + wc_printf("\n"); + wc_printf("\n", WC->nonce); - wprintf("\n", + wc_printf("\n", msgnum); - wprintf("\n", + wc_printf("\n", bstr("calview")); - wprintf("\n", + wc_printf("\n", bstr("year")); - wprintf("\n", + wc_printf("\n", bstr("month")); - wprintf("\n", + wc_printf("\n", bstr("day")); - /** Put it in a borderless table so it lines up nicely */ - wprintf("\n"); - wprintf("\n"); + wc_printf("\">\n"); - wprintf("\n"); + wc_printf("\">\n"); - wprintf("\n"); + wc_printf("\n"); - /** - * If this is an all-day-event, set the end time to be identical to - * the start time (the hour/minute/second will be set to midnight). - * Otherwise extract or create it. - */ - wprintf("\n"); - - wprintf(""); + wc_printf(""); - /** + /* * For a new event, the user creating the event should be the * organizer. Set this field accordingly. */ if (icalcomponent_get_first_property(vevent, ICAL_ORGANIZER_PROPERTY) == NULL) { - sprintf(organizer_string, "MAILTO:%s", WC->cs_inet_email); + sprintf(organizer_string, "mailto:%s", ChrPtr(WC->cs_inet_email)); icalcomponent_add_property(vevent, icalproperty_new_organizer(organizer_string) ); } - /** + /* * Determine who is the organizer of this event. * We need to determine "me" or "not me." */ organizer = icalcomponent_get_first_property(vevent, ICAL_ORGANIZER_PROPERTY); if (organizer != NULL) { strcpy(organizer_string, icalproperty_get_organizer(organizer)); - if (!strncasecmp(organizer_string, "MAILTO:", 7)) { + if (!strncasecmp(organizer_string, "mailto:", 7)) { strcpy(organizer_string, &organizer_string[7]); striplt(organizer_string); serv_printf("ISME %s", organizer_string); @@ -284,36 +366,36 @@ void display_edit_individual_event(icalcomponent *supplied_vevent, long msgnum) } } - wprintf("\n"); + wc_printf("\n"); - /** Transparency */ - wprintf("\n"); + - wprintf(""); - wprintf(_("Busy")); + /* Done with properties. */ + wc_printf("
"); - wprintf(_("Summary")); - wprintf("\n" - "\n"); + + wc_printf("
"); + wc_printf(_("Summary")); + wc_printf("\n" + "
"); - wprintf(_("Location")); - wprintf("\n" - ""); + wc_printf(_("Location")); + wc_printf("\n" + "
"); - wprintf(_("Start")); - wprintf("\n"); + wc_printf("
"); + wc_printf(_("Start")); + wc_printf("\n"); p = icalcomponent_get_first_property(vevent, ICAL_DTSTART_PROPERTY); if (p != NULL) { t_start = icalproperty_get_dtstart(p); @@ -174,106 +239,123 @@ void display_edit_individual_event(icalcomponent *supplied_vevent, long msgnum) } else { localtime_r(&now, &tm_now); - if (strlen(bstr("year")) > 0) { - tm_now.tm_year = atoi(bstr("year")) - 1900; - tm_now.tm_mon = atoi(bstr("month")) - 1; - tm_now.tm_mday = atoi(bstr("day")); - } - if (strlen(bstr("hour")) > 0) { - tm_now.tm_hour = atoi(bstr("hour")); - tm_now.tm_min = atoi(bstr("minute")); + if (havebstr("year")) { + tm_now.tm_year = ibstr("year") - 1900; + tm_now.tm_mon = ibstr("month") - 1; + tm_now.tm_mday = ibstr("day"); + } + if (havebstr("hour")) { + tm_now.tm_hour = ibstr("hour"); + tm_now.tm_min = ibstr("minute"); tm_now.tm_sec = 0; } else { - tm_now.tm_hour = 9; + tm_now.tm_hour = 0; tm_now.tm_min = 0; tm_now.tm_sec = 0; } t_start = icaltime_from_timet_with_zone( mktime(&tm_now), - ((!strcasecmp(bstr("alldayevent"), "yes")) ? 1 : 0), + ((yesbstr("alldayevent")) ? 1 : 0), icaltimezone_get_utc_timezone() ); t_start.is_utc = 1; } - display_icaltimetype_as_webform(&t_start, "dtstart"); + display_icaltimetype_as_webform(&t_start, "dtstart", 0); - wprintf("%s", - (t_start.is_date ? "CHECKED" : "" ), + (t_start.is_date ? "checked=\"checked\"" : "" ), _("All day event") ); - wprintf("
"); - wprintf(_("End")); - wprintf("\n"); - if (t_start.is_date) { - t_end = t_start; + wc_printf("
"); + wc_printf(_("End")); + wc_printf("\n"); + p = icalcomponent_get_first_property(vevent, + ICAL_DTEND_PROPERTY); + if (p != NULL) { + t_end = icalproperty_get_dtend(p); + + /* + * If this is an all-day-event, the end time is set to real end + * day + 1, so we have to adjust accordingly. + */ + if (t_start.is_date) { + icaltime_adjust(&t_end, -1, 0, 0, 0); + } } else { - p = icalcomponent_get_first_property(vevent, - ICAL_DTEND_PROPERTY); - if (p != NULL) { - t_end = icalproperty_get_dtend(p); + if (created_new_vevent == 1) { + /* set default duration */ + if (t_start.is_date) { + /* + * If this is an all-day-event, set the end time to be identical to + * the start time (the hour/minute/second will be set to midnight). + */ + t_end = t_start; + } + else { + /* + * If this is not an all-day event and there is no + * end time specified, make the default one hour + * from the start time. + */ + t_end = t_start; + t_end.hour += 1; + t_end.second = 0; + t_end = icaltime_normalize(t_end); + /* t_end = icaltime_from_timet(now, 0); */ + } } else { - /** - * If this is not an all-day event and there is no - * end time specified, make the default one hour - * from the start time. + /* + * If an existing event has no end date/time this is + * supposed to mean end = start. */ t_end = t_start; - t_end.hour += 1; - t_end.second = 0; - t_end = icaltime_normalize(t_end); - /* t_end = icaltime_from_timet(now, 0); */ } } - display_icaltimetype_as_webform(&t_end, "dtend"); - wprintf("
"); - wprintf(_("Notes")); - wprintf("\n" - "
"); - wprintf(_("Organizer")); - wprintf(""); + wc_printf("
"); + wc_printf(_("Organizer")); + wc_printf(""); escputs(organizer_string); if (organizer_is_me) { - wprintf(" "); - wprintf(_("(you are the organizer)")); - wprintf("\n"); + wc_printf(" "); + wc_printf(_("(you are the organizer)")); + wc_printf("\n"); } - /** + /* * Transmit the organizer as a hidden field. We don't want the user * to be able to change it, but we do want it fed back to the server, * especially if this is a new event and there is no organizer already * in the calendar object. */ - wprintf(""); + wc_printf("\">"); - wprintf("
"); - wprintf(_("Show time as:")); - wprintf(""); + /* Transparency */ + wc_printf("
"); + wc_printf(_("Show time as:")); + wc_printf(""); p = icalcomponent_get_first_property(vevent, ICAL_TRANSP_PROPERTY); if (p == NULL) { - /** No transparency found. Default to opaque (busy). */ + /* No transparency found. Default to opaque (busy). */ p = icalproperty_new_transp(ICAL_TRANSP_OPAQUE); if (p != NULL) { icalcomponent_add_property(vevent, p); @@ -326,91 +408,373 @@ void display_edit_individual_event(icalcomponent *supplied_vevent, long msgnum) v = NULL; } - wprintf(""); - wprintf(_("Free")); - wprintf("  "); + wc_printf(""); + wc_printf(_("Free")); + wc_printf("  "); + + wc_printf(""); + wc_printf(_("Busy")); + + wc_printf("
\n"); - wprintf("
"); - wprintf(_("Attendees")); - wprintf("
" - ""); - wprintf(_("(One per line)")); - wprintf("\n"); + /* Attendees tab (need to move things here) */ + begin_tab(1, 3); + wc_printf("\n"); /* same table style as the event tab */ + wc_printf("\n"); + wc_printf("\n"); + wc_printf("
"); + wc_printf(_("Attendees")); + wc_printf("
" + ""); + wc_printf(_("(One per line)")); + wc_printf("\n"); - /** Pop open an address book -- begin **/ - wprintf( + /* Pop open an address book -- begin */ + wc_printf( " " - "" + "" "", _("Attendees"), _("Contacts") ); - /** Pop open an address book -- end **/ - - wprintf("
" - "
\n"); + end_tab(1, 3); + + /* Recurrence tab */ + begin_tab(2, 3); + + rrule = icalcomponent_get_first_property(vevent, ICAL_RRULE_PROPERTY); + if (rrule) { + recur = icalproperty_get_rrule(rrule); + } + else { + /* blank recurrence with some sensible defaults */ + memset(&recur, 0, sizeof(struct icalrecurrencetype)); + recur.count = 3; + recur.until = icaltime_null_time(); + recur.interval = 1; + recur.freq = ICAL_WEEKLY_RECURRENCE; + } + + wc_printf("%s", + (rrule ? "checked=\"checked\"" : "" ), + _("This is a recurring event") + ); + + wc_printf("
\n"); /* begin 'rrule_div' div */ + + wc_printf("\n"); + + wc_printf("\n"); + + + which_rrend_is_preselected = 0; + if (!icaltime_is_null_time(recur.until)) which_rrend_is_preselected = 2; + if (recur.count > 0) which_rrend_is_preselected = 1; + + wc_printf("\n"); + + wc_printf("
"); + wc_printf(_("Recurrence rule")); + wc_printf(""); + + if ((recur.freq < 0) || (recur.freq > 6)) recur.freq = 4; + wc_printf("%s ", _("Repeats every")); + + wc_printf(" ", recur.interval); + + wc_printf("\n"); + + wc_printf("
"); /* begin 'weekday_selector' div */ + wc_printf("%s
", _("on these weekdays:")); + + memset(weekday_is_selected, 0, 7); + + for (i=0; i%s\n", weekday_labels[i]); + } + wc_printf("
\n"); /* end 'weekday_selector' div */ + + + + + + wc_printf("
"); /* begin 'monthday_selector' div */ + + wc_printf("", + ((which_rrmonthtype_is_preselected == 0) ? "checked='checked'" : "") + ); + + rrmday = t_start.day; + rrmweekday = icaltime_day_of_week(t_start) - 1; + + /* Figure out what week of the month we're in */ + day1 = t_start; + day1.day = 1; + weekbase = icaltime_week_number(day1); + rrmweek = icaltime_week_number(t_start) - weekbase + 1; + + /* Are we going by day of the month or week/day? */ + + if (recur.by_month_day[0] != ICAL_RECURRENCE_ARRAY_MAX) { + which_rrmonthtype_is_preselected = 0; + rrmday = recur.by_month_day[0]; + } + else if (recur.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) { + which_rrmonthtype_is_preselected = 1; + rrmweek = icalrecurrencetype_day_position(recur.by_day[0]); + rrmweekday = icalrecurrencetype_day_day_of_week(recur.by_day[0]) - 1; + } + + wc_printf(_("on day %s%d%s of the month"), "", rrmday, ""); + wc_printf("
\n"); + + wc_printf("", + ((which_rrmonthtype_is_preselected == 1) ? "checked='checked'" : "") + ); + + wc_printf(_("on the ")); + wc_printf(" \n"); + + wc_printf(""); + + wc_printf(" %s
\n", _("of the month")); + + wc_printf("
\n"); /* end 'monthday_selector' div */ + + + rrymweek = rrmweek; + rrymweekday = rrmweekday; + rrymonth = t_start.month; + which_rryeartype_is_preselected = 0; + + if ( + (recur.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) + && (recur.by_day[0] != 0) + && (recur.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX) + && (recur.by_month[0] != 0) + ) { + which_rryeartype_is_preselected = 1; + rrymweek = icalrecurrencetype_day_position(recur.by_day[0]); + rrymweekday = icalrecurrencetype_day_day_of_week(recur.by_day[0]) - 1; + rrymonth = recur.by_month[0]; + } + + wc_printf("
"); /* begin 'yearday_selector' div */ + + wc_printf("", + ((which_rryeartype_is_preselected == 0) ? "checked='checked'" : "") + ); + wc_printf(_("every ")); + wc_printf("%s
", _("year on this date")); + + wc_printf("", + ((which_rryeartype_is_preselected == 1) ? "checked='checked'" : "") + ); + + wc_printf(_("on the ")); + wc_printf(" \n"); + + wc_printf(""); + + wc_printf(" %s ", _("of")); + + wc_printf(""); + wc_printf("
\n"); + + wc_printf("
\n"); /* end 'yearday_selector' div */ + + wc_printf("
"); + wc_printf(_("Recurrence range")); + wc_printf("\n"); + + wc_printf("", + ((which_rrend_is_preselected == 0) ? "checked='checked'" : "") + ); + wc_printf("%s
\n", _("No ending date")); + + wc_printf("", + ((which_rrend_is_preselected == 1) ? "checked='checked'" : "") + ); + wc_printf(_("Repeat this event")); + wc_printf(" ", recur.count); + wc_printf(_("times")); + wc_printf("
\n"); + + wc_printf("", + ((which_rrend_is_preselected == 2) ? "checked='checked'" : "") + ); + wc_printf(_("Repeat this event until ")); + + if (icaltime_is_null_time(recur.until)) { + recur.until = icaltime_add(t_start, icaldurationtype_from_int(604800)); + } + display_icaltimetype_as_webform(&recur.until, "rruntil", 1); + wc_printf("
\n"); + + wc_printf("
\n"); + wc_printf("
\n"); /* end 'rrule' div */ + + end_tab(2, 3); - /** Done with properties. */ - wprintf("
\n
" - "" + /* submit buttons (common area beneath the tabs) */ + begin_tab(3, 3); + wc_printf("
" + "" "  " - "\n" + "\n" "  " - "\n" + "\n" "  " - "\n" - "
\n", + "\n" + "
\n", _("Save"), _("Delete"), _("Check attendee availability"), _("Cancel") ); + end_tab(3, 3); + wc_printf("\n"); - wprintf("\n"); - - wprintf("
\n"); - wprintf("\n" + StrBufAppendPrintf(WC->trailing_javascript, + "eventEditAllDay(); \n" + "RecurrenceShowHide(); \n" + "EnableOrDisableCheckButton(); \n" ); - address_book_popup(); wDumpContent(1); @@ -419,12 +783,14 @@ void display_edit_individual_event(icalcomponent *supplied_vevent, long msgnum) } } -/** - * \brief Save an edited event - * \param supplied_vevent the event to save - * \param msgnum the index on the citserver +/* + * Save an edited event + * + * supplied_vevent: the event to save + * msgnum: the index on the citserver */ -void save_individual_event(icalcomponent *supplied_vevent, long msgnum) { +void save_individual_event(icalcomponent *supplied_vevent, long msgnum, char *from, + int unread, calview *calv) { char buf[SIZ]; icalproperty *prop; icalcomponent *vevent, *encaps; @@ -442,7 +808,11 @@ void save_individual_event(icalcomponent *supplied_vevent, long msgnum) { if (supplied_vevent != NULL) { vevent = supplied_vevent; - /** + + /* Convert all timestamps to UTC to make them easier to process. */ + ical_dezonify(vevent); + + /* * If we're looking at a fully encapsulated VCALENDAR * rather than a VEVENT component, attempt to use the first * relevant VEVENT subcomponent. If there is none, the @@ -453,8 +823,8 @@ void save_individual_event(icalcomponent *supplied_vevent, long msgnum) { if (icalcomponent_isa(vevent) == ICAL_VCALENDAR_COMPONENT) { save_individual_event( icalcomponent_get_first_component( - vevent, ICAL_VEVENT_COMPONENT - ), msgnum + vevent, ICAL_VEVENT_COMPONENT), + msgnum, from, unread, NULL ); return; } @@ -464,10 +834,10 @@ void save_individual_event(icalcomponent *supplied_vevent, long msgnum) { created_new_vevent = 1; } - if ( (strlen(bstr("save_button")) > 0) - || (strlen(bstr("check_button")) > 0) ) { + if ( (havebstr("save_button")) + || (havebstr("check_button")) ) { - /** Replace values in the component with ones from the form */ + /* Replace values in the component with ones from the form */ while (prop = icalcomponent_get_first_property(vevent, ICAL_SUMMARY_PROPERTY), prop != NULL) { @@ -475,21 +845,25 @@ void save_individual_event(icalcomponent *supplied_vevent, long msgnum) { icalproperty_free(prop); } - if (strlen(bstr("summary")) > 0) { - + /* Add NOW() to the calendar object... */ + icalcomponent_set_dtstamp(vevent, + icaltime_from_timet( + time(NULL), 0)); + + if (havebstr("summary")) { icalcomponent_add_property(vevent, icalproperty_new_summary(bstr("summary"))); } else { icalcomponent_add_property(vevent, - icalproperty_new_summary("Untitled Event")); + icalproperty_new_summary(_("Untitled Event"))); } - + while (prop = icalcomponent_get_first_property(vevent, ICAL_LOCATION_PROPERTY), prop != NULL) { icalcomponent_remove_property(vevent, prop); icalproperty_free(prop); } - if (strlen(bstr("location")) > 0) { + if (havebstr("location")) { icalcomponent_add_property(vevent, icalproperty_new_location(bstr("location"))); } @@ -498,7 +872,7 @@ void save_individual_event(icalcomponent *supplied_vevent, long msgnum) { icalcomponent_remove_property(vevent, prop); icalproperty_free(prop); } - if (strlen(bstr("description")) > 0) { + if (havebstr("description")) { icalcomponent_add_property(vevent, icalproperty_new_description(bstr("description"))); } @@ -509,7 +883,7 @@ void save_individual_event(icalcomponent *supplied_vevent, long msgnum) { icalproperty_free(prop); } - if (!strcmp(bstr("alldayevent"), "yes")) { + if (yesbstr("alldayevent")) { all_day_event = 1; } else { @@ -523,19 +897,11 @@ void save_individual_event(icalcomponent *supplied_vevent, long msgnum) { icaltime_from_webform(&event_start, "dtstart"); } - /** - * The following odd-looking snippet of code looks like it - * takes some unnecessary steps. It is done this way because - * libical incorrectly turns an "all day event" into a normal - * event starting at midnight (i.e. it serializes as date/time - * instead of just date) unless icalvalue_new_date() is used. - * So we force it, if this is an all day event. - */ prop = icalproperty_new_dtstart(event_start); + if (all_day_event) { - icalproperty_set_value(prop, - icalvalue_new_date(event_start) - ); + /* Force it to serialize as a date-only rather than date/time */ + icalproperty_set_value(prop, icalvalue_new_date(event_start)); } if (prop) icalcomponent_add_property(vevent, prop); @@ -552,16 +918,106 @@ void save_individual_event(icalcomponent *supplied_vevent, long msgnum) { icalproperty_free(prop); } - if (all_day_event == 0) { - icaltime_from_webform(&t, "dtend"); - icalcomponent_add_property(vevent, - icalproperty_new_dtend(icaltime_normalize(t) - ) - ); + if (all_day_event) { + icaltime_from_webform_dateonly(&t, "dtend"); + + /* with this field supposed to be non-inclusive we have to add one day */ + icaltime_adjust(&t, 1, 0, 0, 0); + } + else { + icaltime_from_webform(&t, "dtend"); } - /** See if transparency is indicated */ - if (strlen(bstr("transp")) > 0) { + icalcomponent_add_property(vevent, + icalproperty_new_dtend(icaltime_normalize(t) + ) + ); + + /* recurrence rules -- begin */ + + /* remove any existing rule */ + while (prop = icalcomponent_get_first_property(vevent, ICAL_RRULE_PROPERTY), prop != NULL) { + icalcomponent_remove_property(vevent, prop); + icalproperty_free(prop); + } + + if (yesbstr("is_recur")) { + struct icalrecurrencetype recur; + icalrecurrencetype_clear(&recur); + + recur.interval = atoi(bstr("interval")); + recur.freq = atoi(bstr("freq")); + + switch(recur.freq) { + + /* These can't happen; they're disabled. */ + case ICAL_SECONDLY_RECURRENCE: + break; + case ICAL_MINUTELY_RECURRENCE: + break; + case ICAL_HOURLY_RECURRENCE: + break; + + /* Daily is valid but there are no further inputs. */ + case ICAL_DAILY_RECURRENCE: + break; + + /* These are the real options. */ + + case ICAL_WEEKLY_RECURRENCE: + j=0; + for (i=0; i<7; ++i) { + snprintf(buf, sizeof buf, "weekday%d", i); + if (YESBSTR(buf)) recur.by_day[j++] = + icalrecurrencetype_day_day_of_week(i+1); + } + recur.by_day[j++] = ICAL_RECURRENCE_ARRAY_MAX; + break; + + case ICAL_MONTHLY_RECURRENCE: + if (!strcasecmp(bstr("rrmonthtype"), "rrmonthtype_mday")) { + recur.by_month_day[0] = event_start.day; + recur.by_month_day[1] = ICAL_RECURRENCE_ARRAY_MAX; + } + else if (!strcasecmp(bstr("rrmonthtype"), "rrmonthtype_wday")) { + recur.by_day[0] = (atoi(bstr("rrmweek")) * 8) + + atoi(bstr("rrmweekday")) + 1; + recur.by_day[1] = ICAL_RECURRENCE_ARRAY_MAX; + } + break; + + case ICAL_YEARLY_RECURRENCE: + if (!strcasecmp(bstr("rryeartype"), "rryeartype_ymday")) { + /* no further action is needed here */ + } + else if (!strcasecmp(bstr("rryeartype"), "rryeartype_ywday")) { + recur.by_month[0] = atoi(bstr("rrymonth")); + recur.by_month[1] = ICAL_RECURRENCE_ARRAY_MAX; + recur.by_day[0] = (atoi(bstr("rrymweek")) * 8) + + atoi(bstr("rrymweekday")) + 1; + recur.by_day[1] = ICAL_RECURRENCE_ARRAY_MAX; + } + break; + + /* This one can't happen either. */ + case ICAL_NO_RECURRENCE: + break; + } + + if (!strcasecmp(bstr("rrend"), "rrend_count")) { + recur.count = atoi(bstr("rrcount")); + } + else if (!strcasecmp(bstr("rrend"), "rrend_until")) { + icaltime_from_webform_dateonly(&recur.until, "rruntil"); + } + + icalcomponent_add_property(vevent, icalproperty_new_rrule(recur)); + } + + /* recurrence rules -- end */ + + /* See if transparency is indicated */ + if (havebstr("transp")) { if (!strcasecmp(bstr("transp"), "opaque")) { formtransp = ICAL_TRANSP_OPAQUE; } @@ -575,48 +1031,39 @@ void save_individual_event(icalcomponent *supplied_vevent, long msgnum) { icalproperty_free(prop); } - lprintf(9, "adding new property...\n"); icalcomponent_add_property(vevent, icalproperty_new_transp(formtransp)); - lprintf(9, "...added it.\n"); } - /** Give this event a UID if it doesn't have one. */ - lprintf(9, "Give this event a UID if it doesn't have one.\n"); + /* Give this event a UID if it doesn't have one. */ if (icalcomponent_get_first_property(vevent, ICAL_UID_PROPERTY) == NULL) { generate_uuid(buf); - icalcomponent_add_property(vevent, - icalproperty_new_uid(buf) - ); + icalcomponent_add_property(vevent, icalproperty_new_uid(buf)); } - /** Increment the sequence ID */ - lprintf(9, "Increment the sequence ID\n"); + /* Increment the sequence ID */ while (prop = icalcomponent_get_first_property(vevent, ICAL_SEQUENCE_PROPERTY), (prop != NULL) ) { i = icalproperty_get_sequence(prop); - lprintf(9, "Sequence was %d\n", i); if (i > sequence) sequence = i; icalcomponent_remove_property(vevent, prop); icalproperty_free(prop); } ++sequence; - lprintf(9, "New sequence is %d. Adding...\n", sequence); icalcomponent_add_property(vevent, icalproperty_new_sequence(sequence) ); - - /** + + /* * Set the organizer, only if one does not already exist *and* * the form is supplying one */ - lprintf(9, "Setting the organizer...\n"); strcpy(buf, bstr("organizer")); if ( (icalcomponent_get_first_property(vevent, - ICAL_ORGANIZER_PROPERTY) == NULL) - && (strlen(buf) > 0) ) { + ICAL_ORGANIZER_PROPERTY) == NULL) + && (!IsEmptyStr(buf)) ) { - /** set new organizer */ + /* set new organizer */ sprintf(organizer_string, "MAILTO:%s", buf); icalcomponent_add_property(vevent, icalproperty_new_organizer(organizer_string) @@ -624,14 +1071,13 @@ void save_individual_event(icalcomponent *supplied_vevent, long msgnum) { } - /** + /* * Add any new attendees listed in the web form */ - lprintf(9, "Add any new attendees\n"); /* First, strip out the parenthesized partstats. */ strcpy(form_attendees, bstr("attendees")); - stripout(form_attendees, '(', ')'); + while ( stripout(form_attendees, '(', ')') != 0); /* Next, change any commas to newlines, because we want newline-separated attendees. */ j = strlen(form_attendees); @@ -644,12 +1090,11 @@ void save_individual_event(icalcomponent *supplied_vevent, long msgnum) { } } - /** Now iterate! */ + /* Now iterate! */ for (i=0; i 0) { - lprintf(9, "Attendee: <%s>\n", buf); + if (!IsEmptyStr(buf)) { sprintf(attendee_string, "MAILTO:%s", buf); foundit = 0; @@ -668,11 +1113,10 @@ void save_individual_event(icalcomponent *supplied_vevent, long msgnum) { } } - /** + /* * Remove any attendees *not* listed in the web form */ -STARTOVER: lprintf(9, "Remove unlisted attendees\n"); - for (attendee = icalcomponent_get_first_property(vevent, ICAL_ATTENDEE_PROPERTY); attendee != NULL; attendee = icalcomponent_get_next_property(vevent, ICAL_ATTENDEE_PROPERTY)) { +STARTOVER: for (attendee = icalcomponent_get_first_property(vevent, ICAL_ATTENDEE_PROPERTY); attendee != NULL; attendee = icalcomponent_get_next_property(vevent, ICAL_ATTENDEE_PROPERTY)) { strcpy(attendee_string, icalproperty_get_attendee(attendee)); if (!strncasecmp(attendee_string, "MAILTO:", 7)) { strcpy(attendee_string, &attendee_string[7]); @@ -691,22 +1135,20 @@ STARTOVER: lprintf(9, "Remove unlisted attendees\n"); } } - /** + /* * Encapsulate event into full VCALENDAR component. Clone it first, * for two reasons: one, it's easier to just free the whole thing * when we're done instead of unbundling, but more importantly, we * can't encapsulate something that may already be encapsulated * somewhere else. */ - lprintf(9, "Encapsulating into full VCALENDAR component\n"); encaps = ical_encapsulate_subcomponent(icalcomponent_new_clone(vevent)); /* Set the method to PUBLISH */ icalcomponent_set_method(encaps, ICAL_METHOD_PUBLISH); - /** If the user clicked 'Save' then save it to the server. */ - lprintf(9, "Serializing it for saving\n"); - if ( (encaps != NULL) && (strlen(bstr("save_button")) > 0) ) { + /* If the user clicked 'Save' then save it to the server. */ + if ( (encaps != NULL) && (havebstr("save_button")) ) { serv_puts("ENT0 1|||4|||1|"); serv_getln(buf, sizeof buf); if (buf[0] == '8') { @@ -717,35 +1159,40 @@ STARTOVER: lprintf(9, "Remove unlisted attendees\n"); } if ( (buf[0] == '8') || (buf[0] == '4') ) { while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { - lprintf(9, "ENT0 REPLY: %s\n", buf); } } if (buf[0] == '2') { strcpy(WC->ImportantMessage, &buf[4]); } + icalmemory_free_ring (); icalcomponent_free(encaps); + encaps = NULL; } - /** Or, check attendee availability if the user asked for that. */ - if ( (encaps != NULL) && (strlen(bstr("check_button")) > 0) ) { + /* Or, check attendee availability if the user asked for that. */ + if ( (encaps != NULL) && (havebstr("check_button")) ) { - /** Call this function, which does the real work */ + /* Call this function, which does the real work */ check_attendee_availability(encaps); - /** This displays the form again, with our annotations */ - display_edit_individual_event(encaps, msgnum); + /* This displays the form again, with our annotations */ + display_edit_individual_event(encaps, msgnum, from, unread, NULL); icalcomponent_free(encaps); + encaps = NULL; + } + if (encaps != NULL) { + icalcomponent_free(encaps); + encaps = NULL; } } - /** + /* * If the user clicked 'Delete' then delete it. */ - lprintf(9, "Checking to see if we have to delete an old event\n"); - if ( (strlen(bstr("delete_button")) > 0) && (msgnum > 0L) ) { - serv_printf("DELE %ld", atol(bstr("msgnum"))); + if ( (havebstr("delete_button")) && (msgnum > 0L) ) { + serv_printf("DELE %ld", lbstr("msgnum")); serv_getln(buf, sizeof buf); } @@ -753,13 +1200,13 @@ STARTOVER: lprintf(9, "Remove unlisted attendees\n"); icalcomponent_free(vevent); } - /** If this was a save or delete, go back to the calendar view. */ - if (strlen(bstr("check_button")) == 0) { - readloop("readfwd"); + /* If this was a save or delete, go back to the calendar or summary view. */ + if (!havebstr("check_button")) { + if (!strcasecmp(bstr("calview"), "summary")) { + summary(); + } + else { + readloop(readfwd, eUseDefault); + } } } - - -#endif /* WEBCIT_WITH_CALENDAR_SERVICE */ - -/*@}*/