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) {
*
*/
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;
}
/* 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)
*/
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;
if (!is_valid_message(TheMessage)) {
CtdlLogPrintf(CTDL_ERR,
"ERROR: invalid preloaded message for output\n");
+ cit_backtrace ();
return(om_no_such_msg);
}
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') {
}
else
{
+ if ((flags & QP_EADDR) != 0)
+ mptr = qp_encode_email_addrs(mptr);
cprintf("To: %s%s", mptr, nl);
}
}
else if (i == 'W') {
cprintf("References: ");
k = num_tokens(mptr, '|');
- for (i=0; i<k; ++i) {
- extract_token(buf, mptr, i, '|', sizeof buf);
+ for (j=0; j<k; ++j) {
+ extract_token(buf, mptr, j, '|', sizeof buf);
cprintf("<%s>", buf);
- if (i == (k-1)) {
+ if (j == (k-1)) {
cprintf("%s", nl);
}
else {
}
}
}
+ if (mptr != mpptr)
+ free (mptr);
}
}
if (subject_found == 0) {
char outbuf[1024];
int outlen = 0;
int nllen = strlen(nl);
+ prev_ch = 0;
while (ch=*mptr, ch!=0) {
if (ch==13) {
/* do nothing */
}
}
}
+ 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);
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;
}
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);
}
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);
}
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);
}
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);
}
* 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];
char *saved_rfc822_version = NULL;
int qualified_for_journaling = 0;
struct CitContext *CCC = CC; /* CachedCitContext - performance boost */
+ char bounce_to[1024] = "";
CtdlLogPrintf(CTDL_DEBUG, "CtdlSubmitMsg() called\n");
if (is_valid_message(msg) == 0) return(-1); /* self check */
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;
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.
*/
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));
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);
}
}
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; i<num_tokens(recps->recp_internet, '|'); ++i) {
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);
}
}
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);
}
}
msg->cm_fields['M'] = strdup(text);
- CtdlSubmitMsg(msg, recp, room);
+ CtdlSubmitMsg(msg, recp, room, 0);
CtdlFreeMessage(msg);
if (recp != NULL) free_recipients(recp);
}
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];
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;
}
int i, j;
char buf[256];
int newuseremail_ok = 0;
+ char references[SIZ];
+ char *ptr;
unbuffer_output();
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. */
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.
free(all_recps);
if (msg != NULL) {
- msgnum = CtdlSubmitMsg(msg, valid, "");
+ msgnum = CtdlSubmitMsg(msg, valid, "", QP_EADDR);
if (do_confirm) {
cprintf("%ld\n", msgnum);
* 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);
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));
);
}
else {
- raw_message[raw_length] = 0;
memcpy(
&encoded_message[strlen(encoded_message)],
raw_message,
);
}
- free(raw_message);
-
CtdlLogPrintf(CTDL_DEBUG, "Allocating\n");
msg = malloc(sizeof(struct CtdlMessage));
memset(msg, 0, sizeof(struct CtdlMessage));
);
}
/* Now write the data */
- CtdlSubmitMsg(msg, NULL, roomname);
+ CtdlSubmitMsg(msg, NULL, roomname, 0);
CtdlFreeMessage(msg);
}
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);
}