# FILE: mailer.pl
# DESCRIPTION: Technical sending of e-mail messages
#-------------------------------------------------------------------------------
# DISCUS COPYRIGHT NOTICE
#
# Discus is copyright (c) 2002 by DiscusWare, LLC, all rights reserved.
# The use of Discus is governed by the Discus License Agreement which is
# available from the Discus WWW site at:
#    http://www.discusware.com/discus/license
#
# Pursuant to the Discus License Agreement, this copyright notice may not be
# removed or altered in any way.
#-------------------------------------------------------------------------------

use strict;
use vars qw($GLOBAL_OPTIONS $DCONF $PARAMS);

###
### send_email_message
###
### Sends an e-mail message to one or more recipients, according to your
### e-mail configuration.
###

sub send_email_message {
	my ($send_hashes, $text, $param_override, $debug, $override) = @_;
	return 0 if $GLOBAL_OPTIONS->{capable} == 0 && ! defined $param_override;
	my @s = ref $send_hashes eq "ARRAY" ? @{ $send_hashes } : ( $send_hashes );
	return 0 if scalar(@s) == 0;
	my $flag = ($GLOBAL_OPTIONS->{discus_taskman} && $GLOBAL_OPTIONS->{taskman_email});
	$flag = 0 if $s[0]->{taskman};
	if ($flag && ! $debug) {
		foreach my $s (@s) {
			$s->{taskman} = 1;
			my @a = ($s, $text, $param_override, $debug);			
			taskman_create_job("send_email_message", "mailer", \@a);
		}
		return 1;
	}
	my $par = defined $param_override ? $param_override : email_configuration_read();
	$par = hash_merge($par, $override, 1) if defined $override && ref $override eq 'HASH';
	my $frstr = $par->{fromname} ne "" ? join(" ", "\"$par->{fromname}\"", "<$par->{fromaddr}>") : $par->{fromaddr};
	my $fradd = $par->{fromaddr};
	$par->{input_stream} =~ s/\$FROMSTRG/$frstr/g;
	$par->{input_stream} =~ s/\$FROMADDR/$fradd/g;
	$par->{command_line} =~ s/\$FROMSTRG/$frstr/g;
	$par->{command_line} =~ s/\$FROMADDR/$fradd/g;
	return 0 if ! defined $par;
	return net_smtp_send(\@s, $text, $par, $debug) if $par->{'net_SMTP'} == 1;
	return mail_sendmail_send(\@s, $text, $par, $debug) if $par->{'net_SMTP'} == 2;
	return raw_socket_send(\@s, $text, $par, $debug) if $par->{'net_SMTP'} == 3;
	return bcc_standard_send(\@s, $text, $par, $debug) if $par->{'1message'} == 1;
	return email_crontab_send(\@s, $text, $par, $debug) if $par->{'1message'} == 2;
	return single_standard_send(\@s, $text, $par, $debug);
}

###
### net_smtp_send
###
### Sends e-mail message using the Net::SMTP module
###

sub net_smtp_send {
	my ($send_hashes, $text, $par, $debug) = @_;
	$par = email_configuration_read() if ! defined $par;
	my ($smtp, $status) = 
		eval '
			use Net::SMTP;
			my $status = 0;
			my $smtp = undef;
			if ($smtp = Net::SMTP->new($par->{"SMTP"}, Timeout => 15)) {
				$status = 1;
			}
			($smtp, $status);
		';
	if ($@) {
		error_message("SMTP configuration error", "[0] Error executing Net::SMTP (error is: $@)!  Make sure Net::SMTP is installed on your server.") if $debug;
		return 0;
	}
	if (!$status) {
		error_message("SMTP connection error", "[1] Error connecting to $par->{'SMTP'}! Be sure you've given the correct name for the SMTP server, that the SMTP server is turned on, and that the SMTP server actually has SMTP service running on it!") if $debug;
		return 0;
	}
	my $fr = "\"$par->{fromname}\"";
	$fr .= " <$par->{fromaddr}>" if $par->{fromaddr};
	$fr .= " <null\@null.null>" if ! $par->{fromaddr};
	my $dataX = "X-Mailer: Discus";
	$dataX .= " Pro" if $DCONF->{pro};
	$dataX .= " <$DCONF->{html_url}>\n";
	foreach my $r (@{ $send_hashes }) {
		my $d = $dataX;
		$d .= "Content-Type: text/html; charset=$DCONF->{mail_charset}\n" if $r->{html};
		$d .= "Content-Type: text/plain; charset=$DCONF->{mail_charset}\n" if ! $r->{html};
		if (!$smtp->mail($par->{fromaddr})) {
			error_message("SMTP send error", "[2] Error sending data to $par->{'SMTP'}: " . $smtp->message()) if $debug;
			return 0;
		}
		if (!$smtp->to($r->{to})) {
			error_message("SMTP send error", "[3] Error sending data to [$r->{to}] $par->{'SMTP'}: " . $smtp->message()) if $debug;
			return 0;
		}
		$smtp->data();
		$smtp->datasend("To: $r->{to}\n");
		$smtp->datasend("Subject: $r->{subject}\n");
		$smtp->datasend("From: $fr\n") if $fr;
		$smtp->datasend("$d");
		$smtp->datasend("MIME-Version: 1.0\n");
		if ($r->{html}) {
			$smtp->datasend("Content-type: text/html; charset=$DCONF->{mail_charset}\n");
		} else {
			$smtp->datasend("Content-type: text/plain; charset=$DCONF->{mail_charset}\n");
		}
		$smtp->datasend("\n");
		$smtp->datasend($text);
		$smtp->dataend();
		my $status_2 = $smtp->send();
		if ($status_2) {
			error_message("SMTP send error", "[4] Error sending data to $par->{'SMTP'}: " . $smtp->message()) if $debug;
			return 0;
		}
	}
	$smtp->quit();
	return 1;
}

