X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmsgbase.c;h=1d691ebb8f4c950797914158f5390583ad429676;hb=32412be33898d9bf9416c4b675d424397638ef39;hp=a76a242741dbc23478da1d90fa6a1e2e7ff9c165;hpb=994fc649cb2d79f2a5872b4700d6ec48131d4e67;p=citadel.git diff --git a/citadel/msgbase.c b/citadel/msgbase.c index a76a24274..1d691ebb8 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -45,7 +45,6 @@ #include "file_ops.h" #include "config.h" #include "control.h" -#include "html.h" #include "genstamp.h" #include "internet_addressing.h" #include "euidindex.h" @@ -90,7 +89,8 @@ char *msgkeys[] = { "hnod", "msgn", "jrnl", - NULL, NULL, + NULL, + "list", "text", "node", "room", @@ -101,7 +101,7 @@ char *msgkeys[] = { "time", "subj", NULL, - NULL, + "wefw", NULL, "cccc", NULL @@ -183,7 +183,7 @@ int alias(char *name) } if (strcasecmp(original_name, name)) { - lprintf(CTDL_INFO, "%s is being forwarded to %s\n", 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 */ @@ -191,7 +191,7 @@ int alias(char *name) if (name[a] == '@') { if (CtdlHostAlias(&name[a+1]) == hostalias_localhost) { name[a] = 0; - lprintf(CTDL_INFO, "Changed to <%s>\n", name); + CtdlLogPrintf(CTDL_INFO, "Changed to <%s>\n", name); } } } @@ -340,8 +340,6 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, int was_seen = 0; long lo = (-1L); long hi = (-1L); - long t = (-1L); - int trimming = 0; struct visit vbuf; long *msglist; int num_msgs = 0; @@ -349,26 +347,35 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, char *is_set; /* actually an array of booleans */ int num_sets; int s; + int w = 0; char setstr[SIZ], lostr[SIZ], histr[SIZ]; - size_t tmp; /* Don't bother doing *anything* if we were passed a list of zero messages */ if (num_target_msgnums < 1) { return; } - lprintf(CTDL_DEBUG, "CtdlSetSeen(%d msgs starting with %ld, %d, %d)\n", + /* If no room was specified, we go with the current room. */ + if (!which_room) { + which_room = &CC->room; + } + + /* If no user was specified, we go with the current user. */ + if (!which_user) { + which_user = &CC->user; + } + + CtdlLogPrintf(CTDL_DEBUG, "CtdlSetSeen(%d msgs starting with %ld, %s, %d) in <%s>\n", num_target_msgnums, target_msgnums[0], - target_setting, which_set); + (target_setting ? "SET" : "CLEAR"), + which_set, + which_room->QRname); /* Learn about the user and room in question */ - CtdlGetRelationship(&vbuf, - ((which_user != NULL) ? which_user : &CC->user), - ((which_room != NULL) ? which_room : &CC->room) - ); + CtdlGetRelationship(&vbuf, which_user, which_room); /* Load the message list */ - cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long)); + cdbfr = cdb_fetch(CDB_MSGLISTS, &which_room->QRnumber, sizeof(long)); if (cdbfr != NULL) { msglist = (long *) cdbfr->ptr; cdbfr->ptr = NULL; /* CtdlSetSeen() now owns this memory */ @@ -391,7 +398,19 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, break; } - /* lprintf(CTDL_DEBUG, "before optimize: %s\n", vset); */ + +#if 0 /* This is a special diagnostic section. Do not allow it to run during normal operation. */ + CtdlLogPrintf(CTDL_DEBUG, "There are %d messages in the room.\n", num_msgs); + for (i=0; i 0) && (msglist[i] <= msglist[i-1])) abort(); + } + CtdlLogPrintf(CTDL_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 + + CtdlLogPrintf(CTDL_DEBUG, "before update: %s\n", vset); /* Translate the existing sequence set into an array of booleans */ num_sets = num_tokens(vset, ','); @@ -401,15 +420,17 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, extract_token(lostr, setstr, 0, ':', sizeof lostr); if (num_tokens(setstr, ':') >= 2) { extract_token(histr, setstr, 1, ':', sizeof histr); - if (!strcmp(histr, "*")) { - snprintf(histr, sizeof histr, "%ld", LONG_MAX); - } } else { strcpy(histr, lostr); } lo = atol(lostr); - hi = atol(histr); + if (!strcmp(histr, "*")) { + hi = LONG_MAX; + } + else { + hi = atol(histr); + } for (i = 0; i < num_msgs; ++i) { if ((msglist[i] >= lo) && (msglist[i] <= hi)) { @@ -418,84 +439,86 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, } } + /* Now translate the array of booleans back into a sequence set */ strcpy(vset, ""); - lo = (-1L); - hi = (-1L); + was_seen = 0; + lo = (-1); + hi = (-1); for (i=0; i sizeof vset) { - remove_token(vset, 0, ','); - trimming = 1; - if (j--) break; /* loop no more than 9 times */ + if (!IsEmptyStr(vset)) { + strcat(vset, ","); + } + if (lo == hi) { + sprintf(&vset[strlen(vset)], "%ld", hi); } - if ( (trimming) && (which_set == ctdlsetseen_seen) ) { - t = atol(vset); - if (t<2) t=2; - --t; - snprintf(lostr, sizeof lostr, - "1:%ld,%s", t, vset); - safestrncpy(vset, lostr, sizeof vset); + else { + sprintf(&vset[strlen(vset)], "%ld:%ld", lo, hi); } - /* end trim-o-matic code */ - - tmp = strlen(vset); - if (tmp > 0) { + } + else if ((is_seen) && (i == num_msgs - 1)) { + w = 1; + if (!IsEmptyStr(vset)) { strcat(vset, ","); - ++tmp; } - if (lo == hi) { - snprintf(&vset[tmp], (sizeof vset) - tmp, - "%ld", lo); + if ((i==0) || (was_seen == 0)) { + sprintf(&vset[strlen(vset)], "%ld", msglist[i]); } else { - snprintf(&vset[tmp], (sizeof vset) - tmp, - "%ld:%ld", lo, hi); + sprintf(&vset[strlen(vset)], "%ld:%ld", lo, msglist[i]); } - lo = (-1L); - hi = (-1L); } + + /* If the string is getting too long, truncate it at the beginning; repeat up to 9 times */ + if (w) for (j=0; j<9; ++j) { + if ((strlen(vset) + 20) > sizeof vset) { + remove_token(vset, 0, ','); + if (which_set == ctdlsetseen_seen) { + char temp[SIZ]; + sprintf(temp, "1:%ld,", atol(vset)-1L); + strcat(temp, vset); + strcpy(vset, temp); + } + } + } + was_seen = is_seen; } + CtdlLogPrintf(CTDL_DEBUG, " after update: %s\n", vset); + /* Decide which message set we're manipulating */ switch (which_set) { case ctdlsetseen_seen: safestrncpy(vbuf.v_seen, vset, sizeof vbuf.v_seen); break; case ctdlsetseen_answered: - safestrncpy(vbuf.v_answered, vset, - sizeof vbuf.v_answered); + safestrncpy(vbuf.v_answered, vset, sizeof vbuf.v_answered); break; } - free(is_set); - /* lprintf(CTDL_DEBUG, " after optimize: %s\n", vset); */ + free(is_set); free(msglist); - CtdlSetRelationship(&vbuf, - ((which_user != NULL) ? which_user : &CC->user), - ((which_room != NULL) ? which_room : &CC->room) - ); + CtdlSetRelationship(&vbuf, which_user, which_room); } @@ -528,7 +551,7 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, int need_to_free_re = 0; regmatch_t pm; - if (content_type) if (!IsEmptyStr(content_type)) { + if ((content_type) && (!IsEmptyStr(content_type))) { regcomp(&re, content_type, 0); need_to_free_re = 1; } @@ -556,7 +579,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 (!IsEmptyStr(content_type)) { + if ((content_type != NULL) && (!IsEmptyStr(content_type))) { /* This call to GetMetaData() sits inside this loop * so that we only do the extra database read per msg @@ -745,7 +768,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) { @@ -902,14 +925,14 @@ void memfmout( */ void list_this_part(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, - void *cbuserdata) + char *cbid, void *cbuserdata) { struct ma_info *ma; ma = (struct ma_info *)cbuserdata; if (ma->is_ma == 0) { - cprintf("part=%s|%s|%s|%s|%s|%ld\n", - name, filename, partnum, disp, cbtype, (long)length); + cprintf("part=%s|%s|%s|%s|%s|%ld|%s\n", + name, filename, partnum, disp, cbtype, (long)length, cbid); } } @@ -918,7 +941,7 @@ void list_this_part(char *name, char *filename, char *partnum, char *disp, */ void list_this_pref(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, - void *cbuserdata) + char *cbid, void *cbuserdata) { struct ma_info *ma; @@ -937,7 +960,7 @@ void list_this_pref(char *name, char *filename, char *partnum, char *disp, */ void list_this_suff(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, - void *cbuserdata) + char *cbid, void *cbuserdata) { struct ma_info *ma; @@ -956,47 +979,49 @@ void list_this_suff(char *name, char *filename, char *partnum, char *disp, */ void mime_download(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, - char *encoding, void *cbuserdata) + char *encoding, char *cbid, void *cbuserdata) { - /* Silently go away if there's already a download open... */ + /* Silently go away if there's already a download open. */ if (CC->download_fp != NULL) return; - /* ...or if this is not the desired section */ - if (strcasecmp(CC->download_desired_section, partnum)) - return; - - CC->download_fp = tmpfile(); - if (CC->download_fp == NULL) - return; - - fwrite(content, length, 1, CC->download_fp); - fflush(CC->download_fp); - rewind(CC->download_fp); - - OpenCmdResult(filename, cbtype); + if ( + (!IsEmptyStr(partnum) && (!strcasecmp(CC->download_desired_section, partnum))) + || (!IsEmptyStr(cbid) && (!strcasecmp(CC->download_desired_section, cbid))) + ) { + CC->download_fp = tmpfile(); + if (CC->download_fp == NULL) + return; + + fwrite(content, length, 1, CC->download_fp); + fflush(CC->download_fp); + rewind(CC->download_fp); + + OpenCmdResult(filename, cbtype); + } } /* - * Callback function for mime parser that outputs a section all at once + * Callback function for mime parser that outputs a section all at once. + * We can specify the desired section by part number *or* content-id. */ void mime_spew_section(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, - char *encoding, void *cbuserdata) + char *encoding, char *cbid, void *cbuserdata) { int *found_it = (int *)cbuserdata; - /* ...or if this is not the desired section */ - if (strcasecmp(CC->download_desired_section, partnum)) - return; - - *found_it = 1; - - cprintf("%d %d\n", BINARY_FOLLOWS, (int)length); - client_write(content, length); + if ( + (!IsEmptyStr(partnum) && (!strcasecmp(CC->download_desired_section, partnum))) + || (!IsEmptyStr(cbid) && (!strcasecmp(CC->download_desired_section, cbid))) + ) { + *found_it = 1; + cprintf("%d %d\n", BINARY_FOLLOWS, (int)length); + client_write(content, length); + } } @@ -1017,7 +1042,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) { @@ -1033,7 +1058,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; } @@ -1096,7 +1121,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; @@ -1138,12 +1163,12 @@ void CtdlFreeMessage(struct CtdlMessage *msg) */ void fixed_output_pre(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, - void *cbuserdata) + char *cbid, void *cbuserdata) { 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; @@ -1158,12 +1183,12 @@ void fixed_output_pre(char *name, char *filename, char *partnum, char *disp, */ void fixed_output_post(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, - char *encoding, void *cbuserdata) + char *encoding, char *cbid, void *cbuserdata) { 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; @@ -1178,7 +1203,7 @@ void fixed_output_post(char *name, char *filename, char *partnum, char *disp, */ void fixed_output(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, - char *encoding, void *cbuserdata) + char *encoding, char *cbid, void *cbuserdata) { char *ptr; char *wptr; @@ -1187,7 +1212,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); @@ -1196,7 +1221,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) ) { - 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; @@ -1251,7 +1276,7 @@ void fixed_output(char *name, char *filename, char *partnum, char *disp, */ void choose_preferred(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, - char *encoding, void *cbuserdata) + char *encoding, char *cbid, void *cbuserdata) { char buf[1024]; int i; @@ -1268,7 +1293,7 @@ void choose_preferred(char *name, char *filename, char *partnum, char *disp, extract_token(buf, CC->preferred_formats, i, '|', sizeof buf); if ( (!strcasecmp(buf, cbtype)) && (!ma->freeze) ) { if (i < ma->chosen_pref) { - lprintf(CTDL_DEBUG, "Setting chosen part: <%s>\n", partnum); + CtdlLogPrintf(CTDL_DEBUG, "Setting chosen part: <%s>\n", partnum); safestrncpy(ma->chosen_part, partnum, sizeof ma->chosen_part); ma->chosen_pref = i; } @@ -1281,7 +1306,7 @@ void choose_preferred(char *name, char *filename, char *partnum, char *disp, */ void output_preferred(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, - char *encoding, void *cbuserdata) + char *encoding, char *cbid, void *cbuserdata) { int i; char buf[128]; @@ -1329,7 +1354,7 @@ void output_preferred(char *name, char *filename, char *partnum, char *disp, /* No translations required or possible: output as text/plain */ cprintf("Content-type: text/plain\n\n"); fixed_output(name, filename, partnum, disp, content, cbtype, cbcharset, - length, encoding, cbuserdata); + length, encoding, cbid, cbuserdata); } @@ -1345,7 +1370,7 @@ struct encapmsg { */ void extract_encapsulated_message(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, - char *encoding, void *cbuserdata) + char *encoding, char *cbid, void *cbuserdata) { struct encapmsg *encap; @@ -1369,17 +1394,18 @@ void extract_encapsulated_message(char *name, char *filename, char *partnum, cha * */ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ - int mode, /* how would you like that message? */ - int headers_only, /* eschew the message body? */ - int do_proto, /* do Citadel protocol responses? */ - int crlf, /* Use CRLF newlines instead of LF? */ - char *section /* NULL or a message/rfc822 section */ + int mode, /* how would you like that message? */ + int headers_only, /* eschew the message body? */ + 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 /* should the bessage be exported clean? */ ) { struct CtdlMessage *TheMessage = NULL; 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 : "<>") ); @@ -1393,11 +1419,10 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ /* FIXME: check message id against msglist for this room */ /* - * Fetch the message from disk. If we're in any sort of headers - * only mode, request that we don't even bother loading the body - * into memory. + * Fetch the message from disk. If we're in HEADERS_FAST mode, + * request that we don't even bother loading the body into memory. */ - if ( (headers_only == HEADERS_FAST) || (headers_only == HEADERS_ONLY) ) { + if (headers_only == HEADERS_FAST) { TheMessage = CtdlFetchMessage(msg_num, 0); } else { @@ -1445,13 +1470,129 @@ 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, flags); CtdlFreeMessage(TheMessage); return(retcode); } +char *qp_encode_email_addrs(char *source) +{ + char user[256], node[256], name[256]; + const char headerStr[] = "=?UTF-8?Q?"; + char *Encoded; + char *EncodedName; + char *nPtr; + int need_to_encode = 0; + long SourceLen; + long EncodedMaxLen; + long nColons = 0; + long *AddrPtr; + long *AddrUtf8; + long nAddrPtrMax = 50; + long nmax; + int InQuotes = 0; + int i, n; + + if (source == NULL) return source; + if (IsEmptyStr(source)) return source; + + AddrPtr = malloc (sizeof (long) * nAddrPtrMax); + AddrUtf8 = malloc (sizeof (long) * nAddrPtrMax); + memset(AddrUtf8, 0, sizeof (long) * nAddrPtrMax); + *AddrPtr = 0; + i = 0; + while (!IsEmptyStr (&source[i])) { + if (nColons >= nAddrPtrMax){ + long *ptr; + + ptr = (long *) malloc(sizeof (long) * nAddrPtrMax * 2); + memcpy (ptr, AddrPtr, sizeof (long) * nAddrPtrMax); + free (AddrPtr), AddrPtr = ptr; + + ptr = (long *) malloc(sizeof (long) * nAddrPtrMax * 2); + memset(&ptr[nAddrPtrMax], 0, + sizeof (long) * nAddrPtrMax); + + memcpy (ptr, AddrUtf8, sizeof (long) * nAddrPtrMax); + free (AddrUtf8), AddrUtf8 = ptr; + nAddrPtrMax *= 2; + } + if (((unsigned char) source[i] < 32) || + ((unsigned char) source[i] > 126)) { + need_to_encode = 1; + AddrUtf8[nColons] = 1; + } + if (source[i] == '"') + InQuotes = !InQuotes; + if (!InQuotes && source[i] == ',') { + AddrPtr[nColons] = i; + nColons++; + } + i++; + } + if (need_to_encode == 0) { + free(AddrPtr); + free(AddrUtf8); + return source; + } + + SourceLen = i; + EncodedMaxLen = nColons * (sizeof(headerStr) + 3) + SourceLen * 3; + Encoded = (char*) malloc (EncodedMaxLen); + + for (i = 0; i < nColons; i++) + source[AddrPtr[i]++] = '\0'; + + nPtr = Encoded; + *nPtr = '\0'; + for (i = 0; i < nColons && nPtr != NULL; i++) { + nmax = EncodedMaxLen - (nPtr - Encoded); + if (AddrUtf8[i]) { + process_rfc822_addr(&source[AddrPtr[i]], + user, + node, + name); + /* TODO: libIDN here ! */ + if (IsEmptyStr(name)) { + n = snprintf(nPtr, nmax, + (i==0)?"%s@%s" : ",%s@%s", + user, node); + } + else { + EncodedName = rfc2047encode(name, strlen(name)); + n = snprintf(nPtr, nmax, + (i==0)?"%s <%s@%s>" : ",%s <%s@%s>", + EncodedName, user, node); + free(EncodedName); + } + } + else { + n = snprintf(nPtr, nmax, + (i==0)?"%s" : ",%s", + &source[AddrPtr[i]]); + } + if (n > 0 ) + nPtr += n; + else { + char *ptr, *nnPtr; + ptr = (char*) malloc(EncodedMaxLen * 2); + memcpy(ptr, Encoded, EncodedMaxLen); + nnPtr = ptr + (nPtr - Encoded), nPtr = nnPtr; + free(Encoded), Encoded = ptr; + EncodedMaxLen *= 2; + i--; /* do it once more with properly lengthened buffer */ + } + } + for (i = 0; i < nColons; i++) + source[--AddrPtr[i]] = ','; + free(AddrUtf8); + free(AddrPtr); + return Encoded; +} + + /* * Get a message off disk. (returns om_* values found in msgbase.h) */ @@ -1460,14 +1601,15 @@ int CtdlOutputPreLoadedMsg( int mode, /* how would you like that message? */ int headers_only, /* eschew the message body? */ int do_proto, /* do Citadel protocol responses? */ - int crlf /* Use CRLF newlines instead of LF? */ + int crlf, /* Use CRLF newlines instead of LF? */ + int flags /* should the bessage be exported clean? */ ) { - int i, k; + int i, j, k; char buf[SIZ]; - cit_uint8_t ch; + cit_uint8_t ch, prev_ch; char allkeys[30]; char display_name[256]; - char *mptr; + char *mptr, *mpptr; char *nl; /* newline string */ int suppress_f = 0; int subject_found = 0; @@ -1481,11 +1623,10 @@ int CtdlOutputPreLoadedMsg( char luser[100]; char fuser[100]; char snode[100]; - char lnode[100]; 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); @@ -1493,8 +1634,9 @@ 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"); + cit_backtrace (); return(om_no_such_msg); } @@ -1640,23 +1782,29 @@ int CtdlOutputPreLoadedMsg( strcpy(luser, ""); strcpy(fuser, ""); strcpy(snode, NODENAME); - strcpy(lnode, HUMANNODE); if (mode == MT_RFC822) { for (i = 0; i < 256; ++i) { if (TheMessage->cm_fields[i]) { - mptr = TheMessage->cm_fields[i]; - + mptr = mpptr = TheMessage->cm_fields[i]; + if (i == 'A') { safestrncpy(luser, mptr, sizeof luser); safestrncpy(suser, mptr, sizeof suser); } else if (i == 'Y') { + if ((flags & QP_EADDR) != 0) + mptr = qp_encode_email_addrs(mptr); cprintf("CC: %s%s", mptr, nl); } else if (i == 'P') { cprintf("Return-Path: %s%s", mptr, nl); } + else if (i == 'L') { + cprintf("List-ID: %s%s", mptr, nl); + } else if (i == 'V') { + if ((flags & QP_EADDR) != 0) + mptr = qp_encode_email_addrs(mptr); cprintf("Envelope-To: %s%s", mptr, nl); } else if (i == 'U') { @@ -1665,8 +1813,6 @@ int CtdlOutputPreLoadedMsg( } else if (i == 'I') safestrncpy(mid, mptr, sizeof mid); - else if (i == 'H') - safestrncpy(lnode, mptr, sizeof lnode); else if (i == 'F') safestrncpy(fuser, mptr, sizeof fuser); /* else if (i == 'O') @@ -1682,6 +1828,8 @@ int CtdlOutputPreLoadedMsg( } else { + if ((flags & QP_EADDR) != 0) + mptr = qp_encode_email_addrs(mptr); cprintf("To: %s%s", mptr, nl); } } @@ -1690,6 +1838,22 @@ int CtdlOutputPreLoadedMsg( 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 (mptr != mpptr) + free (mptr); } } if (subject_found == 0) { @@ -1727,8 +1891,6 @@ int CtdlOutputPreLoadedMsg( cprintf("From: \"%s\" <%s@%s>%s", luser, suser, snode, nl); } - cprintf("Organization: %s%s", lnode, nl); - /* Blank line signifying RFC822 end-of-headers */ if (TheMessage->cm_format_type != FMT_RFC822) { cprintf("%s", nl); @@ -1762,6 +1924,7 @@ START_TEXT: char outbuf[1024]; int outlen = 0; int nllen = strlen(nl); + prev_ch = 0; while (ch=*mptr, ch!=0) { if (ch==13) { /* do nothing */ @@ -1781,6 +1944,14 @@ START_TEXT: } } } + if (flags & ESC_DOT) + { + if ((prev_ch == 10) && (ch == '.') && ((*(mptr+1) == 13) || (*(mptr+1) == 10))) + { + outbuf[outlen++] = '.'; + } + } + prev_ch = ch; ++mptr; if (outlen > 1000) { client_write(outbuf, outlen); @@ -1893,7 +2064,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); + CtdlOutputMsg(msgid, MT_CITADEL, headers_only, 1, 0, NULL, 0); return; } @@ -1909,7 +2080,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); + CtdlOutputMsg(msgid, MT_RFC822, headers_only, 1, 1, NULL, 0); } @@ -1963,7 +2134,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) ); + CtdlOutputMsg(msgid, MT_MIME, 0, 1, 0, (section[0] ? section : NULL) , 0); } @@ -1996,7 +2167,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); + CtdlOutputMsg(msgid, MT_DOWNLOAD, 0, 1, 1, NULL, 0); } @@ -2012,7 +2183,7 @@ 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); + CtdlOutputMsg(msgid, MT_SPEW_SECTION, 0, 1, 1, NULL, 0); } @@ -2043,7 +2214,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); @@ -2058,7 +2229,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); } @@ -2095,14 +2266,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; @@ -2126,7 +2297,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; ilen = 0; ret->ser = NULL; return; @@ -2299,7 +2470,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; @@ -2317,7 +2488,7 @@ 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; @@ -2343,7 +2514,7 @@ void dump_message(struct CtdlMessage *msg, /* unserialized msg */ * Check for valid message format */ if (is_valid_message(msg) == 0) { - lprintf(CTDL_ERR, "dump_message() aborting due to invalid message\n"); + CtdlLogPrintf(CTDL_ERR, "dump_message() aborting due to invalid message\n"); return; } @@ -2371,19 +2542,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 (IsEmptyStr(msg->cm_fields['E'])) return; - /*lprintf(CTDL_DEBUG, "Exclusive ID: <%s> for room <%s>\n", + /*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, ""); } } @@ -2394,8 +2565,9 @@ void ReplicationChecks(struct CtdlMessage *msg) { * Save a message to disk and submit it into the delivery system. */ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ - struct recptypes *recps, /* recipients (if mail) */ - char *force /* force a particular room? */ + struct recptypes *recps, /* recipients (if mail) */ + char *force, /* force a particular room? */ + int flags /* should the bessage be exported clean? */ ) { char submit_filename[128]; char generated_timestamp[32]; @@ -2421,8 +2593,9 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ char *saved_rfc822_version = NULL; int qualified_for_journaling = 0; struct CitContext *CCC = CC; /* CachedCitContext - performance boost */ + char bounce_to[1024] = ""; - 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 @@ -2458,7 +2631,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); } @@ -2473,21 +2646,24 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ strcpy(content_type, "text/plain"); mptr = bmstrcasestr(msg->cm_fields['M'], "Content-type:"); if (mptr != NULL) { + char *aptr; safestrncpy(content_type, &mptr[13], sizeof content_type); striplt(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; + 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) ? CCC->room.QRname : SENTITEMS); + 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) { @@ -2499,7 +2675,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ 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"); } } @@ -2508,7 +2684,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ strcpy(actual_rm, force_room); } - lprintf(CTDL_DEBUG, "Final selection: %s\n", 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); @@ -2522,7 +2698,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } /* 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); /* @@ -2534,7 +2710,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } /* 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); @@ -2542,7 +2718,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; @@ -2560,13 +2736,13 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * message to attach to the journalized copy. */ if (CCC->redirect_buffer != NULL) { - lprintf(CTDL_ALERT, "CCC->redirect_buffer is not NULL during message submission!\n"); + CtdlLogPrintf(CTDL_ALERT, "CCC->redirect_buffer is not NULL during message submission!\n"); abort(); } CCC->redirect_buffer = malloc(SIZ); CCC->redirect_len = 0; CCC->redirect_alloc = SIZ; - CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1); + CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1, QP_EADDR); smi.meta_rfc822_length = CCC->redirect_len; saved_rfc822_version = CCC->redirect_buffer; CCC->redirect_buffer = NULL; @@ -2576,7 +2752,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ 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 @@ -2584,7 +2760,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ */ 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); } } @@ -2601,16 +2777,24 @@ 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"); + CtdlLogPrintf(CTDL_DEBUG, "Updating user\n"); lgetuser(&CCC->user, CCC->curr_user); CCC->user.posted = CCC->user.posted + 1; lputuser(&CCC->user); + /* Decide where bounces need to be delivered */ + if (CCC->logged_in) { + snprintf(bounce_to, sizeof bounce_to, "%s@%s", CCC->user.fullname, config.c_nodename); + } + else { + snprintf(bounce_to, sizeof bounce_to, "%s@%s", msg->cm_fields['A'], msg->cm_fields['N']); + } + /* If this is private, local mail, make a copy in the * recipient's mailbox and bump the reference count. */ @@ -2619,7 +2803,7 @@ 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 @@ -2635,9 +2819,9 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ instr = malloc(instr_alloc); snprintf(instr, instr_alloc, "Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n" - "bounceto|%s@%s\n", + "bounceto|%s\n", SPOOLMIME, newmsgid, (long)time(NULL), - msg->cm_fields['A'], msg->cm_fields['N'] + bounce_to ); imsg = malloc(sizeof(struct CtdlMessage)); @@ -2649,19 +2833,19 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ 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); + CtdlSubmitMsg(imsg, NULL, FNBL_QUEUE_ROOM, 0); 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 @@ -2706,7 +2890,7 @@ 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); + 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); @@ -2717,14 +2901,14 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ */ if (recps != NULL) if (recps->num_internet > 0) { - lprintf(CTDL_DEBUG, "Generating delivery instructions\n"); + 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", + "bounceto|%s\n", SPOOLMIME, newmsgid, (long)time(NULL), - msg->cm_fields['A'], msg->cm_fields['N'] + bounce_to ); for (i=0; irecp_internet, '|'); ++i) { @@ -2745,7 +2929,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ imsg->cm_fields['A'] = strdup("Citadel"); imsg->cm_fields['J'] = strdup("do not journal"); imsg->cm_fields['M'] = instr; /* imsg owns this memory now */ - CtdlSubmitMsg(imsg, NULL, SMTP_SPOOLOUT_ROOM); + CtdlSubmitMsg(imsg, NULL, SMTP_SPOOLOUT_ROOM, QP_EADDR); CtdlFreeMessage(imsg); } @@ -2757,14 +2941,14 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } if (collected_addresses != NULL) { - begin_critical_section(S_ATBF); aptr = (struct addresses_to_be_filed *) malloc(sizeof(struct addresses_to_be_filed)); - aptr->next = atbf; MailboxName(actual_rm, sizeof actual_rm, &CCC->user, USERCONTACTSROOM); aptr->roomname = strdup(actual_rm); aptr->collected_addresses = collected_addresses; + begin_critical_section(S_ATBF); + aptr->next = atbf; atbf = aptr; end_critical_section(S_ATBF); } @@ -2849,7 +3033,7 @@ void quickie_message(char *from, char *fromaddr, char *to, char *room, char *tex } msg->cm_fields['M'] = strdup(text); - CtdlSubmitMsg(msg, recp, room); + CtdlSubmitMsg(msg, recp, room, 0); CtdlFreeMessage(msg); if (recp != NULL) free_recipients(recp); } @@ -2937,7 +3121,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); } } @@ -2979,12 +3163,12 @@ struct CtdlMessage *CtdlMakeMessage( 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 */ + char *preformatted_text, /* ...or NULL to read text from client */ + char *references /* Thread references */ ) { char dest_node[256]; char buf[1024]; struct CtdlMessage *msg; - int i; msg = malloc(sizeof(struct CtdlMessage)); memset(msg, 0, sizeof(struct CtdlMessage)); @@ -3008,11 +3192,7 @@ struct CtdlMessage *CtdlMakeMessage( snprintf(buf, sizeof buf, "%s", author->fullname); msg->cm_fields['P'] = strdup(buf); } - for (i=0; (msg->cm_fields['P'][i]!=0); ++i) { - if (isspace(msg->cm_fields['P'][i])) { - msg->cm_fields['P'][i] = '_'; - } - } + convert_spaces_to_underscores(msg->cm_fields['P']); snprintf(buf, sizeof buf, "%ld", (long)time(NULL)); /* timestamp */ msg->cm_fields['T'] = strdup(buf); @@ -3075,6 +3255,12 @@ struct CtdlMessage *CtdlMakeMessage( msg->cm_fields['E'] = strdup(supplied_euid); } + if (references != NULL) { + if (!IsEmptyStr(references)) { + msg->cm_fields['W'] = strdup(references); + } + } + if (preformatted_text != NULL) { msg->cm_fields['M'] = preformatted_text; } @@ -3106,6 +3292,7 @@ int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, 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); @@ -3114,7 +3301,7 @@ int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, snprintf(errmsgbuf, n, "Not logged in Moderation feature not yet implemented!"); return (ERROR + NOT_LOGGED_IN); } - if ((CC->room.QRflags2 & QR2_SMTP_PUBLIC) == 0) { + if ((PostPublic!=POST_LMTP) &&(CC->room.QRflags2 & QR2_SMTP_PUBLIC) == 0) { SpoolControl *sc; char filename[SIZ]; int found; @@ -3281,7 +3468,9 @@ 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); @@ -3308,22 +3497,6 @@ struct recptypes *validate_recipients(char *supplied_recipients, } strcat(ret->recp_room, this_recp); } - else if (getuser(&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 (getuser(&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 if ( (!strncasecmp(this_recp, "room_", 5)) && (!getroom(&tempQR, &this_recp_cooked[5])) ) { @@ -3354,6 +3527,22 @@ struct recptypes *validate_recipients(char *supplied_recipients, CC->room = tempQR2; } + else if (getuser(&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 (getuser(&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; @@ -3423,12 +3612,12 @@ 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); @@ -3445,7 +3634,7 @@ void free_recipients(struct recptypes *valid) { } if (valid->recptypes_magic != RECPTYPES_MAGIC) { - lprintf(CTDL_EMERG, "Attempt to call free_recipients() on some other data type!\n"); + CtdlLogPrintf(CTDL_EMERG, "Attempt to call free_recipients() on some other data type!\n"); abort(); } @@ -3489,6 +3678,8 @@ void cmd_ent0(char *entargs) int i, j; char buf[256]; int newuseremail_ok = 0; + char references[SIZ]; + char *ptr; unbuffer_output(); @@ -3511,6 +3702,10 @@ void cmd_ent0(char *entargs) break; } extract_token(newuseremail, entargs, 10, '|', sizeof newuseremail); + extract_token(references, entargs, 11, '|', sizeof references); + for (ptr=references; *ptr != 0; ++ptr) { + if (*ptr == '!') *ptr = '|'; + } /* first check to make sure the request is valid. */ @@ -3671,9 +3866,9 @@ void cmd_ent0(char *entargs) * 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 ((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; /* If we're only checking the validity of the request, return * success without creating the message. @@ -3704,7 +3899,7 @@ void cmd_ent0(char *entargs) CC->room.QRname, anonymous, format_type, newusername, newuseremail, subject, ((!IsEmptyStr(supplied_euid)) ? supplied_euid : NULL), - NULL); + NULL, references); /* Put together one big recipients struct containing to/cc/bcc all in * one. This is for the envelope. @@ -3732,7 +3927,7 @@ void cmd_ent0(char *entargs) free(all_recps); if (msg != NULL) { - msgnum = CtdlSubmitMsg(msg, valid, ""); + msgnum = CtdlSubmitMsg(msg, valid, "", QP_EADDR); if (do_confirm) { cprintf("%ld\n", msgnum); @@ -3787,12 +3982,12 @@ int CtdlDeleteMessages(char *room_name, /* which room */ 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 */ @@ -3866,7 +4061,7 @@ 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); } @@ -4010,6 +4205,10 @@ void cmd_move(char *args) /* 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; @@ -4112,7 +4311,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); @@ -4154,7 +4353,7 @@ int TDAP_ProcessAdjRefCountQueue(void) struct arcq arcq_rec; int num_records_processed = 0; - snprintf(file_arcq_temp, sizeof file_arcq_temp, "%s2", file_arcq); + snprintf(file_arcq_temp, sizeof file_arcq_temp, "%s.%04x", file_arcq, rand()); begin_critical_section(S_SUPPMSGMAIN); if (arcfp != NULL) { @@ -4164,7 +4363,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); } @@ -4174,7 +4373,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); } @@ -4186,7 +4385,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); @@ -4217,14 +4416,14 @@ 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); + CtdlLogPrintf(CTDL_DEBUG, "Deleting message <%ld>\n", msgnum); /* Call delete hooks with NULL room to show it has gone altogether */ PerformDeleteHooks(NULL, msgnum); @@ -4247,24 +4446,21 @@ void TDAP_AdjRefCount(long msgnum, int incr) * Note: this could be much more efficient. Right now we use two temporary * 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 *tempfilename, /* Where to fetch it from */ +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 */ + int is_binary, /* Is encoding necessary? */ + int is_unique, /* Del others of this type? */ + unsigned int flags /* Internal save flags */ ) { - FILE *fp; struct ctdlroom qrbuf; char roomname[ROOMNAMELEN]; struct CtdlMessage *msg; - - char *raw_message = NULL; char *encoded_message = NULL; - off_t raw_length = 0; if (is_mailbox != NULL) { MailboxName(roomname, sizeof roomname, is_mailbox, req_room); @@ -4273,24 +4469,10 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ safestrncpy(roomname, req_room, sizeof(roomname)); } - fp = fopen(tempfilename, "rb"); - if (fp == NULL) { - lprintf(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); - - raw_message = malloc((size_t)raw_length + 2); - fread(raw_message, (size_t)raw_length, 1, fp); - fclose(fp); + CtdlLogPrintf(CTDL_DEBUG, "Raw length is %ld\n", (long)raw_length); if (is_binary) { - encoded_message = malloc((size_t) - (((raw_length * 134) / 100) + 4096 ) ); + encoded_message = malloc((size_t) (((raw_length * 134) / 100) + 4096 ) ); } else { encoded_message = malloc((size_t)(raw_length + 4096)); @@ -4318,7 +4500,6 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ ); } else { - raw_message[raw_length] = 0; memcpy( &encoded_message[strlen(encoded_message)], raw_message, @@ -4326,9 +4507,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; @@ -4352,12 +4531,12 @@ 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) ); } /* Now write the data */ - CtdlSubmitMsg(msg, NULL, roomname); + CtdlSubmitMsg(msg, NULL, roomname, 0); CtdlFreeMessage(msg); } @@ -4417,20 +4596,9 @@ char *CtdlGetSysConfig(char *sysconfname) { return(conf); } -void CtdlPutSysConfig(char *sysconfname, char *sysconfdata) { - char temp[PATH_MAX]; - FILE *fp; - CtdlMakeTempFileName(temp, sizeof temp); - - fp = fopen(temp, "w"); - if (fp == NULL) return; - fprintf(fp, "%s", sysconfdata); - fclose(fp); - - /* this handy API function does all the work for us */ - CtdlWriteObject(SYSCONFIGROOM, sysconfname, temp, NULL, 0, 1, 0); - unlink(temp); +void CtdlPutSysConfig(char *sysconfname, char *sysconfdata) { + CtdlWriteObject(SYSCONFIGROOM, sysconfname, sysconfdata, (strlen(sysconfdata)+1), NULL, 0, 1, 0); }