#! /usr/pkg/bin/perl
################################################################
###
###				imput
###
### Author:  Internet Message Group <img@mew.org>
### Created: Aug 31, 1995
### Revised: Feb 15, 2010
###

BEGIN {
    use lib '/usr/pkg/lib/perl5/vendor_perl/5.38.0';
};

$Prog = 'imput';
my $VERSION_DATE = "20161010";
my $VERSION_NUMBER = "153";
$VERSION = "${Prog} version ${VERSION_DATE}(IM${VERSION_NUMBER})";
my $VERSION_INFORMATION = "${Prog} (IM ${VERSION_NUMBER}) ${VERSION_DATE}
Copyright (C) 1999 IM developing team
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
";

require 5.003;

use IM::Address;
use IM::Alias;
use IM::Config;
use IM::Folder qw(touch_folder);
use IM::GetPass;
use IM::History;
use IM::Iso2022jp;
use IM::Japanese;
use IM::Log;
use IM::Message;
use IM::MsgStore;
use IM::Nntp;
use IM::Recipient;
use IM::Smtp;
use IM::TcpTransaction;
use IM::Util;
use integer;
use strict 'refs';
use strict 'subs';
use vars qw($DebugAll $QueueStatus $Subject $Ignore_Dot $Fcc_partial
	    $News_severe_check $PreserveMessage $Queuing $Comment_Name
	    $JustQueuing $Me_too $Dcc_Address $PGP_Sign
	    $opt_verbose $Help $opt_version);

$EXPLANATION = "$VERSION
put mail/news message into networks

Usage: $Prog [OPTIONS] [MSG]
";

# table of environment variables
@EnvConfig = (
    # env. var. name	option name
    'NAME;s;;Name'                => '',
    'SIGNATURE;s;;Name'           => '',
    'SMTPSERVERS;s;;Smtp_servers' => '',
    'NNTPSERVERS;s;;Nntp_servers' => '',
    'ORGANIZATION;s;;Org'         => '',
    'HOSTALIASES;s;;hostAliases'  => '',
    'MSGIDDOMAIN;s;;MsgIdDomain'  => '',
    'FROMDOMAIN;s;;FromDomain'    => '',
    'TODOMAIN;s;;ToDomain'	  => '',

    'mhaltmsg;s;;Dist_file'	  => '',
    'mhdist;s;;Dist_flag'	  => '',
    );

@OptConfig = (
    # table of commandline options
    'version,V;b;;opt_version'
	=> "Output version information and exit",
    'Help;b;;Help'
	=> "Display this help and exit",
    'Debug;b;;DebugAll'
	=> 'Set all debug options',
    'DebugFlag;s;;DebugFlag'
	=> "Set specific debug options (separated with ',')",
    'Verbose;b;;opt_verbose'
	=> 'Set verbose mode',
    ## late evaluated options
    'Require;s;;User_require'
	=> 'User defined perl script to be required',
    'SMTPservers;s;localhost;Smtp_servers'
	=> "List of SMTP servers (separated with ',')
		Each element should be server[/remote_port][%local_port]",
    'EmgSMTPsvrs;s;;Emg_Smtp_servers'
	=> 'List of SMTP servers for Emergency Use (i.e. error reporting)',
    'TryNextOnFatal;b;;Smtp_fatal_next'
	=> 'Try next SMTP server evenif permanent failure',
    'NNTPservers;s;localhost;Nntp_servers'
	=> "List of NNTP servers (separated with ',').
		Each element should be server[/remote_port][%local_port]",
    'NNTPauthuser;s;;Nntp_authuser'
	=> 'User name for NNTP authentication',
    'ClientName;s;localhost;Client_name'
	=> 'Name as a SMTP client (used for SMTP HELO)',
    'SSHServer;s;localhost;SSH_server'
	=> 'SSH port relay server',
    'ObeyMTAdomain;b;;Obey_MTA_domain'
	=> 'Do not qualify local addresses with default domain',
    'FromDomain;s;;Default_from_domain_name'
	=> 'Default domain name for sender',
    'ToDomain;s;;Default_to_domain_name'
	=> 'Default domain name for recipients',
    'MsgIdUser;s;;Message_id_user_name'
	=> 'A user name for Message-Id generation',
    'MsgIdDomain;s;;Message_id_domain_name'
	=> 'A domain name for Message-Id generation',
    'NoMsgIdForNews;s;;NoMsgIdForNews'
	=> 'Strip Message-Id when posting to news system',
    'User;s;;User_name'
	=> "Local part of the sender's address",
    'Address;s;;Mail_Address'
	=> 'Address used in From: header; equivalent to User@FromDomain',
    'Name;s;;Sender_name'
	=> 'Commentary name for sender',
    'NameInComment;b;;Comment_Name'
    	=> 'Show commentary name in () on From: header',
    'Org;s;;Organization'
    	=> 'Name of organization for news posting',
    'Subj;s;;Subject'
    	=> 'A string for subject field',
    'NScmpl;b;;Cmpl_with_gethostbyname'
    	=> 'Use domain-part completion with nameserver',
    'ShowRcpts;b;1;Show_Rcpts_Header'
    	=> 'Allow to show recipients in header as To: if no To: in original',
    'MeToo;b;;Me_too'
    	=> 'Request DCC to me',
    'Dcc;s;;Dcc_Address'
    	=> 'Supplemental DCC address',
    'Fcc;s;;Fcc_folder'
	=> 'Folder name to save FCC',
    'Receipt;b;;Dsn_success_report'
    	=> 'Need a report of successful delivery',
    'Group;s;;Newsgroups'
	=> 'Newsgroup names to be posted in',
## if ISO2022JP
    'JPconv;b;;Iso2022jp_code_conversion'
	=> 'Convert japanese character encoding from EUC/SJIS to JIS',
    'DefCode;s;8BIT;Default_code'
	=> 'Default classification of japanese character code' .
	      "\n\t\t(EUC/SJIS/8BIT)",
    'JPheader;b;1;Iso2022jp_header_mime_conv'
	=> 'Encode japanese JIS characters to MIME style at header',
    'HdrQEncoding;b;;HdrQEncoding'
	=> 'Header encoding type: 0 is B; 1 is Q',
## endif
    'NoHdrFolding;b;;NoFolding'
	=> 'Do not fold long header lines',
    'SortHeader;s;;HeaderSeq'
	=> "Header sequence for sorting (labels separated with ',')",
    '8to7;b;;Conv_8to7'
	=> 'Convert 8bit body to 7bit by base64/quoted-printable encoding',
    '8BitLabel;s;unknown-8bit;Unknown8bit_label'
	=> 'Sub-type label for unknown 8bit body on Content-Type:',
    'Lines;i;;Lines_to_partial'	# XXX
	=> 'Line numbers for splitting into partial messages',
    'Sleep;i;10;Partial_sleep'
	=> 'Sleep interval for dispatching each split messages',
    'Log;s;putlog;Log_file'	# XXX
	=> 'File name to write delivery log',
    'Syslog;b;;'
	=> 'Use SYSLOG feature instead of writing to a file directly',
    'Report;b;1;Error_report_by_mail'
    	=> 'Report errors via mail',
    'MsgId;b;1;Generate_message_id'
	=> 'Generate Message-Id header line',
    'PidMsgId;b;;Message_id_PID'
	=> 'Generate Message-Id with Process ID',
    'UidMsgId;b;;Message_id_UID'
	=> 'Generate Message-Id with User ID instead of login name',
    'Date;b;1;Generate_date'
    	=> 'Generate Date header line',
    'NewsGMTdate;b;;NewsGMTdate'
	=> 'Generate date field in GMT for posting news',
    'UseLines;b;1;UseLines'
	=> 'Generate Lines header line',
    'AliasesFile;s;;Mail_aliases'	# XXX
	=> 'List of files for mail address aliasing',
    'Addrbook;s;;addrbooks'
	=> 'List of Addrbook files',
    'HostAliases;s;;Host_aliases'	# XXX
	=> 'List of files for domain part completion',
    'FccPartial;b;;Fcc_partial'
    	=> 'Save FCC with partial format',
    'Dead;s;dead.letter;Dead_letter'	# XXX
    	=> 'Path of file to save unsent message as a deadletter',
    'JustQueuing;b;;JustQueuing'
	=> 'Just store message into queue without attempt of delivery',
    'Queuing;b;;Queuing'
	=> 'Store message into queue on delivery failure',
    'ProcessQueue;b;;ProcessQueue'
	=> 'Process queued messages',
    'QueueStatus;b;;QueueStatus'
	=> 'Show list of queued messages',
    'Folder;s;;Draft_folder'
	=> 'Path of draft folder directory',
    'MIMEbcc;b;1;Mime_bcc'
	=> 'Use MIME (message/rfc822) style BCC',
    'TrashMark;s;#;Trashmark'
	=> 'Prefix character for draft message file renaming',
    'Preserve;b;;PreserveMessage'
	=> 'Preserve draft message as is even if dispatched successfully',
    'Message;s;;Draft_message'
	=> 'Path/name of draft message',
    'PGPsign;b;;PGP_Sign'
	=> 'Generate PGP signature for body-part',
    'MultipartAdd;s@;;Mulipart_messages'
	=> 'Path/name of message to be added as a part of multipart message',
    'FilenameAdd;b;;Filename_Add'
	=> 'Add filename field at Content-Disposition header',
    'SMTP;b;;Smtp_input_mode'
	=> 'Perform SMTP style input mode',
    'Annotate;b;;Anno_flag'
	=> 'Annotate on the parent message (MsgDB required)',
    'Dist;b;;Dist_flag'
	=> 'Redistribution mode (using Resent-*:)',
    'DistMsg;s;;Dist_file'
    	=> 'Path of message for redistribution',
    'ObeyHeader;b;;Obey_header'
	=> 'Collect recipients from message header',
    'IgnoreDot;b;;Ignore_Dot'
	=> 'Ignore DOT for message termination',
    'NewsCheck;b;;News_severe_check'
	=> 'No news posting if To, Cc header found evenif Newsgroups: exists',
    'ESMTP;b;;Esmtp_flag'
	=> 'Enforce ESMTP (always begins with EHLO)',
    'NewsPost;b;1;News_flag'
	=> 'Enable NNTP',
    'AddHeader;s@;;Add_headers'
	=> 'Header lines to be added',
);