###
### mail_sendmail_send
###
### Sends e-mail message using the Mail::Sendmail module
###

sub mail_sendmail_send {
	my ($send_hashes, $text, $par, $debug) = @_;
	$par = email_configuration_read() if ! defined $par;
	my $dataX = "X-Mailer: Discus";
	$dataX .= " Pro" if $DCONF->{pro};
	$dataX .= " <$DCONF->{html_url}>\n";
	my $fr = $par->{fromname};
	$fr .= " <$par->{fromaddr}>" if $par->{fromaddr};
	foreach my $r (@{ $send_hashes }) {
		my $mail = {
			To => $r->{to},
			From => $fr,
			'X-Mailer' => $dataX,
			Smtp => $par->{SMTP2},
			Message => $text,
			'Reply-to' => $fr,
			Subject => $r->{subject},
			'MIME-Version' => '1.0',
		};
		if ($r->{html}) {
			$mail->{'Content-type'} = 'text/html; charset=$DCONF->{mail_charset}';
		} else {
			$mail->{'Content-type'} = 'text/plain; charset=$DCONF->{mail_charset}';
		}
		my ($status, $error, $log) = eval '
			use Mail::Sendmail;
			my $x = sendmail %{$mail};
			my $err = $Mail::Sendmail::error;
			my $log = $Mail::Sendmail::log;
			($x, $err, $log);
		';
		if ($@) {
			error_message("SMTP configuration error", "[0] Error executing Mail::Sendmail (error is: $@)!  Make sure Mail::Sendmail is installed on your server.") if $debug;
			return 0;
		}
		if ($status) {
			next;
		} elsif ($debug) {
			error_message("Mail::Sendmail Error", "<p><b>Error text:</b> $error</p><p><b>Log entry:</b> $log</p>");
		}
	}
	return 1;
}

###
### email_guess_settings
###
### Guesses e-mail notification settings on a unix host
###

sub email_guess_settings {
	return undef if $^O eq "MSWin32";
	my @sp = ("/usr/bin", "/bin", "/usr/sbin", "/sbin", "/usr/local/bin", "/usr/local/sbin", "/usr/contrib/bin", "/usr/contrib/sbin", "/usr/lib", "/lib", "/etc", "/");
	foreach my $p (@sp) {
		if (-x "$p/sendmail") {
			return {
				command_line => 			"| $p/sendmail -t",
				mail_program => 			"$p/sendmail",
				commandline =>				"-t",
				toaddress =>				1,
				toaddress_prefix =>			"To:",
				fromaddress =>				1,
				fromaddress_prefix => 		"From:",
				bccaddress =>				1,
				bccaddress_prefix => 		"Bcc:",
				subjectaddress =>			1,
				subjectaddress_prefix => 	"Subject:",
				replytoaddress =>			1,
				replytoaddress_prefix => 	"Reply-to:",
				useraddress =>				2,
				input_stream =>				escape("To: \$TO\n\From: \$FROM\nSubject: \$SUBJECT\nReply-to: \$REPLYTO\n"),
				is_guess =>					1,
			};
		}
	}
	foreach my $p (@sp) {
		if (-x "$p/mail") {
			return {
				command_line => 			"| $p/mail -s '\$SUBJECT' -t '\$TO'",
				mail_program => 			"$p/mail",
				commandline =>				"-t",
				toaddress =>				0,
				fromaddress =>				2,
				fromaddress_switch => 		"-F",
				subjectaddress =>			0,
				subjectaddress_switch => 	"-s",
				is_guess =>					1,
			};
		}
	}
	return undef;
}

