petidomo/mailer.c

267 lines
7.6 KiB
C
Raw Normal View History

2000-12-13 13:19:03 +00:00
/*
2019-07-10 13:00:47 +00:00
* Copyright (c) 1995-2019 Peter Simons <simons@cryp.to>
2010-02-24 16:01:14 +00:00
* Copyright (c) 2000-2001 Cable & Wireless GmbH
* Copyright (c) 1999-2000 CyberSolutions GmbH
*
* This program 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 3 of the License, or (at your option) any later
* version.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
2000-12-13 13:19:03 +00:00
#include <config.h>
2000-12-13 13:19:03 +00:00
#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>
2000-12-13 13:19:03 +00:00
#include "libtext/text.h"
#include "petidomo.h"
2000-12-13 13:19:03 +00:00
#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)
{
2000-12-13 13:19:03 +00:00
while((*dst++ = *src++) != '\0')
;
2000-12-13 13:19:03 +00:00
return dst-1;
}
2000-12-13 13:19:03 +00:00
FILE *
OpenMailer(const char * envelope, const char * recipients[])
{
2000-12-13 13:19:03 +00:00
assert(1==0);
return NULL;
}
2000-12-13 13:19:03 +00:00
FILE *
vOpenMailer(const char * envelope, ...)
{
2000-12-13 13:19:03 +00:00
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;
2000-12-13 13:19:03 +00:00
}
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++;
}
}
2000-12-13 13:19:03 +00:00
*p++ = ' ';
/* Append the list of recipients. */
va_start(ap, envelope);
while ((q = va_arg(ap, const char *)) != NULL)
{
p = my_strcpy(p, q);
*p++ = ' ';
}
2000-12-13 13:19:03 +00:00
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));
2000-12-13 13:19:03 +00:00
free(cmdline);
return fh;
}
2000-12-13 13:19:03 +00:00
int
CloseMailer(FILE * fh)
{
2000-12-13 13:19:03 +00:00
return pclose(fh);
}
2000-12-13 13:19:03 +00:00
static int
my_strlen(const char * p)
{
2001-01-19 21:16:25 +00:00
unsigned int i;
2000-12-13 13:19:03 +00:00
for (i = 0; *p && !isspace((int)*p); p++)
i++;
2000-12-13 13:19:03 +00:00
return i;
}
2000-12-13 13:19:03 +00:00
#define MYPIPE_READ fildes[0]
#define MYPIPE_WRITE fildes[1]
int
ListMail(const char * envelope, const char * listname, const struct Mail * MailStruct)
{
2000-12-13 13:19:03 +00:00
const struct PD_Config * MasterConfig = getMasterConfig();
const struct List_Config * ListConfig = getListConfig(listname);
2001-01-19 21:16:25 +00:00
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;
2000-12-13 13:19:03 +00:00
/* 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;
2000-12-13 13:19:03 +00:00
/* Load the list of recipients. */
listfile = loadfile(ListConfig->address_file);
2000-12-13 13:19:03 +00:00
if (listfile == NULL)
return 1;
2000-12-13 13:19:03 +00:00
/* 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;
}
}
2000-12-13 13:19:03 +00:00
return 0;
}