X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmsgbase.c;h=568cefb2e06f6c57175510351cbf1b05acf5b049;hb=0b0f8a2280a8f22877baccd2355d7b41b863bfa0;hp=21a967ec86dc85f9bcf4909482f5c9caf143758c;hpb=06bf4eeae8f104fee9c6edfbd55ef00b4a03b942;p=citadel.git diff --git a/citadel/msgbase.c b/citadel/msgbase.c index 21a967ec8..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" @@ -64,7 +61,6 @@ #include "journaling.h" #include "citadel_dirs.h" #include "clientsocket.h" -#include "serv_network.h" #include "threads.h" #include "ctdl_module.h" @@ -74,13 +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); -/* - * This really belongs in serv_network.c, but I don't know how to export - * symbols between modules. - */ -struct FilterList *filterlist = NULL; - +int MessageDebugEnabled = 0; /* * These are the four-character field headers we use when outputting @@ -104,7 +96,7 @@ char *msgkeys[] = { "hnod", "msgn", "jrnl", - NULL, + "rep2", "list", "text", "node", @@ -150,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]; @@ -198,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 */ @@ -206,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); } } } @@ -354,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); @@ -373,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; @@ -396,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); @@ -441,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(); @@ -574,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) { @@ -593,56 +588,6 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, } - -/* store a value in the binary tree */ -void seenit_store(struct seenit **si, long msgnum) { - struct seenit *this_si; - - if (*si == NULL) { /* store now */ - *si = malloc(sizeof(struct seenit)); - this_si = *si; - this_si->l = NULL; - this_si->r = NULL; - this_si->msgnum = msgnum; - return; - } - - this_si = *si; - if (msgnum < this_si->msgnum) { - seenit_store(&this_si->l, msgnum); - } - else if (msgnum > this_si->msgnum) { - seenit_store(&this_si->r, msgnum); - } - else { - return; - } -} - - -/* search for a value in the binary tree */ -int seenit_isthere(struct seenit *si, long msgnum) { - if (!si) return(0); /* not there */ - if (msgnum < si->msgnum) return(seenit_isthere(si->l, msgnum)); - if (msgnum > si->msgnum) return(seenit_isthere(si->r, msgnum)); - return(1); /* found it */ -} - - -/* free the binary tree */ -void seenit_free(struct seenit **si) { - struct seenit *this_si = *si; - if (!this_si) return; - seenit_free(&this_si->l); - seenit_free(&this_si->r); - free(this_si); - *si = NULL; -} - - - - - /* * API function to perform an operation for each qualifying message in the * current room. (Returns the number of messages processed.) @@ -653,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; @@ -678,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. */ @@ -695,33 +654,10 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, cdb_free(cdbfr); /* we own this memory now */ /* -<<<<<<< HEAD -======= - * 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); - } - - CC->cached_msglist = msglist; - CC->cached_num_msgs = num_msgs; - syslog(LOG_DEBUG, "\033[34m RELOAD \033[0m\n"); - } - - /* ->>>>>>> parent of 4ec6a9d... Updating cmd_euid() to use the CtdlForEachMessage() API fixes the security check in blog view and saves some code * Now begin the traversal. */ if (num_msgs > 0) for (a = 0; a < num_msgs; ++a) { - /* - * cache the msgnums we've seen in order to perform security checks later - */ - if (CC->client_socket > 0) { - seenit_store(&CC->cached_msglist, msglist[a]); - } - /* If the caller is looking for a specific MIME type, filter * out all messages which are not of the type requested. */ @@ -736,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 */ @@ -753,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)) { @@ -815,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; @@ -837,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; @@ -848,7 +799,21 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, } } if (need_to_free_re) regfree(&re); - free(msglist); + + /* + * We cache the most recent msglist in order to do security checks later + */ + if (CCC->client_socket > 0) { + if (CCC->cached_msglist != NULL) { + free(CCC->cached_msglist); + } + CCC->cached_msglist = msglist; + CCC->cached_num_msgs = num_msgs; + } + else { + free(msglist); + } + return num_processed; } @@ -1002,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]; @@ -1015,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; @@ -1033,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; @@ -1055,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; @@ -1071,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; @@ -1151,22 +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); - fflush(CC->download_fp); - rewind(CC->download_fp); + if (rv <= 0) { + MSG_syslog(LOG_EMERG, "mime_download(): Couldn't write: %s\n", + strerror(errno)); + cprintf("%d unable to write tempfile.\n", + ERROR + TOO_BIG); + fclose(CCC->download_fp); + CCC->download_fp = NULL; + return; + } + fflush(CCC->download_fp); + rewind(CCC->download_fp); OpenCmdResult(filename, cbtype); } @@ -1210,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; @@ -1217,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; @@ -1232,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; } @@ -1296,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); } @@ -1340,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; @@ -1360,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; @@ -1380,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; @@ -1387,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); @@ -1396,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; @@ -1417,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); @@ -1453,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; @@ -1464,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; } @@ -1491,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; @@ -1508,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) @@ -1546,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"); @@ -1612,24 +1602,22 @@ 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 */ - -<<<<<<< HEAD - if (seenit_isthere(CC->cached_msglist, msgnum)) { - return om_ok; -======= + 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 */ int min = 0; int max = (CC->cached_num_msgs - 1); while (max >= min) { - syslog(LOG_DEBUG, "\033[35m Checking from %d to %d \033[0m\n", min, max); 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]) { @@ -1638,7 +1626,6 @@ int check_cached_msglist(long msgnum) { else { max = middle - 1; } ->>>>>>> parent of 4ec6a9d... Updating cmd_euid() to use the CtdlForEachMessage() API fixes the security check in blog view and saves some code } return om_access_denied; @@ -1670,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 : "<>") ); @@ -1695,31 +1685,29 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ return(r); } + /* + * Check to make sure the message is actually IN this room + */ r = check_cached_msglist(msg_num); -<<<<<<< HEAD + if (r == om_access_denied) { + /* Not in the cache? We get ONE shot to check it again. */ + CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, NULL, NULL); + r = check_cached_msglist(msg_num); + } if (r != om_ok) { - syslog(LOG_DEBUG, "Denying access to message %ld - not yet listed\n", msg_num); + 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) { - cprintf("%d Message %ld was not found in this room.\n", - ERROR + MESSAGE_NOT_FOUND, + cprintf("%d message %ld was not found in this room\n", + ERROR + HIGHER_ACCESS_REQUIRED, msg_num ); } - else { - cprintf("%d An unknown error has occurred.\n", ERROR); - } - return(r); } -======= - if (r == om_ok) { - syslog(LOG_DEBUG, "\033[32m PASS \033[0m\n"); - } - else { - syslog(LOG_DEBUG, "\033[31m FAIL \033[0m\n"); ->>>>>>> parent of 4ec6a9d... Updating cmd_euid() to use the CtdlForEachMessage() API fixes the security check in blog view and saves some code + return(r); } - /* FIXME after testing, this is where we deny access */ /* * Fetch the message from disk. If we're in HEADERS_FAST mode, @@ -1749,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; @@ -1765,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); @@ -1782,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; @@ -1800,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); @@ -2020,6 +2036,7 @@ void OutputRFC822MsgHeaders( int i, j, k; char *mptr = NULL; char *mpptr = NULL; + char *hptr; for (i = 0; i < 256; ++i) { if (TheMessage->cm_fields[i]) { @@ -2045,7 +2062,11 @@ void OutputRFC822MsgHeaders( else if (i == 'V') { if ((flags & QP_EADDR) != 0) mptr = qp_encode_email_addrs(mptr); - cprintf("Envelope-To: %s%s", mptr, nl); + hptr = mptr; + while ((*hptr != '\0') && isspace(*hptr)) + hptr ++; + if (!IsEmptyStr(hptr)) + cprintf("Envelope-To: %s%s", hptr, nl); } else if (i == 'U') { cprintf("Subject: %s%s", mptr, nl); @@ -2098,7 +2119,11 @@ void OutputRFC822MsgHeaders( } } else if (i == 'K') { - cprintf("Reply-To: <%s>%s", mptr, nl); + hptr = mptr; + while ((*hptr != '\0') && isspace(*hptr)) + hptr ++; + if (!IsEmptyStr(hptr)) + cprintf("Reply-To: %s%s", mptr, nl); } if (mptr != mpptr) free (mptr); @@ -2124,7 +2149,6 @@ void Dump_RFC822HeadersBody( int outlen = 0; int nllen = strlen(nl); char *mptr; - int rc; mptr = TheMessage->cm_fields['M']; @@ -2177,15 +2201,15 @@ 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; } } if (outlen > 0) { - rc = client_write(outbuf, outlen); - outlen = 0; + client_write(outbuf, outlen); } } @@ -2248,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'; @@ -2275,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 */ @@ -2290,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); } @@ -2317,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); @@ -2328,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 @@ -2358,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 */ @@ -2509,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); @@ -2542,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; } @@ -2558,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); } @@ -2612,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); } @@ -2645,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); } @@ -2661,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); +} /* @@ -2679,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; @@ -2692,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); @@ -2705,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); } @@ -2717,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; @@ -2745,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; @@ -2764,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 */ @@ -2806,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; icm_fields['I']==NULL) { @@ -2895,16 +2927,16 @@ 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) { cdb_store(CDB_BIGMSGS, - &newmsgid, - (int)sizeof(long), - holdM, - (strlen(holdM) + 1) - ); + &newmsgid, + (int)sizeof(long), + holdM, + (strlen(holdM) + 1) + ); } retval = newmsgid; } @@ -2928,8 +2960,9 @@ long send_message(struct CtdlMessage *msg) { * serialized message in memory. THE LATTER MUST BE FREED BY THE CALLER. */ void serialize_message(struct ser_ret *ret, /* return values */ - struct CtdlMessage *msg) /* unserialized msg */ + struct CtdlMessage *msg) /* unserialized msg */ { + struct CitContext *CCC = CC; size_t wlen, fieldlen; int i; static char *forder = FORDER; @@ -2938,7 +2971,7 @@ void serialize_message(struct ser_ret *ret, /* return values */ * Check for valid message format */ if (is_valid_message(msg) == 0) { - syslog(LOG_ERR, "serialize_message() aborting due to invalid message\n"); + MSGM_syslog(LOG_ERR, "serialize_message() aborting due to invalid message\n"); ret->len = 0; ret->ser = NULL; return; @@ -2946,13 +2979,13 @@ void serialize_message(struct ser_ret *ret, /* return values */ 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; + ret->len = ret->len + + strlen(msg->cm_fields[(int)forder[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; @@ -2964,83 +2997,44 @@ void serialize_message(struct ser_ret *ret, /* return values */ 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; -} - - -/* - * 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 ? */ -{ - size_t wlen; - 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; - } - - buf = (char*) malloc (Siz + 1); - - wlen = 3; - - 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; - } + 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) { + MSG_syslog(LOG_ERR, "ERROR: len=%ld wlen=%ld\n", + (long)ret->len, (long)wlen); + } 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, ""); } } @@ -3053,7 +3047,8 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ struct recptypes *recps, /* recipients (if mail) */ const char *force, /* force a particular room? */ int flags /* should the message be exported clean? */ -) { + ) +{ char submit_filename[128]; char generated_timestamp[32]; char hold_rm[ROOMNAMELEN]; @@ -3061,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; @@ -3079,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 @@ -3118,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); } @@ -3150,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) { @@ -3162,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"); } } @@ -3171,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); @@ -3185,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); /* @@ -3197,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); @@ -3205,12 +3201,12 @@ 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; safestrncpy(smi.meta_content_type, content_type, - sizeof smi.meta_content_type); + sizeof smi.meta_content_type); /* * Measure how big this message will be when rendered as RFC822. @@ -3223,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); @@ -3235,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 @@ -3243,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); } } @@ -3255,15 +3251,15 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* If other rooms are specified, drop them there too. */ if ((recps != NULL) && (recps->num_room > 0)) - for (i=0; irecp_room, '|'); ++i) { - extract_token(recipient, recps->recp_room, i, - '|', sizeof recipient); - syslog(LOG_DEBUG, "Delivering to room <%s>\n", recipient); - CtdlSaveMsgPointerInRoom(recipient, newmsgid, 0, msg); - } + for (i=0; irecp_room, '|'); ++i) { + extract_token(recipient, recps->recp_room, i, + '|', sizeof recipient); + MSG_syslog(LOG_DEBUG, "Delivering to room <%s>\n", recipient);///// xxxx + 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); @@ -3283,53 +3279,56 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * recipient's mailbox and bump the reference count. */ 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", - recipient); - if (CtdlGetUser(&userbuf, recipient) == 0) { - // Add a flag so the Funambol module knows its mail - msg->cm_fields['W'] = strdup(recipient); - CtdlMailboxName(actual_rm, sizeof actual_rm, &userbuf, MAILROOM); - CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 0, msg); - CtdlBumpNewMailCounter(userbuf.usernum); - if (!IsEmptyStr(config.c_funambol_host) || !IsEmptyStr(config.c_pager_program)) { - /* Generate a instruction message for the Funambol notification - * server, in the same style as the SMTP queue - */ - 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 - ); - - imsg = malloc(sizeof(struct CtdlMessage)); - memset(imsg, 0, sizeof(struct CtdlMessage)); - 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['W'] = strdup(recipient); - CtdlSubmitMsg(imsg, NULL, FNBL_QUEUE_ROOM, 0); - CtdlFreeMessage(imsg); + for (i=0; irecp_local, '|'); ++i) { + 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); + CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 0, msg); + CtdlBumpNewMailCounter(userbuf.usernum); + if (!IsEmptyStr(config.c_funambol_host) || !IsEmptyStr(config.c_pager_program)) { + /* Generate a instruction message for the Funambol notification + * server, in the same style as the SMTP queue + */ + 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 + ); + + imsg = malloc(sizeof(struct CtdlMessage)); + memset(imsg, 0, sizeof(struct CtdlMessage)); + 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['2'] = strdup(recipient); + CtdlSubmitMsg(imsg, NULL, FNBL_QUEUE_ROOM, 0); + CtdlFreeMessage(imsg); + } + } + else { + MSG_syslog(LOG_DEBUG, "No user <%s>\n", recipient); + CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg); } } - else { - 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 @@ -3340,39 +3339,43 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * a network spool receiver that can handle the new style messages. */ if ((recps != NULL) && (recps->num_ignet > 0)) - for (i=0; irecp_ignet, '|'); ++i) { - 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); + for (i=0; irecp_ignet, '|'); ++i) { + 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); - serialize_message(&smr, msg); - if (smr.len > 0) { - snprintf(submit_filename, sizeof submit_filename, + serialize_message(&smr, msg); + if (smr.len > 0) { + snprintf(submit_filename, sizeof submit_filename, "%s/netmail.%04lx.%04x.%04x", ctdl_netin_dir, (long) getpid(), CCC->cs_pid, ++seqnum); - network_fp = fopen(submit_filename, "wb+"); - if (network_fp != NULL) { - rv = fwrite(smr.ser, smr.len, 1, network_fp); - fclose(network_fp); + network_fp = fopen(submit_filename, "wb+"); + if (network_fp != NULL) { + rv = fwrite(smr.ser, smr.len, 1, network_fp); + if (rv == -1) { + MSG_syslog(LOG_EMERG, "CtdlSubmitMsg(): Couldn't write network spool file: %s\n", + strerror(errno)); + } + fclose(network_fp); + } + free(smr.ser); } - 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['R']); + free(msg->cm_fields['D']); + msg->cm_fields['R'] = hold_R; + msg->cm_fields['D'] = 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); @@ -3382,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"); - 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)); @@ -3412,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); } @@ -3430,7 +3446,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ aptr = (struct addresses_to_be_filed *) malloc(sizeof(struct addresses_to_be_filed)); CtdlMailboxName(actual_rm, sizeof actual_rm, - &CCC->user, USERCONTACTSROOM); + &CCC->user, USERCONTACTSROOM); aptr->roomname = strdup(actual_rm); aptr->collected_addresses = collected_addresses; begin_critical_section(S_ATBF); @@ -3476,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; @@ -3528,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); +} /* @@ -3540,7 +3620,7 @@ StrBuf *CtdlReadMessageBodyBuf(char *terminator, /* token signalling EOT */ exist is ALWAYS freed */ int crlf, /* CRLF newlines instead of LF */ int *sock /* socket handle or 0 for this session's client socket */ - ) + ) { StrBuf *Message; StrBuf *LineBuf; @@ -3816,7 +3896,7 @@ struct CtdlMessage *CtdlMakeMessage( char *supplied_euid, /* ...or NULL if this is irrelevant */ char *preformatted_text, /* ...or NULL to read text from client */ char *references /* Thread references */ -) { + ) { char dest_node[256]; char buf[1024]; struct CtdlMessage *msg; @@ -3913,10 +3993,10 @@ struct CtdlMessage *CtdlMakeMessage( msg->cm_fields['E'] = strdup(supplied_euid); } - if (references != NULL) { - if (!IsEmptyStr(references)) { - msg->cm_fields['W'] = strdup(references); - } + if ((references != NULL) && (!IsEmptyStr(references))) { + if (msg->cm_fields['W'] != NULL) + free(msg->cm_fields['W']); + msg->cm_fields['W'] = strdup(references); } if (preformatted_text != NULL) { @@ -3929,6 +4009,10 @@ struct CtdlMessage *CtdlMakeMessage( 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 @@ -3941,7 +4025,7 @@ int CtdlDoIHavePermissionToPostInThisRoom( const char* RemoteIdentifier, int PostPublic, int is_reply -) { + ) { int ra; if (!(CC->logged_in) && @@ -3963,36 +4047,8 @@ int CtdlDoIHavePermissionToPostInThisRoom( return (ERROR + NOT_LOGGED_IN); } if ((PostPublic!=POST_LMTP) &&(CC->room.QRflags2 & QR2_SMTP_PUBLIC) == 0) { - SpoolControl *sc; - char filename[SIZ]; - int found; - if (RemoteIdentifier == NULL) - { - snprintf(errmsgbuf, n, "Need sender to permit access."); - return (ERROR + USERNAME_REQUIRED); - } - - assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir); - begin_critical_section(S_NETCONFIGS); - if (!read_spoolcontrol_file(&sc, filename)) - { - end_critical_section(S_NETCONFIGS); - snprintf(errmsgbuf, n, - "This mailing list only accepts posts from subscribers."); - return (ERROR + NO_SUCH_USER); - } - end_critical_section(S_NETCONFIGS); - found = is_recipient (sc, RemoteIdentifier); - free_spoolcontrol_struct(&sc); - if (found) { - return (0); - } - else { - snprintf(errmsgbuf, n, - "This mailing list only accepts posts from subscribers."); - return (ERROR + NO_SUCH_USER); - } + return netconfig_check_roomaccess(errmsgbuf, n, RemoteIdentifier); } return (0); @@ -4000,30 +4056,36 @@ int CtdlDoIHavePermissionToPostInThisRoom( if ((CC->user.axlevel < AxProbU) && ((CC->room.QRflags & QR_MAILBOX) == 0)) { - snprintf(errmsgbuf, n, "Need to be validated to enter " - "(except in %s> to sysop)", MAILROOM); + snprintf(errmsgbuf, n, "Need to be validated to enter (except in %s> to sysop)", MAILROOM); return (ERROR + HIGHER_ACCESS_REQUIRED); } CtdlRoomAccess(&CC->room, &CC->user, &ra, NULL); - if ( (!(ra & UA_POSTALLOWED)) && (ra & UA_REPLYALLOWED) && (!is_reply) ) { + if (ra & UA_POSTALLOWED) { + strcpy(errmsgbuf, "OK to post or reply here"); + return(0); + } + + if ( (ra & UA_REPLYALLOWED) && (is_reply) ) { /* * To be thorough, we ought to check to see if the message they are * replying to is actually a valid one in this room, but unless this * actually becomes a problem we'll go with high performance instead. */ - snprintf(errmsgbuf, n, "You may only reply to existing messages here."); - return (ERROR + HIGHER_ACCESS_REQUIRED); + strcpy(errmsgbuf, "OK to reply here"); + return(0); } - else if (!(ra & UA_POSTALLOWED)) { - snprintf(errmsgbuf, n, "Higher access is required to post in this room."); + if ( (ra & UA_REPLYALLOWED) && (!is_reply) ) { + /* Clarify what happened with a better error message */ + snprintf(errmsgbuf, n, "You may only reply to existing messages here."); return (ERROR + HIGHER_ACCESS_REQUIRED); } - strcpy(errmsgbuf, "Ok"); - return(0); + snprintf(errmsgbuf, n, "Higher access is required to post in this room."); + return (ERROR + HIGHER_ACCESS_REQUIRED); + } @@ -4042,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! */ @@ -4062,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; @@ -4096,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; @@ -4123,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) ) { @@ -4142,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] = ' '; } @@ -4160,98 +4229,104 @@ struct recptypes *validate_recipients(const char *supplied_recipients, invalid = 0; errmsg[0] = 0; switch(mailtype) { - case MES_LOCAL: - if (!strcasecmp(this_recp, "sysop")) { - ++ret->num_room; - strcpy(this_recp, config.c_aideroom); - if (!IsEmptyStr(ret->recp_room)) { - strcat(ret->recp_room, "|"); - } - strcat(ret->recp_room, this_recp); + case MES_LOCAL: + if (!strcasecmp(this_recp, "sysop")) { + ++ret->num_room; + strcpy(this_recp, config.c_aideroom); + if (!IsEmptyStr(ret->recp_room)) { + strcat(ret->recp_room, "|"); } - else if ( (!strncasecmp(this_recp, "room_", 5)) - && (!CtdlGetRoom(&tempQR, &this_recp_cooked[5])) ) { + strcat(ret->recp_room, this_recp); + } + else if ( (!strncasecmp(this_recp, "room_", 5)) + && (!CtdlGetRoom(&tempQR, &this_recp_cooked[5])) ) { - /* Save room so we can restore it later */ - tempQR2 = CC->room; - CC->room = tempQR; + /* Save room so we can restore it later */ + tempQR2 = CCC->room; + CCC->room = tempQR; - /* Check permissions to send mail to this room */ - err = CtdlDoIHavePermissionToPostInThisRoom( - errmsg, - sizeof errmsg, - RemoteIdentifier, - Flags, - 0 /* 0 = not a reply */ + /* Check permissions to send mail to this room */ + err = CtdlDoIHavePermissionToPostInThisRoom( + errmsg, + sizeof errmsg, + RemoteIdentifier, + Flags, + 0 /* 0 = not a reply */ ); - if (err) - { - ++ret->num_error; - invalid = 1; - } - else { - ++ret->num_room; - if (!IsEmptyStr(ret->recp_room)) { - strcat(ret->recp_room, "|"); - } - strcat(ret->recp_room, &this_recp_cooked[5]); - } - - /* Restore room in case something needs it */ - CC->room = tempQR2; - - } - else if (CtdlGetUser(&tempUS, this_recp) == 0) { - ++ret->num_local; - strcpy(this_recp, tempUS.fullname); - if (!IsEmptyStr(ret->recp_local)) { - strcat(ret->recp_local, "|"); - } - strcat(ret->recp_local, this_recp); - } - else if (CtdlGetUser(&tempUS, this_recp_cooked) == 0) { - ++ret->num_local; - strcpy(this_recp, tempUS.fullname); - if (!IsEmptyStr(ret->recp_local)) { - strcat(ret->recp_local, "|"); - } - strcat(ret->recp_local, this_recp); - } - else { - ++ret->num_error; - invalid = 1; - } - break; - case MES_INTERNET: - /* Yes, you're reading this correctly: if the target - * domain points back to the local system or an attached - * Citadel directory, the address is invalid. That's - * because if the address were valid, we would have - * already translated it to a local address by now. - */ - if (IsDirectory(this_recp, 0)) { + if (err) + { ++ret->num_error; invalid = 1; - } + } else { - ++ret->num_internet; - if (!IsEmptyStr(ret->recp_internet)) { - strcat(ret->recp_internet, "|"); + ++ret->num_room; + if (!IsEmptyStr(ret->recp_room)) { + strcat(ret->recp_room, "|"); + } + strcat(ret->recp_room, &this_recp_cooked[5]); + + if (!IsEmptyStr(ret->recp_orgroom)) { + strcat(ret->recp_orgroom, "|"); } - strcat(ret->recp_internet, this_recp); + strcat(ret->recp_orgroom, org_recp); + } - break; - case MES_IGNET: - ++ret->num_ignet; - if (!IsEmptyStr(ret->recp_ignet)) { - strcat(ret->recp_ignet, "|"); + + /* Restore room in case something needs it */ + CCC->room = tempQR2; + + } + else if (CtdlGetUser(&tempUS, this_recp) == 0) { + ++ret->num_local; + strcpy(this_recp, tempUS.fullname); + if (!IsEmptyStr(ret->recp_local)) { + strcat(ret->recp_local, "|"); } - strcat(ret->recp_ignet, this_recp); - break; - case MES_ERROR: + strcat(ret->recp_local, this_recp); + } + else if (CtdlGetUser(&tempUS, this_recp_cooked) == 0) { + ++ret->num_local; + strcpy(this_recp, tempUS.fullname); + if (!IsEmptyStr(ret->recp_local)) { + strcat(ret->recp_local, "|"); + } + strcat(ret->recp_local, this_recp); + } + else { ++ret->num_error; invalid = 1; - break; + } + break; + case MES_INTERNET: + /* Yes, you're reading this correctly: if the target + * domain points back to the local system or an attached + * Citadel directory, the address is invalid. That's + * because if the address were valid, we would have + * already translated it to a local address by now. + */ + if (IsDirectory(this_recp, 0)) { + ++ret->num_error; + invalid = 1; + } + else { + ++ret->num_internet; + if (!IsEmptyStr(ret->recp_internet)) { + strcat(ret->recp_internet, "|"); + } + strcat(ret->recp_internet, this_recp); + } + break; + case MES_IGNET: + ++ret->num_ignet; + if (!IsEmptyStr(ret->recp_ignet)) { + strcat(ret->recp_ignet, "|"); + } + strcat(ret->recp_ignet, this_recp); + break; + case MES_ERROR: + ++ret->num_error; + invalid = 1; + break; } if (invalid) { if (IsEmptyStr(errmsg)) { @@ -4279,19 +4354,20 @@ 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) { + ret->num_room + ret->num_error) == 0) { ret->num_error = (-1); 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); @@ -4308,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(); } @@ -4317,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); } @@ -4330,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]; @@ -4369,13 +4449,13 @@ void cmd_ent0(char *entargs) extract_token(cc, entargs, 7, '|', sizeof cc); extract_token(bcc, entargs, 8, '|', sizeof bcc); switch(CC->room.QRdefaultview) { - case VIEW_NOTES: - case VIEW_WIKI: - extract_token(supplied_euid, entargs, 9, '|', sizeof supplied_euid); - break; - default: - supplied_euid[0] = 0; - break; + case VIEW_NOTES: + case VIEW_WIKI: + extract_token(supplied_euid, entargs, 9, '|', sizeof supplied_euid); + break; + default: + supplied_euid[0] = 0; + break; } extract_token(newuseremail, entargs, 10, '|', sizeof newuseremail); extract_token(references, entargs, 11, '|', sizeof references); @@ -4391,7 +4471,7 @@ void cmd_ent0(char *entargs) NULL, POST_LOGGED_IN, (!IsEmptyStr(references)) /* is this a reply? or a top-level post? */ - ); + ); if (err) { cprintf("%d %s\n", err, errmsg); @@ -4401,16 +4481,16 @@ 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, newusername - ); + ); return; } @@ -4420,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; } @@ -4438,11 +4518,11 @@ void cmd_ent0(char *entargs) cprintf("%d You don't have permission to author messages as '%s'.\n", ERROR + HIGHER_ACCESS_REQUIRED, newuseremail - ); + ); 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 @@ -4451,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, ""); @@ -4494,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); @@ -4506,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); @@ -4517,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); @@ -4531,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; } @@ -4548,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; @@ -4578,11 +4658,11 @@ void cmd_ent0(char *entargs) cprintf("%d send message\n", SEND_LISTING); } - msg = CtdlMakeMessage(&CC->user, recp, cc, - CC->room.QRname, anonymous, format_type, - newusername, newuseremail, subject, - ((!IsEmptyStr(supplied_euid)) ? supplied_euid : NULL), - NULL, references); + msg = CtdlMakeMessage(&CCC->user, recp, cc, + CCC->room.QRname, anonymous, format_type, + newusername, newuseremail, subject, + ((!IsEmptyStr(supplied_euid)) ? supplied_euid : NULL), + NULL, references); /* Put together one big recipients struct containing to/cc/bcc all in * one. This is for the envelope. @@ -4609,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 { @@ -4643,11 +4736,12 @@ void cmd_ent0(char *entargs) * (returns the actual number of messages deleted) */ int CtdlDeleteMessages(char *room_name, /* which room */ - long *dmsgnums, /* array of msg numbers to be deleted */ - int num_dmsgnums, /* number of msgs to be deleted, or 0 for "any" */ - char *content_type /* or "" for any. regular expressions expected. */ -) + long *dmsgnums, /* array of msg numbers to be deleted */ + int num_dmsgnums, /* number of msgs to be deleted, or 0 for "any" */ + char *content_type /* or "" for any. regular expressions expected. */ + ) { + struct CitContext *CCC = CC; struct ctdlroom qrbuf; struct cdbdata *cdbfr; long *msglist = NULL; @@ -4662,16 +4756,16 @@ int CtdlDeleteMessages(char *room_name, /* which room */ int need_to_free_re = 0; if (content_type) if (!IsEmptyStr(content_type)) { - 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); + regcomp(&re, content_type, 0); + need_to_free_re = 1; + } + MSG_syslog(LOG_DEBUG, "CtdlDeleteMessages(%s, %d msgs, %s)\n", + room_name, num_dmsgnums, content_type); /* 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 */ } @@ -4685,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 */ @@ -4872,12 +4995,12 @@ void cmd_move(char *args) /* Permit move/copy from personal rooms */ if ((CC->room.QRflags & QR_MAILBOX) - && (qtemp.QRflags & QR_MAILBOX)) permit = 1; + && (qtemp.QRflags & QR_MAILBOX)) permit = 1; /* Permit only copy from public to personal room */ if ( (is_copy) - && (!(CC->room.QRflags & QR_MAILBOX)) - && (qtemp.QRflags & QR_MAILBOX)) permit = 1; + && (!(CC->room.QRflags & QR_MAILBOX)) + && (qtemp.QRflags & QR_MAILBOX)) permit = 1; /* Permit message removal from collaborative delete rooms */ if (CC->room.QRflags2 & QR2_COLLABDEL) permit = 1; @@ -4978,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); @@ -5014,6 +5138,63 @@ void AdjRefCount(long msgnum, int incr) new_arcq.arcq_msgnum = msgnum; new_arcq.arcq_delta = incr; rv = fwrite(&new_arcq, sizeof(struct arcq), 1, arcfp); + if (rv == -1) { + MSG_syslog(LOG_EMERG, "Couldn't write Refcount Queue File %s: %s\n", + file_arcq, + strerror(errno)); + } + fflush(arcfp); + + return; +} + +void AdjRefCountList(long *msgnum, long nmsg, int incr) +{ + struct CitContext *CCC = CC; + long i, the_size, offset; + struct arcq *new_arcq; + int rv = 0; + + MSG_syslog(LOG_DEBUG, "AdjRefCountList() msg %ld ref count delta %+d\n", nmsg, incr); + + begin_critical_section(S_SUPPMSGMAIN); + if (arcfp == NULL) { + arcfp = fopen(file_arcq, "ab+"); + chown(file_arcq, CTDLUID, (-1)); + chmod(file_arcq, 0600); + } + end_critical_section(S_SUPPMSGMAIN); + + /* + * If we can't open the queue, perform the operation synchronously. + */ + if (arcfp == NULL) { + for (i = 0; i < nmsg; i++) + TDAP_AdjRefCount(msgnum[i], incr); + return; + } + + 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; @@ -5029,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; @@ -5045,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); } @@ -5055,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); } @@ -5067,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); @@ -5085,6 +5267,7 @@ int TDAP_ProcessAdjRefCountQueue(void) */ void TDAP_AdjRefCount(long msgnum, int incr) { + struct CitContext *CCC = CC; struct MetaData smi; long delnum; @@ -5098,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); @@ -5130,16 +5313,16 @@ void TDAP_AdjRefCount(long msgnum, int incr) * files, and still pull the message into memory as with all others. */ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ - char *content_type, /* MIME type of this object */ - char *raw_message, /* Data to be written */ - off_t raw_length, /* Size of raw_message */ - struct ctdluser *is_mailbox, /* Mailbox room? */ - int is_binary, /* Is encoding necessary? */ - int is_unique, /* Del others of this type? */ - unsigned int flags /* Internal save flags */ - ) + char *content_type, /* MIME type of this object */ + char *raw_message, /* Data to be written */ + off_t raw_length, /* Size of raw_message */ + struct ctdluser *is_mailbox, /* Mailbox room? */ + int is_binary, /* Is encoding necessary? */ + int is_unique, /* Del others of this type? */ + unsigned int flags /* Internal save flags */ + ) { - + struct CitContext *CCC = CC; struct ctdlroom qrbuf; char roomname[ROOMNAMELEN]; struct CtdlMessage *msg; @@ -5152,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 ) ); @@ -5166,12 +5349,12 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ if (is_binary) { sprintf(&encoded_message[strlen(encoded_message)], "Content-transfer-encoding: base64\n\n" - ); + ); } else { sprintf(&encoded_message[strlen(encoded_message)], "Content-transfer-encoding: 7bit\n\n" - ); + ); } if (is_binary) { @@ -5180,23 +5363,23 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ raw_message, (int)raw_length, 0 - ); + ); } else { memcpy( &encoded_message[strlen(encoded_message)], raw_message, (int)(raw_length+1) - ); + ); } - 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); @@ -5207,16 +5390,16 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ /* Create the requested room if we have to. */ if (CtdlGetRoom(&qrbuf, roomname) != 0) { CtdlCreateRoom(roomname, - ( (is_mailbox != NULL) ? 5 : 3 ), - "", 0, 1, 0, VIEW_BBS); + ( (is_mailbox != NULL) ? 5 : 3 ), + "", 0, 1, 0, VIEW_BBS); } /* If the caller specified this object as unique, delete all * other objects of this type that are currently in the room. */ if (is_unique) { - 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); @@ -5251,7 +5434,7 @@ char *CtdlGetSysConfig(char *sysconfname) { begin_critical_section(S_CONFIG); config_msgnum = (-1L); CtdlForEachMessage(MSGS_LAST, 1, NULL, sysconfname, NULL, - CtdlGetSysConfigBackend, NULL); + CtdlGetSysConfigBackend, NULL); msgnum = config_msgnum; end_critical_section(S_CONFIG); @@ -5272,9 +5455,9 @@ char *CtdlGetSysConfig(char *sysconfname) { CtdlGetRoom(&CC->room, hold_rm); if (conf != NULL) do { - extract_token(buf, conf, 0, '\n', sizeof buf); - strcpy(conf, &conf[strlen(buf)+1]); - } while ( (!IsEmptyStr(conf)) && (!IsEmptyStr(buf)) ); + extract_token(buf, conf, 0, '\n', sizeof buf); + strcpy(conf, &conf[strlen(buf)+1]); + } while ( (!IsEmptyStr(conf)) && (!IsEmptyStr(buf)) ); return(conf); } @@ -5336,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");