--- impost-0.99i	Sun Apr  6 00:00:00 1997
+++ impost	Wed Nov 24 04:31:09 1999
@@ -5,7 +5,7 @@
 
 #	IMPOST: An Internet Message Posting Frontend
 
-$Version = "impost version 0.99i (Apr. 6, 1997)";
+$Version = "impost version 0.99i-ssh (Nov. 24, 1999)";
 
 #	Copyright(c)1995,1996,1997 by Motonori Nakamura
 #					<motonori@econ.kyoto-u.ac.jp>
@@ -175,7 +175,7 @@
 	if ($ProcessQueue || $QueueStatus) {
 		&init_final;
 		&process_queue($ProcessQueue);
-		exit 0;
+		&exit(0);
 	}
 
 	&open_aliases;
@@ -591,7 +591,7 @@
 					&mh_annotate if ($Annotate_flag);
 				}
 				print STDERR "message queued.\n" if ($Verbose);
-				exit 0;
+				&exit(0);
 			}
 		}
 		# XXX "send:" is for trap hack of mew B-)
@@ -645,6 +645,8 @@
 				"list of NNTP servers (separated with ',')",
 		'ClientName',	'S:',	*Client_name,		"localhost",
 				"name as a SMTP client (used for SMTP HELO)",
+		'SSHserver',	'S:',	*Ssh_server,			"",
+				"SSH port relay server",
 		'ObeyMTAdomain','T:',	*Obey_MTA_domain,		0,
 				"do not append default domain on local address",
 		'FromDomain',	'S:',	*Default_from_domain_name,	"",
@@ -934,6 +936,7 @@
 	 $pw_quota, $pw_comment, $pw_gcos, $pw_dir, $pw_shell) = getpwuid($<);
 
 	$Login = $pw_name;
+	$Uid = $pw_uid;
 	$Home = $pw_dir;
 	$Home = $ENV{'HOME'} if ($ENV{'HOME'});
 
@@ -1089,7 +1092,7 @@
 		return $file;
 	}
 	if ($file =~ /^\+/) {
-		$file = &get_folders_dir(0)."/".$';
+		$file = &get_folders_dir(0)."/".substr($file,1);
 		return $file;
 	}
 	$base = $Home unless ($base);
@@ -1341,11 +1344,11 @@
 				}
 				if (/^\s*#define\s+SOCK_STREAM\s+(\d+)/) {
 					$SOCK_STREAM = $1;
-					break;
+					last;
 				}
 				if (/^\s*#define\s+SOCK_STREAM\s+NC_TPI_COTS/) {
 					$SOCK_STREAM = $NC_TPI_COTS;
-					break;
+					last;
 				}
 			}
 			close(SOCKET_H);
@@ -1393,7 +1396,7 @@
 	if ($Message_id_PID) {
 		$mid_rnd = "-".$$.$mid_rnd;
 	}
-	local ($mid) = "<$mid_time$mid_rnd.$Login\@$Message_id_domain_name>";
+	local ($mid) = "<$mid_time$mid_rnd.$Uid\@$Message_id_domain_name>";
 	$Mid_hist{$part} = $mid if ($part > 0);
 	return $mid;
 }
