From: Bowyer Jeff <jbowyer@cis.vutbr.cs>
To: libes@cme.nist.gov (Don Libes)
Subject: expect Program #2
Date: Thu, 8 Apr 1993 15:18:42 +0200 (MET DST)

On our anonymous ftp server, we also decided to create a directory that
mirrors all rfc files at nic.ddn.mil.

Consequently, I wrote the following expect program to get new files and
delete obsoleted files.

Jeff

*========================================================================*
 Jeff Bowyer                         EMail: 
 Computing Center		     jbowyer@cis.vutbr.cs
 Technical University of Brno
 Udolni 19, 602 00 BRNO
 Czech Republic
*========================================================================*


THE MAIN SHELL PROGRAM
----------------------------------------------------------------------
MDIR=/users/jbowyer/maint
RDIR=/users/ftp/pub/doc/rfc

expect $MDIR/mirror nic.ddn.mil rfc $RDIR
case $? in
1)	currmin=`date +%M`
	currhour=`date +%H`
	nextmin=`expr $currmin + 15`
	nexthour=$currhour
	if test $nextmin -ge 60
	then
		nexthour=`expr $nexthour + 1`
		nextmin=`expr $nextmin - 60`
	fi
	if test $nexthour -eq 24
	then
		nexthour=0
	fi
	at $nexthour:$nextmin $MDIR/rfcmirror ;;
esac
----------------------------------------------------------------------


THE EXPECT PROGRAM
----------------------------------------------------------------------
match_max -d 100000		;# max size of a directory listing

set destdir "nodir"
set fname "nofile"

set currmonth 0
set curryear 0

set mday 0
set mmonth 0
set myear 0

set localrfcs ""
set needrfcs ""

proc initexpect {} {
	expect_before {
        	        -re "unreachable*" {
                	                     exit 1
                        	           }
	                -re "closed connection*" {
						   exec rm -f $destdir/$fname
                	                           exit 1
                        	                 }
	                -re "Connection timed out*" {
						      exec rm -f $destdir/$fname
						      send "quit\r"
                        	                      exit 1
                                	            }
	                timeout	{
			          exec rm -f $destdir/$fname
				  send "quit\r"
				  exit 1 
	                        }
        	        eof {
	        	      exec rm -f $destdir/$fname
	                      exit 1
        	            }
	              }
}

proc getname {line} {
	# if it's a symbolic link, return local name
	set i [lsearch line "->"]
	if {-1==$i} {
	     # not a sym link
	     # return last token of line as name, and strip off newline at end
	     return [lindex $line 8]
	} else {
	     # sym link, return "a" of "a -> b"
	     return [lindex $line [expr $i-1]]
	}
}

proc getmonth {line} {
	set fmonth [lindex $line [expr [llength $line]-4]]
        return [expr [lsearch {Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec} $fmonth]+1]
}

proc getday {line} {
	return [lindex $line [expr [llength $line]-3]]
}

proc getyear {line fmonth} {
	global currmonth curryear
	
	set fyear [lindex $line [expr [llength $line]-2]]
	if [regexp ".*:.*" $fyear] {
		if {$fmonth>$currmonth} {
			return [expr $curryear-1]
		} else {
			return $curryear
	        }	
	} else {
		return $fyear
	}
}

proc buildllist {thedir} {
	global fname localrfcs

	send "anonymous\r"
	expect {
        	 -re "Password:*"
	       }
	send "jbowyer@cis.vutbr.cs\r"
	expect {
        	 "ok*ftp>*"
	       }
	send "cd $thedir\r"
	expect {
         	 "CWD*success*" {
               	           	  continue -expect
                               	}
	         "ftp>*"
	       }
	send "dir\r"
	expect {
        	 "ftp>*"
	       }

	set buf $expect_out(buffer)\n
	close

	for {} 1 {}	{
		set split_buf [split $buf ""]

		set i [string first "\n" $buf]
		set line [join [lrange $split_buf 0 $i] ""]
		set buf [join [lrange $split_buf [expr 1+$i] end] ""]

		set token [lindex $line 0]
		case $token in	{
			dir\r	{
					# original command
				}
			200	{
					# command successful
				}
			150	{
					# opening data connection
				}
			total	{
					# directory header
				}
			226	{
					# transfer complete, succeeded!
				}
			ftp>	{
					return 1
				}
			.	{
					# unreadable
				}
			default {
					# either file or directory
					set fname [getname $line]
					if [regexp -nocase "^rfc0|^rfc1|^rfc2|^rfc3|^rfc4|^rfc5|^rfc6|^rfc7|^rfc8|^rfc9" $fname] {
					  set lday [getday $line]
					  set lmonth [getmonth $line]
					  set lyear [getyear $line $lmonth]
					  lappend localrfcs [list $fname $lday $lmonth $lyear]
					}
				}
				}
		}
	return 0
}

