about summary refs log tree commit diff
path: root/Functions/Zftp/zfuget
blob: 482da42e921d813a80c28186de9ec4708992b25a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# function zfuget {
# Get a list of files from the server with update.
# In other words, only retrieve files which are newer than local
# ones.  This depends on the clocks being adjusted correctly
# (i.e. if one is fifteen minutes out, for the next fifteen minutes
# updates may not be correctly calculated).  However, difficult
# cases --- where the files are the same size, but the remote is newer,
# or have different sizes, but the local is newer -- are prompted for.
#
# Files are globbed on the remote host --- assuming, of course, they
# haven't already been globbed local, so use 'noglob' e.g. as
# `alias zfuget="noglob zfuget"'.
#
# Options:
#  -G    Glob:     turn off globbing
#  -v    verbose:  print more about the files listed.
#  -s    silent:   don't ask, just guess.  The guesses are:
#                - if the files have different sizes but remote is older ) grab
#                - if they have the same size but remote is newer        )
#                  which is safe if the remote files are always the right ones.
#   -t   time:     update the local file times to the same time as the remote.
#                  Currently this only works if you have the `perl' command,
#                  and that perl is version 5 with the standard library.
#                  See the function zfrtime for more gory details.

emulate -L zsh

local loc rem locstats remstats doit tmpfile=${TMPPREFIX}zfuget$$
local rstat remlist verbose optlist opt bad i silent nglob time
integer stat do_close

zfuget_print_time() {
  local tim=$1
  print -n "$tim[1,4]/$tim[5,6]/$tim[7,8] $tim[9,10]:$tim[11,12].$tim[13,14]"
  print -n GMT
}

zfuget_print () {
  print -n "\nremote $rem ("
  zfuget_print_time $remstats[2]
  print -n ", $remstats[1] bytes)\nlocal $loc ("
  zfuget_print_time $locstats[2]
  print ", $locstats[1] bytes)"
}

while [[ $1 = -* ]]; do
  if [[ $1 = - || $1 = -- ]]; then
    shift;
    break;
  fi
  optlist=${1#-}
  for (( i = 1; i <= $#optlist; i++)); do
    opt=$optlist[$i]
    case $optlist[$i] in
      v) verbose=1
	 ;;
      s) silent=1
	 ;;
      G) nglob=1
	 ;;
      t) time=1
	 ;;
      *) print option $opt not recognised >&2
	 ;;
    esac
  done
  shift
done

[[ -n $bad ]] && return 1

zfautocheck

for remlist in $*; do
  # zfcd directory hack to put the front back to ~
  if [[ $remlist == $HOME || $remlist == $HOME/* ]]; then
    remlist="~${remlist#$HOME}"
  fi
  if [[ $nglob != 1 ]]; then
    zfrglob remlist
  fi
  if (( $#remlist )); then
    for rem in $remlist; do
      loc=${rem:t}
      doit=y
      remstats=()
      if [[ -f $loc ]]; then
	zftp local $loc >$tmpfile
	locstats=($(<$tmpfile))
	zftp remote $rem >$tmpfile
	rstat=$?
	remstats=($(<$tmpfile))
	rm -f $tmpfile
	if [[ $rstat = 2 ]]; then
	  print "Server does not implement full command set required." 1>&2
	  return 1
	elif [[ $rstat = 1 ]]; then
	  print "File not found on server: $rem" 1>&2
	  stat=1
	  continue
	fi
	[[ $verbose = 1 ]] && zfuget_print
	if (( $locstats[1] != $remstats[1] )); then
	  # Files have different sizes
	  if [[ $locstats[2] > $remstats[2] && $silent != 1 ]]; then
	    [[ $verbose != 1 ]] && zfuget_print
	    print "Local file $loc more recent than remote," 1>&2
	    print -n "but sizes are different.  Transfer anyway [y/n]? " 1>&2
	    read -q doit
	  fi
	else
	  # Files have same size
	  if [[ $locstats[2] < $remstats[2] ]]; then
	    if [[ $silent != 1 ]]; then
	      [[ $verbose != 1 ]] && zfuget_print
	      print "Local file $loc has same size as remote," 1>&2
	      print -n "but local file is older. Transfer anyway [y/n]? " 1>&2
	      read -q doit
	    fi
	  else
	    # presumably same file, so don't get it.
	    [[ $verbose = 1 ]] && print Not transferring
	    doit=n
	  fi
	fi
      else
	[[ $verbose = 1 ]] && print New file $loc
      fi
      if [[ $doit = y ]]; then
	if zftp get $rem >$loc; then
	  if [[ $time = 1 ]]; then
	    # if $remstats is set, it's second element is the remote time
	    zfrtime $loc $rem $remstats[2]
	  fi
	else
	  stat=$?
	fi
	
      fi
    done
  fi
done

(( do_close )) && zfclose

return $stat
# }