@@ -1482,11 +1485,44 @@
 	local ($he_name, $he_alias, $he_type, $he_len, $he_addr, @he_addrs);
 	local ($s, $sin);
 	while ($s = shift(@servers)) {
+		$Cur_server_original_form = $s;
 		local ($r) = ($#servers >= 0)?"skipped":"failed";
+		# manage server:localport or server/remoteport:localport notation
+		if ($s =~ s/:(\d+)$//) {
+			$port = $1;
+			$Cur_server = $s;
+			local( $remoteport );
+			if ($s =~ s/\/(\d+)$//) {
+				$remoteport = $1;
+			} else {
+				$remoteport = $se_port;
+			}
+			# Set default value of SSH Relay server.
+			$Ssh_server || ( $Ssh_server = $Client_name );
+			if ($Ssh_server eq 'localhost') {
+				$Errlog .= "Port-forwarding via localhost is not available.\n";
+				$port = $remoteport;
+				$Cur_server = "$s/$port";
+			} else {
+				if ( $port = &ssh_proxy($s,$remoteport,$port,$Ssh_server) ) {
+					$s = 'localhost';
+					$Cur_server = "$Cur_server:$port";
+				} else { # Connection failed.
+					$Errlog .= "Can't login to $Ssh_server.\n";
+					push( @Response, "Can't login to $Ssh_server." );
+					if ($proto =~ /smtp$/i) {
+						&log_history($proto,
+							     join(',', @Recipients), $r);
+					} else { # NNTP
+						&log_history($proto, $Newsgroups, $r);
+					}
+					next;
+				}
+			}
+		}
 		# manage server/port notation
-		if ($s =~ /\/(\d+)$/) {
+		elsif ($s =~ s/\/(\d+)$//) {
 			$port = $1;
-			$s = $`;
 			$Cur_server = "$s/$port";
 		} else {
 			$port = $se_port;
@@ -1705,9 +1741,12 @@
 	local ($rc, $rsp);
 	@Status =();
 	if ($Smtp_opened) {
-		print STDERR "resetting SMTP session.\n"
-			if ($Verbose);
-		return 0 unless (&send_command($SMTPd, "RSET", $logging));
+		if (grep($Smtp_opened eq $_, @Smtp_servers)) {
+			$Cur_server = $Smtp_cur_server;
+			print STDERR "resetting SMTP session.\n"
+				if ($Verbose);
+			return 0 unless (&send_command($SMTPd, "RSET", $logging));
+		}
 		&smtp_close($SMTPd, 0, 0);
 #		return 1;
 	}
@@ -1730,7 +1769,8 @@
 			$Esmtp_support_8bitmime = ($rsp =~ /8BITMIME/i) ? 1 : 0;
 			$Esmtp_support_dsn = ($rsp =~ /DSN/i) ? 1 : 0;
 			$Esmtp_support_verb = ($rsp =~ /VERB/i) ? 1 : 0;
-			$Smtp_opened = 1;
+			$Smtp_cur_server = $Cur_server;
+			$Smtp_opened = $Cur_server_original_form;
 			&send_command($SMTPd, "VERB", $logging)
 				if ($Esmtp_support_verb && $Debug{"smtp"});
 			return 0;
@@ -1740,7 +1780,8 @@
 	# fall back to traditional SMTP
 	$rc = &send_command($SMTPd, "HELO $Client_name", $logging);
 	return $rc if ($rc);
-	$Smtp_opened = 1;
+	$Smtp_cur_server = $Cur_server;
+	$Smtp_opened = $Cur_server_original_form;
 	&send_command($SMTPd, "VERB", $logging) if ($Debug{"smtp"});
 	return 0;
 }
@@ -1924,7 +1965,10 @@
 #
 sub nntp_open {
 	local ($rc);
-	return 0 if ($Nntp_opened);
+	if ($Nntp_opened && grep($Nntp_opened eq $_, @Nntp_servers)){
+		$Cur_server = $Nntp_cur_server;
+		return 0;
+	}
 	return 1 unless ($NNTPd = &connect_server(*Nntp_servers, "nntp"));
 	$Session_log = $Session_log."Transcription of NNTP session follows:\n";
 	if ($rc = &send_command($NNTPd, "", 1)) {
@@ -1935,7 +1979,8 @@
 			return 1;
 		}
 	}
-	$Nntp_opened = 1;
+	$Nntp_cur_server = $Cur_server;
+	$Nntp_opened = $Cur_server_original_form;
 	return 0;
 }
 
@@ -2001,6 +2046,7 @@
 	local ($rc);
 	return $rc if ($rc = &nntp_open);
 	return $rc if ($rc = &send_command($NNTPd, "POST", 1));
+	return -1 if (grep(/^(435|437|440|441)/, @Response) > 0);
 	select ($NNTPd); $| = 0; select (STDOUT);
 	$CRLF = "\r\n";
 	if ($part == 0) {
@@ -2648,6 +2694,7 @@
 			foreach $i (@Del_headers_on_mail) {
 				next hdr if ($line =~ /^$i:/i);
 			}
+			$line =~ s/Newsgroups:/X-Newsgroups:/i;
 		}
 		if ($CHAN =~ /nntp/i) {
 			foreach $i (@Del_headers_on_news) {
@@ -4478,8 +4525,9 @@
 #
 sub trash_message {
 	local ($message_file_path) = &get_input_message_path;
-	$message_file_path =~ /[^\/]+$/;
-	local ($dir, $file) = ($`, $&);
+	local ($dir, $file);
+	( $dir = $message_file_path ) =~ s/([^\/]+$)//;
+	$file = $1;
 	if ($Trashmark) {
 		if (-f "$dir$Trashmark$file") {
 			unlink ("$dir$Trashmark$file");
@@ -4583,29 +4631,33 @@
 	foreach $q (sort {$a <=> $b} readdir(QUEUEDIR)) {
 		next unless ($q =~ /^\d+$/);
 		$QUEUE = "QUEUE";
-		unless (open($QUEUE, "<$queue_dir/$q")) {
-			print STDERR "can't open $queue_dir/$q\n";
+		rename ("$queue_dir/$q", "$queue_dir/$q.wrk");
+		unless (open($QUEUE, "<$queue_dir/$q.wrk")) {
+			print STDERR "can't open $queue_dir/$q.wrk\n";
+			rename ("$queue_dir/$q.wrk", "$queue_dir/$q");
 			return;
 		}
-		print STDERR "processing $queue_dir/$q ...\n" if ($Verbose);
+		print STDERR "processing $queue_dir/$q.wrk ...\n" if ($Verbose);
 		while (<$QUEUE>) {
 			chop;
 			last if (/^$/);
 			print STDERR "ENV>$_\n" if ($Debug{"queue"});
-			if (/^AF:/) { $Annotate_flag = $'; next; }
-			if (/^NF:/) { $News_flag = $'; next; }
-			if (/^PS:/) { $Partial_sleep = $'; next; }
-			if (/^SRH:/) { $Show_Rcpts_Header = $'; next; }
-			if (/^SFN:/) { $Smtp_fatal_next = $'; next; }
-			if (/^DSR:/) { $Dsn_success_report = $'; next; }
-			if (/^MID:/) { $Cur_mid = $'; next; }
-			if (/^CFG:/) { $Config_opt = $'; next; }
-			if (/^PT:/) { $partial_total = $'; next; }
-			if (/^S:/) { $Sender = $'; next; }
-			if (/^SSV:/) { @Smtp_servers = split(',', $'); next; }
-			if (/^NSV:/) { @Nntp_servers = split(',', $'); next; }
-			if (/^R:/) { @Recipients = split(',', $'); next; }
-			if (/^RQ:/) { $User_require = $'; next; }
+			if (/^AF:(.*)/) { $Annotate_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 (/^SSH:(.*)/) { $Ssh_server = $1; next; }
+			if (/^CLI:(.*)/) { $Client_name = $1; next; }
+			if (/^R:(.*)/) { @Recipients = split(',', $1); next; }
+			if (/^RQ:(.*)/) { $User_require = $1; next; }
 			print STDERR "unknown environment: $_\n" if ($Verbose);
 		}
 
@@ -4618,20 +4670,22 @@
 			print STDERR "sending message\n" if ($Debug{"queue"});
 			$rcode = &send_message($News_flag, $partial_total);
 			if ($rcode == 0) {
-				unlink("$queue_dir/$q");
+				unlink("$queue_dir/$q.wrk");
 				print STDERR "$queue_dir/$q sent\n"
 					if ($Verbose);
 			} elsif ($rcode > 0) {
+				rename ("$queue_dir/$q.wrk", "$queue_dir/$q");
 				print STDERR "$queue_dir/$q preserved\n"
 					if ($Verbose);
 			} else {
-				unlink("$queue_dir/$q");
+				unlink("$queue_dir/$q.wrk");
 				print STDERR "$queue_dir/$q failed\n"
 					if ($Verbose);
 				&error_exit;
 			}
 		} else {
 			local ($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";
@@ -4699,6 +4753,7 @@
 		return 0;
 	}
 	foreach $q (readdir(QUEUEDIR)) {
+		$q =~ s/\.wrk$//;
 		if ($q =~ /^\d+$/) {
 			$max = $q if ($max < $q);
 		}
@@ -4730,6 +4785,8 @@
 	print $FILE "RQ:$User_require\n";
 	printf $FILE "SSV:$Smtp_servers\n";
 	printf $FILE "NSV:$Nntp_servers\n";
+	printf $FILE "SSH:$Ssh_server\n";
+	printf $FILE "CLI:$Client_name\n";
 	printf $FILE "R:%s\n", join(',', @Recipients);
 	print $FILE "\n";
 
@@ -4843,8 +4900,97 @@
 	local ($stat) = @_;
 	&smtp_close($SMTPd, 0, 0);
 	&nntp_close($NNTPd, 0, 0);
+	&ssh_close();
 	&close_aliases;
 	exit $stat;
+}
+
+##### SSH_PROXY #####
+#
+# ssh_proxy(server,remote,local,host)
+#	server: SMTP/NNTP server's host name.
+#	remote: Port number on the server.
+#	local:  A candidate of the port number on the local host.
+#	host:   Relay Host.
+# return value:
+#	0: failed
+#	otherwise: The connected port number of the local host.
+#	
+sub ssh_proxy {
+	local( $server, $remote, $local, $host ) = @_;
+
+	$Ssh_fh = "SSH00000" unless $Ssh_fh;
+
+	print STDERR "openning SSH-tunnel to $server/$remote:$local via $host\n"
+	    if ($Verbose);
+	local( $pid, $read, $write );
+      FORK: {
+		$read  = $Ssh_fh++;
+		$write = $Ssh_fh++;
+		pipe( $read, $write );
+		if( $pid = fork ){
+			close $write;
+			local( $buf, $i, $sig );
+			for( $i=0; $i<3; $i++ ){
+				$sig = $SIG{ALRM};
+				$SIG{ALRM} = 'ssh_timeout_handler';
+				eval {
+					alarm 60;
+					$buf = <$read>;
+					alarm 0;
+				};
+				$SIG{ALRM} = $sig;
+				if( $@ !~ /ssh_timeout_handler: SIGALRM is received/ ){
+					push( @Ssh_pid, $pid );
+					if( $buf =~ /ssh_proxy_connect/ ){
+						return $local;
+					} elsif( $buf =~ /Local: bind: Address already in use/ ){
+						$local++;
+						redo FORK;
+					} elsif( $buf ){
+						last;
+					}
+				}
+			}
+			$buf =~ s/\s+$//;
+			$Errlog .= "Accident in Port Forwading: $buf\n";
+			@Response = ( "Accident in Port Forwading: $buf" );
+		} elsif( $pid == 0 ){
+			close $read;
+			open( STDOUT, ">&$write" );
+			open( STDERR, ">&$write" );
+			exec( 'ssh', '-n', '-x', '-o', 'BatchMode yes',
+			      "-L$local:$server:$remote", $host,
+			      'echo ssh_proxy_connect ; sleep 300' );
+			exit 0; # Not reach.
+		} elsif( $! =~ /No more process/ ){
+			sleep 5;
+			redo FORK;
+		} else {
+			$Errlog .= "Can't fork `ssh'.\n";
+			@Response = ( "Can't fork `ssh'." );
+		}
+	}
+	0;
+}
+
+# Internal subroutine.
+sub ssh_timeout_handler {
+	die "ssh_timeout_handler: SIGALRM is received\n";
+}
+
+##### SSH_CLOSE #####
+#
+# ssh_close()
+#	return value: none
+#
+sub ssh_close {
+	if( @Ssh_pid ){
+		kill 15, @Ssh_pid;
+		sleep 3;
+		kill 9, @Ssh_pid;
+	}
+	@Ssh_pid = ();
 }
 
 ##### END OF SCRIPT #####
