/home/lnzliplg/www/fish.tar
info000064400000001731151731340170005426 0ustar00LC_TIME=C
export LC_TIME
#FISH_HAVE_HEAD         1
#FISH_HAVE_SED          2
#FISH_HAVE_AWK          4
#FISH_HAVE_PERL         8
#FISH_HAVE_LSQ         16
#FISH_HAVE_DATE_MDYT   32
#FISH_HAVE_TAIL        64
res=0
if `echo yes| head -c 1 > /dev/null 2>&1` ; then
    res=`expr $res + 1`
fi
if `echo 1 | sed 's/1/2/' >/dev/null 2>&1` ; then
    res=`expr $res + 2`
fi
if `echo 1| awk '{print}' > /dev/null 2>&1` ; then
    res=`expr $res + 4`
fi
if `perl -v > /dev/null 2>&1` ; then
    res=`expr $res + 8`
fi
if `ls -Q / >/dev/null 2>&1` ; then
    res=`expr $res + 16`
fi
dat=`ls -lan / 2>/dev/null | head -n 3 | (
    while read p l u g s rec; do
      if [ -n "$g" ]; then
        if [ -n "$l" ]; then
          echo "$rec"
        fi
      fi
    done
)`
dat=`echo $dat | cut -c1 2>/dev/null`
r=`echo "0123456789"| grep "$dat"`
if [ -z "$r" ]; then
    res=`expr $res + 32`
fi
if `echo yes| tail -c +1 - > /dev/null 2>&1` ; then
    res=`expr $res + 64`
fi
echo $res
echo "### 200"
mkdir000064400000000157151731340200005574 0ustar00#MKD $FISH_FILENAME
if mkdir "/$FISH_FILENAME" 2>/dev/null; then
    echo "### 000"
else
    echo "### 500"
fi
chmod000064400000000223151731340200005552 0ustar00#CHMOD $FISH_FILEMODE $FISH_FILENAME
if chmod ${FISH_FILEMODE} "/${FISH_FILENAME}" 2>/dev/null; then
    echo "### 000"
else
    echo "### 500"
fi
README.fish000064400000014545151731340200006361 0ustar00
		FIles transferred over SHell protocol (V 0.0.3)
		~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This protocol was designed for transferring files over a remote shell
connection (rsh and compatibles). It can be as well used for transfers over 
rsh, and there may be other uses.

Client sends requests of following form:

#FISH_COMMAND
equivalent shell commands,
which may be multiline

Only fish commands are defined here, shell equivalents are for your
information only and will probably vary from implementation to
implementation. Fish commands always have priority: server is
expected to execute fish command if it understands it. If it does not,
however, it can try the luck and execute shell command.

Since version 4.7.3, the scripts that FISH sends to host machines after
a command is transmitted are no longer hardwired in the Midnight
Commander source code.

First, mc looks for system-wide set of scripts, then it checks whether
current user has host-specific overrides in his per-user mc
configuration directory. User-defined overrides take priority over
sytem-wide scripts if they exist. The order in which the directories are
traversed is as follows:

    /usr/libexec/mc/fish
    ~/.local/share/mc/fish/<hostname>/

Server's reply is multiline, but always ends with

### 000<optional text>

line. ### is prefix to mark this line, 000 is return code. Return
codes are superset to those used in ftp.

There are few new exit codes defined:

000 don't know; if there were no previous lines, this marks COMPLETE
success, if they were, it marks failure.

001 don't know; if there were no previous lines, this marks
PRELIMinary success, if they were, it marks failure

				Connecting
				~~~~~~~~~~
Client uses "echo FISH:;/bin/sh" as command executed on remote
machine. This should make it possible for server to distinguish FISH
connections from normal rsh/ssh.

				Commands
				~~~~~~~~
#FISH
echo; start_fish_server; echo '### 200'

