4 * Miscellaneous functions which handle calendar components.
13 "12am", "1am", "2am", "3am", "4am", "5am", "6am",
14 "7am", "8am", "9am", "10am", "11am", "12pm",
15 "1pm", "2pm", "3pm", "4pm", "5pm", "6pm",
16 "7pm", "8pm", "9pm", "10pm", "11pm"
20 * The display_icaltimetype_as_webform() and icaltime_from_webform() functions
21 * handle the display and editing of date/time properties in web pages. The
22 * first one converts an icaltimetype into valid HTML markup -- a series of form
23 * fields for editing the date and time. When the user submits the form, the
24 * results can be fed back into the second function, which turns it back into
25 * an icaltimetype. The "prefix" string required by both functions is prepended
26 * to all field names. This allows a form to contain more than one date/time
27 * property (for example, a start and end time) by ensuring the field names are
28 * unique within the form.
30 * NOTE: These functions assume that the icaltimetype being edited is in UTC, and
31 * will convert to/from local time for editing. "local" in this case is assumed
32 * to be the time zone in which the WebCit server is running. A future improvement
33 * might be to allow the user to specify his/her timezone.
36 void display_icaltimetype_as_webform(struct icaltimetype *t, char *prefix, int date_only) {
43 int all_day_event = 0;
47 time_format = get_time_format_cached ();
50 localtime_r(&now, &tm_now);
51 this_year = tm_now.tm_year + 1900;
53 if (t == NULL) return;
54 if (t->is_date) all_day_event = 1;
55 tt = icaltime_as_timet(*t);
60 localtime_r(&tt, &tm);
63 wprintf("<input type=\"text\" name=\"");
67 wprintf("\" size=\"10\" maxlength=\"10\" value=\"");
68 wc_strftime(timebuf, 32, "%Y-%m-%d", &tm);
72 StrBufAppendPrintf(WC->trailing_javascript, "attachDatePicker('");
73 StrBufAppendPrintf(WC->trailing_javascript, prefix);
74 StrBufAppendPrintf(WC->trailing_javascript, "', '%s');\n", get_selected_language());
76 /* If we're editing a date only, we still generate the time boxes, but we hide them.
77 * This keeps the data model consistent.
80 wprintf("<div style=\"display:none\">");
83 wprintf("<span ID=\"");
87 wprintf("<SELECT NAME=\"%s_hour\" SIZE=\"1\">\n", prefix);
88 for (i=0; i<=23; ++i) {
90 if (time_format == WC_TIMEFORMAT_24) {
91 wprintf("<OPTION %s VALUE=\"%d\">%d</OPTION>\n",
92 ((tm.tm_hour == i) ? "SELECTED" : ""),
97 wprintf("<OPTION %s VALUE=\"%d\">%s</OPTION>\n",
98 ((tm.tm_hour == i) ? "SELECTED" : ""),
104 wprintf("</SELECT>\n");
106 wprintf(_("Minute: "));
107 wprintf("<SELECT NAME=\"%s_minute\" SIZE=\"1\">\n", prefix);
108 for (i=0; i<=59; ++i) {
109 if ( (i % 5 == 0) || (tm.tm_min == i) ) {
110 wprintf("<OPTION %s VALUE=\"%d\">:%02d</OPTION>\n",
111 ((tm.tm_min == i) ? "SELECTED" : ""),
116 wprintf("</SELECT></span>\n");
124 * Get date/time from a web form and convert it into an icaltimetype struct.
126 void icaltime_from_webform(struct icaltimetype *t, char *prefix) {
131 /* Stuff with zero values */
132 memset(t, 0, sizeof(struct icaltimetype));
134 /* Get the year/month/date all in one shot -- it will be in ISO YYYY-MM-DD format */
135 sscanf((char*)BSTR(prefix), "%04d-%02d-%02d", &t->year, &t->month, &t->day);
138 sprintf(vname, "%s_hour", prefix);
139 t->hour = IBSTR(vname);
142 sprintf(vname, "%s_minute", prefix);
143 t->minute = IBSTR(vname);
145 /* time zone is set to the default zone for this server */
148 t->zone = get_default_icaltimezone();
153 * Get date (no time) from a web form and convert it into an icaltimetype struct.
155 void icaltime_from_webform_dateonly(struct icaltimetype *t, char *prefix) {
158 /* Stuff with zero values */
159 memset(t, 0, sizeof(struct icaltimetype));
161 /* Get the year/month/date all in one shot -- it will be in ISO YYYY-MM-DD format */
162 sscanf((char*)BSTR(prefix), "%04d-%02d-%02d", &t->year, &t->month, &t->day);
164 /* time zone is set to the default zone for this server */
171 * Render a PARTSTAT parameter as a string (and put it in parentheses)
173 void partstat_as_string(char *buf, icalproperty *attendee) {
174 icalparameter *partstat_param;
175 icalparameter_partstat partstat;
177 strcpy(buf, _("(status unknown)"));
179 partstat_param = icalproperty_get_first_parameter(
181 ICAL_PARTSTAT_PARAMETER
183 if (partstat_param == NULL) {
187 partstat = icalparameter_get_partstat(partstat_param);
189 case ICAL_PARTSTAT_X:
192 case ICAL_PARTSTAT_NEEDSACTION:
193 strcpy(buf, _("(needs action)"));
195 case ICAL_PARTSTAT_ACCEPTED:
196 strcpy(buf, _("(accepted)"));
198 case ICAL_PARTSTAT_DECLINED:
199 strcpy(buf, _("(declined)"));
201 case ICAL_PARTSTAT_TENTATIVE:
202 strcpy(buf, _("(tenative)"));
204 case ICAL_PARTSTAT_DELEGATED:
205 strcpy(buf, _("(delegated)"));
207 case ICAL_PARTSTAT_COMPLETED:
208 strcpy(buf, _("(completed)"));
210 case ICAL_PARTSTAT_INPROCESS:
211 strcpy(buf, _("(in process)"));
213 case ICAL_PARTSTAT_NONE:
214 strcpy(buf, _("(none)"));
220 * Utility function to encapsulate a subcomponent into a full VCALENDAR.
222 * We also scan for any date/time properties that reference timezones, and attach
223 * those timezones along with the supplied subcomponent. (Increase the size of the array if you need to.)
225 * Note: if you change anything here, change it in Citadel server's ical_send_out_invitations() too.
227 icalcomponent *ical_encapsulate_subcomponent(icalcomponent *subcomp) {
228 icalcomponent *encaps;
230 struct icaltimetype t;
231 const icaltimezone *attached_zones[5] = { NULL, NULL, NULL, NULL, NULL };
233 const icaltimezone *z;
234 int num_zones_attached = 0;
235 int zone_already_attached;
237 if (subcomp == NULL) {
238 lprintf(3, "ERROR: ical_encapsulate_subcomponent() called with NULL argument\n");
243 * If we're already looking at a full VCALENDAR component, this is probably an error.
245 if (icalcomponent_isa(subcomp) == ICAL_VCALENDAR_COMPONENT) {
246 lprintf(3, "ERROR: component sent to ical_encapsulate_subcomponent() already top level\n");
251 for (p = icalcomponent_get_first_property(subcomp, ICAL_ANY_PROPERTY);
253 p = icalcomponent_get_next_property(subcomp, ICAL_ANY_PROPERTY))
255 if ( (icalproperty_isa(p) == ICAL_COMPLETED_PROPERTY)
256 || (icalproperty_isa(p) == ICAL_CREATED_PROPERTY)
257 || (icalproperty_isa(p) == ICAL_DATEMAX_PROPERTY)
258 || (icalproperty_isa(p) == ICAL_DATEMIN_PROPERTY)
259 || (icalproperty_isa(p) == ICAL_DTEND_PROPERTY)
260 || (icalproperty_isa(p) == ICAL_DTSTAMP_PROPERTY)
261 || (icalproperty_isa(p) == ICAL_DTSTART_PROPERTY)
262 || (icalproperty_isa(p) == ICAL_DUE_PROPERTY)
263 || (icalproperty_isa(p) == ICAL_EXDATE_PROPERTY)
264 || (icalproperty_isa(p) == ICAL_LASTMODIFIED_PROPERTY)
265 || (icalproperty_isa(p) == ICAL_MAXDATE_PROPERTY)
266 || (icalproperty_isa(p) == ICAL_MINDATE_PROPERTY)
267 || (icalproperty_isa(p) == ICAL_RECURRENCEID_PROPERTY)
269 t = icalproperty_get_dtstart(p); /*/ it's safe to use dtstart for all of them */
270 if ((icaltime_is_valid_time(t)) && (z=icaltime_get_timezone(t), z)) {
272 zone_already_attached = 0;
273 for (i=0; i<5; ++i) {
274 if (z == attached_zones[i]) {
275 ++zone_already_attached;
276 lprintf(9, "zone already attached!!\n");
279 if ((!zone_already_attached) && (num_zones_attached < 5)) {
280 lprintf(9, "attaching zone %d!\n", num_zones_attached);
281 attached_zones[num_zones_attached++] = z;
284 icalproperty_set_parameter(p,
285 icalparameter_new_tzid(icaltimezone_get_tzid((icaltimezone *)z))
291 /* Encapsulate the VEVENT component into a complete VCALENDAR */
292 encaps = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
293 if (encaps == NULL) {
294 lprintf(3, "ERROR: ical_encapsulate_subcomponent() could not allocate component\n");
298 /* Set the Product ID */
299 icalcomponent_add_property(encaps, icalproperty_new_prodid(PRODID));
301 /* Set the Version Number */
302 icalcomponent_add_property(encaps, icalproperty_new_version("2.0"));
304 /* Attach any timezones we need */
305 if (num_zones_attached > 0) for (i=0; i<num_zones_attached; ++i) {
307 zc = icalcomponent_new_clone(icaltimezone_get_component((icaltimezone *)attached_zones[i]));
308 icalcomponent_add_component(encaps, zc);
311 /* Encapsulate the subcomponent inside */
312 icalcomponent_add_component(encaps, subcomp);
314 /* Return the object we just created. */