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