MSGS command can now do full text search on the room
authorArt Cancro <ajc@citadel.org>
Sun, 27 Aug 2006 02:07:18 +0000 (02:07 +0000)
committerArt Cancro <ajc@citadel.org>
Sun, 27 Aug 2006 02:07:18 +0000 (02:07 +0000)
16 files changed:
citadel/citadel.h
citadel/euidindex.c
citadel/msgbase.c
citadel/msgbase.h
citadel/serv_autocompletion.c
citadel/serv_calendar.c
citadel/serv_expire.c
citadel/serv_fulltext.c
citadel/serv_inetcfg.c
citadel/serv_network.c
citadel/serv_pop3.c
citadel/serv_smtp.c
citadel/serv_vandelay.c
citadel/serv_vcard.c
citadel/server_main.c
citadel/techdoc/protocol.txt

index e4e5d894c3d7b433562d59e4ab6c2d0f40b2aeb9..c12b99ecc76137b57b26186eb857fd5ed08161e1 100644 (file)
@@ -33,7 +33,7 @@ extern "C" {
 /*
  * Text description of this software
  */
-#define CITADEL        "Citadel 6.83"
+#define CITADEL        "Citadel 6.84"
 
 /*
  * REV_LEVEL is the current version number (multiplied by 100 to avoid having
@@ -45,7 +45,7 @@ extern "C" {
  * usually more strict because you're not really supposed to dump/load and
  * upgrade at the same time.
  */
-#define REV_LEVEL      683             /* This version */
+#define REV_LEVEL      684             /* This version */
 #define REV_MIN                591             /* Oldest compatible database */
 #define EXPORT_REV_MIN 655             /* Oldest compatible export files */
 
index bd0da8929a69782d4df5f749949376561831dd36..dd9b171dc6e6d27b684cd88021535d671a883cd2 100644 (file)
@@ -192,7 +192,7 @@ void rebuild_euid_index_for_room(struct ctdlroom *qrbuf, void *data) {
                                        "Rebuilding EUID index for <%s>\n",
                                        rplist->name);
                                usergoto(rplist->name, 0, 0, NULL, NULL);
-                               CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL,
+                               CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL,
                                        rebuild_euid_index_for_msg, NULL);
                        }
                }
index bdee54e1ef4ed50ac94469979d0a06c50c0b4373..d000812dd0e3a2b1a824ac64809b5c796c82726a 100644 (file)
@@ -504,14 +504,14 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums,
  * API function to perform an operation for each qualifying message in the
  * current room.  (Returns the number of messages processed.)
  */
