Back to index

webcit  8.12-dfsg
Classes | Functions
dav.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  epdata

Functions

void dav_common_headers (void)
void dav_main (void)
void dav_get (void)
void dav_put (void)
void dav_delete (void)
void dav_propfind (void)
void dav_options (void)
void dav_report (void)
long locate_message_by_uid (const char *)
void dav_folder_list (void)
void euid_escapize (char *, const char *)
void euid_unescapize (char *, const char *)
void dav_identify_host (void)
void dav_identify_hosthdr (void)
void RegisterDAVNamespace (const char *UrlString, long UrlSLen, const char *DisplayName, long dslen, WebcitHandlerFunc F, WebcitRESTDispatchID RID, long Flags)

Class Documentation

struct epdata

Definition at line 5 of file dav.h.

Class Members
char charset
char desired_content_type_1
char desired_content_type_2
char found_section

Function Documentation

void dav_common_headers ( void  )

Definition at line 31 of file dav_main.c.

                              {
       hprintf(
              "Server: %s / %s\r\n"
              "Connection: close\r\n",
              PACKAGE_STRING, ChrPtr(WC->serv_info->serv_software)
       );
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dav_delete ( void  )
  • What's left is the room name. Remove trailing slashes. */

Definition at line 23 of file dav_delete.c.

{
       wcsession *WCC = WC;
       char dav_uid[SIZ];
       long dav_msgnum = (-1);
       char buf[SIZ];
       int n = 0;
       StrBuf *dav_roomname = NewStrBuf();
       
       /* Now extract the message euid */
       n = StrBufNum_tokens(WCC->Hdr->HR.ReqLine, '/');
       extract_token(dav_uid, ChrPtr(WCC->Hdr->HR.ReqLine), n-1, '/', sizeof dav_uid);
       StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');

       //len = StrLength(WCC->Hdr->HR.ReqLine);
       //if ((len > 0) && (ChrPtr(WCC->Hdr->HR.ReqLinee)[len-1] == '/')) {
       //     StrBufCutRight(WCC->Hdr->HR.ReqLine, 1);
       //}
       //StrBufCutLeft(WCC->Hdr->HR.ReqLine, 1);

       /* Go to the correct room. */
       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
              gotoroom(dav_roomname);
       }
       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
              hprintf("HTTP/1.1 404 not found\r\n");
              dav_common_headers();
              hprintf("Content-Length: 0\r\n\r\n");
              begin_burst();
              end_burst();
              FreeStrBuf(&dav_roomname);
              return;
       }

       dav_msgnum = locate_message_by_uid(dav_uid);

       /*
        * If no item exists with the requested uid ... simple error.
        */
       if (dav_msgnum < 0L) {
              hprintf("HTTP/1.1 404 Not Found\r\n");
              dav_common_headers();
              hprintf("Content-Length: 0\r\n\r\n");
              begin_burst();
              end_burst();
              FreeStrBuf(&dav_roomname);
              return;
       }

       /*
        * It's there ... check the ETag and make sure it matches
        * the message number.
        */
       if (StrLength(WCC->Hdr->HR.dav_ifmatch) > 0) {
              if (StrTol(WCC->Hdr->HR.dav_ifmatch) != dav_msgnum) {
                     hprintf("HTTP/1.1 412 Precondition Failed\r\n");
                     dav_common_headers();
                     hprintf("Content-Length: 0\r\n\r\n");
                     begin_burst();
                     end_burst();
                     FreeStrBuf(&dav_roomname);
                     return;
              }
       }

       /*
        * Ok, attempt to delete the item.
        */
       serv_printf("DELE %ld", dav_msgnum);
       serv_getln(buf, sizeof buf);
       if (buf[0] == '2') {
              hprintf("HTTP/1.1 204 No Content\r\n");   /* success */
              dav_common_headers();
              hprintf("Content-Length: 0\r\n\r\n");
              begin_burst();
              end_burst();
       }
       else {
              hprintf("HTTP/1.1 403 Forbidden\r\n");    /* access denied */
              dav_common_headers();
              hprintf("Content-Length: 0\r\n\r\n");
              begin_burst();
              end_burst();
       }
       FreeStrBuf(&dav_roomname);
       return;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dav_folder_list ( void  )
void dav_get ( void  )

GET on the collection itself returns an ICS of the entire collection.

Definition at line 98 of file dav_get.c.