###
### single_standard_send
###
### Sends individual messages to recipients via normal command-line mechanism
###

sub single_standard_send {
	my ($send_hashes, $text, $par, $debug) = @_;
	my ($command, $input) = email_get_parameters($par);
	my $success = 0;
	foreach my $r (@{ $send_hashes }) {
		$r->{to} =~ s/\@\./\@/g;
		next if $r->{to} !~ m|^([\w\+\-\.]+)\@([\w\+\-\.]+)$|;
		my $command_temp = $command; $command_temp =~ s/\$TO/$r->{to}/g;
		my $input_temp = $input; $input_temp =~ s/\$TO/$r->{to}/g;
		$command_temp =~ s/\$SUBJECT/$r->{subject}/g;
		$input_temp =~ s/\$SUBJECT/$r->{subject}/g;
		$input_temp =~ s/\s+$//;
		$input_temp .= "\n";
		$input_temp .= "Content-type: text/html; charset=$DCONF->{mail_charset}\n" if $r->{html};
		$input_temp .= "Content-type: text/plain; charset=$DCONF->{mail_charset}\n" if ! $r->{html};
		$success += command_line_send($par, $command_temp, $input_temp, $text, $debug);
	}
	if (scalar(@{ $send_hashes })) {
		return int($success / scalar(@{ $send_hashes }));
	} else {
		return 0;
	}
}

###
### bcc_standard_send
###
### Sends one single message using BCC and command-line mechanism
###

sub bcc_standard_send {
	my ($send_hashes, $text, $par, $debug) = @_;
	my ($command, $input) = email_get_parameters($par);
	my @bcc = ();
	foreach my $r (@{ $send_hashes }) {
		$r->{to} =~ s/\@\./\@/g;
		next if $r->{to} !~ m|^([\w\+\-\.]+)\@([\w\+\-\.]+)$|;
		push @bcc, $r->{to};
	}
	return 0 if scalar @bcc == 0;
	my $bcc = join(",", @bcc);
	my $command_temp = $command;
	$command_temp =~ s/\$TO/$par->{chuckaddress}/g;
	$command_temp =~ s/\$BCC/$bcc/g;
	$command_temp =~ s/\$SUBJECT/$send_hashes->[0]->{subject}/g;
	my $input_temp = $input;
	$input_temp =~ s/\$TO/$par->{chuckaddress}/g;
	$input_temp =~ s/\$BCC/$bcc/g;
	$input_temp =~ s/\$SUBJECT/$send_hashes->[0]->{subject}/g;
	$input_temp .= "\n";
	return command_line_send($par, $command_temp, $input_temp, $text, $debug);	
}

###
### command_line_send
###
### Sends a message via the command line (technical guts)
###

