#!/usr/local/bin/wermit +
;
; s y n c h r o n i z e
;
; Synchronizes parallel directory trees over a Telnet connection.
;
; Requires: C-Kermit 7.0 Beta.07 or later.
; Author:   F. da Cruz, Columbia University Kermit Project
;
; Command-line parameters:
;  1. Root of source directory tree on local computer.
;  2. Root of destination directory tree on target computer.
;  3. Hostname or address of target computer.
;  4. Username on target host
;  5. Password on target host
;
; Parameters 2-5 are prompted for if not suplied.
;
; This script synchronizes parallel directory trees on two computers
; over a Telnet connection.  The two computers need not be running the
; same operating system.  For example, any pair from { Win32, UNIX, VMS }
; can be chosen, as long as they are running the required C-Kermit
; version.
;
;  . For shell logins, the remote prompt is assumed to be "$ ".
;    Change as needed (or use IKSD login).
;
;  . The root directory on the target host must exist (easy to
;    change).
;
;  . The synchronization is in one direction only: the target
;    is updated from the source.
;
;  . Subdirectories are created as needed at the destination.
;
;  . Files that exist in the destination tree that do not also
;    exist in the source tree are deleted.
;
;  . Files are transferred in update mode; only the source files
;    that are newer than the corresponding destination files are
;    sent.
;
;  . Backup files (*.~*~) are not sent.  All other files are sent.
;
;  . The destination TCP port is hardwired (Telnet or IKSD).
;
;  . A regular connection is made, rather than a secure one.
;    The password is transmitted in the clear.  This can be fixed
;    by using a Kerberized or SRP-enabled C-Kermit build and then
;    slightly modifying this script.
;
; Limitations:
;
;  . Filenames containing spaces cause trouble.  Avoid them.
;
;  . Empty source directories are not replicated at the target.
;
;  . Special characters in command line options might need to be
;    quoted according to the rules of your shell.  Also note the
;    use \fcontents() around variables containing directory names;
;    this is to prevent recursive evaluation when the directory
;    name contains backslashes (e.g. C:\WINDOWS\SYSTEM).
;
;  . C-Kermit 7.0 Beta.08 and earlier issue various gratuitous
;    and/or misleading messages; this is a cosmetic problem only,
;    fixed in Beta.09.
;
; Begin by checking C-Kermit version:
;
define badversion echo Sorry - C-Kermit 7.0 or later required., exit
if not equal "\v(program)" "C-Kermit" badversion
if LLT \v(version) 70000 badversion

; Define usage and fatal error macros.

define usage exit 1 {
  Usage: sourcedir [ targetdir [ targethost [ username [ password ] ] ] ]
}
define giveup { bye, hangup, close, exit 1 {FATAL: \%1 (Connection closed)} }

; Runtime parameters...

.iksd = 0                              ; Set to nonzero to use IKSD.
.debug = 0                             ; Set to nonzero for debug messages.

; Command-line parsing...

if not def \%1 usage                   ; Give usage message if no arguments.
cd \fcontents(\%1)                     ; Change to source directory
if fail exit 1 Can't CD to "\fcontents(\%1)" ; Failure is fatal

while not def \%3 {                    ; If hostname/address not supplied
    ask \%1 { Host: }                  ; prompt for one until we get it.
    if > \fsplit(\%3) 1 {              ; Allow only one "word" here.
        echo Just the address please.  ; E.g. no TCP port number.
        undef \%3
    }
}
while not def \%2 {                    ; If target directory not supplied
    ask \%2 { Directory on \%3: }      ; ask til we get it.
}
if not def \%4 {                       ; If username not supplied
    ask \%4 { User [\v(user)]: }       ; Prompt for one, but default
    if not def \%4 assign \%4 \v(user) ; to local user ID.
}
while not defined \%5 {                ; Ditto for password
    askq \%5 { Password for \%4 at \%3: }
}
set telnet environment user \%4        ; Make sure correct userid is sent
set exit warning off                   ; No "OK to exit?" prompts please

; This script assumes that authenticated logins are not being performed
; via Kerberos, SRP, or any other supported method.  It can easily be
; modified to use Kerberos or SRP.

set telopt start-tls refuse            ; Do not use START_TLS option
set telopt authentication refuse       ; Do not use AUTH option
set telopt encrypt refuse refuse       ; Do not use ENCRYPT option

if \m(debug) {
    echo Source directory: \fcontents(\%1)
    echo Target directory: \fcontents(\%2)
    echo Target host:      \fcontents(\%3)
    echo User at host:     \fcontents(\%4)
    echo IKSD:             \m(iksd)
    set input echo on
} else {
    set input echo off
    set quiet on
}

if \m(iksd) {                          ; IKSD...
    echo Connecting to \%3:kermit...
    set host \%3 1649 /telnet
    if fail exit 1 Can't open connection to iksd@\%3.
    remote login \%4 \%5
    if fail exit 1 Authentication failure
} else {                               ; Regular shell login
    echo Connecting to \%3:telnet...
    set host \%3 23 /telnet
    if fail exit 1 Can't open Telnet connection to \%3.
    minput 20 login: Username: Password: {Password for \%3:}
    if fail exit 1 Timed out waiting for initial prompt: \v(inwait) sec.
    if ( = \v(minput) 1 || = \v(minput) 2 ) {
	lineout \%4                    ; User ID required - send it.
	minput 10 Password: {Password for \%4:}
	if fail exit 1 Timed out waiting for Password prompt: \v(inwait) sec.
    }
    lineout \%5                        ; Send password
    undef \%5                          ; Erase password from memory
    input 60 {$ }                      ; *** Wait for shell prompt ***
    if fail echo WARNING: No shell prompt ;  But ignore failure
    lineout kermit -x                     ;  Start Kermit server
    input 30 READY TO SERVE...            ;  Courtesy but not necessary
}

; Have a connection with Kermit server on the far end.
; The rest is easy...

.m1 := Can't CD to remote directory "\fcontents(\%2)"
.m2 := WARNING: Update mode not negotiated - performing full transfer...

set transfer bell off                  ; Silence the bell
set transfer display brief             ; Skip the fullscreen display.

rcd \fcontents(\%2)                    ; CD to remote target directory.
if fail giveup {\m(m1)}                ; Failure is fatal
rset file collision update             ; Use update mode (only send new files)
rset server cd-message off             ; We don't need orientation messages
if fail echo {\m(m2)}                  ; Failure is not fatal
echo
send /recursive /nobackup *            ; Send the source tree
if fail giveup {SEND failed}           ; Update failed

; Delete all files at the remote that do not exist locally...

;;; forward fin                        ; Uncomment to skip deletion phase

echo
echo DELETION PHASE: Searching \%3:\fcontents(\%2)...
echo
query kermit rfiles(*)                 ; Get recursive remote file list
if fail giveup {QUERY failed}
.\%n := \v(query)                      ; How many in list
.\%m = 0                               ; How many deleted
if \m(debug) echo REMOTE FILES = \%n   ; Debug message
for \%i 1 \%n 1 {                      ; Loop through remote files
    query kermit nextfile()            ; Next one
    if \m(debug) echo \%i. \v(query)
    if not exist \v(query) {           ; If it doesn't exist on this end...
        rdelete \v(query)              ; Delete the one on the far end
        if success increment \%m       ; Count it if deletion successful
    }
}
if \%m echo
echo DELETED: \%m                      ; Say how many were deleted

:FIN
bye                                    ; Close the server
exit 0                                 ; Update succeeded - done
