#include "serv_network.h"
#include "threads.h"
+#include "ctdl_module.h"
+
long config_msgnum;
struct addresses_to_be_filed *atbf = NULL;
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],
|| (!IsEmptyStr(cbid) && (!strcasecmp(CC->download_desired_section, cbid)))
) {
*found_it = 1;
- cprintf("%d %d\n", BINARY_FOLLOWS, (int)length);
+ cprintf("%d %d|-1|%s|%s\n",
+ BINARY_FOLLOWS,
+ (int)length,
+ filename,
+ cbtype
+ );
client_write(content, length);
}
}
}
+/* 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)
*/
/* 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");
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],
safestrncpy(suser, mptr, sizeof suser);
}
else if (i == 'Y') {
- if ((flags & QP_EADDR) != 0)
+ 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') {
{
if (haschar(mptr, '@') == 0)
{
+ sanitize_truncated_recipient(mptr);
cprintf("To: %s@%s", mptr, config.c_fqdn);
cprintf("%s", nl);
}
else
{
- if ((flags & QP_EADDR) != 0)
+ if ((flags & QP_EADDR) != 0) {
mptr = qp_encode_email_addrs(mptr);
+ }
+ sanitize_truncated_recipient(mptr);
cprintf("To: %s", mptr);
cprintf("%s", nl);
}
int qualified_for_journaling = 0;
struct CitContext *CCC = CC; /* CachedCitContext - performance boost */
char bounce_to[1024] = "";
+ size_t tmp = 0;
CtdlLogPrintf(CTDL_DEBUG, "CtdlSubmitMsg() called\n");
if (is_valid_message(msg) == 0) return(-1); /* self check */
}
/* 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; i<num_tokens(recps->recp_room, '|'); ++i) {
extract_token(recipient, recps->recp_room, i,
'|', sizeof recipient);
lputuser(&CCC->user);
/* Decide where bounces need to be delivered */
- if (CCC->logged_in) {
+ 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 {
/* 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; i<num_tokens(recps->recp_local, '|'); ++i) {
extract_token(recipient, recps->recp_local, i,
'|', sizeof recipient);
* 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; i<num_tokens(recps->recp_ignet, '|'); ++i) {
extract_token(recipient, recps->recp_ignet, i,
'|', sizeof recipient);
* 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);
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; i<num_tokens(recps->recp_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;
/*
* 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;
/* 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 = "";
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]);
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) {
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);
}
}
-/*
- * 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);
-}
-
-
/*
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;
}
/*
* 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);
}
}
+
+
+/*****************************************************************************/
+/* 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$";
+}