/*
 Copyright (C) 1999-2004 IC & S  dbmail@ic-s.nl

 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 2 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, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/* $Id: forward.c 2357 2006-11-06 15:13:18Z leander $
 *
 * takes care of forwarding mail to an external address */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "db.h"
#include "dbmail.h"
#include "debug.h"
#include "forward.h"
#include "list.h"

/* For each of the addresses or programs in targets,
 * send out a copy of the message pointed to by msgidnr.
 *
 * Returns 0 if all went well, -1 if there was an error.
 * FIXME: there is no detail in the error reporting,
 * so there's no way to tell *which* targets failed...
 * */
int forward(u64_t msgidnr, struct list *targets, const char *from,
	    const char *header, u64_t headersize UNUSED)
{
	struct element *target = NULL;
	char *command = NULL;
	char *escaped_from = NULL;
	char *escaped_to = NULL;
	size_t command_len = 0;
	FILE *pipe = NULL;
	int err;
	field_t sendmail;
	char timestr[50];
	time_t td;
	struct tm tm;

	time(&td);		/* get time */
	tm = *localtime(&td);	/* get components */
	strftime(timestr, sizeof(timestr), "%a %b %e %H:%M:%S %Y", &tm);

	GetConfigValue("SENDMAIL", "SMTP", sendmail);
	if (sendmail[0] == '\0')
		trace(TRACE_FATAL,
		      "%s,%s: SENDMAIL not configured (see config file). "
		      "Stop.", __FILE__, __func__);

	trace(TRACE_INFO,
	      "%s,%s: delivering to [%ld] external addresses",
	      __FILE__, __func__, list_totalnodes(targets));

	if (!msgidnr) {
		trace(TRACE_ERROR,
		      "%s,%s: got NULL as message id number",
		      __FILE__, __func__);
		return -1;
	}

	target = list_getstart(targets);

	while (target != NULL) {
		if ((((char *) target->data)[0] == '|')
		    || (((char *) target->data)[0] == '!')) {

			/* external pipe command */
			command_len = strlen((char *) (target->data)) + 1;
			command = dm_malloc(command_len * sizeof(char));
			if (!command) {
				trace(TRACE_ERROR,
				      "%s,%s: out of memory",
				      __FILE__, __func__);
				return -1;
			}
			/* skip the pipe (|) sign */
			strncpy(command, (char *) (target->data) + 1, command_len);
		} else {
			escaped_from = dm_shellesc(from);
			if (!escaped_from) {
				trace(TRACE_ERROR,
				      "%s,%s: out of memory",
				      __FILE__, __func__);
				return -1;
			}
			escaped_to = dm_shellesc((char *) (target->data));
			if (!escaped_to) {
				trace(TRACE_ERROR,
				      "%s,%s: out of memory",
				      __FILE__, __func__);
				return -1;
			}
			/* pipe to sendmail */
			command_len = strlen(sendmail) + strlen(" -f ") +
				strlen(escaped_from) + strlen (" ") +
				strlen(escaped_to) + 1;
			command = dm_malloc(command_len * sizeof(char));
			if (!command) {
				trace(TRACE_ERROR,
				      "%s,%s: out of memory",
				      __FILE__, __func__);
				return -1;
			}

			trace(TRACE_DEBUG,
			      "%s,%s: allocated memory for external "
			      "command call", __FILE__, __func__);
			snprintf(command, command_len, "%s -f %s %s", sendmail, escaped_from, escaped_to);
		}

		trace(TRACE_INFO, "%s,%s: opening pipe to command %s",
		      __FILE__, __func__, command);

		pipe = popen(command, "w");	/* opening pipe */
		dm_free(command);
		command = NULL;

		if (pipe != NULL) {
			trace(TRACE_DEBUG,
			      "%s,%s: call to popen() successfully "
			      "opened pipe [%d]", __FILE__, __func__,
			      fileno(pipe));

			if (((char *) target->data)[0] == '!') {
				/* ! tells us to prepend an mbox style header in this pipe */
				trace(TRACE_DEBUG,
				      "%s,%s: appending mbox style from "
				      "header to pipe returnpath : %s",
				      __FILE__, __func__, from);
				/* format: From<space>address<space><space>Date */
				fprintf(pipe, "From %s  %s\n", from,
					timestr);
			}

			trace(TRACE_INFO,
			      "%s,%s: sending message id number [%llu] "
			      "to forward pipe", __FILE__, __func__,
			      msgidnr);

			err = ferror(pipe);

			trace(TRACE_DEBUG, "%s,%s: ferror reports"
			      " %d, feof reports %d on pipe %d", __FILE__,
			      __func__, err, feof(pipe), fileno(pipe));

			if (!err) {
				if (msgidnr != 0) {
					trace(TRACE_DEBUG,
					      "%s,%s: sending lines from "
					      "message %llu on pipe %d",
					      __FILE__, __func__,
					      msgidnr, fileno(pipe));
					db_send_message_lines(pipe,
							      msgidnr, -2,
							      1);
				} else {
					/* only send the headers if there
					 * is no message to send. */
					trace(TRACE_DEBUG,
					      "%s,%s: writing header to "
					      "pipe", __FILE__,
					      __func__);
					fprintf(pipe, "%s", header);
				}

			}

			trace(TRACE_DEBUG, "%s,%s: closing pipes",
			      __FILE__, __func__);

			if (!ferror(pipe)) {
				pclose(pipe);
				trace(TRACE_DEBUG,
				      "%s,%s: pipe closed",
				      __FILE__, __func__);
			} else {
				trace(TRACE_ERROR,
				      "%s,%s: error on pipe",
				      __FILE__, __func__);
			}
		} else {
			trace(TRACE_ERROR,
			      "%s,%s: Could not open pipe to [%s]",
			      __FILE__, __func__, sendmail);
		}
		target = target->nextnode;
	}
	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1