@CmpConfig = (
    ## for compatibility with send/MH
    'mime;b;;Mime_bcc'				=> '',
    'nomime;B;;Mime_bcc'			=> '',
    'msgid;b;;Generate_message_id'		=> '',
    'nomsgid;B;;Generate_message_id'		=> '',
    'watch;b;;opt_verbose'			=> '',
    'nowatch;B;;opt_verbose'			=> '',
    'verbose;b;;opt_verbose'			=> '',
    'noverbose;B;;opt_verbose'			=> '',
    'draftmessage;s;;Draft_message'		=> '',
    'draftf;s;;Draft_folder'			=> '',
    'draftfolder;s;;Draft_folder'		=> '',
    'nodraftfolder;s;;Dummy'			=> '',
    'draftm;s;;Draft_message'			=> '',
    'draft;B;;Dummy'				=> '',
    'alias;s;;Mail_aliases'			=> '',
    'aliasesfile;s;;Mail_aliases'		=> '',
    'filter;s;;Dummy'				=> '',
    'nofilter;B;;Dummy'				=> '',
    'format;b;;Dummy'				=> '',
    'noformat;B;;Dummy'				=> '',
    'forward;b;;Dummy'				=> '',
    'noforward;B;;Dummy'			=> '',
    'push;b;;Error_report_by_mail'		=> '',
    'nopush;B;;Error_report_by_mail'		=> '',
    'width;i;;Dummy'				=> '',
    'split;i;;Partial_sleep'			=> '',
    'version;b;;opt_version'			=> '',
    'help;b;;Help'				=> '',
## if ISO2022JP
    'hencode;b;;Iso2022jp_header_mime_conv'	=> '',
    'nohencode;B;;Iso2022jp_header_mime_conv'	=> '',
## endif
    'library;s;;Dummy'				=> '',
    'server;s;;Smtp_servers'			=> '',
    'client;s;;Client_name'			=> '',
    ## temporary solution for compatibility with sendmail
    'bs;b;;Smtp_input_mode'			=> '',
    'f;s;;Dummy'				=> '',
    't;b;;Obey_header'				=> '',
    'v;b;;opt_verbose'				=> '',
    'odb;B;;Dummy'				=> '',
    'odi;B;;Dummy'				=> '',
    'oem;B;;Error_report_by_mail'		=> '',
    'oi;B;;Ignore_Dot'				=> '',
    'i;B;;Ignore_Dot'				=> '',
    'om;b;;Me_too'				=> '',
    'm;b;;Me_too'				=> '',
    'odq;b;;JustQueuing'			=> '',
    'q;b;;ProcessQueue'				=> '',
    'bp;b;;QueueStatus'				=> '',
    ## compatibility for sendmail on Sony NEWS
    'J;b;;Iso2022jp_code_conversion'		=> '',
    ## temporary solution for compatibility with inews
    'h;b;;Obey_header'				=> '',
    ## temporary solution for compatibility with ucbmail
    's;s;;Subject'				=> '',
    );

##
## Profile and option processing
##

$selector = read_cfg_selector(\@ARGV);
init_opt(\@OptConfig, \@CmpConfig);
read_env(\@EnvConfig);
read_cfg();
if ($selector ne '') {
    $error = 1 if (set_selector($selector) < 0);
}
read_opt(\@ARGV);
print("${VERSION_INFORMATION}") && exit $EXIT_SUCCESS if $opt_version;
help($EXPLANATION) && exit $EXIT_SUCCESS if $Help;

