Back to index

citadel  8.12
euidindex.c
Go to the documentation of this file.
00001 /*
00002  * Index messages by EUID per room.
00003  */
00004 
00005 #include "sysdep.h"
00006 #include <stdlib.h>
00007 #include <unistd.h>
00008 #include <stdio.h>
00009 #include <fcntl.h>
00010 
00011 #if TIME_WITH_SYS_TIME
00012 # include <sys/time.h>
00013 # include <time.h>
00014 #else
00015 # if HAVE_SYS_TIME_H
00016 #  include <sys/time.h>
00017 # else
00018 #  include <time.h>
00019 # endif
00020 #endif
00021 
00022 
00023 #include <ctype.h>
00024 #include <string.h>
00025 #include <limits.h>
00026 #include <errno.h>
00027 #include <stdarg.h>
00028 #include <sys/stat.h>
00029 #include <libcitadel.h>
00030 #include "citadel.h"
00031 #include "server.h"
00032 #include "database.h"
00033 #include "msgbase.h"
00034 #include "support.h"
00035 #include "sysdep_decls.h"
00036 #include "citserver.h"
00037 #include "room_ops.h"
00038 #include "user_ops.h"
00039 #include "file_ops.h"
00040 #include "config.h"
00041 #include "control.h"
00042 #include "euidindex.h"
00043 
00044 #include "ctdl_module.h"
00045 
00046 /*
00047  * The structure of an euidindex record *key* is:
00048  *
00049  * |----room_number----|----------EUID-------------|
00050  *    (sizeof long)       (actual length of euid)
00051  *
00052  *
00053  * The structure of an euidindex record *value* is:
00054  *
00055  * |-----msg_number----|----room_number----|----------EUID-------------|
00056  *    (sizeof long)       (sizeof long)       (actual length of euid)
00057  *
00058  */
00059 
00060 
00061 
00062 /*
00063  * Return nonzero if the supplied room is one which should have
00064  * an EUID index.
00065  */
00066 int DoesThisRoomNeedEuidIndexing(struct ctdlroom *qrbuf) {
00067 
00068        switch(qrbuf->QRdefaultview) {
00069               case VIEW_BBS:              return(0);
00070               case VIEW_MAILBOX:   return(0);
00071               case VIEW_ADDRESSBOOK:      return(1);
00072               case VIEW_DRAFTS:       return(0);
00073               case VIEW_CALENDAR:  return(1);
00074               case VIEW_TASKS:     return(1);
00075               case VIEW_NOTES:     return(1);
00076               case VIEW_WIKI:             return(1);
00077               case VIEW_BLOG:             return(1);
00078        }
00079        
00080        return(0);
00081 }
00082 
00083 
00084 
00085 
00086 
00087 
00088 /*
00089  * Locate a message in a given room with a given euid, and return
00090  * its message number.
00091  */
00092 long locate_message_by_euid(char *euid, struct ctdlroom *qrbuf) {
00093        return CtdlLocateMessageByEuid (euid, qrbuf);
00094 }
00095 
00096 long CtdlLocateMessageByEuid(char *euid, struct ctdlroom *qrbuf) {
00097        char *key;
00098        int key_len;
00099        struct cdbdata *cdb_euid;
00100        long msgnum = (-1L);
00101 
00102        syslog(LOG_DEBUG, "Searching for EUID <%s> in <%s>\n", euid, qrbuf->QRname);
00103 
00104        key_len = strlen(euid) + sizeof(long) + 1;
00105        key = malloc(key_len);
00106        memcpy(key, &qrbuf->QRnumber, sizeof(long));
00107        strcpy(&key[sizeof(long)], euid);
00108 
00109        cdb_euid = cdb_fetch(CDB_EUIDINDEX, key, key_len);
00110        free(key);
00111 
00112        if (cdb_euid == NULL) {
00113               msgnum = (-1L);
00114        }
00115        else {
00116               /* The first (sizeof long) of the record is what we're
00117                * looking for.  Throw away the rest.
00118                */
00119               memcpy(&msgnum, cdb_euid->ptr, sizeof(long));
00120               cdb_free(cdb_euid);
00121        }
00122        syslog(LOG_DEBUG, "returning msgnum = %ld\n", msgnum);
00123        return(msgnum);
00124 }
00125 
00126 
00127 /*
00128  * Store the euid index for a message, which has presumably just been
00129  * stored in this room by the caller.
00130  */
00131 void index_message_by_euid(char *euid, struct ctdlroom *qrbuf, long msgnum) {
00132        char *key;
00133        int key_len;
00134        char *data;
00135        int data_len;
00136 
00137        syslog(LOG_DEBUG, "Indexing message #%ld <%s> in <%s>\n", msgnum, euid, qrbuf->QRname);
00138 
00139        key_len = strlen(euid) + sizeof(long) + 1;
00140        key = malloc(key_len);
00141        memcpy(key, &qrbuf->QRnumber, sizeof(long));
00142        strcpy(&key[sizeof(long)], euid);
00143 
00144        data_len = sizeof(long) + key_len;
00145        data = malloc(data_len);
00146 
00147        memcpy(data, &msgnum, sizeof(long));
00148        memcpy(&data[sizeof(long)], key, key_len);
00149 
00150        cdb_store(CDB_EUIDINDEX, key, key_len, data, data_len);
00151        free(key);
00152        free(data);
00153 }
00154 
00155 
00156 
00157 /*
00158  * Called by rebuild_euid_index_for_room() to index one message.
00159  */
00160 void rebuild_euid_index_for_msg(long msgnum, void *userdata) {
00161        struct CtdlMessage *msg = NULL;
00162 
00163        msg = CtdlFetchMessage(msgnum, 0);
00164        if (msg == NULL) return;
00165        if (msg->cm_fields['E'] != NULL) {
00166               index_message_by_euid(msg->cm_fields['E'], &CC->room, msgnum);
00167        }
00168        CtdlFreeMessage(msg);
00169 }
00170 
00171 
00172 void rebuild_euid_index_for_room(struct ctdlroom *qrbuf, void *data) {
00173        static struct RoomProcList *rplist = NULL;
00174        struct RoomProcList *ptr;
00175        struct ctdlroom qr;
00176 
00177        /* Lazy programming here.  Call this function as a CtdlForEachRoom backend
00178         * in order to queue up the room names, or call it with a null room
00179         * to make it do the processing.
00180         */
00181        if (qrbuf != NULL) {
00182               ptr = (struct RoomProcList *)
00183                      malloc(sizeof (struct RoomProcList));
00184               if (ptr == NULL) return;
00185 
00186               safestrncpy(ptr->name, qrbuf->QRname, sizeof ptr->name);
00187               ptr->next = rplist;
00188               rplist = ptr;
00189               return;
00190        }
00191 
00192        while (rplist != NULL) {
00193               if (CtdlGetRoom(&qr, rplist->name) == 0) {
00194                      if (DoesThisRoomNeedEuidIndexing(&qr)) {
00195                             syslog(LOG_DEBUG,
00196                                    "Rebuilding EUID index for <%s>\n",
00197                                    rplist->name);
00198                             CtdlUserGoto(rplist->name, 0, 0, NULL, NULL);
00199                             CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL,
00200                                    rebuild_euid_index_for_msg, NULL);
00201                      }
00202               }
00203               ptr = rplist;
00204               rplist = rplist->next;
00205               free(ptr);
00206        }
00207 }
00208 
00209 
00210 /*
00211  * Globally rebuild the EUID indices in every room.
00212  */
00213 void rebuild_euid_index(void) {
00214        cdb_trunc(CDB_EUIDINDEX);          /* delete the old indices */
00215        CtdlForEachRoom(rebuild_euid_index_for_room, NULL);     /* enumerate rm names */
00216        rebuild_euid_index_for_room(NULL, NULL);  /* and index them */
00217 }
00218 
00219 
00220 
00221 /*
00222  * Server command to fetch a message number given an euid.
00223  */
00224 void cmd_euid(char *cmdbuf) {
00225        char euid[256];
00226        long msgnum;
00227         struct cdbdata *cdbfr;
00228         long *msglist = NULL;
00229         int num_msgs = 0;
00230        int i;
00231 
00232        if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
00233 
00234        extract_token(euid, cmdbuf, 0, '|', sizeof euid);
00235        msgnum = CtdlLocateMessageByEuid(euid, &CC->room);
00236        if (msgnum <= 0L) {
00237               cprintf("%d not found\n", ERROR + MESSAGE_NOT_FOUND);
00238               return;
00239        }
00240 
00241         cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long));
00242        if (cdbfr != NULL) {
00243                 num_msgs = cdbfr->len / sizeof(long);
00244                 msglist = (long *) cdbfr->ptr;
00245                 for (i = 0; i < num_msgs; ++i) {
00246                         if (msglist[i] == msgnum) {
00247                             cdb_free(cdbfr);
00248                             cprintf("%d %ld\n", CIT_OK, msgnum);
00249                             return;
00250                      }
00251               }
00252                 cdb_free(cdbfr);
00253        }
00254 
00255        cprintf("%d not found\n", ERROR + MESSAGE_NOT_FOUND);
00256 }
00257 
00258 CTDL_MODULE_INIT(euidindex)
00259 {
00260        if (!threading) {
00261               CtdlRegisterProtoHook(cmd_euid, "EUID", "Perform operations on Extended IDs for messages");
00262        }
00263        /* return our Subversion id for the Log */
00264        return "euidindex";
00265 }