From Morty Abzug <morty@frakir.org>
 
Fore/Marconi support

Also here:
http://www.shrubbery.net/pipermail/rancid-discuss/2005-August/001175.html
 

diff -Nur rancid-2.3.1-local-p4/bin/forelogin.in rancid-2.3.1-local-p5/bin/forelogin.in
--- rancid-2.3.1-local-p4/bin/forelogin.in	1969-12-31 19:00:00.000000000 -0500
+++ rancid-2.3.1-local-p5/bin/forelogin.in	2005-08-16 01:23:08.000000000 -0400
@@ -0,0 +1,526 @@
+#! @EXPECT_PATH@ --
+##
+## $Id: jlogin.in,v 1.46 2004/03/11 19:36:25 heas Exp $
+##
+## Copyright (C) 1997-2004 by Terrapin Communications, Inc.
+## All rights reserved.
+##
+## This software may be freely copied, modified and redistributed
+## without fee for non-commerical purposes provided that this license
+## remains intact and unmodified with any RANCID distribution.
+##
+## There is no warranty or other guarantee of fitness of this software.
+## It is provided solely "as is".  The author(s) disclaim(s) all
+## responsibility and liability with respect to this software's usage
+## or its effect upon hardware, computer systems, other software, or
+## anything else.
+##
+## Except where noted otherwise, rancid was written by and is maintained by
+## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz.
+##
+#
+# The login expect scripts were based on Erik Sherk's gwtn, by permission.
+#
+# jlogin - juniper login
+#
+# Most options are intuitive for logging into a Cisco router.
+# The default username password is the same as the vty password.
+#
+
+# Usage line
+set usage "Usage: $argv0 \[-c command\] \[-Evar=x\] \[-f cloginrc-file\] \
+\[-p user-password\] \[-r passphrase\] \[-s script-file\] \
+\[-u username\] \[-t timeout\] \[-x command-file\] \[-y ssh_cypher_type\] \
+router \[router...\]\n"
+
+# env(CLOGIN) may contain the following chars:
+#	x == do not set xterm banner or name
+
+# Password file
+set password_file $env(HOME)/.cloginrc
+# Default is to login to the router
+set do_command 0
+set do_script 0
+# The default is to automatically enable
+set avenable 1
+# The default is to look in the password file to find the passwords.  This
+# tracks if we receive them on the command line.
+set do_passwd 1
+
+# Find the user in the ENV, or use the unix userid.
+if {[ info exists env(CISCO_USER) ] } {
+    set default_user $env(CISCO_USER)
+} elseif {[ info exists env(USER) ]} {
+    set default_user $env(USER)
+} elseif {[ info exists env(LOGNAME) ]} {
+    set default_user $env(LOGNAME)
+} else {
+    # This uses "id" which I think is portable.  At least it has existed
+    # (without options) on all machines/OSes I've been on recently -
+    # unlike whoami or id -nu.
+    if [ catch {exec id} reason ] {
+	send_error "\nError: could not exec id: $reason\n"
+	exit 1
+    }
+    regexp {\(([^)]*)} "$reason" junk default_user
+}
+
+# Sometimes routers take awhile to answer (the default is 10 sec)
+set timeout 120
+
+# Process the command line
+for {set i 0} {$i < $argc} {incr i} {
+    set arg [lindex $argv $i]
+
+    switch  -glob -- $arg {
+	# Command to run.
+	-c* -
+	-C* {
+	    if {! [  regexp .\[cC\](.+) $arg ignore command]} {
+		incr i
+		set command [ lindex $argv $i ]
+	    }
+	    set do_command 1
+	# Environment variable to pass to -s scripts
+	} -E*
+	{
+	    if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} {
+		set E$varname $varvalue
+	    } else {
+		send_user "\nError: invalid format for -E in $arg\n"
+		exit 1
+	    }
+	# alternate cloginrc file
+	} -f* -
+	-F* {
+	    if {! [ regexp .\[fF\](.+) $arg ignore password_file]} {
+		incr i
+		set password_file [ lindex $argv $i ]
+	    }
+	# user Password
+	} -p* -
+	-P* {
+	    if {! [  regexp .\[pP\](.+) $arg ignore userpasswd]} {
+		incr i
+		set userpasswd [ lindex $argv $i ]
+	    }
+	    set do_passwd 0
+	# passphrase
+	} -r* -
+	-R* {
+	    if {! [  regexp .\[rR\](.+) $arg ignore passphrase]} {
+		incr i
+		set avpassphrase [ lindex $argv $i ]
+	    }
+	# Expect script to run.
+	} -s* -
+	-S* {
+	    if {! [  regexp .\[sS\](.+) $arg ignore sfile]} {
+		incr i
+		set sfile [ lindex $argv $i ]
+	    }
+	    if { ! [ file readable $sfile ] } {
+		send_user "\nError: Can't read $sfile\n"
+		exit 1
+	    }
+	    set do_script 1
+	# Timeout
+	} -t* -
+	-T* {
+	    if {! [ regexp .\[tT\](.+) $arg ignore timeout]} {
+		incr i
+		set timeout [ lindex $argv $i ]
+	    }
+	# Username
+	} -u* -
+	-U* {
+	    if {! [  regexp .\[uU\](.+) $arg ignore user]} {
+		incr i
+		set username [ lindex $argv $i ]
+	    }
+	# command file
+	} -x* -
+	-X* {
+	    if {! [  regexp .\[xX\](.+) $arg ignore cmd_file]} {
+		incr i
+		set cmd_file [ lindex $argv $i ]
+	    }
+	    if [ catch {set cmd_fd [open $cmd_file r]} reason ] {
+		send_user "\nError: $reason\n"
+		exit 1
+	    }
+            set cmd_text [read $cmd_fd]
+            close $cmd_fd
+            set command [join [split $cmd_text \n] \;]
+            set do_command 1
+	# 'ssh -c' cypher type
+	} -y* -
+	-Y* {
+	    if {! [  regexp .\[yY\](.+) $arg ignore cypher]} {
+		incr i
+		set cypher [ lindex $argv $i ]
+	    }
+	} -* {
+	    send_user "\nError: Unknown argument! $arg\n"
+	    send_user $usage
+	    exit 1
+	} default {
+	    break
+	}
+    }
+}
+# Process routers...no routers listed is an error.
+if { $i == $argc } {
+    send_user "\nError: $usage"
+}
+
+# Only be quiet if we are running a script (it can log its output
+# on its own)
+if { $do_script } {
+    log_user 0
+} else {
+    log_user 1
+}
+
+#
+# Done configuration/variable setting.  Now run with it...
+#
+
+# Sets Xterm title if interactive...if its an xterm and the user cares
+proc label { host } {
+    global env
+    # if CLOGIN has an 'x' in it, don't set the xterm name/banner
+    if [info exists env(CLOGIN)] {
+	if {[string first "x" $env(CLOGIN)] != -1} { return }
+    }
+    # take host from ENV(TERM)
+    if [info exists env(TERM)] {
+	if [regexp \^(xterm|vs) $env(TERM) ignore ] {
+	    send_user "\033]1;[lindex [split $host "."] 0]\a"
+	    send_user "\033]2;$host\a"
+        }
+    }
+}
+
+# This is a helper function to make the password file easier to
+# maintain.  Using this the password file has the form:
+# add password sl* 	pete cow
+# add password at* 	steve
+# add password *	hanky-pie
+proc add {var args} { global int_$var ; lappend int_$var $args}
+proc include {args} {
+    global env
+    regsub -all "(^{|}$)" $args {} args
+    if { [ regexp "^/" $args ignore ] == 0 } {
+	set args $env(HOME)/$args
+    }
+    source_password_file $args
+}
+
+proc find {var router} {
+  upvar int_$var list
+  if { [info exists list] } {
+    foreach line $list {
+      if { [string match [lindex $line 0] $router ] } {
+	return [lrange $line 1 end]
+      }
+    }
+  }
+  return {}
+}
+
+# Loads the password file.  Note that as this file is tcl, and that
+# it is sourced, the user better know what to put in there, as it
+# could install more than just password info...  I will assume however,
+# that a "bad guy" could just as easy put such code in the clogin
+# script, so I will leave .cloginrc as just an extention of that script
+proc source_password_file { password_file } {
+    global env
+    if { ! [file exists $password_file] } {
+	send_user "\nError: password file ($password_file) does not exist\n"
+	exit 1
+    }
+    file stat $password_file fileinfo
+    if { [expr ($fileinfo(mode) & 007)] != 0000 } {
+	send_user "\nError: $password_file must not be world readable/writable\n"
+	exit 1
+    }
+    if [ catch {source $password_file} reason ] {
+	send_user "\nError: $reason\n"
+	exit 1
+    }
+}
+
+# Log into the router.
+proc login { router user passwd cmethod cyphertype identfile} {
+    global spawn_id in_proc do_command do_script passphrase prompt
+    global sshcmd
+    set in_proc 1
+
+    # try each of the connection methods in $cmethod until one is successful
+    set progs [llength $cmethod]
+    foreach prog [lrange $cmethod 0 end] {
+	if [string match "telnet*" $prog] {
+	    regexp {telnet(:([^[:space:]]+))*} $prog command suffix port
+	    if {"$port" == ""} {
+		set retval [ catch {spawn telnet $router} reason ]
+	    } else {
+		set retval [ catch {spawn telnet $router $port} reason ]
+	    }
+	    if { $retval } {
+		send_user "\nError: telnet failed: $reason\n"
+		exit 1
+	    }
+	} elseif ![string compare $prog "ssh"] {
+	    # ssh to the router & try to login with or without an identfile.
+	    # We use two calls to spawn since spawn does not seem to parse
+	    # spaces correctly.
+	    if {$identfile != ""} {
+		if [ catch {spawn $sshcmd -c $cyphertype -x -l $user -i $identfile $router} reason ] {
+		    send_user "\nError: failed to $sshcmd: $reason\n"
+		    exit 1
+		}
+	    } else {
+		if [ catch {spawn $sshcmd -c $cyphertype -x -l $user $router} reason ] {
+		    send_user "\nError: failed to $sshcmd: $reason\n"
+		    exit 1
+		}
+	    }
+	} elseif ![string compare $prog "rsh"] {
+	    if [ catch {spawn rsh -l $user $router} reason ] {
+		send_user "\nError: rsh failed: $reason\n"
+		exit 1
+	    }
+	} else {
+	    puts "\nError: unknown connection method: $prog"
+	    return 1
+	}
+	incr progs -1
+	sleep 0.3
+
+	# This helps cleanup each expect clause.
+	expect_after {
+	    timeout {
+		send_user "\nError: TIMEOUT reached\n"
+		catch {close}; wait
+		if { $in_proc} {
+	            return 1
+		} else {
+	            continue
+		}
+            } eof {
+		send_user "\nError: EOF received\n"
+		catch {close}; wait
+		if { $in_proc} {
+	            return 1
+		} else {
+	            continue
+		}
+            }
+	}
+
+	# Here we get a little tricky.  There are several possibilities:
+	# the router can ask for a username and passwd and then
+	# talk to the TACACS server to authenticate you, or if the
+	# TACACS server is not working, then it will use the enable
+	# passwd.  Or, the router might not have TACACS turned on,
+	# then it will just send the passwd.
+	expect {
+	    -re "(Connection refused|Secure connection \[^\n\r]+ refused|Connection closed by)" {
+		catch {close}; wait
+		if !$progs {
+		   send_user "\nError: Connection Refused ($prog)\n"; return 1
+		}
+	    }
+            eof { send_user "\nError: Couldn't login\n"; wait; return 1
+	    } -nocase "unknown host\r\n" {
+		catch {close};
+		send_user "\nError: Unknown host\n"; wait; return 1
+	    } "Host is unreachable" {
+		catch {close};
+		send_user "\nError: Host Unreachable!\n"; wait; return 1
+	    } "No address associated with name" {
+		catch {close};
+		send_user "\nError: Unknown host\n"; wait; return 1
+	    }
+	    "Login incorrect" {
+			  send_user "\nError: Check your password for $router\n"
+			  catch {close}; wait; return 1
+			}
+	    -re "Enter passphrase.*: " {
+		# sleep briefly to allow time for stty -echo
+		sleep 1
+		send "$passphrase\r"
+		exp_continue }
+	    -re "(Host key not found |The authenticity of host .* be established).*\(yes\/no\)\?" {
+		send "yes\r"
+		send_user "\nHost $router added to the list of known hosts.\n"
+		exp_continue }
+	    -re "HOST IDENTIFICATION HAS CHANGED.* \(yes\/no\)\?"	{
+		send "no\r"
+		send_user "\nError: The host key for $router has changed.  Update the SSH known_hosts file accordingly.\n"
+		return 1 }
+	    -re "Offending key for .* \(yes\/no\)\?"   {
+		send "no\r"
+		send_user "\nError: host key mismatch for $router.  Update the SSH known_hosts file accordingly.\n"
+		return 1 }
+	    -re "(Username|\[\r\n]login):"	{
+						  send "$user\r"
+						  exp_continue
+	    					}
+	    "\[Pp]assword:"			{
+						  sleep 1; send "$passwd\r"
+						  exp_continue
+						}
+	    -re "$prompt"		{ break; }
+	    denied	{ send_user "\nError: Check your password for $router\n"
+	                  catch {close}; wait; return 1
+	                }
+	}
+    }
+
+    # we are logged in, now figure out the full prompt
+    send "\r"
+    expect {
+	-re "(\r\n|\n)"		{ exp_continue; }
+	-re "^\r*(\[^\r\n]*$prompt)"	{ set prompt $expect_out(1,string);
+				}
+
+    }
+    set in_proc 0
+    return 0
+}
+
+# Run commands given on the command line.
+proc run_commands { prompt command } {
+    global in_proc
+    set in_proc 1
+
+    send "rows 0\r"
+    expect -exact "rows 0\r\n\r\n"
+    expect -exact $prompt	{}
+
+    match_max 100000
+
+    # Is this a multi-command?
+    if [ string match "*\;*" "$command" ] {
+	set commands [split $command \;]
+	set num_commands [llength $commands]
+
+	for {set i 0} {$i < $num_commands} { incr i} {
+	    send "[lindex $commands $i]\r"
+	    expect {
+		-exact "$prompt"		{}
+		-re "(\r\n|\n)"			{ exp_continue }
+            }
+	}
+    } else {
+	send "$command\r"
+	expect {
+		-exact "$prompt"		{}
+		-re "(\r\n|\n)"			{ exp_continue }
+	}
+    }
+    send "quit"
+    expect "quit"; # hackery or Fore device will kick us out before echoing
+    send "\r"
+    expect {
+	"\n" { exp_continue }
+	timeout { return 0 }
+	eof { return 0 }
+    }
+    set in_proc 0
+}
+
+#
+# For each router... (this is main loop)
+#
+source_password_file $password_file
+set in_proc 0
+foreach router [lrange $argv $i end] {
+    set router [string tolower $router]
+    send_user "$router\n"
+
+    set prompt ">"
+
+    # Figure out username
+    if {[info exists username]} {
+      # command line username
+      set loginname $username
+    } else {
+      set loginname [join [find user $router] ""]
+      if { "$loginname" == "" } { set loginname $default_user }
+    }
+
+    # Figure out loginname's password (if different from the vty password)
+    if {[info exists userpasswd]} {
+      # command line passwd
+      set passwd $userpasswd
+    } else {
+      set passwd [join [lindex [find userpassword $router] 0] ""]
+      if { "$passwd" == "" } {
+        set passwd [join [lindex [find password $router] 0] ""]
+        if { "$passwd" == "" } {
+	  send_user "\nError: no password for $router in $password_file.\n"
+	  continue
+        }
+      }
+    }
+
+    # Figure out identity file to use
+    set identfile [join [lindex [find identity $router] 0] ""]
+
+    # Figure out passphrase to use
+    if {[info exists avpassphrase]} {
+	set passphrase $avpassphrase
+    } else {
+	set passphrase [join [lindex [find passphrase $router] 0] ""]
+    }
+    if { ! [string length "$passphrase"]} {
+	set passphrase $passwd
+    }
+
+    # Figure out ssh cypher type
+    if {[info exists cypher]} {
+      # command line ssh cypher type
+      set cyphertype $cypher
+    } else {
+      set cyphertype [find cyphertype $router]
+      if { "$cyphertype" == "" } { set cyphertype "3des" }
+    }
+
+    # Figure out connection method
+    set cmethod [find method $router]
+    if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} }
+
+    # Figure out the SSH executable name  
+    set sshcmd [find sshcmd $router]  
+    if { "$sshcmd" == "" } { set sshcmd {ssh} }  
+
+    # Login to the router
+    if {[login $router $loginname $passwd $cmethod $cyphertype $identfile]} {
+	continue
+    }
+
+    if { $do_command } {
+	if {[run_commands $prompt $command]} {
+	    continue
+	}
+    } elseif { $do_script } {
+	send "set cli complete-on-space off\r"
+	expect -re $prompt	{}
+	send "set cli screen-length 0\r"
+	expect -re $prompt	{}
+	source $sfile
+	close
+    } else {
+	label $router
+	log_user 1
+	interact
+    }
+
+    # End of for each router
+    wait
+    sleep 0.3
+}
+exit 0
diff -Nur rancid-2.3.1-local-p4/bin/forerancid.in rancid-2.3.1-local-p5/bin/forerancid.in
--- rancid-2.3.1-local-p4/bin/forerancid.in	1969-12-31 19:00:00.000000000 -0500
+++ rancid-2.3.1-local-p5/bin/forerancid.in	2005-08-16 01:23:54.000000000 -0400
@@ -0,0 +1,361 @@
+#! @PERLV_PATH@
+##
+## $Id: jrancid.in,v 1.61 2004/06/05 04:02:08 asp Exp $
+##
+## Copyright (C) 1997-2004 by Terrapin Communications, Inc.
+## All rights reserved.
+##
+## This software may be freely copied, modified and redistributed
+## without fee for non-commerical purposes provided that this license
+## remains intact and unmodified with any RANCID distribution.
+##
+## There is no warranty or other guarantee of fitness of this software.
+## It is provided solely "as is".  The author(s) disclaim(s) all
+## responsibility and liability with respect to this software's usage
+## or its effect upon hardware, computer systems, other software, or
+## anything else.
+##
+## Except where noted otherwise, rancid was written by and is maintained by
+## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz.
+##
+#
+# Amazingly hacked version of Hank's rancid - this one tries to
+# deal with Marconis
+#
+#  RANCID - Really Awesome New Cisco confIg Differ
+#
+# usage: jrancid [-d] [-l] [-f filename | $host]
+#
+use Getopt::Std;
+getopts('dfl');
+$debug = $opt_d;
+$log = $opt_l;
+$file = $opt_f;
+$host = $ARGV[0];
+
+$clean_run = 0;
+$found_end = 0;
+
+my(%filter_pwds);		# password filtering mode
+
+# This routine is used to print out the router configuration
+sub ProcessHistory {
+    my($new_hist_tag,$new_command,$command_string,@string)=(@_);
+    if((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
+       && defined %history) {
+	print eval "$command \%history";
+	undef %history;
+    }
+    if (($new_hist_tag) && ($new_command) && ($command_string)) {
+	if ($history{$command_string}) {
+	    $history{$command_string} = "$history{$command_string}@string";
+	} else {
+	    $history{$command_string} = "@string";
+	}
+    } elsif (($new_hist_tag) && ($new_command)) {
+	$history{++$#history} = "@string";
+    } else {
+	print "@string";
+    }
+    $hist_tag = $new_hist_tag;
+    $command = $new_command;
+    1;
+}
+
+sub numerically { $a <=> $b; }
+
+# This is a sort routing that will sort numerically on the
+# keys of a hash as if it were a normal array.
+sub keynsort {
+    local(%lines)=@_;
+    local($i) = 0;
+    local(@sorted_lines);
+    foreach $key (sort numerically keys(%lines)) {
+	$sorted_lines[$i] = $lines{$key};
+	$i++;
+    }
+    @sorted_lines;
+}
+
+# This is a sort routing that will sort on the
+# keys of a hash as if it were a normal array.
+sub keysort {
+    local(%lines)=@_;
+    local($i) = 0;
+    local(@sorted_lines);
+    foreach $key (sort keys(%lines)) {
+	$sorted_lines[$i] = $lines{$key};
+	$i++;
+    }
+    @sorted_lines;
+}
+
+# This is a sort routing that will sort on the
+# values of a hash as if it were a normal array.
+sub valsort{
+    local(%lines)=@_;
+    local($i) = 0;
+    local(@sorted_lines);
+    foreach $key (sort values %lines) {
+        $sorted_lines[$i] = $key;
+        $i++;
+    }
+    @sorted_lines;
+}
+
+# This is a numerical sort routing (ascending).
+sub numsort {
+    local(%lines)=@_;
+    local($i) = 0;
+    local(@sorted_lines);
+    foreach $num (sort {$a <=> $b} keys %lines) {
+	$sorted_lines[$i] = $lines{$num};
+	$i++;
+    }
+    @sorted_lines;
+}
+
+# This is a sort routine that will sort on the
+# ip address when the ip address is anywhere in
+# the strings.
+sub ipsort {
+    local(%lines)=@_;
+    local($i) = 0;
+    local(@sorted_lines);
+    foreach $addr (sort sortbyipaddr keys %lines) {
+	$sorted_lines[$i] = $lines{$addr};
+	$i++;
+    }
+    @sorted_lines;
+}
+
+# These two routines will sort based upon IP addresses
+sub ipaddrval {
+    my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
+    $a[3]+256*($a[2]+256*($a[1]+256*$a[0]));
+}
+sub sortbyipaddr {
+    &ipaddrval($a) <=> &ipaddrval($b);
+}
+
+###
+### Start of real work
+###
+
+# This routine parses "show chassis clocks"
+# This routine parses "system filesystem dir"
+sub SystemFilesystemDir {
+    print STDERR "    In SystemFilesystemDir: $_" if ($debug);
+
+    s/^.*>\s*(.*)/Output of $1:/;
+    ProcessHistory("","","","# $_");
+    while (<INPUT>) {
+	tr/\015//d;
+	last if(/^$prompt/);
+
+	ProcessHistory("","","","# $_");
+    }
+    return;
+}
+
+# This routine parses assorted hardware show commands
+sub HardwareShow {
+    print STDERR "    In ShowChassisFirmware: $_" if ($debug);
+
+    s/^.*>\s*(.*)/Output of $1:/;
+    ProcessHistory("","","","# $_");
+    while (<INPUT>) {
+	tr/\015//d;
+	last if(/^$prompt/);
+
+	ProcessHistory("","","","# $_");
+    }
+    return;
+}
+
+# This routine parses "system batch show"
+sub SystemBatchShow {
+    my($lines) = 0;
+    my($snmp) = 0;
+    print STDERR "    In SystemBatchShow: $_" if ($debug);
+
+    s/^.*>\s*(.*)/Output of $1:/;
+    ProcessHistory("","","","# $_");
+    while (<INPUT>) {
+	tr/\015//d;
+        # end of config - hopefully.  fore does not have a reliable
+	# end-of-config tag.  appears to end with "\n", but not sure.
+	if(/^$/) {
+	    $found_end++;
+	    last;
+	}
+	$lines++;
+
+	# filter snmp community when appropriate
+	if (/^(security login new )(.*)( snmp community .*)$/) {
+		if (defined($ENV{'NOCOMMSTR'})) {
+		    $_ = "$1\"<removed>\"$3\n";
+		}
+	}
+	if (/^(security login _rawpassword new \S+ )\S+$/ && $filter_pwds >= 2) {
+	    ProcessHistory("","","","$1<removed>$'");
+	    next;
+	}
+	ProcessHistory("","","","$_");
+    }
+
+    if ($lines < 3) {
+	printf(STDERR "ERROR: $host configuration appears truncated.\n");
+	$found_end = 0;
+	return(-1);
+    }
+
+    return;
+}
+
+###
+### End of real work
+###
+
+# dummy function
+sub DoNothing {print STDOUT;}
+
+# Main
+%commands=(
+	"system filesystem dir"         => "SystemFilesystemDir",
+	"hardware cecplus show"		=> "HardwareShow",
+	"hardware chassis"     		=> "HardwareShow",
+	"hardware dualscp show"		=> "HardwareShow",
+	"hardware fabric show" 		=> "HardwareShow",
+	"hardware fans"        		=> "HardwareShow",
+	"hardware netmod show" 		=> "HardwareShow",
+	"hardware port show"   		=> "HardwareShow",
+	"hardware power"       		=> "HardwareShow",
+	"hardware scp show"    		=> "HardwareShow",
+	"hardware temperature" 		=> "HardwareShow",
+	"interface ip show"    		=> "HardwareShow",
+	"interface if show"    		=> "HardwareShow",
+	"system batch show" 		=> "SystemBatchShow",
+);
+@commands=(
+	"system filesystem dir",
+	"hardware cecplus show",
+	"hardware chassis",
+	"hardware dualscp show",
+	"hardware fabric show",
+	"hardware fans",
+	"hardware netmod show",
+	"hardware port show",
+	"hardware power",
+	"hardware temperature",
+	"hardware scp show",
+	"interface ip show",
+	"interface if show",
+	"system batch show",
+);
+
+$fore_commands=join(";",@commands);
+$cmds_regexp=join("|",@commands);
+
+open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
+select(OUTPUT);
+# make OUTPUT unbuffered
+if ($debug) { $| = 1; }
+
+if ($file) {
+    print STDERR "opening file $host\n" if ($debug);
+    print STDOUT "opening file $host\n" if ($log);
+    open(INPUT,"< $host") || die "open failed for $host: $!\n";
+} else {
+    print(STDERR "executing echo forelogin -c\"$fore_commands\" $host\n") if ($debug);
+    print(STDOUT "executing echo forelogin -c\"$fore_commands\" $host\n") if ($debug);
+
+    if (defined($ENV{NOPIPE})) {
+	system "forelogin -c \"$fore_commands\" $host </dev/null > $host.raw" || die "forelogin failed for $host: $!\n";
+	open(INPUT, "< $host.raw") || die "forelogin failed for $host: $!\n";
+    } else {
+	open(INPUT,"forelogin -c \"$fore_commands\" $host </dev/null |") || die "forelogin failed for $host: $!\n";
+    }
+
+}
+
+# determine password filtering mode
+if ($ENV{"FILTER_PWDS"} =~ /no/i) {
+	$filter_pwds = 0;  
+} elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
+	$filter_pwds = 2;
+} else {
+	$filter_pwds = 1;
+}
+
+ProcessHistory("","","","# RANCID-CONTENT-TYPE: fore\n#\n");
+TOP: while(<INPUT>) {
+    tr/\015//d;
+    if (/^Error:/) {
+	print STDOUT ("$host forelogin error: $_");
+	print STDERR ("$host forelogin error: $_") if ($debug);
+	$clean_run=0;
+	last;
+    }
+    if (/System shutdown message/) {
+	print STDOUT ("$host shutdown msg: $_");
+	print STDERR ("$host shutdown msg: $_") if ($debug);
+	$clean_run = 0;
+	last;
+    }
+    if (/error: cli version does not match Managment Daemon/i) {
+	print STDOUT ("$host mgd version mismatch: $_");
+	print STDERR ("$host mgd version mismatch: $_") if ($debug);
+	$clean_run = 0;
+	last;
+    }
+    while (/>\s*($cmds_regexp)\s*$/) {
+	$cmd = $1;
+	if (!defined($prompt)) {
+	    $prompt = ($_ =~ /^([^>]+>)/)[0];
+	    $prompt =~ s/([][}{)(\\])/\\$1/g;
+	    print STDERR ("PROMPT MATCH: $prompt\n") if ($debug);
+	}
+	print STDERR ("HIT COMMAND:$_") if ($debug);
+	if (! defined($commands{$cmd})) {
+	    print STDERR "$host: found unexpected command - \"$cmd\"\n";
+	    $clean_run = 0;
+	    last TOP;
+	}
+	$rval = &{$commands{$cmd}};
+	delete($commands{$cmd});
+	if ($rval == -1) {
+	    $clean_run = 0;
+	    last TOP;
+	}
+    }
+    if (/>\s*quit/) {
+	$clean_run=1;
+	last;
+    }
+}
+print STDOUT "Done forelogin: $_\n" if ($log);
+# Flush History
+ProcessHistory("","","","");
+# Cleanup
+close(INPUT);
+close(OUTPUT);
+
+if (defined($ENV{NOPIPE})) {
+    unlink("$host.raw") if (! $debug);
+}
+
+# check for completeness
+$commands = join(", ", keys(%commands));
+if (scalar(%commands) || !$clean_run || !$found_end) {
+    if (scalar(%commands)) {
+	printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
+	printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
+    }
+    if (!$clean_run || !$found_end) {
+	print STDOUT "$host: End of run not found\n";
+	print STDERR "$host: End of run not found\n" if ($debug);
+	system("/usr/bin/tail -1 $host.new");
+    }
+    unlink "$host.new" if (! $debug);
+}
diff -Nur rancid-2.3.1-local-p4/bin/rancid-fe.in rancid-2.3.1-local-p5/bin/rancid-fe.in
--- rancid-2.3.1-local-p4/bin/rancid-fe.in	2004-01-10 22:49:13.000000000 -0500
+++ rancid-2.3.1-local-p5/bin/rancid-fe.in	2005-08-16 01:24:46.000000000 -0400
@@ -37,6 +37,7 @@
 elsif ($vendor =~ /^erx$/i)		{ exec('jerancid', $router); }
 elsif ($vendor =~ /^extreme$/i)		{ exec('xrancid', $router); }
 elsif ($vendor =~ /^ezt3$/i)		{ exec('erancid', $router); }
+elsif ($vendor =~ /^fore$/i)		{ exec('forerancid', $router); }
 elsif ($vendor =~ /^force10$/i)		{ exec('f10rancid', $router); }
 elsif ($vendor =~ /^foundry$/i)		{ exec('francid', $router); }
 elsif ($vendor =~ /^hitachi$/i)		{ exec('htrancid', $router); }
