X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmsgbase.c;h=405790cb43ded6e5b56871264ae5f2931eec99be;hb=d2ad0f3fb9966e14acc36f9e89f48f581fb4add7;hp=824b51bd337974b232da9bd2644ccaed22db1085;hpb=6e2775961a4c77515aec8718b18f375497678696;p=citadel.git diff --git a/citadel/msgbase.c b/citadel/msgbase.c index 824b51bd3..405790cb4 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -1,21 +1,15 @@ /* * Implements the message store. * - * Copyright (c) 1987-2011 by the citadel.org team + * Copyright (c) 1987-2012 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 as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. + * it under the terms of the GNU General Public License version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "sysdep.h" @@ -44,6 +38,9 @@ #include #include #include + +#include "md5.h" + #include #include "citadel.h" #include "server.h" @@ -73,6 +70,9 @@ 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 @@ -88,32 +88,270 @@ char *msgkeys[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - "from", - NULL, NULL, NULL, - "exti", - "rfca", - NULL, - "hnod", - "msgn", - "jrnl", - NULL, - "list", - "text", - "node", - "room", - "path", - NULL, - "rcpt", - "spec", - "time", - "subj", - NULL, - "wefw", - NULL, - "cccc", - 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 */ }; +eMsgField FieldOrder[] = { +/* Important fields */ + emessageId , + eMessagePath , + eTimestamp , + 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*/ + eReplyTo , + eListID , +/* Q is not used yet */ + eSpecialField, + eenVelopeTo , +/* X is not used yet */ +/* Z is not used yet */ + eCarbonCopY , + eMsgSubject , +/* internal only */ + eErrorMsg , + eSuppressIdx , + eExtnotify , +/* Message text (MUST be last) */ + eMesageText +/* Not saved to disk: + eVltMsgNum +*/ +}; + +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')); +} + +void CM_SetField(struct CtdlMessage *Msg, eMsgField which, const char *buf, long length) +{ + if (Msg->cm_fields[which] != NULL) + free (Msg->cm_fields[which]); + Msg->cm_fields[which] = malloc(length + 1); + memcpy(Msg->cm_fields[which], buf, length); + Msg->cm_fields[which][length] = '\0'; +} + +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) +{ + if (Msg->cm_fields[WhichToCut] == NULL) + return; + + if (strlen(Msg->cm_fields[WhichToCut]) > maxlen) + Msg->cm_fields[WhichToCut][maxlen] = '\0'; +} + +void CM_FlushField(struct CtdlMessage *Msg, eMsgField which) +{ + if (Msg->cm_fields[which] != NULL) + free (Msg->cm_fields[which]); + Msg->cm_fields[which] = NULL; +} + +void CM_CopyField(struct CtdlMessage *Msg, eMsgField WhichToPutTo, eMsgField WhichtToCopy) +{ + long len; + if (Msg->cm_fields[WhichToPutTo] != NULL) + free (Msg->cm_fields[WhichToPutTo]); + + if (Msg->cm_fields[WhichtToCopy] != NULL) + { + len = strlen(Msg->cm_fields[WhichtToCopy]); + Msg->cm_fields[WhichToPutTo] = malloc(len + 1); + memcpy(Msg->cm_fields[WhichToPutTo], Msg->cm_fields[WhichToPutTo], len); + Msg->cm_fields[WhichToPutTo][len] = '\0'; + } + else + Msg->cm_fields[WhichToPutTo] = NULL; +} + + +void CM_PrependToField(struct CtdlMessage *Msg, eMsgField which, const char *buf, long length) +{ + if (Msg->cm_fields[which] != NULL) { + long oldmsgsize; + long newmsgsize; + char *new; + + oldmsgsize = strlen(Msg->cm_fields[which]) + 1; + newmsgsize = length + oldmsgsize; + + new = malloc(newmsgsize); + memcpy(new, buf, length); + memcpy(new + length, Msg->cm_fields[which], oldmsgsize); + free(Msg->cm_fields[which]); + Msg->cm_fields[which] = new; + } + else { + Msg->cm_fields[which] = malloc(length + 1); + memcpy(Msg->cm_fields[which], buf, length); + Msg->cm_fields[which][length] = '\0'; + } +} + +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; +} + +void CM_SetAsFieldSB(struct CtdlMessage *Msg, eMsgField which, StrBuf **buf) +{ + if (Msg->cm_fields[which] != NULL) + free (Msg->cm_fields[which]); + + Msg->cm_fields[which] = SmashStrBuf(buf); +} + +void CM_GetAsField(struct CtdlMessage *Msg, eMsgField which, char **ret, long *retlen) +{ + if (Msg->cm_fields[which] != NULL) + { + *retlen = strlen(Msg->cm_fields[which]); + *ret = Msg->cm_fields[which]; + Msg->cm_fields[which] = NULL; + } + 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) + return 0; + if ((msg->cm_magic) != CTDLMESSAGE_MAGIC) { + struct CitContext *CCC = CC; + MSGM_syslog(LOG_WARNING, "CM_IsValidMsg() -- self-check failed\n"); + return 0; + } + return 1; +} + +void CM_FreeContents(struct CtdlMessage *msg) +{ + int i; + + for (i = 0; i < 256; ++i) + if (msg->cm_fields[i] != NULL) { + free(msg->cm_fields[i]); + } + + msg->cm_magic = 0; /* just in case */ +} +/* + * 'Destructor' for struct CtdlMessage + */ +void CM_Free(struct CtdlMessage *msg) +{ + if (CM_IsValidMsg(msg) == 0) + { + if (msg != NULL) free (msg); + return; + } + CM_FreeContents(msg); + free(msg); +} + +int CM_DupField(eMsgField i, struct CtdlMessage *OrgMsg, struct CtdlMessage *NewMsg) +{ + long len; + len = strlen(OrgMsg->cm_fields[i]); + NewMsg->cm_fields[i] = malloc(len + 1); + if (NewMsg->cm_fields[i] == NULL) + return 0; + memcpy(NewMsg->cm_fields[i], OrgMsg->cm_fields[i], len); + NewMsg->cm_fields[i][len] = '\0'; + return 1; +} + +struct CtdlMessage * CM_Duplicate(struct CtdlMessage *OrgMsg) +{ + int i; + struct CtdlMessage *NewMsg; + + if (CM_IsValidMsg(OrgMsg) == 0) + return NULL; + NewMsg = (struct CtdlMessage *)malloc(sizeof(struct CtdlMessage)); + 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)) + { + CM_Free(NewMsg); + return NULL; + } + } + } + + return NewMsg; +} + + + /* * This function is self explanatory. * (What can I say, I'm in a weird mood today...) @@ -142,6 +380,7 @@ void remove_any_whitespace_to_the_left_or_right_of_at_symbol(char *name) */ int alias(char *name) { /* process alias and routing info for mail */ + struct CitContext *CCC = CC; FILE *fp; int a, i; char aaa[SIZ], bbb[SIZ]; @@ -190,7 +429,7 @@ int alias(char *name) } if (strcasecmp(original_name, name)) { - syslog(LOG_INFO, "%s is being forwarded to %s\n", original_name, name); + MSG_syslog(LOG_INFO, "%s is being forwarded to %s\n", original_name, name); } /* Change "user @ xxx" to "user" if xxx is an alias for this host */ @@ -198,7 +437,7 @@ int alias(char *name) if (name[a] == '@') { if (CtdlHostAlias(&name[a+1]) == hostalias_localhost) { name[a] = 0; - syslog(LOG_INFO, "Changed to <%s>\n", name); + MSG_syslog(LOG_INFO, "Changed to <%s>\n", name); } } } @@ -277,13 +516,13 @@ void headers_listing(long msgnum, void *userdata) cprintf("%ld|%s|%s|%s|%s|%s|\n", msgnum, - (msg->cm_fields['T'] ? msg->cm_fields['T'] : "0"), - (msg->cm_fields['A'] ? msg->cm_fields['A'] : ""), - (msg->cm_fields['N'] ? msg->cm_fields['N'] : ""), - (msg->cm_fields['F'] ? msg->cm_fields['F'] : ""), - (msg->cm_fields['U'] ? msg->cm_fields['U'] : "") + (!CM_IsEmpty(msg, eTimestamp) ? msg->cm_fields[eTimestamp] : "0"), + (!CM_IsEmpty(msg, eAuthor) ? msg->cm_fields[eAuthor] : ""), + (!CM_IsEmpty(msg, eNodeName) ? msg->cm_fields[eNodeName] : ""), + (!CM_IsEmpty(msg, erFc822Addr) ? msg->cm_fields[erFc822Addr] : ""), + (!CM_IsEmpty(msg, eMsgSubject) ? msg->cm_fields[eMsgSubject] : "") ); - CtdlFreeMessage(msg); + CM_Free(msg); } /* @@ -301,9 +540,9 @@ void headers_euid(long msgnum, void *userdata) cprintf("%ld|%s|%s\n", msgnum, - (msg->cm_fields['E'] ? msg->cm_fields['E'] : ""), - (msg->cm_fields['T'] ? msg->cm_fields['T'] : "0")); - CtdlFreeMessage(msg); + (!CM_IsEmpty(msg, eExclusiveID) ? msg->cm_fields[eExclusiveID] : ""), + (!CM_IsEmpty(msg, eTimestamp) ? msg->cm_fields[eTimestamp] : "0")); + CM_Free(msg); } @@ -346,10 +585,11 @@ 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, &CC->user, &CC->room); + CtdlGetRelationship(&vbuf, &CCC->user, &CCC->room); if (which_set == ctdlsetseen_seen) safestrncpy(buf, vbuf.v_seen, SIZ); @@ -365,12 +605,13 @@ void CtdlGetSeen(char *buf, int which_set) { 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); + long hi = (-1L); /// TODO: we just write here. y? visit vbuf; long *msglist; int num_msgs = 0; @@ -388,19 +629,19 @@ 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 = &CC->room; + which_room = &CCC->room; } /* If no user was specified, we go with the current user. */ if (!which_user) { - which_user = &CC->user; + which_user = &CCC->user; } - syslog(LOG_DEBUG, "CtdlSetSeen(%d msgs starting with %ld, %s, %d) in <%s>\n", - num_target_msgnums, target_msgnums[0], - (target_setting ? "SET" : "CLEAR"), - which_set, - which_room->QRname); + MSG_syslog(LOG_DEBUG, "CtdlSetSeen(%d msgs starting with %ld, %s, %d) in <%s>\n", + num_target_msgnums, target_msgnums[0], + (target_setting ? "SET" : "CLEAR"), + which_set, + which_room->QRname); /* Learn about the user and room in question */ CtdlGetRelationship(&vbuf, which_user, which_room); @@ -433,17 +674,17 @@ 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. */ - syslog(LOG_DEBUG, "There are %d messages in the room.\n", num_msgs); + MSG_syslog(LOG_DEBUG, "There are %d messages in the room.\n", num_msgs); for (i=0; i 0) && (msglist[i] <= msglist[i-1])) abort(); } - syslog(LOG_DEBUG, "We are twiddling %d of them.\n", num_target_msgnums); + MSG_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 - syslog(LOG_DEBUG, "before update: %s\n", ChrPtr(vset)); + MSG_syslog(LOG_DEBUG, "before update: %s\n", ChrPtr(vset)); /* Translate the existing sequence set into an array of booleans */ setstr = NewStrBuf(); @@ -566,7 +807,7 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, vset = new_set; } - syslog(LOG_DEBUG, " after update: %s\n", ChrPtr(vset)); + MSG_syslog(LOG_DEBUG, " after update: %s\n", ChrPtr(vset)); /* Decide which message set we're manipulating */ switch (which_set) { @@ -595,7 +836,7 @@ 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; @@ -620,11 +861,25 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, } /* Learn about the user and room in question */ - CtdlGetUser(&CC->user, CC->curr_user); - CtdlGetRelationship(&vbuf, &CC->user, &CC->room); + if (server_shutting_down) { + if (need_to_free_re) regfree(&re); + return -1; + } + CtdlGetUser(&CCC->user, CCC->curr_user); + + if (server_shutting_down) { + if (need_to_free_re) regfree(&re); + return -1; + } + CtdlGetRelationship(&vbuf, &CCC->user, &CCC->room); + + if (server_shutting_down) { + if (need_to_free_re) regfree(&re); + return -1; + } /* Load the message list */ - cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long)); + cdbfr = cdb_fetch(CDB_MSGLISTS, &CCC->room.QRnumber, sizeof(long)); if (cdbfr == NULL) { if (need_to_free_re) regfree(&re); return 0; /* No messages at all? No further action. */ @@ -655,6 +910,11 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, * enough to only do the read if the caller has * specified something that will need it. */ + if (server_shutting_down) { + if (need_to_free_re) regfree(&re); + free(msglist); + return -1; + } GetMetaData(&smi, msglist[a]); /* if (strcasecmp(smi.meta_content_type, content_type)) { old non-regex way */ @@ -672,12 +932,17 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, if (num_msgs > 0) { if (compare != NULL) { for (a = 0; a < num_msgs; ++a) { + if (server_shutting_down) { + if (need_to_free_re) regfree(&re); + free(msglist); + return -1; + } msg = CtdlFetchMessage(msglist[a], 1); if (msg != NULL) { if (CtdlMsgCmp(msg, compare)) { msglist[a] = 0L; } - CtdlFreeMessage(msg); + CM_Free(msg); } } } @@ -734,6 +999,11 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, */ if (num_msgs > 0) for (a = 0; a < num_msgs; ++a) { + if (server_shutting_down) { + if (need_to_free_re) regfree(&re); + free(msglist); + return num_processed; + } thismsg = msglist[a]; if (mode == MSGS_ALL) { is_seen = 0; @@ -756,7 +1026,7 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, || ((mode == MSGS_EQ) && (thismsg == ref)) ) ) { - if ((mode == MSGS_NEW) && (CC->user.flags & US_LASTOLD) && (lastold > 0L) && (printed_lastold == 0) && (!is_seen)) { + if ((mode == MSGS_NEW) && (CCC->user.flags & US_LASTOLD) && (lastold > 0L) && (printed_lastold == 0) && (!is_seen)) { if (CallBack) CallBack(lastold, userdata); printed_lastold = 1; @@ -771,12 +1041,12 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, /* * We cache the most recent msglist in order to do security checks later */ - if (CC->client_socket > 0) { - if (CC->cached_msglist != NULL) { - free(CC->cached_msglist); + if (CCC->client_socket > 0) { + if (CCC->cached_msglist != NULL) { + free(CCC->cached_msglist); } - CC->cached_msglist = msglist; - CC->cached_num_msgs = num_msgs; + CCC->cached_msglist = msglist; + CCC->cached_num_msgs = num_msgs; } else { free(msglist); @@ -860,12 +1130,12 @@ void cmd_msgs(char *cmdbuf) template->cm_anon_type = MES_NORMAL; while(client_getln(buf, sizeof buf) >= 0 && strcmp(buf,"000")) { + long tValueLen; extract_token(tfield, buf, 0, '|', sizeof tfield); - extract_token(tvalue, buf, 1, '|', sizeof tvalue); + tValueLen = extract_token(tvalue, buf, 1, '|', sizeof tvalue); for (i='A'; i<='Z'; ++i) if (msgkeys[i]!=NULL) { if (!strcasecmp(tfield, msgkeys[i])) { - template->cm_fields[i] = - strdup(tvalue); + CM_SetField(template, i, tvalue, tValueLen); } } } @@ -882,48 +1152,11 @@ void cmd_msgs(char *cmdbuf) template, CallBack, NULL); - if (template != NULL) CtdlFreeMessage(template); + if (template != NULL) CM_Free(template); cprintf("000\n"); } - - -/* - * help_subst() - support routine for help file viewer - */ -void help_subst(char *strbuf, char *source, char *dest) -{ - char workbuf[SIZ]; - int p; - - while (p = pattern2(strbuf, source), (p >= 0)) { - strcpy(workbuf, &strbuf[p + strlen(source)]); - strcpy(&strbuf[p], dest); - strcat(strbuf, workbuf); - } -} - - -void do_help_subst(char *buffer) -{ - char buf2[16]; - - help_subst(buffer, "^nodename", config.c_nodename); - help_subst(buffer, "^humannode", config.c_humannode); - help_subst(buffer, "^fqdn", config.c_fqdn); - help_subst(buffer, "^username", CC->user.fullname); - snprintf(buf2, sizeof buf2, "%ld", CC->user.usernum); - help_subst(buffer, "^usernum", buf2); - help_subst(buffer, "^sysadm", config.c_sysadm); - help_subst(buffer, "^variantname", CITADEL); - snprintf(buf2, sizeof buf2, "%d", config.c_maxsessions); - help_subst(buffer, "^maxsessions", buf2); - help_subst(buffer, "^bbsdir", ctdl_message_dir); -} - - - /* * memfmout() - Citadel text formatter and paginator. * Although the original purpose of this routine was to format @@ -935,6 +1168,7 @@ 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]; @@ -948,13 +1182,13 @@ void memfmout( if (ch == '\n') { if (client_write(outbuf, len) == -1) { - syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); + MSGM_syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); return; } len = 0; if (client_write(nl, nllen) == -1) { - syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); + MSGM_syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); return; } column = 0; @@ -966,13 +1200,13 @@ void memfmout( if (column > 72) { /* Beyond 72 columns, break on the next space */ if (client_write(outbuf, len) == -1) { - syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); + MSGM_syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); return; } len = 0; if (client_write(nl, nllen) == -1) { - syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); + MSGM_syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); return; } column = 0; @@ -988,13 +1222,13 @@ void memfmout( if (column > 1000) { /* Beyond 1000 columns, break anywhere */ if (client_write(outbuf, len) == -1) { - syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); + MSGM_syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); return; } len = 0; if (client_write(nl, nllen) == -1) { - syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); + MSGM_syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); return; } column = 0; @@ -1004,7 +1238,7 @@ void memfmout( if (len) { if (client_write(outbuf, len) == -1) { - syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); + MSGM_syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); return; } len = 0; @@ -1096,17 +1330,17 @@ void mime_download(char *name, char *filename, char *partnum, char *disp, ) { CCC->download_fp = tmpfile(); if (CCC->download_fp == NULL) { - syslog(LOG_EMERG, "mime_download(): Couldn't write: %s\n", - strerror(errno)); + 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)); return; } - rv = fwrite(content, length, 1, CC->download_fp); + rv = fwrite(content, length, 1, CCC->download_fp); if (rv <= 0) { - syslog(LOG_EMERG, "mime_download(): Couldn't write: %s\n", - strerror(errno)); + 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); @@ -1158,6 +1392,7 @@ void mime_spew_section(char *name, char *filename, char *partnum, char *disp, */ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) { + struct CitContext *CCC = CC; struct cdbdata *dmsgtext; struct CtdlMessage *ret = NULL; char *mptr; @@ -1165,9 +1400,10 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) cit_uint8_t ch; cit_uint8_t field_header; - syslog(LOG_DEBUG, "CtdlFetchMessage(%ld, %d)\n", msgnum, with_body); + 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); return NULL; } mptr = dmsgtext->ptr; @@ -1180,7 +1416,7 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) */ ch = *mptr++; if (ch != 255) { - syslog(LOG_ERR, "Message %ld appears to be corrupted.\n", msgnum); + MSG_syslog(LOG_ERR, "Message %ld appears to be corrupted.\n", msgnum); cdb_free(dmsgtext); return NULL; } @@ -1197,13 +1433,15 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) * have just processed the 'M' (message text) field. */ do { + long len; if (mptr >= upper_bound) { break; } field_header = *mptr++; - ret->cm_fields[field_header] = strdup(mptr); + len = strlen(mptr); + CM_SetField(ret, field_header, mptr, len); - while (*mptr++ != 0); /* advance to next field */ + mptr += len + 1; /* advance to next field */ } while ((mptr < upper_bound) && (field_header != 'M')); @@ -1214,21 +1452,20 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) * so go ahead and fetch that. Failing that, just set a dummy * body so other code doesn't barf. */ - if ( (ret->cm_fields['M'] == NULL) && (with_body) ) { + if ( (CM_IsEmpty(ret, eMesageText)) && (with_body) ) { dmsgtext = cdb_fetch(CDB_BIGMSGS, &msgnum, sizeof(long)); if (dmsgtext != NULL) { - ret->cm_fields['M'] = dmsgtext->ptr; - dmsgtext->ptr = NULL; + CM_SetAsField(ret, eMesageText, &dmsgtext->ptr, dmsgtext->len); cdb_free(dmsgtext); } } - if (ret->cm_fields['M'] == NULL) { - ret->cm_fields['M'] = strdup("\r\n\r\n (no text)\r\n"); + if (CM_IsEmpty(ret, eMesageText)) { + 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, EVT_BEFOREREAD) > 0) { - CtdlFreeMessage(ret); + CM_Free(ret); return NULL; } @@ -1236,45 +1473,6 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) } -/* - * 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 is_valid_message(struct CtdlMessage *msg) { - if (msg == NULL) - return 0; - if ((msg->cm_magic) != CTDLMESSAGE_MAGIC) { - syslog(LOG_WARNING, "is_valid_message() -- self-check failed\n"); - return 0; - } - return 1; -} - -void CtdlFreeMessageContents(struct CtdlMessage *msg) -{ - int i; - - for (i = 0; i < 256; ++i) - if (msg->cm_fields[i] != NULL) { - free(msg->cm_fields[i]); - } - - msg->cm_magic = 0; /* just in case */ -} -/* - * 'Destructor' for struct CtdlMessage - */ -void CtdlFreeMessage(struct CtdlMessage *msg) -{ - if (is_valid_message(msg) == 0) - { - if (msg != NULL) free (msg); - return; - } - CtdlFreeMessageContents(msg); - free(msg); -} - /* * Pre callback function for multipart/alternative @@ -1290,10 +1488,11 @@ 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; - syslog(LOG_DEBUG, "fixed_output_pre() type=<%s>\n", cbtype); + MSG_syslog(LOG_DEBUG, "fixed_output_pre() type=<%s>\n", cbtype); if (!strcasecmp(cbtype, "multipart/alternative")) { ++ma->is_ma; ma->did_print = 0; @@ -1310,10 +1509,11 @@ 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; - syslog(LOG_DEBUG, "fixed_output_post() type=<%s>\n", cbtype); + MSG_syslog(LOG_DEBUG, "fixed_output_post() type=<%s>\n", cbtype); if (!strcasecmp(cbtype, "multipart/alternative")) { --ma->is_ma; ma->did_print = 0; @@ -1330,6 +1530,7 @@ 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; @@ -1337,7 +1538,7 @@ void fixed_output(char *name, char *filename, char *partnum, char *disp, ma = (struct ma_info *)cbuserdata; - syslog(LOG_DEBUG, + MSG_syslog(LOG_DEBUG, "fixed_output() part %s: %s (%s) (%ld bytes)\n", partnum, filename, cbtype, (long)length); @@ -1346,7 +1547,7 @@ void fixed_output(char *name, char *filename, char *partnum, char *disp, * we've already printed another section, skip this one. */ if ( (ma->is_ma) && (ma->did_print) ) { - syslog(LOG_DEBUG, "Skipping part %s (%s)\n", partnum, cbtype); + MSG_syslog(LOG_DEBUG, "Skipping part %s (%s)\n", partnum, cbtype); return; } ma->did_print = 1; @@ -1403,6 +1604,7 @@ 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; @@ -1414,11 +1616,11 @@ void choose_preferred(char *name, char *filename, char *partnum, char *disp, // 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, CC->preferred_formats, i, '|', sizeof buf); + for (i=0; ipreferred_formats, '|'); ++i) { + extract_token(buf, CCC->preferred_formats, i, '|', sizeof buf); if ( (!strcasecmp(buf, cbtype)) && (!ma->freeze) ) { if (i < ma->chosen_pref) { - syslog(LOG_DEBUG, "Setting chosen part: <%s>\n", partnum); + MSG_syslog(LOG_DEBUG, "Setting chosen part: <%s>\n", partnum); safestrncpy(ma->chosen_part, partnum, sizeof ma->chosen_part); ma->chosen_pref = i; } @@ -1441,6 +1643,7 @@ void output_preferred(char *name, char *cbid, void *cbuserdata) { + struct CitContext *CCC = CC; int i; char buf[128]; int add_newline = 0; @@ -1458,8 +1661,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, CC->preferred_formats, i, '|', sizeof buf); + for (i=0; ipreferred_formats, '|'); ++i) { + extract_token(buf, CCC->preferred_formats, i, '|', sizeof buf); if (!strcasecmp(buf, cbtype)) { /* Yeah! Go! W00t!! */ if (ma->dont_decode == 0) @@ -1496,7 +1699,7 @@ void output_preferred(char *name, cprintf("\n"); if (client_write(text_content, length) == -1) { - syslog(LOG_ERR, "output_preferred(): aborting due to write failure.\n"); + MSGM_syslog(LOG_ERR, "output_preferred(): aborting due to write failure.\n"); return; } if (add_newline) cprintf("\n"); @@ -1562,12 +1765,13 @@ 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 (!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 */ + 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 */ /* Do a binary search within the cached_msglist for the requested msgnum */ @@ -1576,7 +1780,7 @@ int check_cached_msglist(long msgnum) { while (max >= min) { int middle = min + (max-min) / 2 ; - if (msgnum == CC->cached_msglist[middle]) { + if (msgnum == CCC->cached_msglist[middle]) { return om_ok; } if (msgnum > CC->cached_msglist[middle]) { @@ -1616,14 +1820,17 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ int do_proto, /* do Citadel protocol responses? */ int crlf, /* Use CRLF newlines instead of LF? */ char *section, /* NULL or a message/rfc822 section */ - int flags /* various flags; see msgbase.h */ + int flags, /* various flags; see msgbase.h */ + char **Author, + char **Address ) { + struct CitContext *CCC = CC; struct CtdlMessage *TheMessage = NULL; - int retcode = om_no_such_msg; + int retcode = CIT_OK; struct encapmsg encap; int r; - syslog(LOG_DEBUG, "CtdlOutputMsg(msgnum=%ld, mode=%d, section=%s)\n", + MSG_syslog(LOG_DEBUG, "CtdlOutputMsg(msgnum=%ld, mode=%d, section=%s)\n", msg_num, mode, (section ? section : "<>") ); @@ -1651,8 +1858,8 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ r = check_cached_msglist(msg_num); } if (r != om_ok) { - syslog(LOG_DEBUG, "Security check fail: message %ld is not in %s\n", - msg_num, CC->room.QRname + MSG_syslog(LOG_DEBUG, "Security check fail: message %ld is not in %s\n", + msg_num, CCC->room.QRname ); if (do_proto) { if (r == om_access_denied) { @@ -1688,12 +1895,23 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ if (section) if (!IsEmptyStr(section)) if (strcmp(section, "0")) { memset(&encap, 0, sizeof encap); safestrncpy(encap.desired_section, section, sizeof encap.desired_section); - mime_parser(TheMessage->cm_fields['M'], + mime_parser(TheMessage->cm_fields[eMesageText], NULL, *extract_encapsulated_message, NULL, NULL, (void *)&encap, 0 ); - CtdlFreeMessage(TheMessage); + + if ((Author != NULL) && (*Author == NULL)) + { + *Author = TheMessage->cm_fields[eAuthor]; + TheMessage->cm_fields[eAuthor] = NULL; + } + if ((Address != NULL) && (*Address == NULL)) + { + *Address = TheMessage->cm_fields[erFc822Addr]; + TheMessage->cm_fields[erFc822Addr] = NULL; + } + CM_Free(TheMessage); TheMessage = NULL; if (encap.msg) { @@ -1706,19 +1924,34 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ * encapsulated message instead of the top-level * message. Isn't that neat? */ - } else { - if (do_proto) cprintf("%d msg %ld has no part %s\n", - ERROR + MESSAGE_NOT_FOUND, msg_num, section); + if (do_proto) { + cprintf("%d msg %ld has no part %s\n", + ERROR + MESSAGE_NOT_FOUND, + msg_num, + section); + } retcode = om_no_such_msg; } } /* Ok, output the message now */ - retcode = CtdlOutputPreLoadedMsg(TheMessage, mode, headers_only, do_proto, crlf, flags); - CtdlFreeMessage(TheMessage); + if (retcode == CIT_OK) + retcode = CtdlOutputPreLoadedMsg(TheMessage, mode, headers_only, do_proto, crlf, flags); + if ((Author != NULL) && (*Author == NULL)) + { + *Author = TheMessage->cm_fields[eAuthor]; + TheMessage->cm_fields[eAuthor] = NULL; + } + if ((Address != NULL) && (*Address == NULL)) + { + *Address = TheMessage->cm_fields[erFc822Addr]; + TheMessage->cm_fields[erFc822Addr] = NULL; + } + + CM_Free(TheMessage); return(retcode); } @@ -1726,6 +1959,7 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ char *qp_encode_email_addrs(char *source) { + struct CitContext *CCC = CC; char *user, *node, *name; const char headerStr[] = "=?UTF-8?Q?"; char *Encoded; @@ -1744,8 +1978,8 @@ char *qp_encode_email_addrs(char *source) if (source == NULL) return source; if (IsEmptyStr(source)) return source; - cit_backtrace(); - syslog(LOG_DEBUG, "qp_encode_email_addrs: [%s]\n", source); + if (MessageDebugEnabled != 0) cit_backtrace(); + MSG_syslog(LOG_DEBUG, "qp_encode_email_addrs: [%s]\n", source); AddrPtr = malloc (sizeof (long) * nAddrPtrMax); AddrUtf8 = malloc (sizeof (long) * nAddrPtrMax); @@ -1878,16 +2112,15 @@ void OutputCtdlMsgHeaders( struct CtdlMessage *TheMessage, int do_proto) /* do Citadel protocol responses? */ { - char allkeys[30]; - int i, k, n; + int i; int suppress_f = 0; char buf[SIZ]; char display_name[256]; /* begin header processing loop for Citadel message format */ safestrncpy(display_name, "", sizeof display_name); - if (TheMessage->cm_fields['A']) { - strcpy(buf, TheMessage->cm_fields['A']); + if (!CM_IsEmpty(TheMessage, eAuthor)) { + strcpy(buf, TheMessage->cm_fields[eAuthor]); if (TheMessage->cm_anon_type == MES_ANONONLY) { safestrncpy(display_name, "****", sizeof display_name); } @@ -1911,35 +2144,37 @@ void OutputCtdlMsgHeaders( * local Citadel network. */ suppress_f = 0; - if (TheMessage->cm_fields['N'] != NULL) - if (!IsEmptyStr(TheMessage->cm_fields['N'])) - if (haschar(TheMessage->cm_fields['N'], '.') == 0) { - suppress_f = 1; - } + 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. */ - n = safestrncpy(allkeys, FORDER, sizeof allkeys); - for (i=0; icm_fields[k] != NULL) - && (msgkeys[k] != NULL) ) { - if ((k == 'V') || (k == 'R') || (k == 'Y')) { - sanitize_truncated_recipient(TheMessage->cm_fields[k]); + 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)) { + sanitize_truncated_recipient(TheMessage->cm_fields[Field]); } - if (k == 'A') { + if (Field == eAuthor) { if (do_proto) cprintf("%s=%s\n", - msgkeys[k], + msgkeys[Field], display_name); } - else if ((k == 'F') && (suppress_f)) { + else if ((Field == erFc822Addr) && (suppress_f)) { /* do nothing */ } /* Masquerade display name if needed */ else { if (do_proto) cprintf("%s=%s\n", - msgkeys[k], - TheMessage->cm_fields[k] + msgkeys[Field], + TheMessage->cm_fields[Field] ); } } @@ -1970,7 +2205,7 @@ void OutputRFC822MsgHeaders( if (TheMessage->cm_fields[i]) { mptr = mpptr = TheMessage->cm_fields[i]; - if (i == 'A') { + if (i == eAuthor) { safestrncpy(luser, mptr, sizeof_luser); safestrncpy(suser, mptr, sizeof_suser); } @@ -1984,7 +2219,7 @@ void OutputRFC822MsgHeaders( else if (i == 'P') { cprintf("Return-Path: %s%s", mptr, nl); } - else if (i == 'L') { + else if (i == eListID) { cprintf("List-ID: %s%s", mptr, nl); } else if (i == 'V') { @@ -2002,7 +2237,7 @@ void OutputRFC822MsgHeaders( } else if (i == 'I') safestrncpy(mid, mptr, sizeof_mid); /// TODO: detect @ here and copy @nodename in if not found. - else if (i == 'F') + else if (i == erFc822Addr) safestrncpy(fuser, mptr, sizeof_fuser); /* else if (i == 'O') cprintf("X-Citadel-Room: %s%s", @@ -2046,7 +2281,7 @@ void OutputRFC822MsgHeaders( } } } - else if (i == 'K') { + else if (i == eReplyTo) { hptr = mptr; while ((*hptr != '\0') && isspace(*hptr)) hptr ++; @@ -2078,7 +2313,7 @@ void Dump_RFC822HeadersBody( int nllen = strlen(nl); char *mptr; - mptr = TheMessage->cm_fields['M']; + mptr = TheMessage->cm_fields[eMesageText]; prev_ch = '\0'; @@ -2129,7 +2364,8 @@ void Dump_RFC822HeadersBody( if (outlen > 1000) { if (client_write(outbuf, outlen) == -1) { - syslog(LOG_ERR, "Dump_RFC822HeadersBody(): aborting due to write failure.\n"); + struct CitContext *CCC = CC; + MSGM_syslog(LOG_ERR, "Dump_RFC822HeadersBody(): aborting due to write failure.\n"); return; } outlen = 0; @@ -2137,7 +2373,6 @@ void Dump_RFC822HeadersBody( } if (outlen > 0) { client_write(outbuf, outlen); - outlen = 0; } } @@ -2159,7 +2394,7 @@ void DumpFormatFixed( int nllen = strlen (nl); char *mptr; - mptr = TheMessage->cm_fields['M']; + mptr = TheMessage->cm_fields[eMesageText]; if (mode == MT_MIME) { cprintf("Content-type: text/plain\n\n"); @@ -2200,7 +2435,8 @@ void DumpFormatFixed( if (client_write(buf, buflen) == -1) { - syslog(LOG_ERR, "DumpFormatFixed(): aborting due to write failure.\n"); + struct CitContext *CCC = CC; + MSGM_syslog(LOG_ERR, "DumpFormatFixed(): aborting due to write failure.\n"); return; } *buf = '\0'; @@ -2227,6 +2463,7 @@ int CtdlOutputPreLoadedMsg( int crlf, /* Use CRLF newlines instead of LF? */ int flags /* should the bessage be exported clean? */ ) { + struct CitContext *CCC = CC; int i; char *mptr = NULL; const char *nl; /* newline string */ @@ -2242,16 +2479,16 @@ int CtdlOutputPreLoadedMsg( char snode[100]; char mid[100]; - syslog(LOG_DEBUG, "CtdlOutputPreLoadedMsg(TheMessage=%s, %d, %d, %d, %d\n", - ((TheMessage == NULL) ? "NULL" : "not null"), - mode, headers_only, do_proto, crlf); + MSG_syslog(LOG_DEBUG, "CtdlOutputPreLoadedMsg(TheMessage=%s, %d, %d, %d, %d\n", + ((TheMessage == NULL) ? "NULL" : "not null"), + mode, headers_only, do_proto, crlf); strcpy(mid, "unknown"); nl = (crlf ? "\r\n" : "\n"); - if (!is_valid_message(TheMessage)) { - syslog(LOG_ERR, - "ERROR: invalid preloaded message for output\n"); + if (!CM_IsValidMsg(TheMessage)) { + MSGM_syslog(LOG_ERR, + "ERROR: invalid preloaded message for output\n"); cit_backtrace (); return(om_no_such_msg); } @@ -2259,8 +2496,8 @@ int CtdlOutputPreLoadedMsg( /* Suppress envelope recipients if required to avoid disclosing BCC addresses. * Pad it with spaces in order to avoid changing the RFC822 length of the message. */ - if ( (flags & SUPPRESS_ENV_TO) && (TheMessage->cm_fields['V'] != NULL) ) { - memset(TheMessage->cm_fields['V'], ' ', strlen(TheMessage->cm_fields['V'])); + if ( (flags & SUPPRESS_ENV_TO) && (!CM_IsEmpty(TheMessage, eenVelopeTo)) ) { + memset(TheMessage->cm_fields[eenVelopeTo], ' ', strlen(TheMessage->cm_fields[eenVelopeTo])); } /* Are we downloading a MIME component? */ @@ -2269,25 +2506,25 @@ int CtdlOutputPreLoadedMsg( if (do_proto) cprintf("%d This is not a MIME message.\n", ERROR + ILLEGAL_VALUE); - } else if (CC->download_fp != NULL) { + } else if (CCC->download_fp != NULL) { if (do_proto) cprintf( "%d You already have a download open.\n", ERROR + RESOURCE_BUSY); } else { /* Parse the message text component */ - mptr = TheMessage->cm_fields['M']; + mptr = TheMessage->cm_fields[eMesageText]; mime_parser(mptr, NULL, *mime_download, NULL, NULL, NULL, 0); /* If there's no file open by this time, the requested * section wasn't found, so print an error */ - if (CC->download_fp == NULL) { + if (CCC->download_fp == NULL) { if (do_proto) cprintf( "%d Section %s not found.\n", ERROR + FILE_NOT_FOUND, - CC->download_desired_section); + CCC->download_desired_section); } } - return((CC->download_fp != NULL) ? om_ok : om_mime_error); + return((CCC->download_fp != NULL) ? om_ok : om_mime_error); } /* MT_SPEW_SECTION is like MT_DOWNLOAD except it outputs the whole MIME part @@ -2302,7 +2539,7 @@ int CtdlOutputPreLoadedMsg( /* Parse the message text component */ int found_it = 0; - mptr = TheMessage->cm_fields['M']; + mptr = TheMessage->cm_fields[eMesageText]; mime_parser(mptr, NULL, *mime_spew_section, NULL, NULL, (void *)&found_it, 0); /* If section wasn't found, print an error */ @@ -2310,10 +2547,10 @@ int CtdlOutputPreLoadedMsg( if (do_proto) cprintf( "%d Section %s not found.\n", ERROR + FILE_NOT_FOUND, - CC->download_desired_section); + CCC->download_desired_section); } } - return((CC->download_fp != NULL) ? om_ok : om_mime_error); + return((CCC->download_fp != NULL) ? om_ok : om_mime_error); } /* now for the user-mode message reading loops */ @@ -2400,7 +2637,7 @@ START_TEXT: /* Tell the client about the MIME parts in this message */ if (TheMessage->cm_format_type == FMT_RFC822) { if ( (mode == MT_CITADEL) || (mode == MT_MIME) ) { - mptr = TheMessage->cm_fields['M']; + mptr = TheMessage->cm_fields[eMesageText]; memset(&ma, 0, sizeof(struct ma_info)); mime_parser(mptr, NULL, (do_proto ? *list_this_part : NULL), @@ -2441,7 +2678,7 @@ START_TEXT: * message to the reader's screen width. */ if (TheMessage->cm_format_type == FMT_CITADEL) { - mptr = TheMessage->cm_fields['M']; + mptr = TheMessage->cm_fields[eMesageText]; if (mode == MT_MIME) { cprintf("Content-type: text/x-citadel-variformat\n\n"); @@ -2461,7 +2698,7 @@ START_TEXT: ma.use_fo_hooks = 0; strcpy(ma.chosen_part, "1"); ma.chosen_pref = 9999; - ma.dont_decode = CC->msg4_dont_decode; + ma.dont_decode = CCC->msg4_dont_decode; mime_parser(mptr, NULL, *choose_preferred, *fixed_output_pre, *fixed_output_post, (void *)&ma, 1); @@ -2494,7 +2731,7 @@ void cmd_msg0(char *cmdbuf) msgid = extract_long(cmdbuf, 0); headers_only = extract_int(cmdbuf, 1); - CtdlOutputMsg(msgid, MT_CITADEL, headers_only, 1, 0, NULL, 0); + CtdlOutputMsg(msgid, MT_CITADEL, headers_only, 1, 0, NULL, 0, NULL, NULL); return; } @@ -2510,7 +2747,7 @@ void cmd_msg2(char *cmdbuf) msgid = extract_long(cmdbuf, 0); headers_only = extract_int(cmdbuf, 1); - CtdlOutputMsg(msgid, MT_RFC822, headers_only, 1, 1, NULL, 0); + CtdlOutputMsg(msgid, MT_RFC822, headers_only, 1, 1, NULL, 0, NULL, NULL); } @@ -2539,7 +2776,7 @@ void cmd_msg3(char *cmdbuf) } serialize_message(&smr, msg); - CtdlFreeMessage(msg); + CM_Free(msg); if (smr.len == 0) { cprintf("%d Unable to serialize message\n", @@ -2564,7 +2801,7 @@ void cmd_msg4(char *cmdbuf) msgid = extract_long(cmdbuf, 0); extract_token(section, cmdbuf, 1, '|', sizeof section); - CtdlOutputMsg(msgid, MT_MIME, 0, 1, 0, (section[0] ? section : NULL) , 0); + CtdlOutputMsg(msgid, MT_MIME, 0, 1, 0, (section[0] ? section : NULL) , 0, NULL, NULL); } @@ -2597,7 +2834,7 @@ void cmd_opna(char *cmdbuf) extract_token(desired_section, cmdbuf, 1, '|', sizeof desired_section); safestrncpy(CC->download_desired_section, desired_section, sizeof CC->download_desired_section); - CtdlOutputMsg(msgid, MT_DOWNLOAD, 0, 1, 1, NULL, 0); + CtdlOutputMsg(msgid, MT_DOWNLOAD, 0, 1, 1, NULL, 0, NULL, NULL); } @@ -2613,8 +2850,8 @@ void cmd_dlat(char *cmdbuf) extract_token(desired_section, cmdbuf, 1, '|', sizeof desired_section); safestrncpy(CC->download_desired_section, desired_section, sizeof CC->download_desired_section); - CtdlOutputMsg(msgid, MT_SPEW_SECTION, 0, 1, 1, NULL, 0); -} + CtdlOutputMsg(msgid, MT_SPEW_SECTION, 0, 1, 1, NULL, 0, NULL, NULL); +} /* @@ -2631,6 +2868,7 @@ void cmd_dlat(char *cmdbuf) 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; @@ -2644,12 +2882,12 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms long *msgs_to_be_merged = NULL; int num_msgs_to_be_merged = 0; - syslog(LOG_DEBUG, - "CtdlSaveMsgPointersInRoom(room=%s, num_msgs=%d, repl=%d, suppress_rca=%d)\n", - roomname, num_newmsgs, do_repl_check, suppress_refcount_adj + 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 ); - strcpy(hold_rm, CC->room.QRname); + strcpy(hold_rm, CCC->room.QRname); /* Sanity checks */ if (newmsgidlist == NULL) return(ERROR + INTERNAL_ERROR); @@ -2657,10 +2895,10 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms if (num_newmsgs > 1) supplied_msg = NULL; /* Now the regular stuff */ - if (CtdlGetRoomLock(&CC->room, - ((roomname != NULL) ? roomname : CC->room.QRname) ) + if (CtdlGetRoomLock(&CCC->room, + ((roomname != NULL) ? roomname : CCC->room.QRname) ) != 0) { - syslog(LOG_ERR, "No such room <%s>\n", roomname); + MSG_syslog(LOG_ERR, "No such room <%s>\n", roomname); return(ERROR + ROOM_NOT_FOUND); } @@ -2669,7 +2907,7 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms num_msgs_to_be_merged = 0; - cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long)); + cdbfr = cdb_fetch(CDB_MSGLISTS, &CCC->room.QRnumber, sizeof(long)); if (cdbfr == NULL) { msglist = NULL; num_msgs = 0; @@ -2697,14 +2935,16 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms } } - syslog(LOG_DEBUG, "%d unique messages to be merged\n", num_msgs_to_be_merged); + MSG_syslog(LOG_DEBUG, "%d unique messages to be merged\n", 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) { - syslog(LOG_ALERT, "ERROR: can't realloc message list!\n"); + MSGM_syslog(LOG_ALERT, "ERROR: can't realloc message list!\n"); + free(msgs_to_be_merged); + return (ERROR + INTERNAL_ERROR); } memcpy(&msglist[num_msgs], msgs_to_be_merged, (sizeof(long) * num_msgs_to_be_merged) ); num_msgs += num_msgs_to_be_merged; @@ -2716,19 +2956,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, &CC->room.QRnumber, (int)sizeof(long), + cdb_store(CDB_MSGLISTS, &CCC->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. */ - CC->room.QRhighest = highest_msg; - CtdlPutRoomLock(&CC->room); + CCC->room.QRhighest = highest_msg; + CtdlPutRoomLock(&CCC->room); /* Perform replication checks if necessary */ - if ( (DoesThisRoomNeedEuidIndexing(&CC->room)) && (do_repl_check) ) { - syslog(LOG_DEBUG, "CtdlSaveMsgPointerInRoom() doing repl checks\n"); + if ( (DoesThisRoomNeedEuidIndexing(&CCC->room)) && (do_repl_check) ) { + MSGM_syslog(LOG_DEBUG, "CtdlSaveMsgPointerInRoom() doing repl checks\n"); for (i=0; icm_fields['E'] != NULL) { - index_message_by_euid(msg->cm_fields['E'], &CC->room, msgid); + if (!CM_IsEmpty(msg, eExclusiveID)) { + index_message_by_euid(msg->cm_fields[eExclusiveID], &CCC->room, msgid); } /* Free up the memory we may have allocated */ if (msg != supplied_msg) { - CtdlFreeMessage(msg); + CM_Free(msg); } } @@ -2758,20 +2998,18 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms } else { - syslog(LOG_DEBUG, "CtdlSaveMsgPointerInRoom() skips repl checks\n"); + MSGM_syslog(LOG_DEBUG, "CtdlSaveMsgPointerInRoom() skips repl checks\n"); } /* Submit this room for processing by hooks */ - PerformRoomHooks(&CC->room); + PerformRoomHooks(&CCC->room); /* Go back to the room we were in before we wandered here... */ - CtdlGetRoom(&CC->room, hold_rm); + CtdlGetRoom(&CCC->room, hold_rm); /* Bump the reference count for all messages which were merged */ if (!suppress_refcount_adj) { - for (i=0; icm_fields['I']==NULL) { - msg->cm_fields['I'] = strdup(msgidbuf); + if (CM_IsEmpty(msg, emessageId)) { + CM_SetField(msg, emessageId, msgidbuf, msgidbuflen); } /* If the message is big, set its body aside for storage elsewhere */ - if (msg->cm_fields['M'] != NULL) { - if (strlen(msg->cm_fields['M']) > BIGMSG) { + if (!CM_IsEmpty(msg, eMesageText)) { + if (strlen(msg->cm_fields[eMesageText]) > BIGMSG) { is_bigmsg = 1; - holdM = msg->cm_fields['M']; - msg->cm_fields['M'] = NULL; + holdM = msg->cm_fields[eMesageText]; + msg->cm_fields[eMesageText] = NULL; } } @@ -2839,7 +3079,7 @@ long send_message(struct CtdlMessage *msg) { serialize_message(&smr, msg); if (is_bigmsg) { - msg->cm_fields['M'] = holdM; + msg->cm_fields[eMesageText] = holdM; } if (smr.len == 0) { @@ -2851,7 +3091,7 @@ long send_message(struct CtdlMessage *msg) { /* Write our little bundle of joy into the message base */ if (cdb_store(CDB_MSGMAIN, &newmsgid, (int)sizeof(long), smr.ser, smr.len) < 0) { - syslog(LOG_ERR, "Can't store message\n"); + MSGM_syslog(LOG_ERR, "Can't store message\n"); retval = 0L; } else { if (is_bigmsg) { @@ -2886,29 +3126,35 @@ long send_message(struct CtdlMessage *msg) { void serialize_message(struct ser_ret *ret, /* return values */ struct CtdlMessage *msg) /* unserialized msg */ { + struct CitContext *CCC = CC; size_t wlen, fieldlen; int i; - static char *forder = FORDER; + long lengths[NDiskFields]; + + memset(lengths, 0, sizeof(lengths)); /* * Check for valid message format */ - if (is_valid_message(msg) == 0) { - syslog(LOG_ERR, "serialize_message() aborting due to invalid message\n"); + if (CM_IsValidMsg(msg) == 0) { + MSGM_syslog(LOG_ERR, "serialize_message() aborting due to invalid message\n"); ret->len = 0; ret->ser = NULL; return; } ret->len = 3; - for (i=0; i<26; ++i) if (msg->cm_fields[(int)forder[i]] != NULL) - ret->len = ret->len + - strlen(msg->cm_fields[(int)forder[i]]) + 2; + for (i=0; i < NDiskFields; ++i) + if (msg->cm_fields[FieldOrder[i]] != NULL) + { + lengths[i] = strlen(msg->cm_fields[FieldOrder[i]]); + ret->len += lengths[i] + 2; + } ret->ser = malloc(ret->len); if (ret->ser == NULL) { - syslog(LOG_ERR, "serialize_message() malloc(%ld) failed: %s\n", - (long)ret->len, strerror(errno)); + MSG_syslog(LOG_ERR, "serialize_message() malloc(%ld) failed: %s\n", + (long)ret->len, strerror(errno)); ret->len = 0; ret->ser = NULL; return; @@ -2919,81 +3165,52 @@ void serialize_message(struct ser_ret *ret, /* return values */ ret->ser[2] = msg->cm_format_type; wlen = 3; - for (i=0; i<26; ++i) if (msg->cm_fields[(int)forder[i]] != NULL) { - fieldlen = strlen(msg->cm_fields[(int)forder[i]]); - ret->ser[wlen++] = (char)forder[i]; - safestrncpy((char *)&ret->ser[wlen], msg->cm_fields[(int)forder[i]], fieldlen+1); - wlen = wlen + fieldlen + 1; - } - if (ret->len != wlen) syslog(LOG_ERR, "ERROR: len=%ld wlen=%ld\n", - (long)ret->len, (long)wlen); - - return; -} + for (i=0; i < NDiskFields; ++i) + if (msg->cm_fields[FieldOrder[i]] != NULL) + { + fieldlen = lengths[i]; + ret->ser[wlen++] = (char)FieldOrder[i]; + memcpy(&ret->ser[wlen], + msg->cm_fields[FieldOrder[i]], + fieldlen+1); -/* - * Serialize a struct CtdlMessage into the format used on disk and network. - * - * 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 dump_message(struct CtdlMessage *msg, /* unserialized msg */ - long Siz) /* how many chars ? */ -{ - int i; - static char *forder = FORDER; - char *buf; + wlen = wlen + fieldlen + 1; + } - /* - * Check for valid message format - */ - if (is_valid_message(msg) == 0) { - syslog(LOG_ERR, "dump_message() aborting due to invalid message\n"); - return; + if (ret->len != wlen) { + MSG_syslog(LOG_ERR, "ERROR: len=%ld wlen=%ld\n", + (long)ret->len, (long)wlen); } - buf = (char*) malloc (Siz + 1); - - for (i=0; i<26; ++i) if (msg->cm_fields[(int)forder[i]] != NULL) { - snprintf (buf, Siz, " msg[%c] = %s ...\n", (char) forder[i], - msg->cm_fields[(int)forder[i]]); - if (client_write (buf, strlen(buf)) == -1) - { - syslog(LOG_ERR, "dump_message(): aborting due to write failure.\n"); - return; - } - } - return; } - /* * Check to see if any messages already exist in the current room which * 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(&CC->room) == 0) return; + if (DoesThisRoomNeedEuidIndexing(&CCC->room) == 0) return; - syslog(LOG_DEBUG, "Performing replication checks in <%s>\n", - CC->room.QRname); + MSG_syslog(LOG_DEBUG, "Performing replication checks in <%s>\n", + CCC->room.QRname); /* No exclusive id? Don't do anything. */ if (msg == NULL) return; - if (msg->cm_fields['E'] == NULL) return; - if (IsEmptyStr(msg->cm_fields['E'])) return; - /*syslog(LOG_DEBUG, "Exclusive ID: <%s> for room <%s>\n", - msg->cm_fields['E'], CC->room.QRname);*/ + if (CM_IsEmpty(msg, eExclusiveID)) return; + + /*MSG_syslog(LOG_DEBUG, "Exclusive ID: <%s> for room <%s>\n", + msg->cm_fields[eExclusiveID], CCC->room.QRname);*/ - old_msgnum = CtdlLocateMessageByEuid(msg->cm_fields['E'], &CC->room); + old_msgnum = CtdlLocateMessageByEuid(msg->cm_fields[eExclusiveID], &CCC->room); if (old_msgnum > 0L) { - syslog(LOG_DEBUG, "ReplicationChecks() replacing message %ld\n", old_msgnum); - CtdlDeleteMessages(CC->room.QRname, &old_msgnum, 1, ""); + MSG_syslog(LOG_DEBUG, "ReplicationChecks() replacing message %ld\n", old_msgnum); + CtdlDeleteMessages(CCC->room.QRname, &old_msgnum, 1, ""); } } @@ -3009,12 +3226,12 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ ) { char submit_filename[128]; - char generated_timestamp[32]; char hold_rm[ROOMNAMELEN]; char actual_rm[ROOMNAMELEN]; char force_room[ROOMNAMELEN]; char content_type[SIZ]; /* We have to learn this */ char recipient[SIZ]; + const char *room; long newmsgid; const char *mptr = NULL; struct ctdluser userbuf; @@ -3033,46 +3250,44 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ int qualified_for_journaling = 0; CitContext *CCC = MyContext(); char bounce_to[1024] = ""; - size_t tmp = 0; int rv = 0; - syslog(LOG_DEBUG, "CtdlSubmitMsg() called\n"); - if (is_valid_message(msg) == 0) return(-1); /* self check */ + MSGM_syslog(LOG_DEBUG, "CtdlSubmitMsg() called\n"); + if (CM_IsValidMsg(msg) == 0) return(-1); /* self check */ /* If this message has no timestamp, we take the liberty of * giving it one, right now. */ - if (msg->cm_fields['T'] == NULL) { - snprintf(generated_timestamp, sizeof generated_timestamp, "%ld", (long)time(NULL)); - msg->cm_fields['T'] = strdup(generated_timestamp); + if (CM_IsEmpty(msg, eTimestamp)) { + CM_SetFieldLONG(msg, eTimestamp, time(NULL)); } /* If this message has no path, we generate one. */ - if (msg->cm_fields['P'] == NULL) { - if (msg->cm_fields['A'] != NULL) { - msg->cm_fields['P'] = strdup(msg->cm_fields['A']); - for (a=0; !IsEmptyStr(&msg->cm_fields['P'][a]); ++a) { - if (isspace(msg->cm_fields['P'][a])) { - msg->cm_fields['P'][a] = ' '; + if (CM_IsEmpty(msg, eMessagePath)) { + if (!CM_IsEmpty(msg, eAuthor)) { + CM_CopyField(msg, eMessagePath, eAuthor); + for (a=0; !IsEmptyStr(&msg->cm_fields[eMessagePath][a]); ++a) { + if (isspace(msg->cm_fields[eMessagePath][a])) { + msg->cm_fields[eMessagePath][a] = ' '; } } } else { - msg->cm_fields['P'] = strdup("unknown"); + CM_SetField(msg, eMessagePath, HKEY("unknown")); } } if (force == NULL) { - strcpy(force_room, ""); + force_room[0] = '\0'; } else { strcpy(force_room, force); } /* Learn about what's inside, because it's what's inside that counts */ - if (msg->cm_fields['M'] == NULL) { - syslog(LOG_ERR, "ERROR: attempt to save message with NULL body\n"); + if (CM_IsEmpty(msg, eMesageText)) { + MSGM_syslog(LOG_ERR, "ERROR: attempt to save message with NULL body\n"); return(-2); } @@ -3085,7 +3300,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ break; case 4: strcpy(content_type, "text/plain"); - mptr = bmstrcasestr(msg->cm_fields['M'], "Content-type:"); + mptr = bmstrcasestr(msg->cm_fields[eMesageText], "Content-type:"); if (mptr != NULL) { char *aptr; safestrncpy(content_type, &mptr[13], sizeof content_type); @@ -3104,7 +3319,8 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } /* Goto the correct room */ - syslog(LOG_DEBUG, "Selected room %s\n", (recps) ? CCC->room.QRname : SENTITEMS); + 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); if (recps != NULL) { @@ -3116,7 +3332,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ if (CCC->user.axlevel == AxProbU) { strcpy(hold_rm, actual_rm); strcpy(actual_rm, config.c_twitroom); - syslog(LOG_DEBUG, "Diverting to twit room\n"); + MSGM_syslog(LOG_DEBUG, "Diverting to twit room\n"); } } @@ -3125,7 +3341,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ strcpy(actual_rm, force_room); } - syslog(LOG_DEBUG, "Final selection: %s\n", actual_rm); + MSG_syslog(LOG_INFO, "Final selection: %s (%s)\n", actual_rm, room); if (strcasecmp(actual_rm, CCC->room.QRname)) { /* CtdlGetRoom(&CCC->room, actual_rm); */ CtdlUserGoto(actual_rm, 0, 1, NULL, NULL); @@ -3134,12 +3350,12 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* * If this message has no O (room) field, generate one. */ - if (msg->cm_fields['O'] == NULL) { - msg->cm_fields['O'] = strdup(CCC->room.QRname); + if (CM_IsEmpty(msg, eOriginalRoom)) { + CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname)); } /* Perform "before save" hooks (aborting if any return nonzero) */ - syslog(LOG_DEBUG, "Performing before-save hooks\n"); + MSGM_syslog(LOG_DEBUG, "Performing before-save hooks\n"); if (PerformMessageHooks(msg, EVT_BEFORESAVE) > 0) return(-3); /* @@ -3151,7 +3367,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } /* Save it to disk */ - syslog(LOG_DEBUG, "Saving to disk\n"); + MSGM_syslog(LOG_DEBUG, "Saving to disk\n"); newmsgid = send_message(msg); if (newmsgid <= 0L) return(-5); @@ -3159,7 +3375,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * be a critical section because nobody else knows about this message * yet. */ - syslog(LOG_DEBUG, "Creating MetaData record\n"); + MSGM_syslog(LOG_DEBUG, "Creating MetaData record\n"); memset(&smi, 0, sizeof(struct MetaData)); smi.meta_msgnum = newmsgid; smi.meta_refcount = 0; @@ -3177,7 +3393,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * message to attach to the journalized copy. */ if (CCC->redirect_buffer != NULL) { - syslog(LOG_ALERT, "CCC->redirect_buffer is not NULL during message submission!\n"); + MSGM_syslog(LOG_ALERT, "CCC->redirect_buffer is not NULL during message submission!\n"); abort(); } CCC->redirect_buffer = NewStrBufPlain(NULL, SIZ); @@ -3189,7 +3405,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ PutMetaData(&smi); /* Now figure out where to store the pointers */ - syslog(LOG_DEBUG, "Storing pointers\n"); + MSGM_syslog(LOG_DEBUG, "Storing pointers\n"); /* If this is being done by the networker delivering a private * message, we want to BYPASS saving the sender's copy (because there @@ -3197,7 +3413,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ */ if ((!CCC->internal_pgm) || (recps == NULL)) { if (CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 1, msg) != 0) { - syslog(LOG_ERR, "ERROR saving message pointer!\n"); + MSGM_syslog(LOG_ERR, "ERROR saving message pointer!\n"); CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg); } } @@ -3212,12 +3428,12 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ for (i=0; irecp_room, '|'); ++i) { extract_token(recipient, recps->recp_room, i, '|', sizeof recipient); - syslog(LOG_DEBUG, "Delivering to room <%s>\n", recipient); + MSG_syslog(LOG_DEBUG, "Delivering to room <%s>\n", recipient);///// xxxx CtdlSaveMsgPointerInRoom(recipient, newmsgid, 0, msg); } /* Bump this user's messages posted counter. */ - syslog(LOG_DEBUG, "Updating user\n"); + MSGM_syslog(LOG_DEBUG, "Updating user\n"); CtdlGetUserLock(&CCC->user, CCC->curr_user); CCC->user.posted = CCC->user.posted + 1; CtdlPutUserLock(&CCC->user); @@ -3230,7 +3446,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ 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['A'], msg->cm_fields['N']); + snprintf(bounce_to, sizeof bounce_to, "%s@%s", msg->cm_fields[eAuthor], msg->cm_fields[eNodeName]); } /* If this is private, local mail, make a copy in the @@ -3238,9 +3454,11 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ */ if ((recps != NULL) && (recps->num_local > 0)) for (i=0; irecp_local, '|'); ++i) { - extract_token(recipient, recps->recp_local, i, - '|', sizeof recipient); - syslog(LOG_DEBUG, "Delivering private local mail to <%s>\n", + long recipientlen; + recipientlen = extract_token(recipient, + recps->recp_local, i, + '|', sizeof recipient); + MSG_syslog(LOG_DEBUG, "Delivering private local mail to <%s>\n", recipient); if (CtdlGetUser(&userbuf, recipient) == 0) { CtdlMailboxName(actual_rm, sizeof actual_rm, &userbuf, MAILROOM); @@ -3250,13 +3468,17 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* Generate a instruction message for the Funambol notification * server, in the same style as the SMTP queue */ + long instrlen; instr_alloc = 1024; instr = malloc(instr_alloc); - snprintf(instr, instr_alloc, - "Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n" - "bounceto|%s\n", - SPOOLMIME, newmsgid, (long)time(NULL), - bounce_to + instrlen = snprintf( + instr, instr_alloc, + "Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n" + "bounceto|%s\n", + SPOOLMIME, + newmsgid, + (long)time(NULL), //todo: time() is expensive! + bounce_to ); imsg = malloc(sizeof(struct CtdlMessage)); @@ -3264,28 +3486,27 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ imsg->cm_magic = CTDLMESSAGE_MAGIC; imsg->cm_anon_type = MES_NORMAL; imsg->cm_format_type = FMT_RFC822; - imsg->cm_fields['A'] = strdup("Citadel"); - imsg->cm_fields['J'] = strdup("do not journal"); - imsg->cm_fields['M'] = instr; /* imsg owns this memory now */ - imsg->cm_fields['2'] = strdup(recipient); + CM_SetField(imsg, eMsgSubject, HKEY("QMSG")); + CM_SetField(imsg, eAuthor, HKEY("Citadel")); + CM_SetField(imsg, eJournal, HKEY("do not journal")); + CM_SetAsField(imsg, eMesageText, &instr, instrlen); + CM_SetField(imsg, eExtnotify, recipient, recipientlen); CtdlSubmitMsg(imsg, NULL, FNBL_QUEUE_ROOM, 0); - CtdlFreeMessage(imsg); + CM_Free(imsg); } } else { - syslog(LOG_DEBUG, "No user <%s>\n", recipient); + MSG_syslog(LOG_DEBUG, "No user <%s>\n", recipient); CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg); } } /* Perform "after save" hooks */ - syslog(LOG_DEBUG, "Performing after-save hooks\n"); - if (msg->cm_fields['3'] != NULL) free(msg->cm_fields['3']); - msg->cm_fields['3'] = malloc(20); - snprintf(msg->cm_fields['3'], 20, "%ld", newmsgid); + MSGM_syslog(LOG_DEBUG, "Performing after-save hooks\n"); + + CM_SetFieldLONG(msg, eVltMsgNum, newmsgid); PerformMessageHooks(msg, EVT_AFTERSAVE); - free(msg->cm_fields['3']); - msg->cm_fields['3'] = NULL; + CM_FlushField(msg, eVltMsgNum); /* For IGnet mail, we have to save a new copy into the spooler for * each recipient, with the R and D fields set to the recipient and @@ -3300,12 +3521,12 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ extract_token(recipient, recps->recp_ignet, i, '|', sizeof recipient); - hold_R = msg->cm_fields['R']; - hold_D = msg->cm_fields['D']; - msg->cm_fields['R'] = malloc(SIZ); - msg->cm_fields['D'] = malloc(128); - extract_token(msg->cm_fields['R'], recipient, 0, '@', SIZ); - extract_token(msg->cm_fields['D'], recipient, 1, '@', 128); + hold_R = msg->cm_fields[eRecipient]; + hold_D = msg->cm_fields[eDestination]; + msg->cm_fields[eRecipient] = malloc(SIZ); + msg->cm_fields[eDestination] = malloc(128); + extract_token(msg->cm_fields[eRecipient], recipient, 0, '@', SIZ); + extract_token(msg->cm_fields[eDestination], recipient, 1, '@', 128); serialize_message(&smr, msg); if (smr.len > 0) { @@ -3317,22 +3538,22 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ if (network_fp != NULL) { rv = fwrite(smr.ser, smr.len, 1, network_fp); if (rv == -1) { - syslog(LOG_EMERG, "CtdlSubmitMsg(): Couldn't write network spool file: %s\n", - strerror(errno)); + MSG_syslog(LOG_EMERG, "CtdlSubmitMsg(): Couldn't write network spool file: %s\n", + strerror(errno)); } fclose(network_fp); } free(smr.ser); } - free(msg->cm_fields['R']); - free(msg->cm_fields['D']); - msg->cm_fields['R'] = hold_R; - msg->cm_fields['D'] = hold_D; + free(msg->cm_fields[eRecipient]); + free(msg->cm_fields[eDestination]); + msg->cm_fields[eRecipient] = hold_R; + msg->cm_fields[eDestination] = hold_D; } /* Go back to the room we started from */ - syslog(LOG_DEBUG, "Returning to original room %s\n", hold_rm); + MSG_syslog(LOG_DEBUG, "Returning to original room %s\n", hold_rm); if (strcasecmp(hold_rm, CCC->room.QRname)) CtdlUserGoto(hold_rm, 0, 1, NULL, NULL); @@ -3342,29 +3563,41 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * contain a recipient. */ if ((recps != NULL) && (recps->num_internet > 0)) { - syslog(LOG_DEBUG, "Generating delivery instructions\n"); - instr_alloc = 1024; - instr = malloc(instr_alloc); - snprintf(instr, instr_alloc, - "Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n" - "bounceto|%s\n", - SPOOLMIME, newmsgid, (long)time(NULL), - bounce_to - ); + StrBuf *SpoolMsg = NewStrBuf(); + long nTokens; - if (recps->envelope_from != NULL) { - tmp = strlen(instr); - snprintf(&instr[tmp], instr_alloc-tmp, "envelope_from|%s\n", recps->envelope_from); - } + MSGM_syslog(LOG_DEBUG, "Generating delivery instructions\n"); - for (i=0; irecp_internet, '|'); ++i) { - tmp = strlen(instr); - extract_token(recipient, recps->recp_internet, i, '|', sizeof recipient); - if ((tmp + strlen(recipient) + 32) > instr_alloc) { - instr_alloc = instr_alloc * 2; - instr = realloc(instr, instr_alloc); + StrBufPrintf(SpoolMsg, + "Content-type: "SPOOLMIME"\n" + "\n" + "msgid|%ld\n" + "submitted|%ld\n" + "bounceto|%s\n", + newmsgid, + (long)time(NULL), + bounce_to); + + if (recps->envelope_from != NULL) { + StrBufAppendBufPlain(SpoolMsg, HKEY("envelope_from|"), 0); + StrBufAppendBufPlain(SpoolMsg, recps->envelope_from, -1, 0); + StrBufAppendBufPlain(SpoolMsg, HKEY("\n"), 0); + } + if (recps->sending_room != NULL) { + StrBufAppendBufPlain(SpoolMsg, HKEY("source_room|"), 0); + StrBufAppendBufPlain(SpoolMsg, recps->sending_room, -1, 0); + StrBufAppendBufPlain(SpoolMsg, HKEY("\n"), 0); + } + + nTokens = num_tokens(recps->recp_internet, '|'); + for (i = 0; i < nTokens; i++) { + long len; + len = extract_token(recipient, recps->recp_internet, i, '|', sizeof recipient); + if (len > 0) { + StrBufAppendBufPlain(SpoolMsg, HKEY("remote|"), 0); + StrBufAppendBufPlain(SpoolMsg, recipient, len, 0); + StrBufAppendBufPlain(SpoolMsg, HKEY("|0||\n"), 0); } - snprintf(&instr[tmp], instr_alloc - tmp, "remote|%s|0||\n", recipient); } imsg = malloc(sizeof(struct CtdlMessage)); @@ -3372,11 +3605,12 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ imsg->cm_magic = CTDLMESSAGE_MAGIC; imsg->cm_anon_type = MES_NORMAL; imsg->cm_format_type = FMT_RFC822; - imsg->cm_fields['A'] = strdup("Citadel"); - imsg->cm_fields['J'] = strdup("do not journal"); - imsg->cm_fields['M'] = instr; /* imsg owns this memory now */ + imsg->cm_fields[eMsgSubject] = strdup("QMSG"); + imsg->cm_fields[eAuthor] = strdup("Citadel"); + imsg->cm_fields[eJournal] = strdup("do not journal"); + imsg->cm_fields[eMesageText] = SmashStrBuf(&SpoolMsg); /* imsg owns this memory now */ CtdlSubmitMsg(imsg, NULL, SMTP_SPOOLOUT_ROOM, QP_EADDR); - CtdlFreeMessage(imsg); + CM_Free(imsg); } /* @@ -3402,7 +3636,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* * Determine whether this message qualifies for journaling. */ - if (msg->cm_fields['J'] != NULL) { + if (!CM_IsEmpty(msg, eJournal)) { qualified_for_journaling = 0; } else { @@ -3436,18 +3670,16 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } - -void aide_message (char *text, char *subject) -{ - quickie_message("Citadel",NULL,NULL,AIDEROOM,text,FMT_CITADEL,subject); -} - - /* * Convenience function for generating small administrative messages. */ -void quickie_message(const char *from, const char *fromaddr, char *to, char *room, const char *text, - int format_type, const char *subject) +void quickie_message(const char *from, + const char *fromaddr, + const char *to, + char *room, + const char *text, + int format_type, + const char *subject) { struct CtdlMessage *msg; struct recptypes *recp = NULL; @@ -3459,35 +3691,98 @@ void quickie_message(const char *from, const char *fromaddr, char *to, char *roo msg->cm_format_type = format_type; if (from != NULL) { - msg->cm_fields['A'] = strdup(from); + msg->cm_fields[eAuthor] = strdup(from); } else if (fromaddr != NULL) { - msg->cm_fields['A'] = strdup(fromaddr); - if (strchr(msg->cm_fields['A'], '@')) { - *strchr(msg->cm_fields['A'], '@') = 0; + msg->cm_fields[eAuthor] = strdup(fromaddr); + if (strchr(msg->cm_fields[eAuthor], '@')) { + *strchr(msg->cm_fields[eAuthor], '@') = 0; } } else { - msg->cm_fields['A'] = strdup("Citadel"); + msg->cm_fields[eAuthor] = strdup("Citadel"); } - if (fromaddr != NULL) msg->cm_fields['F'] = strdup(fromaddr); - if (room != NULL) msg->cm_fields['O'] = strdup(room); - msg->cm_fields['N'] = strdup(NODENAME); + if (fromaddr != NULL) msg->cm_fields[erFc822Addr] = strdup(fromaddr); + if (room != NULL) msg->cm_fields[eOriginalRoom] = strdup(room); + msg->cm_fields[eNodeName] = strdup(NODENAME); if (to != NULL) { - msg->cm_fields['R'] = strdup(to); + msg->cm_fields[eRecipient] = strdup(to); recp = validate_recipients(to, NULL, 0); } if (subject != NULL) { - msg->cm_fields['U'] = strdup(subject); + msg->cm_fields[eMsgSubject] = strdup(subject); } - msg->cm_fields['M'] = strdup(text); + msg->cm_fields[eMesageText] = strdup(text); CtdlSubmitMsg(msg, recp, room, 0); - CtdlFreeMessage(msg); + 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; + time_t tsday = NOW / (8*60*60); /* just care for a day... */ + + 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); + + if (CheckIfAlreadySeen("FPAideMessage", + guid, + NOW, + tsday, + eUpdate, + ccid, + ioid)!= 0) + { + FreeStrBuf(&guid); + /* yes, we did. flood protection kicks in. */ + syslog(LOG_DEBUG, + "not sending message again\n"); + return; + } + FreeStrBuf(&guid); + /* no, this message isn't sent recently; go ahead. */ + quickie_message(from, + fromaddr, + to, + room, + text, + format_type, + subject); +} /* @@ -3496,7 +3791,7 @@ void quickie_message(const char *from, const char *fromaddr, char *to, char *roo StrBuf *CtdlReadMessageBodyBuf(char *terminator, /* token signalling EOT */ long tlen, size_t maxlen, /* maximum message length */ - char *exist, /* if non-null, append to it; + 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 */ @@ -3513,8 +3808,7 @@ StrBuf *CtdlReadMessageBodyBuf(char *terminator, /* token signalling EOT */ Message = NewStrBufPlain(NULL, 4 * SIZ); } else { - Message = NewStrBufPlain(exist, -1); - free(exist); + Message = NewStrBufDup(exist); } /* Do we need to change leading ".." to "." for SMTP escaping? */ @@ -3577,7 +3871,7 @@ 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? */ - char *exist, /* if non-null, append to it; + StrBuf *exist, /* if non-null, append to it; exist is ALWAYS freed */ long eLen, /* length of exist */ int crlf /* CRLF newlines instead of LF */ @@ -3600,8 +3894,7 @@ ReadAsyncMsg *NewAsyncMsg(const char *terminator, /* token signalling EOT */ NewMsg->MsgBuf = NewStrBufPlain(NULL, len); } else { - NewMsg->MsgBuf = NewStrBufPlain(exist, eLen); - free(exist); + NewMsg->MsgBuf = NewStrBufDup(exist); } /* Do we need to change leading ".." to "." for SMTP escaping? */ if ((tlen == 1) && (*terminator == '.')) { @@ -3734,7 +4027,7 @@ eReadState CtdlReadMessageBodyAsync(AsyncIO *IO) char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ long tlen, size_t maxlen, /* maximum message length */ - char *exist, /* if non-null, append to it; + 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 */ @@ -3760,7 +4053,7 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ * (NOTE: if you supply 'preformatted_text', the buffer you give it * will become part of the message. This means you are no longer * responsible for managing that memory -- it will be freed along with - * the rest of the fields when CtdlFreeMessage() is called.) + * the rest of the fields when CM_Free() is called.) */ struct CtdlMessage *CtdlMakeMessage( @@ -3799,16 +4092,16 @@ struct CtdlMessage *CtdlMakeMessage( if (my_email == NULL) my_email = ""; if (!IsEmptyStr(my_email)) { - msg->cm_fields['P'] = strdup(my_email); + msg->cm_fields[eMessagePath] = strdup(my_email); } else { snprintf(buf, sizeof buf, "%s", author->fullname); - msg->cm_fields['P'] = strdup(buf); + msg->cm_fields[eMessagePath] = strdup(buf); } - convert_spaces_to_underscores(msg->cm_fields['P']); + convert_spaces_to_underscores(msg->cm_fields[eMessagePath]); snprintf(buf, sizeof buf, "%ld", (long)time(NULL)); /* timestamp */ - msg->cm_fields['T'] = strdup(buf); + msg->cm_fields[eTimestamp] = strdup(buf); if ((fake_name != NULL) && (fake_name[0])) { /* author */ FakeAuthor = NewStrBufPlain (fake_name, -1); @@ -3817,34 +4110,34 @@ struct CtdlMessage *CtdlMakeMessage( FakeAuthor = NewStrBufPlain (author->fullname, -1); } StrBufRFC2047encode(&FakeEncAuthor, FakeAuthor); - msg->cm_fields['A'] = SmashStrBuf(&FakeEncAuthor); + msg->cm_fields[eAuthor] = SmashStrBuf(&FakeEncAuthor); FreeStrBuf(&FakeAuthor); if (CC->room.QRflags & QR_MAILBOX) { /* room */ - msg->cm_fields['O'] = strdup(&CC->room.QRname[11]); + msg->cm_fields[eOriginalRoom] = strdup(&CC->room.QRname[11]); } else { - msg->cm_fields['O'] = strdup(CC->room.QRname); + msg->cm_fields[eOriginalRoom] = strdup(CC->room.QRname); } - msg->cm_fields['N'] = strdup(NODENAME); /* nodename */ - msg->cm_fields['H'] = strdup(HUMANNODE); /* hnodename */ + msg->cm_fields[eNodeName] = strdup(NODENAME); /* nodename */ + msg->cm_fields[eHumanNode] = strdup(HUMANNODE); /* hnodename */ if ((recipient != NULL) && (recipient[0] != 0)) { - msg->cm_fields['R'] = strdup(recipient); + msg->cm_fields[eRecipient] = strdup(recipient); } if ((recp_cc != NULL) && (recp_cc[0] != 0)) { - msg->cm_fields['Y'] = strdup(recp_cc); + msg->cm_fields[eCarbonCopY] = strdup(recp_cc); } if (dest_node[0] != 0) { - msg->cm_fields['D'] = strdup(dest_node); + msg->cm_fields[eDestination] = strdup(dest_node); } if (!IsEmptyStr(my_email)) { - msg->cm_fields['F'] = strdup(my_email); + msg->cm_fields[erFc822Addr] = strdup(my_email); } else if ( (author == &CC->user) && (!IsEmptyStr(CC->cs_inet_email)) ) { - msg->cm_fields['F'] = strdup(CC->cs_inet_email); + msg->cm_fields[erFc822Addr] = strdup(CC->cs_inet_email); } if (subject != NULL) { @@ -3860,40 +4153,35 @@ struct CtdlMessage *CtdlMakeMessage( (IsAscii = isascii(subject[i]) != 0 )) i++; if (IsAscii != 0) - msg->cm_fields['U'] = strdup(subject); + msg->cm_fields[eMsgSubject] = strdup(subject); else /* ok, we've got utf8 in the string. */ { - msg->cm_fields['U'] = rfc2047encode(subject, length); + msg->cm_fields[eMsgSubject] = rfc2047encode(subject, length); } } } if (supplied_euid != NULL) { - msg->cm_fields['E'] = strdup(supplied_euid); + msg->cm_fields[eExclusiveID] = strdup(supplied_euid); } if ((references != NULL) && (!IsEmptyStr(references))) { - if (msg->cm_fields['W'] != NULL) - free(msg->cm_fields['W']); - msg->cm_fields['W'] = strdup(references); + if (msg->cm_fields[eWeferences] != NULL) + free(msg->cm_fields[eWeferences]); + msg->cm_fields[eWeferences] = strdup(references); } if (preformatted_text != NULL) { - msg->cm_fields['M'] = preformatted_text; + msg->cm_fields[eMesageText] = preformatted_text; } else { - msg->cm_fields['M'] = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0); + msg->cm_fields[eMesageText] = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0); } return(msg); } -extern int netconfig_check_roomaccess( - char *errmsgbuf, - size_t n, - const char* RemoteIdentifier); /* TODO: find a smarter way */ - /* * Check to see whether we have permission to post a message in the current * room. Returns a *CITADEL ERROR CODE* and puts a message in errmsgbuf, or @@ -3928,7 +4216,7 @@ int CtdlDoIHavePermissionToPostInThisRoom( } if ((PostPublic!=POST_LMTP) &&(CC->room.QRflags2 & QR2_SMTP_PUBLIC) == 0) { - return netconfig_check_roomaccess(errmsgbuf, n, RemoteIdentifier); + return CtdlNetconfigCheckRoomaccess(errmsgbuf, n, RemoteIdentifier); } return (0); @@ -3984,7 +4272,7 @@ int CtdlCheckInternetMailPermission(struct ctdluser *who) { /* User flagged ok? */ if (who->flags & US_INTERNET) return(2); - /* Aide level access? */ + /* Admin level access? */ if (who->axlevel >= AxAideU) return(3); /* No mail for you! */ @@ -4004,11 +4292,14 @@ int CtdlCheckInternetMailPermission(struct ctdluser *who) { struct recptypes *validate_recipients(const char *supplied_recipients, const char *RemoteIdentifier, int Flags) { + struct CitContext *CCC = CC; struct recptypes *ret; char *recipients = NULL; + char *org_recp; char this_recp[256]; char this_recp_cooked[256]; char append[SIZ]; + long len; int num_recps = 0; int i, j; int mailtype; @@ -4038,19 +4329,22 @@ struct recptypes *validate_recipients(const char *supplied_recipients, * actually need, but it's healthier for the heap than doing lots of tiny * realloc() calls instead. */ - - ret->errormsg = malloc(strlen(recipients) + 1024); - ret->recp_local = malloc(strlen(recipients) + 1024); - ret->recp_internet = malloc(strlen(recipients) + 1024); - ret->recp_ignet = malloc(strlen(recipients) + 1024); - ret->recp_room = malloc(strlen(recipients) + 1024); - ret->display_recp = malloc(strlen(recipients) + 1024); + len = strlen(recipients) + 1024; + ret->errormsg = malloc(len); + ret->recp_local = malloc(len); + ret->recp_internet = malloc(len); + ret->recp_ignet = malloc(len); + ret->recp_room = malloc(len); + ret->display_recp = malloc(len); + ret->recp_orgroom = malloc(len); + org_recp = malloc(len); ret->errormsg[0] = 0; ret->recp_local[0] = 0; ret->recp_internet[0] = 0; ret->recp_ignet[0] = 0; ret->recp_room[0] = 0; + ret->recp_orgroom[0] = 0; ret->display_recp[0] = 0; ret->recptypes_magic = RECPTYPES_MAGIC; @@ -4065,7 +4359,6 @@ struct recptypes *validate_recipients(const char *supplied_recipients, /* Now start extracting recipients... */ while (!IsEmptyStr(recipients)) { - for (i=0; i<=strlen(recipients); ++i) { if (recipients[i] == '\"') in_quotes = 1 - in_quotes; if ( ( (recipients[i] == ',') && (!in_quotes) ) || (recipients[i] == 0) ) { @@ -4084,13 +4377,15 @@ struct recptypes *validate_recipients(const char *supplied_recipients, striplt(this_recp); if (IsEmptyStr(this_recp)) break; - syslog(LOG_DEBUG, "Evaluating recipient #%d: %s\n", num_recps, this_recp); + MSG_syslog(LOG_DEBUG, "Evaluating recipient #%d: %s\n", num_recps, this_recp); ++num_recps; + + strcpy(org_recp, this_recp); + alias(this_recp); + alias(this_recp); mailtype = alias(this_recp); - mailtype = alias(this_recp); - mailtype = alias(this_recp); - j = 0; - for (j=0; !IsEmptyStr(&this_recp[j]); ++j) { + + for (j = 0; !IsEmptyStr(&this_recp[j]); ++j) { if (this_recp[j]=='_') { this_recp_cooked[j] = ' '; } @@ -4115,8 +4410,8 @@ struct recptypes *validate_recipients(const char *supplied_recipients, && (!CtdlGetRoom(&tempQR, &this_recp_cooked[5])) ) { /* Save room so we can restore it later */ - tempQR2 = CC->room; - CC->room = tempQR; + tempQR2 = CCC->room; + CCC->room = tempQR; /* Check permissions to send mail to this room */ err = CtdlDoIHavePermissionToPostInThisRoom( @@ -4137,10 +4432,16 @@ struct recptypes *validate_recipients(const char *supplied_recipients, strcat(ret->recp_room, "|"); } strcat(ret->recp_room, &this_recp_cooked[5]); + + if (!IsEmptyStr(ret->recp_orgroom)) { + strcat(ret->recp_orgroom, "|"); + } + strcat(ret->recp_orgroom, org_recp); + } /* Restore room in case something needs it */ - CC->room = tempQR2; + CCC->room = tempQR2; } else if (CtdlGetUser(&tempUS, this_recp) == 0) { @@ -4221,6 +4522,7 @@ struct recptypes *validate_recipients(const char *supplied_recipients, } } } + free(org_recp); if ((ret->num_local + ret->num_internet + ret->num_ignet + ret->num_room + ret->num_error) == 0) { @@ -4228,12 +4530,12 @@ struct recptypes *validate_recipients(const char *supplied_recipients, strcpy(ret->errormsg, "No recipients specified."); } - syslog(LOG_DEBUG, "validate_recipients()\n"); - syslog(LOG_DEBUG, " local: %d <%s>\n", ret->num_local, ret->recp_local); - syslog(LOG_DEBUG, " room: %d <%s>\n", ret->num_room, ret->recp_room); - syslog(LOG_DEBUG, " inet: %d <%s>\n", ret->num_internet, ret->recp_internet); - syslog(LOG_DEBUG, " ignet: %d <%s>\n", ret->num_ignet, ret->recp_ignet); - syslog(LOG_DEBUG, " error: %d <%s>\n", ret->num_error, ret->errormsg); + MSGM_syslog(LOG_DEBUG, "validate_recipients()\n"); + MSG_syslog(LOG_DEBUG, " local: %d <%s>\n", ret->num_local, ret->recp_local); + MSG_syslog(LOG_DEBUG, " room: %d <%s>\n", ret->num_room, ret->recp_room); + MSG_syslog(LOG_DEBUG, " inet: %d <%s>\n", ret->num_internet, ret->recp_internet); + MSG_syslog(LOG_DEBUG, " ignet: %d <%s>\n", ret->num_ignet, ret->recp_ignet); + MSG_syslog(LOG_DEBUG, " error: %d <%s>\n", ret->num_error, ret->errormsg); free(recipients); return(ret); @@ -4250,7 +4552,8 @@ void free_recipients(struct recptypes *valid) { } if (valid->recptypes_magic != RECPTYPES_MAGIC) { - syslog(LOG_EMERG, "Attempt to call free_recipients() on some other data type!\n"); + struct CitContext *CCC = CC; + MSGM_syslog(LOG_EMERG, "Attempt to call free_recipients() on some other data type!\n"); abort(); } @@ -4259,9 +4562,11 @@ void free_recipients(struct recptypes *valid) { if (valid->recp_internet != NULL) free(valid->recp_internet); if (valid->recp_ignet != NULL) free(valid->recp_ignet); if (valid->recp_room != NULL) free(valid->recp_room); + if (valid->recp_orgroom != NULL) free(valid->recp_orgroom); if (valid->display_recp != NULL) free(valid->display_recp); if (valid->bounce_to != NULL) free(valid->bounce_to); if (valid->envelope_from != NULL) free(valid->envelope_from); + if (valid->sending_room != NULL) free(valid->sending_room); free(valid); } @@ -4293,7 +4598,6 @@ void cmd_ent0(char *entargs) char subject[SIZ]; int subject_required = 0; int do_confirm = 0; - int verbose_reply = 0; long msgnum; int i, j; char buf[256]; @@ -4312,7 +4616,6 @@ void cmd_ent0(char *entargs) do_confirm = extract_int(entargs, 6); extract_token(cc, entargs, 7, '|', sizeof cc); extract_token(bcc, entargs, 8, '|', sizeof bcc); - verbose_reply = extract_int(entargs, 9); switch(CC->room.QRdefaultview) { case VIEW_NOTES: case VIEW_WIKI: @@ -4554,36 +4857,39 @@ void cmd_ent0(char *entargs) } free(all_recps); + if ((valid != NULL) && (valid->num_room == 1)) + { + /* posting into an ML room? set the envelope from + * to the actual mail address so others get a valid + * reply-to-header. + */ + msg->cm_fields[eenVelopeTo] = strdup(valid->recp_orgroom); + } + if (msg != NULL) { msgnum = CtdlSubmitMsg(msg, valid, "", QP_EADDR); - if (verbose_reply) - { - if (StrLength(CCC->StatusMessage)>0) - { - StrBufAppendBufPlain(CCC->StatusMessage, HKEY("\n000\n"), 0); - cputbuf(CCC->StatusMessage); - } - else - client_write(HKEY("\n000\n")); - } - if (do_confirm) { cprintf("%ld\n", msgnum); - if (msgnum >= 0L) { + + if (StrLength(CCC->StatusMessage) > 0) { + cprintf("%s\n", ChrPtr(CCC->StatusMessage)); + } + else if (msgnum >= 0L) { client_write(HKEY("Message accepted.\n")); } else { client_write(HKEY("Internal error.\n")); } - if (msg->cm_fields['E'] != NULL) { - cprintf("%s\n", msg->cm_fields['E']); + + if (!CM_IsEmpty(msg, eExclusiveID)) { + cprintf("%s\n", msg->cm_fields[eExclusiveID]); } else { cprintf("\n"); } cprintf("000\n"); } - CtdlFreeMessage(msg); + CM_Free(msg); } if (valid != NULL) { free_recipients(valid); @@ -4603,6 +4909,7 @@ int CtdlDeleteMessages(char *room_name, /* which room */ char *content_type /* or "" for any. regular expressions expected. */ ) { + struct CitContext *CCC = CC; struct ctdlroom qrbuf; struct cdbdata *cdbfr; long *msglist = NULL; @@ -4620,13 +4927,13 @@ int CtdlDeleteMessages(char *room_name, /* which room */ regcomp(&re, content_type, 0); need_to_free_re = 1; } - syslog(LOG_DEBUG, "CtdlDeleteMessages(%s, %d msgs, %s)\n", - room_name, num_dmsgnums, content_type); + MSG_syslog(LOG_DEBUG, " CtdlDeleteMessages(%s, %d msgs, %s)\n", + room_name, num_dmsgnums, content_type); /* get room record, obtaining a lock... */ if (CtdlGetRoomLock(&qrbuf, room_name) != 0) { - syslog(LOG_ERR, "CtdlDeleteMessages(): Room <%s> not found\n", - room_name); + MSG_syslog(LOG_ERR, " CtdlDeleteMessages(): Room <%s> not found\n", + room_name); if (need_to_free_re) regfree(&re); return (0); /* room not found */ } @@ -4640,7 +4947,24 @@ int CtdlDeleteMessages(char *room_name, /* which room */ cdb_free(cdbfr); } if (num_msgs > 0) { - for (i = 0; i < num_msgs; ++i) { + int have_contenttype = (content_type != NULL) && !IsEmptyStr(content_type); + int have_delmsgs = (num_dmsgnums == 0) || (dmsgnums == NULL); + int have_more_del = 1; + + num_msgs = sort_msglist(msglist, num_msgs); + if (num_dmsgnums > 1) + num_dmsgnums = sort_msglist(dmsgnums, num_dmsgnums); +/* + { + StrBuf *dbg = NewStrBuf(); + for (i = 0; i < num_dmsgnums; i++) + StrBufAppendPrintf(dbg, ", %ld", dmsgnums[i]); + MSG_syslog(LOG_DEBUG, " Deleting before: %s", ChrPtr(dbg)); + FreeStrBuf(&dbg); + } +*/ + i = 0; j = 0; + while ((i < num_msgs) && (have_more_del)) { delete_this = 0x00; /* Set/clear a bit for each criterion */ @@ -4648,24 +4972,29 @@ int CtdlDeleteMessages(char *room_name, /* which room */ /* 0 messages in the list or a null list means that we are * interested in deleting any messages which meet the other criteria. */ - if ((num_dmsgnums == 0) || (dmsgnums == NULL)) { + if (have_delmsgs) { delete_this |= 0x01; } else { - for (j=0; j= num_msgs) + continue; + + if (msglist[i] == dmsgnums[j]) { + delete_this |= 0x01; } + j++; + have_more_del = (j < num_dmsgnums); } - if (IsEmptyStr(content_type)) { - delete_this |= 0x02; - } else { + if (have_contenttype) { GetMetaData(&smi, msglist[i]); if (regexec(&re, smi.meta_content_type, 1, &pm, 0) == 0) { delete_this |= 0x02; } + } else { + delete_this |= 0x02; } /* Delete message only if all bits are set */ @@ -4673,8 +5002,17 @@ int CtdlDeleteMessages(char *room_name, /* which room */ dellist[num_deleted++] = msglist[i]; msglist[i] = 0L; } + i++; } - +/* + { + StrBuf *dbg = NewStrBuf(); + for (i = 0; i < num_deleted; i++) + StrBufAppendPrintf(dbg, ", %ld", dellist[i]); + MSG_syslog(LOG_DEBUG, " Deleting: %s", ChrPtr(dbg)); + FreeStrBuf(&dbg); + } +*/ num_msgs = sort_msglist(msglist, num_msgs); cdb_store(CDB_MSGLISTS, &qrbuf.QRnumber, (int)sizeof(long), msglist, (int)(num_msgs * sizeof(long))); @@ -4694,15 +5032,16 @@ int CtdlDeleteMessages(char *room_name, /* which room */ * and we don't want that happening during an S_ROOMS critical * section. */ - if (num_deleted) for (i=0; iuser.axlevel >= AxAideU) permit = 1; /* Room aides can move/copy */ @@ -4933,22 +5272,23 @@ void PutMetaData(struct MetaData *smibuf) */ void AdjRefCount(long msgnum, int incr) { + struct CitContext *CCC = CC; struct arcq new_arcq; int rv = 0; - syslog(LOG_DEBUG, "AdjRefCount() msg %ld ref count delta %+d\n", - msgnum, incr - ); + 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) { - syslog(LOG_DEBUG, "Closing the AdjRefCount queue file\n"); + MSGM_syslog(LOG_DEBUG, "Closing the AdjRefCount queue file\n"); begin_critical_section(S_SUPPMSGMAIN); if (arcfp != NULL) { fclose(arcfp); @@ -4970,10 +5310,62 @@ void AdjRefCount(long msgnum, int incr) new_arcq.arcq_delta = incr; rv = fwrite(&new_arcq, sizeof(struct arcq), 1, arcfp); if (rv == -1) { - syslog(LOG_EMERG, "Couldn't write Refcount Queue File %s: %s\n", - file_arcq, - strerror(errno)); + 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; + } + + 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; + } + 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; @@ -4989,6 +5381,7 @@ void AdjRefCount(long msgnum, int incr) */ int TDAP_ProcessAdjRefCountQueue(void) { + struct CitContext *CCC = CC; char file_arcq_temp[PATH_MAX]; int r; FILE *fp; @@ -5005,7 +5398,7 @@ int TDAP_ProcessAdjRefCountQueue(void) r = link(file_arcq, file_arcq_temp); if (r != 0) { - syslog(LOG_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno)); + MSG_syslog(LOG_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno)); end_critical_section(S_SUPPMSGMAIN); return(num_records_processed); } @@ -5015,7 +5408,7 @@ int TDAP_ProcessAdjRefCountQueue(void) fp = fopen(file_arcq_temp, "rb"); if (fp == NULL) { - syslog(LOG_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno)); + MSG_syslog(LOG_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno)); return(num_records_processed); } @@ -5027,7 +5420,7 @@ int TDAP_ProcessAdjRefCountQueue(void) fclose(fp); r = unlink(file_arcq_temp); if (r != 0) { - syslog(LOG_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno)); + MSG_syslog(LOG_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno)); } return(num_records_processed); @@ -5045,6 +5438,7 @@ int TDAP_ProcessAdjRefCountQueue(void) */ void TDAP_AdjRefCount(long msgnum, int incr) { + struct CitContext *CCC = CC; struct MetaData smi; long delnum; @@ -5058,15 +5452,15 @@ void TDAP_AdjRefCount(long msgnum, int incr) smi.meta_refcount += incr; PutMetaData(&smi); end_critical_section(S_SUPPMSGMAIN); - syslog(LOG_DEBUG, "TDAP_AdjRefCount() msg %ld ref count delta %+d, is now %d\n", - msgnum, incr, smi.meta_refcount + MSG_syslog(LOG_DEBUG, "TDAP_AdjRefCount() msg %ld ref count delta %+d, is now %d\n", + msgnum, incr, smi.meta_refcount ); /* If the reference count is now zero, delete the message * (and its supplementary record as well). */ if (smi.meta_refcount == 0) { - syslog(LOG_DEBUG, "Deleting message <%ld>\n", msgnum); + MSG_syslog(LOG_DEBUG, "Deleting message <%ld>\n", msgnum); /* Call delete hooks with NULL room to show it has gone altogether */ PerformDeleteHooks(NULL, msgnum); @@ -5099,7 +5493,7 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ unsigned int flags /* Internal save flags */ ) { - + struct CitContext *CCC = CC; struct ctdlroom qrbuf; char roomname[ROOMNAMELEN]; struct CtdlMessage *msg; @@ -5112,7 +5506,7 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ safestrncpy(roomname, req_room, sizeof(roomname)); } - syslog(LOG_DEBUG, "Raw length is %ld\n", (long)raw_length); + MSG_syslog(LOG_DEBUG, "Raw length is %ld\n", (long)raw_length); if (is_binary) { encoded_message = malloc((size_t) (((raw_length * 134) / 100) + 4096 ) ); @@ -5150,19 +5544,19 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ ); } - syslog(LOG_DEBUG, "Allocating\n"); + MSGM_syslog(LOG_DEBUG, "Allocating\n"); 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; - msg->cm_fields['A'] = strdup(CC->user.fullname); - msg->cm_fields['O'] = strdup(req_room); - msg->cm_fields['N'] = strdup(config.c_nodename); - msg->cm_fields['H'] = strdup(config.c_humannode); + msg->cm_fields[eAuthor] = strdup(CCC->user.fullname); + msg->cm_fields[eOriginalRoom] = strdup(req_room); + msg->cm_fields[eNodeName] = strdup(config.c_nodename); + msg->cm_fields[eHumanNode] = strdup(config.c_humannode); msg->cm_flags = flags; - msg->cm_fields['M'] = encoded_message; + msg->cm_fields[eMesageText] = encoded_message; /* Create the requested room if we have to. */ if (CtdlGetRoom(&qrbuf, roomname) != 0) { @@ -5174,13 +5568,13 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ * other objects of this type that are currently in the room. */ if (is_unique) { - syslog(LOG_DEBUG, "Deleted %d other msgs of this type\n", - CtdlDeleteMessages(roomname, NULL, 0, content_type) + MSG_syslog(LOG_DEBUG, "Deleted %d other msgs of this type\n", + CtdlDeleteMessages(roomname, NULL, 0, content_type) ); } /* Now write the data */ CtdlSubmitMsg(msg, NULL, roomname, 0); - CtdlFreeMessage(msg); + CM_Free(msg); } @@ -5221,8 +5615,8 @@ char *CtdlGetSysConfig(char *sysconfname) { else { msg = CtdlFetchMessage(msgnum, 1); if (msg != NULL) { - conf = strdup(msg->cm_fields['M']); - CtdlFreeMessage(msg); + conf = strdup(msg->cm_fields[eMesageText]); + CM_Free(msg); } else { conf = NULL; @@ -5296,10 +5690,15 @@ void cmd_isme(char *argbuf) { /*****************************************************************************/ /* MODULE INITIALIZATION STUFF */ /*****************************************************************************/ - +void SetMessageDebugEnabled(const int n) +{ + MessageDebugEnabled = n; +} CTDL_MODULE_INIT(msgbase) { if (!threading) { + CtdlRegisterDebugFlagHook(HKEY("messages"), SetMessageDebugEnabled, &MessageDebugEnabled); + CtdlRegisterProtoHook(cmd_msgs, "MSGS", "Output a list of messages in the current room"); CtdlRegisterProtoHook(cmd_msg0, "MSG0", "Output a message in plain text format"); CtdlRegisterProtoHook(cmd_msg2, "MSG2", "Output a message in RFC822 format");