OSSP CVS Repository

ossp - ossp-pkg/petidomo/mailer.c
Not logged in
[Honeypot]  [Browse]  [Directory]  [Home]  [Login
[Reports]  [Search]  [Ticket]  [Timeline
  [Raw

ossp-pkg/petidomo/mailer.c
/*
   $Source: /v/ossp/cvs/ossp-pkg/petidomo/mailer.c,v $
   $Revision: 1.7 $

   Copyright (C) 2000 by CyberSolutions GmbH, Germany.

   This file is part of Petidomo.

   Petidomo is free 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 2, or (at your option)
   any later version.

   Petidomo 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.
*/

#include <stdlib.h>
#include <stdarg.h>
#include <limits.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>

#include "libtext/text.h"
#include "petidomo.h"

#ifndef ARG_NUM_MAX
#  define ARG_NUM_MAX 4096
#endif
#ifndef ARG_MAX
#  define ARG_MAX 4096
#endif

static char *
my_strcpy(char * dst, const char * src)
    {
    while((*dst++ = *src++) != '\0')
	;
    return dst-1;
    }

FILE *
OpenMailer(const char * envelope, const char * recipients[])
    {
    assert(1==0);
    return NULL;
    }

FILE *
vOpenMailer(const char * envelope, ...)
    {
    const struct PD_Config *   MasterConfig;
    va_list                    ap;
    FILE *                     fh;
    char *                     cmdline;
    char *                     p;
    const char *               q;
    const char *               options;
    unsigned int               cmdline_len;

    MasterConfig = getMasterConfig();

    /* Determine the length of the required buffer. */

    cmdline_len = strlen(MasterConfig->mta);
    cmdline_len += strlen(MasterConfig->mta_options);
    cmdline_len += strlen(envelope);
    va_start(ap, envelope);
    while ((q = va_arg(ap, const char *)) != NULL) {
	cmdline_len += strlen(q) + 1;
    }
    va_end(ap);
    cmdline = xmalloc(cmdline_len+8); /* we don't take any risks :) */

    /* Copy the mta's path and name into the buffer. */

    p = my_strcpy(cmdline, MasterConfig->mta);
    *p++ = ' ';

    /* Copy the mta's options into the array, while replacing '%s'
       with the envelope. */

    for (options = MasterConfig->mta_options; *options != '\0'; )
	{
	if (options[0] == '%' && options[1] == 's')
	    {
	    p = my_strcpy(p, envelope);
	    *p++ = ' ';
	    options += 2;
	    break;
	    }
	else
	    {
	    *p++ = *options++;
	    }
	}
    *p++ = ' ';

    /* Append the list of recipients. */

    va_start(ap, envelope);
    while ((q = va_arg(ap, const char *)) != NULL)
	{
	p = my_strcpy(p, q);
	*p++ = ' ';
	}
    p[-1] = '\0';
    va_end(ap);

    fh = popen(cmdline, "w");
    if (fh == NULL)
	syslog(LOG_ERR, "Failed opening pipe to \"%s\": %s", cmdline, strerror(errno));

    free(cmdline);
    return fh;
    }


int
CloseMailer(FILE * fh)
    {
    return pclose(fh);
    }

static int
my_strlen(const char * p)
    {
    unsigned int  i;
    for (i = 0; *p && !isspace((int)*p); p++)
	i++;
    return i;
    }

#define MYPIPE_READ fildes[0]
#define MYPIPE_WRITE fildes[1]

int
ListMail(const char * envelope, const char * listname, const struct Mail * MailStruct)
    {
    const struct PD_Config * MasterConfig = getMasterConfig();
    const struct List_Config * ListConfig = getListConfig(listname);
    char **      arguments;
    unsigned int arguments_num = 256;
    char         buffer[256];
    char *       listfile;
    char *       nextAddress;
    char *       currAddress;
    char *       p;
    unsigned int counter;
    unsigned int len;
    unsigned int address_byte;
    unsigned int max_address_byte;
    int          fildes[2];
    pid_t        child_pid;
    int          child_status;

    /* Initialize internal stuff. */

    arguments = xmalloc((arguments_num+1) * sizeof(char *));
    max_address_byte = ARG_MAX - strlen(envelope) - strlen(MasterConfig->mta) -
	strlen(MasterConfig->mta_options) - 8;

    /* Load the list of recipients. */

    listfile = loadfile(ListConfig->address_file);
    if (listfile == NULL)
	return 1;

    /* Now go into delivery loop until we're finished. */

    for(counter = 0, currAddress = listfile; *currAddress != '\0'; counter = 0)
	{

	/* Set up the call to the MTA, including options. */

	arguments[counter++] = MasterConfig->mta;
	sprintf(buffer, MasterConfig->mta_options, envelope);
	for (p = buffer, arguments[counter++] = buffer; *p != '\0'; p++)
	    {
	    if (isspace((int)*p))
		{
		*p++ = '\0';
		while(*p != '\0' && isspace((int)*p))
		    p++;
		arguments[counter++] = p;
		}
	    }
	if (strlen(arguments[counter-1]) == 0)
	    counter--;

	/* Append as many recipients as fit. */

	for (address_byte = 0; *currAddress != '\0' ; currAddress = nextAddress)
	    {
	    nextAddress = text_find_next_line(currAddress);
	    len = my_strlen(currAddress);
	    if (address_byte + len > max_address_byte)
		break;
	    if (counter > ARG_NUM_MAX)
		break;
	    currAddress[len] = '\0';
	    address_byte += len;
	    arguments[counter++] = currAddress;
	    if (counter+8 >= arguments_num)
		{
		arguments_num += 256;
		arguments = realloc(arguments, (arguments_num+1) * sizeof(char *));
		if (arguments == NULL)
		    return -1;
		}
	    }

	/* Deliver the mail. */

	arguments[counter++] = NULL;
	if (pipe(fildes) == -1)
	    {
	    syslog(LOG_ERR, "Couldn't open a pipe to my child process: %s", strerror(errno));
	    return -1;
	    }
	child_pid = fork();
	switch(child_pid)
	    {
	    case 0:
		/* Child */
		close(MYPIPE_WRITE);
		if (dup2(MYPIPE_READ, STDIN_FILENO) == -1)
		    {
		    syslog(LOG_ERR, "Child process couldn't read from pipe: %s", strerror(errno));
		    return -1;
		    }
		close(MYPIPE_READ);
		execv(MasterConfig->mta, arguments);
		syslog(LOG_ERR, "Couldn't exec(\"%s\"): %s", MasterConfig->mta, strerror(errno));
		return -1;
	    case -1:
		/* Error */
		syslog(LOG_ERR, "Couldn't fork: %s", strerror(errno));
		return -1;
	    default:
		/* everything is fine */
		close(MYPIPE_READ);
	    }
	write(MYPIPE_WRITE, MailStruct->Header, strlen(MailStruct->Header));
	write(MYPIPE_WRITE, "\n", 1);
	write(MYPIPE_WRITE, MailStruct->Body, strlen(MailStruct->Body));
	if (MailStruct->ListSignature != NULL)
	    write(MYPIPE_WRITE, MailStruct->ListSignature, strlen(MailStruct->ListSignature));
	close(MYPIPE_WRITE);
	waitpid(child_pid, &child_status, 0);
	if (!(WIFEXITED(child_status) && WEXITSTATUS(child_status) == 0))
	    {
	    syslog(LOG_ERR, "The executed mail agent return error %d, aborting.",
		   WEXITSTATUS(child_status));
	    return -1;
	    }
	}
    return 0;
    }

CVSTrac 2.0.1