{
       wcsession *WCC = WC;
       StrBuf *dav_roomname;
       StrBuf *dav_uid;
       long dav_msgnum = (-1);
       char buf[1024];
       int in_body = 0;
       char *ptr;
       char *endptr;
       char *msgtext = NULL;
       size_t msglen = 0;
       size_t msgalloc = 0;
       int linelen;
       char content_type[128];
       char charset[128];
       char date[128];
       struct epdata epdata;

       if (StrBufNum_tokens(WCC->Hdr->HR.ReqLine, '/') < 2) {
              hprintf("HTTP/1.1 404 not found\r\n");
              dav_common_headers();
              hprintf("Content-Type: text/plain\r\n");
              wc_printf("The object you requested was not found.\r\n");
              end_burst();
              return;
       }

       dav_roomname = NewStrBuf();;
       dav_uid = NewStrBuf();;
       StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
       StrBufExtract_token(dav_uid, WCC->Hdr->HR.ReqLine, 1, '/');
       if ((!strcasecmp(ChrPtr(dav_uid), "ics")) || 
           (!strcasecmp(ChrPtr(dav_uid), "calendar.ics"))) {
              FlushStrBuf(dav_uid);
       }

       /* Go to the correct room. */
       if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
              gotoroom(dav_roomname);
       }
       if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
              hprintf("HTTP/1.1 404 not found\r\n");
              dav_common_headers();
              hprintf("Content-Type: text/plain\r\n");
              wc_printf("There is no folder called \"%s\" on this server.\r\n",
                     ChrPtr(dav_roomname));
              end_burst();
              FreeStrBuf(&dav_roomname);
              FreeStrBuf(&dav_uid);
              return;
       }

       if (StrLength(dav_uid) == 0) {
              dav_get_big_ics();
              FreeStrBuf(&dav_roomname);
              FreeStrBuf(&dav_uid);
              return;
       }

       dav_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
       serv_printf("MSG2 %ld", dav_msgnum);
       serv_getln(buf, sizeof buf);
       if (buf[0] != '1') {
              hprintf("HTTP/1.1 404 not found\r\n");
              dav_common_headers();
              hprintf("Content-Type: text/plain\r\n");
              wc_printf("Object \"%s\" was not found in the \"%s\" folder.\r\n",
                     ChrPtr(dav_uid),
                     ChrPtr(dav_roomname));
              end_burst();
              FreeStrBuf(&dav_roomname);
              FreeStrBuf(&dav_uid);
              return;
       }
       FreeStrBuf(&dav_roomname);
       FreeStrBuf(&dav_uid);

       /* We got it; a message is now arriving from the server.  Read it in. */

       in_body = 0;
       strcpy(charset, "UTF-8");
       strcpy(content_type, "text/plain");
       strcpy(date, "");
       while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
              linelen = strlen(buf);

              /* Append it to the buffer */
              if ((msglen + linelen + 3) > msgalloc) {
                     msgalloc = ( (msgalloc > 0) ? (msgalloc * 2) : 1024 );
                     msgtext = realloc(msgtext, msgalloc);
              }
              strcpy(&msgtext[msglen], buf);
              msglen += linelen;
              strcpy(&msgtext[msglen], "\n");
              msglen += 1;

              /* Also learn some things about the message */
              if (linelen == 0) {
                     in_body = 1;
              }
              if (!in_body) {
                     if (!strncasecmp(buf, "Date:", 5)) {
                            safestrncpy(date, &buf[5], sizeof date);
                            striplt(date);
                     }
                     if (!strncasecmp(buf, "Content-type:", 13)) {
                            safestrncpy(content_type, &buf[13], sizeof content_type);
                            striplt(content_type);
                            ptr = bmstrcasestr(&buf[13], "charset=");
                            if (ptr) {
                                   safestrncpy(charset, ptr+8, sizeof charset);
                                   striplt(charset);
                                   endptr = strchr(charset, ';');
                                   if (endptr != NULL) strcpy(endptr, "");
                            }
                            endptr = strchr(content_type, ';');
                            if (endptr != NULL) strcpy(endptr, "");
                     }
              }
       }
       msgtext[msglen] = 0;

       /* Output headers common to single or multi part messages */

       hprintf("HTTP/1.1 200 OK\r\n");
       dav_common_headers();
       hprintf("etag: \"%ld\"\r\n", dav_msgnum);
       hprintf("Date: %s\r\n", date);

       memset(&epdata, 0, sizeof(struct epdata));
       safestrncpy(epdata.charset, charset, sizeof epdata.charset);

       /* If we have a multipart message on our hands, and we are in a groupware room,
        * strip it down to only the relevant part.
        */
       if (!strncasecmp(content_type, "multipart/", 10)) {

              if ( (WCC->CurRoom.defview == VIEW_CALENDAR) || (WCC->CurRoom.defview == VIEW_TASKS) ) {
                     strcpy(epdata.desired_content_type_1, "text/calendar");
              }

              else if (WCC->CurRoom.defview == VIEW_ADDRESSBOOK) {
                     strcpy(epdata.desired_content_type_1, "text/vcard");
                     strcpy(epdata.desired_content_type_2, "text/x-vcard");
              }

              mime_parser(msgtext, &msgtext[msglen], extract_preferred, NULL, NULL, (void *)&epdata, 0);
       }

       /* If epdata.found_section is empty, we haven't output anything yet, so output the whole thing */

       if (IsEmptyStr(epdata.found_section)) {
              ptr = msgtext;
              endptr = &msgtext[msglen];
       
              hprintf("Content-type: %s; charset=%s\r\n", content_type, charset);
       
              in_body = 0;
              do {
                     ptr = memreadline(ptr, buf, sizeof buf);
       
                     if (in_body) {
                            wc_printf("%s\r\n", buf);
                     }
                     else if ((buf[0] == 0) && (in_body == 0)) {
                            in_body = 1;
                            begin_burst();
                     }
              } while (ptr < endptr);
       
              end_burst();
       }

       free(msgtext);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dav_identify_host ( void  )