##
## Main
##

    &initialize;

    @arg_rest = @ARGV;

    $DebugFlag = 'all' if ($DebugAll);
    &debug_option($DebugFlag);

    if ($ProcessQueue || $QueueStatus) {
	&init_final;
	&process_queue(queue_path(), $ProcessQueue);
	exit $EXIT_SUCCESS;
    }

    alias_read($Mail_aliases, $addrbooks);
    hosts_read($Host_aliases);

    if ($Draft_message eq '' && $#arg_rest == 0 && $arg_rest[0] !~ /\@/ &&
        ($arg_rest[0] =~ /^\// || $arg_rest[0] =~ /^\w:\//)) {
	# absolute path expression: a draft message
	$Draft_message = $arg_rest[0];
    }
    $Obey_header = 1 if ($Draft_message);
    if (!$Obey_header && !$Smtp_input_mode) {
	foreach $arg (@arg_rest) {
	    if ($arg !~ /\@/ && ($arg =~ /^\// || $arg =~ /^\w:\//)) {
		# bad address list
		$error = 1;
		last;
#		&error_exit;
	    } else {
		# otherwise: a mail address (not a news group)
		if (&parse_rcpt(0, $arg) < 0) {
		    $error = 1;
		    last;
#		    &error_exit;
		}
		$News_flag = 0;	# XXX
	    }
	}
    } else {
	# a draft message is specified or SMTP input mode
	# XXX arguments ignored
    }

    unless ($Obey_header || $Draft_message || $Smtp_input_mode) {
	# recipients should be specified at command line
	if ($#Recipients < 0 && $Newsgroups eq '') {
	    im_info("message was not delivered.\n");
	    im_info("Recipient names must be specified.\n");
	    exit $EXIT_ERROR;
#	    &error_exit;
	}
    }

##### GET A MESSAGE #####
    if ($Draft_message || $Dist_file) {
	# read whole message from draft message file
	if ($Dist_flag && $Dist_file) {
	    &read_message(1);	# read altmsg to resend
	} else {
	    &read_message(0);	# read normal message
	}
    } elsif ($Smtp_input_mode) {
	# read message with SMTP
	&smtp_get_mail;
    } else {
	# read message from STDIN
	if (&read_header('STDIN', \@Header, 0) < 0) {
	    $error = 1;
	} else {
	    &read_body('STDIN', \@Body, 0, !$Ignore_Dot);
	}
    }
    im_notice("message accepted.\n");

##### SET SIGNAL HANDLING FUNCTIONS #####
#   $SIG{'ALRM'} = \&alarm_func;
    $SIG{'TERM'} = \&term_func;
    $SIG{'INT'} = \&int_func;

##### OPTIONAL CONFIGURATION #####
    if ($Obey_header && ($selector = &header_value(\@Header, 'Config')) ne '') {
	$selector =~ s/\s+//g;
	if ($selector ne '') {
	    $error = 1 if (set_selector($selector) < 0);
	}
	&kill_header(\@Header, 'Config', 0);
	alias_read($Mail_aliases, $addrbooks);
	hosts_read($Host_aliases);
    }

    &init_final;

    my($h);
    foreach $h (@Add_headers) {
	if ($h =~ /^([\w\-]+):\s*(.*)/s) {
	    &add_header(\@Header, 0, $1, $2);
	}
    }

##### HEADER PROCESSING #####
    if ($Obey_header && &header_value(\@Header, 'Return-Receipt-To')) {
	$Dsn_success_report = 1;
	&kill_header(\@Header, 'Return-Receipt-To', 0);
    }

    # Resent-*: checking
    if ($Newsgroups eq ''
     && (($Dist_flag && $Dist_file)
      || ($Obey_header
       && (&header_value(\@Header, 'Resent-To')
        || &header_value(\@Header, 'Resent-Cc'))))) {
	$resend_mode = 1;
	$Resend_prefix = 'Resent-';
	$News_flag = 0;
	im_notice("NNTP disabled (resend is only for mailing).\n");
    } else {
	$resend_mode = 0;
	$Resend_prefix = '';
    }

    # verify invalid headers for posting news
    if ($resend_mode == 0 && $Newsgroups ne '') {
	&add_header(\@Header, 1, 'Newsgroups', $Newsgroups);
	&kill_header(\@Header, 'Path', 0);
	&kill_header(\@Header, 'Followup-To', 0);
	&kill_header(\@Header, 'Received', 0);
	&kill_header(\@Header, 'Return-Path', 0);
	&kill_header(\@Header, 'NNTP-Posting-Host', 0);
	&kill_header(\@Header, 'Xref', 0);
	&kill_header(\@Header, 'Resent-To', 0);
	&kill_header(\@Header, 'Resent-Cc', 0);
	&kill_header(\@Header, 'Resent-From', 0);
	$News_flag = 1;
    } elsif ($News_flag
     && (&header_value(\@Header, 'Newsgroups')
      || &header_value(\@Header, 'BNewsgroups'))
     && !&header_value(\@Header, 'Path')
     && !&header_value(\@Header, 'Received')
     && !&header_value(\@Header, 'Return-Path')
     && !&header_value(\@Header, 'NNTP-Posting-Host')
     && !&header_value(\@Header, 'Xref')
     && (!$News_severe_check
       || !&header_value(\@Header, 'Apparently-To')
       && !&header_value(\@Header, 'To')
       && !&header_value(\@Header, 'Cc'))) {
#	$News_flag = 1;
#	im_notice("NNTP will performed.\n");
    } else {
	$News_flag = 0;
	im_notice("NNTP disabled (header format is not fit).\n");
    }

    if ($Dist_flag && $Dist_file) {
	&rewrite_resend_header;
	&append_dist_header;
    }

## if ISO2022JP
    # hook before convert header
    &$Hook_PreHeaderconv if ($Hook_PreHeaderconv);

    if ($Iso2022jp_header_mime_conv) {
#	if (debug{'header'}) {
#	    open(NULL, '>/dev/null');
#	    &im_debug("=== before header_iso2022jp_conv ===\n");
#	    &put_header(\*NULL, \@Header, 'smtp', 'original');
#	    &im_debug("====================================\n");
#	    close(NULL);
#	}

	if (&header_iso2022jp_conv(\@Header, $Iso2022jp_code_conversion) < 0) {
	    $error = 1;
	}
    }
## endif

    # XXX just for NetNews ?
    if ($News_flag && $Organization && !&header_value(\@Header, 'Organization'))
    {
## if ISO2022JP
	if ($Iso2022jp_code_conversion) {
#	    $c = &code_check($Organization);
#	    if ($c eq 'sjis' || $c eq 'euc' || $c eq 'sORe') { # XXX
		$Organization = &conv_iso2022jp($Organization);
#	    }
	}
	$Organization = &line_iso2022jp_mimefy($Organization)
	  if ($Iso2022jp_header_mime_conv);
## endif
	&add_header(\@Header, 0, 'Organization', $Organization);
    }
    if ($Generate_message_id
     && !&header_value(\@Header, $Resend_prefix.'Message-Id')) {
	$Cur_mid = &gen_message_id(0);
	&add_header(\@Header, 0, $Resend_prefix.'Message-Id', $Cur_mid);
    }
    if ($Generate_date && !&header_value(\@Header, $Resend_prefix.'Date')) {
	&add_header(\@Header, 0, $Resend_prefix.'Date', &gen_date(!$News_flag));
    }
    if ($Sender_name) {
	if ($Comment_Name) {
	    $Sender_line = "$Sender ($Sender_name)";
	} else {
	    $Sender_line = "$Sender_name <$Sender>";
	}
## if ISO2022JP
	if ($Iso2022jp_code_conversion) {
#	    $c = &code_check($Sender_line);
#	    if ($c eq 'sjis' || $c eq 'euc' || $c eq 'sORe') { # XXX
		$Sender_line = &conv_iso2022jp($Sender_line)
#	    }
	}
	$Sender_line = &struct_iso2022jp_mimefy($Sender_line)
	    if ($Iso2022jp_header_mime_conv);
## endif
    } else {
	$Sender_line = $Sender;
    }
    im_debug("Sender: $Sender_line\n") if (&debug('from'));
    unless ($from = &header_value(\@Header, $Resend_prefix.'From')) {
	&add_header(\@Header, 0, $Resend_prefix.'From', $Sender_line);
    } else {
	my $rc = &parse_rcpt(-1, $from);
	if ($rc < 0) {
	    $error = 1;
	} elsif ($rc != 1 || &extract_addr($from) ne $Sender) {
	    &add_header(\@Header, 1, $Resend_prefix.'Sender', $Sender_line);
#	    &add_header(\@Header, 1, 'Originator', $Sender_line)
#		if ($News_flag);
	}
    }
    if (&header_value(\@Header, 'Subject') eq '') {
	&add_header(\@Header, 1, 'Subject', $Subject);
    }

##### BODY PROCESSING #####
    unless (&header_value(\@Header, 'Mime-Version')) {
	$Body_code = code_check_body(\@Body);
	im_debug("Body code is $Body_code\n") if (&debug('code'));
	$do_conv_8to7 = 0;
	if ($Body_code eq '8BIT') {
	    $Need_mime_version_header = 1;
	    $Has_8bit_body = 1;
	    $do_conv_8to7 = 1 if ($Conv_8to7);
	}
## if ISO2022JP
	elsif ($Body_code eq 'JIS') {
	    $Need_mime_version_header = 1;
	    $Has_iso2022jp_body = 1;
	} elsif ($Body_code eq 'SJIS' || $Body_code eq 'EUC') {
	    $Need_mime_version_header = 1;
	    if ($Iso2022jp_code_conversion) {
		$Has_iso2022jp_body = 1;
		convert_iso2022jp_body(\@Body, $Body_code);
		if ($Has_Hankaku_kana) {
		    $Body_code = '8BIT';
		    $Has_8bit_body = 1;
		    $do_conv_8to7 = 1 if ($Conv_8to7);
		}
	    } else {
		$Has_8bit_body = 1;
		$do_conv_8to7 = 1 if ($Conv_8to7);
	    }
	}
	if ($do_conv_8to7) {
	    if ($Need_base64_encoded) {
		&body_base64_encode(\@Body);
		$Body_encoding = 'base64';
	    } else {
		&body_qp_encode(\@Body);
		$Body_encoding = 'quoted-printable';
	    }
	}
## endif
    }

##### HEADER REWRITING #####
#   if (debug{'header'}) {
#	open(NULL, '>/dev/null');
#	&im_debug("=== before rewrite_header ===\n");
#	&put_header(\*NULL, \@Header, 'smtp', 'original');
#	&im_debug("=============================\n");
#	close(NULL);
#   }

    if (&rewrite_header(\@Header) < 0) {
	$error = 1;
    }

#   if (debug{'header'}) {
#	open(NULL, '>/dev/null');
#	&im_debug("=== after rewrite_header ===\n");
#	&put_header(\*NULL, \@Header, 'smtp', 'original');
#	&im_debug("============================\n");
#	close(NULL);
#   }

    &error_exit if ($error);

##### GET RECIPIENTS #####
    if ($Obey_header || $Draft_message) {
	if (&rcpt_pickup(\@Header, $resend_mode, 0) < 0) {
	    &error_exit;
	}
    }

#   if (debug{'header'}) {
#	open(NULL, '>/dev/null');
#	&im_debug("=== after rcpt_pickup ===\n");
#	&put_header(\*NULL, \@Header, 'smtp', 'original');
#	&im_debug("=========================\n");
#	close(NULL);
#   }

##### VERIFY FORMAT OF THE MESSAGE #####
    if ($News_flag) {
	if (&header_value(\@Header, 'Newsgroups') eq ''
	 && &header_value(\@Header, 'BNewsgroups') eq '') {
	    im_err("Bad message format (no Newsgroups:).\n");
	    &error_exit;
	}
	if (&header_value(\@Header, 'Subject') eq '') {
	    im_err("Bad message format (no Subject:).\n");
	    &error_exit;
	}
	if ($#Body < 0) {
	    im_err("No message body.\n");
	    &error_exit;
	}
    } else {
	if ($#Recipients < 0) {
	    im_err("No recipients collected.\n");
	    &error_exit;
	}
    }

    if ($Me_too) {
	&error_exit if (&add_to_rcpt(0, $Sender) < 0);
    }
    my($d);
    foreach $d (split(',', $Dcc_Address)) {
	&error_exit if (&add_to_rcpt(0, $d) < 0);
    }

    # hook before final header processing
    &$Hook_PreFinalHeaderProc if ($Hook_PreFinalHeaderProc);

#   if (debug{'header'}) {
#	open(NULL, '>/dev/null');
#	&im_debug("=== before final header processing ===\n");
#	&put_header(\*NULL, \@Header, 'smtp', 'original');
#	&im_debug("======================================\n");
#	close(NULL);
#   }

##### FINAL HEADER PROCESSING #####
    if (use_xdispatcher()) {
	&add_header(\@Header, 1, 'X-'.$Resend_prefix.'Dispatcher', $VERSION);
    }
    &kill_header(\@Header, 'Bcc', 0);
    &kill_header(\@Header, 'Dcc', 0);
    &kill_header(\@Header, 'Fcc', 0);
    &kill_header(\@Header, 'Resent-Bcc', 0);
    &kill_header(\@Header, 'Resent-Dcc', 0);
    &kill_header(\@Header, 'Resent-Fcc', 0);
    if ($resend_mode) {
	&kill_header(\@Header, 'Resent-Sender', 1);
	&kill_header(\@Header, 'Resent-From', 1);
	&kill_header(\@Header, 'Resent-Message-Id', 1);
    } else {
	&kill_header(\@Header, 'Sender', 1);
	&kill_header(\@Header, 'From', 1);
	&kill_header(\@Header, 'Message-Id', 1);
    }
    if ($Draft_message) {
	# annotation headers
	&kill_header(\@Header, 'Replied', 0);
	&kill_header(\@Header, 'Forwarded', 0);
	&kill_header(\@Header, 'Resent', 0);
    }

    if ($Need_mime_version_header && !&header_value(\@Header, 'Mime-Version')) {
	&add_header(\@Header, 1, 'Mime-Version', '1.0');
	if ($Has_8bit_body) {
	    &add_header(\@Header, 1, 'Content-Type',
		"Text/plain; charset=$Unknown8bit_label");
## if ISO2022JP
	} elsif ($Has_iso2022jp_body) {
	    if ($Body_code eq 'SJIS' || $Body_code eq 'EUC') {
		&add_header(\@Header, 1, 'Content-Type',
		    "Text/plain; charset=iso-2022-jp"
		    ." (auto-converted from $Body_code)");
	    } else {
		&add_header(\@Header, 1, 'Content-Type',
		    'Text/plain; charset=iso-2022-jp');
	    }
## endif
	} else {
	    &add_header(\@Header, 1, 'Content-Type',
		'Text/plain; charset=us-ascii');
	}
	if ($Body_encoding) {
	    &add_header(\@Header, 1, 'Content-Transfer-Encoding',
	      $Body_encoding);
	}
    }

#   if (debug{'header'}) {
#	open(NULL, '>/dev/null');
#	&im_debug("=== after final header processing ===\n");
#	&put_header(\*NULL, \@Header, 'smtp', 'original');
#	&im_debug("=====================================\n");
#	close(NULL);
#   }

##### PGP HANDLING #####
    if ($PGP_Sign) {
	&pgp_process;
    }

##### MULTIPART HANDLING #####
    &add_multipart if (@Mulipart_messages);

##### SIZE OF MESSAGE BODY FIXED #####
    if ($UseLines && &header_value(\@Header, 'Lines') eq '') {
	if ($#Body >= 0) {
	    &add_header(\@Header, 1, 'Lines', $#Body);
	} else {
	    &add_header(\@Header, 1, 'Lines', '0');
	}
    }
    if ($Lines_to_partial > 0 && $#Body > $Lines_to_partial) {
	$partial_total = int(($#Body+$Lines_to_partial-1) / $Lines_to_partial);
    } else {
	$partial_total = 0;
    }

    &kill_empty_header(\@Header);
    &sort_header(\@Header, $HeaderSeq) if ($HeaderSeq);

##### SAVE INTO FOLDER #####
    if ($Fcc_folder) {
	&set_command_response();	# XXX
	foreach $f (split(',', $Fcc_folder)) {
	    $f = '+' . $f if ($f !~ /^\+/);
	    my $p = &save_fcc($f, 1, $partial_total);
	    next if ($p ne '');
	    im_err("folder carbon copy (into $f) failed.\n");
	    &log_action('fcc', &get_cur_server(), $f, 'failed');
	    &error_exit;
	}
    }

##### QUEUING IF NEEDED #####
    if ($JustQueuing) {
	if (&queue_message(queue_path(), \@Header, \@Body) == 0) {
	    if ($Draft_message) {
		&trash_message;
	    }
	    im_notice("message queued.\n");
	    exit $EXIT_SUCCESS;
	}
	im_err("Queuing failed.\n");
	&error_exit;
    }

##### DISPATCH THE MESSAGE #####
    $rcode = &send_message($News_flag, $partial_total);
    if ($rcode == 0) {
	if ($Smtp_input_mode) {
	    &smtp_get_mail_final(0) unless ($Error_report_by_mail);
	} elsif (&verbose) {
	    if ($Info) {
		print STDERR "\n";
		print STDERR $Info;
	    }
	    my $session_log = &get_session_log();
	    if ($session_log) {
		print STDERR "\n";
		print STDERR $session_log;
	    }
	}
	if ($Draft_message) {
	    &trash_message;
	}
	&exit_($EXIT_SUCCESS);
    } else {
	if ($rcode > 0 && $Queuing) {
	    if (&queue_message(queue_path(), \@Header, \@Body) == 0) {
		if ($Draft_message) {
		    &trash_message;
		}
		im_info("message queued.\n");
		exit $EXIT_SUCCESS;
	    }
	}
	im_err("delivery failed.\n");
	&error_exit;
    }
# end of main


##### INITIALIZATION #####
#
# initialize()
#	return value: none
#
sub initialize {

    # Constants
    $Folding_length = 72;

    # Variables
#   @Del_headers_on_mail = ('Originator');
    @Del_headers_on_news = ('To', 'Cc');
    &set_crlf("\n");

    # user's information

    if (unixp()) {
	my($pw_name, $pw_passwd, $pw_uid, $pw_gid, $pw_quota,
	   $pw_comment, $pw_gcos, $pw_dir, $pw_shell) = getpwuid($<);

	$Home = $pw_dir;

	local(@cap) = unpack('aa*', $pw_name);
	$cap[0] =~ tr/a-z/A-Z/;
	local($cap) = join('', @cap);
	if (!$Sender_name) {
	    ($Sender_name = $pw_gcos) =~ s/,.*$//;
	    $Sender_name =~ s/&/$cap/g;
	}
    }

    $Login = im_getlogin();
    $Home = $ENV{'HOME'} if ($ENV{'HOME'});

    srand(time+$$);
#   binmode(STDIN);
}

##### SIGNAL HANDLERS #####
#sub alarm_func {
##   no operation
#}

sub int_func {
    im_info("Terminated by interrupt (SIGINT).\n");
    &error_exit;
}

sub term_func {
    im_info("Terminated by interrupt (SIGTERM).\n");
    &error_exit;
}

##### FINAL INITIALIZATION #####
#
# init_final()
#	return value: none
#
sub init_final {
    # sender information
    if ($Mail_Address ne '' && $Default_from_domain_name eq '') {
	my $a = &extract_addr($Mail_Address);
	if ($a =~ /(.*)\@(.*)/s) {
	    my($u, $h) = ($1, $2);
	    $Default_from_domain_name = $h;
	    $User_name = $u unless ($User_name);
	}
    }

    $Login = $User_name if ($User_name);	# XXX
    unless ($Sender) {
	if ($Default_from_domain_name && !$Obey_MTA_domain) {
	    $Sender = "$Login\@$Default_from_domain_name";
	} else {
	    $Sender = $Login;
	}
    }

    unless ($Message_id_user_name) {
	if ($Message_id_UID) {
	    $Message_id_user_name = $<;
	} else {
	    $Message_id_user_name = $Login;
	}
    }
    unless ($Message_id_domain_name) {
	if ($Default_from_domain_name) {
	    $Message_id_domain_name = $Default_from_domain_name;
	} else {
	    $Message_id_domain_name = 'unknown-domain';
	}
    }

    @Smtp_servers = split(',', $Smtp_servers);
    @Nntp_servers = split(',', $Nntp_servers);

    &log_transaction;

    # user's require file
    if ($User_require) {
	require $User_require;
    }
}

##### SEND A MESSAGE WITH SMTP/NNTP #####
#
# send_message(news_flag, split_flag)
#	news_flag: news mode if true
#	split_flag: splitting into multiple messages with "partial" format
#			is required if true
#	return value:
#		 0: success
#		 1: recoverable error (should be retried)
#		-1: unrecoverable error
#
sub send_message {
    local($news_flag, $split) = @_;
    local($normal, $bcc, $i, $rcode);

    # hook before dispatching the message
    &$Hook_PreDispatching if ($Hook_PreDispatching);

    if ($news_flag) {
	if ($split) {
	    for ($i = 1; $i <= $split; $i++) {
		sleep($Partial_sleep) if ($i > 1);
		$rcode = &nntp_transaction(\@Nntp_servers, \@Header, \@Body,
		  $Newsgroups, $i, $split, $Nntp_authuser);
		return $rcode if ($rcode);
	    }
	} else {
	    $rcode = &nntp_transaction(\@Nntp_servers, \@Header, \@Body,
	      $Newsgroups, 0, 0, $Nntp_authuser);
	    return $rcode if ($rcode);
	}
	# XXX should be controlable? --- yes, of course!
#	&add_header(\@Header, 0, 'X-NNTP-Posting-Status',
#	    "posting successful via " . &get_cur_server");
	im_notice("posting succeeded.\n");
    }

    # header management only for SMTP message
    if (!&header_value(\@Header, 'To')
     && !&header_value(\@Header, 'Cc')
     && !&header_value(\@Header, 'Resent-To')
     && !&header_value(\@Header, 'Resent-Cc')
     && !&header_value(\@Header, 'Apparently-To')) {
	unless ($Show_Rcpts_Header) {
	    &add_header(\@Header, 0, 'To', 'undisclosed-recipients:;');
#	} else {
#	    foreach $rec (@Recipients) {
#		if ($rec =~ /<(.+)>/) {
#		    &add_header(\@Header, 0, 'To', $1);
#		}
#	    }
	}
    }

    foreach $rec (@Recipients) {
	if ($rec =~ /<.+>/) {
	    $normal = 1;
	} else {
	    $bcc = 1;
	}
    }

    if ($normal) {
	if ($split) {
	    for ($i = 1; $i <= $split; $i++) {
		sleep($Partial_sleep) if ($i > 1);
		$rcode = &smtp_transaction(\@Smtp_servers, \@Header, \@Body,
		  0, $i, $split);
		return $rcode if ($rcode);
	    }
	} else {
	    $rcode = &smtp_transaction(\@Smtp_servers, \@Header, \@Body,
	      0, 0, 0);
	    return $rcode if ($rcode);
	}
    }
    if ($bcc) {
	if ($split) {
	    for ($i = 1; $i <= $split; $i++) {
		sleep($Partial_sleep) if ($i > 1);
		$rcode = &smtp_transaction(\@Smtp_servers, \@Header, \@Body,
		  1, $i, $split);
		return $rcode if ($rcode);
	    }
	} else {
	    $rcode = &smtp_transaction(\@Smtp_servers, \@Header, \@Body,
	      1, 0, 0);
	    return $rcode if ($rcode);
	}
    }
    im_notice("delivery succeeded.\n");
    if ($Anno_flag) {
	my $ref;
	if ($Dist_flag) {
	    $ref = &header_value(\@Header, 'Message-Id');
	    &annotate('Resent', $ref) if ($ref ne '');
	} elsif (&header_value(\@Header, 'Subject') =~ /Forward:/) { # XXX
	    my $rfc822;
	    foreach (@Body) {
		if (/^--/) {
		    $ref = '';
		    $rfc822 = 0;
		} elsif (/^Message-Id:\s*(.*)/i) {
		    chomp($ref = $1);
		} elsif (/^Content-Type:\s*Message\/rfc822/i) {
		    $rfc822 = 1;
		} elsif (/^\n$/ && $ref ne '' && $rfc822) {
		    &annotate('Forwarded', $ref);
		    $ref = '';
		    $rfc822 = 0;
		}
	    }
	} else {
	    $ref = &header_value(\@Header, 'References');
	    if ($ref ne '') {
		if ($ref =~ /(<[\w\%_\/\-\.\@]+>)\s+$/) {
		    $ref = $1;
		}
	    } else {
		$ref = &header_value(\@Header, 'In-Reply-To');
		if ($ref =~ /(<[\w\%_\/\-\.\@]+>)/) {
		    $ref = $1;
		} else {
		    $ref = '';
		}
	    }
	    &annotate('Replied', $ref) if ($ref ne '');
	}
    }
    return 0;
}

##### SERVER SIDE SMTP PROCESSING (BEFORE GETTING MAIL) #####
#
# smtp_get_mail()
#	return value: none
#
sub smtp_get_mail {
    local($state) = 0;
    print STDOUT "220 Server ready ($VERSION)\r\n";
    while (<STDIN>) {
	if (/^NOOP\s/i) {
	    print STDOUT "250 OK\r\n";
	} elsif (/^QUIT\s/i) {
	    print STDOUT "221 Closing connection\r\n";
	    close(STDOUT);
	    last;
	} elsif (/^HELO\s/i) {
	    print STDOUT "250 Hello, pleased to meet you\r\n";
	    $state = 1;
	} elsif (/^MAIL FROM:(.*)/i) {
	    $Sender = &extract_addr($1);
	    if ($Default_from_domain_name ne ''
	     && !$Obey_MTA_domain	# XXX
	     && $Sender !~ /[\@%!:]/o) {
		$Sender .= "\@$Default_from_domain_name";
	    }
	    $Sender_name = '';
	    print STDOUT "250 Sender ok\r\n";
	    $state = 2;
	} elsif (/^RCPT TO:(.*)/i) {
	    if ($state != 2) {
		print STDOUT "503 Need MAIL before RCPT\r\n";
		next;
	    }
	    &error_exit if (&add_to_rcpt(0, $1) < 0);
	    print STDOUT "250 Recipient ok\r\n";
	    $state = 3;
	} elsif (/^DATA\s/i) {
	    if ($state != 3) {
		print STDOUT "503 No recipient\r\n";
		next;
	    }
	    print STDOUT "354 End with '.' on a line by itself\r\n";
	    if (&read_header('STDIN', \@Header, 1) < 0) {
		&error_exit;
	    }
	    &read_body("STDIN", \@Body, 1, 0);
	    unless ($Error_report_by_mail) {
		last;
	    } else {
		print STDOUT "250 Message accepted\r\n";
	    }
	} elsif (/^RSET\s/i) {
	    print STDOUT "503 Not supported\r\n";
	} elsif (/^HELP\s/i) {
	    print STDOUT "250 No information\r\n";
	} elsif (/^VRFY\s/i || /^EXPN\s/i) {
	    print STDOUT "503 Not supported\r\n";
	} elsif (/^ONEX\s/i) {
	    print STDOUT "250 Treated as NOOP\r\n";
	} elsif (/^VERB\s/i) {
	    print STDOUT "250 Verbose mode\r\n";
	    &set_verbose(1);
	} else {
	    print STDOUT "500 Command unrecognized\r\n";
	}
    }
}

##### SERVER SIDE SMTP PROCESSING (AFTER GETTING MAIL) #####
#
# smtp_get_mail_final(error_status)
#	error_status: status of delivery to be reported
#	return value: none
#
sub smtp_get_mail_final {
    local($error) = @_;
    return unless (fileno(STDOUT));
    unless ($error) {
	print STDOUT "250 Message accepted for delivery\n";
    }
    while (<STDIN>) {
	if (/^QUIT\s/i) {
	    print STDOUT "221 Closing connection\r\n";
	    close(STDOUT);
	    last;
	} elsif (/^HELO\s/i || /^EHLO\s/i) {
	    print STDOUT "250 Hello\r\n";
	} elsif (/^MAIL\s/i || /^RCPT\s/i || /^DATA\s/i) {
	    print STDOUT "503 Invalid sequence\r\n";
	} elsif (/^NOOP\s/i) {
	    print STDOUT "250 OK\r\n";
	} elsif (/^RSET\s/i) {
	    print STDOUT "503 Not supported\r\n";
	} elsif (/^HELP\s/i) {
	    print STDOUT "250 No information\r\n";
	} elsif (/^VRFY\s/i || /^EXPN\s/i) {
	    print STDOUT "503 Not supported\r\n";
	} elsif (/^ONEX\s/i) {
	    print STDOUT "250 Treated as NOOP\r\n";
	} elsif (/^VERB\s/i) {
	    print STDOUT "250 Verbose mode\r\n";
	    &set_verbose(1);
	} else {
	    print STDOUT "500 Command unrecognized\r\n";
	}
    }
}

##### READ MESSAGE FROM MESSAGE FILE #####
#
# read_message(dist_mode)
#	dist_mode: redistribution mode if ture
#	return value: none
#
sub read_message {
    local($dist_mode) = @_;
    local($message_file);
    local(*READ);
    if ($dist_mode) {
	$message_file = &expand_path($Dist_file);
    } else {
	my $d;
	if ($Draft_folder ne '') {
	    $d = "$Draft_folder/$Draft_message";
	} else {
	    $d = $Draft_message;
	}
	$message_file = &expand_path($d);
    }
    unless (im_open(\*READ, "<$message_file")) {
	im_err("Cannot open: $message_file\n");
	&error_exit;
    }
    if (&read_header(\*READ, \@Header, 0) < 0) {
	&error_exit;
    }
    &read_body(\*READ, \@Body, 0, 0);
    close(READ);
}

##### READ MESSAGE FROM MESSAGE FILE FOR MULTIPART ADDITIONALS #####
#
# read_mp_message(file, content)
#	file: message file name to be read
#	return value: none
#
sub read_mp_message {
    (my $file, local *content) = @_;
    local($message_file);
    local(*MP_READ);
    if ($file eq '-') {
	$message_file = '/dev/tty';	# get from STDIN
    } else {
	$message_file = &expand_path($file);
    }
    unless (im_open(\*MP_READ, "<$message_file")) {
	im_err("Cannot open: $message_file\n");
	&error_exit;
    }
    @content = ();
    while (<MP_READ>) {
	push (@content, $_);
    }
    close(MP_READ);
}

##### ENCAPSULATE MESSAGE BODY #####
#
# encapsulate_body(boundary)
#	boundary: boundary of multipart message
#	return value: none
#
sub encapsulate_body {
    local($boundary) = @_;
    local($l);
#   unshift(@Body, "\n");
    # pull down Content-* header lines into body part
    foreach $l (@Header) {
	if ($l =~ /^(Content-[\w-]+):/i) {
	    unshift(@Body, $l);
	    &kill_header(\@Header, $1, 0);
	}
    }
    foreach $l (@Body) {
	if ($l !~ /^\n?$/) {
	    unshift(@Body, "--$boundary\n");
	    last;
	}
    }
    unshift(@Body, "\n");
}

##### ADDING EXTRA MESSAGES AS MULTIPART #####
#
# add_multipart()
#	return value: none
#
sub add_multipart {
    local($part_code);
    local($mp_boundary) = &gen_message_id(0);
    $mp_boundary =~ y/<@>/-_-/;
    &encapsulate_body($mp_boundary);
    &add_header(\@Header, 1, 'Mime-Version', '1.0')
	if (!&header_value(\@Header, 'Mime-Version'));
    &add_header(\@Header, 1, 'Content-Type', "Multipart/mixed;\n"
	."\tboundary=\"$mp_boundary\"");
    foreach $mp_msg (@Mulipart_messages) {
	im_debug("adding message: $mp_msg\n") if (&debug('multipart'));
	push(@Body, "--$mp_boundary\n");
	&read_mp_message($mp_msg, \@Part);
	$part_code = code_check_body(\@Part);
	im_debug("code = $part_code\n") if (&debug('multipart'));
	# add internal header
	if ($part_code eq 'ASCII') {
	    push(@Body, "Content-Type: Text/plain; charset=us-ascii\n");
## if ISO2022JP
	} elsif ($part_code eq 'JIS') {
	    push(@Body, "Content-Type: Text/plain; charset=iso-2022-jp\n");
	} elsif ($part_code eq 'SJIS' || $part_code eq 'EUC') {
	    if ($Iso2022jp_code_conversion) {
		convert_iso2022jp_body(\@Part, $part_code);
		if ($Has_Hankaku_kana) {
			$part_code = '8BIT';
		} else {
		    push(@Body, "Content-Type: Text/plain; charset=iso-2022-jp"
		      . " (auto-converted from $part_code)\n");
		}
	    } else {
		$part_code = '8BIT';
	    }
## endif
	}
	if ($part_code eq '8BIT') {
	    local($part_encoding);
	    push(@Body, "Content-Type: Text/plain; "
	      . "charset=$Unknown8bit_label\n");
	    if ($Conv_8to7) {
		if ($Need_base64_encoded) {
		    &body_base64_encode(\@Part);
		    $part_encoding = 'base64';
		} else {
		    &body_qp_encode(\@Part);
		    $part_encoding = 'quoted-printable';
		}
		push(@Body, "Content-Transfer-Encoding: $part_encoding\n");
	    }
	}
	if ($Filename_Add) {
	    ($mp_msg_name = $mp_msg) =~ s/^.*\///;
	    push(@Body, "Content-Disposition: attachment; " .
		 "filename=$mp_msg_name\n");
	}
	push(@Body, "\n");
	push(@Body, @Part);
    }
    push(@Body, "--$mp_boundary--\n");
}

##### PGP HANDLING #####
#
# pgp_process()
#	return value: none
#
sub pgp_process {
    local($b, $flg, @Sign);
    $flg = 0;
    foreach $b (@Body) {
	if ($b !~ /^\n?$/) {
	    $flg = 1;
	    last;
	}
    }
    if ($flg == 0) {
	# no message body to be signed
	return;
    }
    local($mp_boundary) = &gen_message_id(0);
    $mp_boundary =~ y/<@>/-_-/;
    &encapsulate_body($mp_boundary);
    &add_header(\@Header, 1, 'Mime-Version', '1.0')
      if (!&header_value(\@Header, 'Mime-Version'));
    &add_header(\@Header, 1, 'Content-Type', "Multipart/signed;\n"
	."\tprotocol=\"application/pgp-signature\";\n"
	."\tmicalg=\"pgp-md5\";\n"
	."\tboundary=\"$mp_boundary\"");

    local($got_sign, $retry);
    $retry = 0;

    do {
	pipe('ReadHandle1', 'WriteHandle1');
	pipe('ReadHandle2', 'WriteHandle2');
	pipe('ReadPassPhrase', 'WritePassPhrase');
	$ENV{'PGPPASSFD'} = fileno(ReadPassPhrase);
	im_debug("FD $ENV{'PGPPASSFD'} is allocated "
	  . "for PGP PassPhrase passing\n")
	     if (&debug('pgp'));

	local($f) = fork;
	if ($f < 0) {
	    im_err("Cannot fork to exec PGP program.\n");
	    &error_exit;
	}
	if ($f > 0) {
	    # parents
	    close('ReadHandle1');
	    close('WriteHandle2');
	    close('ReadPassPhrase');
	    select('ReadHandle2'); $| = 1;
	    select('WriteHandle1'); $| = 1;
	    select('WritePassPhrase'); $| = 1;
	    select(STDOUT);
	} else {
	    # child
	    close('WriteHandle1');
	    close('ReadHandle2');
	    close('WritePassPhrase');
	    close (STDIN);
	    open(STDIN, "<&ReadHandle1");
	    close (STDOUT);
	    open(STDOUT, ">&WriteHandle2");
	    close (STDERR) unless (&debug('pgp'));
	    select('ReadHandle1'); $| = 1;
	    select('WriteHandle2'); $| = 1;
	    select('ReadPassPhrase'); $| = 1;
	    exec ('pgp', '-saf', '+batchmode');
	    exit $EXIT_SUCCESS;
	}
	$flg = 2;
	foreach $b (@Body) {
	    if ($flg > 1 && $b =~ /^--$mp_boundary\n$/) {
		$flg = 1;
		next;
	    }
	    next if ($flg > 1);
	    if ($flg > 0 && $b =~ /^\n$/) {
		$flg = 0;
		next;
	    }
	    next if ($flg > 0);
	    last if ($b =~ /^--$mp_boundary\n$/);
	    print WriteHandle1 $b;
	}
	close('WriteHandle1');

	# passphrase required by child process
	local($phrase) = &getpass_intract('PGP passphrase: ');
	print WritePassPhrase "$phrase\n";
	# get the result

	$got_sign = 0;
	while (<ReadHandle2>) {
	    $got_sign = 1;
	    push(@Sign, $_);
	}
	close(ReadHandle2);
	close(WritePassPhrase);
    } while ($got_sign == 0 && ++$retry < 3);

    push(@Body, "--$mp_boundary\n");
    push(@Body, "Content-Type: Application/Pgp-Signature\n");
    push(@Body, "Content-Transfer-Encoding: 7bit\n");
    push(@Body, "\n");

    push(@Body, @Sign);

    push(@Body, "--$mp_boundary--\n");
    unless ($got_sign) {
	im_err("Bad pass-phrase\n");
	&error_exit;
    }
}

##### SAVE MESSAGE FOR FCC #####
#
# save_fcc(folder_name, save_style, partial_total)
#	folder_name: folder name to be saved in
#	save_style:
#		0 = messages in a file
#		1 = separated messages in a directory
#	partial_total: total number of partial messages
#	return value:
#		NULL: failed
#		path_of_file: success
#
sub save_fcc {
    my($folder, $dir_style, $total) = @_;
    my($fcc_dir, $err_remove, $i, $msg, $dead);
    my($FCC);
    &set_crlf("\n");
    $total = 0 unless ($Fcc_partial);
    if ($folder eq '') {
	$folder = $Dead_letter;
	$dead = 1;
    }
    unless ($total) {
	im_debug("FCC with no spliting.\n") if (&debug('fcc'));
	($FCC, $fcc_dir, $msg, $err_remove) = &open_fcc($folder, $dir_style);
	unless (defined($FCC)) {
	    im_debug("FCC open failed.\n") if (&debug('fcc'));
	    unlink($err_remove) if ($err_remove);
	    return '';
	}
	if (&put_header($FCC, \@Header, 'internal', 'original') < 0
	 || &put_body($FCC, \@Body, 0, 0) < 0) {
	    im_err("FCC write failed ($!).\n");
	    close($FCC);
	    unlink($err_remove) if ($err_remove);
	    return '';
	}
	unless ($fcc_dir) {
	    unless (print $FCC "\n") {
		im_err("FCC write failed ($!).\n");
		close($FCC);
		return '';
	    }
	}
	if (&unixp() && !&no_sync()) {
	    if (fsync(fileno($FCC)) < 0) {
		im_err("FCC write failed ($!).\n");
		close($FCC);
		return '';
	    }
	}
	unless (close($FCC)) {
	    im_err("FCC write failed ($!).\n");
	    return '';
	}
	if ($dead) {
	    &log_action('dead-letter', &get_cur_server(), $d, 'sent');
	} else {
	    &log_action('fcc', &get_cur_server(), $msg, 'sent');
	    unless ($Cur_mid ne '' && history_open(1) < 0) {
		history_store($Cur_mid, $msg);
		history_close();
	    }
	    touch_folder($folder);
	}
	return $msg;
    }

    im_debug("FCC with spliting into $total.\n") if (&debug('fcc'));
    for ($i = 1; $i <= $total; $i++) {
	($FCC, $fcc_dir, $msg, $err_remove) = &open_fcc($folder, $dir_style);
	unless (defined($FCC)) {
	    im_debug("FCC open failed.\n") if (&debug('fcc'));
	    unlink($err_remove) if ($err_remove);
	    return '';
	}
	if (&put_mimed_partial($FCC, \@Header, \@Body, 0, $i, $total) < 0) {
	    im_err("FCC write failed ($!).\n");
	    close($FCC);
	    unlink($err_remove) if ($err_remove);
	    return '';
	}
	unless ($fcc_dir) {
	    unless (print $FCC "\n") {
		im_err("FCC write failed ($!).\n");
		close($FCC);
		unlink($err_remove) if ($err_remove);
		return '';
	    }
	}
	if (&unixp() && !&no_sync()) {
	    if (fsync(fileno($FCC)) < 0) {
		im_err("FCC write failed ($!).\n");
		close($FCC);
		unlink($err_remove) if ($err_remove);
		return '';
	    }
	}
	unless (close($FCC)) {
	    im_err("FCC write failed ($!).\n");
	    unlink($err_remove) if ($err_remove);
	    return '';
	}
	if ($dead) {
	    &log_action('dead-letter', &get_cur_server(), $d, 'sent');
	} else {
	    &log_action('fcc', &get_cur_server(), $msg, 'sent');
	    unless ($Cur_mid ne '' && history_open(1) < 0) {
		history_store($Cur_mid, $msg);
		history_close();
	    }
	    touch_folder($folder);
	}
    }
    return $msg;
}

##### MAKE THE INPUT MESSAGE TRASH #####
#
# trash_message()
#	return value: none
#
sub trash_message {
    return if ($PreserveMessage);
    my $d;
    if ($Draft_folder ne '') {
	$d = "$Draft_folder/$Draft_message";
    } else {
	$d = $Draft_message;
    }
    my $message_file = &expand_path($d);
    if ($message_file =~ /^(.*\D)(\d+)$/) {
	my($dir, $file) = ($1, $2);
	if ($Trashmark) {
	    if (-f "$dir$Trashmark$file") {
		unlink("$dir$Trashmark$file");
	    }
	    if (!rename("$dir$file", "$dir$Trashmark$file")) {
		im_err("Cannot rename: $dir$file as $dir$Trashmark$file\n");
		&error_exit;
	    }
	    im_notice("$dir$file was renamed to $dir$Trashmark$file\n");
	} else {
	    unlink("$dir$file");
	}
    }
}

##### APPEND DIST HEADER #####
#
# append_dist_header()
#	return value: none
#
sub append_dist_header {
    my $d;
    if ($Draft_folder ne '') {
	$d = "$Draft_folder/$Draft_message";
    } else {
	$d = $Draft_message;
    }
    my($message_file) = &expand_path($d);
    local(*DIST);
    unless (im_open(\*DIST, "<$message_file")) {
	im_err("Cannot open: $message_file\n");
	&error_exit;
    }
    if (&read_header(\*DIST, \@Header, 1) < 0) {
	&error_exit;
    }
    close(DIST);
}

##### MH ANNOTATION #####
#
# annotate()
#	return value: none
#
sub annotate {
    my($label, $ref) = @_;
    local $_;
    im_notice("annotating messages ($ref).\n");
    return if (history_open(0) < 0);
    my $msg = history_lookup($ref, LookUpMsg);
    history_close();
    return -1 if ($msg eq '');
    my $first = "$label: Date: " . &gen_date(1) . "\n";
    my $second = '';
    $second = "$label: To: " . join(',', @Recipients) . "\n"
	unless ($#Recipients < 0);
    $second .= "$label: Newsgroups: $Newsgroups\n"
	if ($Newsgroups ne '');
    $second .= "$label: Message-Id: $Cur_mid\n" if ($Cur_mid ne '');
    EACH: foreach (split(',', $msg)) {
	im_notice("annotating $_.\n");
	my $cur = &expand_path($_);
	my $tmp = &conf_dir . "/anno$$\_"
			. substr($cur,rindex($cur,"/")+1,-1) . ".tmp";
	# copy to temporary file
	unless (im_open(\*ORIGINAL, "<$cur")) {
	    im_notice("anno: open failed(1): $cur ($!).\n");
	    next;
	}
	unless (im_open(\*TMP, ">$tmp")) {
	    im_err("anno: creation failed: $tmp ($!).\n");
	    close(ORIGINAL);
	    return -1;
	}
	print TMP $first . $second;
	my $checked = 0;
	my $inheader = 1;
	while (<ORIGINAL>) {
	    # check first line
	    unless ($checked) {
		if ($_ eq $first) {
		    im_debug("already annotated.\n")
		      if (&debug('anno'));
		    # already annotated
		    close(ORIGINAL);
		    close(TMP);
		    unlink($tmp);
		    next EACH;
		}
		$checked = 1;
	    }
	    $inheader = 0 if ($inheader && /^\r?\n$/);
	    if ($inheader && /^Message-Id:\s*(<.*>)/i) {
		if ($ref ne $1) {
		    im_debug("message-id mismatch.\n")
		      if (&debug('anno'));
		    # Message-ID mismatch
		    close(ORIGINAL);
		    close(TMP);
		    unlink($tmp);
		    next EACH;
		}
	    }
	    unless (print TMP $_) {
		im_err("anno: write failed: $tmp ($!).\n");
		close(ORIGINAL);
		close(TMP);
		unlink($tmp);
		return -1;
	    }
	}
	close(ORIGINAL);
	unless (close(TMP)) {
	    im_err("anno: write failed: $tmp ($!).\n");
	    unlink($tmp);
	    return -1;
	}
	# copy back to original file (in case of links)
	unless (im_open(\*TMP, "<$tmp")) {
	    im_err("anno: open failed(2): $tmp ($!).\n");
	    unlink($tmp);
	    return -1;
	}
	unless (im_open(\*ORIGINAL, "+<$cur")) {
	    im_err("anno: open failed(3): $cur ($!).\n");
	    close(TMP);
	    unlink($tmp);
	    return -1;
	}
	my $size = -s ORIGINAL;
	seek(ORIGINAL, 0, 2);
	unless (print ORIGINAL $first . $second) {
	    im_err("anno: can't expand file size: $cur ($!).\n");
	    truncate(ORIGINAL, $size);
	    close(ORIGINAL);
	    close(TMP);
	    unlink($tmp);
	    return -1;
	}
#	seek(ORIGINAL, 0, 0);
	unless (close(ORIGINAL)) {
	    im_err("anno: can't expand file size: $cur ($!).\n");
	    close(TMP);
	    unlink($tmp);
	    return -1;
	}
	unless (im_open(\*ORIGINAL, "+<$cur")) {
	    im_err("anno: open failed(4): $cur ($!).\n");
	    close(TMP);
	    unlink($tmp);
	    return -1;
	}
	while (<TMP>) {
	    unless (print ORIGINAL $_) {
		close(TMP);
		close(ORIGINAL);
		im_err("anno: $cur may be broken ($!). recover from $tmp!\n");
		return -1;
	    }
	}
	unless (close(ORIGINAL)) {
	    close(TMP);
	    im_err("anno: $cur may be broken ($!). recover from $tmp!\n");
	    return -1;
	}
	close(TMP);
	unlink($tmp);
    }
    return 0;
}


##### PROCESS QUEUED MESSAGES #####
#
# process_queue(dir, deliver)
#	dir: queue directory
#	deliver: try delivery
#	reutrn value: none
#
sub process_queue {
    my($queue_dir, $deliver) = @_;
    my($q, $found);
    unless ($deliver) {
	require IM::EncDec && import IM::EncDec;
    }
    unless (-d $queue_dir) {
	im_warn("no queue directory\n");
	return;
    }
    unless (opendir(QUEUEDIR, $queue_dir)) {
	im_warn("can't read $queue_dir\n");
	return;
    }
    foreach $q (sort {$a <=> $b} readdir(QUEUEDIR)) {
	next unless ($q =~ /^\d+$/);
#	$QUEUE = 'QUEUE';
	rename("$queue_dir/$q", "$queue_dir/$q.wrk");
	unless (im_open(\*QUEUE, "<$queue_dir/$q.wrk")) {
	    im_err("can't open $queue_dir/$q.wrk\n");
	    rename("$queue_dir/$q.wrk", "$queue_dir/$q");
	    return;
	}
	im_notice("processing $queue_dir/$q.wrk...\n");
	while (<QUEUE>) {
	    chomp;
	    last if (/^$/);
	    im_debug("ENV>$_\n") if (&debug('queue'));
	    if (/^AF:(.*)/)  { $Anno_flag = $1; next; }
	    if (/^NF:(.*)/)  { $News_flag = $1; next; }
	    if (/^PS:(.*)/)  { $Partial_sleep = $1; next; }
	    if (/^SRH:(.*)/) { $Show_Rcpts_Header = $1; next; }
	    if (/^SFN:(.*)/) { $Smtp_fatal_next = $1; next; }
	    if (/^DSR:(.*)/) { $Dsn_success_report = $1; next; }
	    if (/^MID:(.*)/) { $Cur_mid = $1; next; }
	    if (/^CFG:(.*)/) { $Config_opt = $1; next; }
	    if (/^PT:(.*)/)  { $partial_total = $1; next; }
	    if (/^S:(.*)/)   { $Sender = $1; next; }
	    if (/^SSV:(.*)/) { @Smtp_servers = split(',', $1); next; }
	    if (/^NSV:(.*)/) { @Nntp_servers = split(',', $1); next; }
	    if (/^NAU:(.*)/) { $Nntp_authuser = $1; next; }
	    if (/^SSH:(.*)/) { $SSH_server = $1; next; }
	    if (/^R:(.*)/)   { @Recipients = split(',', $1); next; }
	    if (/^RQ:(.*)/)  { $User_require = $1; next; }
	    im_warn("unknown environment: $_\n");
	}

	im_debug("reading message\n") if (&debug('queue'));
	&read_header(\*QUEUE, \@Header, 0);
	&read_body(\*QUEUE, \@Body, 0, 0) if ($deliver);
	close(QUEUE);

	if ($deliver) {
	    im_debug("sending message\n") if (&debug('queue'));
	    $rcode = &send_message($News_flag, $partial_total);
	    if ($rcode == 0) {
		unlink("$queue_dir/$q.wrk");
		im_info("$queue_dir/$q: sent\n");
	    } elsif ($rcode > 0) {
		rename("$queue_dir/$q.wrk", "$queue_dir/$q");
		im_info("$queue_dir/$q: preserved\n");
	    } else {
		unlink("$queue_dir/$q.wrk");
		im_warn("$queue_dir/$q: delivery failed\n");
		&error_report;
	    }
	} else {
	    my($r, $t);
	    rename("$queue_dir/$q.wrk", "$queue_dir/$q");
	    print "Message queued in $queue_dir/$q";
	    if ($Config_opt ne '') {
		print " (Config: $Config_opt)\n";
	    } else {
		print "\n";
	    }
	    if ($t = &header_value(\@Header, 'Message-ID')) {
		print "    Message-ID: $t\n";
	    }
	    if ($t = &header_value(\@Header, 'Date')) {
		print "    Date: $t\n";
	    }
	    if (($t = &header_value(\@Header, 'Subject')) ne '') {
## if ISO2022JP
		$t =~ s/\?=\s*=\?/\?==?/;
		$t = &mime_decode_string($t);
		$t =~ s/\n\s*//;
## endif
		print "    Subject: $t\n";
	    }
	    if ($News_flag) {
	        my $ng = &header_value(\@Header, 'Newsgroups');
	        $ng = &header_value(\@Header, 'BNewsgroups')
		    if ($ng eq '');
		print "    Will be posted in $ng\n";
	    }
	    print "    Recipients:\n";
	    foreach $r (@Recipients) {
		print "\t$r\n";
	    }
	}

	@Header = ();
	@Body = ();
	$found = 1;
    }
    closedir(QUEUEDIR);
    unless ($found) {
	im_notice("no messages found in queue\n");
    }
    return;
}

##### QUEUE THE MESSAGE #####
#
# queue_message(dir)
#	dir: queue directory
#	reutrn value:
#		-1: failure
#		 0: success
#
sub queue_message {
    local($queue_dir, *Header, *Body) = @_;
    my($q);
    local(*QUEUE);
    unless (-d $queue_dir) {
	unless (mkdir($queue_dir, &folder_mode(0))) {
	    im_err("can't create directory $queue_dir\n");
	    return -1;
	}
    }
    unless (opendir(QUEUEDIR, $queue_dir)) {
	im_err("can't read $queue_dir\n");
	return -1;
    }
    $max = 0;
    foreach $q (readdir(QUEUEDIR)) {
	$q =~ s/\.wrk$//;
	if ($q =~ /^\d+$/) {
	    $max = $q if ($max < $q);
	}
    }
    closedir(QUEUEDIR);
    $max++;
    my($fail_cnt) = 0;
    im_notice("QUEUE creating $queue_dir/$max\n");
    msg_mode(1);
    while (&excl_create(\*QUEUE, "$queue_dir/$max") < 0) {
	$max++;
	if ($fail_cnt++ > 10) {
	    im_err("too many failures creating QUEUE\n");
	    return -1;
	}
    }
    # dumping variables
    print QUEUE "AF:$Anno_flag\n";
    print QUEUE "NF:$News_flag\n";
    print QUEUE "PS:$Partial_sleep\n";
    print QUEUE "SRH:$Show_Rcpts_Header\n";
    print QUEUE "SFN:$Smtp_fatal_next\n";
    print QUEUE "DSR:$Dsn_success_report\n";
    print QUEUE "MID:$Cur_mid\n";
    print QUEUE "CFG:$Config_opt\n";
    print QUEUE "PT:$partial_total\n";
    print QUEUE "S:$Sender\n";
    print QUEUE "RQ:$User_require\n";
    print QUEUE "SSV:$Smtp_servers\n";
    print QUEUE "NSV:$Nntp_servers\n";
    print QUEUE "NAU:$Nntp_authuser\n";
    print QUEUE "SSH:$SSH_server\n";
    print QUEUE "R:".join(',', @Recipients)."\n";
    print QUEUE "\n";

    &set_crlf("\n");
    if (&put_header(\*QUEUE, \@Header, 'internal', 'all') < 0
      || &put_body(\*QUEUE, \@Body, 0, 0) < 0) {
	close(QUEUE);
	im_err("queuing to $queue_dir/$max failed ($!).\n");
	unlink("$queue_dir/$max");
	return -1;
    }
    unless (close (QUEUE)) {
	im_err("queuing to $queue_dir/$max failed ($!).\n");
	unlink("$queue_dir/$max");
	return -1;
    }
    im_notice("queued in $queue_dir/$max\n");
    &log_action('queue', &get_cur_server(), $max, 'queued');
    touch_folder($queue_dir);
    return 0;
}

##### ERROR REPORT #####
#
# error_report()
#
sub error_report {
    my($rc);
    local($errlog) = &im_saved_errors();
    # reset the server list
    @Smtp_servers = split(',', $Smtp_servers);
    push(@Smtp_servers, split(',', $Emg_Smtp_servers));

    for (my $i = 0; $i <= $#Smtp_servers; $i++) {
	$rc = smtp_transaction_for_error_notify($Smtp_servers[$i],
					\@Smtp_servers, \@Header, \@Body);
	return 0 if ($rc == 0);

	smtp_close();
	log_action($Esmtp_flag ? 'esmtp' : 'smtp', get_cur_server(),
		   join(',', @Recipients), 'skipped', command_response());
    }
    if ($rc) {
	im_warn($errlog);
	&set_command_response;
	&set_cur_server('');
	my $d = &save_fcc($Dead_letter, 0, 0);	# XXX
	&log_action("dead-letter", '', $d, 'sent');
	im_warn("Message was saved in $d\n");
	return -1;
    }
    return 0;
}

##### EXIT WITH ERROR REPORT #####
#
# error_exit()
#
sub error_exit {
    local($rc);
#   if (!$Error_report_by_mail && !$Smtp_input_mode) {
#	$Error_report_by_mail = 1 unless (-t STDERR); # unless TTY
#   }
    local($errlog) = &im_saved_errors();
    if ($Error_report_by_mail) {
	# reset the server list
	@Smtp_servers = split(',', $Smtp_servers);
	push(@Smtp_servers, split(',', $Emg_Smtp_servers));

	for (my $i = 0; $i <= $#Smtp_servers; $i++) {
	    $rc = &smtp_transaction_for_error_notify($Smtp_servers[$i],
					     \@Smtp_servers, \@Header, \@Body);
	    last if ($rc == 0);

	    smtp_close();
	    log_action($Esmtp_flag ? 'esmtp' : 'smtp', get_cur_server(),
		       join(',', @Recipients), 'skipped', command_response());

	}
	if ($rc) {
#	    im_warn($errlog);
	    &set_command_response;
	    &set_cur_server('');
	    if ($Draft_message eq '') {
		my $d = &save_fcc('', 0, 0); # XXX
		im_warn("Message was saved in $d\n");
	    } else {
		&log_action("draft", '', $Draft_message, 'preserved');
		im_warn("Draft file $Draft_message preserved.\n");
	    }
	    &exit_($EXIT_ERROR);
	}
	&exit_($EXIT_SUCCESS);
    }
    if ($Smtp_input_mode) {
	while ($errlog) {
	    $errlog =~ /^([^\n]+)/;
	    print STDOUT "554-$1\n";
	    $errlog =~ s/^[^\n]+\n//;
	}
	while ($Info) {
	    $Info =~ /^([^\n]+)/;
	    print STDOUT "554- $1\n";
	    $Info =~ s/^[^\n]+\n//;
	}
	my $session_log = &get_session_log();
	while ($session_log) {
	    $session_log =~ /^([^\n]+)/;
	    print STDOUT "554- $1\n";
	    $session_log =~ s/^[^\n]+\n//;
	}
	print STDOUT "554 Message was not accepted\n";
	&smtp_get_mail_final(1);
	&exit_($EXIT_ERROR);
    } else {
	# notify to the terminal
#	im_err("delivery failed.\n");
#	if ($errlog) {
#	    print STDERR "\n";
#	    print STDERR "Reason:\n";
#	    print STDERR "$errlog\n";
#	}
	if ($Info) {
	    print STDERR "\n";
	    print STDERR $Info;
	}
	my $session_log = &get_session_log();
	if ($session_log) {
	    print STDERR "\n";
	    print STDERR $session_log;
	}
	&set_command_response;
	&set_cur_server('');
	if ($Draft_message eq '') {
	    # save in dead_letter unless the message was prepared
	    # as a draft file.
	    my $d = &save_fcc('', 0, 0); # XXX
	    im_warn("the message was saved in $d\n");
	} else {
	    &log_action('draft', '', $Draft_message, 'preserved');
	    im_warn("Draft file $Draft_message preserved.\n");
	}
	&exit_($EXIT_ERROR);
    }
}

##### EXIT #####
#
# exit_(stat)
#	stat: exit status
#
sub exit_ {
    local($stat) = @_;
    &smtp_close;
    &nntp_close;
    exit $stat;
}

##### END OF SCRIPT #####

### ToDo list
# PGP encription
# MCI for error respose
# 75 char len (1522)
# select SMTP server on each addresses
# connection timed out (signal)
# refusing large size messgae
# deliverability
# header MIME full encoding
# file locking for appending
# sender name config
# draft all
# @HOSTNAME@
# sgid mail

__END__

=head1 NAME

imput - put mail/news message into networks

=head1 SYNOPSIS

B<imput> [OPTIONS] [MSG]

=head1 DESCRIPTION

The I<imput> command dispatches mail/news message by way of SMTP/NNTP.

This command is provided by IM (Internet Message).

=over 5

=item With UCB Mail

Define "sendmail" environment variable with value "imput".

=item With Mew 1.x

Eval (setq mew-prog-imput "imput").

=item With MH

Define sendproc in ~/.mh_profile like "sendproc: imput".

=item With sendmail.el (if you are using VM or ...)

Eval (setq sendmail-program "imput").

=item With mh-e (4 or later)

Eval (setq mh-send-prog "imput").

=item With pine

Define "sendmail-path" in ~/.pinerc, for example:

sendmail-path=/usr/local/bin/imput -Report -ObeyHeader -IgnoreDot

=item With applications which use sendmail

Replace sendmail to this program but if daemon sendmail is required,
original sendmail should be renamed to sendmail.bin or something else
for starting daemon mode sendmail and for newaliasing.

=item With applications which use inews

Header generation by command line option not supported.

=back

=head1 OPTIONS

=over 5

=item I<--version>

Output version information and exit.

=item I<--help>

Display help message and exit.

=item I<--debug={on,off}>

Set all debug options.

=item I<--debugflag=DEBUG_OPTION>

Set specific debug options (separated with ',').

=item I<--verbose={on,off}>

Print verbose messages when running.

=item I<--require=STRING>

User defined perl script to be required.

=item I<--smtpservers=STRING>

List of SMTP servers (separated with ',').

Each element should be server[/remote_port][%local_port]

=item I<--emgsmtpsvrs=STRING>

List of SMTP servers for Emergency Use (i.e. error reporting).

=item I<--trynextonfatal={on,off}>

Try next SMTP server evenif permanent failure.

=item I<--nntpservers=STRING>

List of NNTP servers (separated with ',').

Each element should be server[/remote_port][%local_port]

=item I<--nntpauthuser=STRING>

User name for NNTP authentication.

=item I<--clientname=STRING>

Name as a SMTP client (used for SMTP HELO).

=item I<--sshserver=STRING>

SSH port relay server.

=item I<--obeymtadomain={on,off}>

Do not qualify local addresses with default domain.

=item I<--fromdomain=STRING>

Default domain name for sender.

=item I<--todomain=STRING>

Default domain name for recipients.

=item I<--msgiduser=STRING>

A user name for Message-Id generation.

=item I<--msgiddomain=STRING>

A domain name for Message-Id generation.

=item I<--nomsgidfornews=STRING>

Strip Message-Id when posting to news system.

=item I<--user=STRING>

Local part of the sender address.

=item I<--address=STRING>

Address used in From: header; equivalent to User@FromDomain

=item I<--name=STRING>

Commentary name for sender.

=item I<--nameincomment={on,off}>

Show commentary name in () on From: header.

=item I<--org=STRING>

Name of organization for news posting.

=item I<--subj=STRING>

A string for subject field.

=item I<--nscmpl={on,off}>

Use domain-part completion with nameserver.

=item I<--showrcpts={on,off}>

Allow to show recipients in header as To: if no To: in original.

=item I<--metoo={on,off}>

Request DCC to me.

=item I<--dcc=STRING>

Supplemental DCC address.

=item I<--fcc=STRING>

Folder name to save FCC.

=item I<--receipt={on,off}>

Need a report of successful delivery.

=item I<--group=STRING>

Newsgroup names to be posted in.

=item I<--jpconv={on,off}>

Convert japanese character encoding from EUC/SJIS to JIS.

=item I<--defcode=STRING>

Default classification of japanese character code (EUC/SJIS/8BIT).
Default value is "8bit".

=item I<--jpheader={on,off}>

Encode japanese JIS characters to MIME style at header.
Default value is "on".

=item I<--hdrqencoding={on,off}>

Header encoding type: 0 is B; 1 is Q.

=item I<--nohdrfolding={on,off}>

Do not fold long header lines.

=item I<--sortheader=STRING>

Header sequence for sorting (labels separated with ',').

=item I<--8to7={on,off}>

Convert 8bit body to 7bit by base64/quoted-printable encoding.

=item I<--8bitlabel=STRING>

Sub-type label for unknown 8bit body on Content-Type:.
Default value is "unknown-8bit".

=item I<--lines=NUM>

Line numbers for splitting into partial messages.

=item I<--sleep=NUM>

Sleep interval for dispatching each splitted messages.
Default value is 10.

=item I<--log=STRING>

File name to write delivery log.
Default value is "putlog".

=item I<--syslog={on,off}>

Use SYSLOG feature instead of writing to a file directly.

=item I<--report={on,off}>

Report errors via mail.
Default value is "on".

=item I<--msgid={on,off}>

Generate Message-Id header line.
Default value is "on".

=item I<--pidmsgid={on,off}>

Generate Message-Id with Process ID.

=item I<--uidmsgid={on,off}>

Generate Message-Id with User ID instead of login name.

=item I<--date={on,off}>

Generate Date header line.
Default value is "on".

=item I<--newsgmtdate={on,off}>

Generate date field in GMT for posting news.

=item I<--uselines={on,off}>

Generate Lines header line.
Default value is "on".

=item I<--aliasesfile=STRING>

List of files for mail address aliasing.
Default value is "Aliases".

=item I<--addrbook=STRING>

List of Addrbook files.

=item I<--hostaliases=STRING>

List of files for domain part completion.

=item I<--fccpartial={on,off}>

Save FCC with partial format.

=item I<--dead=STRING>

Path of file to save unsent message as a deadletter.
Default value is "dead.letter".

=item I<--justqueuing={on,off}>

Just store message into queue without attempt of delivery.

=item I<--queuing={on,off}>

Store message into queue on delivery failure.

=item I<--processqueue={on,off}>

Process queued messages.

=item I<--queuestatus={on,off}>

Show list of queued messages.

=item I<--folder=STRING>

Path of draft folder directory.

=item I<--mimebcc={on,off}>

Use MIME (message/rfc822) style BCC.
Default value is "on".

=item I<--trashmark=STRING>

Prefix character for draft message file renaming.
Default value is "#".

=item I<--preserve={on,off}>

Preserve draft message as is even if dispatched successfully.

=item I<--message=STRING>

Path/name of draft message.

=item I<--pgpsign={on,off}>

Generate PGP signature for body-part.

=item I<--multipartadd=STRING,STRING...>

Path/name of message to be added as a part of multipart message.

=item I<--filenameadd={on,off}>

Add filename field at Content-Disposition header.

=item I<--smtp={on,off}>

Perform SMTP style input mode.

=item I<--annotate={on,off}>

Annotate on the parent message (MsgDB required).

=item I<--dist={on,off}>

Redistribution mode (using Resent-*:).

=item I<--distmsg=STRING>

Path of message for redistribution.

=item I<--obeyheader={on,off}>

Collect recipients from message header.

=item I<--ignoredot={on,off}>

Ignore DOT for message termination.

=item I<--newscheck={on,off}>

No news posting if To, Cc header found evenif Newsgroups: exists.

=item I<--esmtp={on,off}>

Enforce ESMTP (always begins with EHLO).

=item I<--newspost={on,off}>

Enable NNTP.
Default value is "on".

=item I<--addheader=STRING,STRING...>

Header lines to be added.

=back

For compatibility with the send command (provided by MH/nmh):

	-mime
	-nomime
	-msgid
	-nomsgid
	-watch
	-nowatch
	-verbose
	-noverbose
	-draftmessage=<string>
	-draftf=<string>
	-draftfolder=<string>
	-nodraftfolder
	-draftm=<string>
	-draft
	-alias=<string>
	-aliasesfile=<string>
	-filter=<string>
	-nofilter
	-format
	-noformat
	-forward
	-noforward
	-push
	-nopush
	-width=<num>
	-split=<num>
	-version
	-help
	-hencode
	-nohencode
	-library=<string>
	-server=<string>
	-client=<string>
	-bs
	-f=<string>
	-t
	-v
	-odb
	-odi
	-oem
	-oi
	-i
	-om
	-m
	-odq
	-q
	-bp
	-J
	-h
	-s=<string>

=head1 COPYRIGHT

IM (Internet Message) is copyrighted by IM developing team.
You can redistribute it and/or modify it under the modified BSD
license.  See the copyright file for more details.

=cut

### Copyright (C) 1997, 1998, 1999 IM developing team
### All rights reserved.
### 
### Redistribution and use in source and binary forms, with or without
### modification, are permitted provided that the following conditions
### are met:
### 
### 1. Redistributions of source code must retain the above copyright
###    notice, this list of conditions and the following disclaimer.
### 2. Redistributions in binary form must reproduce the above copyright
###    notice, this list of conditions and the following disclaimer in the
###    documentation and/or other materials provided with the distribution.
### 3. Neither the name of the team nor the names of its contributors
###    may be used to endorse or promote products derived from this software
###    without specific prior written permission.
### 
### THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS'' AND
### ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
### IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
### PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE TEAM OR CONTRIBUTORS BE
### LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
### CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
### SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
### BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
### WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
### OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
### IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

### Local Variables:
### mode: perl
### End:
