Mailinglists: fix reply-to for local posters
[citadel.git] / citadel / msgbase.c
index 1bc393b26efc0c958d6655f4fc0910ea4863fef2..8834be2fe27f163c658128ce08176b6ac4000eef 100644 (file)
@@ -1,21 +1,15 @@
 /*
  * Implements the message store.
  *
- * Copyright (c) 1987-2011 by the citadel.org team
+ * Copyright (c) 1987-2012 by the citadel.org team
  *
  * This program is open source software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
+ * it under the terms of the GNU General Public License version 3.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
 #include "sysdep.h"
@@ -1084,26 +1078,37 @@ void mime_download(char *name, char *filename, char *partnum, char *disp,
                   char *encoding, char *cbid, void *cbuserdata)
 {
        int rv = 0;
+       CitContext *CCC = MyContext();
 
        /* Silently go away if there's already a download open. */
-       if (CC->download_fp != NULL)
+       if (CCC->download_fp != NULL)
                return;
 
        if (
-               (!IsEmptyStr(partnum) && (!strcasecmp(CC->download_desired_section, partnum)))
-       ||      (!IsEmptyStr(cbid) && (!strcasecmp(CC->download_desired_section, cbid)))
+               (!IsEmptyStr(partnum) && (!strcasecmp(CCC->download_desired_section, partnum)))
+       ||      (!IsEmptyStr(cbid) && (!strcasecmp(CCC->download_desired_section, cbid)))
        ) {
-               CC->download_fp = tmpfile();
-               if (CC->download_fp == NULL)
+               CCC->download_fp = tmpfile();
+               if (CCC->download_fp == NULL) {
+                       syslog(LOG_EMERG, "mime_download(): Couldn't write: %s\n",
+                              strerror(errno));
+                       cprintf("%d cannot open temporary file: %s\n",
+                               ERROR + INTERNAL_ERROR, strerror(errno));
                        return;
+               }
        
                rv = fwrite(content, length, 1, CC->download_fp);
-               if (rv == -1) {
+               if (rv <= 0) {
                        syslog(LOG_EMERG, "mime_download(): Couldn't write: %s\n",
                               strerror(errno));
+                       cprintf("%d unable to write tempfile.\n",
+                               ERROR + TOO_BIG);
+                       fclose(CCC->download_fp);
+                       CCC->download_fp = NULL;
+                       return;
                }
-               fflush(CC->download_fp);
-               rewind(CC->download_fp);
+               fflush(CCC->download_fp);
+               rewind(CCC->download_fp);
        
                OpenCmdResult(filename, cbtype);
        }
@@ -1239,26 +1244,28 @@ int is_valid_message(struct CtdlMessage *msg) {
        return 1;
 }
 
+void CtdlFreeMessageContents(struct CtdlMessage *msg)
+{
+       int i;
+
+       for (i = 0; i < 256; ++i)
+               if (msg->cm_fields[i] != NULL) {
+                       free(msg->cm_fields[i]);
+               }
 
+       msg->cm_magic = 0;      /* just in case */
+}
 /*
  * 'Destructor' for struct CtdlMessage
  */
 void CtdlFreeMessage(struct CtdlMessage *msg)
 {
-       int i;
-
        if (is_valid_message(msg) == 0) 
        {
                if (msg != NULL) free (msg);
                return;
        }
-
-       for (i = 0; i < 256; ++i)
-               if (msg->cm_fields[i] != NULL) {
-                       free(msg->cm_fields[i]);
-               }
-
-       msg->cm_magic = 0;      /* just in case */
+       CtdlFreeMessageContents(msg);
        free(msg);
 }
 
@@ -2635,7 +2642,6 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms
                "CtdlSaveMsgPointersInRoom(room=%s, num_msgs=%d, repl=%d, suppress_rca=%d)\n",
                roomname, num_newmsgs, do_repl_check, suppress_refcount_adj
        );