Definition at line 192 of file dav_main.c.

                             {
       wc_printf("%s", ChrPtr(site_prefix));
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dav_identify_hosthdr ( void  )

Definition at line 205 of file dav_main.c.

                                {
       hprintf("%s", ChrPtr(site_prefix));
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dav_main ( void  )

Definition at line 97 of file dav_main.c.

{
       wcsession *WCC = WC;
       int i, len;

       syslog(LOG_DEBUG, "dav_main() called, logged_in=%d", WCC->logged_in );

       StrBufUnescape(WCC->Hdr->HR.ReqLine, 0);
       StrBufStripSlashes(WCC->Hdr->HR.ReqLine, 0);

       /*
        * If there's an If-Match: header, strip out the quotes if present, and
        * then if all that's left is an asterisk, make it go away entirely.
        */
       len = StrLength(WCC->Hdr->HR.dav_ifmatch);
       if (len > 0) {
              StrBufTrim(WCC->Hdr->HR.dav_ifmatch);
              if (ChrPtr(WCC->Hdr->HR.dav_ifmatch)[0] == '\"') {
                     StrBufCutLeft(WCC->Hdr->HR.dav_ifmatch, 1);
                     len --;
                     for (i=0; i<len; ++i) {
                            if (ChrPtr(WCC->Hdr->HR.dav_ifmatch)[i] == '\"') {
                                   StrBufCutAt(WCC->Hdr->HR.dav_ifmatch, i, NULL);
                                   len = StrLength(WCC->Hdr->HR.dav_ifmatch);
                            }
                     }
              }
              if (!strcmp(ChrPtr(WCC->Hdr->HR.dav_ifmatch), "*")) {
                     FlushStrBuf(WCC->Hdr->HR.dav_ifmatch);
              }
       }

       switch (WCC->Hdr->HR.eReqType)
       {
       /*
        * The OPTIONS method is not required by GroupDAV but it will be
        * needed for future implementations of other DAV-based protocols.
        */
       case eOPTIONS:
              dav_options();
              break;

       /*
        * The PROPFIND method is basically used to list all objects in a
        * room, or to list all relevant rooms on the server.
        */
       case ePROPFIND:
              dav_propfind();
              break;

       /*
        * The GET method is used for fetching individual items.
        */
       case eGET:
              dav_get();
              break;
       
       /*
        * The PUT method is used to add or modify items.
        */
       case ePUT:
              dav_put();
              break;
       
       /*
        * The DELETE method kills, maims, and destroys.
        */
       case eDELETE:
              dav_delete();
              break;

       /*
        * The REPORT method tells us that Mike Shaver is a self-righteous asshole.
        */
       case eREPORT:
              dav_report();
              break;

       default:
       /*
        * Couldn't find what we were looking for.  Die in a car fire.
        */
              hprintf("HTTP/1.1 501 Method not implemented\r\n");
              dav_common_headers();
              hprintf("Content-Type: text/plain\r\n");
              wc_printf("GroupDAV method \"%s\" is not implemented.\r\n",
                     ReqStrs[WCC->Hdr->HR.eReqType]);
              end_burst();
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dav_options ( void  )

Definition at line 22 of file dav_options.c.

{
       wcsession *WCC = WC;
       StrBuf *dav_roomname;
       StrBuf *dav_uid;
       long dav_msgnum = (-1);
       char datestring[256];
       time_t now;

       now = time(NULL);
       http_datestring(datestring, sizeof datestring, now);

       dav_roomname = NewStrBuf();
       dav_uid = NewStrBuf();
       StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
       StrBufExtract_token(dav_uid, WCC->Hdr->HR.ReqLine, 1, '/');

       syslog(LOG_DEBUG, "\033[35m%s (logged_in=%d)\033[0m", ChrPtr(WCC->Hdr->HR.ReqLine), WC->logged_in);
       /*
        * If the room name is blank, the client is doing an OPTIONS on the root.
        */
       if (StrLength(dav_roomname) == 0) {
              syslog(LOG_DEBUG, "\033[36mOPTIONS requested for root\033[0m");
              hprintf("HTTP/1.1 200 OK\r\n");
              dav_common_headers();
              hprintf("Date: %s\r\n", datestring);
              hprintf("DAV: 1\r\n");
              hprintf("Allow: OPTIONS, PROPFIND\r\n");
              hprintf("\r\n");
              begin_burst();
              end_burst();
              FreeStrBuf(&dav_roomname);
              FreeStrBuf(&dav_uid);
              return;
       }

       /* Go to the correct room. */
       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
              gotoroom(dav_roomname);
       }

       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
              syslog(LOG_DEBUG, "\033[36mOPTIONS requested for invalid item\033[0m");
              hprintf("HTTP/1.1 404 not found\r\n");
              dav_common_headers();
              hprintf("Date: %s\r\n", datestring);
              hprintf(
                     "Content-Type: text/plain\r\n");
              begin_burst();
              wc_printf(
                     "There is no folder called \"%s\" on this server.\r\n",
                     ChrPtr(dav_roomname)
              );
              end_burst();
              FreeStrBuf(&dav_roomname);
              FreeStrBuf(&dav_uid);
              return;
       }

       /* If dav_uid is non-empty, client is requesting an OPTIONS on
        * a specific item in the room.
        */
       if (StrLength(dav_uid) != 0) {
              syslog(LOG_DEBUG, "\033[36mOPTIONS requested for specific item\033[0m");
              dav_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
              if (dav_msgnum < 0) {
                     hprintf("HTTP/1.1 404 not found\r\n");
                     dav_common_headers();
                     hprintf("Content-Type: text/plain\r\n");
                     begin_burst();
                     wc_printf(
                            "Object \"%s\" was not found in the \"%s\" folder.\r\n",
                            ChrPtr(dav_uid),
                            ChrPtr(dav_roomname)
                     );
                     FreeStrBuf(&dav_roomname);
                     FreeStrBuf(&dav_uid);
                     end_burst();return;
              }

              hprintf("HTTP/1.1 200 OK\r\n");
              dav_common_headers();
              hprintf("Date: %s\r\n", datestring);
              hprintf("DAV: 1\r\n");
              hprintf("Allow: OPTIONS, PROPFIND, GET, PUT, DELETE\r\n");
              
              begin_burst();
              end_burst();
              FreeStrBuf(&dav_roomname);
              FreeStrBuf(&dav_uid);
              return;
       }

       FreeStrBuf(&dav_roomname);
       FreeStrBuf(&dav_uid);

       /*
        * We got to this point, which means that the client is requesting
        * an OPTIONS on the room itself.
        */
       syslog(LOG_DEBUG, "\033[36mOPTIONS requested for room '%s' (%slogged in)\033[0m",
              ChrPtr(WC->CurRoom.name),
              ((WC->logged_in) ? "" : "not ")
       );
       hprintf("HTTP/1.1 200 OK\r\n");
       dav_common_headers();
       hprintf("Date: %s\r\n", datestring);

       /*
        * Offer CalDAV (RFC 4791) if this is a calendar room
        */
       if ( (WC->CurRoom.view == VIEW_CALENDAR) || (WC->CurRoom.view == VIEW_CALBRIEF) ) {
              hprintf("DAV: 1, calendar-access\r\n");
              syslog(LOG_DEBUG, "\033[36mDAV: 1, calendar-access\033[0m");
       }
       else {
              hprintf("DAV: 1\r\n");
              syslog(LOG_DEBUG, "\033[36mDAV: 1\033[0m");
       }

       hprintf("Allow: OPTIONS, PROPFIND, GET, PUT, REPORT\r\n");
       begin_burst();
       end_burst();
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dav_propfind ( void  )

Definition at line 460 of file dav_propfind.c.

{
       wcsession *WCC = WC;
       StrBuf *dav_roomname;
       StrBuf *dav_uid;
       StrBuf *MsgNum;
       long BufLen;
       long dav_msgnum = (-1);
       char uid[256];
       char encoded_uid[256];
       long *msgs = NULL;
       int num_msgs = 0;
       int i;
       char datestring[256];
       time_t now;

       now = time(NULL);
       http_datestring(datestring, sizeof datestring, now);

       int parse_success = 0;
       XML_Parser xp = XML_ParserCreateNS(NULL, '|');
       if (xp) {
              // XML_SetUserData(xp, XXX);
              XML_SetElementHandler(xp, propfind_xml_start, propfind_xml_end);
              // XML_SetCharacterDataHandler(xp, xrds_xml_chardata);

              const char *req = ChrPtr(WCC->upload);
              if (req) {
                     req = strchr(req, '<');                   /* hunt for the first tag */
              }
              if (!req) {
                     req = "ERROR";                            /* force it to barf */
              }

              i = XML_Parse(xp, req, strlen(req), 1);
              if (!i) {
                     syslog(LOG_DEBUG, "XML_Parse() failed: %s", XML_ErrorString(XML_GetErrorCode(xp)));
                     XML_ParserFree(xp);
                     parse_success = 0;
              }
              else {
                     parse_success = 1;
              }
       }

       if (!parse_success) {
              hprintf("HTTP/1.1 500 Internal Server Error\r\n");
              dav_common_headers();
              hprintf("Date: %s\r\n", datestring);
              hprintf("Content-Type: text/plain\r\n");
              wc_printf("An internal error has occurred at %s:%d.\r\n", __FILE__ , __LINE__ );
              end_burst();
              return;
       }

       dav_roomname = NewStrBuf();
       dav_uid = NewStrBuf();
       StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
       StrBufExtract_token(dav_uid, WCC->Hdr->HR.ReqLine, 1, '/');

       syslog(LOG_DEBUG, "PROPFIND requested for '%s' at depth %d",
              ChrPtr(dav_roomname), WCC->Hdr->HR.dav_depth
       );

       /*
        * If the room name is blank, the client is requesting a folder list.
        */
       if (StrLength(dav_roomname) == 0) {
              dav_collection_list();
              FreeStrBuf(&dav_roomname);
              FreeStrBuf(&dav_uid);
              return;
       }

       /* Go to the correct room. */
       if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
              gotoroom(dav_roomname);
       }
       if (strcasecmp(ChrPtr(WCC->CurRoom.name), ChrPtr(dav_roomname))) {
              hprintf("HTTP/1.1 404 not found\r\n");
              dav_common_headers();
              hprintf("Date: %s\r\n", datestring);
              hprintf("Content-Type: text/plain\r\n");
              wc_printf("There is no folder called \"%s\" on this server.\r\n", ChrPtr(dav_roomname));
              end_burst();
              FreeStrBuf(&dav_roomname);
              FreeStrBuf(&dav_uid);
              return;
       }

       /* If dav_uid is non-empty, client is requesting a PROPFIND on
        * a specific item in the room.  This is not valid GroupDAV, but
        * it is valid WebDAV (and probably CalDAV too).
        */
       if (StrLength(dav_uid) != 0) {

              dav_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
              if (dav_msgnum < 0) {
                     hprintf("HTTP/1.1 404 not found\r\n");
                     dav_common_headers();
                     hprintf("Content-Type: text/plain\r\n");
                     wc_printf("Object \"%s\" was not found in the \"%s\" folder.\r\n",
                            ChrPtr(dav_uid),
                            ChrPtr(dav_roomname)
                     );
                     end_burst();
                     FreeStrBuf(&dav_roomname);
                     FreeStrBuf(&dav_uid);
                     return;
              }

              /* Be rude.  Completely ignore the XML request and simply send them
               * everything we know about (which is going to simply be the ETag and
               * nothing else).  Let the client-side parser sort it out.
               */
              hprintf("HTTP/1.0 207 Multi-Status\r\n");
              dav_common_headers();
              hprintf("Date: %s\r\n", datestring);
              hprintf("Content-type: text/xml\r\n");
              if (DisableGzip || (!WCC->Hdr->HR.gzip_ok))      
                     hprintf("Content-encoding: identity\r\n");
       
              begin_burst();
       
              wc_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
                     "<multistatus xmlns=\"DAV:\">"
              );

              wc_printf("<response>");
              
              wc_printf("<href>");
              dav_identify_host();
              wc_printf("/groupdav/");
              urlescputs(ChrPtr(WCC->CurRoom.name));
              euid_escapize(encoded_uid, ChrPtr(dav_uid));
              wc_printf("/%s", encoded_uid);
              wc_printf("</href>");
              wc_printf("<propstat>");
              wc_printf("<status>HTTP/1.1 200 OK</status>");
              wc_printf("<prop>");
              wc_printf("<getetag>\"%ld\"</getetag>", dav_msgnum);
              wc_printf("<getlastmodified>");
              escputs(datestring);
              wc_printf("</getlastmodified>");
              wc_printf("</prop>");
              wc_printf("</propstat>");

              wc_printf("</response>\n");
              wc_printf("</multistatus>\n");
              end_burst();
              FreeStrBuf(&dav_roomname);
              FreeStrBuf(&dav_uid);
              return;
       }
       FreeStrBuf(&dav_roomname);
       FreeStrBuf(&dav_uid);


       /*
        * If we get to this point the client is performing a PROPFIND on the room itself.
        *
        * We call it a room; DAV calls it a "collection."  We have to give it some properties
        * of the room itself and then offer a list of all items contained therein.
        *
        * Be rude.  Completely ignore the XML request and simply send them
        * everything we know about (which is going to simply be the ETag and
        * nothing else).  Let the client-side parser sort it out.
        */
       //syslog(LOG_DEBUG, "BE RUDE AND IGNORE: \033[31m%s\033[0m", ChrPtr(WC->upload) );
       hprintf("HTTP/1.0 207 Multi-Status\r\n");
       dav_common_headers();
       hprintf("Date: %s\r\n", datestring);
       hprintf("Content-type: text/xml\r\n");
       if (DisableGzip || (!WCC->Hdr->HR.gzip_ok)) {
              hprintf("Content-encoding: identity\r\n");
       }
       begin_burst();

       wc_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
              "<D:multistatus "
                     "xmlns:D=\"DAV:\" "
                     "xmlns:G=\"http://groupdav.org/\" "
                     "xmlns:C=\"urn:ietf:params:xml:ns:caldav\""
              ">"
       );

       /* Transmit the collection resource */
       wc_printf("<D:response>");

       wc_printf("<D:href>");
       dav_identify_host();
       wc_printf("/groupdav/");
       urlescputs(ChrPtr(WCC->CurRoom.name));
       wc_printf("</D:href>");

       wc_printf("<D:propstat>");
       wc_printf("<D:status>HTTP/1.1 200 OK</D:status>");
       wc_printf("<D:prop>");
       wc_printf("<D:displayname>");
       escputs(ChrPtr(WCC->CurRoom.name));
       wc_printf("</D:displayname>");

       wc_printf("<D:owner/>");           /* empty owner ought to be legal; see rfc3744 section 5.1 */

       wc_printf("<D:resourcetype><D:collection/>");
       switch(WCC->CurRoom.defview) {
              case VIEW_CALENDAR:
                     wc_printf("<G:vevent-collection />");
                     wc_printf("<C:calendar />");
                     break;
              case VIEW_TASKS:
                     wc_printf("<G:vtodo-collection />");
                     break;
              case VIEW_ADDRESSBOOK:
                     wc_printf("<G:vcard-collection />");
                     break;
       }
       wc_printf("</D:resourcetype>");

       /* FIXME get the mtime
       wc_printf("<D:getlastmodified>");
              escputs(datestring);
       wc_printf("</D:getlastmodified>");
       */
       wc_printf("</D:prop>");
       wc_printf("</D:propstat>");
       wc_printf("</D:response>");

       /* If a depth greater than zero was specified, transmit the collection listing */

       if (WCC->Hdr->HR.dav_depth > 0) {
              MsgNum = NewStrBuf();
              serv_puts("MSGS ALL");
       
              StrBuf_ServGetln(MsgNum);
              if (GetServerStatus(MsgNum, NULL) == 1)
                     while (BufLen = StrBuf_ServGetln(MsgNum), 
                            ((BufLen >= 0) && 
                            ((BufLen != 3) || strcmp(ChrPtr(MsgNum), "000"))  ))
                     {
                            msgs = realloc(msgs, ++num_msgs * sizeof(long));
                            msgs[num_msgs-1] = StrTol(MsgNum);
                     }
       
              if (num_msgs > 0) for (i=0; i<num_msgs; ++i) {
       
                     syslog(LOG_DEBUG, "PROPFIND enumerating message # %ld", msgs[i]);
                     strcpy(uid, "");
                     now = (-1);
                     serv_printf("MSG0 %ld|3", msgs[i]);
                     StrBuf_ServGetln(MsgNum);
                     if (GetServerStatus(MsgNum, NULL) == 1)
                            while (BufLen = StrBuf_ServGetln(MsgNum), 
                                   ((BufLen >= 0) && 
                                   ((BufLen != 3) || strcmp(ChrPtr(MsgNum), "000")) ))
                            {
                                   if (!strncasecmp(ChrPtr(MsgNum), "exti=", 5)) {
                                          strcpy(uid, &ChrPtr(MsgNum)[5]);
                                   }
                                   else if (!strncasecmp(ChrPtr(MsgNum), "time=", 5)) {
                                          now = atol(&ChrPtr(MsgNum)[5]);
                            }
                     }
       
                     if (!IsEmptyStr(uid)) {
                            wc_printf("<D:response>");
                                   wc_printf("<D:href>");
                                          dav_identify_host();
                                          wc_printf("/groupdav/");
                                          urlescputs(ChrPtr(WCC->CurRoom.name));
                                          euid_escapize(encoded_uid, uid);
                                          wc_printf("/%s", encoded_uid);
                                   wc_printf("</D:href>");
                                   switch(WCC->CurRoom.defview) {
                                   case VIEW_CALENDAR:
                                          wc_printf("<D:getcontenttype>text/x-ical</D:getcontenttype>");
                                          break;
                                   case VIEW_TASKS:
                                          wc_printf("<D:getcontenttype>text/x-ical</D:getcontenttype>");
                                          break;
                                   case VIEW_ADDRESSBOOK:
                                          wc_printf("<D:getcontenttype>text/x-vcard</D:getcontenttype>");
                                          break;
                                   }
                                   wc_printf("<D:propstat>");
                                          wc_printf("<D:status>HTTP/1.1 200 OK</D:status>");
                                          wc_printf("<D:prop>");
                                                 wc_printf("<D:getetag>\"%ld\"</D:getetag>", msgs[i]);
                                          if (now > 0L) {
                                                 http_datestring(datestring, sizeof datestring, now);
                                                 wc_printf("<D:getlastmodified>");
                                                 escputs(datestring);
                                                 wc_printf("</D:getlastmodified>");
                                          }
                                          wc_printf("</D:prop>");
                                   wc_printf("</D:propstat>");
                            wc_printf("</D:response>");
                     }
              }
              FreeStrBuf(&MsgNum);
       }

       wc_printf("</D:multistatus>\n");
       end_burst();

       if (msgs != NULL) {
              free(msgs);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dav_put ( void  )

PUT on the collection itself uploads an ICS of the entire collection.

Definition at line 67 of file dav_put.c.

{
       wcsession *WCC = WC;
       StrBuf *dav_roomname;
       StrBuf *dav_uid;
       long new_msgnum = (-2L);
       long old_msgnum = (-1L);
       char buf[SIZ];
       int n = 0;

       if (StrBufNum_tokens(WCC->Hdr->HR.ReqLine, '/') < 2) {
              hprintf("HTTP/1.1 404 not found\r\n");
              dav_common_headers();
              hprintf("Content-Type: text/plain\r\n");
              begin_burst();
              wc_printf("The object you requested was not found.\r\n");
              end_burst();
              return;
       }

       dav_roomname = NewStrBuf();;
       dav_uid = NewStrBuf();;
       StrBufExtract_token(dav_roomname, WCC->Hdr->HR.ReqLine, 0, '/');
       StrBufExtract_token(dav_uid, WCC->Hdr->HR.ReqLine, 1, '/');
       if ((!strcasecmp(ChrPtr(dav_uid), "ics")) || 
           (!strcasecmp(ChrPtr(dav_uid), "calendar.ics"))) {
              FlushStrBuf(dav_uid);
       }

       /* Go to the correct room. */
       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
              gotoroom(dav_roomname);
       }
       if (strcasecmp(ChrPtr(WC->CurRoom.name), ChrPtr(dav_roomname))) {
              hprintf("HTTP/1.1 404 not found\r\n");
              dav_common_headers();
              hprintf("Content-Type: text/plain\r\n");
              begin_burst();
              wc_printf("There is no folder called \"%s\" on this server.\r\n",
                     ChrPtr(dav_roomname));
              end_burst();
              FreeStrBuf(&dav_roomname);
              FreeStrBuf(&dav_uid);              
              return;
       }

       /*
        * If an HTTP If-Match: header is present, the client is attempting
        * to replace an existing item.  We have to check to see if the
        * message number associated with the supplied uid matches what the
        * client is expecting.  If not, the server probably contains a newer
        * version, so we fail...
        */
       if (StrLength(WCC->Hdr->HR.dav_ifmatch) > 0) {
              syslog(9, "dav_ifmatch: %s\n", ChrPtr(WCC->Hdr->HR.dav_ifmatch));
              old_msgnum = locate_message_by_uid(ChrPtr(dav_uid));
              syslog(9, "old_msgnum:  %ld\n", old_msgnum);
              if (StrTol(WCC->Hdr->HR.dav_ifmatch) != old_msgnum) {
                     hprintf("HTTP/1.1 412 Precondition Failed\r\n");
                     syslog(9, "HTTP/1.1 412 Precondition Failed (ifmatch=%ld, old_msgnum=%ld)\r\n",
                            StrTol(WCC->Hdr->HR.dav_ifmatch), old_msgnum);
                     dav_common_headers();
                     
                     end_burst();
                     FreeStrBuf(&dav_roomname);
                     FreeStrBuf(&dav_uid);
                     return;
              }
       }

       if (StrLength(dav_uid) == 0) {
              dav_put_bigics();
              FreeStrBuf(&dav_roomname);
              FreeStrBuf(&dav_uid);
              return;
       }

       /*
        * We are cleared for upload!  We use the new calling syntax for ENT0
        * which allows a confirmation to be sent back to us.  That's how we
        * extract the message ID.
        */
       serv_puts("ENT0 1|||4|||1|");
       serv_getln(buf, sizeof buf);
       if (buf[0] != '8') {
              hprintf("HTTP/1.1 502 Bad Gateway\r\n");
              dav_common_headers();
              hprintf("Content-type: text/plain\r\n");
              begin_burst();
              wc_printf("%s\r\n", &buf[4]);
              end_burst();
              return;
       }

       /* Send the content to the Citadel server */
       //serv_printf("Content-type: %s\n\n", WCC->upload_content_type);
       serv_putbuf(WCC->upload);
       serv_puts("\n000");

       /* Fetch the reply from the Citadel server */
       n = 0;
       FlushStrBuf(dav_uid);
       while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
              switch(n++) {
              case 0: 
                     new_msgnum = atol(buf);
                     break;
              case 1:       
                     syslog(9, "new_msgnum=%ld (%s)\n", new_msgnum, buf);
                     break;
              case 2: 
                     StrBufAppendBufPlain(dav_uid, buf, -1, 0);
                     break;
              default:
                     break;
              }
       }

       /* Tell the client what happened. */

       /* Citadel failed in some way? */
       if (new_msgnum < 0L) {
              hprintf("HTTP/1.1 502 Bad Gateway\r\n");
              dav_common_headers();
              hprintf("Content-type: text/plain\r\n");
              begin_burst();
              wc_printf("new_msgnum is %ld\r\n"
                     "\r\n", new_msgnum);
              end_burst();
              FreeStrBuf(&dav_roomname);
              FreeStrBuf(&dav_uid);
              return;
       }

       /* We created this item for the first time. */
       if (old_msgnum < 0L) {
               char escaped_uid[1024];
              hprintf("HTTP/1.1 201 Created\r\n");
              syslog(9, "HTTP/1.1 201 Created\r\n");
              dav_common_headers();
              hprintf("etag: \"%ld\"\r\n", new_msgnum);
              hprintf("Location: ");
              dav_identify_hosthdr();
              hprintf("/groupdav/");/* TODO */
              hurlescputs(ChrPtr(dav_roomname));
               euid_escapize(escaped_uid, ChrPtr(dav_uid));
               hprintf("/%s\r\n", escaped_uid);
              end_burst();
              FreeStrBuf(&dav_roomname);
              FreeStrBuf(&dav_uid);
              return;
       }

       /* We modified an existing item. */
       hprintf("HTTP/1.1 204 No Content\r\n");
       syslog(9, "HTTP/1.1 204 No Content\r\n");
       dav_common_headers();
       hprintf("Etag: \"%ld\"\r\n", new_msgnum);
       /* The item we replaced has probably already been deleted by
        * the Citadel server, but we'll do this anyway, just in case.
        */
       serv_printf("DELE %ld", old_msgnum);
       serv_getln(buf, sizeof buf);
       begin_burst();
       end_burst();
       FreeStrBuf(&dav_roomname);
       FreeStrBuf(&dav_uid);
       return;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dav_report ( void  )

Definition at line 61 of file dav_report.c.

{
       char datestring[256];
       time_t now = time(NULL);

       http_datestring(datestring, sizeof datestring, now);
       const char *req = ChrPtr(WC->upload);

       syslog(LOG_DEBUG, "REPORT: \033[31m%s\033[0m", req);

       hprintf("HTTP/1.1 500 Internal Server Error\r\n");
       dav_common_headers();
       hprintf("Date: %s\r\n", datestring);
       hprintf("Content-Type: text/plain\r\n");
       wc_printf("An internal error has occurred at %s:%d.\r\n", __FILE__ , __LINE__ );
       end_burst();
       return;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void euid_escapize ( char *  ,
const char *   
)

Definition at line 44 of file dav_main.c.

                                                     {
       int i, len;
       int target_length = 0;

       strcpy(target, "");
       len = strlen(source);
       for (i=0; i<len; ++i) {
              if ( (isalnum(source[i])) || (source[i]=='-') || (source[i]=='_') ) {
                     target[target_length] = source[i];
                     target[++target_length] = 0;
              }
              else {
                     sprintf(&target[target_length], "=%02X", (0xFF & source[i]));
                     target_length += 3;
              }
       }
}

Here is the caller graph for this function:

void euid_unescapize ( char *  ,
const char *   
)

Definition at line 65 of file dav_main.c.

                                                       {
       int a, b, len;
       char hex[3];
       int target_length = 0;

       strcpy(target, "");

       len = strlen(source);
       for (a = 0; a < len; ++a) {
              if (source[a] == '=') {
                     hex[0] = source[a + 1];
                     hex[1] = source[a + 2];
                     hex[2] = 0;
                     b = 0;
                     b = decode_hex(hex);
                     target[target_length] = b;
                     target[++target_length] = 0;
                     a += 2;
              }
              else {
                     target[target_length] = source[a];
                     target[++target_length] = 0;
              }
       }
}

Here is the caller graph for this function:

long locate_message_by_uid ( const char *  )

Definition at line 54 of file dav_propfind.c.

                                            {
       char buf[256];
       char decoded_uid[1024];
       long retval = (-1L);

       /* decode the UID */
       euid_unescapize(decoded_uid, uid);

       /* ask Citadel if we have this one */
       serv_printf("EUID %s", decoded_uid);
       serv_getln(buf, sizeof buf);
       if (buf[0] == '2') {
              retval = atol(&buf[4]);
       }

       return(retval);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void RegisterDAVNamespace ( const char *  UrlString,
long  UrlSLen,
const char *  DisplayName,
long  dslen,
WebcitHandlerFunc  F,
WebcitRESTDispatchID  RID,
long  Flags 
)

Definition at line 236 of file dav_main.c.

{
       void *vHandler;

       /* first put it in... */
       WebcitAddUrlHandler(UrlString, UrlSLen, DisplayName, dslen, F, Flags|PARSE_REST_URL);
       /* get it out again... */
       GetHash(HandlerHash, UrlString, UrlSLen, &vHandler);
       ((WebcitHandler*)vHandler)->RID = RID;
       /* and keep a copy of it, so we can compare it later */
       Put(DavNamespaces, UrlString, UrlSLen, vHandler, reference_free_handler);
}

Here is the call graph for this function:

Here is the caller graph for this function: