X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmsgbase.c;h=291d54fdda6245be56812a34f4fd6018940f003c;hb=7e5d9e93cc7fdc560eac95647fe329d818444226;hp=2ec3668c0197f1778d6d2932b9b913b413367926;hpb=49548fc3d014f7934231cce0e57e8a3e69dc3683;p=citadel.git diff --git a/citadel/msgbase.c b/citadel/msgbase.c index 2ec3668c0..291d54fdd 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "citadel.h" #include "server.h" #include "serv_extensions.h" @@ -44,21 +45,14 @@ #include "file_ops.h" #include "config.h" #include "control.h" -#include "tools.h" -#include "mime_parser.h" -#include "html.h" #include "genstamp.h" #include "internet_addressing.h" -#include "serv_fulltext.h" -#include "vcard.h" #include "euidindex.h" #include "journaling.h" #include "citadel_dirs.h" +#include "clientsocket.h" #include "serv_network.h" - -#ifdef HAVE_LIBSIEVE -# include "serv_sieve.h" -#endif /* HAVE_LIBSIEVE */ +#include "threads.h" long config_msgnum; struct addresses_to_be_filed *atbf = NULL; @@ -106,7 +100,7 @@ char *msgkeys[] = { "time", "subj", NULL, - NULL, + "wefw", NULL, "cccc", NULL @@ -150,6 +144,9 @@ int alias(char *name) char testnode[64]; char buf[SIZ]; + char original_name[256]; + safestrncpy(original_name, name, sizeof original_name); + striplt(name); remove_any_whitespace_to_the_left_or_right_of_at_symbol(name); stripallbut(name, '<', '>'); @@ -184,14 +181,16 @@ int alias(char *name) strcpy(name, aaa); } - lprintf(CTDL_INFO, "Mail is being forwarded to %s\n", name); + if (strcasecmp(original_name, name)) { + CtdlLogPrintf(CTDL_INFO, "%s is being forwarded to %s\n", original_name, name); + } /* Change "user @ xxx" to "user" if xxx is an alias for this host */ for (a=0; a\n", name); + CtdlLogPrintf(CTDL_INFO, "Changed to <%s>\n", name); } } } @@ -357,7 +356,7 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, return; } - lprintf(CTDL_DEBUG, "CtdlSetSeen(%d msgs starting with %ld, %d, %d)\n", + CtdlLogPrintf(CTDL_DEBUG, "CtdlSetSeen(%d msgs starting with %ld, %d, %d)\n", num_target_msgnums, target_msgnums[0], target_setting, which_set); @@ -391,7 +390,7 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, break; } - /* lprintf(CTDL_DEBUG, "before optimize: %s\n", vset); */ + /* CtdlLogPrintf(CTDL_DEBUG, "before optimize: %s\n", vset); */ /* Translate the existing sequence set into an array of booleans */ num_sets = num_tokens(vset, ','); @@ -490,7 +489,7 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, } free(is_set); - /* lprintf(CTDL_DEBUG, " after optimize: %s\n", vset); */ + /* CtdlLogPrintf(CTDL_DEBUG, " after optimize: %s\n", vset); */ free(msglist); CtdlSetRelationship(&vbuf, ((which_user != NULL) ? which_user : &CC->user), @@ -524,6 +523,14 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, int printed_lastold = 0; int num_search_msgs = 0; long *search_msgs = NULL; + regex_t re; + int need_to_free_re = 0; + regmatch_t pm; + + if (content_type) if (!IsEmptyStr(content_type)) { + regcomp(&re, content_type, 0); + need_to_free_re = 1; + } /* Learn about the user and room in question */ getuser(&CC->user, CC->curr_user); @@ -533,10 +540,9 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long)); if (cdbfr != NULL) { msglist = (long *) cdbfr->ptr; - cdbfr->ptr = NULL; /* CtdlForEachMessage() now owns this memory */ num_msgs = cdbfr->len / sizeof(long); - cdb_free(cdbfr); } else { + if (need_to_free_re) regfree(&re); return 0; /* No messages at all? No further action. */ } @@ -549,7 +555,7 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, /* If the caller is looking for a specific MIME type, filter * out all messages which are not of the type requested. */ - if (content_type != NULL) if (strlen(content_type) > 0) { + if (content_type != NULL) if (!IsEmptyStr(content_type)) { /* This call to GetMetaData() sits inside this loop * so that we only do the extra database read per msg @@ -562,7 +568,8 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, */ GetMetaData(&smi, msglist[a]); - if (strcasecmp(smi.meta_content_type, content_type)) { + /* if (strcasecmp(smi.meta_content_type, content_type)) { old non-regex way */ + if (regexec(&re, smi.meta_content_type, 1, &pm, 0) != 0) { msglist[a] = 0L; } } @@ -599,7 +606,13 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, * over again. */ if ( (num_msgs > 0) && (mode == MSGS_SEARCH) && (search_string) ) { - ft_search(&num_search_msgs, &search_msgs, search_string); + + /* Call search module via hook mechanism. + * NULL means use any search function available. + * otherwise replace with a char * to name of search routine + */ + CtdlModuleDoSearch(&num_search_msgs, &search_msgs, search_string, "fulltext"); + if (num_search_msgs > 0) { int orig_num_msgs; @@ -663,7 +676,8 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, ++num_processed; } } - free(msglist); /* Clean up */ + cdb_free(cdbfr); /* Clean up */ + if (need_to_free_re) regfree(&re); return num_processed; } @@ -730,7 +744,7 @@ void cmd_msgs(char *cmdbuf) template->cm_magic = CTDLMESSAGE_MAGIC; template->cm_anon_type = MES_NORMAL; - while(client_getln(buf, sizeof buf), strcmp(buf,"000")) { + while(client_getln(buf, sizeof buf) >= 0 && strcmp(buf,"000")) { extract_token(tfield, buf, 0, '|', sizeof tfield); extract_token(tvalue, buf, 1, '|', sizeof tvalue); for (i='A'; i<='Z'; ++i) if (msgkeys[i]!=NULL) { @@ -791,7 +805,7 @@ void do_help_subst(char *buffer) help_subst(buffer, "^variantname", CITADEL); snprintf(buf2, sizeof buf2, "%d", config.c_maxsessions); help_subst(buffer, "^maxsessions", buf2); - help_subst(buffer, "^bbsdir", ctdl_bbsbase_dir); + help_subst(buffer, "^bbsdir", ctdl_message_dir); } @@ -980,7 +994,7 @@ void mime_spew_section(char *name, char *filename, char *partnum, char *disp, *found_it = 1; - cprintf("%d %d\n", BINARY_FOLLOWS, length); + cprintf("%d %d\n", BINARY_FOLLOWS, (int)length); client_write(content, length); } @@ -1002,7 +1016,7 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) cit_uint8_t ch; cit_uint8_t field_header; - lprintf(CTDL_DEBUG, "CtdlFetchMessage(%ld, %d)\n", msgnum, with_body); + CtdlLogPrintf(CTDL_DEBUG, "CtdlFetchMessage(%ld, %d)\n", msgnum, with_body); dmsgtext = cdb_fetch(CDB_MSGMAIN, &msgnum, sizeof(long)); if (dmsgtext == NULL) { @@ -1018,9 +1032,7 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) */ ch = *mptr++; if (ch != 255) { - lprintf(CTDL_ERR, - "Message %ld appears to be corrupted.\n", - msgnum); + CtdlLogPrintf(CTDL_ERR, "Message %ld appears to be corrupted.\n", msgnum); cdb_free(dmsgtext); return NULL; } @@ -1083,7 +1095,7 @@ int is_valid_message(struct CtdlMessage *msg) { if (msg == NULL) return 0; if ((msg->cm_magic) != CTDLMESSAGE_MAGIC) { - lprintf(CTDL_WARNING, "is_valid_message() -- self-check failed\n"); + CtdlLogPrintf(CTDL_WARNING, "is_valid_message() -- self-check failed\n"); return 0; } return 1; @@ -1130,7 +1142,7 @@ void fixed_output_pre(char *name, char *filename, char *partnum, char *disp, struct ma_info *ma; ma = (struct ma_info *)cbuserdata; - lprintf(CTDL_DEBUG, "fixed_output_pre() type=<%s>\n", cbtype); + CtdlLogPrintf(CTDL_DEBUG, "fixed_output_pre() type=<%s>\n", cbtype); if (!strcasecmp(cbtype, "multipart/alternative")) { ++ma->is_ma; ma->did_print = 0; @@ -1150,7 +1162,7 @@ void fixed_output_post(char *name, char *filename, char *partnum, char *disp, struct ma_info *ma; ma = (struct ma_info *)cbuserdata; - lprintf(CTDL_DEBUG, "fixed_output_post() type=<%s>\n", cbtype); + CtdlLogPrintf(CTDL_DEBUG, "fixed_output_post() type=<%s>\n", cbtype); if (!strcasecmp(cbtype, "multipart/alternative")) { --ma->is_ma; ma->did_print = 0; @@ -1174,7 +1186,7 @@ void fixed_output(char *name, char *filename, char *partnum, char *disp, ma = (struct ma_info *)cbuserdata; - lprintf(CTDL_DEBUG, + CtdlLogPrintf(CTDL_DEBUG, "fixed_output() part %s: %s (%s) (%ld bytes)\n", partnum, filename, cbtype, (long)length); @@ -1183,14 +1195,13 @@ 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) ) { - lprintf(CTDL_DEBUG, "Skipping part %s (%s)\n", - partnum, cbtype); + CtdlLogPrintf(CTDL_DEBUG, "Skipping part %s (%s)\n", partnum, cbtype); return; } ma->did_print = 1; if ( (!strcasecmp(cbtype, "text/plain")) - || (strlen(cbtype)==0) ) { + || (IsEmptyStr(cbtype)) ) { wptr = content; if (length > 0) { client_write(wptr, length); @@ -1247,14 +1258,18 @@ void choose_preferred(char *name, char *filename, char *partnum, char *disp, ma = (struct ma_info *)cbuserdata; - if (ma->is_ma > 0) { - for (i=0; ipreferred_formats, '|'); ++i) { - extract_token(buf, CC->preferred_formats, i, '|', sizeof buf); - if ( (!strcasecmp(buf, cbtype)) && (!ma->freeze) ) { - if (i < ma->chosen_pref) { - safestrncpy(ma->chosen_part, partnum, sizeof ma->chosen_part); - ma->chosen_pref = i; - } + // NOTE: REMOVING THIS CONDITIONAL FIXES BUG 220 + // http://bugzilla.citadel.org/show_bug.cgi?id=220 + // I don't know if there are any side effects! Please TEST TEST TEST + //if (ma->is_ma > 0) { + + for (i=0; ipreferred_formats, '|'); ++i) { + extract_token(buf, CC->preferred_formats, i, '|', sizeof buf); + if ( (!strcasecmp(buf, cbtype)) && (!ma->freeze) ) { + if (i < ma->chosen_pref) { + CtdlLogPrintf(CTDL_DEBUG, "Setting chosen part: <%s>\n", partnum); + safestrncpy(ma->chosen_part, partnum, sizeof ma->chosen_part); + ma->chosen_pref = i; } } } @@ -1290,19 +1305,19 @@ void output_preferred(char *name, char *filename, char *partnum, char *disp, if (text_content[length-1] != '\n') { ++add_newline; } - cprintf("Content-type: %s", cbtype); - if (strlen(cbcharset) > 0) { + if (!IsEmptyStr(cbcharset)) { cprintf("; charset=%s", cbcharset); } cprintf("\nContent-length: %d\n", (int)(length + add_newline) ); - if (strlen(encoding) > 0) { + if (!IsEmptyStr(encoding)) { cprintf("Content-transfer-encoding: %s\n", encoding); } else { cprintf("Content-transfer-encoding: 7bit\n"); } + cprintf("X-Citadel-MSG4-Partnum: %s\n", partnum); cprintf("\n"); client_write(content, length); if (add_newline) cprintf("\n"); @@ -1363,7 +1378,7 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ int retcode = om_no_such_msg; struct encapmsg encap; - lprintf(CTDL_DEBUG, "CtdlOutputMsg() msgnum=%ld, mode=%d, section=%s\n", + CtdlLogPrintf(CTDL_DEBUG, "CtdlOutputMsg() msgnum=%ld, mode=%d, section=%s\n", msg_num, mode, (section ? section : "<>") ); @@ -1397,7 +1412,7 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ /* Here is the weird form of this command, to process only an * encapsulated message/rfc822 section. */ - if (section) if (strlen(section)>0) if (strcmp(section, "0")) { + if (section) if (!IsEmptyStr(section)) if (strcmp(section, "0")) { memset(&encap, 0, sizeof encap); safestrncpy(encap.desired_section, section, sizeof encap.desired_section); mime_parser(TheMessage->cm_fields['M'], @@ -1429,9 +1444,7 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ } /* Ok, output the message now */ - retcode = CtdlOutputPreLoadedMsg( - TheMessage, mode, - headers_only, do_proto, crlf); + retcode = CtdlOutputPreLoadedMsg(TheMessage, mode, headers_only, do_proto, crlf); CtdlFreeMessage(TheMessage); return(retcode); @@ -1440,7 +1453,6 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ /* * Get a message off disk. (returns om_* values found in msgbase.h) - * */ int CtdlOutputPreLoadedMsg( struct CtdlMessage *TheMessage, @@ -1449,7 +1461,7 @@ int CtdlOutputPreLoadedMsg( int do_proto, /* do Citadel protocol responses? */ int crlf /* Use CRLF newlines instead of LF? */ ) { - int i, k; + int i, j, k; char buf[SIZ]; cit_uint8_t ch; char allkeys[30]; @@ -1472,7 +1484,7 @@ int CtdlOutputPreLoadedMsg( char mid[100]; char datestamp[100]; - lprintf(CTDL_DEBUG, "CtdlOutputPreLoadedMsg(TheMessage=%s, %d, %d, %d, %d\n", + CtdlLogPrintf(CTDL_DEBUG, "CtdlOutputPreLoadedMsg(TheMessage=%s, %d, %d, %d, %d\n", ((TheMessage == NULL) ? "NULL" : "not null"), mode, headers_only, do_proto, crlf); @@ -1480,7 +1492,7 @@ int CtdlOutputPreLoadedMsg( nl = (crlf ? "\r\n" : "\n"); if (!is_valid_message(TheMessage)) { - lprintf(CTDL_ERR, + CtdlLogPrintf(CTDL_ERR, "ERROR: invalid preloaded message for output\n"); return(om_no_such_msg); } @@ -1588,7 +1600,7 @@ int CtdlOutputPreLoadedMsg( */ suppress_f = 0; if (TheMessage->cm_fields['N'] != NULL) - if (strlen(TheMessage->cm_fields['N']) > 0) + if (!IsEmptyStr(TheMessage->cm_fields['N'])) if (haschar(TheMessage->cm_fields['N'], '.') == 0) { suppress_f = 1; } @@ -1662,12 +1674,35 @@ int CtdlOutputPreLoadedMsg( else if (i == 'N') safestrncpy(snode, mptr, sizeof snode); else if (i == 'R') - cprintf("To: %s%s", mptr, nl); + { + if (haschar(mptr, '@') == 0) + { + cprintf("To: %s@%s%s", mptr, config.c_fqdn, nl); + } + else + { + cprintf("To: %s%s", mptr, nl); + } + } else if (i == 'T') { datestring(datestamp, sizeof datestamp, atol(mptr), DATESTRING_RFC822); cprintf("Date: %s%s", datestamp, nl); } + else if (i == 'W') { + cprintf("References: "); + k = num_tokens(mptr, '|'); + for (j=0; j", buf); + if (j == (k-1)) { + cprintf("%s", nl); + } + else { + cprintf(" "); + } + } + } } } if (subject_found == 0) { @@ -1675,7 +1710,7 @@ int CtdlOutputPreLoadedMsg( } } - for (i=0; icm_anon_type == MES_ANONOPT)) { cprintf("From: \"anonymous\" %s", nl); } - else if (strlen(fuser) > 0) { + else if (!IsEmptyStr(fuser)) { cprintf("From: \"%s\" <%s>%s", luser, fuser, nl); } else { @@ -1788,22 +1823,27 @@ START_TEXT: * what message transfer format is in use. */ if (TheMessage->cm_format_type == FMT_FIXED) { + int buflen; if (mode == MT_MIME) { cprintf("Content-type: text/plain\n\n"); } - strcpy(buf, ""); + *buf = '\0'; + buflen = 0; while (ch = *mptr++, ch > 0) { if (ch == 13) ch = 10; - if ((ch == 10) || (strlen(buf) > 250)) { + if ((ch == 10) || (buflen > 250)) { + buf[buflen] = '\0'; cprintf("%s%s", buf, nl); - strcpy(buf, ""); + *buf = '\0'; + buflen = 0; } else { - buf[strlen(buf) + 1] = 0; - buf[strlen(buf)] = ch; + buf[buflen] = ch; + buflen++; } } - if (strlen(buf) > 0) + buf[buflen] = '\0'; + if (!IsEmptyStr(buf)) cprintf("%s%s", buf, nl); } @@ -1837,7 +1877,7 @@ START_TEXT: *choose_preferred, *fixed_output_pre, *fixed_output_post, (void *)&ma, 0); mime_parser(mptr, NULL, - *output_preferred, NULL, NULL, (void *)&ma, 0); + *output_preferred, NULL, NULL, (void *)&ma, CC->msg4_dont_decode); } else { ma.use_fo_hooks = 1; @@ -1946,9 +1986,14 @@ void cmd_msg4(char *cmdbuf) */ void cmd_msgp(char *cmdbuf) { - safestrncpy(CC->preferred_formats, cmdbuf, - sizeof(CC->preferred_formats)); - cprintf("%d ok\n", CIT_OK); + if (!strcasecmp(cmdbuf, "dont_decode")) { + CC->msg4_dont_decode = 1; + cprintf("%d MSG4 will not pre-decode messages.\n", CIT_OK); + } + else { + safestrncpy(CC->preferred_formats, cmdbuf, sizeof(CC->preferred_formats)); + cprintf("%d Preferred MIME formats have been set.\n", CIT_OK); + } } @@ -2011,7 +2056,7 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms long *msgs_to_be_merged = NULL; int num_msgs_to_be_merged = 0; - lprintf(CTDL_DEBUG, + CtdlLogPrintf(CTDL_DEBUG, "CtdlSaveMsgPointersInRoom(room=%s, num_msgs=%d, repl=%d)\n", roomname, num_newmsgs, do_repl_check); @@ -2026,7 +2071,7 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms if (lgetroom(&CC->room, ((roomname != NULL) ? roomname : CC->room.QRname) ) != 0) { - lprintf(CTDL_ERR, "No such room <%s>\n", roomname); + CtdlLogPrintf(CTDL_ERR, "No such room <%s>\n", roomname); return(ERROR + ROOM_NOT_FOUND); } @@ -2063,14 +2108,14 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms } } - lprintf(9, "%d unique messages to be merged\n", num_msgs_to_be_merged); + CtdlLogPrintf(9, "%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) { - lprintf(CTDL_ALERT, "ERROR: can't realloc message list!\n"); + CtdlLogPrintf(CTDL_ALERT, "ERROR: can't realloc message list!\n"); } memcpy(&msglist[num_msgs], msgs_to_be_merged, (sizeof(long) * num_msgs_to_be_merged) ); num_msgs += num_msgs_to_be_merged; @@ -2094,7 +2139,7 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms /* Perform replication checks if necessary */ if ( (DoesThisRoomNeedEuidIndexing(&CC->room)) && (do_repl_check) ) { - lprintf(CTDL_DEBUG, "CtdlSaveMsgPointerInRoom() doing repl checks\n"); + CtdlLogPrintf(CTDL_DEBUG, "CtdlSaveMsgPointerInRoom() doing repl checks\n"); for (i=0; iroom, NULL); - -#ifdef HAVE_LIBSIEVE - /* If this is someone's inbox, submit the room for sieve processing */ - if (!strcasecmp(&CC->room.QRname[11], MAILROOM)) { - sieve_queue_room(&CC->room); - } -#endif /* HAVE_LIBSIEVE */ + /* Submit this room for processing by hooks */ + PerformRoomHooks(&CC->room); /* Go back to the room we were in before we wandered here... */ getroom(&CC->room, hold_rm); @@ -2218,7 +2256,7 @@ long send_message(struct CtdlMessage *msg) { /* Write our little bundle of joy into the message base */ if (cdb_store(CDB_MSGMAIN, &newmsgid, (int)sizeof(long), smr.ser, smr.len) < 0) { - lprintf(CTDL_ERR, "Can't store message\n"); + CtdlLogPrintf(CTDL_ERR, "Can't store message\n"); retval = 0L; } else { if (is_bigmsg) { @@ -2261,7 +2299,7 @@ void serialize_message(struct ser_ret *ret, /* return values */ * Check for valid message format */ if (is_valid_message(msg) == 0) { - lprintf(CTDL_ERR, "serialize_message() aborting due to invalid message\n"); + CtdlLogPrintf(CTDL_ERR, "serialize_message() aborting due to invalid message\n"); ret->len = 0; ret->ser = NULL; return; @@ -2274,7 +2312,7 @@ void serialize_message(struct ser_ret *ret, /* return values */ ret->ser = malloc(ret->len); if (ret->ser == NULL) { - lprintf(CTDL_ERR, "serialize_message() malloc(%ld) failed: %s\n", + CtdlLogPrintf(CTDL_ERR, "serialize_message() malloc(%ld) failed: %s\n", (long)ret->len, strerror(errno)); ret->len = 0; ret->ser = NULL; @@ -2292,13 +2330,50 @@ 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) lprintf(CTDL_ERR, "ERROR: len=%ld wlen=%ld\n", + if (ret->len != wlen) CtdlLogPrintf(CTDL_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) { + CtdlLogPrintf(CTDL_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]]); + client_write (buf, strlen(buf)); + } + + return; +} + + /* * Check to see if any messages already exist in the current room which @@ -2309,19 +2384,19 @@ void ReplicationChecks(struct CtdlMessage *msg) { if (DoesThisRoomNeedEuidIndexing(&CC->room) == 0) return; - lprintf(CTDL_DEBUG, "Performing replication checks in <%s>\n", + CtdlLogPrintf(CTDL_DEBUG, "Performing replication checks in <%s>\n", CC->room.QRname); /* No exclusive id? Don't do anything. */ if (msg == NULL) return; if (msg->cm_fields['E'] == NULL) return; - if (strlen(msg->cm_fields['E']) == 0) return; - /*lprintf(CTDL_DEBUG, "Exclusive ID: <%s> for room <%s>\n", + if (IsEmptyStr(msg->cm_fields['E'])) return; + /*CtdlLogPrintf(CTDL_DEBUG, "Exclusive ID: <%s> for room <%s>\n", msg->cm_fields['E'], CC->room.QRname);*/ old_msgnum = locate_message_by_euid(msg->cm_fields['E'], &CC->room); if (old_msgnum > 0L) { - lprintf(CTDL_DEBUG, "ReplicationChecks() replacing message %ld\n", old_msgnum); + CtdlLogPrintf(CTDL_DEBUG, "ReplicationChecks() replacing message %ld\n", old_msgnum); CtdlDeleteMessages(CC->room.QRname, &old_msgnum, 1, ""); } } @@ -2350,15 +2425,17 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ FILE *network_fp = NULL; static int seqnum = 1; struct CtdlMessage *imsg = NULL; - char *instr; + char *instr = NULL; + size_t instr_alloc = 0; struct ser_ret smr; char *hold_R, *hold_D; char *collected_addresses = NULL; struct addresses_to_be_filed *aptr = NULL; char *saved_rfc822_version = NULL; int qualified_for_journaling = 0; + struct CitContext *CCC = CC; /* CachedCitContext - performance boost */ - lprintf(CTDL_DEBUG, "CtdlSubmitMsg() called\n"); + CtdlLogPrintf(CTDL_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 @@ -2374,7 +2451,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ if (msg->cm_fields['P'] == NULL) { if (msg->cm_fields['A'] != NULL) { msg->cm_fields['P'] = strdup(msg->cm_fields['A']); - for (a=0; acm_fields['P']); ++a) { + for (a=0; !IsEmptyStr(&msg->cm_fields['P'][a]); ++a) { if (isspace(msg->cm_fields['P'][a])) { msg->cm_fields['P'][a] = ' '; } @@ -2394,7 +2471,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) { - lprintf(CTDL_ERR, "ERROR: attempt to save message with NULL body\n"); + CtdlLogPrintf(CTDL_ERR, "ERROR: attempt to save message with NULL body\n"); return(-2); } @@ -2407,46 +2484,49 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ break; case 4: strcpy(content_type, "text/plain"); - mptr = bmstrcasestr(msg->cm_fields['M'], "Content-type: "); + mptr = bmstrcasestr(msg->cm_fields['M'], "Content-type:"); if (mptr != NULL) { - safestrncpy(content_type, &mptr[14], - sizeof content_type); - for (a = 0; a < strlen(content_type); ++a) { - if ((content_type[a] == ';') - || (content_type[a] == ' ') - || (content_type[a] == 13) - || (content_type[a] == 10)) { - content_type[a] = 0; + char *aptr; + safestrncpy(content_type, &mptr[13], sizeof content_type); + striplt(content_type); + aptr = content_type; + while (!IsEmptyStr(aptr)) { + if ((*aptr == ';') + || (*aptr == ' ') + || (*aptr == 13) + || (*aptr == 10)) { + *aptr = 0; } + else aptr++; } } } /* Goto the correct room */ - lprintf(CTDL_DEBUG, "Selected room %s\n", (recps) ? CC->room.QRname : SENTITEMS); - strcpy(hold_rm, CC->room.QRname); - strcpy(actual_rm, CC->room.QRname); + CtdlLogPrintf(CTDL_DEBUG, "Selected room %s\n", (recps) ? CCC->room.QRname : SENTITEMS); + strcpy(hold_rm, CCC->room.QRname); + strcpy(actual_rm, CCC->room.QRname); if (recps != NULL) { strcpy(actual_rm, SENTITEMS); } /* If the user is a twit, move to the twit room for posting */ if (TWITDETECT) { - if (CC->user.axlevel == 2) { + if (CCC->user.axlevel == 2) { strcpy(hold_rm, actual_rm); strcpy(actual_rm, config.c_twitroom); - lprintf(CTDL_DEBUG, "Diverting to twit room\n"); + CtdlLogPrintf(CTDL_DEBUG, "Diverting to twit room\n"); } } /* ...or if this message is destined for Aide> then go there. */ - if (strlen(force_room) > 0) { + if (!IsEmptyStr(force_room)) { strcpy(actual_rm, force_room); } - lprintf(CTDL_DEBUG, "Final selection: %s\n", actual_rm); - if (strcasecmp(actual_rm, CC->room.QRname)) { - /* getroom(&CC->room, actual_rm); */ + CtdlLogPrintf(CTDL_DEBUG, "Final selection: %s\n", actual_rm); + if (strcasecmp(actual_rm, CCC->room.QRname)) { + /* getroom(&CCC->room, actual_rm); */ usergoto(actual_rm, 0, 1, NULL, NULL); } @@ -2454,23 +2534,23 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * If this message has no O (room) field, generate one. */ if (msg->cm_fields['O'] == NULL) { - msg->cm_fields['O'] = strdup(CC->room.QRname); + msg->cm_fields['O'] = strdup(CCC->room.QRname); } /* Perform "before save" hooks (aborting if any return nonzero) */ - lprintf(CTDL_DEBUG, "Performing before-save hooks\n"); + CtdlLogPrintf(CTDL_DEBUG, "Performing before-save hooks\n"); if (PerformMessageHooks(msg, EVT_BEFORESAVE) > 0) return(-3); /* * If this message has an Exclusive ID, and the room is replication * checking enabled, then do replication checks. */ - if (DoesThisRoomNeedEuidIndexing(&CC->room)) { + if (DoesThisRoomNeedEuidIndexing(&CCC->room)) { ReplicationChecks(msg); } /* Save it to disk */ - lprintf(CTDL_DEBUG, "Saving to disk\n"); + CtdlLogPrintf(CTDL_DEBUG, "Saving to disk\n"); newmsgid = send_message(msg); if (newmsgid <= 0L) return(-5); @@ -2478,7 +2558,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * be a critical section because nobody else knows about this message * yet. */ - lprintf(CTDL_DEBUG, "Creating MetaData record\n"); + CtdlLogPrintf(CTDL_DEBUG, "Creating MetaData record\n"); memset(&smi, 0, sizeof(struct MetaData)); smi.meta_msgnum = newmsgid; smi.meta_refcount = 0; @@ -2495,32 +2575,32 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * 2. If journaling is enabled, we will need an RFC822 version of the * message to attach to the journalized copy. */ - if (CC->redirect_buffer != NULL) { - lprintf(CTDL_ALERT, "CC->redirect_buffer is not NULL during message submission!\n"); + if (CCC->redirect_buffer != NULL) { + CtdlLogPrintf(CTDL_ALERT, "CCC->redirect_buffer is not NULL during message submission!\n"); abort(); } - CC->redirect_buffer = malloc(SIZ); - CC->redirect_len = 0; - CC->redirect_alloc = SIZ; + CCC->redirect_buffer = malloc(SIZ); + CCC->redirect_len = 0; + CCC->redirect_alloc = SIZ; CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1); - smi.meta_rfc822_length = CC->redirect_len; - saved_rfc822_version = CC->redirect_buffer; - CC->redirect_buffer = NULL; - CC->redirect_len = 0; - CC->redirect_alloc = 0; + smi.meta_rfc822_length = CCC->redirect_len; + saved_rfc822_version = CCC->redirect_buffer; + CCC->redirect_buffer = NULL; + CCC->redirect_len = 0; + CCC->redirect_alloc = 0; PutMetaData(&smi); /* Now figure out where to store the pointers */ - lprintf(CTDL_DEBUG, "Storing pointers\n"); + CtdlLogPrintf(CTDL_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 * is no local sender; it would otherwise go to the Trashcan). */ - if ((!CC->internal_pgm) || (recps == NULL)) { + if ((!CCC->internal_pgm) || (recps == NULL)) { if (CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 1, msg) != 0) { - lprintf(CTDL_ERR, "ERROR saving message pointer!\n"); + CtdlLogPrintf(CTDL_ERR, "ERROR saving message pointer!\n"); CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg); } } @@ -2537,15 +2617,15 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ for (i=0; irecp_room, '|'); ++i) { extract_token(recipient, recps->recp_room, i, '|', sizeof recipient); - lprintf(CTDL_DEBUG, "Delivering to room <%s>\n", recipient); + CtdlLogPrintf(CTDL_DEBUG, "Delivering to room <%s>\n", recipient); CtdlSaveMsgPointerInRoom(recipient, newmsgid, 0, msg); } /* Bump this user's messages posted counter. */ - lprintf(CTDL_DEBUG, "Updating user\n"); - lgetuser(&CC->user, CC->curr_user); - CC->user.posted = CC->user.posted + 1; - lputuser(&CC->user); + CtdlLogPrintf(CTDL_DEBUG, "Updating user\n"); + lgetuser(&CCC->user, CCC->curr_user); + CCC->user.posted = CCC->user.posted + 1; + lputuser(&CCC->user); /* If this is private, local mail, make a copy in the * recipient's mailbox and bump the reference count. @@ -2555,20 +2635,21 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ for (i=0; irecp_local, '|'); ++i) { extract_token(recipient, recps->recp_local, i, '|', sizeof recipient); - lprintf(CTDL_DEBUG, "Delivering private local mail to <%s>\n", + CtdlLogPrintf(CTDL_DEBUG, "Delivering private local mail to <%s>\n", recipient); if (getuser(&userbuf, recipient) == 0) { // Add a flag so the Funambol module knows its mail msg->cm_fields['W'] = strdup(recipient); - MailboxName(actual_rm, sizeof actual_rm, - &userbuf, MAILROOM); + MailboxName(actual_rm, sizeof actual_rm, &userbuf, MAILROOM); CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 0, msg); BumpNewMailCounter(userbuf.usernum); - if (strlen(config.c_funambol_host) > 0) { + 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 = malloc(SIZ * 2); - snprintf(instr, SIZ * 2, + * 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@%s\n", SPOOLMIME, newmsgid, (long)time(NULL), @@ -2582,21 +2663,21 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ 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->cm_fields['M'] = instr; /* imsg owns this memory now */ imsg->cm_fields['W'] = strdup(recipient); CtdlSubmitMsg(imsg, NULL, FNBL_QUEUE_ROOM); CtdlFreeMessage(imsg); } } else { - lprintf(CTDL_DEBUG, "No user <%s>\n", recipient); + CtdlLogPrintf(CTDL_DEBUG, "No user <%s>\n", recipient); CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg); } } /* Perform "after save" hooks */ - lprintf(CTDL_DEBUG, "Performing after-save hooks\n"); + CtdlLogPrintf(CTDL_DEBUG, "Performing after-save hooks\n"); PerformMessageHooks(msg, EVT_AFTERSAVE); /* For IGnet mail, we have to save a new copy into the spooler for @@ -2625,7 +2706,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ snprintf(submit_filename, sizeof submit_filename, "%s/netmail.%04lx.%04x.%04x", ctdl_netin_dir, - (long) getpid(), CC->cs_pid, ++seqnum); + (long) getpid(), CCC->cs_pid, ++seqnum); network_fp = fopen(submit_filename, "wb+"); if (network_fp != NULL) { fwrite(smr.ser, smr.len, 1, network_fp); @@ -2641,9 +2722,8 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } /* Go back to the room we started from */ - lprintf(CTDL_DEBUG, "Returning to original room %s\n", hold_rm); - if (strcasecmp(hold_rm, CC->room.QRname)) - /* getroom(&CC->room, hold_rm); */ + CtdlLogPrintf(CTDL_DEBUG, "Returning to original room %s\n", hold_rm); + if (strcasecmp(hold_rm, CCC->room.QRname)) usergoto(hold_rm, 0, 1, NULL, NULL); /* For internet mail, generate delivery instructions. @@ -2653,9 +2733,10 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ */ if (recps != NULL) if (recps->num_internet > 0) { - lprintf(CTDL_DEBUG, "Generating delivery instructions\n"); - instr = malloc(SIZ * 2); - snprintf(instr, SIZ * 2, + CtdlLogPrintf(CTDL_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@%s\n", SPOOLMIME, newmsgid, (long)time(NULL), @@ -2664,10 +2745,12 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ for (i=0; irecp_internet, '|'); ++i) { size_t tmp = strlen(instr); - extract_token(recipient, recps->recp_internet, - i, '|', sizeof recipient); - snprintf(&instr[tmp], SIZ * 2 - tmp, - "remote|%s|0||\n", recipient); + 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); + } + snprintf(&instr[tmp], instr_alloc - tmp, "remote|%s|0||\n", recipient); } imsg = malloc(sizeof(struct CtdlMessage)); @@ -2677,7 +2760,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ 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->cm_fields['M'] = instr; /* imsg owns this memory now */ CtdlSubmitMsg(imsg, NULL, SMTP_SPOOLOUT_ROOM); CtdlFreeMessage(imsg); } @@ -2685,7 +2768,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* * Any addresses to harvest for someone's address book? */ - if ( (CC->logged_in) && (recps != NULL) ) { + if ( (CCC->logged_in) && (recps != NULL) ) { collected_addresses = harvest_collected_addresses(msg); } @@ -2695,7 +2778,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ malloc(sizeof(struct addresses_to_be_filed)); aptr->next = atbf; MailboxName(actual_rm, sizeof actual_rm, - &CC->user, USERCONTACTSROOM); + &CCC->user, USERCONTACTSROOM); aptr->roomname = strdup(actual_rm); aptr->collected_addresses = collected_addresses; atbf = aptr; @@ -2775,7 +2858,7 @@ void quickie_message(char *from, char *fromaddr, char *to, char *room, char *tex msg->cm_fields['N'] = strdup(NODENAME); if (to != NULL) { msg->cm_fields['R'] = strdup(to); - recp = validate_recipients(to); + recp = validate_recipients(to, NULL, 0); } if (subject != NULL) { msg->cm_fields['U'] = strdup(subject); @@ -2784,7 +2867,7 @@ void quickie_message(char *from, char *fromaddr, char *to, char *room, char *tex CtdlSubmitMsg(msg, recp, room); CtdlFreeMessage(msg); - if (recp != NULL) free(recp); + if (recp != NULL) free_recipients(recp); } @@ -2796,7 +2879,8 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ size_t maxlen, /* maximum message length */ char *exist, /* if non-null, append to it; exist is ALWAYS freed */ - int crlf /* CRLF newlines instead of LF */ + int crlf, /* CRLF newlines instead of LF */ + int sock /* socket handle or 0 for this session's client socket */ ) { char buf[1024]; int linelen; @@ -2836,7 +2920,12 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ /* read in the lines of message text one by one */ do { - if (client_getln(buf, (sizeof buf - 3)) < 1) finished = 1; + if (sock > 0) { + if (sock_getln(sock, buf, (sizeof buf - 3)) < 0) finished = 1; + } + else { + if (client_getln(buf, (sizeof buf - 3)) < 1) finished = 1; + } if (!strcmp(buf, terminator)) finished = 1; if (crlf) { strcat(buf, "\r\n"); @@ -2864,7 +2953,7 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ } else { buffer_len = (buffer_len * 2); m = ptr; - lprintf(CTDL_DEBUG, "buffer_len is now %ld\n", (long)buffer_len); + CtdlLogPrintf(CTDL_DEBUG, "buffer_len is now %ld\n", (long)buffer_len); } } @@ -2903,6 +2992,7 @@ struct CtdlMessage *CtdlMakeMessage( int type, /* see MES_ types in header file */ int format_type, /* variformat, plain text, MIME... */ char *fake_name, /* who we're masquerading as */ + char *my_email, /* which of my email addresses to use (empty is ok) */ char *subject, /* Subject (optional) */ char *supplied_euid, /* ...or NULL if this is irrelevant */ char *preformatted_text /* ...or NULL to read text from client */ @@ -2923,8 +3013,17 @@ struct CtdlMessage *CtdlMakeMessage( striplt(recipient); striplt(recp_cc); - snprintf(buf, sizeof buf, "cit%ld", author->usernum); /* Path */ - msg->cm_fields['P'] = strdup(buf); + /* Path or Return-Path */ + if (my_email == NULL) my_email = ""; + + if (!IsEmptyStr(my_email)) { + msg->cm_fields['P'] = strdup(my_email); + } + else { + snprintf(buf, sizeof buf, "%s", author->fullname); + msg->cm_fields['P'] = strdup(buf); + } + convert_spaces_to_underscores(msg->cm_fields['P']); snprintf(buf, sizeof buf, "%ld", (long)time(NULL)); /* timestamp */ msg->cm_fields['T'] = strdup(buf); @@ -2954,7 +3053,10 @@ struct CtdlMessage *CtdlMakeMessage( msg->cm_fields['D'] = strdup(dest_node); } - if ( (author == &CC->user) && (strlen(CC->cs_inet_email) > 0) ) { + if (!IsEmptyStr(my_email)) { + msg->cm_fields['F'] = strdup(my_email); + } + else if ( (author == &CC->user) && (!IsEmptyStr(CC->cs_inet_email)) ) { msg->cm_fields['F'] = strdup(CC->cs_inet_email); } @@ -2988,7 +3090,7 @@ struct CtdlMessage *CtdlMakeMessage( msg->cm_fields['M'] = preformatted_text; } else { - msg->cm_fields['M'] = CtdlReadMessageBody("000", config.c_maxmsglen, NULL, 0); + msg->cm_fields['M'] = CtdlReadMessageBody("000", config.c_maxmsglen, NULL, 0, 0); } return(msg); @@ -3000,13 +3102,65 @@ struct CtdlMessage *CtdlMakeMessage( * room. Returns a *CITADEL ERROR CODE* and puts a message in errmsgbuf, or * returns 0 on success. */ -int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, size_t n) { +int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, + size_t n, + const char* RemoteIdentifier, + int PostPublic) { int ra; - if (!(CC->logged_in)) { + if (!(CC->logged_in) && + (PostPublic == POST_LOGGED_IN)) { snprintf(errmsgbuf, n, "Not logged in."); return (ERROR + NOT_LOGGED_IN); } + else if (PostPublic == CHECK_EXISTANCE) { + return (0); // We're Evaling whether a recipient exists + } + else if (!(CC->logged_in)) { + + if ((CC->room.QRflags & QR_READONLY)) { + snprintf(errmsgbuf, n, "Not logged in."); + return (ERROR + NOT_LOGGED_IN); + } + if (CC->room.QRflags2 & QR2_MODERATED) { + snprintf(errmsgbuf, n, "Not logged in Moderation feature not yet implemented!"); + 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 (0); + + } if ((CC->user.axlevel < 2) && ((CC->room.QRflags & QR_MAILBOX) == 0)) { @@ -3052,13 +3206,17 @@ int CtdlCheckInternetMailPermission(struct ctdluser *who) { /* * Validate recipients, count delivery types and errors, and handle aliasing * FIXME check for dupes!!!!! + * * Returns 0 if all addresses are ok, ret->num_error = -1 if no addresses * were specified, or the number of addresses found invalid. - * caller needs to free the result. + * + * Caller needs to free the result using free_recipients() */ -struct recptypes *validate_recipients(char *supplied_recipients) { +struct recptypes *validate_recipients(char *supplied_recipients, + const char *RemoteIdentifier, + int Flags) { struct recptypes *ret; - char recipients[SIZ]; + char *recipients = NULL; char this_recp[256]; char this_recp_cooked[256]; char append[SIZ]; @@ -3068,28 +3226,48 @@ struct recptypes *validate_recipients(char *supplied_recipients) { int invalid; struct ctdluser tempUS; struct ctdlroom tempQR; + struct ctdlroom tempQR2; + int err = 0; + char errmsg[SIZ]; int in_quotes = 0; /* Initialize */ ret = (struct recptypes *) malloc(sizeof(struct recptypes)); if (ret == NULL) return(NULL); - memset(ret, 0, sizeof(struct recptypes)); - ret->num_local = 0; - ret->num_internet = 0; - ret->num_ignet = 0; - ret->num_error = 0; - ret->num_room = 0; + /* Set all strings to null and numeric values to zero */ + memset(ret, 0, sizeof(struct recptypes)); if (supplied_recipients == NULL) { - strcpy(recipients, ""); + recipients = strdup(""); } else { - safestrncpy(recipients, supplied_recipients, sizeof recipients); + recipients = strdup(supplied_recipients); } + /* Allocate some memory. Yes, this allocates 500% more memory than we will + * 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); + + 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->display_recp[0] = 0; + + ret->recptypes_magic = RECPTYPES_MAGIC; + /* Change all valid separator characters to commas */ - for (i=0; i 0) { + while (!IsEmptyStr(recipients)) { for (i=0; i<=strlen(recipients); ++i) { if (recipients[i] == '\"') in_quotes = 1 - in_quotes; @@ -3115,12 +3293,15 @@ struct recptypes *validate_recipients(char *supplied_recipients) { } striplt(this_recp); - lprintf(CTDL_DEBUG, "Evaluating recipient #%d: %s\n", num_recps, this_recp); + if (IsEmptyStr(this_recp)) + break; + CtdlLogPrintf(CTDL_DEBUG, "Evaluating recipient #%d: %s\n", num_recps, this_recp); ++num_recps; mailtype = alias(this_recp); mailtype = alias(this_recp); mailtype = alias(this_recp); - for (j=0; j<=strlen(this_recp); ++j) { + j = 0; + for (j=0; !IsEmptyStr(&this_recp[j]); ++j) { if (this_recp[j]=='_') { this_recp_cooked[j] = ' '; } @@ -3128,21 +3309,53 @@ struct recptypes *validate_recipients(char *supplied_recipients) { this_recp_cooked[j] = this_recp[j]; } } + this_recp_cooked[j] = '\0'; 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 (strlen(ret->recp_room) > 0) { + if (!IsEmptyStr(ret->recp_room)) { strcat(ret->recp_room, "|"); } strcat(ret->recp_room, this_recp); } + else if ( (!strncasecmp(this_recp, "room_", 5)) + && (!getroom(&tempQR, &this_recp_cooked[5])) ) { + + /* Save room so we can restore it later */ + tempQR2 = CC->room; + CC->room = tempQR; + + /* Check permissions to send mail to this room */ + err = CtdlDoIHavePermissionToPostInThisRoom(errmsg, + sizeof errmsg, + RemoteIdentifier, + Flags + ); + 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 (getuser(&tempUS, this_recp) == 0) { ++ret->num_local; strcpy(this_recp, tempUS.fullname); - if (strlen(ret->recp_local) > 0) { + if (!IsEmptyStr(ret->recp_local)) { strcat(ret->recp_local, "|"); } strcat(ret->recp_local, this_recp); @@ -3150,19 +3363,11 @@ struct recptypes *validate_recipients(char *supplied_recipients) { else if (getuser(&tempUS, this_recp_cooked) == 0) { ++ret->num_local; strcpy(this_recp, tempUS.fullname); - if (strlen(ret->recp_local) > 0) { + if (!IsEmptyStr(ret->recp_local)) { strcat(ret->recp_local, "|"); } strcat(ret->recp_local, this_recp); } - else if ( (!strncasecmp(this_recp, "room_", 5)) - && (!getroom(&tempQR, &this_recp_cooked[5])) ) { - ++ret->num_room; - if (strlen(ret->recp_room) > 0) { - strcat(ret->recp_room, "|"); - } - strcat(ret->recp_room, &this_recp_cooked[5]); - } else { ++ret->num_error; invalid = 1; @@ -3175,13 +3380,13 @@ struct recptypes *validate_recipients(char *supplied_recipients) { * because if the address were valid, we would have * already translated it to a local address by now. */ - if (IsDirectory(this_recp)) { + if (IsDirectory(this_recp, 0)) { ++ret->num_error; invalid = 1; } else { ++ret->num_internet; - if (strlen(ret->recp_internet) > 0) { + if (!IsEmptyStr(ret->recp_internet)) { strcat(ret->recp_internet, "|"); } strcat(ret->recp_internet, this_recp); @@ -3189,7 +3394,7 @@ struct recptypes *validate_recipients(char *supplied_recipients) { break; case MES_IGNET: ++ret->num_ignet; - if (strlen(ret->recp_ignet) > 0) { + if (!IsEmptyStr(ret->recp_ignet)) { strcat(ret->recp_ignet, "|"); } strcat(ret->recp_ignet, this_recp); @@ -3200,26 +3405,25 @@ struct recptypes *validate_recipients(char *supplied_recipients) { break; } if (invalid) { - if (strlen(ret->errormsg) == 0) { - snprintf(append, sizeof append, - "Invalid recipient: %s", - this_recp); + if (IsEmptyStr(errmsg)) { + snprintf(append, sizeof append, "Invalid recipient: %s", this_recp); } else { - snprintf(append, sizeof append, - ", %s", this_recp); + snprintf(append, sizeof append, "%s", errmsg); } - if ( (strlen(ret->errormsg) + strlen(append)) < SIZ) { + if ( (strlen(ret->errormsg) + strlen(append) + 3) < SIZ) { + if (!IsEmptyStr(ret->errormsg)) { + strcat(ret->errormsg, "; "); + } strcat(ret->errormsg, append); } } else { - if (strlen(ret->display_recp) == 0) { + if (IsEmptyStr(ret->display_recp)) { strcpy(append, this_recp); } else { - snprintf(append, sizeof append, ", %s", - this_recp); + snprintf(append, sizeof append, ", %s", this_recp); } if ( (strlen(ret->display_recp)+strlen(append)) < SIZ) { strcat(ret->display_recp, append); @@ -3233,17 +3437,42 @@ struct recptypes *validate_recipients(char *supplied_recipients) { strcpy(ret->errormsg, "No recipients specified."); } - lprintf(CTDL_DEBUG, "validate_recipients()\n"); - lprintf(CTDL_DEBUG, " local: %d <%s>\n", ret->num_local, ret->recp_local); - lprintf(CTDL_DEBUG, " room: %d <%s>\n", ret->num_room, ret->recp_room); - lprintf(CTDL_DEBUG, " inet: %d <%s>\n", ret->num_internet, ret->recp_internet); - lprintf(CTDL_DEBUG, " ignet: %d <%s>\n", ret->num_ignet, ret->recp_ignet); - lprintf(CTDL_DEBUG, " error: %d <%s>\n", ret->num_error, ret->errormsg); + CtdlLogPrintf(CTDL_DEBUG, "validate_recipients()\n"); + CtdlLogPrintf(CTDL_DEBUG, " local: %d <%s>\n", ret->num_local, ret->recp_local); + CtdlLogPrintf(CTDL_DEBUG, " room: %d <%s>\n", ret->num_room, ret->recp_room); + CtdlLogPrintf(CTDL_DEBUG, " inet: %d <%s>\n", ret->num_internet, ret->recp_internet); + CtdlLogPrintf(CTDL_DEBUG, " ignet: %d <%s>\n", ret->num_ignet, ret->recp_ignet); + CtdlLogPrintf(CTDL_DEBUG, " error: %d <%s>\n", ret->num_error, ret->errormsg); + free(recipients); return(ret); } +/* + * Destructor for struct recptypes + */ +void free_recipients(struct recptypes *valid) { + + if (valid == NULL) { + return; + } + + if (valid->recptypes_magic != RECPTYPES_MAGIC) { + CtdlLogPrintf(CTDL_EMERG, "Attempt to call free_recipients() on some other data type!\n"); + abort(); + } + + if (valid->errormsg != NULL) free(valid->errormsg); + if (valid->recp_local != NULL) free(valid->recp_local); + 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->display_recp != NULL) free(valid->display_recp); + free(valid); +} + + /* * message entry - mode 0 (normal) @@ -3258,6 +3487,7 @@ void cmd_ent0(char *entargs) int anon_flag = 0; int format_type = 0; char newusername[256]; + char newuseremail[256]; struct CtdlMessage *msg; int anonymous = 0; char errmsg[SIZ]; @@ -3267,8 +3497,12 @@ void cmd_ent0(char *entargs) struct recptypes *valid_cc = NULL; struct recptypes *valid_bcc = NULL; char subject[SIZ]; + int subject_required = 0; int do_confirm = 0; long msgnum; + int i, j; + char buf[256]; + int newuseremail_ok = 0; unbuffer_output(); @@ -3290,10 +3524,11 @@ void cmd_ent0(char *entargs) supplied_euid[0] = 0; break; } + extract_token(newuseremail, entargs, 10, '|', sizeof newuseremail); /* first check to make sure the request is valid. */ - err = CtdlDoIHavePermissionToPostInThisRoom(errmsg, sizeof errmsg); + err = CtdlDoIHavePermissionToPostInThisRoom(errmsg, sizeof errmsg, NULL, POST_LOGGED_IN); if (err) { cprintf("%d %s\n", err, errmsg); @@ -3302,8 +3537,7 @@ void cmd_ent0(char *entargs) /* Check some other permission type things. */ - if (strlen(newusername) == 0) - { + if (IsEmptyStr(newusername)) { strcpy(newusername, CC->user.fullname); } if ( (CC->user.axlevel < 6) @@ -3317,50 +3551,80 @@ void cmd_ent0(char *entargs) return; } + + if (IsEmptyStr(newuseremail)) { + newuseremail_ok = 1; + } + + if (!IsEmptyStr(newuseremail)) { + if (!strcasecmp(newuseremail, CC->cs_inet_email)) { + newuseremail_ok = 1; + } + else if (!IsEmptyStr(CC->cs_inet_other_emails)) { + j = num_tokens(CC->cs_inet_other_emails, '|'); + for (i=0; ics_inet_other_emails, i, '|', sizeof buf); + if (!strcasecmp(newuseremail, buf)) { + newuseremail_ok = 1; + } + } + } + } + + if (!newuseremail_ok) { + cprintf("%d You don't have permission to author messages as '%s'.\n", + ERROR + HIGHER_ACCESS_REQUIRED, + newuseremail + ); + return; + } + CC->cs_flags |= CS_POSTING; - /* In the Mail> room we have to behave a little differently -- + /* In mailbox rooms we have to behave a little differently -- * make sure the user has specified at least one recipient. Then - * validate the recipient(s). + * validate the recipient(s). We do this for the Mail> room, as + * well as any room which has the "Mailbox" view set. */ - if ( (CC->room.QRflags & QR_MAILBOX) - && (!strcasecmp(&CC->room.QRname[11], MAILROOM)) ) { + if ( ( (CC->room.QRflags & QR_MAILBOX) && (!strcasecmp(&CC->room.QRname[11], MAILROOM)) ) + || ( (CC->room.QRflags & QR_MAILBOX) && (CC->curr_view == VIEW_MAILBOX) ) + ) { if (CC->user.axlevel < 2) { strcpy(recp, "sysop"); strcpy(cc, ""); strcpy(bcc, ""); } - valid_to = validate_recipients(recp); + valid_to = validate_recipients(recp, NULL, 0); if (valid_to->num_error > 0) { - cprintf("%d Invalid recipient (To)\n", ERROR + NO_SUCH_USER); - free(valid_to); + cprintf("%d %s\n", ERROR + NO_SUCH_USER, valid_to->errormsg); + free_recipients(valid_to); return; } - valid_cc = validate_recipients(cc); + valid_cc = validate_recipients(cc, NULL, 0); if (valid_cc->num_error > 0) { - cprintf("%d Invalid recipient (CC)\n", ERROR + NO_SUCH_USER); - free(valid_to); - free(valid_cc); + cprintf("%d %s\n", ERROR + NO_SUCH_USER, valid_cc->errormsg); + free_recipients(valid_to); + free_recipients(valid_cc); return; } - valid_bcc = validate_recipients(bcc); + valid_bcc = validate_recipients(bcc, NULL, 0); if (valid_bcc->num_error > 0) { - cprintf("%d Invalid recipient (BCC)\n", ERROR + NO_SUCH_USER); - free(valid_to); - free(valid_cc); - free(valid_bcc); + cprintf("%d %s\n", ERROR + NO_SUCH_USER, valid_bcc->errormsg); + free_recipients(valid_to); + free_recipients(valid_cc); + free_recipients(valid_bcc); return; } /* Recipient required, but none were specified */ if ( (valid_to->num_error < 0) && (valid_cc->num_error < 0) && (valid_bcc->num_error < 0) ) { - free(valid_to); - free(valid_cc); - free(valid_bcc); + free_recipients(valid_to); + free_recipients(valid_cc); + free_recipients(valid_bcc); cprintf("%d At least one recipient is required.\n", ERROR + NO_SUCH_USER); return; } @@ -3370,9 +3634,9 @@ void cmd_ent0(char *entargs) cprintf("%d You do not have permission " "to send Internet mail.\n", ERROR + HIGHER_ACCESS_REQUIRED); - free(valid_to); - free(valid_cc); - free(valid_bcc); + free_recipients(valid_to); + free_recipients(valid_cc); + free_recipients(valid_bcc); return; } } @@ -3381,9 +3645,9 @@ void cmd_ent0(char *entargs) && (CC->user.axlevel < 4) ) { cprintf("%d Higher access required for network mail.\n", ERROR + HIGHER_ACCESS_REQUIRED); - free(valid_to); - free(valid_cc); - free(valid_bcc); + free_recipients(valid_to); + free_recipients(valid_cc); + free_recipients(valid_bcc); return; } @@ -3393,9 +3657,9 @@ void cmd_ent0(char *entargs) && (!CC->internal_pgm)) { cprintf("%d You don't have access to Internet mail.\n", ERROR + HIGHER_ACCESS_REQUIRED); - free(valid_to); - free(valid_cc); - free(valid_bcc); + free_recipients(valid_to); + free_recipients(valid_cc); + free_recipients(valid_bcc); return; } @@ -3416,22 +3680,32 @@ void cmd_ent0(char *entargs) recp[0] = 0; } + /* Recommend to the client that the use of a message subject is + * 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 (valid_to) if (valid_to->num_internet > 0) subject_required = 1; + if (valid_cc) if (valid_cc->num_internet > 0) subject_required = 1; + if (valid_bcc) if (valid_bcc->num_internet > 0) subject_required = 1; + /* If we're only checking the validity of the request, return * success without creating the message. */ if (post == 0) { - cprintf("%d %s\n", CIT_OK, - ((valid_to != NULL) ? valid_to->display_recp : "") ); - free(valid_to); - free(valid_cc); - free(valid_bcc); + cprintf("%d %s|%d\n", CIT_OK, + ((valid_to != NULL) ? valid_to->display_recp : ""), + subject_required); + free_recipients(valid_to); + free_recipients(valid_cc); + free_recipients(valid_bcc); return; } /* We don't need these anymore because we'll do it differently below */ - free(valid_to); - free(valid_cc); - free(valid_bcc); + free_recipients(valid_to); + free_recipients(valid_cc); + free_recipients(valid_bcc); /* Read in the message from the client. */ if (do_confirm) { @@ -3442,8 +3716,8 @@ void cmd_ent0(char *entargs) msg = CtdlMakeMessage(&CC->user, recp, cc, CC->room.QRname, anonymous, format_type, - newusername, subject, - ((strlen(supplied_euid) > 0) ? supplied_euid : NULL), + newusername, newuseremail, subject, + ((!IsEmptyStr(supplied_euid)) ? supplied_euid : NULL), NULL); /* Put together one big recipients struct containing to/cc/bcc all in @@ -3451,20 +3725,20 @@ void cmd_ent0(char *entargs) */ char *all_recps = malloc(SIZ * 3); strcpy(all_recps, recp); - if (strlen(cc) > 0) { - if (strlen(all_recps) > 0) { + if (!IsEmptyStr(cc)) { + if (!IsEmptyStr(all_recps)) { strcat(all_recps, ","); } strcat(all_recps, cc); } - if (strlen(bcc) > 0) { - if (strlen(all_recps) > 0) { + if (!IsEmptyStr(bcc)) { + if (!IsEmptyStr(all_recps)) { strcat(all_recps, ","); } strcat(all_recps, bcc); } - if (strlen(all_recps) > 0) { - valid = validate_recipients(all_recps); + if (!IsEmptyStr(all_recps)) { + valid = validate_recipients(all_recps, NULL, 0); } else { valid = NULL; @@ -3493,7 +3767,7 @@ void cmd_ent0(char *entargs) CtdlFreeMessage(msg); } if (valid != NULL) { - free(valid); + free_recipients(valid); } return; } @@ -3521,17 +3795,20 @@ int CtdlDeleteMessages(char *room_name, /* which room */ struct MetaData smi; regex_t re; regmatch_t pm; + int need_to_free_re = 0; - if (content_type) if (strlen(content_type) > 0) { + if (content_type) if (!IsEmptyStr(content_type)) { regcomp(&re, content_type, 0); + need_to_free_re = 1; } - lprintf(CTDL_DEBUG, "CtdlDeleteMessages(%s, %d msgs, %s)\n", + CtdlLogPrintf(CTDL_DEBUG, "CtdlDeleteMessages(%s, %d msgs, %s)\n", room_name, num_dmsgnums, content_type); /* get room record, obtaining a lock... */ if (lgetroom(&qrbuf, room_name) != 0) { - lprintf(CTDL_ERR, "CtdlDeleteMessages(): Room <%s> not found\n", + CtdlLogPrintf(CTDL_ERR, "CtdlDeleteMessages(): Room <%s> not found\n", room_name); + if (need_to_free_re) regfree(&re); return (0); /* room not found */ } cdbfr = cdb_fetch(CDB_MSGLISTS, &qrbuf.QRnumber, sizeof(long)); @@ -3563,7 +3840,7 @@ int CtdlDeleteMessages(char *room_name, /* which room */ } } - if (strlen(content_type) == 0) { + if (IsEmptyStr(content_type)) { delete_this |= 0x02; } else { GetMetaData(&smi, msglist[i]); @@ -3603,7 +3880,8 @@ int CtdlDeleteMessages(char *room_name, /* which room */ /* Now free the memory we used, and go away. */ if (msglist != NULL) free(msglist); if (dellist != NULL) free(dellist); - lprintf(CTDL_DEBUG, "%d message(s) deleted.\n", num_deleted); + CtdlLogPrintf(CTDL_DEBUG, "%d message(s) deleted.\n", num_deleted); + if (need_to_free_re) regfree(&re); return (num_deleted); } @@ -3743,6 +4021,13 @@ void cmd_move(char *args) && (!(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; + + /* Users allowed to post into the target room may move into it too. */ + if ((CC->room.QRflags & QR_MAILBOX) && + (qtemp.QRflags & UA_POSTALLOWED)) permit = 1; + /* User must have access to target room */ if (!(ra & UA_KNOWN)) permit = 0; @@ -3845,7 +4130,7 @@ void AdjRefCount(long msgnum, int incr) /* msgnum < 0 means that we're trying to close the file */ if (msgnum < 0) { - lprintf(CTDL_DEBUG, "Closing the AdjRefCount queue file\n"); + CtdlLogPrintf(CTDL_DEBUG, "Closing the AdjRefCount queue file\n"); begin_critical_section(S_SUPPMSGMAIN); if (arcfp != NULL) { fclose(arcfp); @@ -3897,7 +4182,7 @@ int TDAP_ProcessAdjRefCountQueue(void) r = link(file_arcq, file_arcq_temp); if (r != 0) { - lprintf(CTDL_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno)); + CtdlLogPrintf(CTDL_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno)); end_critical_section(S_SUPPMSGMAIN); return(num_records_processed); } @@ -3907,7 +4192,7 @@ int TDAP_ProcessAdjRefCountQueue(void) fp = fopen(file_arcq_temp, "rb"); if (fp == NULL) { - lprintf(CTDL_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno)); + CtdlLogPrintf(CTDL_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno)); return(num_records_processed); } @@ -3919,7 +4204,7 @@ int TDAP_ProcessAdjRefCountQueue(void) fclose(fp); r = unlink(file_arcq_temp); if (r != 0) { - lprintf(CTDL_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno)); + CtdlLogPrintf(CTDL_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno)); } return(num_records_processed); @@ -3950,19 +4235,17 @@ void TDAP_AdjRefCount(long msgnum, int incr) smi.meta_refcount += incr; PutMetaData(&smi); end_critical_section(S_SUPPMSGMAIN); - lprintf(CTDL_DEBUG, "msg %ld ref count delta %d, is now %d\n", + CtdlLogPrintf(CTDL_DEBUG, "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) { - lprintf(CTDL_DEBUG, "Deleting message <%ld>\n", msgnum); - - /* Remove from fulltext index */ - if (config.c_enable_fulltext) { - ft_index_message(msgnum, 0); - } + CtdlLogPrintf(CTDL_DEBUG, "Deleting message <%ld>\n", msgnum); + + /* Call delete hooks with NULL room to show it has gone altogether */ + PerformDeleteHooks(NULL, msgnum); /* Remove from message base */ delnum = msgnum; @@ -4010,14 +4293,14 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ fp = fopen(tempfilename, "rb"); if (fp == NULL) { - lprintf(CTDL_CRIT, "Cannot open %s: %s\n", + CtdlLogPrintf(CTDL_CRIT, "Cannot open %s: %s\n", tempfilename, strerror(errno)); return; } fseek(fp, 0L, SEEK_END); raw_length = ftell(fp); rewind(fp); - lprintf(CTDL_DEBUG, "Raw length is %ld\n", (long)raw_length); + CtdlLogPrintf(CTDL_DEBUG, "Raw length is %ld\n", (long)raw_length); raw_message = malloc((size_t)raw_length + 2); fread(raw_message, (size_t)raw_length, 1, fp); @@ -4048,7 +4331,8 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ CtdlEncodeBase64( &encoded_message[strlen(encoded_message)], raw_message, - (int)raw_length + (int)raw_length, + 0 ); } else { @@ -4062,7 +4346,7 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ free(raw_message); - lprintf(CTDL_DEBUG, "Allocating\n"); + CtdlLogPrintf(CTDL_DEBUG, "Allocating\n"); msg = malloc(sizeof(struct CtdlMessage)); memset(msg, 0, sizeof(struct CtdlMessage)); msg->cm_magic = CTDLMESSAGE_MAGIC; @@ -4086,7 +4370,7 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ * other objects of this type that are currently in the room. */ if (is_unique) { - lprintf(CTDL_DEBUG, "Deleted %d other msgs of this type\n", + CtdlLogPrintf(CTDL_DEBUG, "Deleted %d other msgs of this type\n", CtdlDeleteMessages(roomname, NULL, 0, content_type) ); } @@ -4146,7 +4430,7 @@ char *CtdlGetSysConfig(char *sysconfname) { if (conf != NULL) do { extract_token(buf, conf, 0, '\n', sizeof buf); strcpy(conf, &conf[strlen(buf)+1]); - } while ( (strlen(conf)>0) && (strlen(buf)>0) ); + } while ( (!IsEmptyStr(conf)) && (!IsEmptyStr(buf)) ); return(conf); } @@ -4176,23 +4460,23 @@ int CtdlIsMe(char *addr, int addr_buf_len) struct recptypes *recp; int i; - recp = validate_recipients(addr); + recp = validate_recipients(addr, NULL, 0); if (recp == NULL) return(0); if (recp->num_local == 0) { - free(recp); + free_recipients(recp); return(0); } for (i=0; inum_local; ++i) { extract_token(addr, recp->recp_local, i, '|', addr_buf_len); if (!strcasecmp(addr, CC->user.fullname)) { - free(recp); + free_recipients(recp); return(1); } } - free(recp); + free_recipients(recp); return(0); }