X-Git-Url: https://code.citadel.org/?p=citadel.git;a=blobdiff_plain;f=citadel%2Fmsgbase.c;h=081be8980a2aba77e5dd44121e083e57f8e4027e;hp=4d1881c6ba081e67968d2ca8f2d02d48506d4dbf;hb=79d6eafd2a8bb379b3e13ff071a000d9bf36771b;hpb=10a238f3ecfe0a3a197c267442098770c66d364d diff --git a/citadel/msgbase.c b/citadel/msgbase.c index 4d1881c6b..081be8980 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -1,7 +1,7 @@ /* * Implements the message store. * - * Copyright (c) 1987-2012 by the citadel.org team + * Copyright (c) 1987-2021 by the citadel.org team * * This program is open source software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3. @@ -13,20 +13,20 @@ */ +#include +#include #include #include +#include #include - -#include "md5.h" - #include "ctdl_module.h" #include "citserver.h" #include "control.h" +#include "config.h" #include "clientsocket.h" #include "genstamp.h" #include "room_ops.h" #include "user_ops.h" - #include "internet_addressing.h" #include "euidindex.h" #include "msgbase.h" @@ -34,12 +34,6 @@ struct addresses_to_be_filed *atbf = NULL; -/* This temp file holds the queue of operations for AdjRefCount() */ -static FILE *arcfp = NULL; -void AdjRefCountList(long *msgnum, long nmsg, int incr); - -int MessageDebugEnabled = 0; - /* * These are the four-character field headers we use when outputting * messages in Citadel format (as opposed to RFC822 format). @@ -54,34 +48,61 @@ char *msgkeys[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - "from", /* A */ - NULL, /* B */ - NULL, /* C */ - NULL, /* D */ - "exti", /* E */ - "rfca", /* F */ - NULL, /* G */ - "hnod", /* H */ - "msgn", /* I */ - "jrnl", /* J */ - "rep2", /* K */ - "list", /* L */ - "text", /* M */ - "node", /* N */ - "room", /* O */ - "path", /* P */ - NULL, /* Q */ - "rcpt", /* R */ - "spec", /* S */ - "time", /* T */ - "subj", /* U */ - "nvto", /* V */ - "wefw", /* W */ - NULL, /* X */ - "cccc", /* Y */ - NULL /* Z */ + "from", // A -> eAuthor + NULL, // B -> eBig_message + NULL, // C (formerly used as eRemoteRoom) + NULL, // D (formerly used as eDestination) + "exti", // E -> eXclusivID + "rfca", // F -> erFc822Addr + NULL, // G + "hnod", // H (formerly used as eHumanNode) + "msgn", // I -> emessageId + "jrnl", // J -> eJournal + "rep2", // K -> eReplyTo + "list", // L -> eListID + "text", // M -> eMesageText + NULL, // N (formerly used as eNodename) + "room", // O -> eOriginalRoom + "path", // P -> eMessagePath + NULL, // Q + "rcpt", // R -> eRecipient + NULL, // S (formerly used as eSpecialField) + "time", // T -> eTimestamp + "subj", // U -> eMsgSubject + "nvto", // V -> eenVelopeTo + "wefw", // W -> eWeferences + NULL, // X + "cccc", // Y -> eCarbonCopY + NULL // Z }; + +HashList *msgKeyLookup = NULL; + +int GetFieldFromMnemonic(eMsgField *f, const char* c) +{ + void *v = NULL; + if (GetHash(msgKeyLookup, c, 4, &v)) { + *f = (eMsgField) v; + return 1; + } + return 0; +} + +void FillMsgKeyLookupTable(void) +{ + long i; + + msgKeyLookup = NewHash (1, FourHash); + + for (i=0; i < 91; i++) { + if (msgkeys[i] != NULL) { + Put(msgKeyLookup, msgkeys[i], 4, (void*)i, reference_free_handler); + } + } +} + + eMsgField FieldOrder[] = { /* Important fields */ emessageId , @@ -90,21 +111,16 @@ eMsgField FieldOrder[] = { eAuthor , erFc822Addr , eOriginalRoom, - eNodeName , - eHumanNode , eRecipient , - eDestination , /* Semi-important fields */ eBig_message , - eRemoteRoom , eExclusiveID , eWeferences , eJournal , -/* G is not used yet, may become virus signature*/ +/* G is not used yet */ eReplyTo , eListID , /* Q is not used yet */ - eSpecialField, eenVelopeTo , /* X is not used yet */ /* Z is not used yet */ @@ -123,31 +139,35 @@ eMsgField FieldOrder[] = { static const long NDiskFields = sizeof(FieldOrder) / sizeof(eMsgField); -int CM_IsEmpty(struct CtdlMessage *Msg, eMsgField which) -{ - return !((Msg->cm_fields[which] != NULL) && - (Msg->cm_fields[which][0] != '\0')); + +int CM_IsEmpty(struct CtdlMessage *Msg, eMsgField which) { + return !((Msg->cm_fields[which] != NULL) && (Msg->cm_fields[which][0] != '\0')); } -void CM_SetField(struct CtdlMessage *Msg, eMsgField which, const char *buf, long length) -{ - if (Msg->cm_fields[which] != NULL) + +void CM_SetField(struct CtdlMessage *Msg, eMsgField which, const char *buf, long length) { + if (Msg->cm_fields[which] != NULL) { free (Msg->cm_fields[which]); + } + if (length < 0) { // You can set the length to -1 to have CM_SetField measure it for you + length = strlen(buf); + } Msg->cm_fields[which] = malloc(length + 1); memcpy(Msg->cm_fields[which], buf, length); Msg->cm_fields[which][length] = '\0'; Msg->cm_lengths[which] = length; } -void CM_SetFieldLONG(struct CtdlMessage *Msg, eMsgField which, long lvalue) -{ + +void CM_SetFieldLONG(struct CtdlMessage *Msg, eMsgField which, long lvalue) { char buf[128]; long len; len = snprintf(buf, sizeof(buf), "%ld", lvalue); CM_SetField(Msg, which, buf, len); } -void CM_CutFieldAt(struct CtdlMessage *Msg, eMsgField WhichToCut, long maxlen) -{ + + +void CM_CutFieldAt(struct CtdlMessage *Msg, eMsgField WhichToCut, long maxlen) { if (Msg->cm_fields[WhichToCut] == NULL) return; @@ -158,50 +178,49 @@ void CM_CutFieldAt(struct CtdlMessage *Msg, eMsgField WhichToCut, long maxlen) } } -void CM_FlushField(struct CtdlMessage *Msg, eMsgField which) -{ + +void CM_FlushField(struct CtdlMessage *Msg, eMsgField which) { if (Msg->cm_fields[which] != NULL) free (Msg->cm_fields[which]); Msg->cm_fields[which] = NULL; Msg->cm_lengths[which] = 0; } -void CM_Flush(struct CtdlMessage *Msg) -{ + + +void CM_Flush(struct CtdlMessage *Msg) { int i; - if (CM_IsValidMsg(Msg) == 0) + if (CM_IsValidMsg(Msg) == 0) { return; + } - for (i = 0; i < 256; ++i) - { + for (i = 0; i < 256; ++i) { CM_FlushField(Msg, i); } } -void CM_CopyField(struct CtdlMessage *Msg, eMsgField WhichToPutTo, eMsgField WhichtToCopy) -{ + +void CM_CopyField(struct CtdlMessage *Msg, eMsgField WhichToPutTo, eMsgField WhichtToCopy) { long len; - if (Msg->cm_fields[WhichToPutTo] != NULL) + if (Msg->cm_fields[WhichToPutTo] != NULL) { free (Msg->cm_fields[WhichToPutTo]); + } - if (Msg->cm_fields[WhichtToCopy] != NULL) - { + if (Msg->cm_fields[WhichtToCopy] != NULL) { len = Msg->cm_lengths[WhichtToCopy]; Msg->cm_fields[WhichToPutTo] = malloc(len + 1); memcpy(Msg->cm_fields[WhichToPutTo], Msg->cm_fields[WhichtToCopy], len); Msg->cm_fields[WhichToPutTo][len] = '\0'; Msg->cm_lengths[WhichToPutTo] = len; } - else - { + else { Msg->cm_fields[WhichToPutTo] = NULL; Msg->cm_lengths[WhichToPutTo] = 0; } } -void CM_PrependToField(struct CtdlMessage *Msg, eMsgField which, const char *buf, long length) -{ +void CM_PrependToField(struct CtdlMessage *Msg, eMsgField which, const char *buf, long length) { if (Msg->cm_fields[which] != NULL) { long oldmsgsize; long newmsgsize; @@ -225,58 +244,64 @@ void CM_PrependToField(struct CtdlMessage *Msg, eMsgField which, const char *buf } } -void CM_SetAsField(struct CtdlMessage *Msg, eMsgField which, char **buf, long length) -{ - if (Msg->cm_fields[which] != NULL) + +void CM_SetAsField(struct CtdlMessage *Msg, eMsgField which, char **buf, long length) { + if (Msg->cm_fields[which] != NULL) { free (Msg->cm_fields[which]); + } Msg->cm_fields[which] = *buf; *buf = NULL; - Msg->cm_lengths[which] = length; + if (length < 0) { // You can set the length to -1 to have CM_SetField measure it for you + Msg->cm_lengths[which] = strlen(Msg->cm_fields[which]); + } + else { + Msg->cm_lengths[which] = length; + } } -void CM_SetAsFieldSB(struct CtdlMessage *Msg, eMsgField which, StrBuf **buf) -{ - if (Msg->cm_fields[which] != NULL) + +void CM_SetAsFieldSB(struct CtdlMessage *Msg, eMsgField which, StrBuf **buf) { + if (Msg->cm_fields[which] != NULL) { free (Msg->cm_fields[which]); + } Msg->cm_lengths[which] = StrLength(*buf); Msg->cm_fields[which] = SmashStrBuf(buf); } -void CM_GetAsField(struct CtdlMessage *Msg, eMsgField which, char **ret, long *retlen) -{ - if (Msg->cm_fields[which] != NULL) - { + +void CM_GetAsField(struct CtdlMessage *Msg, eMsgField which, char **ret, long *retlen) { + if (Msg->cm_fields[which] != NULL) { *retlen = Msg->cm_lengths[which]; *ret = Msg->cm_fields[which]; Msg->cm_fields[which] = NULL; Msg->cm_lengths[which] = 0; } - else - { + else { *ret = NULL; *retlen = 0; } } + /* * Returns 1 if the supplied pointer points to a valid Citadel message. * If the pointer is NULL or the magic number check fails, returns 0. */ int CM_IsValidMsg(struct CtdlMessage *msg) { - if (msg == NULL) + if (msg == NULL) { return 0; + } if ((msg->cm_magic) != CTDLMESSAGE_MAGIC) { - struct CitContext *CCC = CC; - MSGM_syslog(LOG_WARNING, "CM_IsValidMsg() -- self-check failed\n"); + syslog(LOG_WARNING, "msgbase: CM_IsValidMsg() self-check failed"); return 0; } return 1; } -void CM_FreeContents(struct CtdlMessage *msg) -{ + +void CM_FreeContents(struct CtdlMessage *msg) { int i; for (i = 0; i < 256; ++i) @@ -287,13 +312,13 @@ void CM_FreeContents(struct CtdlMessage *msg) msg->cm_magic = 0; /* just in case */ } + + /* * 'Destructor' for struct CtdlMessage */ -void CM_Free(struct CtdlMessage *msg) -{ - if (CM_IsValidMsg(msg) == 0) - { +void CM_Free(struct CtdlMessage *msg) { + if (CM_IsValidMsg(msg) == 0) { if (msg != NULL) free (msg); return; } @@ -301,40 +326,40 @@ void CM_Free(struct CtdlMessage *msg) free(msg); } -int CM_DupField(eMsgField i, struct CtdlMessage *OrgMsg, struct CtdlMessage *NewMsg) -{ + +int CM_DupField(eMsgField i, struct CtdlMessage *OrgMsg, struct CtdlMessage *NewMsg) { long len; len = OrgMsg->cm_lengths[i]; NewMsg->cm_fields[i] = malloc(len + 1); - if (NewMsg->cm_fields[i] == NULL) + if (NewMsg->cm_fields[i] == NULL) { return 0; + } memcpy(NewMsg->cm_fields[i], OrgMsg->cm_fields[i], len); NewMsg->cm_fields[i][len] = '\0'; NewMsg->cm_lengths[i] = len; return 1; } -struct CtdlMessage * CM_Duplicate(struct CtdlMessage *OrgMsg) -{ + +struct CtdlMessage *CM_Duplicate(struct CtdlMessage *OrgMsg) { int i; struct CtdlMessage *NewMsg; - if (CM_IsValidMsg(OrgMsg) == 0) + if (CM_IsValidMsg(OrgMsg) == 0) { return NULL; + } NewMsg = (struct CtdlMessage *)malloc(sizeof(struct CtdlMessage)); - if (NewMsg == NULL) + if (NewMsg == NULL) { return NULL; + } memcpy(NewMsg, OrgMsg, sizeof(struct CtdlMessage)); memset(&NewMsg->cm_fields, 0, sizeof(char*) * 256); - for (i = 0; i < 256; ++i) - { - if (OrgMsg->cm_fields[i] != NULL) - { - if (!CM_DupField(i, OrgMsg, NewMsg)) - { + for (i = 0; i < 256; ++i) { + if (OrgMsg->cm_fields[i] != NULL) { + if (!CM_DupField(i, OrgMsg, NewMsg)) { CM_Free(NewMsg); return NULL; } @@ -345,9 +370,6 @@ struct CtdlMessage * CM_Duplicate(struct CtdlMessage *OrgMsg) } - - - /* Determine if a given message matches the fields in a message template. * Return 0 for a successful match. */ @@ -380,38 +402,36 @@ int CtdlMsgCmp(struct CtdlMessage *msg, struct CtdlMessage *template) { } - /* * Retrieve the "seen" message list for the current room. */ void CtdlGetSeen(char *buf, int which_set) { - struct CitContext *CCC = CC; visit vbuf; /* Learn about the user and room in question */ - CtdlGetRelationship(&vbuf, &CCC->user, &CCC->room); + CtdlGetRelationship(&vbuf, &CC->user, &CC->room); - if (which_set == ctdlsetseen_seen) + if (which_set == ctdlsetseen_seen) { safestrncpy(buf, vbuf.v_seen, SIZ); - if (which_set == ctdlsetseen_answered) + } + if (which_set == ctdlsetseen_answered) { safestrncpy(buf, vbuf.v_answered, SIZ); + } } - /* * Manipulate the "seen msgs" string (or other message set strings) */ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, int target_setting, int which_set, struct ctdluser *which_user, struct ctdlroom *which_room) { - struct CitContext *CCC = CC; struct cdbdata *cdbfr; int i, k; int is_seen = 0; int was_seen = 0; long lo = (-1L); - long hi = (-1L); /// TODO: we just write here. y? + long hi = (-1L); visit vbuf; long *msglist; int num_msgs = 0; @@ -429,15 +449,15 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, /* If no room was specified, we go with the current room. */ if (!which_room) { - which_room = &CCC->room; + which_room = &CC->room; } /* If no user was specified, we go with the current user. */ if (!which_user) { - which_user = &CCC->user; + which_user = &CC->user; } - MSG_syslog(LOG_DEBUG, "CtdlSetSeen(%d msgs starting with %ld, %s, %d) in <%s>\n", + syslog(LOG_DEBUG, "msgbase: CtdlSetSeen(%d msgs starting with %ld, %s, %d) in <%s>", num_target_msgnums, target_msgnums[0], (target_setting ? "SET" : "CLEAR"), which_set, @@ -453,7 +473,8 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, cdbfr->ptr = NULL; /* CtdlSetSeen() now owns this memory */ num_msgs = cdbfr->len / sizeof(long); cdb_free(cdbfr); - } else { + } + else { return; /* No messages at all? No further action. */ } @@ -474,18 +495,16 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, #if 0 /* This is a special diagnostic section. Do not allow it to run during normal operation. */ - MSG_syslog(LOG_DEBUG, "There are %d messages in the room.\n", num_msgs); + syslog(LOG_DEBUG, "There are %d messages in the room.\n", num_msgs); for (i=0; i 0) && (msglist[i] <= msglist[i-1])) abort(); } - MSG_syslog(LOG_DEBUG, "We are twiddling %d of them.\n", num_target_msgnums); + syslog(LOG_DEBUG, "We are twiddling %d of them.\n", num_target_msgnums); for (k=0; k 0) && (target_msgnums[k] <= target_msgnums[k-1])) abort(); } #endif - MSG_syslog(LOG_DEBUG, "before update: %s\n", ChrPtr(vset)); - /* Translate the existing sequence set into an array of booleans */ setstr = NewStrBuf(); lostr = NewStrBuf(); @@ -519,7 +538,6 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, FreeStrBuf(&lostr); FreeStrBuf(&histr); - /* Now translate the array of booleans back into a sequence set */ FlushStrBuf(vset); was_seen = 0; @@ -607,8 +625,6 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, vset = new_set; } - MSG_syslog(LOG_DEBUG, " after update: %s\n", ChrPtr(vset)); - /* Decide which message set we're manipulating */ switch (which_set) { case ctdlsetseen_seen: @@ -636,7 +652,6 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, ForEachMsgCallback CallBack, void *userdata) { - struct CitContext *CCC = CC; int a, i, j; visit vbuf; struct cdbdata *cdbfr; @@ -665,13 +680,13 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, if (need_to_free_re) regfree(&re); return -1; } - CtdlGetUser(&CCC->user, CCC->curr_user); + CtdlGetUser(&CC->user, CC->curr_user); if (server_shutting_down) { if (need_to_free_re) regfree(&re); return -1; } - CtdlGetRelationship(&vbuf, &CCC->user, &CCC->room); + CtdlGetRelationship(&vbuf, &CC->user, &CC->room); if (server_shutting_down) { if (need_to_free_re) regfree(&re); @@ -679,7 +694,7 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, } /* Load the message list */ - cdbfr = cdb_fetch(CDB_MSGLISTS, &CCC->room.QRnumber, sizeof(long)); + cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long)); if (cdbfr == NULL) { if (need_to_free_re) regfree(&re); return 0; /* No messages at all? No further action. */ @@ -826,13 +841,16 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, || ((mode == MSGS_EQ) && (thismsg == ref)) ) ) { - if ((mode == MSGS_NEW) && (CCC->user.flags & US_LASTOLD) && (lastold > 0L) && (printed_lastold == 0) && (!is_seen)) { - if (CallBack) + if ((mode == MSGS_NEW) && (CC->user.flags & US_LASTOLD) && (lastold > 0L) && (printed_lastold == 0) && (!is_seen)) { + if (CallBack) { CallBack(lastold, userdata); + } printed_lastold = 1; ++num_processed; } - if (CallBack) CallBack(thismsg, userdata); + if (CallBack) { + CallBack(thismsg, userdata); + } ++num_processed; } } @@ -841,12 +859,12 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, /* * We cache the most recent msglist in order to do security checks later */ - if (CCC->client_socket > 0) { - if (CCC->cached_msglist != NULL) { - free(CCC->cached_msglist); + if (CC->client_socket > 0) { + if (CC->cached_msglist != NULL) { + free(CC->cached_msglist); } - CCC->cached_msglist = msglist; - CCC->cached_num_msgs = num_msgs; + CC->cached_msglist = msglist; + CC->cached_num_msgs = num_msgs; } else { free(msglist); @@ -856,7 +874,6 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, } - /* * memfmout() - Citadel text formatter and paginator. * Although the original purpose of this routine was to format @@ -868,7 +885,6 @@ void memfmout( char *mptr, /* where are we going to get our text from? */ const char *nl /* string to terminate lines with */ ) { - struct CitContext *CCC = CC; int column = 0; unsigned char ch = 0; char outbuf[1024]; @@ -880,15 +896,13 @@ void memfmout( while (ch=*(mptr++), ch != 0) { if (ch == '\n') { - if (client_write(outbuf, len) == -1) - { - MSGM_syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); + if (client_write(outbuf, len) == -1) { + syslog(LOG_ERR, "msgbase: memfmout() aborting due to write failure"); return; } len = 0; - if (client_write(nl, nllen) == -1) - { - MSGM_syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); + if (client_write(nl, nllen) == -1) { + syslog(LOG_ERR, "msgbase: memfmout() aborting due to write failure"); return; } column = 0; @@ -898,15 +912,13 @@ void memfmout( } else if (isspace(ch)) { if (column > 72) { /* Beyond 72 columns, break on the next space */ - if (client_write(outbuf, len) == -1) - { - MSGM_syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); + if (client_write(outbuf, len) == -1) { + syslog(LOG_ERR, "msgbase: memfmout() aborting due to write failure"); return; } len = 0; - if (client_write(nl, nllen) == -1) - { - MSGM_syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); + if (client_write(nl, nllen) == -1) { + syslog(LOG_ERR, "msgbase: memfmout() aborting due to write failure"); return; } column = 0; @@ -920,15 +932,13 @@ void memfmout( outbuf[len++] = ch; ++column; if (column > 1000) { /* Beyond 1000 columns, break anywhere */ - if (client_write(outbuf, len) == -1) - { - MSGM_syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); + if (client_write(outbuf, len) == -1) { + syslog(LOG_ERR, "msgbase: memfmout() aborting due to write failure"); return; } len = 0; - if (client_write(nl, nllen) == -1) - { - MSGM_syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); + if (client_write(nl, nllen) == -1) { + syslog(LOG_ERR, "msgbase: memfmout(): aborting due to write failure"); return; } column = 0; @@ -936,9 +946,8 @@ void memfmout( } } if (len) { - if (client_write(outbuf, len) == -1) - { - MSGM_syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); + if (client_write(outbuf, len) == -1) { + syslog(LOG_ERR, "msgbase: memfmout() aborting due to write failure"); return; } client_write(nl, nllen); @@ -947,7 +956,6 @@ void memfmout( } - /* * Callback function for mime parser that simply lists the part */ @@ -971,6 +979,7 @@ void list_this_part(char *name, char *filename, char *partnum, char *disp, } } + /* * Callback function for multipart prefix */ @@ -990,6 +999,7 @@ void list_this_pref(char *name, char *filename, char *partnum, char *disp, } } + /* * Callback function for multipart sufffix */ @@ -1019,44 +1029,38 @@ void mime_download(char *name, char *filename, char *partnum, char *disp, char *encoding, char *cbid, void *cbuserdata) { int rv = 0; - CitContext *CCC = MyContext(); /* Silently go away if there's already a download open. */ - if (CCC->download_fp != NULL) + if (CC->download_fp != NULL) return; if ( - (!IsEmptyStr(partnum) && (!strcasecmp(CCC->download_desired_section, partnum))) - || (!IsEmptyStr(cbid) && (!strcasecmp(CCC->download_desired_section, cbid))) + (!IsEmptyStr(partnum) && (!strcasecmp(CC->download_desired_section, partnum))) + || (!IsEmptyStr(cbid) && (!strcasecmp(CC->download_desired_section, cbid))) ) { - CCC->download_fp = tmpfile(); - if (CCC->download_fp == NULL) { - MSG_syslog(LOG_EMERG, "mime_download(): Couldn't write: %s\n", - strerror(errno)); - cprintf("%d cannot open temporary file: %s\n", - ERROR + INTERNAL_ERROR, strerror(errno)); + CC->download_fp = tmpfile(); + if (CC->download_fp == NULL) { + syslog(LOG_ERR, "msgbase: mime_download() couldn't write: %m"); + cprintf("%d cannot open temporary file: %s\n", ERROR + INTERNAL_ERROR, strerror(errno)); return; } - rv = fwrite(content, length, 1, CCC->download_fp); + rv = fwrite(content, length, 1, CC->download_fp); if (rv <= 0) { - MSG_syslog(LOG_EMERG, "mime_download(): Couldn't write: %s\n", - strerror(errno)); - cprintf("%d unable to write tempfile.\n", - ERROR + TOO_BIG); - fclose(CCC->download_fp); - CCC->download_fp = NULL; + syslog(LOG_ERR, "msgbase: mime_download() Couldn't write: %m"); + cprintf("%d unable to write tempfile.\n", ERROR + TOO_BIG); + fclose(CC->download_fp); + CC->download_fp = NULL; return; } - fflush(CCC->download_fp); - rewind(CCC->download_fp); + fflush(CC->download_fp); + rewind(CC->download_fp); OpenCmdResult(filename, cbtype); } } - /* * Callback function for mime parser that outputs a section all at once. * We can specify the desired section by part number *or* content-id. @@ -1084,32 +1088,20 @@ void mime_spew_section(char *name, char *filename, char *partnum, char *disp, } -/* - * Load a message from disk into memory. - * This is used by CtdlOutputMsg() and other fetch functions. - * - * NOTE: Caller is responsible for freeing the returned CtdlMessage struct - * using the CtdlMessageFree() function. - */ -struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) +struct CtdlMessage *CtdlDeserializeMessage(long msgnum, int with_body, const char *Buffer, long Length) { - struct CitContext *CCC = CC; - struct cdbdata *dmsgtext; struct CtdlMessage *ret = NULL; - char *mptr; - char *upper_bound; + const char *mptr; + const char *upper_bound; cit_uint8_t ch; cit_uint8_t field_header; eMsgField which; - MSG_syslog(LOG_DEBUG, "CtdlFetchMessage(%ld, %d)\n", msgnum, with_body); - dmsgtext = cdb_fetch(CDB_MSGMAIN, &msgnum, sizeof(long)); - if (dmsgtext == NULL) { - MSG_syslog(LOG_ERR, "CtdlFetchMessage(%ld, %d) Failed!\n", msgnum, with_body); + mptr = Buffer; + upper_bound = Buffer + Length; + if (msgnum <= 0) { return NULL; } - mptr = dmsgtext->ptr; - upper_bound = mptr + dmsgtext->len; /* Parse the three bytes that begin EVERY message on disk. * The first is always 0xFF, the on-disk magic number. @@ -1118,8 +1110,7 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) */ ch = *mptr++; if (ch != 255) { - MSG_syslog(LOG_ERR, "Message %ld appears to be corrupted.\n", msgnum); - cdb_free(dmsgtext); + syslog(LOG_ERR, "msgbase: message %ld appears to be corrupted", msgnum); return NULL; } ret = (struct CtdlMessage *) malloc(sizeof(struct CtdlMessage)); @@ -1129,13 +1120,6 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) ret->cm_anon_type = *mptr++; /* Anon type byte */ ret->cm_format_type = *mptr++; /* Format type byte */ - - if (dmsgtext->ptr[dmsgtext->len - 1] != '\0') - { - MSG_syslog(LOG_ERR, "CtdlFetchMessage(%ld, %d) Forcefully terminating message!!\n", msgnum, with_body); - dmsgtext->ptr[dmsgtext->len - 1] = '\0'; - } - /* * The rest is zero or more arbitrary fields. Load them in. * We're done when we encounter either a zero-length field or @@ -1146,8 +1130,7 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) long len; /* work around possibly buggy messages: */ - while (field_header == '\0') - { + while (field_header == '\0') { if (mptr >= upper_bound) { break; } @@ -1165,8 +1148,42 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) } while ((mptr < upper_bound) && (field_header != 'M')); + return (ret); +} + + +/* + * Load a message from disk into memory. + * This is used by CtdlOutputMsg() and other fetch functions. + * + * NOTE: Caller is responsible for freeing the returned CtdlMessage struct + * using the CM_Free(); function. + */ +struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) +{ + struct cdbdata *dmsgtext; + struct CtdlMessage *ret = NULL; + + syslog(LOG_DEBUG, "msgbase: CtdlFetchMessage(%ld, %d)", msgnum, with_body); + dmsgtext = cdb_fetch(CDB_MSGMAIN, &msgnum, sizeof(long)); + if (dmsgtext == NULL) { + syslog(LOG_ERR, "msgbase: CtdlFetchMessage(%ld, %d) Failed!", msgnum, with_body); + return NULL; + } + + if (dmsgtext->ptr[dmsgtext->len - 1] != '\0') { + syslog(LOG_ERR, "msgbase: CtdlFetchMessage(%ld, %d) Forcefully terminating message!!", msgnum, with_body); + dmsgtext->ptr[dmsgtext->len - 1] = '\0'; + } + + ret = CtdlDeserializeMessage(msgnum, with_body, dmsgtext->ptr, dmsgtext->len); + cdb_free(dmsgtext); + if (ret == NULL) { + return NULL; + } + /* Always make sure there's something in the msg text field. If * it's NULL, the message text is most likely stored separately, * so go ahead and fetch that. Failing that, just set a dummy @@ -1183,17 +1200,10 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) CM_SetField(ret, eMesageText, HKEY("\r\n\r\n (no text)\r\n")); } - /* Perform "before read" hooks (aborting if any return nonzero) */ - if (PerformMessageHooks(ret, NULL, EVT_BEFOREREAD) > 0) { - CM_Free(ret); - return NULL; - } - return (ret); } - /* * Pre callback function for multipart/alternative * @@ -1208,11 +1218,10 @@ void fixed_output_pre(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, char *cbid, void *cbuserdata) { - struct CitContext *CCC = CC; struct ma_info *ma; ma = (struct ma_info *)cbuserdata; - MSG_syslog(LOG_DEBUG, "fixed_output_pre() type=<%s>\n", cbtype); + syslog(LOG_DEBUG, "msgbase: fixed_output_pre() type=<%s>", cbtype); if (!strcasecmp(cbtype, "multipart/alternative")) { ++ma->is_ma; ma->did_print = 0; @@ -1222,6 +1231,7 @@ void fixed_output_pre(char *name, char *filename, char *partnum, char *disp, } } + /* * Post callback function for multipart/alternative */ @@ -1229,11 +1239,10 @@ void fixed_output_post(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, char *cbid, void *cbuserdata) { - struct CitContext *CCC = CC; struct ma_info *ma; ma = (struct ma_info *)cbuserdata; - MSG_syslog(LOG_DEBUG, "fixed_output_post() type=<%s>\n", cbtype); + syslog(LOG_DEBUG, "msgbase: fixed_output_post() type=<%s>", cbtype); if (!strcasecmp(cbtype, "multipart/alternative")) { --ma->is_ma; ma->did_print = 0; @@ -1243,6 +1252,7 @@ void fixed_output_post(char *name, char *filename, char *partnum, char *disp, } } + /* * Inline callback function for mime parser that wants to display text */ @@ -1250,7 +1260,6 @@ void fixed_output(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, char *cbid, void *cbuserdata) { - struct CitContext *CCC = CC; char *ptr; char *wptr; size_t wlen; @@ -1258,16 +1267,17 @@ void fixed_output(char *name, char *filename, char *partnum, char *disp, ma = (struct ma_info *)cbuserdata; - MSG_syslog(LOG_DEBUG, - "fixed_output() part %s: %s (%s) (%ld bytes)\n", - partnum, filename, cbtype, (long)length); + syslog(LOG_DEBUG, + "msgbase: fixed_output() part %s: %s (%s) (%ld bytes)", + partnum, filename, cbtype, (long)length + ); /* * If we're in the middle of a multipart/alternative scope and * we've already printed another section, skip this one. */ if ( (ma->is_ma) && (ma->did_print) ) { - MSG_syslog(LOG_DEBUG, "Skipping part %s (%s)\n", partnum, cbtype); + syslog(LOG_DEBUG, "msgbase: skipping part %s (%s)", partnum, cbtype); return; } ma->did_print = 1; @@ -1285,7 +1295,7 @@ void fixed_output(char *name, char *filename, char *partnum, char *disp, } if (!strcasecmp(cbtype, "text/html")) { - ptr = html_to_ascii(content, length, 80, 0); + ptr = html_to_ascii(content, length, 80); wlen = strlen(ptr); client_write(ptr, wlen); if ((wlen > 0) && (ptr[wlen-1] != '\n')) { @@ -1309,6 +1319,7 @@ void fixed_output(char *name, char *filename, char *partnum, char *disp, } } + /* * The client is elegant and sophisticated and wants to be choosy about * MIME content types, so figure out which multipart/alternative part @@ -1324,23 +1335,17 @@ void choose_preferred(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, char *cbid, void *cbuserdata) { - struct CitContext *CCC = CC; char buf[1024]; int i; struct ma_info *ma; ma = (struct ma_info *)cbuserdata; - // NOTE: REMOVING THIS CONDITIONAL FIXES BUG 220 - // http://bugzilla.citadel.org/show_bug.cgi?id=220 - // I don't know if there are any side effects! Please TEST TEST TEST - //if (ma->is_ma > 0) { - - for (i=0; ipreferred_formats, '|'); ++i) { - extract_token(buf, CCC->preferred_formats, i, '|', sizeof buf); + for (i=0; ipreferred_formats, '|'); ++i) { + extract_token(buf, CC->preferred_formats, i, '|', sizeof buf); if ( (!strcasecmp(buf, cbtype)) && (!ma->freeze) ) { if (i < ma->chosen_pref) { - MSG_syslog(LOG_DEBUG, "Setting chosen part: <%s>\n", partnum); + syslog(LOG_DEBUG, "msgbase: setting chosen part to <%s>", partnum); safestrncpy(ma->chosen_part, partnum, sizeof ma->chosen_part); ma->chosen_pref = i; } @@ -1348,6 +1353,7 @@ void choose_preferred(char *name, char *filename, char *partnum, char *disp, } } + /* * Now that we've chosen our preferred part, output it. */ @@ -1363,7 +1369,6 @@ void output_preferred(char *name, char *cbid, void *cbuserdata) { - struct CitContext *CCC = CC; int i; char buf[128]; int add_newline = 0; @@ -1381,8 +1386,8 @@ void output_preferred(char *name, /* If the content-type of this part is in our preferred formats * list, we can simply output it verbatim. */ - for (i=0; ipreferred_formats, '|'); ++i) { - extract_token(buf, CCC->preferred_formats, i, '|', sizeof buf); + for (i=0; ipreferred_formats, '|'); ++i) { + extract_token(buf, CC->preferred_formats, i, '|', sizeof buf); if (!strcasecmp(buf, cbtype)) { /* Yeah! Go! W00t!! */ if (ma->dont_decode == 0) @@ -1419,7 +1424,7 @@ void output_preferred(char *name, cprintf("\n"); if (client_write(text_content, length) == -1) { - MSGM_syslog(LOG_ERR, "output_preferred(): aborting due to write failure.\n"); + syslog(LOG_ERR, "msgbase: output_preferred() aborting due to write failure"); return; } if (add_newline) cprintf("\n"); @@ -1485,13 +1490,12 @@ void extract_encapsulated_message(char *name, char *filename, char *partnum, cha * (This is a security check) */ int check_cached_msglist(long msgnum) { - struct CitContext *CCC = CC; /* cases in which we skip the check */ - if (!CCC) return om_ok; /* not a session */ - if (CCC->client_socket <= 0) return om_ok; /* not a client session */ - if (CCC->cached_msglist == NULL) return om_access_denied; /* no msglist fetched */ - if (CCC->cached_num_msgs == 0) return om_access_denied; /* nothing to check */ + if (!CC) return om_ok; /* not a session */ + if (CC->client_socket <= 0) return om_ok; /* not a client session */ + if (CC->cached_msglist == NULL) return om_access_denied; /* no msglist fetched */ + if (CC->cached_num_msgs == 0) return om_access_denied; /* nothing to check */ /* Do a binary search within the cached_msglist for the requested msgnum */ @@ -1500,7 +1504,7 @@ int check_cached_msglist(long msgnum) { while (max >= min) { int middle = min + (max-min) / 2 ; - if (msgnum == CCC->cached_msglist[middle]) { + if (msgnum == CC->cached_msglist[middle]) { return om_ok; } if (msgnum > CC->cached_msglist[middle]) { @@ -1515,7 +1519,6 @@ int check_cached_msglist(long msgnum) { } - /* * Get a message off disk. (returns om_* values found in msgbase.h) * @@ -1531,13 +1534,12 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ char **Address, char **MessageID ) { - struct CitContext *CCC = CC; struct CtdlMessage *TheMessage = NULL; int retcode = CIT_OK; struct encapmsg encap; int r; - MSG_syslog(LOG_DEBUG, "CtdlOutputMsg(msgnum=%ld, mode=%d, section=%s)\n", + syslog(LOG_DEBUG, "msgbase: CtdlOutputMsg(msgnum=%ld, mode=%d, section=%s)", msg_num, mode, (section ? section : "<>") ); @@ -1565,8 +1567,8 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ r = check_cached_msglist(msg_num); } if (r != om_ok) { - MSG_syslog(LOG_DEBUG, "Security check fail: message %ld is not in %s\n", - msg_num, CCC->room.QRname + syslog(LOG_DEBUG, "msgbase: security check fail; message %ld is not in %s", + msg_num, CC->room.QRname ); if (do_proto) { if (r == om_access_denied) { @@ -1673,13 +1675,8 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ } - -void OutputCtdlMsgHeaders( - struct CtdlMessage *TheMessage, - int do_proto) /* do Citadel protocol responses? */ -{ +void OutputCtdlMsgHeaders(struct CtdlMessage *TheMessage, int do_proto) { int i; - int suppress_f = 0; char buf[SIZ]; char display_name[256]; @@ -1706,53 +1703,45 @@ void OutputCtdlMsgHeaders( } } - /* Don't show Internet address for users on the - * local Citadel network. - */ - suppress_f = 0; - if (!CM_IsEmpty(TheMessage, eNodeName) && - (haschar(TheMessage->cm_fields[eNodeName], '.') == 0)) - { - suppress_f = 1; - } - /* Now spew the header fields in the order we like them. */ for (i=0; i< NDiskFields; ++i) { eMsgField Field; Field = FieldOrder[i]; if (Field != eMesageText) { - if ( (!CM_IsEmpty(TheMessage, Field)) - && (msgkeys[Field] != NULL) ) { - if ((Field == eenVelopeTo) || - (Field == eRecipient) || - (Field == eCarbonCopY)) { + if ( (!CM_IsEmpty(TheMessage, Field)) && (msgkeys[Field] != NULL) ) { + if ((Field == eenVelopeTo) || (Field == eRecipient) || (Field == eCarbonCopY)) { sanitize_truncated_recipient(TheMessage->cm_fields[Field]); } if (Field == eAuthor) { - if (do_proto) cprintf("%s=%s\n", - msgkeys[Field], - display_name); - } - else if ((Field == erFc822Addr) && (suppress_f)) { - /* do nothing */ + if (do_proto) { + cprintf("%s=%s\n", msgkeys[Field], display_name); + } } /* Masquerade display name if needed */ else { - if (do_proto) cprintf("%s=%s\n", - msgkeys[Field], - TheMessage->cm_fields[Field] - ); + if (do_proto) { + cprintf("%s=%s\n", msgkeys[Field], TheMessage->cm_fields[Field]); + } + } + /* Give the client a hint about whether the message originated locally */ + if (Field == erFc822Addr) { + if (IsDirectory(TheMessage->cm_fields[Field] ,0)) { + cprintf("locl=yes\n"); // message originated locally. + } + + + } } } } - } + void OutputRFC822MsgHeaders( struct CtdlMessage *TheMessage, - int flags, /* should the bessage be exported clean */ - const char *nl, + int flags, /* should the message be exported clean */ + const char *nl, int nlen, char *mid, long sizeof_mid, char *suser, long sizeof_suser, char *luser, long sizeof_luser, @@ -1802,27 +1791,18 @@ void OutputRFC822MsgHeaders( subject_found = 1; break; case emessageId: - safestrncpy(mid, mptr, sizeof_mid); /// TODO: detect @ here and copy @nodename in if not found. + safestrncpy(mid, mptr, sizeof_mid); break; case erFc822Addr: safestrncpy(fuser, mptr, sizeof_fuser); - /* case eOriginalRoom: - cprintf("X-Citadel-Room: %s%s", - mptr, nl) - break; - ; */ - case eNodeName: - safestrncpy(snode, mptr, sizeof_snode); break; case eRecipient: - if (haschar(mptr, '@') == 0) - { + if (haschar(mptr, '@') == 0) { sanitize_truncated_recipient(mptr); - cprintf("To: %s@%s", mptr, config.c_fqdn); + cprintf("To: %s@%s", mptr, CtdlGetConfigStr("c_fqdn")); cprintf("%s", nl); } - else - { + else { if ((flags & QP_EADDR) != 0) { mptr = qp_encode_email_addrs(mptr); } @@ -1832,8 +1812,7 @@ void OutputRFC822MsgHeaders( } break; case eTimestamp: - datestring(datestamp, sizeof datestamp, - atol(mptr), DATESTRING_RFC822); + datestring(datestamp, sizeof datestamp, atol(mptr), DATESTRING_RFC822); cprintf("Date: %s%s", datestamp, nl); break; case eWeferences: @@ -1858,25 +1837,21 @@ void OutputRFC822MsgHeaders( cprintf("Reply-To: %s%s", mptr, nl); break; - case eRemoteRoom: - case eDestination: case eExclusiveID: - case eHumanNode: case eJournal: case eMesageText: case eBig_message: case eOriginalRoom: - case eSpecialField: case eErrorMsg: case eSuppressIdx: case eExtnotify: case eVltMsgNum: /* these don't map to mime message headers. */ break; - } - if (mptr != mpptr) + if (mptr != mpptr) { free (mptr); + } } } if (subject_found == 0) { @@ -1889,8 +1864,7 @@ void Dump_RFC822HeadersBody( struct CtdlMessage *TheMessage, int headers_only, /* eschew the message body? */ int flags, /* should the bessage be exported clean? */ - - const char *nl) + const char *nl, int nlen) { cit_uint8_t prev_ch; int eoh = 0; @@ -1899,10 +1873,10 @@ void Dump_RFC822HeadersBody( int outlen = 0; int nllen = strlen(nl); char *mptr; + int lfSent = 0; mptr = TheMessage->cm_fields[eMesageText]; - prev_ch = '\0'; while (*mptr != '\0') { if (*mptr == '\r') { @@ -1926,7 +1900,7 @@ void Dump_RFC822HeadersBody( ((headers_only == HEADERS_ONLY) && (mptr < StartOfText)) || ((headers_only != HEADERS_NONE) && (headers_only != HEADERS_ONLY)) - ) { + ) { if (*mptr == '\n') { memcpy(&outbuf[outlen], nl, nllen); outlen += nllen; @@ -1937,34 +1911,31 @@ void Dump_RFC822HeadersBody( } } } - if (flags & ESC_DOT) - { - if ((prev_ch == '\n') && - (*mptr == '.') && - ((*(mptr+1) == '\r') || (*(mptr+1) == '\n'))) - { + if (flags & ESC_DOT) { + if ((prev_ch == '\n') && (*mptr == '.') && ((*(mptr+1) == '\r') || (*(mptr+1) == '\n'))) { outbuf[outlen++] = '.'; } prev_ch = *mptr; } ++mptr; if (outlen > 1000) { - if (client_write(outbuf, outlen) == -1) - { - struct CitContext *CCC = CC; - MSGM_syslog(LOG_ERR, "Dump_RFC822HeadersBody(): aborting due to write failure.\n"); + if (client_write(outbuf, outlen) == -1) { + syslog(LOG_ERR, "msgbase: Dump_RFC822HeadersBody() aborting due to write failure"); return; } + lfSent = (outbuf[outlen - 1] == '\n'); outlen = 0; } } if (outlen > 0) { client_write(outbuf, outlen); + lfSent = (outbuf[outlen - 1] == '\n'); } + if (!lfSent) + client_write(nl, nlen); } - /* If the format type on disk is 1 (fixed-format), then we want * everything to be output completely literally ... regardless of * what message transfer format is in use. @@ -1972,13 +1943,12 @@ void Dump_RFC822HeadersBody( void DumpFormatFixed( struct CtdlMessage *TheMessage, int mode, /* how would you like that message? */ - const char *nl) + const char *nl, int nllen) { cit_uint8_t ch; char buf[SIZ]; int buflen; int xlline = 0; - int nllen = strlen (nl); char *mptr; mptr = TheMessage->cm_fields[eMesageText]; @@ -2008,22 +1978,19 @@ void DumpFormatFixed( ch = '\r'; } } - /* if we reach the outer bounds of our buffer, - abort without respect what whe purge. */ - if (xlline && - ((isspace(ch)) || - (buflen > SIZ - nllen - 2))) + + /* if we reach the outer bounds of our buffer, abort without respect for what we purge. */ + if (xlline && ((isspace(ch)) || (buflen > SIZ - nllen - 2))) { ch = '\r'; + } if (ch == '\r') { memcpy (&buf[buflen], nl, nllen); buflen += nllen; buf[buflen] = '\0'; - if (client_write(buf, buflen) == -1) - { - struct CitContext *CCC = CC; - MSGM_syslog(LOG_ERR, "DumpFormatFixed(): aborting due to write failure.\n"); + if (client_write(buf, buflen) == -1) { + syslog(LOG_ERR, "msgbase: DumpFormatFixed() aborting due to write failure"); return; } *buf = '\0'; @@ -2035,10 +2002,12 @@ void DumpFormatFixed( } } buf[buflen] = '\0'; - if (!IsEmptyStr(buf)) + if (!IsEmptyStr(buf)) { cprintf("%s%s", buf, nl); + } } + /* * Get a message off disk. (returns om_* values found in msgbase.h) */ @@ -2050,32 +2019,32 @@ int CtdlOutputPreLoadedMsg( int crlf, /* Use CRLF newlines instead of LF? */ int flags /* should the bessage be exported clean? */ ) { - struct CitContext *CCC = CC; int i; const char *nl; /* newline string */ + int nlen; struct ma_info ma; /* Buffers needed for RFC822 translation. These are all filled * using functions that are bounds-checked, and therefore we can * make them substantially smaller than SIZ. */ - char suser[100]; - char luser[100]; - char fuser[100]; - char snode[100]; - char mid[100]; + char suser[1024]; + char luser[1024]; + char fuser[1024]; + char snode[1024]; + char mid[1024]; - MSG_syslog(LOG_DEBUG, "CtdlOutputPreLoadedMsg(TheMessage=%s, %d, %d, %d, %d\n", + syslog(LOG_DEBUG, "msgbase: CtdlOutputPreLoadedMsg(TheMessage=%s, %d, %d, %d, %d", ((TheMessage == NULL) ? "NULL" : "not null"), - mode, headers_only, do_proto, crlf); + mode, headers_only, do_proto, crlf + ); strcpy(mid, "unknown"); nl = (crlf ? "\r\n" : "\n"); + nlen = crlf ? 2 : 1; if (!CM_IsValidMsg(TheMessage)) { - MSGM_syslog(LOG_ERR, - "ERROR: invalid preloaded message for output\n"); - cit_backtrace (); + syslog(LOG_ERR, "msgbase: error; invalid preloaded message for output"); return(om_no_such_msg); } @@ -2092,7 +2061,7 @@ int CtdlOutputPreLoadedMsg( if (do_proto) cprintf("%d This is not a MIME message.\n", ERROR + ILLEGAL_VALUE); - } else if (CCC->download_fp != NULL) { + } else if (CC->download_fp != NULL) { if (do_proto) cprintf( "%d You already have a download open.\n", ERROR + RESOURCE_BUSY); @@ -2103,14 +2072,14 @@ int CtdlOutputPreLoadedMsg( /* If there's no file open by this time, the requested * section wasn't found, so print an error */ - if (CCC->download_fp == NULL) { + if (CC->download_fp == NULL) { if (do_proto) cprintf( "%d Section %s not found.\n", ERROR + FILE_NOT_FOUND, - CCC->download_desired_section); + CC->download_desired_section); } } - return((CCC->download_fp != NULL) ? om_ok : om_mime_error); + return((CC->download_fp != NULL) ? om_ok : om_mime_error); } /* MT_SPEW_SECTION is like MT_DOWNLOAD except it outputs the whole MIME part @@ -2133,10 +2102,10 @@ int CtdlOutputPreLoadedMsg( if (do_proto) cprintf( "%d Section %s not found.\n", ERROR + FILE_NOT_FOUND, - CCC->download_desired_section); + CC->download_desired_section); } } - return((CCC->download_fp != NULL) ? om_ok : om_mime_error); + return((CC->download_fp != NULL) ? om_ok : om_mime_error); } /* now for the user-mode message reading loops */ @@ -2147,7 +2116,7 @@ int CtdlOutputPreLoadedMsg( /* Tell the client which format type we're using. */ if ( (mode == MT_CITADEL) && (do_proto) ) { - cprintf("type=%d\n", TheMessage->cm_format_type); + cprintf("type=%d\n", TheMessage->cm_format_type); // Tell the client which format type we're using. } /* nhdr=yes means that we're only displaying headers, no body */ @@ -2158,20 +2127,20 @@ int CtdlOutputPreLoadedMsg( cprintf("nhdr=yes\n"); } - if ((mode == MT_CITADEL) || (mode == MT_MIME)) + if ((mode == MT_CITADEL) || (mode == MT_MIME)) { OutputCtdlMsgHeaders(TheMessage, do_proto); - + } /* begin header processing loop for RFC822 transfer format */ strcpy(suser, ""); strcpy(luser, ""); strcpy(fuser, ""); - memcpy(snode, CFG_KEY(c_nodename) + 1); + strcpy(snode, ""); if (mode == MT_RFC822) OutputRFC822MsgHeaders( TheMessage, flags, - nl, + nl, nlen, mid, sizeof(mid), suser, sizeof(suser), luser, sizeof(luser), @@ -2186,12 +2155,8 @@ int CtdlOutputPreLoadedMsg( } if (mode == MT_RFC822) { - if (!strcasecmp(snode, NODENAME)) { - safestrncpy(snode, FQDN, sizeof snode); - } - /* Construct a fun message id */ - cprintf("Message-ID: <%s", mid);/// todo: this possibly breaks threadding mails. + cprintf("Message-ID: <%s", mid); if (strchr(mid, '@')==NULL) { cprintf("@%s", snode); } @@ -2235,7 +2200,7 @@ START_TEXT: TheMessage, headers_only, flags, - nl); + nl, nlen); goto DONE; } } @@ -2253,7 +2218,7 @@ START_TEXT: DumpFormatFixed( TheMessage, mode, /* how would you like that message? */ - nl); + nl, nlen); /* If the message on disk is format 0 (Citadel vari-format), we * output using the formatter at 80 columns. This is the final output @@ -2281,7 +2246,7 @@ START_TEXT: ma.use_fo_hooks = 0; strcpy(ma.chosen_part, "1"); ma.chosen_pref = 9999; - ma.dont_decode = CCC->msg4_dont_decode; + ma.dont_decode = CC->msg4_dont_decode; mime_parser(CM_RANGE(TheMessage, eMesageText), *choose_preferred, *fixed_output_pre, *fixed_output_post, (void *)&ma, 1); @@ -2316,7 +2281,6 @@ DONE: /* now we're done */ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newmsgs, int do_repl_check, struct CtdlMessage *supplied_msg, int suppress_refcount_adj ) { - struct CitContext *CCC = CC; int i, j, unique; char hold_rm[ROOMNAMELEN]; struct cdbdata *cdbfr; @@ -2330,12 +2294,12 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms long *msgs_to_be_merged = NULL; int num_msgs_to_be_merged = 0; - MSG_syslog(LOG_DEBUG, - "CtdlSaveMsgPointersInRoom(room=%s, num_msgs=%d, repl=%d, suppress_rca=%d)\n", - roomname, num_newmsgs, do_repl_check, suppress_refcount_adj + syslog(LOG_DEBUG, + "msgbase: CtdlSaveMsgPointersInRoom(room=%s, num_msgs=%d, repl=%d, suppress_rca=%d)", + roomname, num_newmsgs, do_repl_check, suppress_refcount_adj ); - strcpy(hold_rm, CCC->room.QRname); + strcpy(hold_rm, CC->room.QRname); /* Sanity checks */ if (newmsgidlist == NULL) return(ERROR + INTERNAL_ERROR); @@ -2343,10 +2307,10 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms if (num_newmsgs > 1) supplied_msg = NULL; /* Now the regular stuff */ - if (CtdlGetRoomLock(&CCC->room, - ((roomname != NULL) ? roomname : CCC->room.QRname) ) + if (CtdlGetRoomLock(&CC->room, + ((roomname != NULL) ? roomname : CC->room.QRname) ) != 0) { - MSG_syslog(LOG_ERR, "No such room <%s>\n", roomname); + syslog(LOG_ERR, "msgbase: no such room <%s>", roomname); return(ERROR + ROOM_NOT_FOUND); } @@ -2355,7 +2319,7 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms num_msgs_to_be_merged = 0; - cdbfr = cdb_fetch(CDB_MSGLISTS, &CCC->room.QRnumber, sizeof(long)); + cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long)); if (cdbfr == NULL) { msglist = NULL; num_msgs = 0; @@ -2383,14 +2347,14 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms } } - MSG_syslog(LOG_DEBUG, "%d unique messages to be merged\n", num_msgs_to_be_merged); + syslog(LOG_DEBUG, "msgbase: %d unique messages to be merged", num_msgs_to_be_merged); /* * Now merge the new messages */ msglist = realloc(msglist, (sizeof(long) * (num_msgs + num_msgs_to_be_merged)) ); if (msglist == NULL) { - MSGM_syslog(LOG_ALERT, "ERROR: can't realloc message list!\n"); + syslog(LOG_ALERT, "msgbase: ERROR; can't realloc message list!"); free(msgs_to_be_merged); return (ERROR + INTERNAL_ERROR); } @@ -2404,19 +2368,19 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms highest_msg = msglist[num_msgs - 1]; /* Write it back to disk. */ - cdb_store(CDB_MSGLISTS, &CCC->room.QRnumber, (int)sizeof(long), + cdb_store(CDB_MSGLISTS, &CC->room.QRnumber, (int)sizeof(long), msglist, (int)(num_msgs * sizeof(long))); /* Free up the memory we used. */ free(msglist); /* Update the highest-message pointer and unlock the room. */ - CCC->room.QRhighest = highest_msg; - CtdlPutRoomLock(&CCC->room); + CC->room.QRhighest = highest_msg; + CtdlPutRoomLock(&CC->room); /* Perform replication checks if necessary */ - if ( (DoesThisRoomNeedEuidIndexing(&CCC->room)) && (do_repl_check) ) { - MSGM_syslog(LOG_DEBUG, "CtdlSaveMsgPointerInRoom() doing repl checks\n"); + if ( (DoesThisRoomNeedEuidIndexing(&CC->room)) && (do_repl_check) ) { + syslog(LOG_DEBUG, "msgbase: CtdlSaveMsgPointerInRoom() doing repl checks"); for (i=0; icm_fields[eExclusiveID], &CCC->room, msgid); + index_message_by_euid(msg->cm_fields[eExclusiveID], &CC->room, msgid); } /* Free up the memory we may have allocated */ @@ -2446,14 +2410,17 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms } else { - MSGM_syslog(LOG_DEBUG, "CtdlSaveMsgPointerInRoom() skips repl checks\n"); + syslog(LOG_DEBUG, "msgbase: CtdlSaveMsgPointerInRoom() skips repl checks"); } /* Submit this room for processing by hooks */ - PerformRoomHooks(&CCC->room); + int total_roomhook_errors = PerformRoomHooks(&CC->room); + if (total_roomhook_errors) { + syslog(LOG_WARNING, "msgbase: room hooks returned %d errors", total_roomhook_errors); + } /* Go back to the room we were in before we wandered here... */ - CtdlGetRoom(&CCC->room, hold_rm); + CtdlGetRoom(&CC->room, hold_rm); /* Bump the reference count for all messages which were merged */ if (!suppress_refcount_adj) { @@ -2481,8 +2448,6 @@ int CtdlSaveMsgPointerInRoom(char *roomname, long msgid, } - - /* * Message base operation to save a new message to the message store * (returns new message number) @@ -2491,75 +2456,98 @@ int CtdlSaveMsgPointerInRoom(char *roomname, long msgid, * called by server-side modules. * */ -long send_message(struct CtdlMessage *msg) { - struct CitContext *CCC = CC; - long newmsgid; +long CtdlSaveThisMessage(struct CtdlMessage *msg, long msgid, int Reply) { long retval; - char msgidbuf[256]; - long msgidbuflen; struct ser_ret smr; int is_bigmsg = 0; char *holdM = NULL; long holdMLen = 0; - /* Get a new message number */ - newmsgid = get_new_message_number(); - msgidbuflen = snprintf(msgidbuf, sizeof msgidbuf, "%08lX-%08lX@%s", - (long unsigned int) time(NULL), - (long unsigned int) newmsgid, - config.c_fqdn - ); - - /* Generate an ID if we don't have one already */ - if (CM_IsEmpty(msg, emessageId)) { - CM_SetField(msg, emessageId, msgidbuf, msgidbuflen); - } - - /* If the message is big, set its body aside for storage elsewhere */ - if (!CM_IsEmpty(msg, eMesageText)) { - if (msg->cm_lengths[eMesageText] > BIGMSG) { - is_bigmsg = 1; - holdM = msg->cm_fields[eMesageText]; - msg->cm_fields[eMesageText] = NULL; - holdMLen = msg->cm_lengths[eMesageText]; - msg->cm_lengths[eMesageText] = 0; - } + /* + * If the message is big, set its body aside for storage elsewhere + * and we hide the message body from the serializer + */ + if (!CM_IsEmpty(msg, eMesageText) && msg->cm_lengths[eMesageText] > BIGMSG) { + is_bigmsg = 1; + holdM = msg->cm_fields[eMesageText]; + msg->cm_fields[eMesageText] = NULL; + holdMLen = msg->cm_lengths[eMesageText]; + msg->cm_lengths[eMesageText] = 0; } /* Serialize our data structure for storage in the database */ CtdlSerializeMessage(&smr, msg); if (is_bigmsg) { + /* put the message body back into the message */ msg->cm_fields[eMesageText] = holdM; msg->cm_lengths[eMesageText] = holdMLen; } if (smr.len == 0) { - cprintf("%d Unable to serialize message\n", - ERROR + INTERNAL_ERROR); + if (Reply) { + cprintf("%d Unable to serialize message\n", + ERROR + INTERNAL_ERROR); + } + else { + syslog(LOG_ERR, "msgbase: CtdlSaveMessage() unable to serialize message"); + + } return (-1L); } /* Write our little bundle of joy into the message base */ - if (cdb_store(CDB_MSGMAIN, &newmsgid, (int)sizeof(long), - smr.ser, smr.len) < 0) { - MSGM_syslog(LOG_ERR, "Can't store message\n"); - retval = 0L; - } else { + retval = cdb_store(CDB_MSGMAIN, &msgid, (int)sizeof(long), smr.ser, smr.len); + if (retval < 0) { + syslog(LOG_ERR, "msgbase: can't store message %ld: %ld", msgid, retval); + } + else { if (is_bigmsg) { - cdb_store(CDB_BIGMSGS, - &newmsgid, - (int)sizeof(long), - holdM, - (holdMLen + 1) + retval = cdb_store(CDB_BIGMSGS, + &msgid, + (int)sizeof(long), + holdM, + (holdMLen + 1) ); + if (retval < 0) { + syslog(LOG_ERR, "msgbase: failed to store message body for msgid %ld: %ld", msgid, retval); + } } - retval = newmsgid; } /* Free the memory we used for the serialized message */ free(smr.ser); + return(retval); +} + + +long send_message(struct CtdlMessage *msg) { + long newmsgid; + long retval; + char msgidbuf[256]; + long msgidbuflen; + + /* Get a new message number */ + newmsgid = get_new_message_number(); + + /* Generate an ID if we don't have one already */ + if (CM_IsEmpty(msg, emessageId)) { + msgidbuflen = snprintf(msgidbuf, sizeof msgidbuf, "%08lX-%08lX@%s", + (long unsigned int) time(NULL), + (long unsigned int) newmsgid, + CtdlGetConfigStr("c_fqdn") + ); + + CM_SetField(msg, emessageId, msgidbuf, msgidbuflen); + } + + retval = CtdlSaveThisMessage(msg, newmsgid, 1); + + if (retval == 0) { + retval = newmsgid; + } + /* Return the *local* message ID to the caller * (even if we're storing an incoming network message) */ @@ -2567,18 +2555,16 @@ long send_message(struct CtdlMessage *msg) { } - /* - * Serialize a struct CtdlMessage into the format used on disk and network. + * Serialize a struct CtdlMessage into the format used on disk. * * This function loads up a "struct ser_ret" (defined in server.h) which * contains the length of the serialized message and a pointer to the * serialized message in memory. THE LATTER MUST BE FREED BY THE CALLER. */ void CtdlSerializeMessage(struct ser_ret *ret, /* return values */ - struct CtdlMessage *msg) /* unserialized msg */ + struct CtdlMessage *msg) /* unserialized msg */ { - struct CitContext *CCC = CC; size_t wlen; int i; @@ -2586,7 +2572,7 @@ void CtdlSerializeMessage(struct ser_ret *ret, /* return values */ * Check for valid message format */ if (CM_IsValidMsg(msg) == 0) { - MSGM_syslog(LOG_ERR, "CtdlSerializeMessage() aborting due to invalid message\n"); + syslog(LOG_ERR, "msgbase: CtdlSerializeMessage() aborting due to invalid message"); ret->len = 0; ret->ser = NULL; return; @@ -2599,8 +2585,7 @@ void CtdlSerializeMessage(struct ser_ret *ret, /* return values */ ret->ser = malloc(ret->len); if (ret->ser == NULL) { - MSG_syslog(LOG_ERR, "CtdlSerializeMessage() malloc(%ld) failed: %s\n", - (long)ret->len, strerror(errno)); + syslog(LOG_ERR, "msgbase: CtdlSerializeMessage() malloc(%ld) failed: %m", (long)ret->len); ret->len = 0; ret->ser = NULL; return; @@ -2611,9 +2596,8 @@ void CtdlSerializeMessage(struct ser_ret *ret, /* return values */ ret->ser[2] = msg->cm_format_type; wlen = 3; - for (i=0; i < NDiskFields; ++i) - if (msg->cm_fields[FieldOrder[i]] != NULL) - { + for (i=0; i < NDiskFields; ++i) { + if (msg->cm_fields[FieldOrder[i]] != NULL) { ret->ser[wlen++] = (char)FieldOrder[i]; memcpy(&ret->ser[wlen], @@ -2622,10 +2606,10 @@ void CtdlSerializeMessage(struct ser_ret *ret, /* return values */ wlen = wlen + msg->cm_lengths[FieldOrder[i]] + 1; } + } if (ret->len != wlen) { - MSG_syslog(LOG_ERR, "ERROR: len=%ld wlen=%ld\n", - (long)ret->len, (long)wlen); + syslog(LOG_ERR, "msgbase: ERROR; len=%ld wlen=%ld", (long)ret->len, (long)wlen); } return; @@ -2637,39 +2621,34 @@ void CtdlSerializeMessage(struct ser_ret *ret, /* return values */ * carry the same Exclusive ID as this one. If any are found, delete them. */ void ReplicationChecks(struct CtdlMessage *msg) { - struct CitContext *CCC = CC; long old_msgnum = (-1L); - if (DoesThisRoomNeedEuidIndexing(&CCC->room) == 0) return; + if (DoesThisRoomNeedEuidIndexing(&CC->room) == 0) return; - MSG_syslog(LOG_DEBUG, "Performing replication checks in <%s>\n", - CCC->room.QRname); + syslog(LOG_DEBUG, "msgbase: performing replication checks in <%s>", CC->room.QRname); /* No exclusive id? Don't do anything. */ if (msg == NULL) return; if (CM_IsEmpty(msg, eExclusiveID)) return; - /*MSG_syslog(LOG_DEBUG, "Exclusive ID: <%s> for room <%s>\n", - msg->cm_fields[eExclusiveID], CCC->room.QRname);*/ + /*syslog(LOG_DEBUG, "msgbase: exclusive ID: <%s> for room <%s>", + msg->cm_fields[eExclusiveID], CC->room.QRname);*/ - old_msgnum = CtdlLocateMessageByEuid(msg->cm_fields[eExclusiveID], &CCC->room); + old_msgnum = CtdlLocateMessageByEuid(msg->cm_fields[eExclusiveID], &CC->room); if (old_msgnum > 0L) { - MSG_syslog(LOG_DEBUG, "ReplicationChecks() replacing message %ld\n", old_msgnum); - CtdlDeleteMessages(CCC->room.QRname, &old_msgnum, 1, ""); + syslog(LOG_DEBUG, "msgbase: ReplicationChecks() replacing message %ld", old_msgnum); + CtdlDeleteMessages(CC->room.QRname, &old_msgnum, 1, ""); } } - /* * Save a message to disk and submit it into the delivery system. */ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ - recptypes *recps, /* recipients (if mail) */ - const char *force, /* force a particular room? */ - int flags /* should the message be exported clean? */ - ) -{ + struct recptypes *recps, /* recipients (if mail) */ + const char *force /* force a particular room? */ +) { char hold_rm[ROOMNAMELEN]; char actual_rm[ROOMNAMELEN]; char force_room[ROOMNAMELEN]; @@ -2686,9 +2665,8 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ struct addresses_to_be_filed *aptr = NULL; StrBuf *saved_rfc822_version = NULL; int qualified_for_journaling = 0; - CitContext *CCC = MyContext(); - MSGM_syslog(LOG_DEBUG, "CtdlSubmitMsg() called\n"); + syslog(LOG_DEBUG, "msgbase: CtdlSubmitMsg() called"); if (CM_IsValidMsg(msg) == 0) return(-1); /* self check */ /* If this message has no timestamp, we take the liberty of @@ -2723,7 +2701,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* Learn about what's inside, because it's what's inside that counts */ if (CM_IsEmpty(msg, eMesageText)) { - MSGM_syslog(LOG_ERR, "ERROR: attempt to save message with NULL body\n"); + syslog(LOG_ERR, "msgbase: ERROR; attempt to save message with NULL body"); return(-2); } @@ -2755,20 +2733,20 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } /* Goto the correct room */ - room = (recps) ? CCC->room.QRname : SENTITEMS; - MSG_syslog(LOG_DEBUG, "Selected room %s\n", room); - strcpy(hold_rm, CCC->room.QRname); - strcpy(actual_rm, CCC->room.QRname); + room = (recps) ? CC->room.QRname : SENTITEMS; + syslog(LOG_DEBUG, "msgbase: selected room %s", room); + strcpy(hold_rm, CC->room.QRname); + strcpy(actual_rm, CC->room.QRname); if (recps != NULL) { strcpy(actual_rm, SENTITEMS); } /* If the user is a twit, move to the twit room for posting */ if (TWITDETECT) { - if (CCC->user.axlevel == AxProbU) { + if (CC->user.axlevel == AxProbU) { strcpy(hold_rm, actual_rm); - strcpy(actual_rm, config.c_twitroom); - MSGM_syslog(LOG_DEBUG, "Diverting to twit room\n"); + strcpy(actual_rm, CtdlGetConfigStr("c_twitroom")); + syslog(LOG_DEBUG, "msgbase: diverting to twit room"); } } @@ -2777,33 +2755,33 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ strcpy(actual_rm, force_room); } - MSG_syslog(LOG_INFO, "Final selection: %s (%s)\n", actual_rm, room); - if (strcasecmp(actual_rm, CCC->room.QRname)) { - /* CtdlGetRoom(&CCC->room, actual_rm); */ + syslog(LOG_DEBUG, "msgbase: final selection: %s (%s)", actual_rm, room); + if (strcasecmp(actual_rm, CC->room.QRname)) { + /* CtdlGetRoom(&CC->room, actual_rm); */ CtdlUserGoto(actual_rm, 0, 1, NULL, NULL, NULL, NULL); } /* * If this message has no O (room) field, generate one. */ - if (CM_IsEmpty(msg, eOriginalRoom)) { - CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname)); + if (CM_IsEmpty(msg, eOriginalRoom) && !IsEmptyStr(CC->room.QRname)) { + CM_SetField(msg, eOriginalRoom, CC->room.QRname, -1); } /* Perform "before save" hooks (aborting if any return nonzero) */ - MSGM_syslog(LOG_DEBUG, "Performing before-save hooks\n"); + syslog(LOG_DEBUG, "msgbase: performing before-save hooks"); if (PerformMessageHooks(msg, recps, EVT_BEFORESAVE) > 0) return(-3); /* * If this message has an Exclusive ID, and the room is replication * checking enabled, then do replication checks. */ - if (DoesThisRoomNeedEuidIndexing(&CCC->room)) { + if (DoesThisRoomNeedEuidIndexing(&CC->room)) { ReplicationChecks(msg); } /* Save it to disk */ - MSGM_syslog(LOG_DEBUG, "Saving to disk\n"); + syslog(LOG_DEBUG, "msgbase: saving to disk"); newmsgid = send_message(msg); if (newmsgid <= 0L) return(-5); @@ -2811,12 +2789,11 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * be a critical section because nobody else knows about this message * yet. */ - MSGM_syslog(LOG_DEBUG, "Creating MetaData record\n"); + syslog(LOG_DEBUG, "msgbase: creating metadata record"); memset(&smi, 0, sizeof(struct MetaData)); smi.meta_msgnum = newmsgid; smi.meta_refcount = 0; - safestrncpy(smi.meta_content_type, content_type, - sizeof smi.meta_content_type); + safestrncpy(smi.meta_content_type, content_type, sizeof smi.meta_content_type); /* * Measure how big this message will be when rendered as RFC822. @@ -2828,29 +2805,29 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * 2. If journaling is enabled, we will need an RFC822 version of the * message to attach to the journalized copy. */ - if (CCC->redirect_buffer != NULL) { - MSGM_syslog(LOG_ALERT, "CCC->redirect_buffer is not NULL during message submission!\n"); + if (CC->redirect_buffer != NULL) { + syslog(LOG_ALERT, "msgbase: CC->redirect_buffer is not NULL during message submission!"); abort(); } - CCC->redirect_buffer = NewStrBufPlain(NULL, SIZ); + CC->redirect_buffer = NewStrBufPlain(NULL, SIZ); CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1, QP_EADDR); - smi.meta_rfc822_length = StrLength(CCC->redirect_buffer); - saved_rfc822_version = CCC->redirect_buffer; - CCC->redirect_buffer = NULL; + smi.meta_rfc822_length = StrLength(CC->redirect_buffer); + saved_rfc822_version = CC->redirect_buffer; + CC->redirect_buffer = NULL; PutMetaData(&smi); /* Now figure out where to store the pointers */ - MSGM_syslog(LOG_DEBUG, "Storing pointers\n"); + syslog(LOG_DEBUG, "msgbase: storing pointers"); /* If this is being done by the networker delivering a private * message, we want to BYPASS saving the sender's copy (because there * is no local sender; it would otherwise go to the Trashcan). */ - if ((!CCC->internal_pgm) || (recps == NULL)) { + if ((!CC->internal_pgm) || (recps == NULL)) { if (CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 1, msg) != 0) { - MSGM_syslog(LOG_ERR, "ERROR saving message pointer!\n"); - CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg); + syslog(LOG_ERR, "msgbase: ERROR saving message pointer %ld in %s", newmsgid, actual_rm); + CtdlSaveMsgPointerInRoom(CtdlGetConfigStr("c_aideroom"), newmsgid, 0, msg); } } @@ -2860,50 +2837,46 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } /* If other rooms are specified, drop them there too. */ - if ((recps != NULL) && (recps->num_room > 0)) + if ((recps != NULL) && (recps->num_room > 0)) { for (i=0; irecp_room, '|'); ++i) { - extract_token(recipient, recps->recp_room, i, - '|', sizeof recipient); - MSG_syslog(LOG_DEBUG, "Delivering to room <%s>\n", recipient);///// xxxx + extract_token(recipient, recps->recp_room, i, '|', sizeof recipient); + syslog(LOG_DEBUG, "msgbase: delivering to room <%s>", recipient); CtdlSaveMsgPointerInRoom(recipient, newmsgid, 0, msg); } + } /* Bump this user's messages posted counter. */ - MSGM_syslog(LOG_DEBUG, "Updating user\n"); - CtdlGetUserLock(&CCC->user, CCC->curr_user); - CCC->user.posted = CCC->user.posted + 1; - CtdlPutUserLock(&CCC->user); + syslog(LOG_DEBUG, "msgbase: updating user"); + CtdlLockGetCurrentUser(); + CC->user.posted = CC->user.posted + 1; + CtdlPutCurrentUserLock(); /* Decide where bounces need to be delivered */ - if ((recps != NULL) && (recps->bounce_to == NULL)) - { - if (CCC->logged_in) - snprintf(bounce_to, sizeof bounce_to, "%s@%s", - CCC->user.fullname, config.c_nodename); - else - snprintf(bounce_to, sizeof bounce_to, "%s@%s", - msg->cm_fields[eAuthor], msg->cm_fields[eNodeName]); + if ((recps != NULL) && (recps->bounce_to == NULL)) { + if (CC->logged_in) { + strcpy(bounce_to, CC->user.fullname); + } + else if (!IsEmptyStr(msg->cm_fields[eAuthor])){ + strcpy(bounce_to, msg->cm_fields[eAuthor]); + } recps->bounce_to = bounce_to; } CM_SetFieldLONG(msg, eVltMsgNum, newmsgid); - /* If this is private, local mail, make a copy in the * recipient's mailbox and bump the reference count. */ - if ((recps != NULL) && (recps->num_local > 0)) - { + if ((recps != NULL) && (recps->num_local > 0)) { char *pch; int ntokens; pch = recps->recp_local; recps->recp_local = recipient; ntokens = num_tokens(pch, '|'); - for (i=0; i\n", recipient); + syslog(LOG_DEBUG, "msgbase: delivering private local mail to <%s>", recipient); if (CtdlGetUser(&userbuf, recipient) == 0) { CtdlMailboxName(actual_rm, sizeof actual_rm, &userbuf, MAILROOM); CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 0, msg); @@ -2911,36 +2884,35 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ PerformMessageHooks(msg, recps, EVT_AFTERUSRMBOXSAVE); } else { - MSG_syslog(LOG_DEBUG, "No user <%s>\n", recipient); - CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg); + syslog(LOG_DEBUG, "msgbase: no user <%s>", recipient); + CtdlSaveMsgPointerInRoom(CtdlGetConfigStr("c_aideroom"), newmsgid, 0, msg); } } recps->recp_local = pch; } /* Perform "after save" hooks */ - MSGM_syslog(LOG_DEBUG, "Performing after-save hooks\n"); + syslog(LOG_DEBUG, "msgbase: performing after-save hooks"); PerformMessageHooks(msg, recps, EVT_AFTERSAVE); CM_FlushField(msg, eVltMsgNum); /* Go back to the room we started from */ - MSG_syslog(LOG_DEBUG, "Returning to original room %s\n", hold_rm); - if (strcasecmp(hold_rm, CCC->room.QRname)) + syslog(LOG_DEBUG, "msgbase: returning to original room %s", hold_rm); + if (strcasecmp(hold_rm, CC->room.QRname)) { CtdlUserGoto(hold_rm, 0, 1, NULL, NULL, NULL, NULL); + } /* * Any addresses to harvest for someone's address book? */ - if ( (CCC->logged_in) && (recps != NULL) ) { + if ( (CC->logged_in) && (recps != NULL) ) { collected_addresses = harvest_collected_addresses(msg); } if (collected_addresses != NULL) { - aptr = (struct addresses_to_be_filed *) - malloc(sizeof(struct addresses_to_be_filed)); - CtdlMailboxName(actual_rm, sizeof actual_rm, - &CCC->user, USERCONTACTSROOM); + aptr = (struct addresses_to_be_filed *) malloc(sizeof(struct addresses_to_be_filed)); + CtdlMailboxName(actual_rm, sizeof actual_rm, &CC->user, USERCONTACTSROOM); aptr->roomname = strdup(actual_rm); aptr->collected_addresses = collected_addresses; begin_critical_section(S_ATBF); @@ -2957,13 +2929,13 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } else { if (recps == NULL) { - qualified_for_journaling = config.c_journal_pubmsgs; + qualified_for_journaling = CtdlGetConfigInt("c_journal_pubmsgs"); } else if (recps->num_local + recps->num_ignet + recps->num_internet > 0) { - qualified_for_journaling = config.c_journal_email; + qualified_for_journaling = CtdlGetConfigInt("c_journal_email"); } else { - qualified_for_journaling = config.c_journal_pubmsgs; + qualified_for_journaling = CtdlGetConfigInt("c_journal_pubmsgs"); } } @@ -2992,7 +2964,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* * Convenience function for generating small administrative messages. */ -void quickie_message(const char *from, +long quickie_message(const char *from, const char *fromaddr, const char *to, char *room, @@ -3001,7 +2973,7 @@ void quickie_message(const char *from, const char *subject) { struct CtdlMessage *msg; - recptypes *recp = NULL; + struct recptypes *recp = NULL; msg = malloc(sizeof(struct CtdlMessage)); memset(msg, 0, sizeof(struct CtdlMessage)); @@ -3009,12 +2981,12 @@ void quickie_message(const char *from, msg->cm_anon_type = MES_NORMAL; msg->cm_format_type = format_type; - if (from != NULL) { - CM_SetField(msg, eAuthor, from, strlen(from)); + if (!IsEmptyStr(from)) { + CM_SetField(msg, eAuthor, from, -1); } - else if (fromaddr != NULL) { + else if (!IsEmptyStr(fromaddr)) { char *pAt; - CM_SetField(msg, eAuthor, fromaddr, strlen(fromaddr)); + CM_SetField(msg, eAuthor, fromaddr, -1); pAt = strchr(msg->cm_fields[eAuthor], '@'); if (pAt != NULL) { CM_CutFieldAt(msg, eAuthor, pAt - msg->cm_fields[eAuthor]); @@ -3024,92 +2996,23 @@ void quickie_message(const char *from, msg->cm_fields[eAuthor] = strdup("Citadel"); } - if (fromaddr != NULL) CM_SetField(msg, erFc822Addr, fromaddr, strlen(fromaddr)); - if (room != NULL) CM_SetField(msg, eOriginalRoom, room, strlen(room)); - CM_SetField(msg, eNodeName, CFG_KEY(c_nodename)); - if (to != NULL) { - CM_SetField(msg, eRecipient, to, strlen(to)); + if (!IsEmptyStr(fromaddr)) CM_SetField(msg, erFc822Addr, fromaddr, -1); + if (!IsEmptyStr(room)) CM_SetField(msg, eOriginalRoom, room, -1); + if (!IsEmptyStr(to)) { + CM_SetField(msg, eRecipient, to, -1); recp = validate_recipients(to, NULL, 0); } - if (subject != NULL) { - CM_SetField(msg, eMsgSubject, subject, strlen(subject)); + if (!IsEmptyStr(subject)) { + CM_SetField(msg, eMsgSubject, subject, -1); + } + if (!IsEmptyStr(text)) { + CM_SetField(msg, eMesageText, text, -1); } - CM_SetField(msg, eMesageText, text, strlen(text)); - CtdlSubmitMsg(msg, recp, room, 0); + long msgnum = CtdlSubmitMsg(msg, recp, room); CM_Free(msg); if (recp != NULL) free_recipients(recp); -} - -void flood_protect_quickie_message(const char *from, - const char *fromaddr, - const char *to, - char *room, - const char *text, - int format_type, - const char *subject, - int nCriterions, - const char **CritStr, - long *CritStrLen, - long ccid, - long ioid, - time_t NOW) -{ - int i; - u_char rawdigest[MD5_DIGEST_LEN]; - struct MD5Context md5context; - StrBuf *guid; - char timestamp[64]; - long tslen; - static const time_t tsday = (8*60*60); /* just care for a day... */ - time_t seenstamp; - - tslen = snprintf(timestamp, sizeof(timestamp), "%ld", tsday); - MD5Init(&md5context); - - for (i = 0; i < nCriterions; i++) - MD5Update(&md5context, - (const unsigned char*)CritStr[i], CritStrLen[i]); - MD5Update(&md5context, - (const unsigned char*)timestamp, tslen); - MD5Final(rawdigest, &md5context); - - guid = NewStrBufPlain(NULL, - MD5_DIGEST_LEN * 2 + 12); - StrBufHexEscAppend(guid, NULL, rawdigest, MD5_DIGEST_LEN); - StrBufAppendBufPlain(guid, HKEY("_fldpt"), 0); - if (StrLength(guid) > 40) - StrBufCutAt(guid, 40, NULL); - - seenstamp = CheckIfAlreadySeen("FPAideMessage", - guid, - NOW, - tsday, - eUpdate, - ccid, - ioid); - if (seenstamp < tsday) - { - FreeStrBuf(&guid); - /* yes, we did. flood protection kicks in. */ - syslog(LOG_DEBUG, - "not sending message again - %ld < %ld \n", seenstamp, tsday); - return; - } - else - { - syslog(LOG_DEBUG, - "sending message. %ld >= %ld", seenstamp, tsday); - FreeStrBuf(&guid); - /* no, this message isn't sent recently; go ahead. */ - quickie_message(from, - fromaddr, - to, - room, - text, - format_type, - subject); - } + return msgnum; } @@ -3121,10 +3024,8 @@ StrBuf *CtdlReadMessageBodyBuf(char *terminator, /* token signalling EOT */ size_t maxlen, /* maximum message length */ StrBuf *exist, /* if non-null, append to it; exist is ALWAYS freed */ - int crlf, /* CRLF newlines instead of LF */ - int *sock /* socket handle or 0 for this session's client socket */ - ) -{ + int crlf /* CRLF newlines instead of LF */ +) { StrBuf *Message; StrBuf *LineBuf; int flushing = 0; @@ -3146,18 +3047,12 @@ StrBuf *CtdlReadMessageBodyBuf(char *terminator, /* token signalling EOT */ /* read in the lines of message text one by one */ do { - if (sock != NULL) { - if ((CtdlSockGetLine(sock, LineBuf, 5) < 0) || - (*sock == -1)) - finished = 1; - } - else { - if (CtdlClientGetLine(LineBuf) < 0) finished = 1; + if (CtdlClientGetLine(LineBuf) < 0) { + finished = 1; } - if ((StrLength(LineBuf) == tlen) && - (!strcmp(ChrPtr(LineBuf), terminator))) + if ((StrLength(LineBuf) == tlen) && (!strcmp(ChrPtr(LineBuf), terminator))) { finished = 1; - + } if ( (!flushing) && (!finished) ) { if (crlf) { StrBufAppendBufPlain(LineBuf, HKEY("\r\n"), 0); @@ -3167,13 +3062,9 @@ StrBuf *CtdlReadMessageBodyBuf(char *terminator, /* token signalling EOT */ } /* Unescape SMTP-style input of two dots at the beginning of the line */ - if ((dotdot) && - (StrLength(LineBuf) == 2) && - (!strcmp(ChrPtr(LineBuf), ".."))) - { + if ((dotdot) && (StrLength(LineBuf) > 1) && (ChrPtr(LineBuf)[0] == '.')) { StrBufCutLeft(LineBuf, 1); } - StrBufAppendBuf(Message, LineBuf, 0); } @@ -3185,169 +3076,6 @@ StrBuf *CtdlReadMessageBodyBuf(char *terminator, /* token signalling EOT */ return Message; } -void DeleteAsyncMsg(ReadAsyncMsg **Msg) -{ - if (*Msg == NULL) - return; - FreeStrBuf(&(*Msg)->MsgBuf); - - free(*Msg); - *Msg = NULL; -} - -ReadAsyncMsg *NewAsyncMsg(const char *terminator, /* token signalling EOT */ - long tlen, - size_t maxlen, /* maximum message length */ - size_t expectlen, /* if we expect a message, how long should it be? */ - StrBuf *exist, /* if non-null, append to it; - exist is ALWAYS freed */ - long eLen, /* length of exist */ - int crlf /* CRLF newlines instead of LF */ - ) -{ - ReadAsyncMsg *NewMsg; - - NewMsg = (ReadAsyncMsg *)malloc(sizeof(ReadAsyncMsg)); - memset(NewMsg, 0, sizeof(ReadAsyncMsg)); - - if (exist == NULL) { - long len; - - if (expectlen == 0) { - len = 4 * SIZ; - } - else { - len = expectlen + 10; - } - NewMsg->MsgBuf = NewStrBufPlain(NULL, len); - } - else { - NewMsg->MsgBuf = NewStrBufDup(exist); - } - /* Do we need to change leading ".." to "." for SMTP escaping? */ - if ((tlen == 1) && (*terminator == '.')) { - NewMsg->dodot = 1; - } - - NewMsg->terminator = terminator; - NewMsg->tlen = tlen; - - NewMsg->maxlen = maxlen; - - NewMsg->crlf = crlf; - - return NewMsg; -} - -/* - * Back end function used by CtdlMakeMessage() and similar functions - */ -eReadState CtdlReadMessageBodyAsync(AsyncIO *IO) -{ - ReadAsyncMsg *ReadMsg; - int MsgFinished = 0; - eReadState Finished = eMustReadMore; - -#ifdef BIGBAD_IODBG - char fn [SIZ]; - FILE *fd; - const char *pch = ChrPtr(IO->SendBuf.Buf); - const char *pchh = IO->SendBuf.ReadWritePointer; - long nbytes; - - if (pchh == NULL) - pchh = pch; - - nbytes = StrLength(IO->SendBuf.Buf) - (pchh - pch); - snprintf(fn, SIZ, "/tmp/foolog_ev_%s.%d", - ((CitContext*)(IO->CitContext))->ServiceName, - IO->SendBuf.fd); - - fd = fopen(fn, "a+"); -#endif - - ReadMsg = IO->ReadMsg; - - /* read in the lines of message text one by one */ - do { - Finished = StrBufChunkSipLine(IO->IOBuf, &IO->RecvBuf); - - switch (Finished) { - case eMustReadMore: /// read new from socket... -#ifdef BIGBAD_IODBG - if (IO->RecvBuf.ReadWritePointer != NULL) { - nbytes = StrLength(IO->RecvBuf.Buf) - (IO->RecvBuf.ReadWritePointer - ChrPtr(IO->RecvBuf.Buf)); - fprintf(fd, "Read; Line unfinished: %ld Bytes still in buffer [", nbytes); - - fwrite(IO->RecvBuf.ReadWritePointer, nbytes, 1, fd); - - fprintf(fd, "]\n"); - } else { - fprintf(fd, "BufferEmpty! \n"); - } - fclose(fd); -#endif - return Finished; - break; - case eBufferNotEmpty: /* shouldn't happen... */ - case eReadSuccess: /// done for now... - break; - case eReadFail: /// WHUT? - ///todo: shut down! - break; - } - - - if ((StrLength(IO->IOBuf) == ReadMsg->tlen) && - (!strcmp(ChrPtr(IO->IOBuf), ReadMsg->terminator))) { - MsgFinished = 1; -#ifdef BIGBAD_IODBG - fprintf(fd, "found Terminator; Message Size: %d\n", StrLength(ReadMsg->MsgBuf)); -#endif - } - else if (!ReadMsg->flushing) { - -#ifdef BIGBAD_IODBG - fprintf(fd, "Read Line: [%d][%s]\n", StrLength(IO->IOBuf), ChrPtr(IO->IOBuf)); -#endif - - /* Unescape SMTP-style input of two dots at the beginning of the line */ - if ((ReadMsg->dodot) && - (StrLength(IO->IOBuf) == 2) && /* TODO: do we just unescape lines with two dots or any line? */ - (!strcmp(ChrPtr(IO->IOBuf), ".."))) - { -#ifdef BIGBAD_IODBG - fprintf(fd, "UnEscaped!\n"); -#endif - StrBufCutLeft(IO->IOBuf, 1); - } - - if (ReadMsg->crlf) { - StrBufAppendBufPlain(IO->IOBuf, HKEY("\r\n"), 0); - } - else { - StrBufAppendBufPlain(IO->IOBuf, HKEY("\n"), 0); - } - - StrBufAppendBuf(ReadMsg->MsgBuf, IO->IOBuf, 0); - } - - /* if we've hit the max msg length, flush the rest */ - if (StrLength(ReadMsg->MsgBuf) >= ReadMsg->maxlen) ReadMsg->flushing = 1; - - } while (!MsgFinished); - -#ifdef BIGBAD_IODBG - fprintf(fd, "Done with reading; %s.\n, ", - (MsgFinished)?"Message Finished": "FAILED"); - fclose(fd); -#endif - if (MsgFinished) - return eReadSuccess; - else - return eAbort; -} - /* * Back end function used by CtdlMakeMessage() and similar functions @@ -3357,8 +3085,7 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ size_t maxlen, /* maximum message length */ StrBuf *exist, /* if non-null, append to it; exist is ALWAYS freed */ - int crlf, /* CRLF newlines instead of LF */ - int *sock /* socket handle or 0 for this session's client socket */ + int crlf /* CRLF newlines instead of LF */ ) { StrBuf *Message; @@ -3367,14 +3094,15 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ tlen, maxlen, exist, - crlf, - sock); + crlf + ); if (Message == NULL) return NULL; else return SmashStrBuf(&Message); } + struct CtdlMessage *CtdlMakeMessage( struct ctdluser *author, /* author's user structure */ char *recipient, /* NULL if it's not mail */ @@ -3388,8 +3116,7 @@ struct CtdlMessage *CtdlMakeMessage( char *supplied_euid, /* ...or NULL if this is irrelevant */ char *preformatted_text, /* ...or NULL to read text from client */ char *references /* Thread references */ -) -{ +) { return CtdlMakeMessageLen( author, /* author's user structure */ recipient, /* NULL if it's not mail */ @@ -3415,6 +3142,7 @@ struct CtdlMessage *CtdlMakeMessage( } + /* * Build a binary message to be saved on disk. * (NOTE: if you supply 'preformatted_text', the buffer you give it @@ -3422,7 +3150,6 @@ struct CtdlMessage *CtdlMakeMessage( * responsible for managing that memory -- it will be freed along with * the rest of the fields when CM_Free() is called.) */ - struct CtdlMessage *CtdlMakeMessageLen( struct ctdluser *author, /* author's user structure */ char *recipient, /* NULL if it's not mail */ @@ -3445,11 +3172,7 @@ struct CtdlMessage *CtdlMakeMessageLen( long textlen, char *references, /* Thread references */ long reflen - ) -{ - struct CitContext *CCC = CC; - /* Don't confuse the poor folks if it's not routed mail. * / - char dest_node[256] = "";*/ +) { long blen; char buf[1024]; struct CtdlMessage *msg; @@ -3469,8 +3192,8 @@ struct CtdlMessage *CtdlMakeMessageLen( if (myelen > 0) { CM_SetField(msg, eMessagePath, my_email, myelen); } - else { - CM_SetField(msg, eMessagePath, author->fullname, strlen(author->fullname)); + else if (!IsEmptyStr(author->fullname)) { + CM_SetField(msg, eMessagePath, author->fullname, -1); } convert_spaces_to_underscores(msg->cm_fields[eMessagePath]); @@ -3487,16 +3210,15 @@ struct CtdlMessage *CtdlMakeMessageLen( CM_SetAsFieldSB(msg, eAuthor, &FakeEncAuthor); FreeStrBuf(&FakeAuthor); - if (CCC->room.QRflags & QR_MAILBOX) { /* room */ - CM_SetField(msg, eOriginalRoom, &CCC->room.QRname[11], strlen(&CCC->room.QRname[11])); - } - else { - CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname)); + if (!!IsEmptyStr(CC->room.QRname)) { + if (CC->room.QRflags & QR_MAILBOX) { /* room */ + CM_SetField(msg, eOriginalRoom, &CC->room.QRname[11], -1); + } + else { + CM_SetField(msg, eOriginalRoom, CC->room.QRname, -1); + } } - CM_SetField(msg, eNodeName, CFG_KEY(c_nodename)); - CM_SetField(msg, eHumanNode, CFG_KEY(c_humannode)); - if (rcplen > 0) { CM_SetField(msg, eRecipient, recipient, rcplen); } @@ -3507,8 +3229,8 @@ struct CtdlMessage *CtdlMakeMessageLen( if (myelen > 0) { CM_SetField(msg, erFc822Addr, my_email, myelen); } - else if ( (author == &CCC->user) && (!IsEmptyStr(CCC->cs_inet_email)) ) { - CM_SetField(msg, erFc822Addr, CCC->cs_inet_email, strlen(CCC->cs_inet_email)); + else if ( (author == &CC->user) && (!IsEmptyStr(CC->cs_inet_email)) ) { + CM_SetField(msg, erFc822Addr, CC->cs_inet_email, -1); } if (subject != NULL) { @@ -3547,7 +3269,7 @@ struct CtdlMessage *CtdlMakeMessageLen( } else { StrBuf *MsgBody; - MsgBody = CtdlReadMessageBodyBuf(HKEY("000"), config.c_maxmsglen, NULL, 0, 0); + MsgBody = CtdlReadMessageBodyBuf(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0); if (MsgBody != NULL) { CM_SetAsFieldSB(msg, eMesageText, &MsgBody); } @@ -3557,19 +3279,15 @@ struct CtdlMessage *CtdlMakeMessageLen( } - - /* * API function to delete messages which match a set of criteria * (returns the actual number of messages deleted) */ -int CtdlDeleteMessages(char *room_name, /* which room */ - long *dmsgnums, /* array of msg numbers to be deleted */ - int num_dmsgnums, /* number of msgs to be deleted, or 0 for "any" */ - char *content_type /* or "" for any. regular expressions expected. */ - ) -{ - struct CitContext *CCC = CC; +int CtdlDeleteMessages(const char *room_name, // which room + long *dmsgnums, // array of msg numbers to be deleted + int num_dmsgnums, // number of msgs to be deleted, or 0 for "any" + char *content_type // or "" for any. regular expressions expected. +) { struct ctdlroom qrbuf; struct cdbdata *cdbfr; long *msglist = NULL; @@ -3587,15 +3305,13 @@ int CtdlDeleteMessages(char *room_name, /* which room */ regcomp(&re, content_type, 0); need_to_free_re = 1; } - MSG_syslog(LOG_DEBUG, " CtdlDeleteMessages(%s, %d msgs, %s)\n", - room_name, num_dmsgnums, content_type); + syslog(LOG_DEBUG, "msgbase: CtdlDeleteMessages(%s, %d msgs, %s)", room_name, num_dmsgnums, content_type); /* get room record, obtaining a lock... */ if (CtdlGetRoomLock(&qrbuf, room_name) != 0) { - MSG_syslog(LOG_ERR, " CtdlDeleteMessages(): Room <%s> not found\n", - room_name); + syslog(LOG_ERR, "msgbase: CtdlDeleteMessages(): Room <%s> not found", room_name); if (need_to_free_re) regfree(&re); - return (0); /* room not found */ + return(0); /* room not found */ } cdbfr = cdb_fetch(CDB_MSGLISTS, &qrbuf.QRnumber, sizeof(long)); @@ -3619,7 +3335,7 @@ int CtdlDeleteMessages(char *room_name, /* which room */ StrBuf *dbg = NewStrBuf(); for (i = 0; i < num_dmsgnums; i++) StrBufAppendPrintf(dbg, ", %ld", dmsgnums[i]); - MSG_syslog(LOG_DEBUG, " Deleting before: %s", ChrPtr(dbg)); + syslog(LOG_DEBUG, "msgbase: Deleting before: %s", ChrPtr(dbg)); FreeStrBuf(&dbg); } */ @@ -3669,7 +3385,7 @@ int CtdlDeleteMessages(char *room_name, /* which room */ StrBuf *dbg = NewStrBuf(); for (i = 0; i < num_deleted; i++) StrBufAppendPrintf(dbg, ", %ld", dellist[i]); - MSG_syslog(LOG_DEBUG, " Deleting: %s", ChrPtr(dbg)); + syslog(LOG_DEBUG, "msgbase: Deleting: %s", ChrPtr(dbg)); FreeStrBuf(&dbg); } */ @@ -3701,20 +3417,17 @@ int CtdlDeleteMessages(char *room_name, /* which room */ /* Now free the memory we used, and go away. */ if (msglist != NULL) free(msglist); if (dellist != NULL) free(dellist); - MSG_syslog(LOG_DEBUG, " %d message(s) deleted.\n", num_deleted); + syslog(LOG_DEBUG, "msgbase: %d message(s) deleted", num_deleted); if (need_to_free_re) regfree(&re); return (num_deleted); } - - /* * GetMetaData() - Get the supplementary record for a message */ void GetMetaData(struct MetaData *smibuf, long msgnum) { - struct cdbdata *cdbsmi; long TheIndex; @@ -3727,11 +3440,12 @@ void GetMetaData(struct MetaData *smibuf, long msgnum) cdbsmi = cdb_fetch(CDB_MSGMAIN, &TheIndex, sizeof(long)); if (cdbsmi == NULL) { - return; /* record not found; go with defaults */ + return; /* record not found; leave it alone */ } memcpy(smibuf, cdbsmi->ptr, ((cdbsmi->len > sizeof(struct MetaData)) ? - sizeof(struct MetaData) : cdbsmi->len)); + sizeof(struct MetaData) : cdbsmi->len) + ); cdb_free(cdbsmi); return; } @@ -3749,184 +3463,29 @@ void PutMetaData(struct MetaData *smibuf) cdb_store(CDB_MSGMAIN, &TheIndex, (int)sizeof(long), - smibuf, (int)sizeof(struct MetaData)); - + smibuf, (int)sizeof(struct MetaData) + ); } + /* - * AdjRefCount - submit an adjustment to the reference count for a message. - * (These are just queued -- we actually process them later.) + * Convenience function to process a big block of AdjRefCount() operations */ -void AdjRefCount(long msgnum, int incr) -{ - struct CitContext *CCC = CC; - struct arcq new_arcq; - int rv = 0; - - MSG_syslog(LOG_DEBUG, "AdjRefCount() msg %ld ref count delta %+d\n", msgnum, incr); - - begin_critical_section(S_SUPPMSGMAIN); - if (arcfp == NULL) { - arcfp = fopen(file_arcq, "ab+"); - chown(file_arcq, CTDLUID, (-1)); - chmod(file_arcq, 0600); - } - end_critical_section(S_SUPPMSGMAIN); - - /* msgnum < 0 means that we're trying to close the file */ - if (msgnum < 0) { - MSGM_syslog(LOG_DEBUG, "Closing the AdjRefCount queue file\n"); - begin_critical_section(S_SUPPMSGMAIN); - if (arcfp != NULL) { - fclose(arcfp); - arcfp = NULL; - } - end_critical_section(S_SUPPMSGMAIN); - return; - } - - /* - * If we can't open the queue, perform the operation synchronously. - */ - if (arcfp == NULL) { - TDAP_AdjRefCount(msgnum, incr); - return; - } - - new_arcq.arcq_msgnum = msgnum; - new_arcq.arcq_delta = incr; - rv = fwrite(&new_arcq, sizeof(struct arcq), 1, arcfp); - if (rv == -1) { - MSG_syslog(LOG_EMERG, "Couldn't write Refcount Queue File %s: %s\n", - file_arcq, - strerror(errno)); - } - fflush(arcfp); - - return; -} - void AdjRefCountList(long *msgnum, long nmsg, int incr) { - struct CitContext *CCC = CC; - long i, the_size, offset; - struct arcq *new_arcq; - int rv = 0; - - MSG_syslog(LOG_DEBUG, "AdjRefCountList() msg %ld ref count delta %+d\n", nmsg, incr); - - begin_critical_section(S_SUPPMSGMAIN); - if (arcfp == NULL) { - arcfp = fopen(file_arcq, "ab+"); - chown(file_arcq, CTDLUID, (-1)); - chmod(file_arcq, 0600); - } - end_critical_section(S_SUPPMSGMAIN); - - /* - * If we can't open the queue, perform the operation synchronously. - */ - if (arcfp == NULL) { - for (i = 0; i < nmsg; i++) - TDAP_AdjRefCount(msgnum[i], incr); - return; - } + long i; - the_size = sizeof(struct arcq) * nmsg; - new_arcq = malloc(the_size); for (i = 0; i < nmsg; i++) { - new_arcq[i].arcq_msgnum = msgnum[i]; - new_arcq[i].arcq_delta = incr; + AdjRefCount(msgnum[i], incr); } - rv = 0; - offset = 0; - while ((rv >= 0) && (offset < the_size)) - { - rv = fwrite(new_arcq + offset, 1, the_size - offset, arcfp); - if (rv == -1) { - MSG_syslog(LOG_EMERG, "Couldn't write Refcount Queue File %s: %s\n", - file_arcq, - strerror(errno)); - } - else { - offset += rv; - } - } - free(new_arcq); - fflush(arcfp); - - return; } /* - * TDAP_ProcessAdjRefCountQueue() - * - * Process the queue of message count adjustments that was created by calls - * to AdjRefCount() ... by reading the queue and calling TDAP_AdjRefCount() - * for each one. This should be an "off hours" operation. + * AdjRefCount - adjust the reference count for a message. We need to delete from disk any message whose reference count reaches zero. */ -int TDAP_ProcessAdjRefCountQueue(void) -{ - struct CitContext *CCC = CC; - char file_arcq_temp[PATH_MAX]; - int r; - FILE *fp; - struct arcq arcq_rec; - int num_records_processed = 0; - - snprintf(file_arcq_temp, sizeof file_arcq_temp, "%s.%04x", file_arcq, rand()); - - begin_critical_section(S_SUPPMSGMAIN); - if (arcfp != NULL) { - fclose(arcfp); - arcfp = NULL; - } - - r = link(file_arcq, file_arcq_temp); - if (r != 0) { - MSG_syslog(LOG_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno)); - end_critical_section(S_SUPPMSGMAIN); - return(num_records_processed); - } - - unlink(file_arcq); - end_critical_section(S_SUPPMSGMAIN); - - fp = fopen(file_arcq_temp, "rb"); - if (fp == NULL) { - MSG_syslog(LOG_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno)); - return(num_records_processed); - } - - while (fread(&arcq_rec, sizeof(struct arcq), 1, fp) == 1) { - TDAP_AdjRefCount(arcq_rec.arcq_msgnum, arcq_rec.arcq_delta); - ++num_records_processed; - } - - fclose(fp); - r = unlink(file_arcq_temp); - if (r != 0) { - MSG_syslog(LOG_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno)); - } - - return(num_records_processed); -} - - - -/* - * TDAP_AdjRefCount - adjust the reference count for a message. - * This one does it "for real" because it's called by - * the autopurger function that processes the queue - * created by AdjRefCount(). If a message's reference - * count becomes zero, we also delete the message from - * disk and de-index it. - */ -void TDAP_AdjRefCount(long msgnum, int incr) +void AdjRefCount(long msgnum, int incr) { - struct CitContext *CCC = CC; - struct MetaData smi; long delnum; @@ -3939,15 +3498,12 @@ void TDAP_AdjRefCount(long msgnum, int incr) smi.meta_refcount += incr; PutMetaData(&smi); end_critical_section(S_SUPPMSGMAIN); - MSG_syslog(LOG_DEBUG, "TDAP_AdjRefCount() msg %ld ref count delta %+d, is now %d\n", - msgnum, incr, smi.meta_refcount - ); + syslog(LOG_DEBUG, "msgbase: AdjRefCount() msg %ld ref count delta %+d, is now %d", msgnum, incr, smi.meta_refcount); - /* If the reference count is now zero, delete the message - * (and its supplementary record as well). + /* If the reference count is now zero, delete both the message and its metadata record. */ if (smi.meta_refcount == 0) { - MSG_syslog(LOG_DEBUG, "Deleting message <%ld>\n", msgnum); + syslog(LOG_DEBUG, "msgbase: deleting message <%ld>", msgnum); /* Call delete hooks with NULL room to show it has gone altogether */ PerformDeleteHooks(NULL, msgnum); @@ -3961,9 +3517,9 @@ void TDAP_AdjRefCount(long msgnum, int incr) delnum = (0L - msgnum); cdb_delete(CDB_MSGMAIN, &delnum, (int)sizeof(long)); } - } + /* * Write a generic object to this room * @@ -3972,15 +3528,13 @@ void TDAP_AdjRefCount(long msgnum, int incr) */ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ char *content_type, /* MIME type of this object */ - char *raw_message, /* Data to be written */ - off_t raw_length, /* Size of raw_message */ + char *raw_message, /* Data to be written */ + off_t raw_length, /* Size of raw_message */ struct ctdluser *is_mailbox, /* Mailbox room? */ int is_binary, /* Is encoding necessary? */ int is_unique, /* Del others of this type? */ - unsigned int flags /* Internal save flags */ - ) -{ - struct CitContext *CCC = CC; + unsigned int flags /* Internal save flags */ +) { struct ctdlroom qrbuf; char roomname[ROOMNAMELEN]; struct CtdlMessage *msg; @@ -3993,7 +3547,7 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ safestrncpy(roomname, req_room, sizeof(roomname)); } - MSG_syslog(LOG_DEBUG, "Raw length is %ld\n", (long)raw_length); + syslog(LOG_DEBUG, "msfbase: raw length is %ld", (long)raw_length); if (is_binary) { encoded_message = NewStrBufPlain(NULL, (size_t) (((raw_length * 134) / 100) + 4096 ) ); @@ -4020,54 +3574,46 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ StrBufAppendBufPlain(encoded_message, raw_message, raw_length, 0); } - MSGM_syslog(LOG_DEBUG, "Allocating\n"); + syslog(LOG_DEBUG, "msgbase: allocating"); msg = malloc(sizeof(struct CtdlMessage)); memset(msg, 0, sizeof(struct CtdlMessage)); msg->cm_magic = CTDLMESSAGE_MAGIC; msg->cm_anon_type = MES_NORMAL; msg->cm_format_type = 4; - CM_SetField(msg, eAuthor, CCC->user.fullname, strlen(CCC->user.fullname)); - CM_SetField(msg, eOriginalRoom, req_room, strlen(req_room)); - CM_SetField(msg, eNodeName, CFG_KEY(c_nodename)); - CM_SetField(msg, eHumanNode, CFG_KEY(c_humannode)); + CM_SetField(msg, eAuthor, CC->user.fullname, -1); + CM_SetField(msg, eOriginalRoom, req_room, -1); msg->cm_flags = flags; CM_SetAsFieldSB(msg, eMesageText, &encoded_message); /* Create the requested room if we have to. */ if (CtdlGetRoom(&qrbuf, roomname) != 0) { - CtdlCreateRoom(roomname, - ( (is_mailbox != NULL) ? 5 : 3 ), - "", 0, 1, 0, VIEW_BBS); + CtdlCreateRoom(roomname, ( (is_mailbox != NULL) ? 5 : 3 ), "", 0, 1, 0, VIEW_BBS); } /* If the caller specified this object as unique, delete all * other objects of this type that are currently in the room. */ if (is_unique) { - MSG_syslog(LOG_DEBUG, "Deleted %d other msgs of this type\n", + syslog(LOG_DEBUG, "msgbase: deleted %d other msgs of this type", CtdlDeleteMessages(roomname, NULL, 0, content_type) ); } /* Now write the data */ - CtdlSubmitMsg(msg, NULL, roomname, 0); + CtdlSubmitMsg(msg, NULL, roomname); CM_Free(msg); } +/************************************************************************/ +/* MODULE INITIALIZATION */ +/************************************************************************/ -/*****************************************************************************/ -/* MODULE INITIALIZATION STUFF */ -/*****************************************************************************/ -void SetMessageDebugEnabled(const int n) -{ - MessageDebugEnabled = n; -} CTDL_MODULE_INIT(msgbase) { if (!threading) { - CtdlRegisterDebugFlagHook(HKEY("messages"), SetMessageDebugEnabled, &MessageDebugEnabled); + FillMsgKeyLookupTable(); } - /* return our Subversion id for the Log */ + /* return our module id for the log */ return "msgbase"; }