proc buildrlist {thedir} {
	global fname masterrfcs

	send "anonymous\r"
	expect {
        	 -re "Password:*"
	       }
	send "jbowyer@cis.vutbr.cs\r"
	expect {
        	 "ok*ftp>*"
	       }
	send "cd $thedir\r"
	expect {
         	 "CWD*success*" {
               	           	  continue -expect
                               	}
	         "ftp>*"
	       }
	send "dir\r"
	expect {
        	 "ftp>*"
	       }

	set buf $expect_out(buffer)\n
	close

	for {} 1 {}	{
		set split_buf [split $buf ""]

		set i [string first "\n" $buf]
		set line [join [lrange $split_buf 0 $i] ""]
		set buf [join [lrange $split_buf [expr 1+$i] end] ""]

		set token [lindex $line 0]
		case $token in	{
			dir\r	{
					# original command
				}
			200	{
					# command successful
				}
			150	{
					# opening data connection
				}
			total	{
					# directory header
				}
			226	{
					# transfer complete, succeeded!
				}
			ftp>	{
					return 1
				}
			.	{
					# unreadable
				}
			default {
					# either file or directory
					set fname [getname $line]
					if [regexp -nocase "^rfc0|^rfc1|^rfc2|^rfc3|^rfc4|^rfc5|^rfc6|^rfc7|^rfc8|^rfc9" $fname] {
					  set lday [getday $line]
					  set lmonth [getmonth $line]
					  set lyear [getyear $line $lmonth]
					  lappend masterrfcs [list $fname $lday $lmonth $lyear]
					}
				}
				}
		}
	return 0
}

proc getmasterdates {} {
	global masterfile mday mmonth myear

	set mday [expr [lindex $masterfile 1]]
	set mmonth [expr [lindex $masterfile 2]]
	set myear [expr [lindex $masterfile 3]]
}

proc newmaster {} {
	global masterfile mday mmonth myear localfile

	getmasterdates

	set lday [expr [lindex $localfile 1]]
	set lmonth [expr [lindex $localfile 2]]
	set lyear [expr [lindex $localfile 3]]

	if $myear>$lyear {
	  return 1
	} else {
	  if $myear==$lyear {
	    if $mmonth>$lmonth {
	      return 1
	    } else {
	      if $mmonth==$lmonth {
		if $mday>$lday {
		  return 1
		}
	      }
	    }
	  }
	}
	return 0
}

proc getrfile {} {
	global destdir fname needfile mday mmonth myear
	
        set fname [lindex $needfile 0]
	
	send "get $fname\r"
	expect {
                 "ftp>*"
               }
	exec chmod "666" $destdir/$fname
	set touchstr [format "%02d%02d0000%s" $mmonth $mday [string range $myear 2 end]]
	exec touch $touchstr $destdir/$fname
	exec chmod "444" $destdir/$fname
}

log_file /users/jbowyer/maint/logs/rfclog

set destdir [lindex $argv 3]

set currmonth [exec date +%m]
set curryear [exec date +%Y]

set timeout 900

spawn ftp rhino.cis.vutbr.cs
initexpect
expect {
	 -re "unknown host"	{
 				  exit 1
				}
         -re "unreachable*"	{
				  exit 1
				}
         -re "Name*"
       }
if [buildllist "pub/doc/rfc"] {
	spawn ftp [lindex $argv 1]
	initexpect
	expect {
		 -re "unknown host"	{
	 				  exit 1
					}
	         -re "unreachable*"	{
					  exit 1
					}
	         -re "Name*"
	       }
	if [buildrlist [lindex $argv 2]] {
		foreach masterfile $masterrfcs {
			set foundrfc 0
			foreach localfile $localrfcs {
				if 0==[string compare [lindex $masterfile 0] [lindex $localfile 0]] {
					if [newmaster] {
						lappend needrfcs $masterfile
					}
					set localindex [lsearch $localrfcs $localfile]
					set localrfcs [concat [lrange $localrfcs 0 [expr $localindex-1]] [lrange $localrfcs [expr $localindex+1] end]]

					set foundrfc 1
					break
				}
			}
			if !$foundrfc {
				lappend needrfcs $masterfile
			}
		}
		if [llength $localrfcs]>0 {
			foreach killfile $localrfcs {
				exec rm -f $destdir/[lindex $killfile 0]
			}
		}
		if [llength $needrfcs]>0 {
			spawn ftp [lindex $argv 1]
			initexpect
			expect {
				 -re "unknown host"	{
	 						  exit 1
							}
			         -re "unreachable*"	{
							  exit 1
							}
			         -re "Name*"
			       }
			send "anonymous\r"
			expect {
        			 -re "Password:*"
			       }
			send "jbowyer@cis.vutbr.cs\r"
			expect {
        			 "ok*ftp>*"
			       }
			send "cd [lindex $argv 2]\r"
			expect {
	        	 	 "CWD*success*" {
        	       		           	  continue -expect
                	        	       	}
		        	 "ftp>*"
			       }
			send "binary\r"
			expect {
		                 "ftp>*"
		               }
			send "hash\r"
			expect {
		                 "ftp>*"
		               }
			send "lcd $destdir\r"
			expect {
		                 "ftp>*"
		               }
			foreach needfile $needrfcs {
				getmasterdates
				getrfile
			}
		}
	}
}

exit 0
