X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmsgbase.c;h=568cefb2e06f6c57175510351cbf1b05acf5b049;hb=0b0f8a2280a8f22877baccd2355d7b41b863bfa0;hp=1bff449e2f9002fbaf70bd690fe757eeec98b2bb;hpb=88883a6bf9e4859707fb43c3cd3608fb5166f76c;p=citadel.git diff --git a/citadel/msgbase.c b/citadel/msgbase.c index 1bff449e2..568cefb2e 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 @@ -96,7 +96,7 @@ char *msgkeys[] = { "hnod", "msgn", "jrnl", - NULL, + "rep2", "list", "text", "node", @@ -142,6 +142,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 +191,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 +199,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); } } } @@ -346,10 +347,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 +367,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 +391,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 +436,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 +569,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 +598,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 +623,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 +672,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,6 +694,11 @@ 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)) { @@ -734,6 +761,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 +788,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 +803,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); @@ -935,6 +967,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 +981,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 +999,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 +1021,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 +1037,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; @@ -1084,26 +1117,37 @@ void mime_download(char *name, char *filename, char *partnum, char *disp, char *encoding, char *cbid, void *cbuserdata) { int rv = 0; + CitContext *CCC = MyContext(); /* Silently go away if there's already a download open. */ - if (CC->download_fp != NULL) + if (CCC->download_fp != NULL) return; if ( - (!IsEmptyStr(partnum) && (!strcasecmp(CC->download_desired_section, partnum))) - || (!IsEmptyStr(cbid) && (!strcasecmp(CC->download_desired_section, cbid))) + (!IsEmptyStr(partnum) && (!strcasecmp(CCC->download_desired_section, partnum))) + || (!IsEmptyStr(cbid) && (!strcasecmp(CCC->download_desired_section, cbid))) ) { - CC->download_fp = tmpfile(); - if (CC->download_fp == NULL) + CCC->download_fp = tmpfile(); + if (CCC->download_fp == NULL) { + MSG_syslog(LOG_EMERG, "mime_download(): Couldn't write: %s\n", + strerror(errno)); + cprintf("%d cannot open temporary file: %s\n", + ERROR + INTERNAL_ERROR, strerror(errno)); return; + } rv = fwrite(content, length, 1, CC->download_fp); - if (rv == -1) { - syslog(LOG_EMERG, "mime_download(): Couldn't write: %s\n", - strerror(errno)); + if (rv <= 0) { + MSG_syslog(LOG_EMERG, "mime_download(): Couldn't write: %s\n", + strerror(errno)); + cprintf("%d unable to write tempfile.\n", + ERROR + TOO_BIG); + fclose(CCC->download_fp); + CCC->download_fp = NULL; + return; } - fflush(CC->download_fp); - rewind(CC->download_fp); + fflush(CCC->download_fp); + rewind(CCC->download_fp); OpenCmdResult(filename, cbtype); } @@ -1147,6 +1191,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; @@ -1154,7 +1199,7 @@ 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) { return NULL; @@ -1169,7 +1214,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; } @@ -1233,32 +1278,35 @@ 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"); + struct CitContext *CCC = CC; + MSGM_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) { - int i; - if (is_valid_message(msg) == 0) { if (msg != NULL) free (msg); return; } - - for (i = 0; i < 256; ++i) - if (msg->cm_fields[i] != NULL) { - free(msg->cm_fields[i]); - } - - msg->cm_magic = 0; /* just in case */ + CtdlFreeMessageContents(msg); free(msg); } @@ -1277,10 +1325,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; @@ -1297,10 +1346,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; @@ -1317,6 +1367,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; @@ -1324,7 +1375,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); @@ -1333,7 +1384,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; @@ -1354,7 +1405,7 @@ void fixed_output(char *name, char *filename, char *partnum, char *disp, ptr = html_to_ascii(content, length, 80, 0); wlen = strlen(ptr); client_write(ptr, wlen); - if (ptr[wlen-1] != '\n') { + if ((wlen > 0) && (ptr[wlen-1] != '\n')) { cprintf("\n"); } free(ptr); @@ -1390,6 +1441,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; @@ -1401,11 +1453,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; } @@ -1428,6 +1480,7 @@ void output_preferred(char *name, char *cbid, void *cbuserdata) { + struct CitContext *CCC = CC; int i; char buf[128]; int add_newline = 0; @@ -1445,8 +1498,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) @@ -1483,7 +1536,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"); @@ -1549,12 +1602,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 */ @@ -1563,7 +1617,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]) { @@ -1603,14 +1657,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 : "<>") ); @@ -1638,8 +1695,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) { @@ -1680,6 +1737,17 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ *extract_encapsulated_message, NULL, NULL, (void *)&encap, 0 ); + + if ((Author != NULL) && (*Author == NULL)) + { + *Author = TheMessage->cm_fields['A']; + TheMessage->cm_fields['A'] = NULL; + } + if ((Address != NULL) && (*Address == NULL)) + { + *Address = TheMessage->cm_fields['F']; + TheMessage->cm_fields['F'] = NULL; + } CtdlFreeMessage(TheMessage); TheMessage = NULL; @@ -1696,15 +1764,31 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ } 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); + if (retcode == CIT_OK) + retcode = CtdlOutputPreLoadedMsg(TheMessage, mode, headers_only, do_proto, crlf, flags); + if ((Author != NULL) && (*Author == NULL)) + { + *Author = TheMessage->cm_fields['A']; + TheMessage->cm_fields['A'] = NULL; + } + if ((Address != NULL) && (*Address == NULL)) + { + *Address = TheMessage->cm_fields['F']; + TheMessage->cm_fields['F'] = NULL; + } + CtdlFreeMessage(TheMessage); return(retcode); @@ -1713,6 +1797,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; @@ -1731,8 +1816,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); @@ -2116,7 +2201,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; @@ -2124,7 +2210,6 @@ void Dump_RFC822HeadersBody( } if (outlen > 0) { client_write(outbuf, outlen); - outlen = 0; } } @@ -2187,7 +2272,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'; @@ -2214,6 +2300,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 */ @@ -2229,16 +2316,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"); + MSGM_syslog(LOG_ERR, + "ERROR: invalid preloaded message for output\n"); cit_backtrace (); return(om_no_such_msg); } @@ -2256,7 +2343,7 @@ 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); @@ -2267,14 +2354,14 @@ int CtdlOutputPreLoadedMsg( /* 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 @@ -2297,10 +2384,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 */ @@ -2448,7 +2535,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); @@ -2481,7 +2568,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; } @@ -2497,7 +2584,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); } @@ -2551,7 +2638,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); } @@ -2584,7 +2671,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); } @@ -2600,8 +2687,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); +} /* @@ -2618,6 +2705,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; @@ -2631,12 +2719,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); @@ -2644,10 +2732,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); } @@ -2656,7 +2744,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; @@ -2684,14 +2772,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; @@ -2703,19 +2793,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); + index_message_by_euid(msg->cm_fields['E'], &CCC->room, msgid); } /* Free up the memory we may have allocated */ @@ -2745,20 +2835,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; ilen = 0; ret->ser = NULL; return; @@ -2894,8 +2984,8 @@ void serialize_message(struct ser_ret *ret, /* return values */ 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; @@ -2912,75 +3002,39 @@ void serialize_message(struct ser_ret *ret, /* return values */ 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; -} - - -/* - * 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; - - /* - * 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);*/ + /*MSG_syslog(LOG_DEBUG, "Exclusive ID: <%s> for room <%s>\n", + msg->cm_fields['E'], CCC->room.QRname);*/ - old_msgnum = CtdlLocateMessageByEuid(msg->cm_fields['E'], &CC->room); + old_msgnum = CtdlLocateMessageByEuid(msg->cm_fields['E'], &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, ""); } } @@ -3002,6 +3056,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ 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; @@ -3020,10 +3075,9 @@ 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"); + MSGM_syslog(LOG_DEBUG, "CtdlSubmitMsg() called\n"); if (is_valid_message(msg) == 0) return(-1); /* self check */ /* If this message has no timestamp, we take the liberty of @@ -3059,7 +3113,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* 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"); + MSGM_syslog(LOG_ERR, "ERROR: attempt to save message with NULL body\n"); return(-2); } @@ -3091,7 +3145,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) { @@ -3103,7 +3158,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"); } } @@ -3112,7 +3167,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); @@ -3126,7 +3181,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } /* 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); /* @@ -3138,7 +3193,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); @@ -3146,7 +3201,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; @@ -3164,7 +3219,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); @@ -3176,7 +3231,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 @@ -3184,7 +3239,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); } } @@ -3199,12 +3254,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); @@ -3227,7 +3282,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ 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", + 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); @@ -3251,24 +3306,29 @@ 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['U'] = strdup("QMSG"); 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['W'] = strdup(recipient); + imsg->cm_fields['2'] = strdup(recipient); CtdlSubmitMsg(imsg, NULL, FNBL_QUEUE_ROOM, 0); CtdlFreeMessage(imsg); } } else { - syslog(LOG_DEBUG, "No user <%s>\n", recipient); - CtdlSaveMsgPointerInRoom(config.c_aideroom, - newmsgid, 0, msg); + 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"); + MSGM_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); PerformMessageHooks(msg, EVT_AFTERSAVE); + free(msg->cm_fields['3']); + msg->cm_fields['3'] = NULL; /* 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,8 +3360,8 @@ 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); } @@ -3315,7 +3375,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } /* 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); @@ -3325,29 +3385,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"); + + StrBufPrintf(SpoolMsg, + "Content-type: "SPOOLMIME"\n" + "\n" + "msgid|%ld\n" + "submitted|%ld\n" + "bounceto|%s\n", + newmsgid, + (long)time(NULL), + bounce_to); - 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); + 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)); @@ -3355,9 +3427,10 @@ 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['U'] = strdup("QMSG"); 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['M'] = SmashStrBuf(&SpoolMsg); /* imsg owns this memory now */ CtdlSubmitMsg(imsg, NULL, SMTP_SPOOLOUT_ROOM, QP_EADDR); CtdlFreeMessage(imsg); } @@ -3419,18 +3492,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, + char *to, + char *room, + const char *text, + int format_type, + const char *subject) { struct CtdlMessage *msg; struct recptypes *recp = NULL; @@ -3471,6 +3542,72 @@ void quickie_message(const char *from, const char *fromaddr, char *to, char *roo if (recp != NULL) free_recipients(recp); } +void flood_protect_quickie_message(const char *from, + const char *fromaddr, + char *to, + char *room, + const char *text, + int format_type, + const char *subject, + int nCriterions, + const char **CritStr, + long *CritStrLen) +{ + int i; + struct UseTable ut; + u_char rawdigest[MD5_DIGEST_LEN]; + struct MD5Context md5context; + StrBuf *guid; + struct cdbdata *cdbut; + char timestamp[64]; + long tslen; + time_t ts = time(NULL); + time_t tsday = ts / (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); + /* Find out if we've already sent a similar message */ + memcpy(ut.ut_msgid, SKEY(guid)); + ut.ut_timestamp = ts; + + cdbut = cdb_fetch(CDB_USETABLE, SKEY(guid)); + + if (cdbut != NULL) { + /* yes, we did. flood protection kicks in. */ + syslog(LOG_DEBUG, + "not sending message again\n"); + cdb_free(cdbut); + } + + /* rewrite the record anyway, to update the timestamp */ + cdb_store(CDB_USETABLE, + SKEY(guid), + &ut, sizeof(struct UseTable) ); + + if (cdbut != NULL) return; + /* no, this message isn't sent recently; go ahead. */ + quickie_message(from, + fromaddr, + to, + room, + text, + format_type, + subject); +} /* @@ -3967,7 +4104,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! */ @@ -3987,11 +4124,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; @@ -4021,19 +4161,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; @@ -4048,7 +4191,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) ) { @@ -4067,13 +4209,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] = ' '; } @@ -4098,8 +4242,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( @@ -4120,10 +4264,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) { @@ -4204,6 +4354,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) { @@ -4211,12 +4362,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); @@ -4233,7 +4384,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(); } @@ -4242,9 +4394,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); } @@ -4255,6 +4409,7 @@ void free_recipients(struct recptypes *valid) { */ void cmd_ent0(char *entargs) { + struct CitContext *CCC = CC; int post = 0; char recp[SIZ]; char cc[SIZ]; @@ -4326,11 +4481,11 @@ void cmd_ent0(char *entargs) /* Check some other permission type things. */ if (IsEmptyStr(newusername)) { - strcpy(newusername, CC->user.fullname); + strcpy(newusername, CCC->user.fullname); } - if ( (CC->user.axlevel < AxAideU) - && (strcasecmp(newusername, CC->user.fullname)) - && (strcasecmp(newusername, CC->cs_inet_fn)) + if ( (CCC->user.axlevel < AxAideU) + && (strcasecmp(newusername, CCC->user.fullname)) + && (strcasecmp(newusername, CCC->cs_inet_fn)) ) { cprintf("%d You don't have permission to author messages as '%s'.\n", ERROR + HIGHER_ACCESS_REQUIRED, @@ -4345,13 +4500,13 @@ void cmd_ent0(char *entargs) } if (!IsEmptyStr(newuseremail)) { - if (!strcasecmp(newuseremail, CC->cs_inet_email)) { + if (!strcasecmp(newuseremail, CCC->cs_inet_email)) { newuseremail_ok = 1; } - else if (!IsEmptyStr(CC->cs_inet_other_emails)) { - j = num_tokens(CC->cs_inet_other_emails, '|'); + else if (!IsEmptyStr(CCC->cs_inet_other_emails)) { + j = num_tokens(CCC->cs_inet_other_emails, '|'); for (i=0; ics_inet_other_emails, i, '|', sizeof buf); + extract_token(buf, CCC->cs_inet_other_emails, i, '|', sizeof buf); if (!strcasecmp(newuseremail, buf)) { newuseremail_ok = 1; } @@ -4367,7 +4522,7 @@ void cmd_ent0(char *entargs) return; } - CC->cs_flags |= CS_POSTING; + CCC->cs_flags |= CS_POSTING; /* In mailbox rooms we have to behave a little differently -- * make sure the user has specified at least one recipient. Then @@ -4376,10 +4531,10 @@ void cmd_ent0(char *entargs) * is the DRAFTS room which does not require recipients */ - if ( ( ( (CC->room.QRflags & QR_MAILBOX) && (!strcasecmp(&CC->room.QRname[11], MAILROOM)) ) - || ( (CC->room.QRflags & QR_MAILBOX) && (CC->curr_view == VIEW_MAILBOX) ) - ) && (strcasecmp(&CC->room.QRname[11], USERDRAFTROOM)) !=0 ) { - if (CC->user.axlevel < AxProbU) { + if ( ( ( (CCC->room.QRflags & QR_MAILBOX) && (!strcasecmp(&CCC->room.QRname[11], MAILROOM)) ) + || ( (CCC->room.QRflags & QR_MAILBOX) && (CCC->curr_view == VIEW_MAILBOX) ) + ) && (strcasecmp(&CCC->room.QRname[11], USERDRAFTROOM)) !=0 ) { + if (CCC->user.axlevel < AxProbU) { strcpy(recp, "sysop"); strcpy(cc, ""); strcpy(bcc, ""); @@ -4419,7 +4574,7 @@ void cmd_ent0(char *entargs) } if (valid_to->num_internet + valid_cc->num_internet + valid_bcc->num_internet > 0) { - if (CtdlCheckInternetMailPermission(&CC->user)==0) { + if (CtdlCheckInternetMailPermission(&CCC->user)==0) { cprintf("%d You do not have permission " "to send Internet mail.\n", ERROR + HIGHER_ACCESS_REQUIRED); @@ -4431,7 +4586,7 @@ void cmd_ent0(char *entargs) } if ( ( (valid_to->num_internet + valid_to->num_ignet + valid_cc->num_internet + valid_cc->num_ignet + valid_bcc->num_internet + valid_bcc->num_ignet) > 0) - && (CC->user.axlevel < AxNetU) ) { + && (CCC->user.axlevel < AxNetU) ) { cprintf("%d Higher access required for network mail.\n", ERROR + HIGHER_ACCESS_REQUIRED); free_recipients(valid_to); @@ -4442,8 +4597,8 @@ void cmd_ent0(char *entargs) if ((RESTRICT_INTERNET == 1) && (valid_to->num_internet + valid_cc->num_internet + valid_bcc->num_internet > 0) - && ((CC->user.flags & US_INTERNET) == 0) - && (!CC->internal_pgm)) { + && ((CCC->user.flags & US_INTERNET) == 0) + && (!CCC->internal_pgm)) { cprintf("%d You don't have access to Internet mail.\n", ERROR + HIGHER_ACCESS_REQUIRED); free_recipients(valid_to); @@ -4456,16 +4611,16 @@ void cmd_ent0(char *entargs) /* Is this a room which has anonymous-only or anonymous-option? */ anonymous = MES_NORMAL; - if (CC->room.QRflags & QR_ANONONLY) { + if (CCC->room.QRflags & QR_ANONONLY) { anonymous = MES_ANONONLY; } - if (CC->room.QRflags & QR_ANONOPT) { + if (CCC->room.QRflags & QR_ANONOPT) { if (anon_flag == 1) { /* only if the user requested it */ anonymous = MES_ANONOPT; } } - if ((CC->room.QRflags & QR_MAILBOX) == 0) { + if ((CCC->room.QRflags & QR_MAILBOX) == 0) { recp[0] = 0; } @@ -4473,7 +4628,7 @@ void cmd_ent0(char *entargs) * strongly recommended in this room, if either the SUBJECTREQ flag * is set, or if there is one or more Internet email recipients. */ - if (CC->room.QRflags2 & QR2_SUBJECTREQ) subject_required = 1; + if (CCC->room.QRflags2 & QR2_SUBJECTREQ) subject_required = 1; if ((valid_to) && (valid_to->num_internet > 0)) subject_required = 1; if ((valid_cc) && (valid_cc->num_internet > 0)) subject_required = 1; if ((valid_bcc) && (valid_bcc->num_internet > 0)) subject_required = 1; @@ -4503,8 +4658,8 @@ void cmd_ent0(char *entargs) cprintf("%d send message\n", SEND_LISTING); } - msg = CtdlMakeMessage(&CC->user, recp, cc, - CC->room.QRname, anonymous, format_type, + msg = CtdlMakeMessage(&CCC->user, recp, cc, + CCC->room.QRname, anonymous, format_type, newusername, newuseremail, subject, ((!IsEmptyStr(supplied_euid)) ? supplied_euid : NULL), NULL, references); @@ -4534,17 +4689,30 @@ 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['V'] = strdup(valid->recp_orgroom); + } + if (msg != NULL) { msgnum = CtdlSubmitMsg(msg, valid, "", QP_EADDR); - if (do_confirm) { cprintf("%ld\n", msgnum); - if (msgnum >= 0L) { - cprintf("Message accepted.\n"); + + if (StrLength(CCC->StatusMessage) > 0) { + cprintf("%s\n", ChrPtr(CCC->StatusMessage)); + } + else if (msgnum >= 0L) { + client_write(HKEY("Message accepted.\n")); } else { - cprintf("Internal error.\n"); + client_write(HKEY("Internal error.\n")); } + if (msg->cm_fields['E'] != NULL) { cprintf("%s\n", msg->cm_fields['E']); } else { @@ -4573,6 +4741,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; @@ -4590,13 +4759,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 */ } @@ -4610,32 +4779,51 @@ 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 */ /* 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; juser.axlevel >= AxAideU) permit = 1; /* Room aides can move/copy */ @@ -4903,22 +5101,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); @@ -4940,10 +5139,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; @@ -4959,6 +5210,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; @@ -4975,7 +5227,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); } @@ -4985,7 +5237,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); } @@ -4997,7 +5249,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); @@ -5015,6 +5267,7 @@ int TDAP_ProcessAdjRefCountQueue(void) */ void TDAP_AdjRefCount(long msgnum, int incr) { + struct CitContext *CCC = CC; struct MetaData smi; long delnum; @@ -5028,15 +5281,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); @@ -5069,7 +5322,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; @@ -5082,7 +5335,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 ) ); @@ -5120,13 +5373,13 @@ 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['A'] = strdup(CCC->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); @@ -5144,8 +5397,8 @@ 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 */ @@ -5266,10 +5519,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");