sub command_line_send {
	my ($par, $command, $input, $text, $debug) = @_;
	my $tempfile = "";
	if ($par->{'tempfile'} == 0) {
		if (! open (MAIL, "$command")) {
			log_error("mailer.pl", "command_line_send", "Could not open command $command: $!") if ! $debug;
			error_message("Command Line Sending Error", "Could not open command $command: $!") if $debug;
			return 0;
		}
	} else {
		my $pid = $$;
		my $timecache = time;
		$pid =~ s/\D//g;
		$tempfile = "$DCONF->{message_dir}/$timecache-$pid.tmp";
		if (! open (MAIL, ">$tempfile")) {
			log_error("mailer.pl", "command_line_send", "Could not open temporary file $tempfile: $!") if ! $debug;
			error_message("Command Line Sending Error", "Could not open temporary file $tempfile: $!") if $debug;
			return 0;
		}
	}
	$input =~ s/\s+$/\n/;
	print MAIL $input;
	print MAIL "MIME-Version: 1.0\n";
	print MAIL "\n";
	print MAIL $text;
	close (MAIL);
	return 1 if $par->{'tempfile'} == 0;
	my $command_temp = $command;
	$command_temp =~ s/^\|\s*//;
	my $mail_prog = $par->{'mail_program'};
	my $cmdline = "";
	if ($command_temp !~ m|\$TEMPFILE|) {
		my $pr = quotemeta($mail_prog);
		my $stuff = "";
		if ($command_temp =~ m|$pr|) {
			$stuff = $';
			$command_temp = $mail_prog;
		} else {
			$stuff = "";
		}
		$cmdline = "$mail_prog \"$tempfile\" $stuff";
	} else {
		$cmdline = $command_temp;
		$cmdline =~ s/\$TEMPFILE/$tempfile/g;
	}
	
	if ($^O eq "MSWin32") {
		$mail_prog =~ s%/%\\%g; $cmdline =~ s%/%\\%g; $cmdline =~ s/'/"/g; $cmdline =~ s/^\s*//;
		my $cwd = "";
		if ($mail_prog =~ m|(.*)\\|) { $cwd = $1; } else { $cwd = "."; }
		return windows_process_send($mail_prog, $cmdline, $cwd, $debug);
	} else {
		if (system $cmdline) {
			unlink ($tempfile);
			log_error("mailer.pl", "command_line_send", "Send failed for [$cmdline] $!") if ! $debug;
			error_message("Send Failed", "Failed to execute command '$cmdline': $!") if $debug;
			return 0;
		}
	}
	unlink ($tempfile);
	return 1;	
}

###
### windows_process_send
###
### Sends an e-mail message with the Win32::Process module
###

sub windows_process_send {
	my ($mail_prog, $cmdline, $cwd, $debug) = @_;
	my $code = eval '
		use Win32::Process;
		use Win32;
		my $ProcessObj = undef;
		my $ExitCode = undef;
		if (Win32::Process::Create($ProcessObj, "$mail_prog", "$cmdline", 0, DETACHED_PROCESS, $cwd)) {
			$ProcessObj->Wait(INFINITE);
			$ProcessObj->GetExitCode( $ExitCode );
			$ExitCode;
		} else {
			error_message("Windows Process Creation Error", Win32::FormatMessage(Win32::GetLastError()) . "<P>Command line:<PRE>$cmdline</PRE><P>CWD:<PRE>$cwd</PRE>") if $debug;
			log_error("mailer.pl", "windows_process_send", Win32::FormatMessage(Win32::GetLastError())) if ! $debug;
			0;
		}
	';
	return $code;
}

###
### mailer_error
###
### Prints error to log or to screen depending on whether or not you are debugging
###

sub mailer_error {
	my ($debug, $subroutine, $errortext, $sock) = @_;
	if ($debug) {
		close $sock if defined $sock;
		error_message("Mail Error: $subroutine", $errortext, 0, 1);
	} else {
		log_error("mailer.pl", $subroutine, $errortext);
	}
}

###
### raw_socket_send
###
### This should work on almost every platform; it requires only the very
### standard FileHandle module
###

