"Fossies" - the Fresh Open Source Software Archive

Member "mlmmj-1.3.0/src/mlmmj-bounce.c" (2 Oct 2016, 10182 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-bounce.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) 2004 Morten K. Poulsen <morten at afdelingp.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 <time.h>
   33 #include <dirent.h>
   34 #include <sys/mman.h>
   35 #include <string.h>
   36 #include <ctype.h>
   37 
   38 #include "getlistaddr.h"
   39 #include "getlistdelim.h"
   40 #include "mlmmj.h"
   41 #include "strgen.h"
   42 #include "wrappers.h"
   43 #include "log_error.h"
   44 #include "subscriberfuncs.h"
   45 #include "mygetline.h"
   46 #include "prepstdreply.h"
   47 #include "memory.h"
   48 #include "find_email_adr.h"
   49 #include "gethdrline.h"
   50 
   51 
   52 void do_probe(const char *listdir, const char *mlmmjsend, const char *addr)
   53 {
   54     text *txt;
   55     file_lines_state *fls;
   56     char *myaddr, *from, *a, *queuefilename, *listaddr;
   57     char *listfqdn, *listname, *probefile, *listdelim=getlistdelim(listdir);
   58     int fd;
   59     time_t t;
   60 
   61     myaddr = mystrdup(addr);
   62 
   63     listaddr = getlistaddr(listdir);
   64     listname = genlistname(listaddr);
   65     listfqdn = genlistfqdn(listaddr);
   66 
   67     from = concatstr(6, listname, listdelim, "bounces-probe-", myaddr, "@",
   68              listfqdn);
   69 
   70     myfree(listaddr);
   71     myfree(listdelim);
   72     myfree(listfqdn);
   73     myfree(listname);
   74 
   75     a = strrchr(myaddr, '=');
   76     if (!a) {
   77         myfree(myaddr);
   78         myfree(from);
   79         log_error(LOG_ARGS, "do_probe(): malformed address");
   80         exit(EXIT_FAILURE);
   81 
   82     }
   83     *a = '@';
   84 
   85     txt = open_text(listdir, "probe", NULL, NULL, NULL, "bounce-probe");
   86     MY_ASSERT(txt);
   87     register_unformatted(txt, "bouncenumbers", "%bouncenumbers%"); /* DEPRECATED */
   88     fls = init_truncated_file_lines(addr, 0, ':');
   89     register_formatted(txt, "bouncenumbers",
   90             rewind_file_lines, get_file_line, fls);
   91     queuefilename = prepstdreply(txt, listdir, "$listowner$", myaddr, NULL);
   92     MY_ASSERT(queuefilename);
   93     close_text(txt);
   94 
   95     finish_file_lines(fls);
   96 
   97     probefile = concatstr(4, listdir, "/bounce/", addr, "-probe");
   98     MY_ASSERT(probefile);
   99     t = time(NULL);
  100     a = mymalloc(32);
  101     snprintf(a, 31, "%ld", (long int)t);
  102     a[31] = '\0';
  103     unlink(probefile);
  104     fd = open(probefile, O_WRONLY|O_TRUNC|O_CREAT, S_IRUSR|S_IWUSR);
  105     if(fd < 0)
  106         log_error(LOG_ARGS, "Could not open %s", probefile);
  107     else
  108         if(writen(fd, a, strlen(a)) < 0)
  109             log_error(LOG_ARGS, "Could not write time in probe");
  110 
  111     myfree(probefile);
  112 
  113     execlp(mlmmjsend, mlmmjsend,
  114                 "-l", "5",
  115                 "-L", listdir,
  116                 "-T", myaddr,
  117                 "-F", from,
  118                 "-m", queuefilename, (char *)NULL);
  119 
  120     log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjsend);
  121 
  122     exit(EXIT_FAILURE);
  123 }
  124 
  125 char *dsnparseaddr(const char *mailname)
  126 {
  127     int fd, indsn = 0, i;
  128     char *line, *linedup, *search, *addr = NULL;
  129     struct email_container emails = { 0, NULL };
  130 
  131     fd = open(mailname, O_RDONLY);
  132     if(fd < 0) {
  133         log_error(LOG_ARGS, "Could not open bounceindexfile %s",
  134                 mailname);
  135         return NULL;
  136     }
  137 
  138     while((line = gethdrline(fd, NULL))) {
  139         linedup = mystrdup(line);
  140         for(i = 0; line[i]; i++)
  141             linedup[i] = tolower(line[i]);
  142         search = strstr(linedup, "message/delivery-status");
  143         myfree(linedup);
  144         if(search) {
  145             indsn = 1;
  146             myfree(line);
  147             continue;
  148         }
  149         if(indsn) {
  150             /* TODO: this parsing could be greatly improved */
  151             if(strncasecmp(line, "Final-Recipient:", 16)) {
  152                 search = strstr(line, ";");
  153                 if (search) {
  154                     find_email_adr(search+1, &emails);
  155                     if(emails.emailcount > 0) {
  156                         addr = mystrdup(emails.emaillist[0]);
  157                         for(i = 0; i < emails.emailcount; i++)
  158                             myfree(emails.emaillist[i]);
  159                         myfree(emails.emaillist);
  160                     }
  161                 }
  162                 myfree(line);
  163                 break;
  164             }
  165         }
  166         myfree(line);
  167     }
  168 
  169     return addr;
  170 }
  171 
  172 static void print_help(const char *prg)
  173 {
  174     printf("Usage: %s -L /path/to/list\n"
  175            "       [-a john=doe.org | -d] [-n num | -p]\n"
  176            " -a: Address string that bounces\n"
  177            " -h: This help\n"
  178            " -L: Full path to list directory\n"
  179            " -n: Message number in the archive\n"
  180            " -d: Attempt to parse DSN to determine address\n"
  181            " -p: Send out a probe\n"
  182            " -V: Print version\n", prg);
  183 
  184     exit(EXIT_SUCCESS);
  185 }
  186 
  187 int main(int argc, char **argv)
  188 {
  189     int opt, fd, dsnbounce = 0, i = 0;
  190     char *listdir = NULL, *address = NULL, *number = NULL;
  191     char *bindir, *mlmmjsend, *savename;
  192     char *mailname = NULL, *bfilename, *a, *buf, *lowcaseaddr;
  193     size_t len;
  194     time_t t;
  195     int probe = 0;
  196     struct stat st;
  197     uid_t uid;
  198 
  199     log_set_name(argv[0]);
  200 
  201     CHECKFULLPATH(argv[0]);
  202 
  203     bindir = mydirname(argv[0]);
  204     mlmmjsend = concatstr(2, bindir, "/mlmmj-send");
  205     myfree(bindir);
  206 
  207     while ((opt = getopt(argc, argv, "hdVL:a:n:m:p")) != -1) {
  208         switch(opt) {
  209         case 'L':
  210             listdir = optarg;
  211             break;
  212         case 'a':
  213             address = optarg;
  214             break;
  215         case 'd':
  216             dsnbounce = 1;
  217             break;
  218         case 'm':
  219             mailname = optarg;
  220             break;
  221         case 'n':
  222             number = optarg;
  223             break;
  224         case 'p':
  225             probe = 1;
  226             break;
  227         case 'h':
  228             print_help(argv[0]);
  229             break;
  230         case 'V':
  231             print_version(argv[0]);
  232             exit(0);
  233         }
  234     }
  235 
  236     if(listdir == NULL || (address == NULL && dsnbounce == 0)
  237                 || (number == NULL && probe == 0)) {
  238         fprintf(stderr,
  239             "You have to specify -L, -a or -d and -n or -p\n");
  240         fprintf(stderr, "%s -h for help\n", argv[0]);
  241         exit(EXIT_FAILURE);
  242     }
  243 
  244     /* Lets make sure no random user tries to do bouncehandling */
  245     if(listdir) {
  246         if(stat(listdir, &st) == 0) {
  247             uid = getuid();
  248             if(uid && uid != st.st_uid) {
  249                 log_error(LOG_ARGS,
  250                     "Have to invoke either as root "
  251                     "or as the user owning listdir");
  252                 writen(STDERR_FILENO,
  253                     "Have to invoke either as root "
  254                     "or as the user owning listdir\n", 60);
  255                 exit(EXIT_FAILURE);
  256             }
  257         } else {
  258             log_error(LOG_ARGS, "Could not stat %s", listdir);
  259             exit(EXIT_FAILURE);
  260         }
  261     }
  262 
  263     if(dsnbounce) {
  264         address = dsnparseaddr(mailname);
  265 
  266         /* Delete the mailfile, no need for it anymore */
  267         if(mailname)
  268             unlink(mailname);
  269 
  270         if(address == NULL)
  271             exit(EXIT_SUCCESS);
  272 
  273         a = strrchr(address, '@');
  274         MY_ASSERT(a);
  275         *a = '=';
  276     }
  277 
  278     /* Make the address lowercase */
  279     lowcaseaddr = mystrdup(address);
  280     i = 0;
  281     while(lowcaseaddr[i]) {
  282         lowcaseaddr[i] = tolower(lowcaseaddr[i]);
  283         i++;
  284     }
  285     address = lowcaseaddr;
  286 
  287     if(number != NULL && probe != 0) {
  288         fprintf(stderr, "You can only specify one of -n or -p\n");
  289         fprintf(stderr, "%s -h for help\n", argv[0]);
  290         exit(EXIT_FAILURE);
  291     }
  292 
  293     if (probe) {
  294         /* send out a probe */
  295         do_probe(listdir, mlmmjsend, address);
  296         /* do_probe() will never return */
  297         exit(EXIT_FAILURE);
  298     }
  299 
  300 #if 0
  301     log_error(LOG_ARGS, "listdir = [%s] address = [%s] number = [%s]", listdir, address, number);
  302 #endif
  303 
  304     /* check if it's sub/unsub requests bouncing, and in that case
  305      * simply remove the confirmation file. Variablenames address and
  306      * number are a bit misleading in this case due to the different
  307      * construction of the sub/unsub confirmation From header.
  308      */
  309     if(strcmp(number, "confsub") == 0) {
  310         a = concatstr(3, listdir, "/subconf/", address);
  311         unlink(a);
  312         myfree(a);
  313         if(mailname)
  314             unlink(mailname);
  315         exit(EXIT_SUCCESS);
  316     }
  317     if(strcmp(number, "confunsub") == 0) {
  318         a = concatstr(3, listdir, "/unsubconf/", address);
  319         unlink(a);
  320         myfree(a);
  321         if(mailname)
  322             unlink(mailname);
  323         exit(EXIT_SUCCESS);
  324     }
  325     /* Below checks for bounce probes bouncing. If they do, simply remove
  326      * the probe file and exit successfully. Yes, I know the variables
  327      * have horrible names, but please bear with me.
  328      */
  329     if(strcmp(number, "probe") == 0) {
  330         a = concatstr(4, listdir, "/bounce/", address, "-probe");
  331         unlink(a);
  332         unlink(mailname);
  333         myfree(a);
  334         exit(EXIT_SUCCESS);
  335     }
  336 
  337     /* save the filename with '=' before replacing it with '@' */
  338     bfilename = concatstr(3, listdir, "/bounce/", address);
  339 
  340     a = strrchr(address, '=');
  341     if (!a) {
  342         if(mailname)
  343             unlink(mailname);
  344         exit(EXIT_SUCCESS);  /* ignore malformed address */
  345     }
  346     *a = '@';
  347 
  348     /* make sure it's a subscribed address */
  349     if(is_subbed(listdir, address, 0) == SUB_NONE) {
  350         log_error(LOG_ARGS, "%s is bouncing but not subscribed?",
  351                 address);
  352         if(mailname)
  353             unlink(mailname);
  354         myfree(bfilename);
  355         exit(EXIT_SUCCESS); /* Not subbed, so exit silently */
  356     }
  357 
  358     if(lstat(bfilename, &st) == 0) {
  359         if((st.st_mode & S_IFLNK) == S_IFLNK) {
  360             log_error(LOG_ARGS, "%s is a symbolic link",
  361                     bfilename);
  362             exit(EXIT_FAILURE);
  363         }
  364     }
  365 
  366     if ((fd = open(bfilename, O_WRONLY|O_APPEND|O_CREAT,
  367             S_IRUSR|S_IWUSR)) < 0) {
  368         log_error(LOG_ARGS, "Could not open '%s'", bfilename);
  369         myfree(bfilename);
  370         exit(EXIT_FAILURE);
  371     }
  372 
  373     /* TODO check that the message is not already bounced */
  374 
  375     /* XXX How long can the string representation of an integer be?
  376      * It is not a security issue (we use snprintf()), but it would be
  377      * bad mojo to cut the timestamp field  -- mortenp 20040427 */
  378 
  379     /* int + ":" + int + " # Wed Jun 30 21:49:08 1993\n" + NUL */
  380     len = 20 + 1 + 20 + 28 + 1;
  381 
  382     buf = mymalloc(len);
  383     if (!buf) exit(EXIT_FAILURE);
  384 
  385     t = time(NULL);
  386     snprintf(buf, len-26, "%s:%ld # ", number, (long int)t);
  387     ctime_r(&t, buf+strlen(buf));
  388     writen(fd, buf, strlen(buf));
  389     close(fd);
  390 
  391     if(mailname) {
  392         savename = concatstr(2, bfilename, ".lastmsg");
  393         rename(mailname, savename);
  394         myfree(savename);
  395     }
  396 
  397     myfree(bfilename);
  398     if(dsnbounce && address)
  399         myfree(address);
  400 
  401     return EXIT_SUCCESS;
  402 }