This command is sent at the beginning. It marks that client wishes to
talk via FISH protocol. #VER command must follow. If server
understands FISH protocol, it has option to put FISH server somewhere
on system path and name it start_fish_server.

#VER 0.0.2 <feature1> <feature2> <...>
echo '### 000'

This command is the second one. It sends client version and extensions
to the server. Server should reply with protocol version to be used,
and list of extensions accepted.

VER 0.0.0 <feature2>
### 200

#PWD
pwd; echo '### 200'

Server should reply with current directory (in form /abc/def/ghi)
followed by line indicating success.

#LIST /directory
ls -lLa $1 | grep '^[^cbt]' | ( while read p x u g s m d y n; do echo "P$p $u.$g
S$s
d$m $d $y
:$n
"; done )
ls -lLa $1 | grep '^[cb]' | ( while read p x u g a i m d y n; do echo "P$p $u.$g
E$a$i
dD$m $d $y
:$n
"; done )
echo '### 200'

This allows client to list directory or get status information about
single file. Output is in following form (any line except :<filename>
may be omitted):

P<unix permissions> <owner>.<group>
S<size>
d<3-letters month name> <day> <year or HH:MM>
D<year> <month> <day> <hour> <minute> <second>[.1234]
E<major-of-device>,<minor>
:<filename>
L<filename symlink points to>
<blank line to separate items>

Unix permissions are of form X--------- where X is type of
file. Currently, '-' means regular file, 'd' means directory, 'c', 'b'
means character and block device, 'l' means symbolic link, 'p' means
FIFO and 's' means socket.

'd' has three fields: month (one of strings Jan Feb Mar Apr May Jun
Jul Aug Sep Oct Nov Dec), day of month, and third is either single
number indicating year, or HH:MM field (assume current year in such
case). As you've probably noticed, this is pretty broken; it is for
compatibility with ls listing.

#RETR /some/name
ls -l /some/name | ( read a b c d x e; echo $x ); echo '### 100'; cat /some/name; echo '### 200'

Server sends line with filesize on it, followed by line with ### 100
indicating partial success, then it sends binary data (exactly
filesize bytes) and follows them with (with no preceding newline) ###
200.

Note that there's no way to abort running RETR command - except
closing the connection.

#STOR <size> /file/name
> /file/name; echo '### 001'; ( dd bs=4096 count=<size/4096>; dd bs=<size%4096> count=1 ) 2>/dev/null | ( cat > %s; cat > /dev/null ); echo '### 200'

This command is for storing /file/name, which is exactly size bytes
big. You probably think I went crazy. Well, I did not: that strange
cat > /dev/null has purpose to discard any extra data which was not
written to disk (due to for example out of space condition).

[Why? Imagine uploading file with "rm -rf /" line in it.]

#CWD /somewhere
cd /somewhere; echo '### 000'

It is specified here, but I'm not sure how wise idea is to use this
one: it breaks stateless-ness of the protocol.

Following commands should be rather self-explanatory:

#CHMOD 1234 file
chmod 1234 file; echo '### 000'

#DELE /some/path
rm -f /some/path; echo '### 000'

#MKD /some/path
mkdir /some/path; echo '### 000'

#RMD /some/path
rmdir /some/path; echo '### 000'

#RENAME /path/a /path/b
mv /path/a /path/b; echo '### 000'

#LINK /path/a /path/b
ln /path/a /path/b; echo '### 000'

#SYMLINK /path/a /path/b
ln -s /path/a /path/b; echo '### 000'

#CHOWN user /file/name
chown user /file/name; echo '### 000'

#CHGRP group /file/name
chgrp group /file/name; echo '### 000'

#INFO
...collect info about host into $result ...
echo $result
echo '### 200'

#READ <offset> <size> /path/and/filename
cat /path/and/filename | ( dd bs=4096 count=<offset/4096> > /dev/null;
dd bs=<offset%4096> count=1 > /dev/null;
dd bs=4096 count=<offset/4096>;
dd bs=<offset%4096> count=1; )

Returns ### 200 on successful exit, ### 291 on successful exit when
reading ended at eof, ### 292 on successfull exit when reading did not
end at eof.

#WRITE <offset> <size> /path/and/filename

Hmm, shall we define these ones if we know our client is not going to
use them?

you can use follow parameters:
FISH_FILESIZE
FISH_FILENAME
FISH_FILEMODE
FISH_FILEOWNER
FISH_FILEGROUPE
FISH_FILEFROM
FISH_FILETO

NB:
'FISH_FILESIZE' used if we operate with single file name in 'unlink', 'rmdir', 'chmod', etc...
'FISH_FILEFROM','FISH_FILETO'  used if we operate with two files in 'ln', 'hardlink', 'mv' etc...
'FISH_FILEOWNER', 'FISH_FILEGROUPE' is a new user/group in chown

also flags:
FISH_HAVE_HEAD
FISH_HAVE_SED
FISH_HAVE_AWK
FISH_HAVE_PERL
FISH_HAVE_LSQ
FISH_HAVE_DATE_MDYT

That's all, folks!
						pavel@ucw.cz
unlink000064400000000162151731340200005762 0ustar00#DELE $FISH_FILENAME
if rm -f "/${FISH_FILENAME}" 2>/dev/null; then
    echo "### 000"
else
    echo "### 500"
fi
append000064400000000646151731340200005740 0ustar00#APPE $FISH_FILESIZE $FISH_FILENAME
FILENAME="/${FISH_FILENAME}"
echo "### 001"
{
    bss=4096
    bsl=4095
    if [ $FISH_FILESIZE -lt $bss ]; then
        bss=1;
        bsl=0;
    fi
    while [ $FISH_FILESIZE -gt 0 ]; do
        cnt=`expr \\( $FISH_FILESIZE + $bsl \\) / $bss`
        n=`dd bs=$bss count=$cnt | tee -a "${FILENAME}" | wc -c`
        FISH_FILESIZE=`expr $FISH_FILESIZE - $n`
    done
}; echo "### 200"
ln000064400000000273151731340200005076 0ustar00#SYMLINK $FISH_FILEFROM $FISH_FILETO
FILEFROM="${FISH_FILEFROM}"
FILETO="/${FISH_FILETO}"
if ln -s "${FILEFROM}" "${FILETO}" 2>/dev/null; then
   echo "### 000"
else
   echo "### 500"
fi
chown000064400000000254151731340200005602 0ustar00#CHOWN $FISH_FILEOWNER:$FISH_FILEGROUP $FISH_FILENAME
if chown ${FISH_FILEOWNER}:${FISH_FILEGROUP} "/${FISH_FILENAME}" ; then
    echo "### 000"
else
    echo "### 500"
fi
fexists000064400000000130151731340200006142 0ustar00#ISEXISTS $FISH_FILENAME
ls -l "/${FISH_FILENAME}" >/dev/null 2>/dev/null
echo '### '$?
rmdir000064400000000157151731340200005603 0ustar00#RMD $FISH_FILENAME
if rmdir "/${FISH_FILENAME}" 2>/dev/null; then
   echo "### 000"
else
   echo "### 500"
fi
ls000064400000011241151731340210005101 0ustar00#LIST /${FISH_DIR}
LC_TIME=C
export LC_TIME
perl_res="1"
fish_list_lsq ()
{
FISH_DIR="$1"
ls -Qlan "${FISH_DIR}" 2>/dev/null | grep '^[^cbt]' | (
while read p l u g s m d y n; do
    echo "P$p $u.$g"
    echo "S$s"
    echo "d$m $d $y"
    echo ":$n"
    echo
done
)

ls -Qlan "${FISH_DIR}" 2>/dev/null | grep '^[cb]' | (
while read p l u g a i m d y n; do
    echo "P$p $u.$g"
    echo "E$a$i"
    echo "d$m $d $y"
    echo ":$n"
    echo
done
)
echo '### 200'
}

fish_list_sed ()
{
FISH_DIR="$1"
ls -lan "${FISH_DIR}" 2>/dev/null | grep '^[^cbt]' | (
while read p l u g s rec; do
    if [ -n "$g" ]; then
        if [ -n "$FISH_HAVE_DATE_MDYT" ]; then
            filename=`echo "$rec"| sed 's/[^[:space:]]\+ \+[^[:space:]]\+ \+[^[:space:]]\+ //'`
            filedate=`echo "$rec"| sed 's/\([^[:space:]]\+ \+[^[:space:]]\+ \+[^[:space:]]\+\) .*/\1/'`
        else
            filename=`echo "$rec"| sed 's/[^[:space:]]\+ \+[^[:space:]]\+ //'`
            filedate=`echo "$rec"| sed 's/\([^[:space:]]\+ \+[^[:space:]]\+\) .*/\1/'`
        fi
        pfile=\"`echo "$filename" | sed -e 's#^\(.*\) -> \(.*\)#\1" -> "\2#'`\"
        echo "P$p $u.$g"
        echo "S$s"
        if [ -n "$FISH_HAVE_DATE_MDYT" ]; then
            echo "d$filedate"
        else
            echo "D$filedate"
        fi
        echo ":$pfile"
        echo
    fi
done
)
ls -lan "${FISH_DIR}" 2>/dev/null | grep '^[cb]' | (
while read p l u g a i rec; do
    if [ -n "$g" ]; then
        if [ -n "$FISH_HAVE_DATE_MDYT" ]; then
            filename=`echo "$rec"| sed 's/[^[:space:]]\+ \+[^[:space:]]\+ \+[^[:space:]]\+ //'`
            filedate=`echo "$rec"| sed 's/\([^[:space:]]\+ \+[^[:space:]]\+ \+[^[:space:]]\+\) .*/\1/'`
        else
            filename=`echo "$rec"| sed 's/[^[:space:]]\+ \+[^[:space:]]\+ //'`
            filedate=`echo "$rec"| sed 's/\([^[:space:]]\+ \+[^[:space:]]\+\) .*/\1/'`
        fi
        pfile=\"`echo "$filename" | sed -e 's#^\(.*\) -> \(.*\)#\1" -> "\2#'`\"
        echo "P$p $u.$g"
        echo "E$a$i"
        if [ -n "$FISH_HAVE_DATE_MDYT" ]; then
            echo "d$filedate"
        else
            echo "D$filedate"
        fi
        echo ":$pfile"
        echo
    fi
done
)
echo '### 200'
}

fish_list_poor_ls ()
{
FISH_DIR="$1"
ls -lan "${FISH_DIR}" 2>/dev/null | grep '^[^cbt]' | (
while read p l u g s m d y n n2 n3; do
    if [ -n "$g" ]; then
        if [ "$m" = "0" ]; then
            s=$d; m=$y; d=$n; y=$n2; n=$n3
        else
            n=$n" "$n2" "$n3
        fi
        echo "P$p $u $g"
        echo "S$s"
        echo "d$m $d $y"
        echo ":"$n
        echo
    fi
done
)
ls -lan "${FISH_DIR}" 2>/dev/null | grep '^[cb]' | (
while read p l u g a i m d y n n2 n3; do
    if [ -n "$g" ]; then
        if [ "$a" = "0" ]; then
            a=$m; i=$d; m=$y; d=$n; y=$n2; n=$n3
        else
            n=$n" "$n2" "$n3
        fi
        echo "P$p $u $g"
        echo "E$a$i"
        echo "d$m $d $y"
        echo ":"$n
        echo
    fi
done
)
echo '### 200'
}

fish_list_perl ()
{
FISH_DIR=$1
perl -e '
use strict;
use POSIX;
use Fcntl;
use POSIX ":fcntl_h"; #S_ISLNK was here until 5.6
import Fcntl ":mode" unless defined &S_ISLNK; #and is now here
my $dirname = $ARGV[0];
if (opendir (DIR, $dirname)) {
while((my $filename = readdir (DIR))){
    my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = lstat("$dirname/$filename");
    my $mloctime= strftime("%%m-%%d-%%Y %%H:%%M", localtime $mtime);
    my $strutils_shell_escape_regex = s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'\''"\ \\])/\\$1/g;
    my $e_filename = $filename;
    $e_filename =~ $strutils_shell_escape_regex;
    if (S_ISLNK ($mode)) {
        my $linkname = readlink ("$dirname/$filename");
        $linkname =~ $strutils_shell_escape_regex;
        printf("R%%o %%o $uid.$gid\nS$size\nd$mloctime\n:\"%%s\" -> \"%%s\"\n\n", S_IMODE($mode), S_IFMT($mode), $e_filename, $linkname);
    } elsif (S_ISCHR ($mode) || S_ISBLK ($mode)) {
        my $minor = $rdev %% 256;
        my $major = int( $rdev / 256 );
        printf("R%%o %%o $uid.$gid\nE$major,$minor\nd$mloctime\n:\"%%s\"\n\n", S_IMODE($mode), S_IFMT($mode), $e_filename);
    } else {
        printf("R%%o %%o $uid.$gid\nS$size\nd$mloctime\n:\"%%s\"\n\n", S_IMODE($mode), S_IFMT($mode), $e_filename);
    }
}
    printf("### 200\n");
    closedir(DIR);
} else {
    printf("### 500\n");
}
exit 0
' "/${FISH_DIR}"
perl_res=$?
}

if [ -n "${FISH_HAVE_PERL}" ]; then
    fish_list_perl "/${FISH_FILENAME}"
fi
if [ "${perl_res}" != "0" ]; then
    if [ -n "${FISH_HAVE_LSQ}" ]; then
        fish_list_lsq "/${FISH_FILENAME}"
    elif [ -n "${FISH_HAVE_SED}" ]; then
        fish_list_sed "/${FISH_FILENAME}"
    else
        fish_list_poor_ls "/${FISH_FILENAME}"
    fi
fi
hardlink000064400000000266151731340210006264 0ustar00#LINK $FISH_FILEFROM $FISH_FILETO
FILEFROM="/${FISH_FILEFROM}"
FILETO="/${FISH_FILETO}"
if ln "${FILEFROM}" "${FILETO}" 2>/dev/null; then
   echo "### 000"
else
   echo "### 500"
fi
mv000064400000000216151731340210005105 0ustar00#RENAME $FISH_FILEFROM $FISH_FILETO
if mv "/${FISH_FILEFROM}" "/${FISH_FILETO}" 2>/dev/null; then
   echo "### 000"
else
   echo "### 500"
fi
get000064400000004147151731340210005251 0ustar00#RETR $FISH_FILENAME $FISH_START_OFFSET
LC_TIME=C
export LC_TIME
fish_get_perl ()
{
FILENAME=$1
OFFSET=$2
perl -e '
use strict;
use POSIX;
use Fcntl;
my $filename = $ARGV[0];
my $pos = $ARGV[1];
my $content;
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = lstat("$filename");
my $n;
if (open IFILE,$filename) {
    if ($size<$pos) {
        printf("0\n");
    } else {
        $size-=$pos;
        printf("$size\n");
    }
    printf("### 100\n");
    seek (IFILE, $pos, 0);
    while ($n = read(IFILE,$content,$blksize)!= 0) {
        print $content;
    }
    close IFILE;
    printf("### 200\n");
} else {
    printf("### 500\n");
}
exit 0
' "${FILENAME}" $OFFSET
}

fish_get_tail ()
{
FILENAME=$1
OFFSET=$2
LC_TIME=C
export LC_TIME
if dd if="${FILENAME}" of=/dev/null bs=1 count=1 2>/dev/null ; then
    file_size=`ls -ln "${FILENAME}" 2>/dev/null | (
       read p l u g s r
       echo $s
    )`
    if [ $OFFSET -gt 0 ]; then
        file_size=`expr $file_size - $OFFSET`
        OFFSET=`expr $OFFSET + 1`
    fi
    if [ $file_size -gt 0 ]; then
        echo $file_size
    else
        echo 0
    fi
    echo "### 100"
    if [ $OFFSET -gt 0 ]; then
        tail -c +${OFFSET} "${FILENAME}"
    else
        cat "${FILENAME}"
    fi
    echo "### 200"
else
    echo "### 500"
fi
}

fish_get_dd ()
{
FILENAME=$1
OFFSET=$2
LC_TIME=C
export LC_TIME
if dd if="${FILENAME}" of=/dev/null bs=1 count=1 2>/dev/null ; then
    file_size=`ls -ln "${FILENAME}" 2>/dev/null | (
       read p l u g s r
       echo $s
    )`
    file_size=`expr $file_size - $OFFSET`
    if [ $file_size -gt 0 ]; then
        echo $file_size
    else
        echo 0
    fi
    echo "### 100"
    if [ $OFFSET -gt 0 ]; then
        dd skip=$OFFSET ibs=1 if="${FILENAME}" 2>/dev/null
    else
        cat "${FILENAME}"
    fi
    echo "### 200"
else
    echo "### 500"
fi
}

if [ -n "${FISH_HAVE_PERL}" ]; then
    fish_get_perl "/${FISH_FILENAME}" ${FISH_START_OFFSET}
elif [ -n "${FISH_HAVE_TAIL}" ]; then
    fish_get_tail "/${FISH_FILENAME}" ${FISH_START_OFFSET}
else
    fish_get_dd "/${FISH_FILENAME}" ${FISH_START_OFFSET}
fi
send000064400000000672151731340210005422 0ustar00#STOR $FISH_FILESIZE $FISH_FILENAME
FILENAME="/${FISH_FILENAME}"
echo "### 001"
{
    > "${FILENAME}"
    bss=4096
    bsl=4095
    if [ $FISH_FILESIZE -lt $bss ]; then
        bss=1;
        bsl=0;
    fi
    while [ $FISH_FILESIZE -gt 0 ]; do
        cnt=`expr \\( $FISH_FILESIZE + $bsl \\) / $bss`
        n=`dd bs=$bss count=$cnt | tee -a "${FILENAME}" | wc -c`
        FISH_FILESIZE=`expr $FISH_FILESIZE - $n`
    done
}; echo "### 200"
utime000064400000001145151731340210005610 0ustar00#UTIME "$FISH_TOUCHATIME_W_NSEC" "$FISH_TOUCHMTIME_W_NSEC" "$FISH_FILENAME"
if TZ=UTC touch -m -d "$FISH_TOUCHMTIME_W_NSEC" "/${FISH_FILENAME}" 2>/dev/null && \
   TZ=UTC touch -a -d "$FISH_TOUCHATIME_W_NSEC" "/${FISH_FILENAME}" 2>/dev/null; then
  echo "### 000"
elif TZ=UTC touch -m -t $FISH_TOUCHMTIME "/${FISH_FILENAME}" 2>/dev/null && \
     TZ=UTC touch -a -t $FISH_TOUCHATIME "/${FISH_FILENAME}" 2>/dev/null; then
  echo "### 000"
elif [ -n "$FISH_HAVE_PERL" ] &&
   perl -e 'utime '$FISH_FILEATIME','$FISH_FILEMTIME',@ARGV;' "/${FISH_FILENAME}" 2>/dev/null; then
  echo "### 000"
else
  echo "### 500"
fi