-int CtdlForEachMessage(int mode, long ref,
+int CtdlForEachMessage(int mode, long ref, char *search_string,
                        char *content_type,
                        struct CtdlMessage *compare,
                        void (*CallBack) (long, void *),
                        void *userdata)
 {
 
-       int a;
+       int a, i, j;
        struct visit vbuf;
        struct cdbdata *cdbfr;
        long *msglist = NULL;
@@ -523,6 +523,8 @@ int CtdlForEachMessage(int mode, long ref,
        int is_seen = 0;
        long lastold = 0L;
        int printed_lastold = 0;
+       int num_search_msgs = 0;
+       long *search_msgs = NULL;
 
        /* Learn about the user and room in question */
        get_mm();
@@ -587,7 +589,45 @@ int CtdlForEachMessage(int mode, long ref,
                }
        }
 
+       /* If a search string was specified, get a message list from
+        * the full text index and remove messages which aren't on both
+        * lists.
+        *
+        * How this works:
+        * Since the lists are sorted and strictly ascending, and the
+        * output list is guaranteed to be shorter than or equal to the
+        * input list, we overwrite the bottom of the input list.  This
+        * eliminates the need to memmove big chunks of the list over and
+        * over again.
+        */
+       if ( (num_msgs > 0) && (mode == MSGS_SEARCH) && (search_string) ) {
+               ft_search(&num_search_msgs, &search_msgs, search_string);
+               if (num_search_msgs > 0) {
        
+                       int orig_num_msgs;
+
+                       orig_num_msgs = num_msgs;
+                       num_msgs = 0;
+                       for (i=0; i<orig_num_msgs; ++i) {
+                               for (j=0; j<num_search_msgs; ++j) {
+                                       if (msglist[i] == search_msgs[j]) {
+                                               msglist[num_msgs++] = msglist[j];
+                                       }
+                               }
+                       }
+               }
+               else {
+                       num_msgs = 0;   /* No messages qualify */
+               }
+               if (search_msgs != NULL) free(search_msgs);
+
+               /* Now that we've purged messages which don't contain the search
+                * string, treat a MSGS_SEARCH just like a MSGS_ALL from this
+                * point on.
+                */
+               mode = MSGS_ALL;
+       }
+
        /*
         * Now iterate through the message list, according to the
         * criteria supplied by the caller.
@@ -647,13 +687,14 @@ void cmd_msgs(char *cmdbuf)
        int with_template = 0;
        struct CtdlMessage *template = NULL;
        int with_headers = 0;
+       char search_string[1024];
 
        extract_token(which, cmdbuf, 0, '|', sizeof which);
        cm_ref = extract_int(cmdbuf, 1);
+       extract_token(search_string, cmdbuf, 1, '|', sizeof search_string);
        with_template = extract_int(cmdbuf, 2);
        with_headers = extract_int(cmdbuf, 3);
 
-       mode = MSGS_ALL;
        strcat(which, "   ");
        if (!strncasecmp(which, "OLD", 3))
                mode = MSGS_OLD;
@@ -665,12 +706,22 @@ void cmd_msgs(char *cmdbuf)
                mode = MSGS_LAST;
        else if (!strncasecmp(which, "GT", 2))
                mode = MSGS_GT;
+       else if (!strncasecmp(which, "SEARCH", 6))
+               mode = MSGS_SEARCH;
+       else
+               mode = MSGS_ALL;
 
        if ((!(CC->logged_in)) && (!(CC->internal_pgm))) {
                cprintf("%d not logged in\n", ERROR + NOT_LOGGED_IN);
                return;
        }
 
+       if ( (mode == MSGS_SEARCH) && (!config.c_enable_fulltext) ) {
+               cprintf("%d Full text index is not enabled on this server.\n",
+                       ERROR + CMD_NOT_SUPPORTED);
+               return;
+       }
+
        if (with_template) {
                unbuffer_output();
                cprintf("%d Send template then receive message list\n",
@@ -695,7 +746,8 @@ void cmd_msgs(char *cmdbuf)
        }
 
        CtdlForEachMessage(mode,
-                       cm_ref,
+                       ( (mode == MSGS_SEARCH) ? 0 : cm_ref ),
+                       ( (mode == MSGS_SEARCH) ? search_string : NULL ),
                        NULL,
                        template,
                        (with_headers ? headers_listing : simple_listing),
@@ -3827,7 +3879,7 @@ char *CtdlGetSysConfig(char *sysconfname) {
        /* We want the last (and probably only) config in this room */
        begin_critical_section(S_CONFIG);
        config_msgnum = (-1L);
-       CtdlForEachMessage(MSGS_LAST, 1, sysconfname, NULL,
+       CtdlForEachMessage(MSGS_LAST, 1, NULL, sysconfname, NULL,
                CtdlGetSysConfigBackend, NULL);
        msgnum = config_msgnum;
        end_critical_section(S_CONFIG);
index fc0219e314ccc47815a9ab18d07faaabc2d82b3c..88c58ecaccf319ab46d7876400d27e8d07fb97fd 100644 (file)
@@ -2,13 +2,16 @@
 
 #define aide_message(text)      quickie_message("Citadel",NULL,AIDEROOM,text,0,NULL)
 
-#define MSGS_ALL        0
-#define MSGS_OLD        1
-#define MSGS_NEW        2
-#define MSGS_FIRST      3
-#define MSGS_LAST       4
-#define MSGS_GT         5
-#define MSGS_EQ                6
+enum {
+       MSGS_ALL,
+       MSGS_OLD,
+       MSGS_NEW,
+       MSGS_FIRST,
+       MSGS_LAST,
+       MSGS_GT,
+       MSGS_EQ,
+       MSGS_SEARCH
+};
 
 /*
  * Possible return codes from CtdlOutputMsg()
@@ -99,7 +102,9 @@ void PutMetaData(struct MetaData *);
 void AdjRefCount(long, int);
 void simple_listing(long, void *);
 int CtdlMsgCmp(struct CtdlMessage *msg, struct CtdlMessage *template);
-int CtdlForEachMessage(int mode, long ref,
+int CtdlForEachMessage(int mode,
+                       long ref,
+                       char *searchstring,
                        char *content_type,
                        struct CtdlMessage *compare,
                         void (*CallBack) (long, void *),
index 71aa0a0358f5b422e4d4f6988c360e1b8ff95b5f..1a6e38fabd20e6570d20494cc938cdf2fc9def29 100644 (file)
@@ -180,13 +180,13 @@ void cmd_auto(char *argbuf) {
 
        /* Take a spin through the user's personal address book */
        if (getroom(&CC->room, USERCONTACTSROOM) == 0) {
-               CtdlForEachMessage(MSGS_ALL, 0, "text/x-vcard", NULL,
+               CtdlForEachMessage(MSGS_ALL, 0, NULL, "text/x-vcard", NULL,
                                        hunt_for_autocomplete, search_string);
        }
        
        /* FIXME try the global address book */
        if (getroom(&CC->room, ADDRESS_BOOK_ROOM) == 0) {
-               CtdlForEachMessage(MSGS_ALL, 0, "text/x-vcard", NULL,
+               CtdlForEachMessage(MSGS_ALL, 0, NULL, "text/x-vcard", NULL,
                                        hunt_for_autocomplete, search_string);
        }
        
index 596271cc95e3e1cfb181acbf06bf621b555ff656..a847f20002b6296bb2eb012b09bc5e61c85d3cd8 100644 (file)
@@ -976,7 +976,7 @@ void ical_hunt_for_conflicts(icalcomponent *cal) {
 
        cprintf("%d Conflicting events:\n", LISTING_FOLLOWS);
 
-       CtdlForEachMessage(MSGS_ALL, 0, "text/calendar",
+       CtdlForEachMessage(MSGS_ALL, 0, NULL, "text/calendar",
                NULL,
                ical_hunt_for_conflicts_backend,
                (void *) cal
@@ -1281,7 +1281,7 @@ void ical_freebusy(char *who) {
 
        /* Add busy time from events */
        lprintf(CTDL_DEBUG, "Adding busy time from events\n");
-       CtdlForEachMessage(MSGS_ALL, 0, "text/calendar",
+       CtdlForEachMessage(MSGS_ALL, 0, NULL, "text/calendar",
                NULL, ical_freebusy_backend, (void *)fb
        );
 
@@ -1421,7 +1421,8 @@ void ical_getics(void)
        icalcomponent_set_method(encaps, ICAL_METHOD_PUBLISH);
 
        /* Now go through the room encapsulating all calendar items. */
-       CtdlForEachMessage(MSGS_ALL, 0, "text/calendar",
+       CtdlForEachMessage(MSGS_ALL, 0, NULL,
+               "text/calendar",
                NULL,
                ical_getics_backend,
                (void *) encaps
index 28b0968de4a6591faa26aed310af74196c865ac8..6927a6509dbf5112935bcc1ca884a42d1d5494ff 100644 (file)
@@ -745,7 +745,7 @@ void do_fsck_msg(long msgnum, void *userdata) {
 void do_fsck_room(struct ctdlroom *qrbuf, void *data)
 {
        getroom(&CC->room, qrbuf->QRname);
-       CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, do_fsck_msg, NULL);
+       CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, do_fsck_msg, NULL);
 }
 
 /*
index 9c6f1d896167b69c5bd07f8da82bad2b808fcafd..ab78a7428c2ac08b40b5de6eb8c3ace0aea8baaf 100644 (file)
@@ -208,7 +208,7 @@ void ft_index_msg(long msgnum, void *userdata) {
 void ft_index_room(struct ctdlroom *qrbuf, void *data)
 {
        getroom(&CC->room, qrbuf->QRname);
-       CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, ft_index_msg, NULL);
+       CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, ft_index_msg, NULL);
 }
 
 
index 89b5e5d66bdbd925e9ab0ae56096045f07320520..5d49d5fa8951c645e2a412ff49debf74457fa390 100644 (file)
@@ -165,7 +165,7 @@ void spamstrings_init_backend(long msgnum, void *userdata) {
 
 void inetcfg_init(void) {
        if (getroom(&CC->room, SYSCONFIGROOM) != 0) return;
-       CtdlForEachMessage(MSGS_LAST, 1, INTERNETCFG, NULL,
+       CtdlForEachMessage(MSGS_LAST, 1, NULL, INTERNETCFG, NULL,
                inetcfg_init_backend, NULL);
 }
 
index 27704f10321fe5af6d06c033df307f9755cb7717..a769aab3e3c20a4cba7c88abb75881f82f322836 100644 (file)
@@ -992,7 +992,7 @@ void network_spoolout_room(char *room_to_spool) {
        }
 
        /* Do something useful */
-       CtdlForEachMessage(MSGS_GT, sc.lastsent, NULL, NULL,
+       CtdlForEachMessage(MSGS_GT, sc.lastsent, NULL, NULL, NULL,
                network_spool_msg, &sc);
 
        /* If we wrote a digest, deliver it and then close it */
@@ -1127,7 +1127,7 @@ int network_sync_to(char *target_node) {
        if (!found_node) return(-1);
 
        /* Send ALL messages */
-       num_spooled = CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL,
+       num_spooled = CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL,
                network_spool_msg, &sc);
 
        /* Concise cleanup because we know there's only one node in the sc */
index a6f004e00f8d535bb04c1f2fe6ecb59ee7cf5c0a..db1689fb88e37487214803fc6d17e557d06f0a81 100644 (file)
@@ -180,7 +180,7 @@ int pop3_grab_mailbox(void) {
        if (getroom(&CC->room, MAILROOM) != 0) return(-1);
 
        /* Load up the messages */
-       CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL,
+       CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL,
                pop3_add_message, NULL);
 
        /* Figure out which are old and which are new */
index e1a933475207541eec10b63e70c30ae05dcae20c..ac12d1eaa49f69c7d586e781629e853fb42afc17 100644 (file)
@@ -1700,7 +1700,7 @@ void smtp_do_queue(void) {
                lprintf(CTDL_ERR, "Cannot find room <%s>\n", SMTP_SPOOLOUT_ROOM);
                return;
        }
-       CtdlForEachMessage(MSGS_ALL, 0L,
+       CtdlForEachMessage(MSGS_ALL, 0L, NULL,
                SPOOLMIME, NULL, smtp_do_procmsg, NULL);
 
        lprintf(CTDL_INFO, "SMTP: queue run completed\n");
index 501e5b74f5163d8d29074a5751f4945a589ae511..730eee13ce20f02dc82aa75d191360998da0748c 100644 (file)
@@ -103,7 +103,7 @@ void artv_export_rooms_backend(struct ctdlroom *qrbuf, void *data) {
        /* format of message list export is all message numbers output
         * one per line terminated by a 0.
         */
-       CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL,
+       CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL,
                artv_export_room_msg, NULL);
        cprintf("0\n");
 
index 2d91b75bdeb7e1ea352476fc0497f8ad23b0b873..6ec6d216704ae2b3294cddb34ea139ee55581bae 100644 (file)
@@ -189,7 +189,7 @@ void cmd_igab(char *argbuf) {
        CtdlDirectoryInit();
 
        /* We want *all* vCards in this room */
-       CtdlForEachMessage(MSGS_ALL, 0, "text/x-vcard",
+       CtdlForEachMessage(MSGS_ALL, 0, NULL, "text/x-vcard",
                NULL, vcard_add_to_directory, NULL);
 
        getroom(&CC->room, hold_rm);    /* return to saved room */
@@ -522,7 +522,7 @@ struct vCard *vcard_get_user(struct ctdluser *u) {
 
        /* We want the last (and probably only) vcard in this room */
        VCmsgnum = (-1);
-       CtdlForEachMessage(MSGS_LAST, 1, "text/x-vcard",
+       CtdlForEachMessage(MSGS_LAST, 1, NULL, "text/x-vcard",
                NULL, vcard_gu_backend, (void *)&VCmsgnum );
        getroom(&CC->room, hold_rm);    /* return to saved room */
 
@@ -1051,7 +1051,7 @@ void store_this_ha(struct addresses_to_be_filed *aptr) {
 
        /* First remove any addresses we already have in the address book */
        usergoto(aptr->roomname, 0, 0, NULL, NULL);
-       CtdlForEachMessage(MSGS_ALL, 0, "text/x-vcard", NULL,
+       CtdlForEachMessage(MSGS_ALL, 0, NULL, "text/x-vcard", NULL,
                strip_addresses_already_have, aptr->collected_addresses);
 
        if (strlen(aptr->collected_addresses) > 0)
index 68f663b4dda06ef58be8033ea12fbbcaf2eb68bb..134e564348432a257d4b90bc0427b5be8aed51e5 100644 (file)
@@ -80,7 +80,9 @@ int main(int argc, char **argv)
        int home=0;
        char relhome[PATH_MAX]="";
        char ctdldir[PATH_MAX]=CTDLDIR;
+#ifdef HAVE_RUN_DIR
        struct stat filestats;
+#endif
        
        /* initialize the master context */
        InitializeMasterCC();
index 75b8bac48a6d97cacc3a83c74b3524a2f388ba2c..767e3cd66426b07a94f835e3553723d883f4fb28 100644 (file)
@@ -474,6 +474,10 @@ which case that many message pointers will be returned; "first" plus a
 number, for the corresponding effect; or "gt" plus a number, to list all
 messages in the current room with a message number greater than the one
 specified.  If no parameters are specified, "all" is assumed.
+ In addition, the first parameter may be set to "search", in which case the
+third parameter must be a search string.  This will request all messages
+in the current room whose text contains the search string.
 
  The third argument, may be either 0 or 1.  If it is 1, this command behaves
 differently: before a listing is returned, the client must transmit a list