X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmsgbase.c;h=9563223d63961eb05d222e557f24192ec96fd6de;hb=91d9721e1459680919a057886cc7ab7792b2bef4;hp=81ee81aa8e8c8e78b94324af31abdf17cb047ea7;hpb=2bfaf9b78162ffd9a7604431ed6f35acb1468104;p=citadel.git diff --git a/citadel/msgbase.c b/citadel/msgbase.c index 81ee81aa8..9563223d6 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -54,6 +54,8 @@ #include "serv_network.h" #include "threads.h" +#include "ctdl_module.h" + long config_msgnum; struct addresses_to_be_filed *atbf = NULL; @@ -89,7 +91,8 @@ char *msgkeys[] = { "hnod", "msgn", "jrnl", - NULL, NULL, + NULL, + "list", "text", "node", "room", @@ -297,6 +300,8 @@ int CtdlMsgCmp(struct CtdlMessage *msg, struct CtdlMessage *template) { for (i='A'; i<='Z'; ++i) { if (template->cm_fields[i] != NULL) { if (msg->cm_fields[i] == NULL) { + /* Considered equal if temmplate is empty string */ + if (IsEmptyStr(template->cm_fields[i])) continue; return 1; } if (strcasecmp(msg->cm_fields[i], @@ -334,40 +339,47 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, int target_setting, int which_set, struct ctdluser *which_user, struct ctdlroom *which_room) { struct cdbdata *cdbfr; - int i, j, k; + int i, k; int is_seen = 0; 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; - char vset[SIZ]; + StrBuf *vset; + StrBuf *setstr; + StrBuf *lostr; + StrBuf *histr; + const char *pvset; char *is_set; /* actually an array of booleans */ - int num_sets; - int s; - 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; } - CtdlLogPrintf(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 */ @@ -382,33 +394,52 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, /* Decide which message set we're manipulating */ switch(which_set) { - case ctdlsetseen_seen: - safestrncpy(vset, vbuf.v_seen, sizeof vset); - break; - case ctdlsetseen_answered: - safestrncpy(vset, vbuf.v_answered, sizeof vset); - break; + case ctdlsetseen_seen: + vset = NewStrBufPlain(vbuf.v_seen, -1); + break; + case ctdlsetseen_answered: + vset = NewStrBufPlain(vbuf.v_answered, -1); + break; + default: + vset = NewStrBuf(); } - /* CtdlLogPrintf(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", ChrPtr(vset)); /* Translate the existing sequence set into an array of booleans */ - num_sets = num_tokens(vset, ','); - for (s=0; s= 2) { - extract_token(histr, setstr, 1, ':', sizeof histr); - if (!strcmp(histr, "*")) { - snprintf(histr, sizeof histr, "%ld", LONG_MAX); - } + setstr = NewStrBuf(); + lostr = NewStrBuf(); + histr = NewStrBuf(); + pvset = NULL; + while (StrBufExtract_NextToken(setstr, vset, &pvset, ',') >= 0) { + + StrBufExtract_token(lostr, setstr, 0, ':'); + if (StrBufNum_tokens(setstr, ':') >= 2) { + StrBufExtract_token(histr, setstr, 1, ':'); + } + else { + FlushStrBuf(histr); + StrBufAppendBuf(histr, lostr, 0); + } + lo = StrTol(lostr); + if (!strcmp(ChrPtr(histr), "*")) { + hi = LONG_MAX; } else { - strcpy(histr, lostr); + hi = StrTol(histr); } - lo = atol(lostr); - hi = atol(histr); for (i = 0; i < num_msgs; ++i) { if ((msglist[i] >= lo) && (msglist[i] <= hi)) { @@ -416,85 +447,114 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, } } } + FreeStrBuf(&setstr); + FreeStrBuf(&lostr); + FreeStrBuf(&histr); + /* Now translate the array of booleans back into a sequence set */ - strcpy(vset, ""); - lo = (-1L); - hi = (-1L); + FlushStrBuf(vset); + 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 (StrLength(vset) > 0) { + StrBufAppendBufPlain(vset, HKEY(","), 0); } - 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); + if (lo == hi) { + StrBufAppendPrintf(vset, "%ld", hi); } - /* end trim-o-matic code */ + else { + StrBufAppendPrintf(vset, "%ld:%ld", lo, hi); + } + } - tmp = strlen(vset); - if (tmp > 0) { - strcat(vset, ","); - ++tmp; + if ((is_seen) && (i == num_msgs - 1)) { + if (StrLength(vset) > 0) { + StrBufAppendBufPlain(vset, HKEY(","), 0); } - if (lo == hi) { - snprintf(&vset[tmp], (sizeof vset) - tmp, - "%ld", lo); + if ((i==0) || (was_seen == 0)) { + StrBufAppendPrintf(vset, "%ld", msglist[i]); } else { - snprintf(&vset[tmp], (sizeof vset) - tmp, - "%ld:%ld", lo, hi); + StrBufAppendPrintf(vset, "%ld:%ld", lo, msglist[i]); } - lo = (-1L); - hi = (-1L); } + was_seen = is_seen; } + /* + * We will have to stuff this string back into a 4096 byte buffer, so if it's + * larger than that now, truncate it by removing tokens from the beginning. + * The limit of 100 iterations is there to prevent an infinite loop in case + * something unexpected happens. + */ + int number_of_truncations = 0; + while ( (StrLength(vset) > SIZ) && (number_of_truncations < 100) ) { + StrBufRemove_token(vset, 0, ','); + ++number_of_truncations; + } + + /* + * If we're truncating the sequence set of messages marked with the 'seen' flag, + * we want the earliest messages (the truncated ones) to be marked, not unmarked. + * Otherwise messages at the beginning will suddenly appear to be 'unseen'. + */ + if ( (which_set == ctdlsetseen_seen) && (number_of_truncations > 0) ) { + StrBuf *first_tok; + first_tok = NewStrBuf(); + StrBufExtract_token(first_tok, vset, 0, ','); + StrBufRemove_token(vset, 0, ','); + + if (StrBufNum_tokens(first_tok, ':') > 1) { + StrBufRemove_token(first_tok, 0, ':'); + } + + StrBuf *new_set; + new_set = NewStrBuf(); + StrBufAppendBufPlain(new_set, HKEY("1:"), 0); + StrBufAppendBuf(new_set, first_tok, 0); + StrBufAppendBufPlain(new_set, HKEY(":"), 0); + StrBufAppendBuf(new_set, vset, 0); + + FreeStrBuf(&vset); + FreeStrBuf(&first_tok); + vset = new_set; + } + + CtdlLogPrintf(CTDL_DEBUG, " after update: %s\n", ChrPtr(vset)); + /* Decide which message set we're manipulating */ switch (which_set) { case ctdlsetseen_seen: - safestrncpy(vbuf.v_seen, vset, sizeof vbuf.v_seen); + safestrncpy(vbuf.v_seen, ChrPtr(vset), sizeof vbuf.v_seen); break; case ctdlsetseen_answered: - safestrncpy(vbuf.v_answered, vset, - sizeof vbuf.v_answered); + safestrncpy(vbuf.v_answered, ChrPtr(vset), sizeof vbuf.v_answered); break; } - free(is_set); - /* CtdlLogPrintf(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); + FreeStrBuf(&vset); } @@ -502,7 +562,9 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, * API function to perform an operation for each qualifying message in the * current room. (Returns the number of messages processed.) */ -int CtdlForEachMessage(int mode, long ref, char *search_string, +int CtdlForEachMessage(int mode, + long ref, + char *search_string, char *content_type, struct CtdlMessage *compare, void (*CallBack) (long, void *), @@ -527,7 +589,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; } @@ -555,7 +617,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 @@ -594,6 +656,30 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, } } + /* If an EUID was specified, throw away all messages except the correct one. */ + if (mode == MSGS_EUID) { + long correct_msgnum; + int found_match = 0; + + if ((num_msgs > 0) && (search_string) ) { + correct_msgnum = locate_message_by_euid(search_string, &CC->room); + if ( (num_msgs > 0) && (correct_msgnum >= 0L) ) { + for (i=0; icm_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) { @@ -762,7 +850,7 @@ void cmd_msgs(char *cmdbuf) CtdlForEachMessage(mode, ( (mode == MSGS_SEARCH) ? 0 : cm_ref ), - ( (mode == MSGS_SEARCH) ? search_string : NULL ), + ( ((mode == MSGS_SEARCH)||(mode == MSGS_EUID)) ? search_string : NULL ), NULL, template, (with_headers ? headers_listing : simple_listing), @@ -901,14 +989,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); } } @@ -917,7 +1005,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; @@ -936,7 +1024,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; @@ -955,47 +1043,55 @@ 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) { + int rv = 0; - /* 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; + + rv = 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|-1|%s|%s\n", + BINARY_FOLLOWS, + (int)length, + filename, + cbtype + ); + client_write(content, length); + } } @@ -1137,7 +1233,7 @@ 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; @@ -1157,7 +1253,7 @@ 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; @@ -1177,7 +1273,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; @@ -1250,7 +1346,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; @@ -1280,7 +1376,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]; @@ -1328,7 +1424,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); } @@ -1344,7 +1440,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; @@ -1368,11 +1464,12 @@ 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; @@ -1392,11 +1489,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 { @@ -1444,13 +1540,154 @@ 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; +} + + +/* If the last item in a list of recipients was truncated to a partial address, + * remove it completely in order to avoid choking libSieve + */ +void sanitize_truncated_recipient(char *str) +{ + if (!str) return; + if (num_tokens(str, ',') < 2) return; + + int len = strlen(str); + if (len < 900) return; + if (len > 998) str[998] = 0; + + char *cptr = strrchr(str, ','); + if (!cptr) return; + + char *lptr = strchr(cptr, '<'); + char *rptr = strchr(cptr, '>'); + + if ( (lptr) && (rptr) && (rptr > lptr) ) return; + + *cptr = 0; +} + + + /* * Get a message off disk. (returns om_* values found in msgbase.h) */ @@ -1459,14 +1696,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; @@ -1480,7 +1718,6 @@ int CtdlOutputPreLoadedMsg( char luser[100]; char fuser[100]; char snode[100]; - char lnode[100]; char mid[100]; char datestamp[100]; @@ -1494,6 +1731,7 @@ int CtdlOutputPreLoadedMsg( if (!is_valid_message(TheMessage)) { CtdlLogPrintf(CTDL_ERR, "ERROR: invalid preloaded message for output\n"); + cit_backtrace (); return(om_no_such_msg); } @@ -1563,7 +1801,7 @@ int CtdlOutputPreLoadedMsg( /* nhdr=yes means that we're only displaying headers, no body */ if ( (TheMessage->cm_anon_type == MES_ANONONLY) - && (mode == MT_CITADEL) + && ((mode == MT_CITADEL) || (mode == MT_MIME)) && (do_proto) ) { cprintf("nhdr=yes\n"); @@ -1612,6 +1850,9 @@ int CtdlOutputPreLoadedMsg( if (k != 'M') { if ( (TheMessage->cm_fields[k] != NULL) && (msgkeys[k] != NULL) ) { + if ((k == 'V') || (k == 'R') || (k == 'Y')) { + sanitize_truncated_recipient(TheMessage->cm_fields[k]); + } if (k == 'A') { if (do_proto) cprintf("%s=%s\n", msgkeys[k], @@ -1639,23 +1880,31 @@ 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); + } + sanitize_truncated_recipient(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') { @@ -1664,8 +1913,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') @@ -1677,11 +1924,18 @@ int CtdlOutputPreLoadedMsg( { if (haschar(mptr, '@') == 0) { - cprintf("To: %s@%s%s", mptr, config.c_fqdn, nl); + sanitize_truncated_recipient(mptr); + cprintf("To: %s@%s", mptr, config.c_fqdn); + cprintf("%s", nl); } else { - cprintf("To: %s%s", mptr, nl); + if ((flags & QP_EADDR) != 0) { + mptr = qp_encode_email_addrs(mptr); + } + sanitize_truncated_recipient(mptr); + cprintf("To: %s", mptr); + cprintf("%s", nl); } } else if (i == 'T') { @@ -1692,10 +1946,10 @@ int CtdlOutputPreLoadedMsg( else if (i == 'W') { cprintf("References: "); k = num_tokens(mptr, '|'); - for (i=0; i", buf); - if (i == (k-1)) { + if (j == (k-1)) { cprintf("%s", nl); } else { @@ -1703,6 +1957,8 @@ int CtdlOutputPreLoadedMsg( } } } + if (mptr != mpptr) + free (mptr); } } if (subject_found == 0) { @@ -1740,8 +1996,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); @@ -1775,6 +2029,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 */ @@ -1794,6 +2049,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); @@ -1906,7 +2169,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; } @@ -1922,7 +2185,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); } @@ -1976,7 +2239,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); } @@ -2009,7 +2272,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); } @@ -2025,7 +2288,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); } @@ -2407,8 +2670,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]; @@ -2434,6 +2698,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] = ""; + size_t tmp = 0; + int rv = 0; CtdlLogPrintf(CTDL_DEBUG, "CtdlSubmitMsg() called\n"); if (is_valid_message(msg) == 0) return(-1); /* self check */ @@ -2582,7 +2849,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ 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; @@ -2606,14 +2873,12 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } /* For internet mail, drop a copy in the outbound queue room */ - if (recps != NULL) - if (recps->num_internet > 0) { + if ((recps != NULL) && (recps->num_internet > 0)) { CtdlSaveMsgPointerInRoom(SMTP_SPOOLOUT_ROOM, newmsgid, 0, msg); } /* If other rooms are specified, drop them there too. */ - if (recps != NULL) - if (recps->num_room > 0) + if ((recps != NULL) && (recps->num_room > 0)) for (i=0; irecp_room, '|'); ++i) { extract_token(recipient, recps->recp_room, i, '|', sizeof recipient); @@ -2627,11 +2892,21 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ CCC->user.posted = CCC->user.posted + 1; lputuser(&CCC->user); + /* Decide where bounces need to be delivered */ + if ((recps != NULL) && (recps->bounce_to != NULL)) { + safestrncpy(bounce_to, recps->bounce_to, sizeof bounce_to); + } + else 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. */ - if (recps != NULL) - if (recps->num_local > 0) + if ((recps != NULL) && (recps->num_local > 0)) for (i=0; irecp_local, '|'); ++i) { extract_token(recipient, recps->recp_local, i, '|', sizeof recipient); @@ -2651,9 +2926,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)); @@ -2665,7 +2940,7 @@ 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); } } @@ -2688,8 +2963,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * node. We'll revisit this again in a year or so when everyone has * a network spool receiver that can handle the new style messages. */ - if (recps != NULL) - if (recps->num_ignet > 0) + if ((recps != NULL) && (recps->num_ignet > 0)) for (i=0; irecp_ignet, '|'); ++i) { extract_token(recipient, recps->recp_ignet, i, '|', sizeof recipient); @@ -2709,7 +2983,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ (long) getpid(), CCC->cs_pid, ++seqnum); network_fp = fopen(submit_filename, "wb+"); if (network_fp != NULL) { - fwrite(smr.ser, smr.len, 1, network_fp); + rv = fwrite(smr.ser, smr.len, 1, network_fp); fclose(network_fp); } free(smr.ser); @@ -2731,20 +3005,24 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * not happen because the delivery instructions message does not * contain a recipient. */ - if (recps != NULL) - if (recps->num_internet > 0) { + if ((recps != NULL) && (recps->num_internet > 0)) { 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 ); + if (recps->envelope_from != NULL) { + tmp = strlen(instr); + snprintf(&instr[tmp], instr_alloc-tmp, "envelope_from|%s\n", recps->envelope_from); + } + for (i=0; irecp_internet, '|'); ++i) { - size_t tmp = strlen(instr); + tmp = strlen(instr); extract_token(recipient, recps->recp_internet, i, '|', sizeof recipient); if ((tmp + strlen(recipient) + 32) > instr_alloc) { instr_alloc = instr_alloc * 2; @@ -2761,7 +3039,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); } @@ -2773,14 +3051,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); } @@ -2828,8 +3106,8 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* * Convenience function for generating small administrative messages. */ -void quickie_message(char *from, char *fromaddr, char *to, char *room, char *text, - int format_type, char *subject) +void quickie_message(const char *from, const char *fromaddr, char *to, char *room, const char *text, + int format_type, const char *subject) { struct CtdlMessage *msg; struct recptypes *recp = NULL; @@ -2865,7 +3143,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); } @@ -2995,7 +3273,8 @@ 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]; @@ -3010,8 +3289,8 @@ struct CtdlMessage *CtdlMakeMessage( /* Don't confuse the poor folks if it's not routed mail. */ strcpy(dest_node, ""); - striplt(recipient); - striplt(recp_cc); + if (recipient != NULL) striplt(recipient); + if (recp_cc != NULL) striplt(recp_cc); /* Path or Return-Path */ if (my_email == NULL) my_email = ""; @@ -3028,10 +3307,12 @@ struct CtdlMessage *CtdlMakeMessage( snprintf(buf, sizeof buf, "%ld", (long)time(NULL)); /* timestamp */ msg->cm_fields['T'] = strdup(buf); - if (fake_name[0]) /* author */ + if ((fake_name != NULL) && (fake_name[0])) { /* author */ msg->cm_fields['A'] = strdup(fake_name); - else + } + else { msg->cm_fields['A'] = strdup(author->fullname); + } if (CC->room.QRflags & QR_MAILBOX) { /* room */ msg->cm_fields['O'] = strdup(&CC->room.QRname[11]); @@ -3043,10 +3324,10 @@ struct CtdlMessage *CtdlMakeMessage( msg->cm_fields['N'] = strdup(NODENAME); /* nodename */ msg->cm_fields['H'] = strdup(HUMANNODE); /* hnodename */ - if (recipient[0] != 0) { + if ((recipient != NULL) && (recipient[0] != 0)) { msg->cm_fields['R'] = strdup(recipient); } - if (recp_cc[0] != 0) { + if ((recp_cc != NULL) && (recp_cc[0] != 0)) { msg->cm_fields['Y'] = strdup(recp_cc); } if (dest_node[0] != 0) { @@ -3086,6 +3367,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; } @@ -3469,6 +3756,8 @@ void free_recipients(struct recptypes *valid) { 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); + if (valid->bounce_to != NULL) free(valid->bounce_to); + if (valid->envelope_from != NULL) free(valid->envelope_from); free(valid); } @@ -3503,6 +3792,8 @@ void cmd_ent0(char *entargs) int i, j; char buf[256]; int newuseremail_ok = 0; + char references[SIZ]; + char *ptr; unbuffer_output(); @@ -3525,6 +3816,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. */ @@ -3685,9 +3980,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. @@ -3718,7 +4013,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. @@ -3746,7 +4041,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); @@ -3947,19 +4242,6 @@ void cmd_dele(char *args) } -/* - * Back end API function for moves and deletes (multiple messages) - */ -int CtdlCopyMsgsToRoom(long *msgnums, int num_msgs, char *dest) { - int err; - - err = CtdlSaveMsgPointersInRoom(dest, msgnums, num_msgs, 1, NULL); - if (err != 0) return(err); - - return(0); -} - - /* @@ -3993,8 +4275,12 @@ void cmd_move(char *args) is_copy = extract_int(args, 2); if (getroom(&qtemp, targ) != 0) { - cprintf("%d '%s' does not exist.\n", - ERROR + ROOM_NOT_FOUND, targ); + cprintf("%d '%s' does not exist.\n", ERROR + ROOM_NOT_FOUND, targ); + return; + } + + if (!strcasecmp(qtemp.QRname, CC->room.QRname)) { + cprintf("%d Source and target rooms are the same.\n", ERROR + ALREADY_EXISTS); return; } @@ -4049,7 +4335,7 @@ void cmd_move(char *args) /* * Do the copy */ - err = CtdlCopyMsgsToRoom(msgs, num_msgs, targ); + err = CtdlSaveMsgPointersInRoom(targ, msgs, num_msgs, 1, NULL); if (err != 0) { cprintf("%d Cannot store message(s) in %s: error %d\n", err, targ, err); @@ -4121,6 +4407,7 @@ void PutMetaData(struct MetaData *smibuf) void AdjRefCount(long msgnum, int incr) { struct arcq new_arcq; + int rv = 0; begin_critical_section(S_SUPPMSGMAIN); if (arcfp == NULL) { @@ -4150,7 +4437,7 @@ void AdjRefCount(long msgnum, int incr) new_arcq.arcq_msgnum = msgnum; new_arcq.arcq_delta = incr; - fwrite(&new_arcq, sizeof(struct arcq), 1, arcfp); + rv = fwrite(&new_arcq, sizeof(struct arcq), 1, arcfp); fflush(arcfp); return; @@ -4172,7 +4459,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) { @@ -4235,7 +4522,7 @@ void TDAP_AdjRefCount(long msgnum, int incr) smi.meta_refcount += incr; PutMetaData(&smi); end_critical_section(S_SUPPMSGMAIN); - CtdlLogPrintf(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 @@ -4265,24 +4552,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); @@ -4291,24 +4575,10 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ safestrncpy(roomname, req_room, sizeof(roomname)); } - fp = fopen(tempfilename, "rb"); - if (fp == NULL) { - CtdlLogPrintf(CTDL_CRIT, "Cannot open %s: %s\n", - tempfilename, strerror(errno)); - return; - } - fseek(fp, 0L, SEEK_END); - raw_length = ftell(fp); - rewind(fp); 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); - fclose(fp); - 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)); @@ -4336,7 +4606,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, @@ -4344,8 +4613,6 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ ); } - free(raw_message); - CtdlLogPrintf(CTDL_DEBUG, "Allocating\n"); msg = malloc(sizeof(struct CtdlMessage)); memset(msg, 0, sizeof(struct CtdlMessage)); @@ -4375,7 +4642,7 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ ); } /* Now write the data */ - CtdlSubmitMsg(msg, NULL, roomname); + CtdlSubmitMsg(msg, NULL, roomname, 0); CtdlFreeMessage(msg); } @@ -4435,20 +4702,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); } @@ -4498,3 +4754,27 @@ void cmd_isme(char *argbuf) { } } + + +/*****************************************************************************/ +/* MODULE INITIALIZATION STUFF */ +/*****************************************************************************/ + +CTDL_MODULE_INIT(msgbase) +{ + CtdlRegisterProtoHook(cmd_msgs, "MSGS", "Output a list of messages in the current room"); + CtdlRegisterProtoHook(cmd_msg0, "MSG0", "Output a message in plain text format"); + CtdlRegisterProtoHook(cmd_msg2, "MSG2", "Output a message in RFC822 format"); + CtdlRegisterProtoHook(cmd_msg3, "MSG3", "Output a message in raw format (deprecated)"); + CtdlRegisterProtoHook(cmd_msg4, "MSG4", "Output a message in the client's preferred format"); + CtdlRegisterProtoHook(cmd_msgp, "MSGP", "Select preferred format for MSG4 output"); + CtdlRegisterProtoHook(cmd_opna, "OPNA", "Open an attachment for download"); + CtdlRegisterProtoHook(cmd_dlat, "DLAT", "Download an attachment"); + CtdlRegisterProtoHook(cmd_ent0, "ENT0", "Enter a message"); + CtdlRegisterProtoHook(cmd_dele, "DELE", "Delete a message"); + CtdlRegisterProtoHook(cmd_move, "MOVE", "Move or copy a message to another room"); + CtdlRegisterProtoHook(cmd_isme, "ISME", "Determine whether an email address belongs to a user"); + + /* return our Subversion id for the Log */ + return "$Id$"; +}