"Fossies" - the Fresh Open Source Software Archive

Member "mlmmj-1.3.0/src/mlmmj-process.c" (2 Oct 2016, 32746 Bytes) of package /linux/privat/mlmmj-1.3.0.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mlmmj-process.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.2.19.0_vs_1.3.0.

    1 /* Copyright (C) 2003, 2003, 2004 Mads Martin Joergensen <mmj at mmj.dk>
    2  *
    3  * $Id$
    4  *
    5  * Permission is hereby granted, free of charge, to any person obtaining a copy
    6  * of this software and associated documentation files (the "Software"), to
    7  * deal in the Software without restriction, including without limitation the
    8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    9  * sell copies of the Software, and to permit persons to whom the Software is
   10  * furnished to do so, subject to the following conditions:
   11  *
   12  * The above copyright notice and this permission notice shall be included in
   13  * all copies or substantial portions of the Software.
   14  *
   15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   21  * IN THE SOFTWARE.
   22  */
   23 
   24 #include <stdio.h>
   25 #include <stdlib.h>
   26 #include <unistd.h>
   27 #include <errno.h>
   28 #include <string.h>
   29 #include <sys/types.h>
   30 #include <sys/stat.h>
   31 #include <fcntl.h>
   32 #include <sys/wait.h>
   33 #include <libgen.h>
   34 #include <regex.h>
   35 
   36 #include "mlmmj.h"
   37 #include "wrappers.h"
   38 #include "find_email_adr.h"
   39 #include "incindexfile.h"
   40 #include "getlistaddr.h"
   41 #include "getlistdelim.h"
   42 #include "listcontrol.h"
   43 #include "strgen.h"
   44 #include "do_all_the_voodoo_here.h"
   45 #include "log_error.h"
   46 #include "mygetline.h"
   47 #include "statctrl.h"
   48 #include "ctrlvalue.h"
   49 #include "ctrlvalues.h"
   50 #include "getlistaddr.h"
   51 #include "prepstdreply.h"
   52 #include "subscriberfuncs.h"
   53 #include "memory.h"
   54 #include "log_oper.h"
   55 #include "unistr.h"
   56 #include "chomp.h"
   57 
   58 enum action {
   59     ALLOW,
   60     SEND,
   61     DENY,
   62     MODERATE,
   63     DISCARD
   64 };
   65 
   66 
   67 static char *action_strs[] = {
   68     "allowed",
   69     "sent",
   70     "denied",
   71     "moderated",
   72     "discarded"
   73 };
   74 
   75 
   76 enum modreason {
   77     MODNONSUBPOSTS,
   78     MODNONMODPOSTS,
   79     ACCESS,
   80     MODERATED
   81 };
   82 
   83 
   84 static char *modreason_strs[] = {
   85     "modnonsubposts",
   86     "modnonmodposts",
   87     "access",
   88     "moderated"
   89 };
   90 
   91 
   92 static int is_moderator(const char *listdir, const char *address,
   93         char **moderators) {
   94     char *buf, *tmp, *moderatorsfilename;
   95     int moderatorsfd, foundaddr = 0;
   96 
   97     moderatorsfilename = concatstr(2, listdir, "/control/moderators");
   98     if((moderatorsfd = open(moderatorsfilename, O_RDONLY)) < 0) {
   99         log_error(LOG_ARGS, "Could not open '%s'", moderatorsfilename);
  100         myfree(moderatorsfilename);
  101         exit(EXIT_FAILURE);
  102     }
  103     myfree(moderatorsfilename);
  104 
  105     while((buf = mygetline(moderatorsfd))) {
  106         chomp(buf);
  107         if(address && strcasecmp(buf, address) == 0) {
  108             foundaddr = 1;
  109             if (!moderators) {
  110                 close(moderatorsfd);
  111                 myfree(buf);
  112                 return foundaddr;
  113             }
  114         }
  115         if (moderators) {
  116             tmp = *moderators;
  117             *moderators = concatstr(3, *moderators, buf, "\n");
  118             myfree(tmp);
  119         }
  120         myfree(buf);
  121     }
  122 
  123     close(moderatorsfd);
  124     return foundaddr;
  125 }
  126 
  127 
  128 static void newmoderated(const char *listdir, const char *mailfilename,
  129           const char *mlmmjsend, const char *efromsender,
  130           const char *subject, const char *posteraddr,
  131           enum modreason modreason)
  132 {
  133     char *from, *listfqdn, *listname, *moderators = NULL;
  134     char *replyto, *listaddr = getlistaddr(listdir), *listdelim;
  135     text *txt;
  136     memory_lines_state *mls;
  137     char *queuefilename = NULL;
  138     const char *efromismod = NULL;
  139     char *mailbasename = mybasename(mailfilename), *to, *reject;
  140     int notifymod = 0, status;
  141     pid_t childpid, pid;
  142 #if 0
  143     printf("mailfilename = [%s], mailbasename = [%s]\n", mailfilename,
  144                                                  mailbasename);
  145 #endif
  146     listfqdn = genlistfqdn(listaddr);
  147     listname = genlistname(listaddr);
  148 
  149     if(statctrl(listdir, "ifmodsendonlymodmoderate"))
  150         efromismod = efromsender;
  151 
  152     if(!is_moderator(listdir, efromismod, &moderators))
  153         efromismod = NULL;
  154 
  155     if(efromismod) mls = init_memory_lines(efromismod);
  156     else mls = init_memory_lines(moderators);
  157 
  158     myfree(moderators);
  159 
  160     listdelim = getlistdelim(listdir);
  161     replyto = concatstr(6, listname, listdelim, "release-", mailbasename,
  162                 "@", listfqdn);
  163     reject = concatstr(6, listname, listdelim, "reject-", mailbasename,
  164                 "@", listfqdn);
  165 
  166     from = concatstr(4, listname, listdelim, "owner@", listfqdn);
  167     to = concatstr(3, listname, "-moderators@", listfqdn); /* FIXME JFA: Should this be converted? Why, why not? */
  168 
  169     myfree(listdelim);
  170     myfree(listname);
  171     myfree(listfqdn);
  172 
  173     txt = open_text(listdir, "moderate", "post",
  174             modreason_strs[modreason], NULL, "moderation");
  175     MY_ASSERT(txt);
  176     register_unformatted(txt, "subject", subject);
  177     register_unformatted(txt, "posteraddr", posteraddr);
  178     register_unformatted(txt, "moderateaddr", replyto); /* DEPRECATED */
  179     register_unformatted(txt, "releaseaddr", replyto);
  180     register_unformatted(txt, "rejectaddr", reject);
  181     register_unformatted(txt, "moderators", "%moderators%"); /* DEPRECATED */
  182     register_formatted(txt, "moderators",
  183             rewind_memory_lines, get_memory_line, mls);
  184     register_originalmail(txt, mailfilename);
  185     queuefilename = prepstdreply(txt, listdir, "$listowner$", to, replyto);
  186     MY_ASSERT(queuefilename);
  187     close_text(txt);
  188 
  189     /* we might need to exec more than one mlmmj-send */
  190     
  191     notifymod = !efromismod && statctrl(listdir,"notifymod");
  192     
  193     if (notifymod) {
  194         childpid = fork();
  195         if(childpid < 0)
  196             log_error(LOG_ARGS, "Could not fork; poster not notified");
  197     } else
  198         childpid = -1;
  199 
  200     if(childpid != 0) {
  201         if(childpid > 0) {
  202             do /* Parent waits for the child */
  203                 pid = waitpid(childpid, &status, 0);
  204             while(pid == -1 && errno == EINTR);
  205         }
  206 
  207         finish_memory_lines(mls);
  208 
  209         if(efromismod)
  210             execlp(mlmmjsend, mlmmjsend,
  211                     "-l", "1",
  212                     "-L", listdir,
  213                     "-F", from,
  214                     "-m", queuefilename,
  215                     "-T", efromsender, (char *)NULL);
  216         else
  217             execlp(mlmmjsend, mlmmjsend,
  218                     "-l", "2",
  219                     "-L", listdir,
  220                     "-F", from,
  221                     "-m", queuefilename, (char *)NULL);
  222         log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjsend);
  223         exit(EXIT_FAILURE);
  224     }
  225 
  226     myfree(queuefilename);
  227 
  228     /* send mail to poster that the list is moderated */
  229 
  230     txt = open_text(listdir, "wait", "post",
  231             modreason_strs[modreason], NULL, "moderation-poster");
  232     MY_ASSERT(txt);
  233     register_unformatted(txt, "subject", subject);
  234     register_unformatted(txt, "posteraddr", posteraddr);
  235     register_unformatted(txt, "moderators", "%moderators%"); /* DEPRECATED */
  236     register_formatted(txt, "moderators",
  237             rewind_memory_lines, get_memory_line, mls);
  238     register_originalmail(txt, mailfilename);
  239     queuefilename = prepstdreply(txt, listdir,
  240             "$listowner$", efromsender, NULL);
  241     MY_ASSERT(queuefilename);
  242     close_text(txt);
  243 
  244     finish_memory_lines(mls);
  245 
  246     execlp(mlmmjsend, mlmmjsend,
  247             "-l", "1",
  248             "-L", listdir,
  249             "-F", from,
  250             "-m", queuefilename,
  251             "-T", efromsender, (char *)NULL);
  252 
  253     log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjsend);
  254     exit(EXIT_FAILURE);
  255 }
  256 
  257 
  258 static enum action do_access(struct strlist *rule_strs, struct strlist *hdrs,
  259         const char *from, const char *listdir)
  260 {
  261     int i, j;
  262     unsigned int match;
  263     char *rule_ptr;
  264     char errbuf[128];
  265     int err;
  266     enum action act;
  267     unsigned int not;
  268     regex_t regexp;
  269     char *hdr;
  270 
  271     for (i=0; i<rule_strs->count; i++) {
  272 
  273         rule_ptr = rule_strs->strs[i];
  274 
  275         if (strncmp(rule_ptr, "allow", 5) == 0) {
  276             rule_ptr += 5;
  277             act = ALLOW;
  278         } else if (strncmp(rule_ptr, "send", 4) == 0) {
  279             rule_ptr += 4;
  280             act = SEND;
  281         } else if (strncmp(rule_ptr, "deny", 4) == 0) {
  282             rule_ptr += 4;
  283             act = DENY;
  284         } else if (strncmp(rule_ptr, "moderate", 8) == 0) {
  285             rule_ptr += 8;
  286             act = MODERATE;
  287         } else if (strncmp(rule_ptr, "discard", 7) == 0) {
  288             rule_ptr += 7;
  289             act = DISCARD;
  290         } else {
  291             errno = 0;
  292             log_error(LOG_ARGS, "Unable to parse rule #%d \"%s\":"
  293                     " Missing action keyword. Denying post from \"%s\"",
  294                     i, rule_strs->strs[i], from);
  295             log_oper(listdir, OPLOGFNAME, "Unable to parse rule #%d \"%s\":"
  296                     " Missing action keyword. Denying post from \"%s\"",
  297                     i, rule_strs->strs[i], from);
  298             return DENY;
  299         }
  300 
  301         if (*rule_ptr == ' ') {
  302             rule_ptr++;
  303         } else if (*rule_ptr == '\0') {
  304             /* the rule is a keyword and no regexp */
  305             log_oper(listdir, OPLOGFNAME, "mlmmj-process: access -"
  306                     " A mail from \"%s\" was %s by rule #%d \"%s\"",
  307                     from, action_strs[act], i, rule_strs->strs[i]);
  308             return act;
  309         } else {
  310             /* we must have space or end of string */
  311             errno = 0;
  312             log_error(LOG_ARGS, "Unable to parse rule #%d \"%s\":"
  313                     " Invalid character after action keyword."
  314                     " Denying post from \"%s\"", i, rule_strs->strs[i], from);
  315             log_oper(listdir, OPLOGFNAME, "Unable to parse rule #%d \"%s\":"
  316                     " Invalid character after action keyword."
  317                     " Denying post from \"%s\"", i, rule_strs->strs[i], from);
  318             return DENY;
  319         }
  320 
  321         if (*rule_ptr == '!') {
  322             rule_ptr++;
  323             not = 1;
  324         } else {
  325             not = 0;
  326         }
  327 
  328         /* remove unanchored ".*" from beginning of regexp to stop the
  329          * regexp matching to loop so long time it seems like it's
  330          * hanging */
  331         if (strncmp(rule_ptr, "^.*", 3) == 0) {
  332             rule_ptr += 3;
  333         }
  334         while (strncmp(rule_ptr, ".*", 2) == 0) {
  335             rule_ptr += 2;
  336         }
  337 
  338         if ((err = regcomp(&regexp, rule_ptr,
  339                 REG_EXTENDED | REG_NOSUB | REG_ICASE))) {
  340             regerror(err, &regexp, errbuf, sizeof(errbuf));
  341             regfree(&regexp);
  342             errno = 0;
  343             log_error(LOG_ARGS, "regcomp() failed for rule #%d \"%s\""
  344                     " (message: '%s') (expression: '%s')"
  345                     " Denying post from \"%s\"",
  346                     i, rule_strs->strs[i], errbuf, rule_ptr, from);
  347             log_oper(listdir, OPLOGFNAME, "regcomp() failed for rule"
  348                     " #%d \"%s\" (message: '%s') (expression: '%s')"
  349                     " Denying post from \"%s\"",
  350                     i, rule_strs->strs[i], errbuf, rule_ptr, from);
  351             return DENY;
  352         }
  353 
  354         match = 0;
  355         for (j=0; j<hdrs->count; j++) {
  356             if (regexec(&regexp, hdrs->strs[j], 0, NULL, 0)
  357                     == 0) {
  358                 match = 1;
  359                 break;
  360             }
  361         }
  362 
  363         regfree(&regexp);
  364 
  365         if (match != not) {
  366             if (match) {
  367                 hdr = mystrdup(hdrs->strs[j]);
  368                 log_oper(listdir, OPLOGFNAME, "mlmmj-process: access -"
  369                         " A mail from \"%s\" with header \"%s\" was %s by"
  370                         " rule #%d \"%s\"", from, hdr, action_strs[act],
  371                         i, rule_strs->strs[i]);
  372                 myfree(hdr);
  373             } else {
  374                 log_oper(listdir, OPLOGFNAME, "mlmmj-process: access -"
  375                         " A mail from \"%s\" was %s by rule #%d \"%s\""
  376                         " because no header matched.", from,
  377                         action_strs[act], i, rule_strs->strs[i]);
  378             }
  379             return act;
  380         }
  381 
  382     }
  383 
  384     log_oper(listdir, OPLOGFNAME, "mlmmj-process: access -"
  385             " A mail from \"%s\" didn't match any rules, and"
  386             " was denied by default.", from);
  387     return DENY;
  388 }
  389 
  390 
  391 static int addrmatch(const char *listaddr, const char *addr,
  392         const char *listdelim, char **recipextra)
  393 {
  394     char *delim, *atsign;
  395     size_t len;
  396 
  397     if (!addr)
  398         return 0;
  399 
  400     if(strcasecmp(listaddr, addr) == 0) {
  401         if (recipextra)
  402             *recipextra = NULL;
  403         return 1;
  404     }
  405 
  406     if (!listdelim)
  407         return 0;
  408 
  409     delim = strstr(addr, listdelim);
  410     if (!delim)
  411         return 0;
  412 
  413     len = delim - addr;
  414     if(strncasecmp(listaddr, addr, len) != 0)
  415         return 0;
  416     if(*(listaddr + len) != '@')
  417         return 0;
  418 
  419     delim += strlen(listdelim);
  420 
  421     atsign = strrchr(delim, '@');
  422     if (!atsign)
  423         return 0;
  424 
  425     if(strcasecmp(listaddr + len + 1, atsign + 1) != 0)
  426         return 0;
  427 
  428     if (recipextra) {
  429         len = atsign - delim;
  430         *recipextra = (char *)mymalloc(len + 1);
  431         strncpy(*recipextra, delim, len);
  432         (*recipextra)[len] = '\0';
  433     }
  434 
  435     return 1;
  436 }
  437 
  438 
  439 static void print_help(const char *prg)
  440 {
  441     printf("Usage: %s -L /path/to/list\n"
  442            "       -m /path/to/mail [-h] [-P] [-V]\n"
  443            " -h: This help\n"
  444            " -L: Full path to list directory\n"
  445            " -m: Full path to mail file\n"
  446            " -P: Don't execute mlmmj-send\n"
  447            " -V: Print version\n", prg);
  448 
  449     exit(EXIT_SUCCESS);
  450 }
  451 
  452 int main(int argc, char **argv)
  453 {
  454     int i, j, opt, noprocess = 0, moderated = 0, send = 0;
  455     enum modreason modreason;
  456     int hdrfd, footfd, rawmailfd, donemailfd, omitfd;
  457     int addrtocc, intocc = 0, findaddress = 0;
  458     int maxmailsize = 0;
  459     int notmetoo = 0;
  460     int subonlypost = 0, modonlypost = 0, modnonsubposts = 0, foundaddr = 0;
  461     char *listdir = NULL, *mailfile = NULL, *headerfilename = NULL;
  462     char *footerfilename = NULL, *donemailname = NULL;
  463     char *randomstr = NULL, *mqueuename, *omitfilename;
  464     char *mlmmjsend, *mlmmjsub, *mlmmjunsub, *mlmmjbounce;
  465     char *bindir, *subjectprefix, *discardname, *listaddr, *listdelim = NULL;
  466     char *listfqdn, *listname, *fromaddr;
  467     text *txt;
  468     char *queuefilename, *recipextra = NULL, *owner = NULL;
  469     char *maxmailsizestr;
  470     char *subject = NULL, *posteraddr = NULL;
  471     char *envstr, *efrom;
  472     struct stat st;
  473     uid_t uid;
  474     struct email_container fromemails = { 0, NULL };
  475     struct email_container toemails = { 0, NULL };
  476     struct email_container ccemails = { 0, NULL };
  477     struct email_container rpemails = { 0, NULL };
  478     struct email_container dtemails = { 0, NULL };
  479     struct strlist *access_rules = NULL;
  480     struct strlist *delheaders = NULL;
  481     struct strlist allheaders;
  482     struct strlist *listaddrs = NULL;
  483     struct mailhdr readhdrs[] = {
  484         { "From:", 0, NULL },
  485         { "To:", 0, NULL },
  486         { "Cc:", 0, NULL },
  487         { "Return-Path:", 0, NULL },
  488         { "Delivered-To:", 0, NULL },
  489         { "Subject:", 0, NULL },
  490         { NULL, 0, NULL }
  491     };
  492 
  493     CHECKFULLPATH(argv[0]);
  494 
  495     log_set_name(argv[0]);
  496 
  497     bindir = mydirname(argv[0]);
  498     mlmmjsend = concatstr(2, bindir, "/mlmmj-send");
  499     mlmmjsub = concatstr(2, bindir, "/mlmmj-sub");
  500     mlmmjunsub = concatstr(2, bindir, "/mlmmj-unsub");
  501     mlmmjbounce = concatstr(2, bindir, "/mlmmj-bounce");
  502     myfree(bindir);
  503 
  504     while ((opt = getopt(argc, argv, "hVPm:L:")) != -1) {
  505         switch(opt) {
  506         case 'L':
  507             listdir = optarg;
  508             break;
  509         case 'm':
  510             mailfile = optarg;
  511             break;
  512         case 'h':
  513             print_help(argv[0]);
  514             break;
  515         case 'P':
  516             noprocess = 1;
  517             break;
  518         case 'V':
  519             print_version(argv[0]);
  520             exit(EXIT_SUCCESS);
  521         }
  522     }
  523 
  524     if(listdir == NULL || mailfile == NULL) {
  525         fprintf(stderr, "You have to specify -L and -m\n");
  526         fprintf(stderr, "%s -h for help\n", argv[0]);
  527         exit(EXIT_FAILURE);
  528     }
  529 
  530     /* Lets make sure no random user tries to send mail to the list */
  531     if(listdir) {
  532         if(stat(listdir, &st) == 0) {
  533             uid = getuid();
  534             if(uid && uid != st.st_uid) {
  535                 log_error(LOG_ARGS,
  536                     "Have to invoke either as root "
  537                     "or as the user owning listdir");
  538                 writen(STDERR_FILENO,
  539                     "Have to invoke either as root "
  540                     "or as the user owning listdir\n", 60);
  541                 exit(EXIT_FAILURE);
  542             }
  543         } else {
  544             log_error(LOG_ARGS, "Could not stat %s", listdir);
  545             exit(EXIT_FAILURE);
  546         }
  547     }
  548 
  549         do {
  550                 myfree(donemailname);
  551                 myfree(randomstr);
  552                 randomstr = random_str();
  553                 donemailname = concatstr(3, listdir, "/queue/", randomstr);
  554 
  555                 donemailfd = open(donemailname, O_RDWR|O_CREAT|O_EXCL,
  556                         S_IRUSR|S_IWUSR);
  557 
  558         } while ((donemailfd < 0) && (errno == EEXIST));
  559 
  560     if(donemailfd < 0) {
  561         log_error(LOG_ARGS, "could not create %s", donemailname);
  562         myfree(donemailname);
  563         exit(EXIT_FAILURE);
  564     }
  565 #if 0
  566     log_error(LOG_ARGS, "donemailname = [%s]\n", donemailname);
  567 #endif
  568     if((rawmailfd = open(mailfile, O_RDONLY)) < 0) {
  569         unlink(donemailname);
  570         myfree(donemailname);
  571         log_error(LOG_ARGS, "could not open() input mail file");
  572         exit(EXIT_FAILURE);
  573     }
  574 
  575     /* hdrfd is checked in do_all_the_voodoo_here(), because the
  576      * customheaders file might not exist */
  577     headerfilename = concatstr(2, listdir, "/control/customheaders");
  578     hdrfd = open(headerfilename, O_RDONLY);
  579     myfree(headerfilename);
  580 
  581     /* footfd is checked in do_all_the_voodoo_here(), see above */
  582     footerfilename = concatstr(2, listdir, "/control/footer");
  583     footfd = open(footerfilename, O_RDONLY);
  584     myfree(footerfilename);
  585 
  586     delheaders = ctrlvalues(listdir, "delheaders");
  587     if(delheaders == NULL) {
  588         delheaders = mymalloc(sizeof(struct strlist));
  589         delheaders->count = 0;
  590         delheaders->strs = NULL;
  591     }
  592 
  593     delheaders->strs = myrealloc(delheaders->strs,
  594             (delheaders->count+2) * sizeof(char *));
  595     delheaders->strs[delheaders->count++] = mystrdup("From ");
  596     delheaders->strs[delheaders->count++] = mystrdup("Return-Path:");
  597 
  598     subjectprefix = ctrlvalue(listdir, "prefix");
  599 
  600     if(do_all_the_voodoo_here(rawmailfd, donemailfd, hdrfd, footfd,
  601                 delheaders, readhdrs,
  602                 &allheaders, subjectprefix) < 0) {
  603         log_error(LOG_ARGS, "Error in do_all_the_voodoo_here");
  604         exit(EXIT_FAILURE);
  605     }
  606 
  607     for(i = 0; i < delheaders->count; i++)
  608         myfree(delheaders->strs[i]);
  609     myfree(delheaders->strs);
  610 
  611     close(rawmailfd);
  612     close(donemailfd);
  613 
  614     if(hdrfd >= 0)
  615         close(hdrfd);
  616     if(footfd >= 0)
  617         close(footfd);
  618 
  619     /* To: addresses */
  620     for(i = 0; i < readhdrs[1].valuecount; i++) {
  621         find_email_adr(readhdrs[1].values[i], &toemails);
  622     }
  623 
  624     /* Cc: addresses */
  625     for(i = 0; i < readhdrs[2].valuecount; i++) {
  626         find_email_adr(readhdrs[2].values[i], &ccemails);
  627     }
  628 
  629     /* Delivered-To: addresses */
  630     for(i = 0; i < readhdrs[4].valuecount; i++) {
  631         find_email_adr(readhdrs[4].values[i], &dtemails);
  632     }
  633 
  634     /* address extension (the "foo" part of "user+foo@domain.tld") */
  635     if((envstr = getenv("DEFAULT")) != NULL) {
  636         /* qmail */
  637         recipextra = mystrdup(envstr);
  638     } else if((envstr = getenv("EXTENSION")) != NULL) {
  639         /* postfix */
  640         recipextra = mystrdup(envstr);
  641     } else if((envstr = getenv("LOCAL_PART_SUFFIX")) != NULL) {
  642         /* exim */
  643         listdelim = getlistdelim(listdir);
  644         if (strncmp(envstr, listdelim, strlen(listdelim)) == 0) {
  645             recipextra = mystrdup(envstr + strlen(listdelim));
  646         } else {
  647             recipextra = mystrdup(envstr);
  648         }
  649         myfree(listdelim);
  650         listdelim = NULL;
  651     } else {
  652         findaddress = 1;
  653     }
  654 
  655     addrtocc = !(statctrl(listdir, "tocc"));
  656 
  657     if (findaddress) {
  658         listdelim = getlistdelim(listdir);
  659     }
  660     if(addrtocc || findaddress) {
  661         listaddrs = ctrlvalues(listdir, "listaddress");
  662         for(i = 0; i < dtemails.emailcount; i++) {
  663             for(j = 0; j < listaddrs->count; j++) {
  664                 if(addrmatch(listaddrs->strs[j], dtemails.emaillist[i],
  665                         listdelim, &recipextra)) {
  666                     findaddress = 0;
  667                     myfree(listdelim);
  668                     listdelim = NULL;
  669                     break;
  670                 }
  671             }
  672         }
  673     }
  674     if(addrtocc || findaddress) {
  675         for(i = 0; i < toemails.emailcount; i++) {
  676             for(j = 0; j < listaddrs->count; j++) {
  677                 if(addrmatch(listaddrs->strs[j], toemails.emaillist[i],
  678                         listdelim, &recipextra)) {
  679                     intocc = 1;
  680                     break;
  681                 }
  682             }
  683         }
  684         if (!intocc) for(i = 0; i < ccemails.emailcount; i++) {
  685             for(j = 0; j < listaddrs->count; j++) {
  686                 if(addrmatch(listaddrs->strs[j], ccemails.emaillist[i],
  687                         listdelim, &recipextra)) {
  688                     intocc = 1;
  689                     break;
  690                 }
  691             }
  692         }
  693     }
  694     if (listdelim) {
  695         myfree(listdelim);
  696         listdelim = NULL;
  697     }
  698     if (listaddrs) for(i = 0; i < listaddrs->count; i++)
  699         myfree(listaddrs->strs[i]);
  700 
  701     if(recipextra && (strlen(recipextra) == 0)) {
  702         myfree(recipextra);
  703         recipextra = NULL;
  704     }
  705 
  706     /* From: addresses */
  707     for(i = 0; i < readhdrs[0].valuecount; i++) {
  708         find_email_adr(readhdrs[0].values[i], &fromemails);
  709     }
  710     /* discard malformed mail with invalid From: unless it's a bounce */
  711     if(fromemails.emailcount != 1 &&
  712             (recipextra == NULL ||
  713             strncmp(recipextra, "bounces", 7) != 0)) {
  714         for(i = 0; i < fromemails.emailcount; i++)
  715             printf("fromemails.emaillist[%d] = %s\n",
  716                     i, fromemails.emaillist[i]);
  717         discardname = concatstr(3, listdir,
  718                 "/queue/discarded/", randomstr);
  719         log_error(LOG_ARGS, "Discarding %s due to invalid From:",
  720                 mailfile);
  721         for(i = 0; i < fromemails.emailcount; i++)
  722             log_error(LOG_ARGS, "fromemails.emaillist[%d] = %s\n",
  723                     i, fromemails.emaillist[i]);
  724         rename(mailfile, discardname);
  725         unlink(donemailname);
  726         myfree(donemailname);
  727         myfree(discardname);
  728         myfree(randomstr);
  729         /* TODO: free emailstructs */
  730         exit(EXIT_SUCCESS);
  731     }
  732     /* The only time posteraddr will remain unset is when the mail is a
  733      * bounce, so the mail will be processed by listcontrol() and the
  734      * program will terminate before posteraddr is used. */
  735     if (fromemails.emailcount > 0)
  736             posteraddr = fromemails.emaillist[0];
  737 
  738     /* Return-Path: addresses */
  739     for(i = 0; i < readhdrs[3].valuecount; i++) {
  740         find_email_adr(readhdrs[3].values[i], &rpemails);
  741     }
  742 
  743     /* envelope from */
  744     if((envstr = getenv("SENDER")) != NULL) {
  745         /* qmail, postfix, exim */
  746         efrom = mystrdup(envstr);
  747     } else if(rpemails.emailcount >= 1) {
  748         /* the (first) Return-Path: header */
  749         efrom = mystrdup(rpemails.emaillist[0]);
  750     } else {
  751         efrom = mystrdup("");
  752     }
  753 
  754     /* Subject: */
  755     if (readhdrs[5].valuecount)
  756             subject = unistr_header_to_utf8(readhdrs[5].values[0]);
  757     if (!subject) subject = mystrdup("");
  758 
  759     if(recipextra) {
  760         owner = concatstr(2, listdir, "/control/owner");
  761         if(owner && strcmp(recipextra, "owner") == 0) {
  762             /* Why is this here, and not in listcontrol() ?
  763              * -- mortenp 20060409 */
  764             /* strip envelope from before resending */
  765             delheaders->count = 0;
  766             delheaders->strs = NULL;
  767             delheaders->strs = myrealloc(delheaders->strs,
  768                     2 * sizeof(char *));
  769             delheaders->strs[delheaders->count++] =
  770                 mystrdup("From ");
  771             delheaders->strs[delheaders->count++] =
  772                 mystrdup("Return-Path:");
  773             if((rawmailfd = open(mailfile, O_RDONLY)) < 0) {
  774                 log_error(LOG_ARGS, "could not open() "
  775                             "input mail file");
  776                 exit(EXIT_FAILURE);
  777             }
  778             if((donemailfd = open(donemailname,
  779                         O_WRONLY|O_TRUNC)) < 0) {
  780                 log_error(LOG_ARGS, "could not open() "
  781                             "output mail file");
  782                 exit(EXIT_FAILURE);
  783             }
  784             if(do_all_the_voodoo_here(rawmailfd, donemailfd, -1,
  785                     -1, delheaders,
  786                     NULL, &allheaders, NULL) < 0) {
  787                 log_error(LOG_ARGS, "do_all_the_voodoo_here");
  788                 exit(EXIT_FAILURE);
  789             }
  790             for(i = 0; i < delheaders->count; i++)
  791                 myfree(delheaders->strs[i]);
  792             myfree(delheaders->strs);
  793             close(rawmailfd);
  794             close(donemailfd);
  795             unlink(mailfile);
  796             log_oper(listdir, OPLOGFNAME, "mlmmj-process: sending"
  797                     " mail from %s to owner",
  798                     efrom);
  799             execlp(mlmmjsend, mlmmjsend,
  800                     "-l", "4",
  801                     "-L", listdir,
  802                     "-F", efrom,
  803                     "-s", owner,
  804                     "-a",
  805                     "-m", donemailname, (char *)NULL);
  806             log_error(LOG_ARGS, "execlp() of '%s' failed",
  807                     mlmmjsend);
  808             exit(EXIT_FAILURE);
  809         }
  810 #if 0
  811         log_error(LOG_ARGS, "listcontrol(from, %s, %s, %s, %s, %s, %s, %s)\n", listdir, toemails.emaillist[0], mlmmjsub, mlmmjunsub, mlmmjsend, mlmmjbounce, donemailname);
  812 #endif
  813         unlink(mailfile);
  814         listcontrol(&fromemails, listdir, recipextra,
  815                 mlmmjsub, mlmmjunsub, mlmmjsend, mlmmjbounce,
  816                 donemailname);
  817 
  818         return EXIT_SUCCESS;
  819     }
  820 
  821     listaddr = getlistaddr(listdir);
  822 
  823     /* checking incoming mail's size */
  824     maxmailsizestr = ctrlvalue(listdir, "maxmailsize");
  825     if(maxmailsizestr) {
  826         maxmailsize = atol(maxmailsizestr);
  827         if(stat(donemailname, &st) < 0) {
  828             log_error(LOG_ARGS, "stat(%s,..) failed", donemailname);
  829             exit(EXIT_FAILURE);
  830         }
  831 
  832         if(st.st_size > maxmailsize) {
  833 
  834             if (statctrl(listdir, "nomaxmailsizedenymails")) {
  835                 errno = 0;
  836                 log_error(LOG_ARGS, "Discarding %s due to"
  837                         " size limit (%d bytes too big)",
  838                         donemailname, (st.st_size - maxmailsize));
  839                 unlink(donemailname);
  840                 unlink(mailfile);
  841                 myfree(donemailname);
  842                 myfree(maxmailsizestr);
  843                 exit(EXIT_SUCCESS);
  844             }
  845 
  846             listdelim = getlistdelim(listdir);
  847             listname = genlistname(listaddr);
  848             listfqdn = genlistfqdn(listaddr);
  849             fromaddr = concatstr(4, listname, listdelim,
  850                     "bounces-help@", listfqdn);
  851             txt = open_text(listdir, "deny", "post",
  852                     "maxmailsize", NULL, "maxmailsize");
  853             MY_ASSERT(txt);
  854             register_unformatted(txt, "subject", subject);
  855             register_unformatted(txt, "posteraddr", posteraddr);
  856             register_unformatted(txt, "maxmailsize", maxmailsizestr);
  857             register_originalmail(txt, donemailname);
  858             queuefilename = prepstdreply(txt, listdir,
  859                     "$listowner$", posteraddr, NULL);
  860             MY_ASSERT(queuefilename);
  861             close_text(txt);
  862             myfree(listdelim);
  863             myfree(listname);
  864             myfree(listfqdn);
  865             unlink(donemailname);
  866             unlink(mailfile);
  867             myfree(donemailname);
  868             myfree(maxmailsizestr);
  869             execlp(mlmmjsend, mlmmjsend,
  870                     "-l", "1",
  871                     "-L", listdir,
  872                     "-T", posteraddr,
  873                     "-F", fromaddr,
  874                     "-m", queuefilename, (char *)NULL);
  875 
  876             log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjsend);
  877             exit(EXIT_FAILURE);
  878         }
  879     }
  880 
  881     myfree(delheaders);
  882 
  883     if(strcmp(efrom, "") == 0) { /* don't send mails with <> in From
  884                          to the list */
  885         discardname = concatstr(3, listdir,
  886                 "/queue/discarded/",
  887                 randomstr);
  888         errno = 0;
  889         log_error(LOG_ARGS, "Discarding %s due to missing envelope"
  890                 " from address", mailfile);
  891         rename(mailfile, discardname);
  892         unlink(donemailname);
  893         myfree(donemailname);
  894         myfree(discardname);
  895         myfree(randomstr);
  896         /* TODO: free emailstructs */
  897         exit(EXIT_SUCCESS);
  898     }
  899 
  900     unlink(mailfile);
  901 
  902     if(addrtocc && !intocc) {
  903         /* Don't send a mail about denial to the list, but silently
  904          * discard and exit. Also don't in case of it being turned off
  905          */
  906         if ((strcasecmp(listaddr, posteraddr) == 0) ||
  907                 statctrl(listdir, "notoccdenymails")) {
  908             log_error(LOG_ARGS, "Discarding %s because list"
  909                     " address was not in To: or Cc:,"
  910                     " and From: was the list or"
  911                     " notoccdenymails was set",
  912                     mailfile);
  913             myfree(listaddr);
  914             unlink(donemailname);
  915             myfree(donemailname);
  916             exit(EXIT_SUCCESS);
  917         }
  918         listdelim = getlistdelim(listdir);
  919         listname = genlistname(listaddr);
  920         listfqdn = genlistfqdn(listaddr);
  921         fromaddr = concatstr(4, listname, listdelim, "bounces-help@",
  922                      listfqdn);
  923         txt = open_text(listdir, "deny", "post",
  924                 "tocc", NULL, "notintocc");
  925         MY_ASSERT(txt);
  926         register_unformatted(txt, "subject", subject);
  927         register_unformatted(txt, "posteraddr", posteraddr);
  928         register_originalmail(txt, donemailname);
  929         queuefilename = prepstdreply(txt, listdir,
  930                 "$listowner$", posteraddr, NULL);
  931         MY_ASSERT(queuefilename)
  932         close_text(txt);
  933         myfree(listdelim);
  934         myfree(listname);
  935         myfree(listfqdn);
  936         unlink(donemailname);
  937         myfree(donemailname);
  938         execlp(mlmmjsend, mlmmjsend,
  939                 "-l", "1",
  940                 "-L", listdir,
  941                 "-T", posteraddr,
  942                 "-F", fromaddr,
  943                 "-m", queuefilename, (char *)NULL);
  944 
  945         log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjsend);
  946         exit(EXIT_FAILURE);
  947     }
  948 
  949     access_rules = ctrlvalues(listdir, "access");
  950     if (access_rules) {
  951         enum action accret;
  952         /* Don't send a mail about denial to the list, but silently
  953          * discard and exit. Also do this in case it's turned off */
  954         accret = do_access(access_rules, &allheaders,
  955                     posteraddr, listdir);
  956         if (accret == DENY) {
  957             if ((strcasecmp(listaddr, posteraddr) == 0) ||
  958                     statctrl(listdir, "noaccessdenymails")) {
  959                 log_error(LOG_ARGS, "Discarding %s because"
  960                     " it was denied by an access"
  961                     " rule, and From: was the list"
  962                     " address or noaccessdenymails"
  963                     " was set",
  964                     mailfile);
  965                 myfree(listaddr);
  966                 unlink(donemailname);
  967                 myfree(donemailname);
  968                 exit(EXIT_SUCCESS);
  969             }
  970             listdelim = getlistdelim(listdir);
  971             listname = genlistname(listaddr);
  972             listfqdn = genlistfqdn(listaddr);
  973             fromaddr = concatstr(4, listname, listdelim,
  974                     "bounces-help@", listfqdn);
  975             txt = open_text(listdir, "deny", "post",
  976                     "access", NULL, "access");
  977             MY_ASSERT(txt);
  978             register_unformatted(txt, "subject", subject);
  979             register_unformatted(txt, "posteraddr", posteraddr);
  980             register_originalmail(txt, donemailname);
  981             queuefilename = prepstdreply(txt, listdir,
  982                     "$listowner$", posteraddr, NULL);
  983             MY_ASSERT(queuefilename)
  984             close_text(txt);
  985             myfree(listaddr);
  986             myfree(listdelim);
  987             myfree(listname);
  988             myfree(listfqdn);
  989             unlink(donemailname);
  990             myfree(donemailname);
  991             myfree(randomstr);
  992             execlp(mlmmjsend, mlmmjsend,
  993                     "-l", "1",
  994                     "-L", listdir,
  995                     "-T", posteraddr,
  996                     "-F", fromaddr,
  997                     "-m", queuefilename, (char *)NULL);
  998 
  999             log_error(LOG_ARGS, "execlp() of '%s' failed",
 1000                     mlmmjsend);
 1001             exit(EXIT_FAILURE);
 1002         } else if (accret == MODERATE) {
 1003             moderated = 1;
 1004             modreason = ACCESS;
 1005         } else if (accret == DISCARD) {
 1006                     discardname = concatstr(3, listdir,
 1007                                 "/queue/discarded/", randomstr);
 1008             myfree(randomstr);
 1009                     if(rename(donemailname, discardname) < 0) {
 1010                 log_error(LOG_ARGS, "could not rename(%s,%s)",
 1011                         donemailname, discardname);
 1012                 myfree(donemailname);
 1013                 myfree(discardname);
 1014                 exit(EXIT_FAILURE);
 1015             }
 1016             myfree(donemailname);
 1017             myfree(discardname);
 1018                     exit(EXIT_SUCCESS);
 1019         } else if (accret == SEND) {
 1020             send = 1;
 1021         } else if (accret == ALLOW) {
 1022             /* continue processing as normal */
 1023         }
 1024     }
 1025 
 1026     subonlypost = statctrl(listdir, "subonlypost");
 1027     modonlypost = statctrl(listdir, "modonlypost");
 1028     modnonsubposts = statctrl(listdir, "modnonsubposts");
 1029     /* modnonsubposts implies subonlypost if modonlypost is not set */
 1030     if (modnonsubposts && !modonlypost) subonlypost = 1;
 1031 
 1032     if(!send && (subonlypost || modonlypost || modnonsubposts)) {
 1033         /* Don't send a mail about denial to the list, but silently
 1034          * discard and exit. */
 1035         if (strcasecmp(listaddr, posteraddr) == 0) {
 1036             log_error(LOG_ARGS, "Discarding %s because"
 1037                     " there are sender restrictions but"
 1038                     " From: was the list address",
 1039                     mailfile);
 1040             myfree(listaddr);
 1041             unlink(donemailname);
 1042             myfree(donemailname);
 1043             exit(EXIT_SUCCESS);
 1044         }
 1045         if(subonlypost) {
 1046             foundaddr = (is_subbed(listdir, posteraddr, 0) !=
 1047                     SUB_NONE);
 1048         } else if (modonlypost) {
 1049             foundaddr = is_moderator(listdir, posteraddr, NULL);
 1050         }
 1051         if(!foundaddr) {
 1052             if(modnonsubposts) {
 1053                 moderated = 1;
 1054                 if (subonlypost)
 1055                 modreason = MODNONSUBPOSTS;
 1056                 else if (modonlypost)
 1057                 modreason = MODNONMODPOSTS;
 1058             } else {
 1059                 if((subonlypost &&
 1060                     statctrl(listdir, "nosubonlydenymails")) ||
 1061                     (modonlypost &&
 1062                     statctrl(listdir, "nomodonlydenymails"))) {
 1063                 log_error(LOG_ARGS, "Discarding %s because"
 1064                     " no{sub|mod}onlydenymails was set",
 1065                     mailfile);
 1066                 myfree(listaddr);
 1067                 unlink(donemailname);
 1068                 myfree(donemailname);
 1069                 exit(EXIT_SUCCESS);
 1070                 }
 1071                 listdelim = getlistdelim(listdir);
 1072                 listname = genlistname(listaddr);
 1073                 listfqdn = genlistfqdn(listaddr);
 1074                 fromaddr = concatstr(4, listname, listdelim,
 1075                     "bounces-help@", listfqdn);
 1076                 if (subonlypost) {
 1077                 txt = open_text(listdir, "deny", "post",
 1078                     "subonlypost", NULL, "subonlypost");
 1079                 } else if (modonlypost) {
 1080                 txt = open_text(listdir, "deny", "post",
 1081                     "modonlypost", NULL, NULL);
 1082                 }
 1083                 MY_ASSERT(txt);
 1084                 register_unformatted(txt, "subject", subject);
 1085                 register_unformatted(txt, "posteraddr", posteraddr);
 1086                 register_originalmail(txt, donemailname);
 1087                 queuefilename = prepstdreply(txt, listdir,
 1088                     "$listowner$", posteraddr, NULL);
 1089                 MY_ASSERT(queuefilename)
 1090                 close_text(txt);
 1091                 myfree(listaddr);
 1092                 myfree(listdelim);
 1093                 myfree(listname);
 1094                 myfree(listfqdn);
 1095                 unlink(donemailname);
 1096                 myfree(donemailname);
 1097                 execlp(mlmmjsend, mlmmjsend,
 1098                     "-L", listdir,
 1099                     "-l", "1",
 1100                     "-T", posteraddr,
 1101                     "-F", fromaddr,
 1102                     "-m", queuefilename, (char *)NULL);
 1103 
 1104                 log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjsend);
 1105                 exit(EXIT_FAILURE);
 1106             }
 1107         }
 1108     }
 1109 
 1110     if(!send && !moderated) {
 1111         if(statctrl(listdir, "moderated")) {
 1112             moderated = 1;
 1113             modreason = MODERATED;
 1114         }
 1115     }
 1116 
 1117     notmetoo = statctrl(listdir, "notmetoo");
 1118 
 1119     if(moderated) {
 1120         mqueuename = concatstr(3, listdir, "/moderation/",
 1121                        randomstr);
 1122         myfree(randomstr);
 1123         if(rename(donemailname, mqueuename) < 0) {
 1124             log_error(LOG_ARGS, "could not rename(%s,%s)",
 1125                         donemailname, mqueuename);
 1126             myfree(donemailname);
 1127             myfree(mqueuename);
 1128             exit(EXIT_FAILURE);
 1129         }
 1130         myfree(donemailname);
 1131         if (notmetoo) {
 1132             omitfilename = concatstr(2, mqueuename, ".omit");
 1133             omitfd = open(omitfilename, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
 1134             if (omitfd < 0) {
 1135                 log_error(LOG_ARGS, "could not open %s",
 1136                                 omitfilename);
 1137                 myfree(mqueuename);
 1138                 myfree(omitfilename);
 1139                 exit(EXIT_FAILURE);
 1140             }
 1141             myfree(omitfilename);
 1142             if(writen(omitfd, posteraddr, strlen(posteraddr)) < 0) {
 1143                 log_error(LOG_ARGS,
 1144                         "could not write omit file");
 1145                 myfree(mqueuename);
 1146                 exit(EXIT_FAILURE);
 1147             }
 1148             fsync(omitfd);
 1149             close(omitfd);
 1150         }
 1151         newmoderated(listdir, mqueuename,
 1152                 mlmmjsend, efrom, subject, posteraddr,
 1153                 modreason);
 1154         return EXIT_SUCCESS;
 1155     }
 1156 
 1157     myfree(randomstr);
 1158 
 1159     if(noprocess) {
 1160         myfree(donemailname);
 1161         /* XXX: toemails and ccemails etc. have to be myfree() */
 1162         exit(EXIT_SUCCESS);
 1163     }
 1164 
 1165     if (notmetoo)
 1166         execlp(mlmmjsend, mlmmjsend,
 1167                 "-L", listdir,
 1168                 "-o", posteraddr,
 1169                 "-m", donemailname, (char *)NULL);
 1170     else
 1171         execlp(mlmmjsend, mlmmjsend,
 1172                 "-L", listdir,
 1173                 "-m", donemailname, (char *)NULL);
 1174     log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjsend);
 1175 
 1176     return EXIT_FAILURE;
 1177 }