X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fcalendar.c;h=10296ae798d82827a84877b4d80f15c81bc34113;hb=abeb8adc38f9d55fcb6cb3d076f57239b0a9a4d5;hp=423583060b122606e5a91f699fe799ae4e1b8625;hpb=10e202e9a1fefc16b7efb1d515af1e9f2c8d6ce7;p=citadel.git diff --git a/webcit/calendar.c b/webcit/calendar.c index 423583060..10296ae79 100644 --- a/webcit/calendar.c +++ b/webcit/calendar.c @@ -27,7 +27,7 @@ #include "webcit.h" #include "webserver.h" -#ifndef HAVE_ICAL_H +#ifndef WEBCIT_WITH_CALENDAR_SERVICE /* * Handler stubs for builds with no calendar library available @@ -38,7 +38,7 @@ void cal_process_attachment(char *part_source, long msgnum, char *cal_partnum) { " but support for calendars is not available on this " "particular system. Please ask your system administrator to " "install a new version of the Citadel web service with " - "calendaring enabled.
\n" + "calendaring enabled.
\n" ); } @@ -48,7 +48,7 @@ void display_calendar(long msgnum) { "Cannot display calendar item. You are seeing this error " "because your WebCit service has not been installed with " "calendar support. Please contact your system administrator." - "
\n"); + "
\n"); } void display_task(long msgnum) { @@ -56,10 +56,10 @@ void display_task(long msgnum) { "Cannot display to-do item. You are seeing this error " "because your WebCit service has not been installed with " "calendar support. Please contact your system administrator." - "
\n"); + "
\n"); } -#else /* HAVE_ICAL_H */ +#else /* WEBCIT_WITH_CALENDAR_SERVICE */ /****** End of handler stubs. Everything below this line is real. ******/ @@ -70,6 +70,7 @@ void display_task(long msgnum) { /* * Process a calendar object * ...at this point it's already been deserialized by cal_process_attachment() + * */ void cal_process_object(icalcomponent *cal, int recursion_level, @@ -103,8 +104,8 @@ void cal_process_object(icalcomponent *cal, "" "  " - "Meeting invitation - \n" + "Meeting invitation" + "\n" ); break; case ICAL_METHOD_REPLY: @@ -112,8 +113,8 @@ void cal_process_object(icalcomponent *cal, "" "  " - "Attendee's reply to your invitation - \n" + "Attendee's reply to your invitation" + "\n" ); break; case ICAL_METHOD_PUBLISH: @@ -121,8 +122,8 @@ void cal_process_object(icalcomponent *cal, "" "  " - "Published event - \n" + "Published event" + "\n" ); break; default: @@ -200,11 +201,17 @@ void cal_process_object(icalcomponent *cal, wprintf("Attendee:"); strcpy(buf, icalproperty_get_attendee(p)); if (!strncasecmp(buf, "MAILTO:", 7)) { + + /* screen name or email address */ strcpy(buf, &buf[7]); striplt(buf); escputs(buf); + wprintf(" "); + + /* participant status */ + partstat_as_string(buf, p); + escputs(buf); } - /* FIXME add status */ wprintf("\n"); } @@ -220,11 +227,12 @@ void cal_process_object(icalcomponent *cal, if (the_method == ICAL_METHOD_REQUEST) { /* Check for conflicts */ + lprintf(9, "Checking server calendar for conflicts...\n"); serv_printf("ICAL conflicts|%ld|%s|", msgnum, cal_partnum); serv_gets(buf); if (buf[0] == '1') { while (serv_gets(buf), strcmp(buf, "000")) { - extract(conflict_name, buf, 3); + extract_token(conflict_name, buf, 3, '|', sizeof conflict_name); is_update = extract_int(buf, 4); wprintf("%s" "" @@ -248,6 +256,7 @@ void cal_process_object(icalcomponent *cal, "\n"); } } + lprintf(9, "...done.\n"); /* Display the Accept/Decline buttons */ wprintf("" @@ -323,11 +332,11 @@ void cal_process_attachment(char *part_source, long msgnum, char *cal_partnum) { cal = icalcomponent_new_from_string(part_source); if (cal == NULL) { - wprintf("Error parsing calendar object: %s
\n", - icalerror_strerror(icalerrno)); + wprintf("Error parsing calendar object
\n"); return; } + ical_dezonify(cal); cal_process_object(cal, 0, msgnum, cal_partnum); /* Free the memory we obtained from libical's constructor */ @@ -343,13 +352,14 @@ void cal_process_attachment(char *part_source, long msgnum, char *cal_partnum) { void respond_to_request(void) { char buf[SIZ]; - output_headers(3); + output_headers(1, 1, 2, 0, 0, 0, 0); - wprintf("
" - "Respond to meeting request" - "