sub raw_socket_send {
	my ($send_hashes, $text, $par, $debug) = @_;
	$par = email_configuration_read() if ! defined $par;
	my $smtp = $par->{SMTP3};
	my $smtp_sock = undef;
	if ($smtp !~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) {
		mailer_error($debug, "raw_socket_send", "SMTP server is invalid.");
		return 0;
	} else {
		$smtp_sock = pack('C4',$1,$2,$3,$4);
	}
	my $proto = getprotobyname('tcp');
	my $port = 25;
	eval 'use Socket; use FileHandle;';
	mailer_error($debug, "raw_socket_send", "(1) Socket/Filehandle module not implemented here: $@") if $@;
	my $sock = eval ' FileHandle::new(); ';
	mailer_error($debug, "raw_socket_send", "(2) Socket/Filehandle module not implemented here: $@") if $@;
	if (! socket($sock, AF_INET(), SOCK_STREAM(), $proto)) {
		mailer_error($debug, "raw_socket_send", "Socket Failed: $!");
		return 0;
	}
	if (! connect($sock, pack('Sna4x8', AF_INET(), $port, $smtp_sock))) {
		mailer_error($debug, "raw_socket_send", "Connect Failed to $smtp port $port: $!", $sock);
		return 0;
	}
	my ($oldfh) = select($sock); $| = 1; select($oldfh);
	$_ = <$sock>;
	if (/^[45]/) {
		close $sock;
		mailer_error($debug, "raw_socket_send", "$smtp server not available: $!");
		return 0;
	}
	print $sock "helo localhost\r\n";
	$_ = <$sock>;
	if (/^[45]/) {
		close $sock;
		mailer_error($debug, "raw_socket_send", "$smtp server error: $!");
		return 0;
	}
	my $success = 0;
	my $fr_addr = defined $par->{fromaddr} ? $par->{fromaddr} : "nobody\@localhost";
	my $from = "$par->{fromname} <$fr_addr>";
	my @txt = split(/\n/, $text);
	foreach my $line (@txt) {
		if ($line =~ /^\s*$/) {
			$line = "\r\n";
		} else {
			$line = trim($line);
			if ($line =~ /^\.+$/) {
				$line = "(.)\r\n";
			} else {
				$line .= "\r\n";
			}
		}
	}
	my $dataX = "X-Mailer: Discus";
	$dataX .= " Pro" if $DCONF->{pro};
	$dataX .= " <$DCONF->{html_url}>";
	foreach my $r (@{ $send_hashes }) {
		$r->{to} =~ s/\@\./\@/g;
		next if $r->{to} !~ m|^([\w\+\-\.]+)\@([\w\+\-\.]+)$|;
		print $sock "mail from: $fr_addr\r\n";
		$_ = <$sock>;
		if (/^[45]/) {
			mailer_error($debug, "raw_socket_send", "$smtp send error (mail from $fr_addr): $!", $sock);
			next;
		}
		print $sock "rcpt to: $r->{to}\r\n";
		$_ = <$sock>;
		if (/^[45]/) {
			mailer_error($debug, "raw_socket_send", "$smtp send error (rcpt to $r->{to}) (perhaps relaying denied?): $!", $sock);
			next;
		}
		print $sock "data\r\n";
		if (/^[45]/) {
			mailer_error($debug, "raw_socket_send", "$smtp send error (would not accept data): $!", $sock);
			next;
		}
		print $sock "To: $r->{to}\r\n";
		print $sock "From: $from\r\n";
		print $sock "Subject: $r->{subject}\r\n";
		print $sock "Reply-to: $fr_addr\r\n";
		print $sock "X-Mailer: $dataX\r\n";
		print $sock "MIME-Version: 1.0\r\n";
		if ($r->{html}) {
			print $sock "Content-type: text/html; charset=$DCONF->{mail_charset}\r\n";
		} else {
			print $sock "Content-type: text/plain; charset=$DCONF->{mail_charset}\r\n";
		}
		print $sock "\r\n";
		print $sock @txt;
		print $sock "\r\n.\r\n";
		if (/^[45]/) {
			mailer_error($debug, "raw_socket_send", "Text send to $r->{to} failed: $!", $sock);
			next;
		}
		$success++;
	}
	print $sock "quit\r\n";
	$_ = <$sock>;
	close $sock;
	if (scalar(@{ $send_hashes })) {
		return int($success / scalar(@{ $send_hashes }));
	} else {
		return 0;
	}
}


###
### email_get_parameters
###
### Gets input stream and command line for sending
###

sub email_get_parameters {
	my ($par) = @_;
	my $command = $par->{'command_line'};
	my $input = $par->{'input_stream'};
	$command =~ s/\$REPLYTO/$par->{fromaddr}/g;
	$input =~ s/\$REPLYTO/$par->{fromaddr}/g;
	$input .= "X-Mailer: Discus $PARAMS->{release}.$PARAMS->{revision}";
	$input .= " Pro" if $DCONF->{pro};
	$input .= " <$DCONF->{html_url}>\n";
	return ($command, $input);
}

###
### email_crontab_send
###
### Sends a message with "cron-based" sending mechanism
###

