]> code.citadel.org Git - citadel.git/blobdiff - citadel/msgbase.c
* Full text indexer is now switchable on/off
[citadel.git] / citadel / msgbase.c
index 75a6830a109891b548e5979f022f81f4269f7554..cf73c74f956d3facef92bc534d6a36e6411676fe 100644 (file)
 #include "room_ops.h"
 #include "user_ops.h"
 #include "file_ops.h"
+#include "config.h"
 #include "control.h"
 #include "tools.h"
 #include "mime_parser.h"
 #include "html.h"
 #include "genstamp.h"
 #include "internet_addressing.h"
+#include "serv_fulltext.h"
 
-extern struct config config;
 long config_msgnum;
 
 
@@ -306,7 +307,6 @@ void CtdlGetSeen(char *buf, int which_set) {
  * Manipulate the "seen msgs" string (or other message set strings)
  */
 void CtdlSetSeen(long target_msgnum, int target_setting, int which_set) {
-       char newseen[SIZ];
        struct cdbdata *cdbfr;
        int i;
        int is_seen = 0;
@@ -317,6 +317,10 @@ void CtdlSetSeen(long target_msgnum, int target_setting, int which_set) {
        long *msglist;
        int num_msgs = 0;
        char vset[SIZ];
+       char *is_set;   /* actually an array of booleans */
+       int num_sets;
+       int s;
+       char setstr[SIZ], lostr[SIZ], histr[SIZ];
 
        lprintf(CTDL_DEBUG, "CtdlSetSeen(%ld, %d, %d)\n",
                target_msgnum, target_setting, which_set);
@@ -335,12 +339,48 @@ void CtdlSetSeen(long target_msgnum, int target_setting, int which_set) {
                return; /* No messages at all?  No further action. */
        }
 
+       is_set = malloc(num_msgs * sizeof(char));
+       memset(is_set, 0, (num_msgs * sizeof(char)) );
+
        /* Decide which message set we're manipulating */
-       if (which_set == ctdlsetseen_seen) strcpy(vset, vbuf.v_seen);
-       if (which_set == ctdlsetseen_answered) strcpy(vset, vbuf.v_answered);
+       switch(which_set) {
+               case ctdlsetseen_seen:
+                       safestrncpy(vset, vbuf.v_seen, sizeof vset);
+                       break;
+               case ctdlsetseen_answered:
+                       safestrncpy(vset, vbuf.v_answered, sizeof vset);
+                       break;
+       }
+
+       /* lprintf(CTDL_DEBUG, "before optimize: %s\n", vset); */
+
+       /* Translate the existing sequence set into an array of booleans */
+       num_sets = num_tokens(vset, ',');
+       for (s=0; s<num_sets; ++s) {
+               extract_token(setstr, vset, s, ',', sizeof setstr);
+
+               extract_token(lostr, setstr, 0, ':', sizeof lostr);
+               if (num_tokens(setstr, ':') >= 2) {
+                       extract_token(histr, setstr, 1, ':', sizeof histr);
+                       if (!strcmp(histr, "*")) {
+                               snprintf(histr, sizeof histr, "%ld", LONG_MAX);
+                       }
+               }
+               else {
+                       strcpy(histr, lostr);
+               }
+               lo = atol(lostr);
+               hi = atol(histr);
+
+               for (i = 0; i < num_msgs; ++i) {
+                       if ((msglist[i] >= lo) && (msglist[i] <= hi)) {
+                               is_set[i] = 1;
+                       }
+               }
+       }
 
-       lprintf(CTDL_DEBUG, "before optimize: %s\n", vset);
-       strcpy(newseen, "");
+       /* Now translate the array of booleans back into a sequence set */
+       strcpy(vset, "");
 
        for (i=0; i<num_msgs; ++i) {
                is_seen = 0;
@@ -349,7 +389,7 @@ void CtdlSetSeen(long target_msgnum, int target_setting, int which_set) {
                        is_seen = target_setting;
                }
                else {
-                       if (is_msg_in_sequence_set(vset, msglist[i])) {
+                       if (is_set[i]) {
                                is_seen = 1;
                        }
                }
@@ -362,21 +402,21 @@ void CtdlSetSeen(long target_msgnum, int target_setting, int which_set) {
                   || ((is_seen == 1) && (i == num_msgs-1)) ) {
                        size_t tmp;
 
-                       if ( (strlen(newseen) + 20) > SIZ) {
-                               strcpy(newseen, &newseen[20]);
-                               newseen[0] = '*';
+                       if ( (strlen(vset) + 20) > sizeof vset) {
+                               strcpy(vset, &vset[20]);
+                               vset[0] = '*';
                        }
-                       tmp = strlen(newseen);
+                       tmp = strlen(vset);
                        if (tmp > 0) {
-                               strcat(newseen, ",");
+                               strcat(vset, ",");
                                tmp++;
                        }
                        if (lo == hi) {
-                               snprintf(&newseen[tmp], sizeof newseen - tmp,
+                               snprintf(&vset[tmp], sizeof vset - tmp,
                                         "%ld", lo);
                        }
                        else {
-                               snprintf(&newseen[tmp], sizeof newseen - tmp,
+                               snprintf(&vset[tmp], sizeof vset - tmp,
                                         "%ld:%ld", lo, hi);
                        }
                        lo = (-1L);
@@ -386,10 +426,18 @@ void CtdlSetSeen(long target_msgnum, int target_setting, int which_set) {
        }
 
        /* Decide which message set we're manipulating */
-       if (which_set == ctdlsetseen_seen) strcpy(vbuf.v_seen, newseen);
-       if (which_set == ctdlsetseen_answered) strcpy(vbuf.v_answered, newseen);
+       switch (which_set) {
+               case ctdlsetseen_seen:
+                       safestrncpy(vbuf.v_seen, vset, sizeof vbuf.v_seen);
+                       break;
+               case ctdlsetseen_answered:
+                       safestrncpy(vbuf.v_answered, vset,
+                                               sizeof vbuf.v_answered);
+                       break;
+       }
+       free(is_set);
 
-       lprintf(CTDL_DEBUG, " after optimize: %s\n", newseen);
+       /* lprintf(CTDL_DEBUG, " after optimize: %s\n", vset); */
        free(msglist);
        CtdlSetRelationship(&vbuf, &CC->user, &CC->room);
 }
@@ -522,7 +570,7 @@ int CtdlForEachMessage(int mode, long ref,
 
 /*
  * cmd_msgs()  -  get list of message #'s in this room
- *                implements the MSGS server command using CtdlForEachMessage()
+ *             implements the MSGS server command using CtdlForEachMessage()
  */
 void cmd_msgs(char *cmdbuf)
 {
@@ -627,10 +675,10 @@ void do_help_subst(char *buffer)
 
 /*
  * memfmout()  -  Citadel text formatter and paginator.
- *             Although the original purpose of this routine was to format
- *             text to the reader's screen width, all we're really using it
- *             for here is to format text out to 80 columns before sending it
- *             to the client.  The client software may reformat it again.
+ *          Although the original purpose of this routine was to format
+ *          text to the reader's screen width, all we're really using it
+ *          for here is to format text out to 80 columns before sending it
+ *          to the client.  The client software may reformat it again.
  */
 void memfmout(
        int width,              /* screen width to use */
@@ -1096,11 +1144,11 @@ int CtdlOutputMsg(long msg_num,         /* message number (local) to fetch */
        /* FIXME: check message id against msglist for this room */
 
        /*
-        * Fetch the message from disk.  If we're in sooper-fast headers
+        * Fetch the message from disk.  If we're in any sort of headers
         * only mode, request that we don't even bother loading the body
         * into memory.
         */
-       if (headers_only == HEADERS_FAST) {
+       if ( (headers_only == HEADERS_FAST) || (headers_only == HEADERS_ONLY) ) {
                TheMessage = CtdlFetchMessage(msg_num, 0);
        }
        else {
@@ -1215,7 +1263,7 @@ int CtdlOutputPreLoadedMsg(
 
        /* nhdr=yes means that we're only displaying headers, no body */
        if ( (TheMessage->cm_anon_type == MES_ANONONLY)
-           && (mode == MT_CITADEL)
+          && (mode == MT_CITADEL)
           && (do_proto)
           ) {
                cprintf("nhdr=yes\n");
@@ -1311,9 +1359,9 @@ int CtdlOutputPreLoadedMsg(
                                        safestrncpy(lnode, mptr, sizeof lnode);
                                else if (i == 'F')
                                        safestrncpy(fuser, mptr, sizeof fuser);
-                               else if (i == 'O')
+                               /* else if (i == 'O')
                                        cprintf("X-Citadel-Room: %s%s",
-                                               mptr, nl);
+                                               mptr, nl); */
                                else if (i == 'N')
                                        safestrncpy(snode, mptr, sizeof snode);
                                else if (i == 'R')
@@ -1348,16 +1396,20 @@ int CtdlOutputPreLoadedMsg(
                cprintf(">%s", nl);
 
                if (!is_room_aide() && (TheMessage->cm_anon_type == MES_ANONONLY)) {
-                       cprintf("From: x@x.org (----)%s", nl);
+                       // cprintf("From: x@x.org (----)%s", nl);
+                       cprintf("From: \"----\" <x@x.org>%s", nl);
                }
                else if (!is_room_aide() && (TheMessage->cm_anon_type == MES_ANONOPT)) {
-                       cprintf("From: x@x.org (anonymous)%s", nl);
+                       // cprintf("From: x@x.org (anonymous)%s", nl);
+                       cprintf("From: \"anonymous\" <x@x.org>%s", nl);
                }
                else if (strlen(fuser) > 0) {
-                       cprintf("From: %s (%s)%s", fuser, luser, nl);
+                       // cprintf("From: %s (%s)%s", fuser, luser, nl);
+                       cprintf("From: \"%s\" <%s>%s", luser, fuser, nl);
                }
                else {
-                       cprintf("From: %s@%s (%s)%s", suser, snode, luser, nl);
+                       // cprintf("From: %s@%s (%s)%s", suser, snode, luser, nl);
+                       cprintf("From: \"%s\" <%s@%s>%s", luser, suser, snode, nl);
                }
 
                cprintf("Organization: %s%s", lnode, nl);
@@ -1377,9 +1429,9 @@ START_TEXT:
        if (TheMessage->cm_format_type == FMT_RFC822) {
                if ( (mode == MT_CITADEL) || (mode == MT_MIME) ) {
                        mime_parser(mptr, NULL,
-                               *list_this_part,
-                               *list_this_pref,
-                               *list_this_suff,
+                               (do_proto ? *list_this_part : NULL),
+                               (do_proto ? *list_this_pref : NULL),
+                               (do_proto ? *list_this_suff : NULL),
                                NULL, 0);
                }
                else if (mode == MT_RFC822) {   /* unparsed RFC822 dump */
@@ -1626,10 +1678,10 @@ void cmd_opna(char *cmdbuf)
 int CtdlSaveMsgPointerInRoom(char *roomname, long msgid, int flags) {
        int i;
        char hold_rm[ROOMNAMELEN];
-        struct cdbdata *cdbfr;
-        int num_msgs;
-        long *msglist;
-        long highest_msg = 0L;
+       struct cdbdata *cdbfr;
+       int num_msgs;
+       long *msglist;
+       long highest_msg = 0L;
        struct CtdlMessage *msg = NULL;
 
        lprintf(CTDL_DEBUG, "CtdlSaveMsgPointerInRoom(%s, %ld, %d)\n",
@@ -1674,25 +1726,25 @@ int CtdlSaveMsgPointerInRoom(char *roomname, long msgid, int flags) {
                return(ERROR + ROOM_NOT_FOUND);
        }
 
-        cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long));
-        if (cdbfr == NULL) {
-                msglist = NULL;
-                num_msgs = 0;
-        } else {
-                msglist = malloc(cdbfr->len);
-                if (msglist == NULL)
-                        lprintf(CTDL_ALERT, "ERROR malloc msglist!\n");
-                num_msgs = cdbfr->len / sizeof(long);
-                memcpy(msglist, cdbfr->ptr, cdbfr->len);
-                cdb_free(cdbfr);
-        }
+       cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long));
+       if (cdbfr == NULL) {
+               msglist = NULL;
+               num_msgs = 0;
+       } else {
+               msglist = malloc(cdbfr->len);
+               if (msglist == NULL)
+                       lprintf(CTDL_ALERT, "ERROR malloc msglist!\n");
+               num_msgs = cdbfr->len / sizeof(long);
+               memcpy(msglist, cdbfr->ptr, cdbfr->len);
+               cdb_free(cdbfr);
+       }
 
 
        /* Make sure the message doesn't already exist in this room.  It
         * is absolutely taboo to have more than one reference to the same
         * message in a room.
         */
-        if (num_msgs > 0) for (i=0; i<num_msgs; ++i) {
+       if (num_msgs > 0) for (i=0; i<num_msgs; ++i) {
                if (msglist[i] == msgid) {
                        lputroom(&CC->room);    /* unlock the room */
                        getroom(&CC->room, hold_rm);
@@ -1702,27 +1754,27 @@ int CtdlSaveMsgPointerInRoom(char *roomname, long msgid, int flags) {
                }
        }
 
-        /* Now add the new message */
-        ++num_msgs;
-        msglist = realloc(msglist, (num_msgs * sizeof(long)));
+       /* Now add the new message */
+       ++num_msgs;
+       msglist = realloc(msglist, (num_msgs * sizeof(long)));
 
-        if (msglist == NULL) {
-                lprintf(CTDL_ALERT, "ERROR: can't realloc message list!\n");
-        }
-        msglist[num_msgs - 1] = msgid;
+       if (msglist == NULL) {
+               lprintf(CTDL_ALERT, "ERROR: can't realloc message list!\n");
+       }
+       msglist[num_msgs - 1] = msgid;
 
-        /* Sort the message list, so all the msgid's are in order */
-        num_msgs = sort_msglist(msglist, num_msgs);
+       /* Sort the message list, so all the msgid's are in order */
+       num_msgs = sort_msglist(msglist, num_msgs);
 
-        /* Determine the highest message number */
-        highest_msg = msglist[num_msgs - 1];
+       /* Determine the highest message number */
+       highest_msg = msglist[num_msgs - 1];
 
-        /* Write it back to disk. */
-        cdb_store(CDB_MSGLISTS, &CC->room.QRnumber, (int)sizeof(long),
-                  msglist, (int)(num_msgs * sizeof(long)));
+       /* Write it back to disk. */
+       cdb_store(CDB_MSGLISTS, &CC->room.QRnumber, (int)sizeof(long),
+                 msglist, (int)(num_msgs * sizeof(long)));
 
-        /* Free up the memory we used. */
-        free(msglist);
+       /* Free up the memory we used. */
+       free(msglist);
 
        /* Update the highest-message pointer and unlock the room. */
        CC->room.QRhighest = highest_msg;
@@ -1736,7 +1788,7 @@ int CtdlSaveMsgPointerInRoom(char *roomname, long msgid, int flags) {
 
        /* Return success. */
        if (msg != NULL) CtdlFreeMessage(msg);
-        return (0);
+       return (0);
 }
 
 
@@ -1753,7 +1805,7 @@ long send_message(struct CtdlMessage *msg) {
        long newmsgid;
        long retval;
        char msgidbuf[256];
-        struct ser_ret smr;
+       struct ser_ret smr;
        int is_bigmsg = 0;
        char *holdM = NULL;
 
@@ -1776,17 +1828,17 @@ long send_message(struct CtdlMessage *msg) {
        }
 
        /* Serialize our data structure for storage in the database */  
-        serialize_message(&smr, msg);
+       serialize_message(&smr, msg);
 
        if (is_bigmsg) {
                msg->cm_fields['M'] = holdM;
        }
 
-        if (smr.len == 0) {
-                cprintf("%d Unable to serialize message\n",
-                        ERROR + INTERNAL_ERROR);
-                return (-1L);
-        }
+       if (smr.len == 0) {
+               cprintf("%d Unable to serialize message\n",
+                       ERROR + INTERNAL_ERROR);
+               return (-1L);
+       }
 
        /* Write our little bundle of joy into the message base */
        if (cdb_store(CDB_MSGMAIN, &newmsgid, (int)sizeof(long),
@@ -1806,7 +1858,7 @@ long send_message(struct CtdlMessage *msg) {
        }
 
        /* Free the memory we used for the serialized message */
-        free(smr.ser);
+       free(smr.ser);
 
        /* Return the *local* message ID to the caller
         * (even if we're storing an incoming network message)
@@ -2108,7 +2160,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
        }
 
        /* Bump this user's messages posted counter. */
-       lprintf(CTDL_DEBUG, "Updating user\n");
+       lprintf(CTDL_DEBUG, "Updating user (FIXME defer this)\n");
        lgetuser(&CC->user, CC->curr_user);
        CC->user.posted = CC->user.posted + 1;
        lputuser(&CC->user);
@@ -2165,7 +2217,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
                if (smr.len > 0) {
                        snprintf(submit_filename, sizeof submit_filename,
                                "./network/spoolin/netmail.%04lx.%04x.%04x",
-                               (long) getpid(), CC->cs_pid, ++seqnum);
+                               (long) getpid(), CC->cs_pid, ++seqnum);
                        network_fp = fopen(submit_filename, "wb+");
                        if (network_fp != NULL) {
                                fwrite(smr.ser, smr.len, 1, network_fp);
@@ -2208,7 +2260,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
                                 "remote|%s|0||\n", recipient);
                }
 
-               imsg = malloc(sizeof(struct CtdlMessage));
+               imsg = malloc(sizeof(struct CtdlMessage));
                memset(imsg, 0, sizeof(struct CtdlMessage));
                imsg->cm_magic = CTDLMESSAGE_MAGIC;
                imsg->cm_anon_type = MES_NORMAL;
@@ -3114,7 +3166,7 @@ void PutMetaData(struct MetaData *smibuf)
 
 /*
  * AdjRefCount  -  change the reference count for a message;
- *                 delete the message if it reaches zero
+ *              delete the message if it reaches zero
  */
 void AdjRefCount(long msgnum, int incr)
 {
@@ -3128,24 +3180,28 @@ void AdjRefCount(long msgnum, int incr)
         */
        begin_critical_section(S_SUPPMSGMAIN);
        GetMetaData(&smi, msgnum);
-       lprintf(CTDL_DEBUG, "Ref count for message <%ld> before write is <%d>\n",
-               msgnum, smi.meta_refcount);
        smi.meta_refcount += incr;
        PutMetaData(&smi);
        end_critical_section(S_SUPPMSGMAIN);
-       lprintf(CTDL_DEBUG, "Ref count for message <%ld> after write is <%d>\n",
-               msgnum, smi.meta_refcount);
+       lprintf(CTDL_DEBUG, "msg %ld ref count incr %d, is now %d\n",
+               msgnum, incr, smi.meta_refcount);
 
        /* If the reference count is now zero, delete the message
         * (and its supplementary record as well).
+        * FIXME ... defer this so it doesn't keep the user waiting.
         */
        if (smi.meta_refcount == 0) {
                lprintf(CTDL_DEBUG, "Deleting message <%ld>\n", msgnum);
+
+               /* Remove from fulltext index */
+               ft_index_message(msgnum, 0);
+
+               /* Remove from message base */
                delnum = msgnum;
                cdb_delete(CDB_MSGMAIN, &delnum, (int)sizeof(long));
                cdb_delete(CDB_BIGMSGS, &delnum, (int)sizeof(long));
 
-               /* We have to delete the metadata record too! */
+               /* Remove metadata record */
                delnum = (0L - msgnum);
                cdb_delete(CDB_MSGMAIN, &delnum, (int)sizeof(long));
        }
@@ -3305,10 +3361,10 @@ char *CtdlGetSysConfig(char *sysconfname) {
                conf = NULL;
        }
        else {
-               msg = CtdlFetchMessage(msgnum, 1);
-               if (msg != NULL) {
-                       conf = strdup(msg->cm_fields['M']);
-                       CtdlFreeMessage(msg);
+               msg = CtdlFetchMessage(msgnum, 1);
+               if (msg != NULL) {
+                       conf = strdup(msg->cm_fields['M']);
+                       CtdlFreeMessage(msg);
                }
                else {
                        conf = NULL;