-       if (num_newmsgs > 0) for (i=0; i<num_newmsgs; ++i) syslog(LOG_DEBUG, "\033[33mmerge %ld\033[0m", newmsgidlist[i]);
 
        strcpy(hold_rm, CC->room.QRname);
 
@@ -2682,10 +2688,6 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms
                }
                if (unique) {
                        msgs_to_be_merged[num_msgs_to_be_merged++] = newmsgidlist[i];
-                       syslog(LOG_DEBUG, "\033[32mmsg %ld is being merged\033[0m", newmsgidlist[i]);
-               }
-               else {
-                       syslog(LOG_DEBUG, "\033[31mmsg %ld is not unique\033[0m", newmsgidlist[i]);
                }
        }
 
@@ -3025,7 +3027,6 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
        int qualified_for_journaling = 0;
        CitContext *CCC = MyContext();
        char bounce_to[1024] = "";
-       size_t tmp = 0;
        int rv = 0;
 
        syslog(LOG_DEBUG, "CtdlSubmitMsg() called\n");
@@ -3204,7 +3205,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
                for (i=0; i<num_tokens(recps->recp_room, '|'); ++i) {
                        extract_token(recipient, recps->recp_room, i,
                                      '|', sizeof recipient);
-                       syslog(LOG_DEBUG, "Delivering to room <%s>\n", recipient);
+                       syslog(LOG_DEBUG, "Delivering to room <%s>\n", recipient);///// xxxx
                        CtdlSaveMsgPointerInRoom(recipient, newmsgid, 0, msg);
                }
 
@@ -3256,6 +3257,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
                                        imsg->cm_magic = CTDLMESSAGE_MAGIC;
                                        imsg->cm_anon_type = MES_NORMAL;
                                        imsg->cm_format_type = FMT_RFC822;
+                                       imsg->cm_fields['U'] = strdup("QMSG");
                                        imsg->cm_fields['A'] = strdup("Citadel");
                                        imsg->cm_fields['J'] = strdup("do not journal");
                                        imsg->cm_fields['M'] = instr;   /* imsg owns this memory now */
@@ -3266,14 +3268,18 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,     /* message to save */
                        }
                        else {
                                syslog(LOG_DEBUG, "No user <%s>\n", recipient);
-                               CtdlSaveMsgPointerInRoom(config.c_aideroom,
-                                                        newmsgid, 0, msg);
+                               CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg);
                        }
                }
 
        /* Perform "after save" hooks */
        syslog(LOG_DEBUG, "Performing after-save hooks\n");
+       if (msg->cm_fields['3'] != NULL) free(msg->cm_fields['3']);
+       msg->cm_fields['3'] = malloc(20);
+       snprintf(msg->cm_fields['3'], 20, "%ld", newmsgid);
        PerformMessageHooks(msg, EVT_AFTERSAVE);
