Skeleton code for filters.
[citadel.git] / webcit-ng / server / room_functions.c
index 67b3e9082943ca78a952b0048e00c6d8fa9a3ff5..09e7bac39f307cd41c3cde7e04028c55a0992648 100644 (file)
@@ -1,39 +1,32 @@
 // Room functions
 //
-// Copyright (c) 1996-2022 by the citadel.org team
+// Copyright (c) 1996-2024 by the citadel.org team
 //
-// This program is open source software.  Use, duplication, or
-// disclosure are subject to the GNU General Public License v3.
+// This program is open source software.  Use, duplication, or disclosure is subject to the GNU General Public License v3.
 
 #include "webcit.h"
 
 
-// Return a "zero-terminated" array of message numbers in the current room.
+// Return an array of message numbers in the current room.
 // Caller owns the memory and must free it.  Returns NULL if any problems.
-long *get_msglist(struct ctdlsession *c, char *which_msgs) {
+Array *get_msglist(struct ctdlsession *c, char *which_msgs) {
        char buf[1024];
-       long *msglist = NULL;
-       int num_msgs = 0;
-       int num_alloc = 0;
+       Array *msglist = NULL;
+
+       msglist = array_new(sizeof(long));
+       if (msglist == NULL) {
+               return(NULL);
+       }
 
        ctdl_printf(c, "MSGS %s", which_msgs);
        ctdl_readline(c, buf, sizeof(buf));
        if (buf[0] == '1') {
-               do {
-                       if (num_msgs >= num_alloc) {
-                               if (num_alloc == 0) {
-                                       num_alloc = 1024;
-                                       msglist = malloc(num_alloc * sizeof(long));
-                               }
-                               else {
-                                       num_alloc *= 2;
-                                       msglist = realloc(msglist, num_alloc * sizeof(long));
-                               }
-                       }
-                       ctdl_readline(c, buf, sizeof(buf));
-                       msglist[num_msgs++] = atol(buf);
-               } while (strcmp(buf, "000"));   // this makes the last element a "0" terminator
+               while (ctdl_readline(c, buf, sizeof(buf)), strcmp(buf, "000")) { 
+                       long m = atol(buf);
+                       array_append(msglist, &m);
+               }
        }
+
        return msglist;
 }
 
@@ -52,14 +45,14 @@ int match_etags(char *taglist, long msgnum) {
 
        for (i = 0; i < num_tags; ++i) {
                extract_token(tag, taglist, i, ',', sizeof tag);
-               striplt(tag);
+               string_trim(tag);
                char *lq = (strchr(tag, '"'));
                char *rq = (strrchr(tag, '"'));
                if (lq < rq) {                                  // has two double quotes
                        strcpy(rq, "");
                        strcpy(tag, ++lq);
                }
-               striplt(tag);
+               string_trim(tag);
                if (!strcmp(tag, "*")) {                        // wildcard match
                        return (1);
                }
@@ -111,18 +104,21 @@ void json_mailbox(struct http_transaction *h, struct ctdlsession *c) {
        ctdl_readline(c, buf, sizeof(buf));
        if (buf[0] == '1') {
                while (ctdl_readline(c, buf, sizeof(buf)), (strcmp(buf, "000"))) {
-                       utf8ify_rfc822_string(buf);
                        JsonValue *jmsg = NewJsonObject(HKEY("message"));
                        JsonObjectAppend(jmsg, NewJsonNumber(HKEY("msgnum"), extract_long(buf, 0)));
                        JsonObjectAppend(jmsg, NewJsonNumber(HKEY("time"), extract_long(buf, 1)));
                        extract_token(field, buf, 2, '|', sizeof field);
+                       utf8ify_rfc822_string(field);
                        JsonObjectAppend(jmsg, NewJsonPlainString(HKEY("author"), field, -1));
                        extract_token(field, buf, 4, '|', sizeof field);
+                       utf8ify_rfc822_string(field);
                        JsonObjectAppend(jmsg, NewJsonPlainString(HKEY("addr"), field, -1));
                        extract_token(field, buf, 5, '|', sizeof field);
+                       utf8ify_rfc822_string(field);
                        JsonObjectAppend(jmsg, NewJsonPlainString(HKEY("subject"), field, -1));
                        JsonObjectAppend(jmsg, NewJsonNumber(HKEY("msgidhash"), extract_long(buf, 6)));
                        extract_token(field, buf, 7, '|', sizeof field);
+                       utf8ify_rfc822_string(field);
                        JsonObjectAppend(jmsg, NewJsonPlainString(HKEY("references"), field, -1));
                        JsonArrayAppend(j, jmsg);               // add the message to the array
                }
@@ -143,14 +139,16 @@ void json_mailbox(struct http_transaction *h, struct ctdlsession *c) {
 // Client is requesting a message list
 void json_msglist(struct http_transaction *h, struct ctdlsession *c, char *which) {
        int i = 0;
-       long *msglist = get_msglist(c, which);
+       Array *msglist = get_msglist(c, which);
        JsonValue *j = NewJsonArray(HKEY("msgs"));
 
        if (msglist != NULL) {
-               for (i = 0; msglist[i] > 0; ++i) {
-                       JsonArrayAppend(j, NewJsonNumber(HKEY("m"), msglist[i]));
+               for (i = 0; i < array_len(msglist); ++i) {
+                       long m;
+                       memcpy(&m, array_get_element_at(msglist, i), sizeof(long));
+                       JsonArrayAppend(j, NewJsonNumber(HKEY("m"), m));
                }
-               free(msglist);
+               array_free(msglist);
        }
 
        StrBuf *sj = NewStrBuf();
@@ -262,7 +260,7 @@ void object_in_room(struct http_transaction *h, struct ctdlsession *c) {
        // A sixth component in the URL can be one of two things:
        // (1) a MIME part specifier, in which case the client wants to download that component within the message
        // (2) a content-type, in which ase the client wants us to try to render it a certain way
-       if (num_tokens(h->url, '/') == 6) {
+       if (num_tokens(h->url, '/') >= 6) {
                extract_token(buf, h->url, 5, '/', sizeof buf);
                if (!IsEmptyStr(buf)) {
                        if (!strcasecmp(buf, "json")) {
@@ -288,8 +286,7 @@ void object_in_room(struct http_transaction *h, struct ctdlsession *c) {
                return;
        }
 
-       // DOOOOOO ITTTTT!!!
-
+       // Now perform the requested operation.
        if (!strcasecmp(h->method, "DELETE")) {
                dav_delete_message(h, c, msgnum);
        }
@@ -299,10 +296,15 @@ void object_in_room(struct http_transaction *h, struct ctdlsession *c) {
        else if (!strcasecmp(h->method, "PUT")) {
                dav_put_message(h, c, unescaped_euid, msgnum);
        }
+       else if (!strcasecmp(h->method, "MOVE")) {
+               dav_move_or_copy_message(h, c, msgnum, DAV_MOVE);
+       }
+       else if (!strcasecmp(h->method, "COPY")) {
+               dav_move_or_copy_message(h, c, msgnum, DAV_COPY);
+       }
        else {
-               do_404(h);      // Got this far but the method made no sense?  Bummer.
+               do_404(h);              // We should never get here, but if we do, a 404 error is clean.
        }
-
 }
 
 
@@ -313,7 +315,7 @@ void report_the_room_itself(struct http_transaction *h, struct ctdlsession *c) {
                return;
        }
 
-       do_404(h);              // future implementations like CardDAV will require code paths here
+       do_404(h);                      // future implementations like CardDAV will require code paths here
 }
 
 
@@ -330,7 +332,7 @@ void options_the_room_itself(struct http_transaction *h, struct ctdlsession *c)
        else {
                add_response_header(h, strdup("DAV"), strdup("1"));     // ordinary WebDAV for all other room types
        }
-       add_response_header(h, strdup("Allow"), strdup("OPTIONS, PROPFIND, GET, PUT, REPORT, DELETE"));
+       add_response_header(h, strdup("Allow"), strdup("OPTIONS, PROPFIND, GET, PUT, REPORT, DELETE, MOVE, COPY"));
 }
 
 
@@ -342,8 +344,13 @@ void propfind_the_room_itself(struct http_transaction *h, struct ctdlsession *c)
        syslog(LOG_DEBUG, "Client PROPFIND requested depth: %d", dav_depth);
        StrBuf *Buf = NewStrBuf();
 
-       StrBufAppendPrintf(Buf, "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
-                          "<D:multistatus " "xmlns:D=\"DAV:\" " "xmlns:C=\"urn:ietf:params:xml:ns:caldav\"" ">");
+       StrBufAppendPrintf(Buf,
+               "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+               "<D:multistatus "
+               "xmlns:D=\"DAV:\" "
+               "xmlns:C=\"urn:ietf:params:xml:ns:caldav\""
+               ">"
+       );
 
        // Transmit the collection resource
        StrBufAppendPrintf(Buf, "<D:response>");
@@ -406,17 +413,21 @@ void propfind_the_room_itself(struct http_transaction *h, struct ctdlsession *c)
        // If a depth greater than zero was specified, transmit the collection listing
        // BEGIN COLLECTION
        if (dav_depth > 0) {
-               long *msglist = get_msglist(c, "ALL");
+               Array *msglist = get_msglist(c, "ALL");
                if (msglist) {
                        int i;
-                       for (i = 0; (msglist[i] > 0); ++i) {
-                               if ((i % 10) == 0)
+                       for (i = 0; i < array_len(msglist); ++i) {
+                               if ((i % 10) == 0) {
                                        syslog(LOG_DEBUG, "PROPFIND enumerated %d messages", i);
-                               e = NULL;       // EUID gets stored here
+                               }
+                               e = NULL;               // EUID gets stored here
                                timestamp = 0;
 
+                               long m;
+                               memcpy(&m, array_get_element_at(msglist, i), sizeof(long));
+
                                char cbuf[1024];
-                               ctdl_printf(c, "MSG0 %ld|3", msglist[i]);
+                               ctdl_printf(c, "MSG0 %ld|3", m);
                                ctdl_readline(c, cbuf, sizeof(cbuf));
                                if (cbuf[0] == '1')
                                        while (ctdl_readline(c, cbuf, sizeof(cbuf)), strcmp(cbuf, "000")) {
@@ -432,7 +443,7 @@ void propfind_the_room_itself(struct http_transaction *h, struct ctdlsession *c)
                                        }
                                if (e == NULL) {
                                        e = malloc(20);
-                                       sprintf(e, "%ld", msglist[i]);
+                                       sprintf(e, "%ld", m);
                                }
                                StrBufAppendPrintf(Buf, "<D:response>");
 
@@ -471,13 +482,13 @@ void propfind_the_room_itself(struct http_transaction *h, struct ctdlsession *c)
                                                free(datestring);
                                        }
                                        if (enumerate_by_euid) {        // FIXME ajc 2017oct30 should this be inside the timestamp conditional?
-                                               StrBufAppendPrintf(Buf, "<D:getetag>\"%ld\"</D:getetag>", msglist[i]);
+                                               StrBufAppendPrintf(Buf, "<D:getetag>\"%ld\"</D:getetag>", m);
                                        }
                                }
                                StrBufAppendPrintf(Buf, "</D:prop></D:propstat></D:response>\n");
                                free(e);
                        }
-                       free(msglist);
+                       array_free(msglist);
                };
        }
        // END COLLECTION
@@ -503,12 +514,12 @@ void get_the_room_itself(struct http_transaction *h, struct ctdlsession *c) {
        JsonObjectAppend(j, NewJsonNumber(HKEY("current_view"), c->room_current_view));
        JsonObjectAppend(j, NewJsonNumber(HKEY("default_view"), c->room_default_view));
        JsonObjectAppend(j, NewJsonNumber(HKEY("is_room_aide"), c->is_room_aide));
+       JsonObjectAppend(j, NewJsonNumber(HKEY("is_trash_folder"), c->is_trash_folder));
        JsonObjectAppend(j, NewJsonNumber(HKEY("can_delete_messages"), c->can_delete_messages));
        JsonObjectAppend(j, NewJsonNumber(HKEY("new_messages"), c->new_messages));
        JsonObjectAppend(j, NewJsonNumber(HKEY("total_messages"), c->total_messages));
        JsonObjectAppend(j, NewJsonNumber(HKEY("last_seen"), c->last_seen));
        JsonObjectAppend(j, NewJsonNumber(HKEY("room_mtime"), c->room_mtime));
-       JsonObjectAppend(j, NewJsonNumber(HKEY("new_mail"), c->new_mail));
 
        StrBuf *sj = NewStrBuf();
        SerializeJson(sj, j, 1);        // '1' == free the source array
@@ -632,11 +643,11 @@ void ctdl_r(struct http_transaction *h, struct ctdlsession *c) {
                        c->last_seen = extract_long(&buf[4], 6);        // The highest message number the user has read in this room
                        //      7       (int)rmailflag                  Boolean flag: 1 if this is a Mail> room, 0 otherwise.
                        c->is_room_aide = extract_int(&buf[4], 8);
-                       c->new_mail = extract_int(&buf[4], 9);          // the number of new messages in the user's INBOX
+                       //      9                                       This position is no longer used
                        //      10      (int)CC->room.QRfloor           The floor number this room resides on
                        c->room_current_view = extract_int(&buf[4], 11);
                        c->room_default_view = extract_int(&buf[4], 12);
-                       //      13      (int)is_trash                   Boolean flag: 1 if this is the user's Trash folder, 0 otherwise.
+                       c->is_trash_folder  = extract_int(&buf[4], 13); // Boolean flag: 1 if this is the user's Trash folder, 0 otherwise.
                        room_flags2 = extract_long(&buf[4], 14);        // More flags associated with this room.
                        c->room_mtime = extract_long(&buf[4], 15);      // Timestamp of the last write activity in this room
 
@@ -670,7 +681,7 @@ void ctdl_r(struct http_transaction *h, struct ctdlsession *c) {
                }
                return;
        }
-       if (num_tokens(h->url, '/') == 6) {
+       if (num_tokens(h->url, '/') >= 6) {
                object_in_room(h, c);   //      /ctdl/r/roomname/object/ or possibly /ctdl/r/roomname/object/component
                return;
        }