/* * Display a specific page from a wiki room * * "rev" may be set to an empty string to display the current version. * "do_revert" may be set to nonzero to perform a reversion to the specified version. */ void display_wiki_page_backend(char *pagename, char *rev, int do_revert) { wcsession *WCC = WC; const StrBuf *Mime; long msgnum = (-1L); char buf[256]; if ((WCC->CurRoom.view != VIEW_WIKI) && (WCC->CurRoom.view != VIEW_WIKIMD)) { wc_printf(_("'%s' is not a Wiki room."), ChrPtr(WCC->CurRoom.name) ); return; } if (IsEmptyStr(pagename)) { strcpy(pagename, "home"); } str_wiki_index(pagename); /* convert index name to lowercase and numeric only */ if ((rev != NULL) && (strlen(rev) > 0)) { /* read an older revision */ serv_printf("WIKI rev|%s|%s|%s", pagename, rev, (do_revert ? "revert" : "fetch") ); serv_getln(buf, sizeof buf); if (buf[0] == '2') { msgnum = extract_long(&buf[4], 0); } } else { /* read the current revision */ msgnum = locate_message_by_uid(pagename); } if (msgnum >= 0L) { read_message(WCC->WBuf, HKEY("view_message"), msgnum, NULL, &Mime); return; } wc_printf("<br><br>" "<div align=\"center\">" "<table border=\"0\" bgcolor=\"#ffffff\" cellpadding=\"10\">" "<tr><td align=\"center\">" ); wc_printf("<br><b>"); wc_printf(_("There is no page called '%s' here."), pagename); wc_printf("</b><br><br>"); wc_printf(_("Select the 'Edit this page' link in the room banner " "if you would like to create this page.")); wc_printf("<br><br>"); wc_printf("</td></tr></table></div>\n"); }
/* * The pathname is always going to be /groupdav/room_name/euid */ void dav_delete(void) { 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, '/'); ///* What's left is the room name. Remove trailing slashes. */ //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; }
/* * The pathname is always going to take one of two formats: * [/groupdav/]room_name/euid (GroupDAV) * [/groupdav/]room_name (webcal) */ void dav_put(void) { 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(LOG_DEBUG, "dav_ifmatch: %s\n", ChrPtr(WCC->Hdr->HR.dav_ifmatch)); old_msgnum = locate_message_by_uid(ChrPtr(dav_uid)); syslog(LOG_DEBUG, "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(LOG_INFO, "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; } } /** PUT on the collection itself uploads an ICS of the entire collection. */ 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(LOG_DEBUG, "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(LOG_DEBUG, "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(LOG_DEBUG, "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; }
/* * The pathname is always going to be /groupdav/room_name/msg_num */ void dav_options(void) { 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(); }