+       free(msg->cm_fields['3']);
+       msg->cm_fields['3'] = NULL;
 
        /* For IGnet mail, we have to save a new copy into the spooler for
         * each recipient, with the R and D fields set to the recipient and
@@ -3330,29 +3336,41 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,     /* message to save */
         * contain a recipient.
         */
        if ((recps != NULL) && (recps->num_internet > 0)) {
+               StrBuf *SpoolMsg = NewStrBuf();
+               long nTokens;
+
                syslog(LOG_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\n",
-                        SPOOLMIME, newmsgid, (long)time(NULL),
-                        bounce_to
-                       );
 
-               if (recps->envelope_from != NULL) {
-                       tmp = strlen(instr);
-                       snprintf(&instr[tmp], instr_alloc-tmp, "envelope_from|%s\n", recps->envelope_from);
-               }
+               StrBufPrintf(SpoolMsg,
+                            "Content-type: "SPOOLMIME"\n"
+                            "\n"
+                            "msgid|%ld\n"
+                            "submitted|%ld\n"
+                            "bounceto|%s\n",
+                            newmsgid,
+                            (long)time(NULL),
+                            bounce_to);
 
-               for (i=0; i<num_tokens(recps->recp_internet, '|'); ++i) {
-                       tmp = strlen(instr);
-                       extract_token(recipient, recps->recp_internet, i, '|', sizeof recipient);
-                       if ((tmp + strlen(recipient) + 32) > instr_alloc) {
-                               instr_alloc = instr_alloc * 2;
-                               instr = realloc(instr, instr_alloc);
+               if (recps->envelope_from != NULL) {
+                       StrBufAppendBufPlain(SpoolMsg, HKEY("envelope_from|"), 0);
+                       StrBufAppendBufPlain(SpoolMsg, recps->envelope_from, -1, 0);
+                       StrBufAppendBufPlain(SpoolMsg, HKEY("\n"), 0);
+               }
+               if (recps->sending_room != NULL) {
+                       StrBufAppendBufPlain(SpoolMsg, HKEY("source_room|"), 0);
+                       StrBufAppendBufPlain(SpoolMsg, recps->sending_room, -1, 0);
+                       StrBufAppendBufPlain(SpoolMsg, HKEY("\n"), 0);
+               }
+
+               nTokens = num_tokens(recps->recp_internet, '|');
+               for (i = 0; i < nTokens; i++) {
+                       long len;
+                       len = extract_token(recipient, recps->recp_internet, i, '|', sizeof recipient);
+                       if (len > 0) {
+                               StrBufAppendBufPlain(SpoolMsg, HKEY("remote|"), 0);
+                               StrBufAppendBufPlain(SpoolMsg, recipient, len, 0);
+                               StrBufAppendBufPlain(SpoolMsg, HKEY("|0||\n"), 0);
                        }
-                       snprintf(&instr[tmp], instr_alloc - tmp, "remote|%s|0||\n", recipient);
                }
 
                imsg = malloc(sizeof(struct CtdlMessage));
@@ -3360,9 +3378,10 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,      /* message to save */
                imsg->cm_magic = CTDLMESSAGE_MAGIC;
                imsg->cm_anon_type = MES_NORMAL;
                imsg->cm_format_type = FMT_RFC822;
+               imsg->cm_fields['U'] = strdup("QMSG");
                imsg->cm_fields['A'] = strdup("Citadel");
                imsg->cm_fields['J'] = strdup("do not journal");
-               imsg->cm_fields['M'] = instr;   /* imsg owns this memory now */
+               imsg->cm_fields['M'] = SmashStrBuf(&SpoolMsg);  /* imsg owns this memory now */
                CtdlSubmitMsg(imsg, NULL, SMTP_SPOOLOUT_ROOM, QP_EADDR);
                CtdlFreeMessage(imsg);
        }
@@ -3994,9 +4013,11 @@ struct recptypes *validate_recipients(const char *supplied_recipients,
                                      int Flags) {
        struct recptypes *ret;
        char *recipients = NULL;
+       char *org_recp;
        char this_recp[256];
        char this_recp_cooked[256];
        char append[SIZ];
+       long len;
        int num_recps = 0;
        int i, j;
        int mailtype;
@@ -4026,19 +4047,22 @@ struct recptypes *validate_recipients(const char *supplied_recipients,
         * actually need, but it's healthier for the heap than doing lots of tiny
         * realloc() calls instead.
         */
-
-       ret->errormsg = malloc(strlen(recipients) + 1024);
-       ret->recp_local = malloc(strlen(recipients) + 1024);
-       ret->recp_internet = malloc(strlen(recipients) + 1024);
-       ret->recp_ignet = malloc(strlen(recipients) + 1024);
-       ret->recp_room = malloc(strlen(recipients) + 1024);
-       ret->display_recp = malloc(strlen(recipients) + 1024);
+       len = strlen(recipients) + 1024;
+       ret->errormsg = malloc(len);
+       ret->recp_local = malloc(len);
+       ret->recp_internet = malloc(len);
+       ret->recp_ignet = malloc(len);
+       ret->recp_room = malloc(len);
+       ret->display_recp = malloc(len);
+       ret->recp_orgroom = malloc(len);
+       org_recp = malloc(len);
 
        ret->errormsg[0] = 0;
        ret->recp_local[0] = 0;
        ret->recp_internet[0] = 0;
        ret->recp_ignet[0] = 0;
        ret->recp_room[0] = 0;
+       ret->recp_orgroom[0] = 0;
        ret->display_recp[0] = 0;
 
        ret->recptypes_magic = RECPTYPES_MAGIC;
@@ -4053,7 +4077,6 @@ struct recptypes *validate_recipients(const char *supplied_recipients,
        /* Now start extracting recipients... */
 
        while (!IsEmptyStr(recipients)) {
-
                for (i=0; i<=strlen(recipients); ++i) {
                        if (recipients[i] == '\"') in_quotes = 1 - in_quotes;
                        if ( ( (recipients[i] == ',') && (!in_quotes) ) || (recipients[i] == 0) ) {
@@ -4074,6 +4097,8 @@ struct recptypes *validate_recipients(const char *supplied_recipients,
                        break;
                syslog(LOG_DEBUG, "Evaluating recipient #%d: %s\n", num_recps, this_recp);
                ++num_recps;
+
+               strcpy(org_recp, this_recp);
                mailtype = alias(this_recp);
                mailtype = alias(this_recp);
                mailtype = alias(this_recp);
@@ -4125,6 +4150,12 @@ struct recptypes *validate_recipients(const char *supplied_recipients,
                                                strcat(ret->recp_room, "|");
                                        }
                                        strcat(ret->recp_room, &this_recp_cooked[5]);
+
+                                       if (!IsEmptyStr(ret->recp_orgroom)) {
+                                               strcat(ret->recp_orgroom, "|");
+                                       }
+                                       strcat(ret->recp_orgroom, org_recp);
+
                                }
                                        
                                /* Restore room in case something needs it */
@@ -4209,6 +4240,7 @@ struct recptypes *validate_recipients(const char *supplied_recipients,
                        }
                }
        }
+       free(org_recp);
 
        if ((ret->num_local + ret->num_internet + ret->num_ignet +
             ret->num_room + ret->num_error) == 0) {
@@ -4247,6 +4279,7 @@ void free_recipients(struct recptypes *valid) {
        if (valid->recp_internet != NULL)       free(valid->recp_internet);
        if (valid->recp_ignet != NULL)          free(valid->recp_ignet);
        if (valid->recp_room != NULL)           free(valid->recp_room);
+       if (valid->recp_orgroom != NULL)        free(valid->recp_orgroom);
        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);
@@ -4542,6 +4575,15 @@ void cmd_ent0(char *entargs)
        }
        free(all_recps);
 
+       if ((valid != NULL) && (valid->num_room == 1))
+       {
+               /* posting into an ML room? set the envelope from 
+                * to the actual mail address so others get a valid
+                * reply-to-header.
+                */
+               msg->cm_fields['V'] = strdup(valid->recp_orgroom);
+       }
+
        if (msg != NULL) {
                msgnum = CtdlSubmitMsg(msg, valid, "", QP_EADDR);
                if (verbose_reply)
@@ -4924,13 +4966,13 @@ void AdjRefCount(long msgnum, int incr)
        struct arcq new_arcq;
        int rv = 0;
 
-       syslog(LOG_DEBUG, "AdjRefCount() msg %ld ref count delta %+d\n",
-              msgnum, incr
-               );
+       syslog(LOG_DEBUG, "AdjRefCount() msg %ld ref count delta %+d\n", msgnum, incr);
 
        begin_critical_section(S_SUPPMSGMAIN);
        if (arcfp == NULL) {
                arcfp = fopen(file_arcq, "ab+");
+               chown(file_arcq, CTDLUID, (-1));
+               chmod(file_arcq, 0600);
        }
        end_critical_section(S_SUPPMSGMAIN);