2 * Miscellaneous functions which handle calendar components.
4 * Copyright (c) 1996-2010 by the citadel.org team
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "webserver.h"
27 "12am", "1am", "2am", "3am", "4am", "5am", "6am",
28 "7am", "8am", "9am", "10am", "11am", "12pm",
29 "1pm", "2pm", "3pm", "4pm", "5pm", "6pm",
30 "7pm", "8pm", "9pm", "10pm", "11pm"
34 * The display_icaltimetype_as_webform() and icaltime_from_webform() functions
35 * handle the display and editing of date/time properties in web pages. The
36 * first one converts an icaltimetype into valid HTML markup -- a series of form
37 * fields for editing the date and time. When the user submits the form, the
38 * results can be fed back into the second function, which turns it back into
39 * an icaltimetype. The "prefix" string required by both functions is prepended
40 * to all field names. This allows a form to contain more than one date/time
41 * property (for example, a start and end time) by ensuring the field names are
42 * unique within the form.
44 * NOTE: These functions assume that the icaltimetype being edited is in UTC, and
45 * will convert to/from local time for editing. "local" in this case is assumed
46 * to be the time zone in which the WebCit server is running. A future improvement
47 * might be to allow the user to specify his/her timezone.
50 void display_icaltimetype_as_webform(struct icaltimetype *t, char *prefix, int date_only) {
58 int all_day_event = 0;
62 time_format = get_time_format_cached ();
65 localtime_r(&now, &tm_now);
66 this_year = tm_now.tm_year + 1900;
68 if (t == NULL) return;
69 if (t->is_date) all_day_event = 1;
70 tt = icaltime_as_timet(*t);
75 localtime_r(&tt, &tm);
78 wc_printf("<input type=\"text\" name=\"");
79 StrBufAppendBufPlain(WCC->WBuf, prefix, -1, 0);
80 wc_printf("\" id=\"");
81 StrBufAppendBufPlain(WCC->WBuf, prefix, -1, 0);
82 wc_printf("\" size=\"10\" maxlength=\"10\" value=\"");
83 wc_strftime(timebuf, 32, "%Y-%m-%d", &tm);
84 StrBufAppendBufPlain(WCC->WBuf, timebuf, -1, 0);
87 StrBufAppendPrintf(WC->trailing_javascript, "attachDatePicker('");
88 StrBufAppendPrintf(WC->trailing_javascript, prefix);
89 StrBufAppendPrintf(WC->trailing_javascript, "', '%s');\n", get_selected_language());
91 /* If we're editing a date only, we still generate the time boxes, but we hide them.
92 * This keeps the data model consistent.
95 wc_printf("<div style=\"display:none\">");
98 wc_printf("<span ID=\"");
99 StrBufAppendBufPlain(WCC->WBuf, prefix, -1, 0);
100 wc_printf("_time\">");
101 wc_printf(_("Hour: "));
102 wc_printf("<SELECT NAME=\"%s_hour\" SIZE=\"1\">\n", prefix);
103 for (i=0; i<=23; ++i) {
105 if (time_format == WC_TIMEFORMAT_24) {
106 wc_printf("<OPTION %s VALUE=\"%d\">%d</OPTION>\n",
107 ((tm.tm_hour == i) ? "SELECTED" : ""),
112 wc_printf("<OPTION %s VALUE=\"%d\">%s</OPTION>\n",
113 ((tm.tm_hour == i) ? "SELECTED" : ""),
119 wc_printf("</SELECT>\n");
121 wc_printf(_("Minute: "));
122 wc_printf("<SELECT NAME=\"%s_minute\" SIZE=\"1\">\n", prefix);
123 for (i=0; i<=59; ++i) {
124 if ( (i % 5 == 0) || (tm.tm_min == i) ) {
125 wc_printf("<OPTION %s VALUE=\"%d\">:%02d</OPTION>\n",
126 ((tm.tm_min == i) ? "SELECTED" : ""),
131 wc_printf("</SELECT></span>\n");
139 * Get date/time from a web form and convert it into an icaltimetype struct.
141 void icaltime_from_webform(struct icaltimetype *t, char *prefix) {
146 /* Stuff with zero values */
147 memset(t, 0, sizeof(struct icaltimetype));
149 /* Get the year/month/date all in one shot -- it will be in ISO YYYY-MM-DD format */
150 sscanf((char*)BSTR(prefix), "%04d-%02d-%02d", &t->year, &t->month, &t->day);
153 sprintf(vname, "%s_hour", prefix);
154 t->hour = IBSTR(vname);
157 sprintf(vname, "%s_minute", prefix);
158 t->minute = IBSTR(vname);
160 /* time zone is set to the default zone for this server */
163 t->zone = get_default_icaltimezone();
168 * Get date (no time) from a web form and convert it into an icaltimetype struct.
170 void icaltime_from_webform_dateonly(struct icaltimetype *t, char *prefix) {
173 /* Stuff with zero values */
174 memset(t, 0, sizeof(struct icaltimetype));
176 /* Get the year/month/date all in one shot -- it will be in ISO YYYY-MM-DD format */
177 sscanf((char*)BSTR(prefix), "%04d-%02d-%02d", &t->year, &t->month, &t->day);
179 /* time zone is set to the default zone for this server */
186 * Render a PARTSTAT parameter as a string (and put it in parentheses)
188 void partstat_as_string(char *buf, icalproperty *attendee) {
189 icalparameter *partstat_param;
190 icalparameter_partstat partstat;
192 strcpy(buf, _("(status unknown)"));
194 partstat_param = icalproperty_get_first_parameter(
196 ICAL_PARTSTAT_PARAMETER
198 if (partstat_param == NULL) {
202 partstat = icalparameter_get_partstat(partstat_param);
204 case ICAL_PARTSTAT_X:
207 case ICAL_PARTSTAT_NEEDSACTION:
208 strcpy(buf, _("(needs action)"));
210 case ICAL_PARTSTAT_ACCEPTED:
211 strcpy(buf, _("(accepted)"));
213 case ICAL_PARTSTAT_DECLINED:
214 strcpy(buf, _("(declined)"));
216 case ICAL_PARTSTAT_TENTATIVE:
217 strcpy(buf, _("(tenative)"));
219 case ICAL_PARTSTAT_DELEGATED:
220 strcpy(buf, _("(delegated)"));
222 case ICAL_PARTSTAT_COMPLETED:
223 strcpy(buf, _("(completed)"));
225 case ICAL_PARTSTAT_INPROCESS:
226 strcpy(buf, _("(in process)"));
228 case ICAL_PARTSTAT_NONE:
229 strcpy(buf, _("(none)"));
235 * Utility function to encapsulate a subcomponent into a full VCALENDAR.
237 * We also scan for any date/time properties that reference timezones, and attach
238 * those timezones along with the supplied subcomponent. (Increase the size of the array if you need to.)
240 * Note: if you change anything here, change it in Citadel server's ical_send_out_invitations() too.
242 icalcomponent *ical_encapsulate_subcomponent(icalcomponent *subcomp) {
243 icalcomponent *encaps;
245 struct icaltimetype t;
246 const icaltimezone *attached_zones[5] = { NULL, NULL, NULL, NULL, NULL };
248 const icaltimezone *z;
249 int num_zones_attached = 0;
250 int zone_already_attached;
252 if (subcomp == NULL) {
253 lprintf(3, "ERROR: ical_encapsulate_subcomponent() called with NULL argument\n");
258 * If we're already looking at a full VCALENDAR component, this is probably an error.
260 if (icalcomponent_isa(subcomp) == ICAL_VCALENDAR_COMPONENT) {
261 lprintf(3, "ERROR: component sent to ical_encapsulate_subcomponent() already top level\n");
266 for (p = icalcomponent_get_first_property(subcomp, ICAL_ANY_PROPERTY);
268 p = icalcomponent_get_next_property(subcomp, ICAL_ANY_PROPERTY))
270 if ( (icalproperty_isa(p) == ICAL_COMPLETED_PROPERTY)
271 || (icalproperty_isa(p) == ICAL_CREATED_PROPERTY)
272 || (icalproperty_isa(p) == ICAL_DATEMAX_PROPERTY)
273 || (icalproperty_isa(p) == ICAL_DATEMIN_PROPERTY)
274 || (icalproperty_isa(p) == ICAL_DTEND_PROPERTY)
275 || (icalproperty_isa(p) == ICAL_DTSTAMP_PROPERTY)
276 || (icalproperty_isa(p) == ICAL_DTSTART_PROPERTY)
277 || (icalproperty_isa(p) == ICAL_DUE_PROPERTY)
278 || (icalproperty_isa(p) == ICAL_EXDATE_PROPERTY)
279 || (icalproperty_isa(p) == ICAL_LASTMODIFIED_PROPERTY)
280 || (icalproperty_isa(p) == ICAL_MAXDATE_PROPERTY)
281 || (icalproperty_isa(p) == ICAL_MINDATE_PROPERTY)
282 || (icalproperty_isa(p) == ICAL_RECURRENCEID_PROPERTY)
284 t = icalproperty_get_dtstart(p); /*/ it's safe to use dtstart for all of them */
285 if ((icaltime_is_valid_time(t)) && (z=icaltime_get_timezone(t), z)) {
287 zone_already_attached = 0;
288 for (i=0; i<5; ++i) {
289 if (z == attached_zones[i]) {
290 ++zone_already_attached;
291 lprintf(9, "zone already attached!!\n");
294 if ((!zone_already_attached) && (num_zones_attached < 5)) {
295 lprintf(9, "attaching zone %d!\n", num_zones_attached);
296 attached_zones[num_zones_attached++] = z;
299 icalproperty_set_parameter(p,
300 icalparameter_new_tzid(icaltimezone_get_tzid((icaltimezone *)z))
306 /* Encapsulate the VEVENT component into a complete VCALENDAR */
307 encaps = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
308 if (encaps == NULL) {
309 lprintf(3, "ERROR: ical_encapsulate_subcomponent() could not allocate component\n");
313 /* Set the Product ID */
314 icalcomponent_add_property(encaps, icalproperty_new_prodid(PRODID));
316 /* Set the Version Number */
317 icalcomponent_add_property(encaps, icalproperty_new_version("2.0"));
319 /* Attach any timezones we need */
320 if (num_zones_attached > 0) for (i=0; i<num_zones_attached; ++i) {
322 zc = icalcomponent_new_clone(icaltimezone_get_component((icaltimezone *)attached_zones[i]));
323 icalcomponent_add_component(encaps, zc);
326 /* Encapsulate the subcomponent inside */
327 icalcomponent_add_component(encaps, subcomp);
329 /* Return the object we just created. */