* serv_getln now is a wrapper around existing functionality. a new temporary var...
[citadel.git] / webcit / calendar.c
index 455173f6bd173179613069de4421cfc4506c5493..48a0f1fc793461630d2a70e8d70a03643e94f9c4 100644 (file)
@@ -125,7 +125,7 @@ void cal_process_object(StrBuf *Target,
                        }
                        else {
                                tt = icaltime_as_timet(t);
-                               webcit_fmt_date(buf, tt, 0);
+                               webcit_fmt_date(buf, 256, tt, DATEFMT_FULL);
                                StrBufAppendPrintf(Target, "<dt>");
                                StrBufAppendPrintf(Target, _("Starting date/time:"));
                                StrBufAppendPrintf(Target, "</dt><dd>%s</dd>", buf);
@@ -136,7 +136,7 @@ void cal_process_object(StrBuf *Target,
                if (p != NULL) {
                        t = icalproperty_get_dtend(p);
                        tt = icaltime_as_timet(t);
-                       webcit_fmt_date(buf, tt, 0);
+                       webcit_fmt_date(buf, 256, tt, DATEFMT_FULL);
                        StrBufAppendPrintf(Target, "<dt>");
                        StrBufAppendPrintf(Target, _("Ending date/time:"));
                        StrBufAppendPrintf(Target, "</dt><dd>%s</dd>", buf);
@@ -275,12 +275,11 @@ void cal_process_object(StrBuf *Target,
 
 /*
  * Deserialize a calendar object in a message so it can be displayed.
- *
  */
 void cal_process_attachment(wc_mime_attachment *Mime) 
 {
        icalcomponent *cal;
-       
+
        cal = icalcomponent_new_from_string(ChrPtr(Mime->Data));
        FlushStrBuf(Mime->Data);
        if (cal == NULL) {
@@ -298,9 +297,8 @@ void cal_process_attachment(wc_mime_attachment *Mime)
 
 
 
-/**
- * \brief accept/decline meeting
- * Respond to a meeting request
+/*
+ * Respond to a meeting request - accept/decline meeting
  */
 void respond_to_request(void) 
 {
@@ -344,8 +342,8 @@ void respond_to_request(void)
 
 
 
-/**
- * \brief Handle an incoming RSVP
+/*
+ * Handle an incoming RSVP
  */
 void handle_rsvp(void) 
 {
@@ -599,7 +597,12 @@ void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum, ch
        if (supplied_vtodo != NULL) {
                vtodo = supplied_vtodo;
 
-               /**
+               /*
+                * It's safe to convert to UTC here because there are no recurrences to worry about.
+                */
+               ical_dezonify(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
@@ -622,7 +625,7 @@ void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum, ch
                created_new_vtodo = 1;
        }
        
-       /*/ TODO: Can we take all this and move it into a template?      */
+       /* TODO: Can we take all this and move it into a template?       */
        output_headers(1, 1, 1, 0, 0, 0);
        wprintf("<!-- start task edit form -->");
        p = icalcomponent_get_first_property(vtodo, ICAL_SUMMARY_PROPERTY);
@@ -670,6 +673,7 @@ void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum, ch
        wprintf(_("No date"));
        
        wprintf(" ");
+       wprintf("<span ID=\"dtstart_date\">");
        wprintf(_("or"));
        wprintf(" ");
        if (p != NULL) {
@@ -678,7 +682,14 @@ void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum, ch
        else
                IcalTime = icaltime_current_time_with_zone(get_default_icaltimezone());
        display_icaltimetype_as_webform(&IcalTime, "dtstart", 0);
-       wprintf("</TD></TR>\n");
+
+       wprintf("<INPUT TYPE=\"CHECKBOX\" NAME=\"dtstart_time_assoc\" ID=\"dtstart_time_assoc\" VALUE=\"yes\"");
+       if (!IcalTime.is_date) {
+               wprintf("CHECKED=\"CHECKED\"");
+       }
+       wprintf(">");
+       wprintf(_("Time associated"));
+       wprintf("</span></TD></TR>\n");
 
        wprintf("<TR><TD>");
        wprintf(_("Due date:"));
@@ -691,6 +702,7 @@ void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum, ch
        wprintf(">");
        wprintf(_("No date"));
        wprintf(" ");
+       wprintf("<span ID=\"due_date\">\n");
        wprintf(_("or"));
        wprintf(" ");
        if (p != NULL) {
@@ -699,8 +711,14 @@ void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum, ch
        else
                IcalTime = icaltime_current_time_with_zone(get_default_icaltimezone());
        display_icaltimetype_as_webform(&IcalTime, "due", 0);
-               
-       wprintf("</TD></TR>\n");
+
+       wprintf("<INPUT TYPE=\"CHECKBOX\" NAME=\"due_time_assoc\" ID=\"due_time_assoc\" VALUE=\"yes\"");
+       if (!IcalTime.is_date) {
+               wprintf("CHECKED=\"CHECKED\"");
+       }
+       wprintf(">");
+       wprintf(_("Time associated"));
+       wprintf("</span></TD></TR>\n");
        todoStatus = icalcomponent_get_status(vtodo);
        wprintf("<TR><TD>\n");
        wprintf(_("Completed:"));
@@ -758,9 +776,10 @@ void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum, ch
 }
 
 /*
- * \brief Save an edited task
- * \param supplied_vtodo the task to save
- * \param msgnum number of the mesage in our db
+ * Save an edited task
+ *
+ * supplied_vtodo      the task to save
+ * msgnum              number of the mesage in our db
  */
 void save_individual_task(icalcomponent *supplied_vtodo, long msgnum, char* from, int unread,
                                struct calview *calv)
@@ -813,7 +832,7 @@ void save_individual_task(icalcomponent *supplied_vtodo, long msgnum, char* from
                                                   icalproperty_new_summary(bstr("summary")));
                } else {
                        icalcomponent_add_property(vtodo,
-                                                  icalproperty_new_summary("Untitled Task"));
+                                                  icalproperty_new_summary(_("Untitled Task")));
                }
        
                while (prop = icalcomponent_get_first_property(vtodo,
@@ -832,7 +851,12 @@ void save_individual_task(icalcomponent *supplied_vtodo, long msgnum, char* from
                        icalproperty_free(prop);
                }
                if (IsEmptyStr(bstr("nodtstart"))) {
-                       icaltime_from_webform(&t, "dtstart");
+                       if (yesbstr("dtstart_time")) {
+                               icaltime_from_webform(&t, "dtstart");
+                       }
+                       else {
+                               icaltime_from_webform_dateonly(&t, "dtstart");
+                       }
                        icalcomponent_add_property(vtodo,
                                                   icalproperty_new_dtstart(t)
                                );
@@ -842,10 +866,23 @@ void save_individual_task(icalcomponent *supplied_vtodo, long msgnum, char* from
                        icalcomponent_remove_property(vtodo,prop);
                        icalproperty_free(prop);
                }
+               while(prop = icalcomponent_get_first_property(vtodo,
+                                                             ICAL_PERCENTCOMPLETE_PROPERTY), prop != NULL) {
+                       icalcomponent_remove_property(vtodo,prop);
+                       icalproperty_free(prop);
+               }
+
                if (havebstr("status")) {
-                       icalproperty_status taskStatus = icalproperty_string_to_status(
-                               bstr("status"));
+                       icalproperty_status taskStatus = icalproperty_string_to_status(bstr("status"));
                        icalcomponent_set_status(vtodo, taskStatus);
+                       icalcomponent_add_property(vtodo,
+                               icalproperty_new_percentcomplete(
+                                       (strcasecmp(bstr("status"), "completed") ? 0 : 100)
+                               )
+                       );
+               }
+               else {
+                       icalcomponent_add_property(vtodo, icalproperty_new_percentcomplete(0));
                }
                while (prop = icalcomponent_get_first_property(vtodo,
                                                               ICAL_CATEGORIES_PROPERTY), prop != NULL) {
@@ -862,7 +899,12 @@ void save_individual_task(icalcomponent *supplied_vtodo, long msgnum, char* from
                        icalproperty_free(prop);
                }
                if (IsEmptyStr(bstr("nodue"))) {
-                       icaltime_from_webform(&t, "due");
+                       if (yesbstr("due_time")) {
+                               icaltime_from_webform(&t, "due");
+                       }
+                       else {
+                               icaltime_from_webform_dateonly(&t, "due");
+                       }
                        icalcomponent_add_property(vtodo,
                                                   icalproperty_new_due(t)
                                );
@@ -877,7 +919,7 @@ void save_individual_task(icalcomponent *supplied_vtodo, long msgnum, char* from
                                );
                }
 
-               /** Increment the sequence ID */
+               /* Increment the sequence ID */
                lprintf(9, "Increment the sequence ID\n");
                while (prop = icalcomponent_get_first_property(vtodo,
                                                               ICAL_SEQUENCE_PROPERTY), (prop != NULL) ) {
@@ -893,7 +935,7 @@ void save_individual_task(icalcomponent *supplied_vtodo, long msgnum, char* from
                                           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
@@ -912,7 +954,7 @@ void save_individual_task(icalcomponent *supplied_vtodo, long msgnum, char* from
                        serv_puts(icalcomponent_as_ical_string(encaps));
                        serv_puts("000");
 
-                       /**
+                       /*
                         * Probably not necessary; the server will see the UID
                         * of the object and delete the old one anyway, but
                         * just in case...
@@ -949,6 +991,45 @@ void save_individual_task(icalcomponent *supplied_vtodo, long msgnum, char* from
 
 
 
+void process_ical_object(long msgnum, int unread,
+                        char *from, 
+                        char *FlatIcal, 
+                        icalcomponent_kind which_kind,
+                        IcalCallbackFunc CallBack,
+                        struct calview *calv
+       ) 
+{
+       icalcomponent *cal, *c;
+
+       cal = icalcomponent_new_from_string(FlatIcal);
+       if (cal != NULL) {
+
+               /* A which_kind of (-1) means just load the whole thing */
+               if (which_kind == (-1)) {
+                       CallBack(cal, msgnum, from, unread, calv);
+               }
+               
+               /* Otherwise recurse and hunt */
+               else {
+                       
+                       /* Simple components of desired type */
+                       if (icalcomponent_isa(cal) == which_kind) {
+                               CallBack(cal, msgnum, from, unread, calv);
+                       }
+                       
+                       /* Subcomponents of desired type */
+                       for (c = icalcomponent_get_first_component(cal, which_kind);
+                            (c != 0);
+                            c = icalcomponent_get_next_component(cal, which_kind)) {
+                               CallBack(c, msgnum, from, unread, calv);
+                       }
+                       
+               }
+               
+               icalcomponent_free(cal);
+       }
+}
+
 /*
  * Code common to all icalendar display handlers.  Given a message number and a MIME
  * type, we load the message and hunt for that MIME type.  If found, we load
@@ -956,12 +1037,16 @@ void save_individual_task(icalcomponent *supplied_vtodo, long msgnum, char* from
  * the requested object type, and feed it to the specified handler.
  */
 void load_ical_object(long msgnum, int unread,
-                          icalcomponent_kind which_kind,
-                          void (*callback)(icalcomponent *, long, char*, int, struct calview *),
-                          struct calview *calv
+                     icalcomponent_kind which_kind,
+                     IcalCallbackFunc CallBack,
+                     struct calview *calv,
+                     int RenderAsync
        ) 
 {
-       char buf[1024];
+       StrBuf *Buf;
+       StrBuf *Data;
+       const char *bptr;
+       int Done = 0;
        char from[128] = "";
        char mime_partnum[256];
        char mime_filename[256];
@@ -970,68 +1055,111 @@ void load_ical_object(long msgnum, int unread,
        int mime_length;
        char relevant_partnum[256];
        char *relevant_source = NULL;
-       icalcomponent *cal, *c;
+       int phase = 0;                          /* 0 = citadel headers, 1 = mime headers, 2 = body */
+       char msg4_content_type[256] = "";
+       char msg4_content_encoding[256] = "";
+       int msg4_content_length = 0;
 
        relevant_partnum[0] = '\0';
-       sprintf(buf, "MSG4 %ld", msgnum);       /* we need the mime headers */
-       serv_puts(buf);
-       serv_getln(buf, sizeof buf);
-       if (buf[0] != '1') return;
-
-       while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
-               if (!strncasecmp(buf, "part=", 5)) {
-                       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"))
-                             || (!strcasecmp(mime_content_type, "application/ics"))
-                             || (!strcasecmp(mime_content_type, "text/vtodo"))
-                               ) {
-                               strcpy(relevant_partnum, mime_partnum);
-                       }
-               }
-               else if (!strncasecmp(buf, "from=", 4)) {
-                       extract_token(from, buf, 1, '=', sizeof(from));
-               }
+       serv_printf("MSG4 %ld", msgnum);        /* we need the mime headers */
+       Buf = NewStrBuf();
+       StrBuf_ServGetln(Buf);
+       if (GetServerStatus(Buf, NULL) != 1) {
+               FreeStrBuf (&Buf);
+               return;
        }
-
-       if (!IsEmptyStr(relevant_partnum)) {
-               relevant_source = load_mimepart(msgnum, relevant_partnum);
-               if (relevant_source != NULL) {
-
-                       cal = icalcomponent_new_from_string(relevant_source);
-                       if (cal != NULL) {
-
-                               /* A which_kind of (-1) means just load the whole thing */
-                               if (which_kind == (-1)) {
-                                       callback(cal, msgnum, from, unread, calv);
+       while (!Done && (StrBuf_ServGetln(Buf)>=0)) {
+               if ( (StrLength(Buf)==3) && 
+                    !strcmp(ChrPtr(Buf), "000")) {
+                       Done = 1;
+                       break;
+               }
+               bptr = ChrPtr(Buf);
+               switch (phase) {
+               case 0:
+                       if (!strncasecmp(bptr, "part=", 5)) {
+                               extract_token(mime_filename, &bptr[5], 1, '|', sizeof mime_filename);
+                               extract_token(mime_partnum, &bptr[5], 2, '|', sizeof mime_partnum);
+                               extract_token(mime_disposition, &bptr[5], 3, '|', sizeof mime_disposition);
+                               extract_token(mime_content_type, &bptr[5], 4, '|', sizeof mime_content_type);
+                               mime_length = extract_int(&bptr[5], 5);
+
+                               if (  (!strcasecmp(mime_content_type, "text/calendar"))
+                                     || (!strcasecmp(mime_content_type, "application/ics"))
+                                     || (!strcasecmp(mime_content_type, "text/vtodo"))
+                                       ) {
+                                       strcpy(relevant_partnum, mime_partnum);
                                }
-
-                               /* Otherwise recurse and hunt */
-                               else {
-
-                                       /* Simple components of desired type */
-                                       if (icalcomponent_isa(cal) == which_kind) {
-                                               callback(cal, msgnum, from, unread, calv);
-                                       }
-       
-                                       /* Subcomponents of desired type */
-                                       for (c = icalcomponent_get_first_component(cal, which_kind);
-                                       (c != 0);
-                                       c = icalcomponent_get_next_component(cal, which_kind)) {
-                                               callback(c, msgnum, from, unread, calv);
-                                       }
-
+                       }
+                       else if (!strncasecmp(bptr, "from=", 4)) {
+                               extract_token(from, bptr, 1, '=', sizeof(from));
+                       }
+                       else if ((phase == 0) && (!strncasecmp(bptr, "text", 4))) {
+                               phase = 1;
+                       }
+               break;
+               case 1:
+                       if (!IsEmptyStr(bptr)) {
+                               if (!strncasecmp(bptr, "Content-type: ", 14)) {
+                                       safestrncpy(msg4_content_type, &bptr[14], sizeof msg4_content_type);
+                                       striplt(msg4_content_type);
                                }
-
-                               icalcomponent_free(cal);
+                               else if (!strncasecmp(bptr, "Content-transfer-encoding: ", 27)) {
+                                       safestrncpy(msg4_content_encoding, &bptr[27], sizeof msg4_content_encoding);
+                                       striplt(msg4_content_type);
+                               }
+                               else if ((!strncasecmp(bptr, "Content-length: ", 16))) {
+                                       msg4_content_length = atoi(&bptr[16]);
+                               }
+                               break;
                        }
-                       free(relevant_source);
+                       else {
+                               phase++;
+                               
+                               if ((msg4_content_length > 0)
+                                   && ( !strcasecmp(msg4_content_encoding, "7bit"))
+                                   && ((!strcasecmp(mime_content_type, "text/calendar"))
+                                       || (!strcasecmp(mime_content_type, "application/ics"))
+                                       || (!strcasecmp(mime_content_type, "text/vtodo"))
+                                           )
+                                       ) 
+                               {
+                               }
+                       }
+               case 2:
+                       Data = NewStrBufPlain(NULL, msg4_content_length * 2);
+                       if (msg4_content_length > 0) {
+                               StrBuf_ServGetBLOBBuffered(Data, msg4_content_length);
+                               phase ++;
+                       }
+                       else {
+                               StrBufAppendBuf(Data, Buf, 0);
+                               StrBufAppendBufPlain(Data, "\r\n", 1, 0);
+                       }
+               case 3:
+                       StrBufAppendBuf(Data, Buf, 0);
                }
        }
+       FreeStrBuf(&Buf);
+
+       /* If MSG4 didn't give us the part we wanted, but we know that we can find it
+        * as one of the other MIME parts, attempt to load it now.
+        */
+       if ((Data == NULL) && (!IsEmptyStr(relevant_partnum))) {
+               Data = load_mimepart(msgnum, relevant_partnum);
+       }
+
+       if (Data != NULL) {
+               relevant_source = (char*) ChrPtr(Data);
+               process_ical_object(msgnum, unread,
+                                   from, 
+                                   relevant_source, 
+                                   which_kind,
+                                   CallBack,
+                                   calv);
+               FreeStrBuf (&Data);
+       }
+
        icalmemory_free_ring();
 }
 
@@ -1039,15 +1167,14 @@ void load_ical_object(long msgnum, int unread,
  * Display a calendar item
  */
 void load_calendar_item(message_summary *Msg, int unread, struct calview *c) {
-       /*load_ical_object(Msg->msgnum, unread, ICAL_VEVENT_COMPONENT, display_individual_cal, c);*/
-       load_ical_object(Msg->msgnum, unread, (-1), display_individual_cal, c);
+       load_ical_object(Msg->msgnum, unread, (-1), display_individual_cal, c, 1);
 }
 
 /*
  * Display task view
  */
 void display_task(message_summary *Msg, int unread) {
-       load_ical_object(Msg->msgnum, unread, ICAL_VTODO_COMPONENT, display_individual_cal, NULL);
+       load_ical_object(Msg->msgnum, unread, ICAL_VTODO_COMPONENT, display_individual_cal, NULL, 0);
 }
 
 /*
@@ -1065,9 +1192,9 @@ void display_edit_task(void) {
        if (msgnum > 0L) {
                /* existing task */
                load_ical_object(msgnum, 0,
-                                     ICAL_VTODO_COMPONENT,
-                                     display_edit_individual_task,
-                                     NULL
+                                ICAL_VTODO_COMPONENT,
+                                display_edit_individual_task,
+                                NULL, 0
                );
        }
        else {
@@ -1083,7 +1210,7 @@ void save_task(void) {
        long msgnum = 0L;
        msgnum = lbstr("msgnum");
        if (msgnum > 0L) {
-               load_ical_object(msgnum, 0, ICAL_VTODO_COMPONENT, save_individual_task, NULL);
+               load_ical_object(msgnum, 0, ICAL_VTODO_COMPONENT, save_individual_task, NULL, 0);
        }
        else {
                save_individual_task(NULL, 0L, "", 0, NULL);
@@ -1099,7 +1226,7 @@ void display_edit_event(void) {
        msgnum = lbstr("msgnum");
        if (msgnum > 0L) {
                /* existing event */
-               load_ical_object(msgnum, 0, ICAL_VEVENT_COMPONENT, display_edit_individual_event, NULL);
+               load_ical_object(msgnum, 0, ICAL_VEVENT_COMPONENT, display_edit_individual_event, NULL, 0);
        }
        else {
                /* new event */
@@ -1116,8 +1243,7 @@ void save_event(void) {
        msgnum = lbstr("msgnum");
 
        if (msgnum > 0L) {
-               /* load_ical_object(msgnum, 0, ICAL_VEVENT_COMPONENT, save_individual_event, NULL); */
-               load_ical_object(msgnum, 0, (-1), save_individual_event, NULL);
+               load_ical_object(msgnum, 0, (-1), save_individual_event, NULL, 0);
        }
        else {
                save_individual_event(NULL, 0L, "", 0, NULL);
@@ -1175,9 +1301,9 @@ void
 InitModule_CALENDAR
 (void)
 {
-       RegisterPreference(HKEY("daystart"), _("Calendar day view begins at:"), PRF_INT, NULL);
-       RegisterPreference(HKEY("dayend"), _("Calendar day view ends at:"), PRF_INT, NULL);
-       RegisterPreference(HKEY("weekstart"), _("Week starts on:"), PRF_INT, NULL);
+       RegisterPreference("daystart", _("Calendar day view begins at:"), PRF_INT, NULL);
+       RegisterPreference("dayend", _("Calendar day view ends at:"), PRF_INT, NULL);
+       RegisterPreference("weekstart", _("Week starts on:"), PRF_INT, NULL);
 
        WebcitAddUrlHandler(HKEY("display_edit_task"), display_edit_task, 0);
        WebcitAddUrlHandler(HKEY("save_task"), save_task, 0);