\n" + wprintf("
\n"); + wprintf("
" + "Respond to meeting request" + "
\n" ); + wprintf("
\n
\n"); serv_printf("ICAL respond|%s|%s|%s|", bstr("msgnum"), @@ -386,7 +396,7 @@ void respond_to_request(void) { wprintf("wc_roomname); - wprintf("\">
Return to messages

\n"); + wprintf("\">
Return to messages
\n"); wDumpContent(1); } @@ -399,12 +409,14 @@ void respond_to_request(void) { void handle_rsvp(void) { char buf[SIZ]; - output_headers(3); + output_headers(1, 1, 2, 0, 0, 0, 0); - wprintf("
" - "Update your calendar with this RSVP" - "

\n" + wprintf("
\n"); + wprintf("
" + "" + "Update your calendar with this RSVP" + "
\n" + "
\n
\n" ); serv_printf("ICAL handle_rsvp|%s|%s|%s|", @@ -437,7 +449,7 @@ void handle_rsvp(void) { wprintf("wc_roomname); - wprintf("\">
Return to messages

\n"); + wprintf("\">
Return to messages
\n"); wDumpContent(1); } @@ -464,33 +476,17 @@ void display_individual_cal(icalcomponent *cal, long msgnum) { WC->num_cal += 1; WC->disp_cal = realloc(WC->disp_cal, - (sizeof(icalcomponent *) * WC->num_cal) ); - WC->disp_cal[WC->num_cal - 1] = icalcomponent_new_clone(cal); + (sizeof(struct disp_cal) * WC->num_cal) ); + WC->disp_cal[WC->num_cal - 1].cal = icalcomponent_new_clone(cal); - WC->cal_msgnum = realloc(WC->cal_msgnum, - (sizeof(long) * WC->num_cal) ); - WC->cal_msgnum[WC->num_cal - 1] = msgnum; + WC->disp_cal[WC->num_cal - 1].cal_msgnum = msgnum; } -/* - * Display a task in the task list - */ -void display_individual_task(icalcomponent *vtodo, long msgnum) { - icalproperty *p; - - p = icalcomponent_get_first_property(vtodo, ICAL_SUMMARY_PROPERTY); - wprintf("
  • ", msgnum); - if (p != NULL) { - escputs((char *)icalproperty_get_comment(p)); - } - wprintf("\n"); -} - - /* * Display a task by itself (for editing) + * */ void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum) { icalcomponent *vtodo; @@ -503,33 +499,55 @@ void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum) { if (supplied_vtodo != NULL) { vtodo = supplied_vtodo; + + /* If we're looking at a fully encapsulated VCALENDAR + * rather than a VTODO component, attempt to use the first + * relevant VTODO subcomponent. If there is none, the + * NULL returned by icalcomponent_get_first_component() will + * tell the next iteration of this function to create a + * new one. + */ + if (icalcomponent_isa(vtodo) == ICAL_VCALENDAR_COMPONENT) { + display_edit_individual_task( + icalcomponent_get_first_component( + vtodo, ICAL_VTODO_COMPONENT + ), msgnum + ); + return; + } } else { vtodo = icalcomponent_new(ICAL_VTODO_COMPONENT); created_new_vtodo = 1; } - output_headers(3); - wprintf("
    " - "Edit task" - "

    \n" + output_headers(1, 1, 2, 0, 0, 0, 0); + wprintf("
    \n" + "
    " + "Edit task" + "
    \n" + "
    \n
    \n" ); + wprintf("
    " + "
    "); + wprintf("
    \n"); wprintf("\n", msgnum); - wprintf("Summary: " + wprintf("\n"); + + wprintf("\n"); - wprintf("Start date: "); + wprintf("\n"); - wprintf("Due date: "); + wprintf("
    Summary:" "
    \n"); + wprintf("\">
    Start date:"); p = icalcomponent_get_first_property(vtodo, ICAL_DTSTART_PROPERTY); if (p != NULL) { t = icalproperty_get_dtstart(p); @@ -538,9 +556,9 @@ void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum) { t = icaltime_from_timet(now, 0); } display_icaltimetype_as_webform(&t, "dtstart"); - wprintf("
    \n"); + wprintf("
    Due date:"); p = icalcomponent_get_first_property(vtodo, ICAL_DUE_PROPERTY); if (p != NULL) { t = icalproperty_get_due(p); @@ -549,18 +567,19 @@ void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum) { t = icaltime_from_timet(now, 0); } display_icaltimetype_as_webform(&t, "due"); - wprintf("
    \n"); - - wprintf("

    \n"); + wprintf("
    \n"); - wprintf("" + wprintf("
    " + "" "  " "\n" "  " @@ -570,6 +589,7 @@ void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum) { wprintf("\n"); + wprintf("
    \n"); wDumpContent(1); if (created_new_vtodo) { @@ -579,16 +599,34 @@ void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum) { /* * Save an edited task + * */ void save_individual_task(icalcomponent *supplied_vtodo, long msgnum) { char buf[SIZ]; int delete_existing = 0; icalproperty *prop; - icalcomponent *vtodo; + icalcomponent *vtodo, *encaps; int created_new_vtodo = 0; + int i; + int sequence = 0; if (supplied_vtodo != NULL) { vtodo = supplied_vtodo; + /* If we're looking at a fully encapsulated VCALENDAR + * rather than a VTODO component, attempt to use the first + * relevant VTODO subcomponent. If there is none, the + * NULL returned by icalcomponent_get_first_component() will + * tell the next iteration of this function to create a + * new one. + */ + if (icalcomponent_isa(vtodo) == ICAL_VCALENDAR_COMPONENT) { + save_individual_task( + icalcomponent_get_first_component( + vtodo, ICAL_VTODO_COMPONENT + ), msgnum + ); + return; + } } else { vtodo = icalcomponent_new(ICAL_VTODO_COMPONENT); @@ -636,14 +674,50 @@ void save_individual_task(icalcomponent *supplied_vtodo, long msgnum) { icaltime_from_webform("due") ) ); - + + /* Give this task a UID if it doesn't have one. */ + lprintf(9, "Give this task a UID if it doesn't have one.\n"); + if (icalcomponent_get_first_property(vtodo, + ICAL_UID_PROPERTY) == NULL) { + generate_uuid(buf); + icalcomponent_add_property(vtodo, + icalproperty_new_uid(buf) + ); + } + + /* Increment the sequence ID */ + lprintf(9, "Increment the sequence ID\n"); + while (prop = icalcomponent_get_first_property(vtodo, + ICAL_SEQUENCE_PROPERTY), (prop != NULL) ) { + i = icalproperty_get_sequence(prop); + lprintf(9, "Sequence was %d\n", i); + if (i > sequence) sequence = i; + icalcomponent_remove_property(vtodo, prop); + icalproperty_free(prop); + } + ++sequence; + lprintf(9, "New sequence is %d. Adding...\n", sequence); + icalcomponent_add_property(vtodo, + icalproperty_new_sequence(sequence) + ); + + /* + * Encapsulate event into full VCALENDAR component. Clone it first, + * for two reasons: one, it's easier to just free the whole thing + * when we're done instead of unbundling, but more importantly, we + * can't encapsulate something that may already be encapsulated + * somewhere else. + */ + lprintf(9, "Encapsulating into full VCALENDAR component\n"); + encaps = ical_encapsulate_subcomponent(icalcomponent_new_clone(vtodo)); + /* Serialize it and save it to the message base */ serv_puts("ENT0 1|||4"); serv_gets(buf); if (buf[0] == '4') { serv_puts("Content-type: text/calendar"); serv_puts(""); - serv_puts(icalcomponent_as_ical_string(vtodo)); + serv_puts(icalcomponent_as_ical_string(encaps)); serv_puts("000"); /* Probably not necessary; the server will see the UID @@ -652,6 +726,7 @@ void save_individual_task(icalcomponent *supplied_vtodo, long msgnum) { */ delete_existing = 1; } + icalcomponent_free(encaps); } /* @@ -681,6 +756,7 @@ void save_individual_task(icalcomponent *supplied_vtodo, long msgnum) { * type, we load the message and hunt for that MIME type. If found, we load * the relevant part, deserialize it into a libical component, filter it for * the requested object type, and feed it to the specified handler. + * */ void display_using_handler(long msgnum, char *mimetype, @@ -704,10 +780,10 @@ void display_using_handler(long msgnum, while (serv_gets(buf), strcmp(buf, "000")) { if (!strncasecmp(buf, "part=", 5)) { - extract(mime_filename, &buf[5], 1); - extract(mime_partnum, &buf[5], 2); - extract(mime_disposition, &buf[5], 3); - extract(mime_content_type, &buf[5], 4); + extract_token(mime_filename, &buf[5], 1, '|', sizeof mime_filename); + extract_token(mime_partnum, &buf[5], 2, '|', sizeof mime_partnum); + extract_token(mime_disposition, &buf[5], 3, '|', sizeof mime_disposition); + extract_token(mime_content_type, &buf[5], 4, '|', sizeof mime_content_type); mime_length = extract_int(&buf[5], 5); if (!strcasecmp(mime_content_type, "text/calendar")) { @@ -724,6 +800,8 @@ void display_using_handler(long msgnum, cal = icalcomponent_new_from_string(relevant_source); if (cal != NULL) { + ical_dezonify(cal); + /* Simple components of desired type */ if (icalcomponent_isa(cal) == which_kind) { callback(cal, msgnum); @@ -754,12 +832,17 @@ void display_calendar(long msgnum) { void display_task(long msgnum) { display_using_handler(msgnum, "text/calendar", ICAL_VTODO_COMPONENT, - display_individual_task); + display_individual_cal); } void display_edit_task(void) { long msgnum = 0L; + /* Force change the room if we have to */ + if (strlen(bstr("taskrm")) > 0) { + gotoroom(bstr("taskrm")); + } + msgnum = atol(bstr("msgnum")); if (msgnum > 0L) { /* existing task */ @@ -818,4 +901,47 @@ void save_event(void) { } } -#endif /* HAVE_ICAL_H */ + + + + +/* + * freebusy display (for client software) + */ +void do_freebusy(char *req) { + char who[SIZ]; + char buf[SIZ]; + char *fb; + + extract_token(who, req, 1, ' ', sizeof who); + if (!strncasecmp(who, "/freebusy/", 10)) { + strcpy(who, &who[10]); + } + unescape_input(who); + + if ( (!strcasecmp(&who[strlen(who)-4], ".vcf")) + || (!strcasecmp(&who[strlen(who)-4], ".vfb")) ) { + who[strlen(who)-4] = 0; + } + + lprintf(9, "freebusy requested for <%s>\n", who); + serv_printf("ICAL freebusy|%s", who); + serv_gets(buf); + + if (buf[0] != '1') { + wprintf("HTTP/1.0 404 %s\n", &buf[4]); + output_headers(0, 0, 0, 0, 0, 0, 0); + wprintf("Content-Type: text/plain\r\n"); + wprintf("\r\n"); + wprintf("%s\n", &buf[4]); + return; + } + + fb = read_server_text(); + http_transmit_thing(fb, strlen(fb), "text/calendar", 0); + free(fb); +} + + + +#endif /* WEBCIT_WITH_CALENDAR_SERVICE */