sub email_crontab_send {
	my ($send_hashes, $text, $par, $debug) = @_;
	my $filename = join("", time, $$, $ENV{'REMOTE_ADDR'}); $filename =~ s/\D//g;
	my ($command, $input) = email_get_parameters($par);
	while (-r "$DCONF->{admin_dir}/mailqueue/$filename-1.txt") {
		$filename .= int(rand(10));
	}
	my $file = "$DCONF->{admin_dir}/mailqueue/$filename";
	my $ctr = 0;
	foreach my $r (@{ $send_hashes }) {
		$ctr++;
		$r->{to} =~ s/\@\./\@/g;
		my $command_temp = $command;
		$command_temp =~ s/\$TO/$r->{to}/g;
		$command_temp =~ s/\$SUBJECT/$r->{subject}/g;
		my $input_temp = $input;
		$input_temp =~ s/\$TO/$r->{to}/g;
		$input_temp =~ s/\$SUBJECT/$r->{subject}/g;
		$input_temp =~ s/\s+$/\n/;
		$input_temp .= "MIME-Version: 1.0\n";
		$input_temp .= "Content-type: text/html; charset=$DCONF->{mail_charset}\n" if $r->{html};
		$input_temp .= "Content-type: text/plain; charset=$DCONF->{mail_charset}\n" if ! $r->{html};
		$input_temp .= "\n";
		open (FILE, "> $file-$ctr.txt") || error_message("Mail Send Error", "Could not open mail queue for writing!");
		print FILE "$command_temp\n";
		print FILE $input_temp;
		print FILE $text;
		print FILE "<==============>|$r->{user}|", crypt($r->{pass}, "cookie"), "|<==============>\n" if ($r->{user} ne "" && $par->{'reply_email'});
		close (FILE);
		chmod (oct($DCONF->{perms0666}), "$file-$ctr.txt");
	}
	return 1;
}

###
### email_configuration_read
###
### Reads e-mail configuration from email.txt file
###

sub email_configuration_read {
	my $k = $_[0];
	my $o = defined $k ? $k : readfile("$DCONF->{admin_dir}/email.txt", "email_configuration_read", { create => 1, zero_ok => 1, no_lock => 1, no_unlock => 1 });
	return undef if ! defined $o;
	undef my $result;
	foreach my $line (@{$o}) {
		if ($line =~ m|^(\w+)=(.*)|) {
			my ($o, $t) = ($1, $2);
			$t =~ s/\r//g; $t = unescape($t) if $t =~ /^[\w\+\%]+$/;
			$result->{$o} = $t;
		}
	}
	return $result;
}

###
### email_configuration_save
###
### Writes e-mail configuration into email.txt file
###

sub email_configuration_save {
	my ($s, $infile) = @_;
	my $f = defined $infile ? $infile : readfile("$DCONF->{admin_dir}/email.txt", "email_configuration_read", { create => 1, zero_ok => 1, no_unlock => 1 });
	my $r = {};
	foreach my $l (@{ $f }) {
		if ($l =~ m|^(\w+)=(.*)|) {
			my ($o, $t) = ($1, $2);
			$t =~ s/\r//g;
			$t = unescape($t) if $t !~ /\s/;
			$r->{$o} = $t;
		}
	}
	hash_merge($r, $s, 1);
	my @o = sort map { join("", join("=", $_, escape($r->{$_})), "\n") } keys(%{ $r });
	return defined $infile ? \@o : writefile("$DCONF->{admin_dir}/email.txt", \@o, "email_configuration_save", { no_lock => 1 });
}

###
### construct_command_line_string
###
### Constructs a command line and an input stream
###

sub construct_command_line_string {
	my ($Q) = @_;
	my @z = (
		{ id => 'to',		x => '$TO' },
		{ id => 'from',		x => '$FROMSTRG' },
		{ id => 'user',		x => '$FROMADDR' },
		{ id => 'subject',	x => '$SUBJECT' },
		{ id => 'bcc',		x => '$BCC' },
		{ id => 'replyto',	x => '$FROMADDR' },
	);
	my @cl = ();
	my @is = ();
	foreach my $z (@z) {
		next if $z->{id} eq "bcc" && $Q->{'1message'} != 1;
		my $I = join("", $z->{id}, "address");
		my $L1 = $Q->{lineformat} == 1 ? join(trim(join(" ", $Q->{join("_", $I, "prefix")}, $z->{x})), "'", "'") : trim(join(" ", $Q->{join("_", $I, "prefix")}, join($z->{x}, "'", "'")));
		my $L2 = trim(join(" ", $Q->{join("_", $I, "prefix")}, $z->{x}));
		my $L3 = trim(join("", $Q->{join("_", $I, "prefix")}, $z->{x}));
		if ($Q->{join("_", $I, "prefix")} !~ /\S/ && $Q->{$I} == 0) {
			push @cl, $L3;
		} elsif ($Q->{$I} == 0) {
			push @cl, trim($L1);
		} elsif ($Q->{$I} == 1) {
			push @is, $L2;
		}
	}
	unshift @cl, $Q->{commandline} if $Q->{commandline} ne "";
	push @cl, $Q->{commandlineend} if $Q->{commandlineend} ne "";
	unshift @cl, $Q->{mail_program};
	my $cl = join(" ", '|', @cl);
	my $is = join("\n", @is); $is .= "\n";
	return ($cl, $is);
}

1;
