2 * Miscellaneous functions which handle calendar components.
4 * Copyright (c) 1996-2012 by the citadel.org team
6 * This program is open source software. You can redistribute it and/or
7 * modify it under the terms of the GNU General Public License, version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 #include "webserver.h"
22 "12am", "1am", "2am", "3am", "4am", "5am", "6am",
23 "7am", "8am", "9am", "10am", "11am", "12pm",
24 "1pm", "2pm", "3pm", "4pm", "5pm", "6pm",
25 "7pm", "8pm", "9pm", "10pm", "11pm"
29 * The display_icaltimetype_as_webform() and icaltime_from_webform() functions
30 * handle the display and editing of date/time properties in web pages. The
31 * first one converts an icaltimetype into valid HTML markup -- a series of form
32 * fields for editing the date and time. When the user submits the form, the
33 * results can be fed back into the second function, which turns it back into
34 * an icaltimetype. The "prefix" string required by both functions is prepended
35 * to all field names. This allows a form to contain more than one date/time
36 * property (for example, a start and end time) by ensuring the field names are
37 * unique within the form.
39 * NOTE: These functions assume that the icaltimetype being edited is in UTC, and
40 * will convert to/from local time for editing. "local" in this case is assumed
41 * to be the time zone in which the WebCit server is running. A future improvement
42 * might be to allow the user to specify his/her timezone.
45 void display_icaltimetype_as_webform(struct icaltimetype *t, char *prefix, int date_only) {
52 int all_day_event = 0;
56 time_format = get_time_format_cached ();
59 localtime_r(&now, &tm_now);
61 if (t == NULL) return;
62 if (t->is_date) all_day_event = 1;
63 tt = icaltime_as_timet(*t);
68 localtime_r(&tt, &tm);
71 wc_printf("<input type=\"date\" name=\"");
72 StrBufAppendBufPlain(WCC->WBuf, prefix, -1, 0);
73 wc_printf("\" id=\"");
74 StrBufAppendBufPlain(WCC->WBuf, prefix, -1, 0);
75 wc_printf("\" size=\"10\" maxlength=\"10\" value=\"");
76 wc_strftime(timebuf, 32, "%Y-%m-%d", &tm);
77 StrBufAppendBufPlain(WCC->WBuf, timebuf, -1, 0);
80 StrBufAppendPrintf(WC->trailing_javascript, "attachDatePicker('");
81 StrBufAppendPrintf(WC->trailing_javascript, prefix);
82 StrBufAppendPrintf(WC->trailing_javascript, "', '%s');\n", get_selected_language());
84 /* If we're editing a date only, we still generate the time boxes, but we hide them.
85 * This keeps the data model consistent.
88 wc_printf("<div style=\"display:none\">");
91 wc_printf("<span ID=\"");
92 StrBufAppendBufPlain(WCC->WBuf, prefix, -1, 0);
93 wc_printf("_time\">");
94 wc_printf(_("Hour: "));
95 wc_printf("<SELECT NAME=\"%s_hour\" SIZE=\"1\">\n", prefix);
96 for (i=0; i<=23; ++i) {
98 if (time_format == WC_TIMEFORMAT_24) {
99 wc_printf("<OPTION %s VALUE=\"%d\">%d</OPTION>\n",
100 ((tm.tm_hour == i) ? "SELECTED" : ""),
105 wc_printf("<OPTION %s VALUE=\"%d\">%s</OPTION>\n",
106 ((tm.tm_hour == i) ? "SELECTED" : ""),
112 wc_printf("</SELECT>\n");
114 wc_printf(_("Minute: "));
115 wc_printf("<SELECT NAME=\"%s_minute\" SIZE=\"1\">\n", prefix);
116 for (i=0; i<=59; ++i) {
117 if ( (i % 5 == 0) || (tm.tm_min == i) ) {
118 wc_printf("<OPTION %s VALUE=\"%d\">:%02d</OPTION>\n",
119 ((tm.tm_min == i) ? "SELECTED" : ""),
124 wc_printf("</SELECT></span>\n");
132 * Get date/time from a web form and convert it into an icaltimetype struct.
134 void icaltime_from_webform(struct icaltimetype *t, char *prefix) {
139 /* Stuff with zero values */
140 memset(t, 0, sizeof(struct icaltimetype));
142 /* Get the year/month/date all in one shot -- it will be in ISO YYYY-MM-DD format */
143 sscanf((char*)BSTR(prefix), "%04d-%02d-%02d", &t->year, &t->month, &t->day);
146 sprintf(vname, "%s_hour", prefix);
147 t->hour = IBSTR(vname);
150 sprintf(vname, "%s_minute", prefix);
151 t->minute = IBSTR(vname);
153 /* time zone is set to the default zone for this server */
155 t->zone = get_default_icaltimezone();
160 * Get date (no time) from a web form and convert it into an icaltimetype struct.
162 void icaltime_from_webform_dateonly(struct icaltimetype *t, char *prefix) {
165 /* Stuff with zero values */
166 memset(t, 0, sizeof(struct icaltimetype));
168 /* Get the year/month/date all in one shot -- it will be in ISO YYYY-MM-DD format */
169 sscanf((char*)BSTR(prefix), "%04d-%02d-%02d", &t->year, &t->month, &t->day);
171 /* time zone is set to the default zone for this server */
172 t->zone = icaltimezone_get_utc_timezone();
178 * Render a PARTSTAT parameter as a string (and put it in parentheses)
180 void partstat_as_string(char *buf, icalproperty *attendee) {
181 icalparameter *partstat_param;
182 icalparameter_partstat partstat;
184 strcpy(buf, _("(status unknown)"));
186 partstat_param = icalproperty_get_first_parameter(
188 ICAL_PARTSTAT_PARAMETER
190 if (partstat_param == NULL) {
194 partstat = icalparameter_get_partstat(partstat_param);
196 case ICAL_PARTSTAT_X:
199 case ICAL_PARTSTAT_NEEDSACTION:
200 strcpy(buf, _("(needs action)"));
202 case ICAL_PARTSTAT_ACCEPTED:
203 strcpy(buf, _("(accepted)"));
205 case ICAL_PARTSTAT_DECLINED:
206 strcpy(buf, _("(declined)"));
208 case ICAL_PARTSTAT_TENTATIVE:
209 strcpy(buf, _("(tenative)"));
211 case ICAL_PARTSTAT_DELEGATED:
212 strcpy(buf, _("(delegated)"));
214 case ICAL_PARTSTAT_COMPLETED:
215 strcpy(buf, _("(completed)"));
217 case ICAL_PARTSTAT_INPROCESS:
218 strcpy(buf, _("(in process)"));
220 case ICAL_PARTSTAT_NONE:
221 strcpy(buf, _("(none)"));
227 * Utility function to encapsulate a subcomponent into a full VCALENDAR.
229 * We also scan for any date/time properties that reference timezones, and attach
230 * those timezones along with the supplied subcomponent. (Increase the size of the array if you need to.)
232 * Note: if you change anything here, change it in Citadel server's ical_send_out_invitations() too.
234 icalcomponent *ical_encapsulate_subcomponent(icalcomponent *subcomp) {
235 icalcomponent *encaps;
237 struct icaltimetype t;
238 const icaltimezone *attached_zones[5] = { NULL, NULL, NULL, NULL, NULL };
240 const icaltimezone *z;
241 int num_zones_attached = 0;
242 int zone_already_attached;
244 if (subcomp == NULL) {
245 syslog(LOG_WARNING, "ERROR: ical_encapsulate_subcomponent() called with NULL argument\n");
250 * If we're already looking at a full VCALENDAR component, this is probably an error.
252 if (icalcomponent_isa(subcomp) == ICAL_VCALENDAR_COMPONENT) {
253 syslog(LOG_WARNING, "ERROR: component sent to ical_encapsulate_subcomponent() already top level\n");
258 for (p = icalcomponent_get_first_property(subcomp, ICAL_ANY_PROPERTY);
260 p = icalcomponent_get_next_property(subcomp, ICAL_ANY_PROPERTY))
262 if ( (icalproperty_isa(p) == ICAL_COMPLETED_PROPERTY)
263 || (icalproperty_isa(p) == ICAL_CREATED_PROPERTY)
264 || (icalproperty_isa(p) == ICAL_DATEMAX_PROPERTY)
265 || (icalproperty_isa(p) == ICAL_DATEMIN_PROPERTY)
266 || (icalproperty_isa(p) == ICAL_DTEND_PROPERTY)
267 || (icalproperty_isa(p) == ICAL_DTSTAMP_PROPERTY)
268 || (icalproperty_isa(p) == ICAL_DTSTART_PROPERTY)
269 || (icalproperty_isa(p) == ICAL_DUE_PROPERTY)
270 || (icalproperty_isa(p) == ICAL_EXDATE_PROPERTY)
271 || (icalproperty_isa(p) == ICAL_LASTMODIFIED_PROPERTY)
272 || (icalproperty_isa(p) == ICAL_MAXDATE_PROPERTY)
273 || (icalproperty_isa(p) == ICAL_MINDATE_PROPERTY)
274 || (icalproperty_isa(p) == ICAL_RECURRENCEID_PROPERTY)
276 t = icalproperty_get_dtstart(p); /*/ it's safe to use dtstart for all of them */
277 if ((icaltime_is_valid_time(t)) && (z=icaltime_get_timezone(t), z)) {
279 zone_already_attached = 0;
280 for (i=0; i<5; ++i) {
281 if (z == attached_zones[i]) {
282 ++zone_already_attached;
283 syslog(LOG_DEBUG, "zone already attached!!\n");
286 if ((!zone_already_attached) && (num_zones_attached < 5)) {
287 syslog(LOG_DEBUG, "attaching zone %d!\n", num_zones_attached);
288 attached_zones[num_zones_attached++] = z;
291 icalproperty_set_parameter(p,
292 icalparameter_new_tzid(icaltimezone_get_tzid((icaltimezone *)z))
298 /* Encapsulate the VEVENT component into a complete VCALENDAR */
299 encaps = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
300 if (encaps == NULL) {
301 syslog(LOG_WARNING, "ERROR: ical_encapsulate_subcomponent() could not allocate component\n");
305 /* Set the Product ID */
306 icalcomponent_add_property(encaps, icalproperty_new_prodid(PRODID));
308 /* Set the Version Number */
309 icalcomponent_add_property(encaps, icalproperty_new_version("2.0"));
311 /* Attach any timezones we need */
312 if (num_zones_attached > 0) for (i=0; i<num_zones_attached; ++i) {
314 zc = icalcomponent_new_clone(icaltimezone_get_component((icaltimezone *)attached_zones[i]));
315 icalcomponent_add_component(encaps, zc);
318 /* Encapsulate the subcomponent inside */
319 icalcomponent_add_component(encaps, subcomp);
321 /* Return the object we just created. */