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\">");
84 wprintf("<SELECT NAME=\"%s_hour\" SIZE=\"1\">\n", prefix);
85 for (i=0; i<=23; ++i) {
87 if (time_format == WC_TIMEFORMAT_24) {
88 wprintf("<OPTION %s VALUE=\"%d\">%d</OPTION>\n",
89 ((tm.tm_hour == i) ? "SELECTED" : ""),
94 wprintf("<OPTION %s VALUE=\"%d\">%s</OPTION>\n",
95 ((tm.tm_hour == i) ? "SELECTED" : ""),
101 wprintf("</SELECT>\n");
103 wprintf(_("Minute: "));
104 wprintf("<SELECT NAME=\"%s_minute\" SIZE=\"1\">\n", prefix);
105 for (i=0; i<=59; ++i) {
106 if ( (i % 5 == 0) || (tm.tm_min == i) ) {
107 wprintf("<OPTION %s VALUE=\"%d\">:%02d</OPTION>\n",
108 ((tm.tm_min == i) ? "SELECTED" : ""),
113 wprintf("</SELECT>\n");
121 * Get date/time from a web form and convert it into an icaltimetype struct.
123 void icaltime_from_webform(struct icaltimetype *t, char *prefix) {
126 struct icaltimetype t2;
128 /* Stuff tm with zero values */
129 memset(&tm, 0, sizeof(struct tm));
131 /* Get the year/month/date all in one shot */
132 strptime((char*)BSTR(prefix), "%Y-%m-%d", &tm);
135 sprintf(vname, "%s_hour", prefix);
136 tm.tm_hour = IBSTR(vname);
139 sprintf(vname, "%s_minute", prefix);
140 tm.tm_min = IBSTR(vname);
142 /* now convert to icaltimetyepe */
143 t2 = icaltime_from_timet_with_zone(mktime(&tm), 0, get_default_icaltimezone());
144 t2.zone = get_default_icaltimezone();
145 memcpy(t, &t2, sizeof(struct icaltimetype));
150 * Get date (no time) from a web form and convert it into an icaltimetype struct.
152 void icaltime_from_webform_dateonly(struct icaltimetype *t, char *prefix) {
155 struct icaltimetype t2;
157 /* Stuff tm with zero values */
158 memset(&tm, 0, sizeof(struct tm));
160 /* Convert from string to icaltimetype */
161 strptime((char *)BSTR(prefix), "%Y-%m-%d", &tm);
163 t2 = icaltime_from_timet(tm_t, 1);
164 memcpy(t, &t2, sizeof(struct icaltimetype));
169 * Render a PARTSTAT parameter as a string (and put it in parentheses)
171 void partstat_as_string(char *buf, icalproperty *attendee) {
172 icalparameter *partstat_param;
173 icalparameter_partstat partstat;
175 strcpy(buf, _("(status unknown)"));
177 partstat_param = icalproperty_get_first_parameter(
179 ICAL_PARTSTAT_PARAMETER
181 if (partstat_param == NULL) {
185 partstat = icalparameter_get_partstat(partstat_param);
187 case ICAL_PARTSTAT_X:
190 case ICAL_PARTSTAT_NEEDSACTION:
191 strcpy(buf, _("(needs action)"));
193 case ICAL_PARTSTAT_ACCEPTED:
194 strcpy(buf, _("(accepted)"));
196 case ICAL_PARTSTAT_DECLINED:
197 strcpy(buf, _("(declined)"));
199 case ICAL_PARTSTAT_TENTATIVE:
200 strcpy(buf, _("(tenative)"));
202 case ICAL_PARTSTAT_DELEGATED:
203 strcpy(buf, _("(delegated)"));
205 case ICAL_PARTSTAT_COMPLETED:
206 strcpy(buf, _("(completed)"));
208 case ICAL_PARTSTAT_INPROCESS:
209 strcpy(buf, _("(in process)"));
211 case ICAL_PARTSTAT_NONE:
212 strcpy(buf, _("(none)"));
218 * Utility function to encapsulate a subcomponent into a full VCALENDAR.
220 * We also scan for any date/time properties that reference timezones, and attach
221 * those timezones along with the supplied subcomponent. (Increase the size of the array if you need to.)
223 * Note: if you change anything here, change it in Citadel server's ical_send_out_invitations() too.
225 icalcomponent *ical_encapsulate_subcomponent(icalcomponent *subcomp) {
226 icalcomponent *encaps;
228 struct icaltimetype t;
229 const icaltimezone *attached_zones[5] = { NULL, NULL, NULL, NULL, NULL };
231 const icaltimezone *z;
232 int num_zones_attached = 0;
233 int zone_already_attached;
235 if (subcomp == NULL) {
236 lprintf(3, "ERROR: ical_encapsulate_subcomponent() called with NULL argument\n");
241 * If we're already looking at a full VCALENDAR component, this is probably an error.
243 if (icalcomponent_isa(subcomp) == ICAL_VCALENDAR_COMPONENT) {
244 lprintf(3, "ERROR: component sent to ical_encapsulate_subcomponent() already top level\n");
249 for (p = icalcomponent_get_first_property(subcomp, ICAL_ANY_PROPERTY);
251 p = icalcomponent_get_next_property(subcomp, ICAL_ANY_PROPERTY))
253 if ( (icalproperty_isa(p) == ICAL_COMPLETED_PROPERTY)
254 || (icalproperty_isa(p) == ICAL_CREATED_PROPERTY)
255 || (icalproperty_isa(p) == ICAL_DATEMAX_PROPERTY)
256 || (icalproperty_isa(p) == ICAL_DATEMIN_PROPERTY)
257 || (icalproperty_isa(p) == ICAL_DTEND_PROPERTY)
258 || (icalproperty_isa(p) == ICAL_DTSTAMP_PROPERTY)
259 || (icalproperty_isa(p) == ICAL_DTSTART_PROPERTY)
260 || (icalproperty_isa(p) == ICAL_DUE_PROPERTY)
261 || (icalproperty_isa(p) == ICAL_EXDATE_PROPERTY)
262 || (icalproperty_isa(p) == ICAL_LASTMODIFIED_PROPERTY)
263 || (icalproperty_isa(p) == ICAL_MAXDATE_PROPERTY)
264 || (icalproperty_isa(p) == ICAL_MINDATE_PROPERTY)
265 || (icalproperty_isa(p) == ICAL_RECURRENCEID_PROPERTY)
267 t = icalproperty_get_dtstart(p); // it's safe to use dtstart for all of them
268 if ((icaltime_is_valid_time(t)) && (z=icaltime_get_timezone(t), z)) {
270 zone_already_attached = 0;
271 for (i=0; i<5; ++i) {
272 if (z == attached_zones[i]) {
273 ++zone_already_attached;
274 lprintf(9, "zone already attached!!\n");
277 if ((!zone_already_attached) && (num_zones_attached < 5)) {
278 lprintf(9, "attaching zone %d!\n", num_zones_attached);
279 attached_zones[num_zones_attached++] = z;
282 icalproperty_set_parameter(p,
283 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 lprintf(3, "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) for (i=0; i<num_zones_attached; ++i) {
305 zc = icalcomponent_new_clone(icaltimezone_get_component((icaltimezone *)attached_zones[i]));
306 icalcomponent_add_component(encaps, zc);
309 /* Encapsulate the subcomponent inside */
310 icalcomponent_add_component(encaps, subcomp);
312 /* Return the object we just created. */