4 * Miscellaneous functions which handle calendar components.
6 * Copyright (c) 1996-2010 by the citadel.org team
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "webserver.h"
29 "12am", "1am", "2am", "3am", "4am", "5am", "6am",
30 "7am", "8am", "9am", "10am", "11am", "12pm",
31 "1pm", "2pm", "3pm", "4pm", "5pm", "6pm",
32 "7pm", "8pm", "9pm", "10pm", "11pm"
36 * The display_icaltimetype_as_webform() and icaltime_from_webform() functions
37 * handle the display and editing of date/time properties in web pages. The
38 * first one converts an icaltimetype into valid HTML markup -- a series of form
39 * fields for editing the date and time. When the user submits the form, the
40 * results can be fed back into the second function, which turns it back into
41 * an icaltimetype. The "prefix" string required by both functions is prepended
42 * to all field names. This allows a form to contain more than one date/time
43 * property (for example, a start and end time) by ensuring the field names are
44 * unique within the form.
46 * NOTE: These functions assume that the icaltimetype being edited is in UTC, and
47 * will convert to/from local time for editing. "local" in this case is assumed
48 * to be the time zone in which the WebCit server is running. A future improvement
49 * might be to allow the user to specify his/her timezone.
52 void display_icaltimetype_as_webform(struct icaltimetype *t, char *prefix, int date_only) {
60 int all_day_event = 0;
64 time_format = get_time_format_cached ();
67 localtime_r(&now, &tm_now);
68 this_year = tm_now.tm_year + 1900;
70 if (t == NULL) return;
71 if (t->is_date) all_day_event = 1;
72 tt = icaltime_as_timet(*t);
77 localtime_r(&tt, &tm);
80 wc_printf("<input type=\"text\" name=\"");
81 StrBufAppendBufPlain(WCC->WBuf, prefix, -1, 0);
82 wc_printf("\" id=\"");
83 StrBufAppendBufPlain(WCC->WBuf, prefix, -1, 0);
84 wc_printf("\" size=\"10\" maxlength=\"10\" value=\"");
85 wc_strftime(timebuf, 32, "%Y-%m-%d", &tm);
86 StrBufAppendBufPlain(WCC->WBuf, timebuf, -1, 0);
89 StrBufAppendPrintf(WC->trailing_javascript, "attachDatePicker('");
90 StrBufAppendPrintf(WC->trailing_javascript, prefix);
91 StrBufAppendPrintf(WC->trailing_javascript, "', '%s');\n", get_selected_language());
93 /* If we're editing a date only, we still generate the time boxes, but we hide them.
94 * This keeps the data model consistent.
97 wc_printf("<div style=\"display:none\">");
100 wc_printf("<span ID=\"");
101 StrBufAppendBufPlain(WCC->WBuf, prefix, -1, 0);
102 wc_printf("_time\">");
103 wc_printf(_("Hour: "));
104 wc_printf("<SELECT NAME=\"%s_hour\" SIZE=\"1\">\n", prefix);
105 for (i=0; i<=23; ++i) {
107 if (time_format == WC_TIMEFORMAT_24) {
108 wc_printf("<OPTION %s VALUE=\"%d\">%d</OPTION>\n",
109 ((tm.tm_hour == i) ? "SELECTED" : ""),
114 wc_printf("<OPTION %s VALUE=\"%d\">%s</OPTION>\n",
115 ((tm.tm_hour == i) ? "SELECTED" : ""),
121 wc_printf("</SELECT>\n");
123 wc_printf(_("Minute: "));
124 wc_printf("<SELECT NAME=\"%s_minute\" SIZE=\"1\">\n", prefix);
125 for (i=0; i<=59; ++i) {
126 if ( (i % 5 == 0) || (tm.tm_min == i) ) {
127 wc_printf("<OPTION %s VALUE=\"%d\">:%02d</OPTION>\n",
128 ((tm.tm_min == i) ? "SELECTED" : ""),
133 wc_printf("</SELECT></span>\n");
141 * Get date/time from a web form and convert it into an icaltimetype struct.
143 void icaltime_from_webform(struct icaltimetype *t, char *prefix) {
148 /* Stuff with zero values */
149 memset(t, 0, sizeof(struct icaltimetype));
151 /* Get the year/month/date all in one shot -- it will be in ISO YYYY-MM-DD format */
152 sscanf((char*)BSTR(prefix), "%04d-%02d-%02d", &t->year, &t->month, &t->day);
155 sprintf(vname, "%s_hour", prefix);
156 t->hour = IBSTR(vname);
159 sprintf(vname, "%s_minute", prefix);
160 t->minute = IBSTR(vname);
162 /* time zone is set to the default zone for this server */
165 t->zone = get_default_icaltimezone();
170 * Get date (no time) from a web form and convert it into an icaltimetype struct.
172 void icaltime_from_webform_dateonly(struct icaltimetype *t, char *prefix) {
175 /* Stuff with zero values */
176 memset(t, 0, sizeof(struct icaltimetype));
178 /* Get the year/month/date all in one shot -- it will be in ISO YYYY-MM-DD format */
179 sscanf((char*)BSTR(prefix), "%04d-%02d-%02d", &t->year, &t->month, &t->day);
181 /* time zone is set to the default zone for this server */
188 * Render a PARTSTAT parameter as a string (and put it in parentheses)
190 void partstat_as_string(char *buf, icalproperty *attendee) {
191 icalparameter *partstat_param;
192 icalparameter_partstat partstat;
194 strcpy(buf, _("(status unknown)"));
196 partstat_param = icalproperty_get_first_parameter(
198 ICAL_PARTSTAT_PARAMETER
200 if (partstat_param == NULL) {
204 partstat = icalparameter_get_partstat(partstat_param);
206 case ICAL_PARTSTAT_X:
209 case ICAL_PARTSTAT_NEEDSACTION:
210 strcpy(buf, _("(needs action)"));
212 case ICAL_PARTSTAT_ACCEPTED:
213 strcpy(buf, _("(accepted)"));
215 case ICAL_PARTSTAT_DECLINED:
216 strcpy(buf, _("(declined)"));
218 case ICAL_PARTSTAT_TENTATIVE:
219 strcpy(buf, _("(tenative)"));
221 case ICAL_PARTSTAT_DELEGATED:
222 strcpy(buf, _("(delegated)"));
224 case ICAL_PARTSTAT_COMPLETED:
225 strcpy(buf, _("(completed)"));
227 case ICAL_PARTSTAT_INPROCESS:
228 strcpy(buf, _("(in process)"));
230 case ICAL_PARTSTAT_NONE:
231 strcpy(buf, _("(none)"));
237 * Utility function to encapsulate a subcomponent into a full VCALENDAR.
239 * We also scan for any date/time properties that reference timezones, and attach
240 * those timezones along with the supplied subcomponent. (Increase the size of the array if you need to.)
242 * Note: if you change anything here, change it in Citadel server's ical_send_out_invitations() too.
244 icalcomponent *ical_encapsulate_subcomponent(icalcomponent *subcomp) {
245 icalcomponent *encaps;
247 struct icaltimetype t;
248 const icaltimezone *attached_zones[5] = { NULL, NULL, NULL, NULL, NULL };
250 const icaltimezone *z;
251 int num_zones_attached = 0;
252 int zone_already_attached;
254 if (subcomp == NULL) {
255 lprintf(3, "ERROR: ical_encapsulate_subcomponent() called with NULL argument\n");
260 * If we're already looking at a full VCALENDAR component, this is probably an error.
262 if (icalcomponent_isa(subcomp) == ICAL_VCALENDAR_COMPONENT) {
263 lprintf(3, "ERROR: component sent to ical_encapsulate_subcomponent() already top level\n");
268 for (p = icalcomponent_get_first_property(subcomp, ICAL_ANY_PROPERTY);
270 p = icalcomponent_get_next_property(subcomp, ICAL_ANY_PROPERTY))
272 if ( (icalproperty_isa(p) == ICAL_COMPLETED_PROPERTY)
273 || (icalproperty_isa(p) == ICAL_CREATED_PROPERTY)
274 || (icalproperty_isa(p) == ICAL_DATEMAX_PROPERTY)
275 || (icalproperty_isa(p) == ICAL_DATEMIN_PROPERTY)
276 || (icalproperty_isa(p) == ICAL_DTEND_PROPERTY)
277 || (icalproperty_isa(p) == ICAL_DTSTAMP_PROPERTY)
278 || (icalproperty_isa(p) == ICAL_DTSTART_PROPERTY)
279 || (icalproperty_isa(p) == ICAL_DUE_PROPERTY)
280 || (icalproperty_isa(p) == ICAL_EXDATE_PROPERTY)
281 || (icalproperty_isa(p) == ICAL_LASTMODIFIED_PROPERTY)
282 || (icalproperty_isa(p) == ICAL_MAXDATE_PROPERTY)
283 || (icalproperty_isa(p) == ICAL_MINDATE_PROPERTY)
284 || (icalproperty_isa(p) == ICAL_RECURRENCEID_PROPERTY)
286 t = icalproperty_get_dtstart(p); /*/ it's safe to use dtstart for all of them */
287 if ((icaltime_is_valid_time(t)) && (z=icaltime_get_timezone(t), z)) {
289 zone_already_attached = 0;
290 for (i=0; i<5; ++i) {
291 if (z == attached_zones[i]) {
292 ++zone_already_attached;
293 lprintf(9, "zone already attached!!\n");
296 if ((!zone_already_attached) && (num_zones_attached < 5)) {
297 lprintf(9, "attaching zone %d!\n", num_zones_attached);
298 attached_zones[num_zones_attached++] = z;
301 icalproperty_set_parameter(p,
302 icalparameter_new_tzid(icaltimezone_get_tzid((icaltimezone *)z))
308 /* Encapsulate the VEVENT component into a complete VCALENDAR */
309 encaps = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
310 if (encaps == NULL) {
311 lprintf(3, "ERROR: ical_encapsulate_subcomponent() could not allocate component\n");
315 /* Set the Product ID */
316 icalcomponent_add_property(encaps, icalproperty_new_prodid(PRODID));
318 /* Set the Version Number */
319 icalcomponent_add_property(encaps, icalproperty_new_version("2.0"));
321 /* Attach any timezones we need */
322 if (num_zones_attached > 0) for (i=0; i<num_zones_attached; ++i) {
324 zc = icalcomponent_new_clone(icaltimezone_get_component((icaltimezone *)attached_zones[i]));
325 icalcomponent_add_component(encaps, zc);
328 /* Encapsulate the subcomponent inside */
329 icalcomponent_add_component(encaps, subcomp);
331 /* Return the object we just created. */