/* $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 #include #include #include #include #include #include #include #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; }