summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernhard Rosenkraenzer <Bernhard.Rosenkranzer@linaro.org>2011-10-10 11:48:48 +0159
committerBernhard Rosenkraenzer <Bernhard.Rosenkranzer@linaro.org>2011-10-10 11:55:55 +0159
commit2cbcbec2a3530c1e947a23e9497f0bfefb453278 (patch)
tree3223c7336c0602155addcba81a9d348fb455e650
downloadlrzsz-2cbcbec2a3530c1e947a23e9497f0bfefb453278.tar.gz
Import upstream sources from lrzsz 0.12.21HEADmaster
-rw-r--r--canit.c46
-rw-r--r--crctab.c140
-rw-r--r--error.c210
-rw-r--r--error.h65
-rw-r--r--long-options.c83
-rw-r--r--long-options.h10
-rw-r--r--lrz.c2313
-rw-r--r--lsyslog.c81
-rw-r--r--lsz.c2492
-rw-r--r--protname.c41
-rw-r--r--rbsb.c506
-rw-r--r--tcp.c169
-rw-r--r--timing.c186
-rw-r--r--timing.h1
-rw-r--r--xstrtol.c180
-rw-r--r--xstrtol.h66
-rw-r--r--xstrtoul.c2
-rw-r--r--xstrtoul.h7
-rw-r--r--zglobal.h463
-rw-r--r--zm.c982
-rw-r--r--zmodem.h142
-rw-r--r--zperr.c113
-rw-r--r--zreadline.c136
23 files changed, 8434 insertions, 0 deletions
diff --git a/canit.c b/canit.c
new file mode 100644
index 0000000..f947a25
--- /dev/null
+++ b/canit.c
@@ -0,0 +1,46 @@
+/*
+ canit - cancel zmodem connection
+ Copyright (C) until 1988 Chuck Forsberg (Omen Technology INC)
+ Copyright (C) 1994 Matt Porter, Michael D. Black
+ Copyright (C) 1996, 1997 Uwe Ohse
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+#include "zglobal.h"
+
+#define SS_NORMAL 0
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+
+/* send cancel string to get the other end to shut up */
+void
+canit (int fd)
+{
+ static char canistr[] =
+ {
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0
+ };
+ purgeline(fd);
+ write(fd,canistr,strlen(canistr));
+ if (fd==0)
+ write(1,canistr,strlen(canistr));
+}
+
diff --git a/crctab.c b/crctab.c
new file mode 100644
index 0000000..6b9bada
--- /dev/null
+++ b/crctab.c
@@ -0,0 +1,140 @@
+/*
+ * Crc calculation stuff
+ */
+
+/* crctab calculated by Mark G. Mendel, Network Systems Corporation */
+unsigned short crctab[256] = {
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+ 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+ 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+ 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+/*
+ * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
+ * NOTE: First srgument must be in range 0 to 255.
+ * Second argument is referenced twice.
+ *
+ * Programmers may incorporate any or all code into their programs,
+ * giving proper credit within the source. Publication of the
+ * source routines is permitted so long as proper credit is given
+ * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
+ * Omen Technology.
+ */
+
+#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
+
+/*
+ * Copyright (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ */
+
+/* First, the polynomial itself and its table of feedback terms. The */
+/* polynomial is */
+/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
+/* Note that we take it "backwards" and put the highest-order term in */
+/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
+/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
+/* the MSB being 1. */
+
+/* Note that the usual hardware shift register implementation, which */
+/* is what we're using (we're merely optimizing it by doing eight-bit */
+/* chunks at a time) shifts bits into the lowest-order term. In our */
+/* implementation, that means shifting towards the right. Why do we */
+/* do it this way? Because the calculated CRC must be transmitted in */
+/* order from highest-order term to lowest-order term. UARTs transmit */
+/* characters in order from LSB to MSB. By storing the CRC this way, */
+/* we hand it to the UART in the order low-byte to high-byte; the UART */
+/* sends each low-bit to hight-bit; and the result is transmission bit */
+/* by bit from highest- to lowest-order term without requiring any bit */
+/* shuffling on our part. Reception works similarly. */
+
+/* The feedback terms table consists of 256, 32-bit entries. Notes: */
+/* */
+/* The table can be generated at runtime if desired; code to do so */
+/* is shown later. It might not be obvious, but the feedback */
+/* terms simply represent the results of eight shift/xor opera- */
+/* tions for all combinations of data and CRC register values. */
+/* */
+/* The values must be right-shifted by eight bits by the "updcrc" */
+/* logic; the shift must be unsigned (bring in zeroes). On some */
+/* hardware you could probably optimize the shift in assembler by */
+/* using byte-swap instructions. */
+
+long cr3tab[] = { /* CRC polynomial 0xedb88320 */
+0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+#ifdef NFGM
+long
+UPDC32(b, c)
+long c;
+{
+ return (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF));
+}
+
+#else
+
+#define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF))
+#endif
+
+/* End of crctab.c */
diff --git a/error.c b/error.c
new file mode 100644
index 0000000..8b96b91
--- /dev/null
+++ b/error.c
@@ -0,0 +1,210 @@
+/* error.c -- error handler for noninteractive utilities
+ Copyright (C) 1990, 91, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC || defined(__cplusplus)
+# if __STDC__ || defined(__cplusplus)
+# include <stdarg.h>
+# define VA_START(args, lastarg) va_start(args, lastarg)
+# else
+# include <varargs.h>
+# define VA_START(args, lastarg) va_start(args)
+# endif
+#else
+# define va_alist a1, a2, a3, a4, a5, a6, a7, a8
+# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
+#endif
+
+#if STDC_HEADERS || _LIBC
+# include <stdlib.h>
+# include <string.h>
+#else
+void exit ();
+#endif
+
+#ifndef _
+# define _(String) String
+#endif
+
+/* If NULL, error will flush stdout, then print on stderr the program
+ name, a colon and a space. Otherwise, error will call this
+ function without parameters instead. */
+void (*error_print_progname) (
+#if __STDC__ - 0
+ void
+#endif
+ );
+
+/* This variable is incremented each time `error' is called. */
+unsigned int error_message_count;
+
+#ifdef _LIBC
+/* In the GNU C library, there is a predefined variable for this. */
+
+# define program_name program_invocation_name
+# include <errno.h>
+
+#else
+
+/* The calling program should define program_name and set it to the
+ name of the executing program. */
+extern char *program_name;
+
+# if HAVE_STRERROR
+# ifndef strerror /* On some systems, strerror is a macro */
+char *strerror ();
+# endif
+# else
+static char *
+private_strerror (errnum)
+ int errnum;
+{
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+
+ if (errnum > 0 && errnum <= sys_nerr)
+ return sys_errlist[errnum];
+ return _("Unknown system error");
+}
+# define strerror private_strerror
+# endif /* HAVE_STRERROR */
+#endif /* _LIBC */
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+ format string with optional args.
+ If ERRNUM is nonzero, print its corresponding system error message.
+ Exit with status STATUS if it is nonzero. */
+/* VARARGS */
+
+void
+#if defined(VA_START) && __STDC__
+error (int status, int errnum, const char *message, ...)
+#else
+error (status, errnum, message, va_alist)
+ int status;
+ int errnum;
+ char *message;
+ va_dcl
+#endif
+{
+#if defined(VA_START)
+ va_list args;
+#endif
+
+ if (error_print_progname)
+ (*error_print_progname) ();
+ else
+ {
+ fflush (stdout);
+ fprintf (stderr, "%s: ", program_name);
+ }
+
+#if defined(VA_START)
+ VA_START(args, message);
+# if HAVE_VPRINTF || _LIBC
+ vfprintf (stderr, message, args);
+# else
+ _doprnt (message, args, stderr);
+# endif
+ va_end (args);
+#else
+ fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+
+ ++error_message_count;
+ if (errnum)
+ fprintf (stderr, ": %s", strerror (errnum));
+ putc ('\n', stderr);
+ fflush (stderr);
+ if (status)
+ exit (status);
+}
+
+/* Sometimes we want to have at most one error per line. This
+ variable controls whether this mode is selected or not. */
+int error_one_per_line;
+
+void
+#if defined(VA_START) && __STDC__
+error_at_line (int status, int errnum, const char *file_name,
+ unsigned int line_number, const char *message, ...)
+#else
+error_at_line (status, errnum, file_name, line_number, message, va_alist)
+ int status;
+ int errnum;
+ const char *file_name;
+ unsigned int line_number;
+ char *message;
+ va_dcl
+#endif
+{
+#ifdef VA_START
+ va_list args;
+#endif
+
+ if (error_one_per_line)
+ {
+ static const char *old_file_name;
+ static unsigned int old_line_number;
+
+ if (old_line_number == line_number &&
+ (file_name == old_file_name || !strcmp (old_file_name, file_name)))
+ /* Simply return and print nothing. */
+ return;
+
+ old_file_name = file_name;
+ old_line_number = line_number;
+ }
+
+ if (error_print_progname)
+ (*error_print_progname) ();
+ else
+ {
+ fflush (stdout);
+ fprintf (stderr, "%s:", program_name);
+ }
+
+ if (file_name != NULL)
+ fprintf (stderr, "%s:%d: ", file_name, line_number);
+
+#ifdef VA_START
+ VA_START (args, message);
+# if HAVE_VPRINTF || _LIBC
+ vfprintf (stderr, message, args);
+# else
+ _doprnt (message, args, stderr);
+# endif
+ va_end (args);
+#else
+ fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+
+ ++error_message_count;
+ if (errnum)
+ fprintf (stderr, ": %s", strerror (errnum));
+ putc ('\n', stderr);
+ fflush (stderr);
+ if (status)
+ exit (status);
+}
diff --git a/error.h b/error.h
new file mode 100644
index 0000000..3439f37
--- /dev/null
+++ b/error.h
@@ -0,0 +1,65 @@
+/* error.h -- declaration for error-reporting function
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _error_h_
+#define _error_h_
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
+# define __attribute__(Spec) /* empty */
+# endif
+/* The __-protected variants of `format' and `printf' attributes
+ are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __format__ format
+# define __printf__ printf
+# endif
+#endif
+
+#if defined (__STDC__) && __STDC__
+
+/* Print a message with `fprintf (stderr, FORMAT, ...)';
+ if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
+ If STATUS is nonzero, terminate the program with `exit (STATUS)'. */
+
+extern void error (int status, int errnum, const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+
+extern void error_at_line (int status, int errnum, const char *fname,
+ unsigned int lineno, const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 5, 6)));
+
+/* If NULL, error will flush stdout, then print on stderr the program
+ name, a colon and a space. Otherwise, error will call this
+ function without parameters instead. */
+extern void (*error_print_progname) (void);
+
+#else
+void error ();
+void error_at_line ();
+extern void (*error_print_progname) ();
+#endif
+
+/* This variable is incremented each time `error' is called. */
+extern unsigned int error_message_count;
+
+/* Sometimes we want to have at most one error per line. This
+ variable controls whether this mode is selected or not. */
+extern int error_one_per_line;
+
+#endif /* _error_h_ */
diff --git a/long-options.c b/long-options.c
new file mode 100644
index 0000000..fe069fd
--- /dev/null
+++ b/long-options.c
@@ -0,0 +1,83 @@
+/* Utility to accept --help and --version options as unobtrusively as possible.
+ Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Jim Meyering (meyering@comco.com) */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <getopt.h>
+#include "long-options.h"
+
+static struct option const long_options[] =
+{
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'v'},
+ {0, 0, 0, 0}
+};
+
+/* Process long options --help and --version, but only if argc == 2.
+ Be careful not to gobble up `--'. */
+#ifdef __cplusplus
+void parse_long_options (int argc, char **argv,
+ void (*version)(void), void (*usage)(int))
+#else
+void
+parse_long_options (argc, argv,version, usage)
+ int argc;
+ char **argv;
+ void (*version)();
+ void (*usage)();
+#endif
+{
+ int c;
+ int saved_opterr;
+ int saved_optind;
+
+ saved_opterr = opterr;
+ saved_optind = optind;
+
+ /* Don't print an error message for unrecognized options. */
+ opterr = 0;
+
+ if (argc == 2
+ && (c = getopt_long (argc, argv, "+", long_options, (int *) 0)) != EOF)
+ {
+ switch (c)
+ {
+ case 'h':
+ (*usage) (0);
+
+ case 'v':
+ (*version) ();
+ /* printf ("%s (%s) %s\n", command_name, package, version_string); */
+ exit (0);
+
+ default:
+ /* Don't process any other long-named options. */
+ break;
+ }
+ }
+
+ /* Restore previous value. */
+ opterr = saved_opterr;
+
+ /* Restore optind in case it has advanced past a leading `--'. */
+ optind = saved_optind;
+}
diff --git a/long-options.h b/long-options.h
new file mode 100644
index 0000000..14459cd
--- /dev/null
+++ b/long-options.h
@@ -0,0 +1,10 @@
+#undef __P
+#if defined (__STDC__) && __STDC__
+#define __P(args) args
+#else
+#define __P(args) ()
+#endif
+
+void parse_long_options __P ((int _argc, char **_argv,
+ void (*_version) (void),
+ void (*_usage) (int)));
diff --git a/lrz.c b/lrz.c
new file mode 100644
index 0000000..9202f59
--- /dev/null
+++ b/lrz.c
@@ -0,0 +1,2313 @@
+/*
+ lrz - receive files with x/y/zmodem
+ Copyright (C) until 1988 Chuck Forsberg (Omen Technology INC)
+ Copyright (C) 1994 Matt Porter, Michael D. Black
+ Copyright (C) 1996, 1997 Uwe Ohse
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ originally written by Chuck Forsberg
+*/
+
+#include "zglobal.h"
+
+#define SS_NORMAL 0
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+
+#include "timing.h"
+#include "long-options.h"
+#include "xstrtoul.h"
+#include "error.h"
+
+#ifndef STRICT_PROTOTYPES
+extern time_t time();
+extern char *strerror();
+#endif
+
+#ifndef HAVE_ERRNO_DECLARATION
+extern int errno;
+#endif
+
+#define MAX_BLOCK 8192
+
+/*
+ * Max value for HOWMANY is 255 if NFGVMIN is not defined.
+ * A larger value reduces system overhead but may evoke kernel bugs.
+ * 133 corresponds to an XMODEM/CRC sector
+ */
+#ifndef HOWMANY
+#ifdef NFGVMIN
+#define HOWMANY MAX_BLOCK
+#else
+#define HOWMANY 255
+#endif
+#endif
+
+unsigned Baudrate = 2400;
+
+FILE *fout;
+
+
+int Lastrx;
+int Crcflg;
+int Firstsec;
+int errors;
+int Restricted=1; /* restricted; no /.. or ../ in filenames */
+int Readnum = HOWMANY; /* Number of bytes to ask for in read() from modem */
+int skip_if_not_found;
+
+char *Pathname;
+const char *program_name; /* the name by which we were called */
+
+int Topipe=0;
+int MakeLCPathname=TRUE; /* make received pathname lower case */
+int Verbose=0;
+int Quiet=0; /* overrides logic that would otherwise set verbose */
+int Nflag = 0; /* Don't really transfer files */
+int Rxclob=FALSE; /* Clobber existing file */
+int Rxbinary=FALSE; /* receive all files in bin mode */
+int Rxascii=FALSE; /* receive files in ascii (translate) mode */
+int Thisbinary; /* current file is to be received in bin mode */
+int try_resume=FALSE;
+int allow_remote_commands=FALSE;
+int junk_path=FALSE;
+int no_timeout=FALSE;
+enum zm_type_enum protocol;
+int under_rsh=FALSE;
+int zmodem_requested=FALSE;
+
+#ifdef SEGMENTS
+static int chinseg = 0; /* Number of characters received in this data seg */
+#endif
+static char *secbuf;
+
+#ifdef ENABLE_TIMESYNC
+static int timesync_flag=0;
+static int in_timesync=0;
+#endif
+int tcp_socket=-1;
+int tcp_flag=0;
+char *tcp_server_address=NULL;
+
+#if defined(F_GETFD) && defined(F_SETFD) && defined(O_SYNC)
+static int o_sync = 0;
+#endif
+static int rzfiles __P ((struct zm_fileinfo *));
+static int tryz __P ((void));
+static void checkpath __P ((const char *name));
+static void chkinvok __P ((const char *s));
+static void report __P ((int sct));
+static void uncaps __P ((char *s));
+static int IsAnyLower __P ((const char *s));
+static int putsec __P ((struct zm_fileinfo *zi, char *buf, size_t n));
+static int make_dirs __P ((char *pathname));
+static int procheader __P ((char *name, struct zm_fileinfo *));
+static int wcgetsec __P ((size_t *Blklen, char *rxbuf, unsigned int maxtime));
+static int wcrx __P ((struct zm_fileinfo *));
+static int wcrxpn __P ((struct zm_fileinfo *, char *rpn));
+static int wcreceive __P ((int argc, char **argp));
+static int rzfile __P ((struct zm_fileinfo *));
+static void usage __P ((int exitcode, const char *what));
+static void usage1 __P ((int exitcode));
+static void exec2 __P ((const char *s));
+static int closeit __P ((struct zm_fileinfo *));
+static void ackbibi __P ((void));
+static int sys2 __P ((const char *s));
+static void zmputs __P ((const char *s));
+static size_t getfree __P ((void));
+
+static long buffersize=32768;
+static unsigned long min_bps=0;
+static long min_bps_time=120;
+
+char Lzmanag; /* Local file management request */
+char zconv; /* ZMODEM file conversion request */
+char zmanag; /* ZMODEM file management request */
+char ztrans; /* ZMODEM file transport request */
+int Zctlesc; /* Encode control characters */
+int Zrwindow = 1400; /* RX window size (controls garbage count) */
+
+int tryzhdrtype=ZRINIT; /* Header type to send corresponding to Last rx close */
+time_t stop_time;
+
+#ifdef ENABLE_SYSLOG
+# if defined(ENABLE_SYSLOG_FORCE) || defined(ENABLE_SYSLOG_DEFAULT)
+int enable_syslog=TRUE;
+# else
+int enable_syslog=FALSE;
+# endif
+#define DO_SYSLOG_FNAME(message) do { \
+ if (enable_syslog) { \
+ const char *shortname; \
+ if (!zi->fname) \
+ shortname="no.name"; \
+ else { \
+ shortname=strrchr(zi->fname,'/'); \
+ if (!shortname) \
+ shortname=zi->fname; \
+ else \
+ shortname++; \
+ } \
+ lsyslog message ; \
+ } \
+} while(0)
+#define DO_SYSLOG(message) do { \
+ if (enable_syslog) { \
+ lsyslog message ; \
+ } \
+} while(0)
+#else
+#define DO_SYSLOG_FNAME(message) do { } while(0)
+#define DO_SYSLOG(message) do { } while(0)
+#endif
+
+
+/* called by signal interrupt or terminate to clean things up */
+RETSIGTYPE
+bibi(int n)
+{
+ if (zmodem_requested)
+ zmputs(Attn);
+ canit(STDOUT_FILENO);
+ io_mode(0,0);
+ error(128+n,0,_("caught signal %d; exiting"), n);
+}
+
+static struct option const long_options[] =
+{
+ {"append", no_argument, NULL, '+'},
+ {"ascii", no_argument, NULL, 'a'},
+ {"binary", no_argument, NULL, 'b'},
+ {"bufsize", required_argument, NULL, 'B'},
+ {"allow-commands", no_argument, NULL, 'C'},
+ {"allow-remote-commands", no_argument, NULL, 'C'},
+ {"escape", no_argument, NULL, 'e'},
+ {"rename", no_argument, NULL, 'E'},
+ {"help", no_argument, NULL, 'h'},
+ {"crc-check", no_argument, NULL, 'H'},
+ {"junk-path", no_argument, NULL, 'j'},
+ {"errors", required_argument, NULL, 3},
+ {"disable-timeouts", no_argument, NULL, 'O'},
+ {"disable-timeout", no_argument, NULL, 'O'}, /* i can't get it right */
+ {"min-bps", required_argument, NULL, 'm'},
+ {"min-bps-time", required_argument, NULL, 'M'},
+ {"newer", no_argument, NULL, 'n'},
+ {"newer-or-longer", no_argument, NULL, 'N'},
+ {"protect", no_argument, NULL, 'p'},
+ {"resume", no_argument, NULL, 'r'},
+ {"restricted", no_argument, NULL, 'R'},
+ {"quiet", no_argument, NULL, 'q'},
+ {"stop-at", required_argument, NULL, 's'},
+ {"timesync", no_argument, NULL, 'S'},
+ {"timeout", required_argument, NULL, 't'},
+ {"keep-uppercase", no_argument, NULL, 'u'},
+ {"unrestrict", no_argument, NULL, 'U'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"windowsize", required_argument, NULL, 'w'},
+ {"with-crc", no_argument, NULL, 'c'},
+ {"xmodem", no_argument, NULL, 'X'},
+ {"ymodem", no_argument, NULL, 1},
+ {"zmodem", no_argument, NULL, 'Z'},
+ {"overwrite", no_argument, NULL, 'y'},
+ {"null", no_argument, NULL, 'D'},
+ {"syslog", optional_argument, NULL , 2},
+ {"delay-startup", required_argument, NULL, 4},
+ {"o-sync", no_argument, NULL, 5},
+ {"o_sync", no_argument, NULL, 5},
+ {"tcp-server", no_argument, NULL, 6},
+ {"tcp-client", required_argument, NULL, 7},
+ {NULL,0,NULL,0}
+};
+
+static void
+show_version(void)
+{
+ printf ("%s (GNU %s) %s\n", program_name, PACKAGE, VERSION);
+}
+
+int
+main(int argc, char *argv[])
+{
+ register char *cp;
+ register int npats;
+ char **patts=NULL; /* keep compiler quiet */
+ int exitcode=0;
+ int c;
+ unsigned int startup_delay=0;
+
+ Rxtimeout = 100;
+ setbuf(stderr, NULL);
+ if ((cp=getenv("SHELL")) && (strstr(cp, "rsh") || strstr(cp, "rksh")
+ || strstr(cp,"rbash") || strstr(cp, "rshell")))
+ under_rsh=TRUE;
+ if ((cp=getenv("ZMODEM_RESTRICTED"))!=NULL)
+ Restricted=2;
+
+ /* make temporary and unfinished files */
+ umask(0077);
+
+ from_cu();
+ chkinvok(argv[0]); /* if called as [-]rzCOMMAND set flag */
+
+#ifdef ENABLE_SYSLOG
+ openlog(program_name,LOG_PID,ENABLE_SYSLOG);
+#endif
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ parse_long_options (argc, argv, show_version, usage1);
+
+ while ((c = getopt_long (argc, argv,
+ "a+bB:cCDeEhm:M:OprRqs:St:uUvw:XZy",
+ long_options, (int *) 0)) != EOF)
+ {
+ unsigned long int tmp;
+ char *tmpptr;
+ enum strtol_error s_err;
+
+ switch (c)
+ {
+ case 0:
+ break;
+ case '+': Lzmanag = ZF1_ZMAPND; break;
+ case 'a': Rxascii=TRUE; break;
+ case 'b': Rxbinary=TRUE; break;
+ case 'B':
+ if (strcmp(optarg,"auto")==0)
+ buffersize=-1;
+ else
+ buffersize=strtol(optarg,NULL,10);
+ break;
+ case 'c': Crcflg=TRUE; break;
+ case 'C': allow_remote_commands=TRUE; break;
+ case 'D': Nflag = TRUE; break;
+ case 'E': Lzmanag = ZF1_ZMCHNG; break;
+ case 'e': Zctlesc = 1; break;
+ case 'h': usage(0,NULL); break;
+ case 'H': Lzmanag= ZF1_ZMCRC; break;
+ case 'j': junk_path=TRUE; break;
+ case 'm':
+ s_err = xstrtoul (optarg, &tmpptr, 0, &tmp, "km");
+ min_bps = tmp;
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("min_bps"), s_err);
+ break;
+ case 'M':
+ s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL);
+ min_bps_time = tmp;
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("min_bps_time"), s_err);
+ if (min_bps_time<=1)
+ usage(2,_("min_bps_time must be > 1"));
+ break;
+ case 'N': Lzmanag = ZF1_ZMNEWL; break;
+ case 'n': Lzmanag = ZF1_ZMNEW; break;
+ case 'O': no_timeout=TRUE; break;
+ case 'p': Lzmanag = ZF1_ZMPROT; break;
+ case 'q': Quiet=TRUE; Verbose=0; break;
+ case 's':
+ if (isdigit((unsigned char) (*optarg))) {
+ struct tm *tm;
+ time_t t;
+ int hh,mm;
+ char *nex;
+
+ hh = strtoul (optarg, &nex, 10);
+ if (hh>23)
+ usage(2,_("hour to large (0..23)"));
+ if (*nex!=':')
+ usage(2, _("unparsable stop time\n"));
+ nex++;
+ mm = strtoul (optarg, &nex, 10);
+ if (mm>59)
+ usage(2,_("minute to large (0..59)"));
+
+ t=time(NULL);
+ tm=localtime(&t);
+ tm->tm_hour=hh;
+ tm->tm_min=hh;
+ stop_time=mktime(tm);
+ if (stop_time<t)
+ stop_time+=86400L; /* one day more */
+ if (stop_time - t <10)
+ usage(2,_("stop time to small"));
+ } else {
+ s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL);
+ stop_time = tmp + time(0);
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("stop-at"), s_err);
+ if (tmp<10)
+ usage(2,_("stop time to small"));
+ }
+ break;
+
+
+ case 'r':
+ if (try_resume)
+ Lzmanag= ZF1_ZMCRC;
+ else
+ try_resume=TRUE;
+ break;
+ case 'R': Restricted++; break;
+ case 'S':
+#ifdef ENABLE_TIMESYNC
+ timesync_flag++;
+ if (timesync_flag==2) {
+#ifdef HAVE_SETTIMEOFDAY
+ error(0,0,_("don't have settimeofday, will not set time\n"));
+#endif
+ if (getuid()!=0)
+ error(0,0,
+ _("not running as root (this is good!), can not set time\n"));
+ }
+#endif
+ break;
+ case 't':
+ s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL);
+ Rxtimeout = tmp;
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("timeout"), s_err);
+ if (Rxtimeout<10 || Rxtimeout>1000)
+ usage(2,_("timeout out of range 10..1000"));
+ break;
+ case 'w':
+ s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL);
+ Zrwindow = tmp;
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("window size"), s_err);
+ break;
+ case 'u':
+ MakeLCPathname=FALSE; break;
+ case 'U':
+ if (!under_rsh)
+ Restricted=0;
+ else {
+ DO_SYSLOG((LOG_INFO,"--unrestrict option used under restricted shell"));
+ error(1,0,
+ _("security violation: can't do that under restricted shell\n"));
+ }
+ break;
+ case 'v':
+ ++Verbose; break;
+ case 'X': protocol=ZM_XMODEM; break;
+ case 1: protocol=ZM_YMODEM; break;
+ case 'Z': protocol=ZM_ZMODEM; break;
+ case 'y':
+ Rxclob=TRUE; break;
+ case 2:
+#ifdef ENABLE_SYSLOG
+# ifndef ENABLE_SYSLOG_FORCE
+ if (optarg && (!strcmp(optarg,"off") || !strcmp(optarg,"no"))) {
+ if (under_rsh)
+ error(0,0, _("cannot turnoff syslog"));
+ else
+ enable_syslog=FALSE;
+ }
+ else
+ enable_syslog=TRUE;
+# else
+ error(0,0, _("cannot turnoff syslog"));
+# endif
+#endif
+ case 3:
+ s_err = xstrtoul (optarg, NULL, 0, &tmp, "km");
+ bytes_per_error = tmp;
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("bytes_per_error"), s_err);
+ if (bytes_per_error<100)
+ usage(2,_("bytes-per-error should be >100"));
+ break;
+ case 4:
+ s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL);
+ startup_delay = tmp;
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("startup delay"), s_err);
+ break;
+ case 5:
+#if defined(F_GETFD) && defined(F_SETFD) && defined(O_SYNC)
+ o_sync=1;
+#else
+ error(0,0, _("O_SYNC not supported by the kernel"));
+#endif
+ break;
+ case 6:
+ tcp_flag=2;
+ break;
+ case 7:
+ tcp_flag=3;
+ tcp_server_address=(char *)strdup(optarg);
+ if (!tcp_server_address)
+ error(1,0,_("out of memory"));
+ break;
+ default:
+ usage(2,NULL);
+ }
+
+ }
+
+ if (getuid()!=geteuid()) {
+ error(1,0,
+ _("this program was never intended to be used setuid\n"));
+ }
+
+#ifdef SEGMENTS
+ secbuf=malloc(1+(SEGMENTS+1)*MAX_BLOCK);
+#else
+ secbuf=malloc(MAX_BLOCK+1);
+#endif
+ if (!secbuf) error(1,0,_("out of memory"));
+
+ /* initialize zsendline tab */
+ zsendline_init();
+#ifdef HAVE_SIGINTERRUPT
+ siginterrupt(SIGALRM,1);
+#endif
+ if (startup_delay)
+ sleep(startup_delay);
+
+ npats = argc - optind;
+ patts=&argv[optind];
+
+ if (npats > 1)
+ usage(2,_("garbage on commandline"));
+ if (protocol!=ZM_XMODEM && npats)
+ usage(2, _("garbage on commandline"));
+ if (Restricted && allow_remote_commands) {
+ allow_remote_commands=FALSE;
+ }
+ if (Fromcu && !Quiet) {
+ if (Verbose == 0)
+ Verbose = 2;
+ }
+
+ vfile("%s %s\n", program_name, VERSION);
+
+ if (tcp_flag==2) {
+ char buf[256];
+#ifdef MAXHOSTNAMELEN
+ char hn[MAXHOSTNAMELEN];
+#else
+ char hn[256];
+#endif
+ char *p,*q;
+ int d;
+
+ /* tell receiver to receive via tcp */
+ d=tcp_server(buf);
+ p=strchr(buf+1,'<');
+ p++;
+ q=strchr(p,'>');
+ *q=0;
+ if (gethostname(hn,sizeof(hn))==-1) {
+ error(1,0, _("hostname too long\n"));
+ }
+ fprintf(stdout,"connect with lrz --tcp-client \"%s:%s\"\n",hn,p);
+ fflush(stdout);
+ /* ok, now that this file is sent we can switch to tcp */
+
+ tcp_socket=tcp_accept(d);
+ dup2(tcp_socket,0);
+ dup2(tcp_socket,1);
+ }
+ if (tcp_flag==3) {
+ char buf[256];
+ char *p;
+ p=strchr(tcp_server_address,':');
+ if (!p)
+ error(1,0, _("illegal server address\n"));
+ *p++=0;
+ sprintf(buf,"[%s] <%s>\n",tcp_server_address,p);
+
+ fprintf(stdout,"connecting to %s\n",buf);
+ fflush(stdout);
+
+ /* we need to switch to tcp mode */
+ tcp_socket=tcp_connect(buf);
+ dup2(tcp_socket,0);
+ dup2(tcp_socket,1);
+ }
+
+ io_mode(0,1);
+ readline_setup(0, HOWMANY, MAX_BLOCK*2);
+ if (signal(SIGINT, bibi) == SIG_IGN)
+ signal(SIGINT, SIG_IGN);
+ else
+ signal(SIGINT, bibi);
+ signal(SIGTERM, bibi);
+ signal(SIGPIPE, bibi);
+ if (wcreceive(npats, patts)==ERROR) {
+ exitcode=0200;
+ canit(STDOUT_FILENO);
+ }
+ io_mode(0,0);
+ if (exitcode && !zmodem_requested) /* bellow again with all thy might. */
+ canit(STDOUT_FILENO);
+ if (Verbose)
+ {
+ fputs("\r\n",stderr);
+ if (exitcode)
+ fputs(_("Transfer incomplete\n"),stderr);
+ else
+ fputs(_("Transfer complete\n"),stderr);
+ }
+ exit(exitcode);
+}
+
+static void
+usage1(int exitcode)
+{
+ usage(exitcode,NULL);
+}
+
+static void
+usage(int exitcode, const char *what)
+{
+ FILE *f=stdout;
+
+ if (exitcode)
+ {
+ if (what)
+ fprintf(stderr, "%s: %s\n",program_name,what);
+ fprintf (stderr, _("Try `%s --help' for more information.\n"),
+ program_name);
+ exit(exitcode);
+ }
+
+ fprintf(f, _("%s version %s\n"), program_name,
+ VERSION);
+
+ fprintf(f,_("Usage: %s [options] [filename.if.xmodem]\n"), program_name);
+ fputs(_("Receive files with ZMODEM/YMODEM/XMODEM protocol\n"),f);
+ fputs(_(
+ " (X) = option applies to XMODEM only\n"
+ " (Y) = option applies to YMODEM only\n"
+ " (Z) = option applies to ZMODEM only\n"
+ ),f);
+ fputs(_(
+" -+, --append append to existing files\n"
+" -a, --ascii ASCII transfer (change CR/LF to LF)\n"
+" -b, --binary binary transfer\n"
+" -B, --bufsize N buffer N bytes (N==auto: buffer whole file)\n"
+" -c, --with-crc Use 16 bit CRC (X)\n"
+" -C, --allow-remote-commands allow execution of remote commands (Z)\n"
+" -D, --null write all received data to /dev/null\n"
+" --delay-startup N sleep N seconds before doing anything\n"
+" -e, --escape Escape control characters (Z)\n"
+" -E, --rename rename any files already existing\n"
+" --errors N generate CRC error every N bytes (debugging)\n"
+" -h, --help Help, print this usage message\n"
+" -m, --min-bps N stop transmission if BPS below N\n"
+" -M, --min-bps-time N for at least N seconds (default: 120)\n"
+" -O, --disable-timeouts disable timeout code, wait forever for data\n"
+" --o-sync open output file(s) in synchronous write mode\n"
+" -p, --protect protect existing files\n"
+" -q, --quiet quiet, no progress reports\n"
+" -r, --resume try to resume interrupted file transfer (Z)\n"
+" -R, --restricted restricted, more secure mode\n"
+" -s, --stop-at {HH:MM|+N} stop transmission at HH:MM or in N seconds\n"
+" -S, --timesync request remote time (twice: set local time)\n"
+" --syslog[=off] turn syslog on or off, if possible\n"
+" -t, --timeout N set timeout to N tenths of a second\n"
+" --tcp-server open socket, wait for connection (Z)\n"
+" --tcp-client ADDR:PORT open socket, connect to ... (Z)\n"
+" -u, --keep-uppercase keep upper case filenames\n"
+" -U, --unrestrict disable restricted mode (if allowed to)\n"
+" -v, --verbose be verbose, provide debugging information\n"
+" -w, --windowsize N Window is N bytes (Z)\n"
+" -X --xmodem use XMODEM protocol\n"
+" -y, --overwrite Yes, clobber existing file if any\n"
+" --ymodem use YMODEM protocol\n"
+" -Z, --zmodem use ZMODEM protocol\n"
+"\n"
+"short options use the same arguments as the long ones\n"
+ ),f);
+ exit(exitcode);
+}
+
+/*
+ * Let's receive something already.
+ */
+
+static int
+wcreceive(int argc, char **argp)
+{
+ int c;
+ struct zm_fileinfo zi;
+#ifdef ENABLE_SYSLOG
+ const char *shortname=NULL;;
+#endif
+ zi.fname=NULL;
+ zi.modtime=0;
+ zi.mode=0;
+ zi.bytes_total=0;
+ zi.bytes_sent=0;
+ zi.bytes_received=0;
+ zi.bytes_skipped=0;
+ zi.eof_seen=0;
+
+ if (protocol!=ZM_XMODEM || argc==0) {
+ Crcflg=1;
+ if ( !Quiet)
+ vstringf(_("%s waiting to receive."), program_name);
+ if ((c=tryz())!=0) {
+ if (c == ZCOMPL)
+ return OK;
+ if (c == ERROR)
+ goto fubar;
+ c = rzfiles(&zi);
+
+#ifdef ENABLE_SYSLOG
+ shortname=NULL;
+#endif
+ if (c)
+ goto fubar;
+ } else {
+ for (;;) {
+ if (Verbose > 1
+#ifdef ENABLE_SYSLOG
+ || enable_syslog
+#endif
+ )
+ timing(1,NULL);
+#ifdef ENABLE_SYSLOG
+ shortname=NULL;
+#endif
+ if (wcrxpn(&zi,secbuf)== ERROR)
+ goto fubar;
+ if (secbuf[0]==0)
+ return OK;
+ if (procheader(secbuf, &zi) == ERROR)
+ goto fubar;
+#ifdef ENABLE_SYSLOG
+ shortname=strrchr(zi.fname,'/');
+ if (shortname)
+ shortname++;
+ else
+ shortname=zi.fname;
+#endif
+ if (wcrx(&zi)==ERROR)
+ goto fubar;
+
+ if (Verbose > 1
+#ifdef ENABLE_SYSLOG
+ || enable_syslog
+#endif
+ ) {
+ double d;
+ long bps;
+ d=timing(0,NULL);
+ if (d==0)
+ d=0.5; /* can happen if timing uses time() */
+ bps=(zi.bytes_received-zi.bytes_skipped)/d;
+
+ if (Verbose>1) {
+ vstringf(
+ _("\rBytes received: %7ld/%7ld BPS:%-6ld \r\n"),
+ (long) zi.bytes_received, (long) zi.bytes_total, bps);
+ }
+#ifdef ENABLE_SYSLOG
+ if (enable_syslog)
+ lsyslog(LOG_INFO,"%s/%s: %ld Bytes, %ld BPS",
+ shortname,protname(),zi.bytes_received, bps);
+#endif
+ }
+ }
+ }
+ } else {
+ char dummy[128];
+ dummy[0]='\0'; /* pre-ANSI HPUX cc demands this */
+ dummy[1]='\0'; /* procheader uses name + 1 + strlen(name) */
+ zi.bytes_total = DEFBYTL;
+
+ if (Verbose > 1
+#ifdef ENABLE_SYSLOG
+ || enable_syslog
+#endif
+ )
+ timing(1,NULL);
+ procheader(dummy, &zi);
+
+ if (Pathname)
+ free(Pathname);
+ errno=0;
+ Pathname=malloc(PATH_MAX+1);
+ if (!Pathname)
+ error(1,0,_("out of memory"));
+
+ strcpy(Pathname, *argp);
+ checkpath(Pathname);
+#ifdef ENABLE_SYSLOG
+ shortname=strrchr(*argp,'/');
+ if (shortname)
+ shortname++;
+ else
+ shortname=*argp;
+#endif
+ vchar('\n');
+ vstringf(_("%s: ready to receive %s"), program_name, Pathname);
+ vstring("\r\n");
+
+ if ((fout=fopen(Pathname, "w")) == NULL) {
+#ifdef ENABLE_SYSLOG
+ if (enable_syslog)
+ lsyslog(LOG_ERR,"%s/%s: cannot open: %m",
+ shortname,protname());
+#endif
+ return ERROR;
+ }
+ if (wcrx(&zi)==ERROR) {
+ goto fubar;
+ }
+ if (Verbose > 1
+#ifdef ENABLE_SYSLOG
+ || enable_syslog
+#endif
+ ) {
+ double d;
+ long bps;
+ d=timing(0,NULL);
+ if (d==0)
+ d=0.5; /* can happen if timing uses time() */
+ bps=(zi.bytes_received-zi.bytes_skipped)/d;
+ if (Verbose) {
+ vstringf(
+ _("\rBytes received: %7ld BPS:%-6ld \r\n"),
+ (long) zi.bytes_received, bps);
+ }
+#ifdef ENABLE_SYSLOG
+ if (enable_syslog)
+ lsyslog(LOG_INFO,"%s/%s: %ld Bytes, %ld BPS",
+ shortname,protname(),zi.bytes_received, bps);
+#endif
+ }
+ }
+ return OK;
+fubar:
+#ifdef ENABLE_SYSLOG
+ if (enable_syslog)
+ lsyslog(LOG_ERR,"%s/%s: got error",
+ shortname ? shortname : "no.name", protname());
+#endif
+ canit(STDOUT_FILENO);
+ if (Topipe && fout) {
+ pclose(fout); return ERROR;
+ }
+ if (fout)
+ fclose(fout);
+
+ if (Restricted && Pathname) {
+ unlink(Pathname);
+ vstringf(_("\r\n%s: %s removed.\r\n"), program_name, Pathname);
+ }
+ return ERROR;
+}
+
+
+/*
+ * Fetch a pathname from the other end as a C ctyle ASCIZ string.
+ * Length is indeterminate as long as less than Blklen
+ * A null string represents no more files (YMODEM)
+ */
+static int
+wcrxpn(struct zm_fileinfo *zi, char *rpn)
+{
+ register int c;
+ size_t Blklen=0; /* record length of received packets */
+
+#ifdef NFGVMIN
+ READLINE_PF(1);
+#else
+ purgeline(0);
+#endif
+
+et_tu:
+ Firstsec=TRUE;
+ zi->eof_seen=FALSE;
+ sendline(Crcflg?WANTCRC:NAK);
+ flushmo();
+ purgeline(0); /* Do read next time ... */
+ while ((c = wcgetsec(&Blklen, rpn, 100)) != 0) {
+ if (c == WCEOT) {
+ zperr( _("Pathname fetch returned EOT"));
+ sendline(ACK);
+ flushmo();
+ purgeline(0); /* Do read next time ... */
+ READLINE_PF(1);
+ goto et_tu;
+ }
+ return ERROR;
+ }
+ sendline(ACK);
+ flushmo();
+ return OK;
+}
+
+/*
+ * Adapted from CMODEM13.C, written by
+ * Jack M. Wierda and Roderick W. Hart
+ */
+static int
+wcrx(struct zm_fileinfo *zi)
+{
+ register int sectnum, sectcurr;
+ register char sendchar;
+ size_t Blklen;
+
+ Firstsec=TRUE;sectnum=0;
+ zi->eof_seen=FALSE;
+ sendchar=Crcflg?WANTCRC:NAK;
+
+ for (;;) {
+ sendline(sendchar); /* send it now, we're ready! */
+ flushmo();
+ purgeline(0); /* Do read next time ... */
+ sectcurr=wcgetsec(&Blklen, secbuf,
+ (unsigned int) ((sectnum&0177) ? 50 : 130));
+ report(sectcurr);
+ if (sectcurr==((sectnum+1) &0377)) {
+ sectnum++;
+ /* if using xmodem we don't know how long a file is */
+ if (zi->bytes_total && R_BYTESLEFT(zi) < Blklen)
+ Blklen=R_BYTESLEFT(zi);
+ zi->bytes_received+=Blklen;
+ if (putsec(zi, secbuf, Blklen)==ERROR)
+ return ERROR;
+ sendchar=ACK;
+ }
+ else if (sectcurr==(sectnum&0377)) {
+ zperr( _("Received dup Sector"));
+ sendchar=ACK;
+ }
+ else if (sectcurr==WCEOT) {
+ if (closeit(zi))
+ return ERROR;
+ sendline(ACK);
+ flushmo();
+ purgeline(0); /* Do read next time ... */
+ return OK;
+ }
+ else if (sectcurr==ERROR)
+ return ERROR;
+ else {
+ zperr( _("Sync Error"));
+ return ERROR;
+ }
+ }
+}
+
+/*
+ * Wcgetsec fetches a Ward Christensen type sector.
+ * Returns sector number encountered or ERROR if valid sector not received,
+ * or CAN CAN received
+ * or WCEOT if eot sector
+ * time is timeout for first char, set to 4 seconds thereafter
+ ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
+ * (Caller must do that when he is good and ready to get next sector)
+ */
+static int
+wcgetsec(size_t *Blklen, char *rxbuf, unsigned int maxtime)
+{
+ register int checksum, wcj, firstch;
+ register unsigned short oldcrc;
+ register char *p;
+ int sectcurr;
+
+ for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
+
+ if ((firstch=READLINE_PF(maxtime))==STX) {
+ *Blklen=1024; goto get2;
+ }
+ if (firstch==SOH) {
+ *Blklen=128;
+get2:
+ sectcurr=READLINE_PF(1);
+ if ((sectcurr+(oldcrc=READLINE_PF(1)))==0377) {
+ oldcrc=checksum=0;
+ for (p=rxbuf,wcj=*Blklen; --wcj>=0; ) {
+ if ((firstch=READLINE_PF(1)) < 0)
+ goto bilge;
+ oldcrc=updcrc(firstch, oldcrc);
+ checksum += (*p++ = firstch);
+ }
+ if ((firstch=READLINE_PF(1)) < 0)
+ goto bilge;
+ if (Crcflg) {
+ oldcrc=updcrc(firstch, oldcrc);
+ if ((firstch=READLINE_PF(1)) < 0)
+ goto bilge;
+ oldcrc=updcrc(firstch, oldcrc);
+ if (oldcrc & 0xFFFF)
+ zperr( _("CRC"));
+ else {
+ Firstsec=FALSE;
+ return sectcurr;
+ }
+ }
+ else if (((checksum-firstch)&0377)==0) {
+ Firstsec=FALSE;
+ return sectcurr;
+ }
+ else
+ zperr( _("Checksum"));
+ }
+ else
+ zperr(_("Sector number garbled"));
+ }
+ /* make sure eot really is eot and not just mixmash */
+#ifdef NFGVMIN
+ else if (firstch==EOT && READLINE_PF(1)==TIMEOUT)
+ return WCEOT;
+#else
+ else if (firstch==EOT && READLINE_PF>0)
+ return WCEOT;
+#endif
+ else if (firstch==CAN) {
+ if (Lastrx==CAN) {
+ zperr( _("Sender Cancelled"));
+ return ERROR;
+ } else {
+ Lastrx=CAN;
+ continue;
+ }
+ }
+ else if (firstch==TIMEOUT) {
+ if (Firstsec)
+ goto humbug;
+bilge:
+ zperr( _("TIMEOUT"));
+ }
+ else
+ zperr( _("Got 0%o sector header"), firstch);
+
+humbug:
+ Lastrx=0;
+ {
+ int cnt=1000;
+ while(cnt-- && READLINE_PF(1)!=TIMEOUT)
+ ;
+ }
+ if (Firstsec) {
+ sendline(Crcflg?WANTCRC:NAK);
+ flushmo();
+ purgeline(0); /* Do read next time ... */
+ } else {
+ maxtime=40;
+ sendline(NAK);
+ flushmo();
+ purgeline(0); /* Do read next time ... */
+ }
+ }
+ /* try to stop the bubble machine. */
+ canit(STDOUT_FILENO);
+ return ERROR;
+}
+
+#define ZCRC_DIFFERS (ERROR+1)
+#define ZCRC_EQUAL (ERROR+2)
+/*
+ * do ZCRC-Check for open file f.
+ * check at most check_bytes bytes (crash recovery). if 0 -> whole file.
+ * remote file size is remote_bytes.
+ */
+static int
+do_crc_check(FILE *f, size_t remote_bytes, size_t check_bytes)
+{
+ struct stat st;
+ unsigned long crc;
+ unsigned long rcrc;
+ size_t n;
+ int c;
+ int t1=0,t2=0;
+ if (-1==fstat(fileno(f),&st)) {
+ DO_SYSLOG((LOG_ERR,"cannot fstat open file: %s",strerror(errno)));
+ return ERROR;
+ }
+ if (check_bytes==0 && ((size_t) st.st_size)!=remote_bytes)
+ return ZCRC_DIFFERS; /* shortcut */
+
+ crc=0xFFFFFFFFL;
+ n=check_bytes;
+ if (n==0)
+ n=st.st_size;
+ while (n-- && ((c = getc(f)) != EOF))
+ crc = UPDC32(c, crc);
+ crc = ~crc;
+ clearerr(f); /* Clear EOF */
+ fseek(f, 0L, 0);
+
+ while (t1<3) {
+ stohdr(check_bytes);
+ zshhdr(ZCRC, Txhdr);
+ while(t2<3) {
+ size_t tmp;
+ c = zgethdr(Rxhdr, 0, &tmp);
+ rcrc=(unsigned long) tmp;
+ switch (c) {
+ default: /* ignore */
+ break;
+ case ZFIN:
+ return ERROR;
+ case ZRINIT:
+ return ERROR;
+ case ZCAN:
+ if (Verbose)
+ vstringf(_("got ZCAN"));
+ return ERROR;
+ break;
+ case ZCRC:
+ if (crc!=rcrc)
+ return ZCRC_DIFFERS;
+ return ZCRC_EQUAL;
+ break;
+ }
+ }
+ }
+ return ERROR;
+}
+
+/*
+ * Process incoming file information header
+ */
+static int
+procheader(char *name, struct zm_fileinfo *zi)
+{
+ const char *openmode;
+ char *p;
+ static char *name_static=NULL;
+ char *nameend;
+
+ if (name_static)
+ free(name_static);
+ if (junk_path) {
+ p=strrchr(name,'/');
+ if (p) {
+ p++;
+ if (!*p) {
+ /* alert - file name ended in with a / */
+ if (Verbose)
+ vstringf(_("file name ends with a /, skipped: %s\n"),name);
+ DO_SYSLOG((LOG_ERR,"file name ends with a /, skipped: %s", name));
+ return ERROR;
+ }
+ name=p;
+ }
+ }
+ name_static=malloc(strlen(name)+1);
+ if (!name_static)
+ error(1,0,_("out of memory"));
+ strcpy(name_static,name);
+ zi->fname=name_static;
+
+ if (Verbose>2) {
+ vstringf(_("zmanag=%d, Lzmanag=%d\n"),zmanag,Lzmanag);
+ vstringf(_("zconv=%d\n"),zconv);
+ }
+
+ /* set default parameters and overrides */
+ openmode = "w";
+ Thisbinary = (!Rxascii) || Rxbinary;
+ if (Lzmanag)
+ zmanag = Lzmanag;
+
+ /*
+ * Process ZMODEM remote file management requests
+ */
+ if (!Rxbinary && zconv == ZCNL) /* Remote ASCII override */
+ Thisbinary = 0;
+ if (zconv == ZCBIN) /* Remote Binary override */
+ Thisbinary = TRUE;
+ if (Thisbinary && zconv == ZCBIN && try_resume)
+ zconv=ZCRESUM;
+ if (zmanag == ZF1_ZMAPND && zconv!=ZCRESUM)
+ openmode = "a";
+ if (skip_if_not_found)
+ openmode="r+";
+
+#ifdef ENABLE_TIMESYNC
+ in_timesync=0;
+ if (timesync_flag && 0==strcmp(name,"$time$.t"))
+ in_timesync=1;
+#endif
+
+ zi->bytes_total = DEFBYTL;
+ zi->mode = 0;
+ zi->eof_seen = 0;
+ zi->modtime = 0;
+
+ nameend = name + 1 + strlen(name);
+ if (*nameend) { /* file coming from Unix or DOS system */
+ long modtime;
+ long bytes_total;
+ int mode;
+ sscanf(nameend, "%ld%lo%o", &bytes_total, &modtime, &mode);
+ zi->modtime=modtime;
+ zi->bytes_total=bytes_total;
+ zi->mode=mode;
+ if (zi->mode & UNIXFILE)
+ ++Thisbinary;
+ }
+
+ /* Check for existing file */
+ if (zconv != ZCRESUM && !Rxclob && (zmanag&ZF1_ZMMASK) != ZF1_ZMCLOB
+ && (zmanag&ZF1_ZMMASK) != ZF1_ZMAPND
+#ifdef ENABLE_TIMESYNC
+ && !in_timesync
+#endif
+ && (fout=fopen(name, "r"))) {
+ struct stat sta;
+ char *tmpname;
+ char *ptr;
+ int i;
+ if (zmanag == ZF1_ZMNEW || zmanag==ZF1_ZMNEWL) {
+ if (-1==fstat(fileno(fout),&sta)) {
+#ifdef ENABLE_SYSLOG
+ int e=errno;
+#endif
+ if (Verbose)
+ vstringf(_("file exists, skipped: %s\n"),name);
+ DO_SYSLOG((LOG_ERR,"cannot fstat open file %s: %s",
+ name,strerror(e)));
+ return ERROR;
+ }
+ if (zmanag == ZF1_ZMNEW) {
+ if (sta.st_mtime > zi->modtime) {
+ DO_SYSLOG((LOG_INFO,"skipping %s: newer file exists", name));
+ return ERROR; /* skips file */
+ }
+ } else {
+ /* newer-or-longer */
+ if (((size_t) sta.st_size) >= zi->bytes_total
+ && sta.st_mtime > zi->modtime) {
+ DO_SYSLOG((LOG_INFO,"skipping %s: longer+newer file exists", name));
+ return ERROR; /* skips file */
+ }
+ }
+ fclose(fout);
+ } else if (zmanag==ZF1_ZMCRC) {
+ int r=do_crc_check(fout,zi->bytes_total,0);
+ if (r==ERROR) {
+ fclose(fout);
+ return ERROR;
+ }
+ if (r!=ZCRC_DIFFERS) {
+ return ERROR; /* skips */
+ }
+ fclose(fout);
+ } else {
+ size_t namelen;
+ fclose(fout);
+ if ((zmanag & ZF1_ZMMASK)!=ZF1_ZMCHNG) {
+ if (Verbose)
+ vstringf(_("file exists, skipped: %s\n"),name);
+ return ERROR;
+ }
+ /* try to rename */
+ namelen=strlen(name);
+ tmpname=alloca(namelen+5);
+ memcpy(tmpname,name,namelen);
+ ptr=tmpname+namelen;
+ *ptr++='.';
+ i=0;
+ do {
+ sprintf(ptr,"%d",i++);
+ } while (i<1000 && stat(tmpname,&sta)==0);
+ if (i==1000)
+ return ERROR;
+ free(name_static);
+ name_static=malloc(strlen(tmpname)+1);
+ if (!name_static)
+ error(1,0,_("out of memory"));
+ strcpy(name_static,tmpname);
+ zi->fname=name_static;
+ }
+ }
+
+ if (!*nameend) { /* File coming from CP/M system */
+ for (p=name_static; *p; ++p) /* change / to _ */
+ if ( *p == '/')
+ *p = '_';
+
+ if ( *--p == '.') /* zap trailing period */
+ *p = 0;
+ }
+
+#ifdef ENABLE_TIMESYNC
+ if (in_timesync)
+ {
+ long t=time(0);
+ long d=t-zi->modtime;
+ if (d<0)
+ d=0;
+ if ((Verbose && d>60) || Verbose > 1)
+ vstringf(_("TIMESYNC: here %ld, remote %ld, diff %ld seconds\n"),
+ (long) t, (long) zi->modtime, d);
+#ifdef HAVE_SETTIMEOFDAY
+ if (timesync_flag > 1 && d > 10)
+ {
+ struct timeval tv;
+ tv.tv_sec=zi->modtime;
+ tv.tv_usec=0;
+ if (settimeofday(&tv,NULL))
+ vstringf(_("TIMESYNC: cannot set time: %s\n"),
+ strerror(errno));
+ }
+#endif
+ return ERROR; /* skips file */
+ }
+#endif /* ENABLE_TIMESYNC */
+
+ if (!zmodem_requested && MakeLCPathname && !IsAnyLower(name_static)
+ && !(zi->mode&UNIXFILE))
+ uncaps(name_static);
+ if (Topipe > 0) {
+ if (Pathname)
+ free(Pathname);
+ Pathname=malloc((PATH_MAX)*2);
+ if (!Pathname)
+ error(1,0,_("out of memory"));
+ sprintf(Pathname, "%s %s", program_name+2, name_static);
+ if (Verbose) {
+ vstringf("%s: %s %s\n",
+ _("Topipe"),
+ Pathname, Thisbinary?"BIN":"ASCII");
+ }
+ if ((fout=popen(Pathname, "w")) == NULL)
+ return ERROR;
+ } else {
+ if (protocol==ZM_XMODEM)
+ /* we don't have the filename yet */
+ return OK; /* dummy */
+ if (Pathname)
+ free(Pathname);
+ Pathname=malloc((PATH_MAX)*2);
+ if (!Pathname)
+ error(1,0,_("out of memory"));
+ strcpy(Pathname, name_static);
+ if (Verbose) {
+ /* overwrite the "waiting to receive" line */
+ vstring("\r \r");
+ vstringf(_("Receiving: %s\n"), name_static);
+ }
+ checkpath(name_static);
+ if (Nflag)
+ {
+ /* cast because we might not have a prototyp for strdup :-/ */
+ free(name_static);
+ name_static=(char *) strdup("/dev/null");
+ if (!name_static)
+ {
+ fprintf(stderr,"%s: %s\n", program_name, _("out of memory"));
+ exit(1);
+ }
+ }
+#ifdef OMEN
+ /* looks like a security hole -- uwe */
+ if (name_static[0] == '!' || name_static[0] == '|') {
+ if ( !(fout = popen(name_static+1, "w"))) {
+ return ERROR;
+ }
+ Topipe = -1; return(OK);
+ }
+#endif
+ if (Thisbinary && zconv==ZCRESUM) {
+ struct stat st;
+ fout = fopen(name_static, "r+");
+ if (fout && 0==fstat(fileno(fout),&st))
+ {
+ int can_resume=TRUE;
+ if (zmanag==ZF1_ZMCRC) {
+ int r=do_crc_check(fout,zi->bytes_total,st.st_size);
+ if (r==ERROR) {
+ fclose(fout);
+ return ZFERR;
+ }
+ if (r==ZCRC_DIFFERS) {
+ can_resume=FALSE;
+ }
+ }
+ if ((unsigned long)st.st_size > zi->bytes_total) {
+ can_resume=FALSE;
+ }
+ /* retransfer whole blocks */
+ zi->bytes_skipped = st.st_size & ~(1023);
+ if (can_resume) {
+ if (fseek(fout, (long) zi->bytes_skipped, SEEK_SET)) {
+ fclose(fout);
+ return ZFERR;
+ }
+ }
+ else
+ zi->bytes_skipped=0; /* resume impossible, file has changed */
+ goto buffer_it;
+ }
+ zi->bytes_skipped=0;
+ if (fout)
+ fclose(fout);
+ }
+ fout = fopen(name_static, openmode);
+#ifdef ENABLE_MKDIR
+ if ( !fout && Restricted < 2) {
+ if (make_dirs(name_static))
+ fout = fopen(name_static, openmode);
+ }
+#endif
+ if ( !fout)
+ {
+#ifdef ENABLE_SYSLOG
+ int e=errno;
+#endif
+ zpfatal(_("cannot open %s"), name_static);
+ DO_SYSLOG((LOG_ERR,"%s: cannot open: %s",
+ protname(),strerror(e)));
+ return ERROR;
+ }
+ }
+buffer_it:
+ if (Topipe == 0) {
+ static char *s=NULL;
+ static size_t last_length=0;
+#if defined(F_GETFD) && defined(F_SETFD) && defined(O_SYNC)
+ if (o_sync) {
+ int oldflags;
+ oldflags = fcntl (fileno(fout), F_GETFD, 0);
+ if (oldflags>=0 && !(oldflags & O_SYNC)) {
+ oldflags|=O_SYNC;
+ fcntl (fileno(fout), F_SETFD, oldflags); /* errors don't matter */
+ }
+ }
+#endif
+
+ if (buffersize==-1 && s) {
+ if (zi->bytes_total>last_length) {
+ free(s);
+ s=NULL;
+ last_length=0;
+ }
+ }
+ if (!s && buffersize) {
+ last_length=32768;
+ if (buffersize==-1) {
+ if (zi->bytes_total>0)
+ last_length=zi->bytes_total;
+ } else
+ last_length=buffersize;
+ /* buffer `4096' bytes pages */
+ last_length=(last_length+4095)&0xfffff000;
+ s=malloc(last_length);
+ if (!s) {
+ zpfatal(_("out of memory"));
+ exit(1);
+ }
+ }
+ if (s) {
+#ifdef SETVBUF_REVERSED
+ setvbuf(fout,_IOFBF,s,last_length);
+#else
+ setvbuf(fout,s,_IOFBF,last_length);
+#endif
+ }
+ }
+ zi->bytes_received=zi->bytes_skipped;
+
+ return OK;
+}
+
+#ifdef ENABLE_MKDIR
+/*
+ * Directory-creating routines from Public Domain TAR by John Gilmore
+ */
+
+/*
+ * After a file/link/symlink/dir creation has failed, see if
+ * it's because some required directory was not present, and if
+ * so, create all required dirs.
+ */
+static int
+make_dirs(char *pathname)
+{
+ register char *p; /* Points into path */
+ int madeone = 0; /* Did we do anything yet? */
+ int save_errno = errno; /* Remember caller's errno */
+
+ if (errno != ENOENT)
+ return 0; /* Not our problem */
+
+ for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
+ /* Avoid mkdir of empty string, if leading or double '/' */
+ if (p == pathname || p[-1] == '/')
+ continue;
+ /* Avoid mkdir where last part of path is '.' */
+ if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
+ continue;
+ *p = 0; /* Truncate the path there */
+ if ( !mkdir(pathname, 0777)) { /* Try to create it as a dir */
+ vfile("Made directory %s\n", pathname);
+ madeone++; /* Remember if we made one */
+ *p = '/';
+ continue;
+ }
+ *p = '/';
+ if (errno == EEXIST) /* Directory already exists */
+ continue;
+ /*
+ * Some other error in the mkdir. We return to the caller.
+ */
+ break;
+ }
+ errno = save_errno; /* Restore caller's errno */
+ return madeone; /* Tell them to retry if we made one */
+}
+
+#endif /* ENABLE_MKDIR */
+
+/*
+ * Putsec writes the n characters of buf to receive file fout.
+ * If not in binary mode, carriage returns, and all characters
+ * starting with CPMEOF are discarded.
+ */
+static int
+putsec(struct zm_fileinfo *zi, char *buf, size_t n)
+{
+ register char *p;
+
+ if (n == 0)
+ return OK;
+ if (Thisbinary) {
+ if (fwrite(buf,n,1,fout)!=1)
+ return ERROR;
+ }
+ else {
+ if (zi->eof_seen)
+ return OK;
+ for (p=buf; n>0; ++p,n-- ) {
+ if ( *p == '\r')
+ continue;
+ if (*p == CPMEOF) {
+ zi->eof_seen=TRUE;
+ return OK;
+ }
+ putc(*p ,fout);
+ }
+ }
+ return OK;
+}
+
+/* make string s lower case */
+static void
+uncaps(char *s)
+{
+ for ( ; *s; ++s)
+ if (isupper((unsigned char)(*s)))
+ *s = tolower(*s);
+}
+/*
+ * IsAnyLower returns TRUE if string s has lower case letters.
+ */
+static int
+IsAnyLower(const char *s)
+{
+ for ( ; *s; ++s)
+ if (islower((unsigned char)(*s)))
+ return TRUE;
+ return FALSE;
+}
+
+static void
+report(int sct)
+{
+ if (Verbose>1)
+ {
+ vstringf(_("Blocks received: %d"),sct);
+ vchar('\r');
+ }
+}
+
+/*
+ * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
+ * If called as [-][dir/../]rzCOMMAND set the pipe flag
+ * If called as rb use YMODEM protocol
+ */
+static void
+chkinvok(const char *s)
+{
+ const char *p;
+
+ p = s;
+ while (*p == '-')
+ s = ++p;
+ while (*p)
+ if (*p++ == '/')
+ s = p;
+ if (*s == 'v') {
+ Verbose=1; ++s;
+ }
+ program_name = s;
+ if (*s == 'l')
+ s++; /* lrz -> rz */
+ protocol=ZM_ZMODEM;
+ if (s[0]=='r' && s[1]=='x')
+ protocol=ZM_XMODEM;
+ if (s[0]=='r' && (s[1]=='b' || s[1]=='y'))
+ protocol=ZM_YMODEM;
+ if (s[2] && protocol!=ZM_XMODEM)
+ Topipe = 1;
+}
+
+/*
+ * Totalitarian Communist pathname processing
+ */
+static void
+checkpath(const char *name)
+{
+ if (Restricted) {
+ const char *p;
+ p=strrchr(name,'/');
+ if (p)
+ p++;
+ else
+ p=name;
+ /* don't overwrite any file in very restricted mode.
+ * don't overwrite hidden files in restricted mode */
+ if ((Restricted==2 || *name=='.') && fopen(name, "r") != NULL) {
+ canit(STDOUT_FILENO);
+ vstring("\r\n");
+ vstringf(_("%s: %s exists\n"),
+ program_name, name);
+ bibi(-1);
+ }
+ /* restrict pathnames to current tree or uucppublic */
+ if ( strstr(name, "../")
+#ifdef PUBDIR
+ || (name[0]== '/' && strncmp(name, PUBDIR,
+ strlen(PUBDIR)))
+#endif
+ ) {
+ canit(STDOUT_FILENO);
+ vstring("\r\n");
+ vstringf(_("%s:\tSecurity Violation"),program_name);
+ vstring("\r\n");
+ bibi(-1);
+ }
+ if (Restricted > 1) {
+ if (name[0]=='.' || strstr(name,"/.")) {
+ canit(STDOUT_FILENO);
+ vstring("\r\n");
+ vstringf(_("%s:\tSecurity Violation"),program_name);
+ vstring("\r\n");
+ bibi(-1);
+ }
+ }
+ }
+}
+
+/*
+ * Initialize for Zmodem receive attempt, try to activate Zmodem sender
+ * Handles ZSINIT frame
+ * Return ZFILE if Zmodem filename received, -1 on error,
+ * ZCOMPL if transaction finished, else 0
+ */
+static int
+tryz(void)
+{
+ register int c, n;
+ register int cmdzack1flg;
+ int zrqinits_received=0;
+ size_t bytes_in_block=0;
+
+ if (protocol!=ZM_ZMODEM) /* Check for "rb" program name */
+ return 0;
+
+ for (n=zmodem_requested?15:5;
+ (--n + zrqinits_received) >=0 && zrqinits_received<10; ) {
+ /* Set buffer length (0) and capability flags */
+#ifdef SEGMENTS
+ stohdr(SEGMENTS*MAX_BLOCK);
+#else
+ stohdr(0L);
+#endif
+#ifdef CANBREAK
+ Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
+#else
+ Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
+#endif
+#ifdef ENABLE_TIMESYNC
+ if (timesync_flag)
+ Txhdr[ZF1] |= ZF1_TIMESYNC;
+#endif
+ if (Zctlesc)
+ Txhdr[ZF0] |= TESCCTL; /* TESCCTL == ESCCTL */
+ zshhdr(tryzhdrtype, Txhdr);
+
+ if (tryzhdrtype == ZSKIP) /* Don't skip too far */
+ tryzhdrtype = ZRINIT; /* CAF 8-21-87 */
+again:
+ switch (zgethdr(Rxhdr, 0, NULL)) {
+ case ZRQINIT:
+ /* getting one ZRQINIT is totally ok. Normally a ZFILE follows
+ * (and might be in our buffer, so don't purge it). But if we
+ * get more ZRQINITs than the sender has started up before us
+ * and sent ZRQINITs while waiting.
+ */
+ zrqinits_received++;
+ continue;
+
+ case ZEOF:
+ continue;
+ case TIMEOUT:
+ continue;
+ case ZFILE:
+ zconv = Rxhdr[ZF0];
+ if (!zconv)
+ /* resume with sz -r is impossible (at least with unix sz)
+ * if this is not set */
+ zconv=ZCBIN;
+ if (Rxhdr[ZF1] & ZF1_ZMSKNOLOC) {
+ Rxhdr[ZF1] &= ~(ZF1_ZMSKNOLOC);
+ skip_if_not_found=TRUE;
+ }
+ zmanag = Rxhdr[ZF1];
+ ztrans = Rxhdr[ZF2];
+ tryzhdrtype = ZRINIT;
+ c = zrdata(secbuf, MAX_BLOCK,&bytes_in_block);
+ io_mode(0,3);
+ if (c == GOTCRCW)
+ return ZFILE;
+ zshhdr(ZNAK, Txhdr);
+ goto again;
+ case ZSINIT:
+ /* this once was:
+ * Zctlesc = TESCCTL & Rxhdr[ZF0];
+ * trouble: if rz get --escape flag:
+ * - it sends TESCCTL to sz,
+ * get a ZSINIT _without_ TESCCTL (yeah - sender didn't know),
+ * overwrites Zctlesc flag ...
+ * - sender receives TESCCTL and uses "|=..."
+ * so: sz escapes, but rz doesn't unescape ... not good.
+ */
+ Zctlesc |= TESCCTL & Rxhdr[ZF0];
+ if (zrdata(Attn, ZATTNLEN,&bytes_in_block) == GOTCRCW) {
+ stohdr(1L);
+ zshhdr(ZACK, Txhdr);
+ goto again;
+ }
+ zshhdr(ZNAK, Txhdr);
+ goto again;
+ case ZFREECNT:
+ stohdr(getfree());
+ zshhdr(ZACK, Txhdr);
+ goto again;
+ case ZCOMMAND:
+ cmdzack1flg = Rxhdr[ZF0];
+ if (zrdata(secbuf, MAX_BLOCK,&bytes_in_block) == GOTCRCW) {
+ if (Verbose)
+ {
+ vstringf("%s: %s\n", program_name,
+ _("remote command execution requested"));
+ vstringf("%s: %s\n", program_name, secbuf);
+ }
+ if (!allow_remote_commands)
+ {
+ if (Verbose)
+ vstringf("%s: %s\n", program_name,
+ _("not executed"));
+ zshhdr(ZCOMPL, Txhdr);
+ DO_SYSLOG((LOG_INFO,"rexec denied: %s",secbuf));
+ return ZCOMPL;
+ }
+ DO_SYSLOG((LOG_INFO,"rexec allowed: %s",secbuf));
+ if (cmdzack1flg & ZCACK1)
+ stohdr(0L);
+ else
+ stohdr((size_t)sys2(secbuf));
+ purgeline(0); /* dump impatient questions */
+ do {
+ zshhdr(ZCOMPL, Txhdr);
+ }
+ while (++errors<20 && zgethdr(Rxhdr,1, NULL) != ZFIN);
+ ackbibi();
+ if (cmdzack1flg & ZCACK1)
+ exec2(secbuf);
+ return ZCOMPL;
+ }
+ zshhdr(ZNAK, Txhdr);
+ goto again;
+ case ZCOMPL:
+ goto again;
+ default:
+ continue;
+ case ZFIN:
+ ackbibi();
+ return ZCOMPL;
+ case ZRINIT:
+ if (Verbose)
+ vstringf(_("got ZRINIT"));
+ return ERROR;
+ case ZCAN:
+ if (Verbose)
+ vstringf(_("got ZCAN"));
+ return ERROR;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ * Receive 1 or more files with ZMODEM protocol
+ */
+static int
+rzfiles(struct zm_fileinfo *zi)
+{
+ register int c;
+
+ for (;;) {
+ timing(1,NULL);
+ c = rzfile(zi);
+ switch (c) {
+ case ZEOF:
+ if (Verbose > 1
+#ifdef ENABLE_SYSLOG
+ || enable_syslog
+#endif
+ ) {
+ double d;
+ long bps;
+ d=timing(0,NULL);
+ if (d==0)
+ d=0.5; /* can happen if timing uses time() */
+ bps=(zi->bytes_received-zi->bytes_skipped)/d;
+ if (Verbose > 1) {
+ vstringf(
+ _("\rBytes received: %7ld/%7ld BPS:%-6ld \r\n"),
+ (long) zi->bytes_received, (long) zi->bytes_total, bps);
+ }
+ DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: %ld Bytes, %ld BPS",shortname,
+ protname(), (long) zi->bytes_total,bps));
+ }
+ /* FALL THROUGH */
+ case ZSKIP:
+ if (c==ZSKIP)
+ {
+ if (Verbose)
+ vstringf(_("Skipped"));
+ DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: skipped",shortname,protname()));
+ }
+ switch (tryz()) {
+ case ZCOMPL:
+ return OK;
+ default:
+ return ERROR;
+ case ZFILE:
+ break;
+ }
+ continue;
+ default:
+ return c;
+ case ERROR:
+ DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: error",shortname,protname()));
+ return ERROR;
+ }
+ }
+}
+
+/* "OOSB" means Out Of Sync Block. I once thought that if sz sents
+ * blocks a,b,c,d, of which a is ok, b fails, we might want to save
+ * c and d. But, alas, i never saw c and d.
+ */
+#define SAVE_OOSB
+#ifdef SAVE_OOSB
+typedef struct oosb_t {
+ size_t pos;
+ size_t len;
+ char *data;
+ struct oosb_t *next;
+} oosb_t;
+struct oosb_t *anker=NULL;
+#endif
+
+/*
+ * Receive a file with ZMODEM protocol
+ * Assumes file name frame is in secbuf
+ */
+static int
+rzfile(struct zm_fileinfo *zi)
+{
+ register int c, n;
+ long last_rxbytes=0;
+ unsigned long last_bps=0;
+ long not_printed=0;
+ time_t low_bps=0;
+ size_t bytes_in_block=0;
+
+ zi->eof_seen=FALSE;
+
+ n = 20;
+
+ if (procheader(secbuf,zi) == ERROR) {
+ DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: procheader error",
+ shortname,protname()));
+ return (tryzhdrtype = ZSKIP);
+ }
+
+ for (;;) {
+#ifdef SEGMENTS
+ chinseg = 0;
+#endif
+ stohdr(zi->bytes_received);
+ zshhdr(ZRPOS, Txhdr);
+ goto skip_oosb;
+nxthdr:
+#ifdef SAVE_OOSB
+ if (anker) {
+ oosb_t *akt,*last,*next;
+ for (akt=anker,last=NULL;akt;last= akt ? akt : last ,akt=next) {
+ if (akt->pos==zi->bytes_received) {
+ putsec(zi, akt->data, akt->len);
+ zi->bytes_received += akt->len;
+ vfile("using saved out-of-sync-paket %lx, len %ld",
+ akt->pos,akt->len);
+ goto nxthdr;
+ }
+ next=akt->next;
+ if (akt->pos<zi->bytes_received) {
+ vfile("removing unneeded saved out-of-sync-paket %lx, len %ld",
+ akt->pos,akt->len);
+ if (last)
+ last->next=akt->next;
+ else
+ anker=akt->next;
+ free(akt->data);
+ free(akt);
+ akt=NULL;
+ }
+ }
+ }
+#endif
+ skip_oosb:
+ c = zgethdr(Rxhdr, 0, NULL);
+ switch (c) {
+ default:
+ DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: error: zgethdr returned %d",shortname,
+ protname(),c));
+ vfile("rzfile: zgethdr returned %d", c);
+ return ERROR;
+ case ZNAK:
+ case TIMEOUT:
+#ifdef SEGMENTS
+ putsec(secbuf, chinseg);
+ chinseg = 0;
+#endif
+ if ( --n < 0) {
+ DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: error: zgethdr returned %s",shortname,
+ protname(),c == ZNAK ? "ZNAK" : "TIMEOUT"));
+ vfile("rzfile: zgethdr returned %d", c);
+ return ERROR;
+ }
+ case ZFILE:
+ zrdata(secbuf, MAX_BLOCK,&bytes_in_block);
+ continue;
+ case ZEOF:
+#ifdef SEGMENTS
+ putsec(secbuf, chinseg);
+ chinseg = 0;
+#endif
+ if (rclhdr(Rxhdr) != (long) zi->bytes_received) {
+ /*
+ * Ignore eof if it's at wrong place - force
+ * a timeout because the eof might have gone
+ * out before we sent our zrpos.
+ */
+ errors = 0; goto nxthdr;
+ }
+ if (closeit(zi)) {
+ tryzhdrtype = ZFERR;
+ DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: error: closeit return <>0",
+ shortname, protname()));
+ vfile("rzfile: closeit returned <> 0");
+ return ERROR;
+ }
+ vfile("rzfile: normal EOF");
+ return c;
+ case ERROR: /* Too much garbage in header search error */
+#ifdef SEGMENTS
+ putsec(secbuf, chinseg);
+ chinseg = 0;
+#endif
+ if ( --n < 0) {
+ DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: error: zgethdr returned %d",
+ shortname, protname(),c));
+ vfile("rzfile: zgethdr returned %d", c);
+ return ERROR;
+ }
+ zmputs(Attn);
+ continue;
+ case ZSKIP:
+#ifdef SEGMENTS
+ putsec(secbuf, chinseg);
+ chinseg = 0;
+#endif
+ closeit(zi);
+ DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: error: sender skipped",
+ shortname, protname()));
+ vfile("rzfile: Sender SKIPPED file");
+ return c;
+ case ZDATA:
+ if (rclhdr(Rxhdr) != (long) zi->bytes_received) {
+#if defined(SAVE_OOSB)
+ oosb_t *neu;
+ size_t pos=rclhdr(Rxhdr);
+#endif
+ if ( --n < 0) {
+ vfile("rzfile: out of sync");
+ DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: error: out of sync",
+ shortname, protname()));
+ return ERROR;
+ }
+#if defined(SAVE_OOSB)
+ switch (c = zrdata(secbuf, MAX_BLOCK,&bytes_in_block))
+ {
+ case GOTCRCW:
+ case GOTCRCG:
+ case GOTCRCE:
+ case GOTCRCQ:
+ if (pos>zi->bytes_received) {
+ neu=malloc(sizeof(oosb_t));
+ if (neu)
+ neu->data=malloc(bytes_in_block);
+ if (neu && neu->data) {
+#ifdef ENABLE_SYSLOG
+/* call syslog to tell me if this happens */
+ lsyslog(LOG_ERR,
+ "saving out-of-sync-block %lx, len %lu",
+ pos, (unsigned long) bytes_in_block);
+#endif
+ vfile("saving out-of-sync-block %lx, len %lu",pos,
+ (unsigned long) bytes_in_block);
+ memcpy(neu->data,secbuf,bytes_in_block);
+ neu->pos=pos;
+ neu->len=bytes_in_block;
+ neu->next=anker;
+ anker=neu;
+ }
+ else if (neu)
+ free(neu);
+ }
+ }
+#endif
+#ifdef SEGMENTS
+ putsec(secbuf, chinseg);
+ chinseg = 0;
+#endif
+ zmputs(Attn); continue;
+ }
+moredata:
+ if ((Verbose>1 || min_bps || stop_time)
+ && (not_printed > (min_bps ? 3 : 7)
+ || zi->bytes_received > last_bps / 2 + last_rxbytes)) {
+ int minleft = 0;
+ int secleft = 0;
+ time_t now;
+ double d;
+ d=timing(0,&now);
+ if (d==0)
+ d=0.5; /* timing() might use time() */
+ last_bps=zi->bytes_received/d;
+ if (last_bps > 0) {
+ minleft = (R_BYTESLEFT(zi))/last_bps/60;
+ secleft = ((R_BYTESLEFT(zi))/last_bps)%60;
+ }
+ if (min_bps) {
+ if (low_bps) {
+ if (last_bps<min_bps) {
+ if (now-low_bps>=min_bps_time) {
+ /* too bad */
+ vfile(_("rzfile: bps rate %ld below min %ld"),
+ last_bps, min_bps);
+ DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: bps rate low: %ld < %ld",
+ shortname, protname(), last_bps, min_bps));
+ return ERROR;
+ }
+ }
+ else
+ low_bps=0;
+ } else if (last_bps<min_bps) {
+ low_bps=now;
+ }
+ }
+ if (stop_time && now>=stop_time) {
+ /* too bad */
+ vfile(_("rzfile: reached stop time"));
+ DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: reached stop time",
+ shortname, protname()));
+ return ERROR;
+ }
+
+ if (Verbose > 1) {
+ vstringf(_("\rBytes received: %7ld/%7ld BPS:%-6ld ETA %02d:%02d "),
+ (long) zi->bytes_received, (long) zi->bytes_total,
+ last_bps, minleft, secleft);
+ last_rxbytes=zi->bytes_received;
+ not_printed=0;
+ }
+ } else if (Verbose)
+ not_printed++;
+#ifdef SEGMENTS
+ if (chinseg >= (MAX_BLOCK * SEGMENTS)) {
+ putsec(secbuf, chinseg);
+ chinseg = 0;
+ }
+ switch (c = zrdata(secbuf+chinseg, MAX_BLOCK,&bytes_in_block))
+#else
+ switch (c = zrdata(secbuf, MAX_BLOCK,&bytes_in_block))
+#endif
+ {
+ case ZCAN:
+#ifdef SEGMENTS
+ putsec(secbuf, chinseg);
+ chinseg = 0;
+#endif
+ vfile("rzfile: zrdata returned %d", c);
+ DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: zrdata returned ZCAN",
+ shortname, protname()));
+ return ERROR;
+ case ERROR: /* CRC error */
+#ifdef SEGMENTS
+ putsec(secbuf, chinseg);
+ chinseg = 0;
+#endif
+ if ( --n < 0) {
+ vfile("rzfile: zgethdr returned %d", c);
+ DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: zrdata returned ERROR",
+ shortname, protname()));
+ return ERROR;
+ }
+ zmputs(Attn);
+ continue;
+ case TIMEOUT:
+#ifdef SEGMENTS
+ putsec(secbuf, chinseg);
+ chinseg = 0;
+#endif
+ if ( --n < 0) {
+ DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: zrdata returned TIMEOUT",
+ shortname, protname()));
+ vfile("rzfile: zgethdr returned %d", c);
+ return ERROR;
+ }
+ continue;
+ case GOTCRCW:
+ n = 20;
+#ifdef SEGMENTS
+ chinseg += bytes_in_block;
+ putsec(zi, secbuf, chinseg);
+ chinseg = 0;
+#else
+ putsec(zi, secbuf, bytes_in_block);
+#endif
+ zi->bytes_received += bytes_in_block;
+ stohdr(zi->bytes_received);
+ zshhdr(ZACK | 0x80, Txhdr);
+ goto nxthdr;
+ case GOTCRCQ:
+ n = 20;
+#ifdef SEGMENTS
+ chinseg += bytes_in_block;
+#else
+ putsec(zi, secbuf, bytes_in_block);
+#endif
+ zi->bytes_received += bytes_in_block;
+ stohdr(zi->bytes_received);
+ zshhdr(ZACK, Txhdr);
+ goto moredata;
+ case GOTCRCG:
+ n = 20;
+#ifdef SEGMENTS
+ chinseg += bytes_in_block;
+#else
+ putsec(zi, secbuf, bytes_in_block);
+#endif
+ zi->bytes_received += bytes_in_block;
+ goto moredata;
+ case GOTCRCE:
+ n = 20;
+#ifdef SEGMENTS
+ chinseg += bytes_in_block;
+#else
+ putsec(zi, secbuf, bytes_in_block);
+#endif
+ zi->bytes_received += bytes_in_block;
+ goto nxthdr;
+ }
+ }
+ }
+}
+
+/*
+ * Send a string to the modem, processing for \336 (sleep 1 sec)
+ * and \335 (break signal)
+ */
+static void
+zmputs(const char *s)
+{
+ const char *p;
+
+ while (s && *s)
+ {
+ p=strpbrk(s,"\335\336");
+ if (!p)
+ {
+ write(1,s,strlen(s));
+ return;
+ }
+ if (p!=s)
+ {
+ write(1,s,(size_t) (p-s));
+ s=p;
+ }
+ if (*p=='\336')
+ sleep(1);
+ else
+ sendbrk(0);
+ p++;
+ }
+}
+
+/*
+ * Close the receive dataset, return OK or ERROR
+ */
+static int
+closeit(struct zm_fileinfo *zi)
+{
+ int ret;
+ if (Topipe) {
+ if (pclose(fout)) {
+ return ERROR;
+ }
+ return OK;
+ }
+ ret=fclose(fout);
+ if (ret) {
+ zpfatal(_("file close error"));
+ /* this may be any sort of error, including random data corruption */
+
+ unlink(Pathname);
+ return ERROR;
+ }
+ if (zi->modtime) {
+#ifdef HAVE_STRUCT_UTIMBUF
+ struct utimbuf timep;
+ timep.actime = time(NULL);
+ timep.modtime = zi->modtime;
+ utime(Pathname, &timep);
+#else
+ time_t timep[2];
+ timep[0] = time(NULL);
+ timep[1] = zi->modtime;
+ utime(Pathname, timep);
+#endif
+ }
+#ifdef S_ISREG
+ if (S_ISREG(zi->mode)) {
+#else
+ if ((zi->mode&S_IFMT) == S_IFREG) {
+#endif
+ /* we must not make this program executable if running
+ * under rsh, because the user might have uploaded an
+ * unrestricted shell.
+ */
+ if (under_rsh)
+ chmod(Pathname, (00666 & zi->mode));
+ else
+ chmod(Pathname, (07777 & zi->mode));
+ }
+ return OK;
+}
+
+/*
+ * Ack a ZFIN packet, let byegones be byegones
+ */
+static void
+ackbibi(void)
+{
+ int n;
+
+ vfile("ackbibi:");
+ Readnum = 1;
+ stohdr(0L);
+ for (n=3; --n>=0; ) {
+ purgeline(0);
+ zshhdr(ZFIN, Txhdr);
+ switch (READLINE_PF(100)) {
+ case 'O':
+ READLINE_PF(1); /* Discard 2nd 'O' */
+ vfile("ackbibi complete");
+ return;
+ case RCDO:
+ return;
+ case TIMEOUT:
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * Strip leading ! if present, do shell escape.
+ */
+static int
+sys2(const char *s)
+{
+ if (*s == '!')
+ ++s;
+ return system(s);
+}
+
+/*
+ * Strip leading ! if present, do exec.
+ */
+static void
+exec2(const char *s)
+{
+ if (*s == '!')
+ ++s;
+ io_mode(0,0);
+ execl("/bin/sh", "sh", "-c", s);
+ zpfatal("execl");
+ exit(1);
+}
+
+/*
+ * Routine to calculate the free bytes on the current file system
+ * ~0 means many free bytes (unknown)
+ */
+static size_t
+getfree(void)
+{
+ return((size_t) (~0L)); /* many free bytes ... */
+}
+
+/* End of lrz.c */
diff --git a/lsyslog.c b/lsyslog.c
new file mode 100644
index 0000000..6baf4a2
--- /dev/null
+++ b/lsyslog.c
@@ -0,0 +1,81 @@
+/*
+ lsyslog.c - wrapper for the syslog function
+ Copyright (C) 1997 Uwe Ohse
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+*/
+#include "config.h"
+#ifdef ENABLE_SYSLOG
+#include "zglobal.h"
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#if __STDC__
+# include <stdarg.h>
+# define VA_START(args, lastarg) va_start(args, lastarg)
+# define WAYTOGO
+#else
+# include <varargs.h>
+# define VA_START(args, lastarg) va_start(args)
+#endif
+
+void
+#ifdef WAYTOGO
+lsyslog(int prio, const char *format, ...)
+#else
+lsyslog(prio,format,va_alist)
+ int prio;
+ const char *format;
+ va_dcl
+#endif
+{
+#ifdef ENABLE_SYSLOG
+ static char *username=NULL;
+ static char uid_string[20]=""; /* i'd really hate this function to fail! */
+ char *s=NULL;
+ static int init_done=0;
+ va_list ap;
+ if (!enable_syslog)
+ return;
+ if (!init_done) {
+ uid_t uid;
+ struct passwd *pwd;
+ init_done=1;
+ uid=getuid();
+ pwd=getpwuid(uid);
+ if (pwd && pwd->pw_name && *pwd->pw_name) {
+ username=strdup(pwd->pw_name);
+ }
+ if (!username) {
+ username=uid_string;
+ sprintf(uid_string,"#%lu",(unsigned long) uid);
+ }
+ }
+
+ VA_START(ap, format);
+ vasprintf(&s,format, ap);
+ va_end(ap);
+ syslog(prio,"[%s] %s",username,s);
+ free(s);
+#else
+ (void) prio; /* get rid of warning */
+ (void) format; /* get rid of warning */
+#endif
+}
+
diff --git a/lsz.c b/lsz.c
new file mode 100644
index 0000000..e04896a
--- /dev/null
+++ b/lsz.c
@@ -0,0 +1,2492 @@
+/*
+ lsz - send files with x/y/zmodem
+ Copyright (C) until 1988 Chuck Forsberg (Omen Technology INC)
+ Copyright (C) 1994 Matt Porter, Michael D. Black
+ Copyright (C) 1996, 1997 Uwe Ohse
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ originally written by Chuck Forsberg
+*/
+#include "zglobal.h"
+
+/* char *getenv(); */
+
+#define SS_NORMAL 0
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+
+#ifndef R_OK
+# define R_OK 4
+#endif
+
+#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MMAP)
+# include <sys/mman.h>
+size_t mm_size;
+void *mm_addr=NULL;
+#else
+# undef HAVE_MMAP
+#endif
+#include "timing.h"
+#include "long-options.h"
+#include "xstrtoul.h"
+#include "error.h"
+
+#ifndef STRICT_PROTOTYPES
+extern time_t time();
+extern char *strerror();
+#endif
+
+#ifndef HAVE_ERRNO_DECLARATION
+extern int errno;
+#endif
+
+unsigned Baudrate=2400; /* Default, should be set by first mode() call */
+unsigned Txwindow; /* Control the size of the transmitted window */
+unsigned Txwspac; /* Spacing between zcrcq requests */
+unsigned Txwcnt; /* Counter used to space ack requests */
+size_t Lrxpos; /* Receiver's last reported offset */
+int errors;
+enum zm_type_enum protocol;
+int under_rsh=FALSE;
+extern int turbo_escape;
+static int no_unixmode;
+
+int Canseek=1; /* 1: can; 0: only rewind, -1: neither */
+
+static int zsendfile __P ((struct zm_fileinfo *zi, const char *buf, size_t blen));
+static int getnak __P ((void));
+static int wctxpn __P ((struct zm_fileinfo *));
+static int wcs __P ((const char *oname, const char *remotename));
+static size_t zfilbuf __P ((struct zm_fileinfo *zi));
+static size_t filbuf __P ((char *buf, size_t count));
+static int getzrxinit __P ((void));
+static int calc_blklen __P ((long total_sent));
+static int sendzsinit __P ((void));
+static int wctx __P ((struct zm_fileinfo *));
+static int zsendfdata __P ((struct zm_fileinfo *));
+static int getinsync __P ((struct zm_fileinfo *, int flag));
+static void countem __P ((int argc, char **argv));
+static void chkinvok __P ((const char *s));
+static void usage __P ((int exitcode, const char *what));
+static int zsendcmd __P ((const char *buf, size_t blen));
+static void saybibi __P ((void));
+static int wcsend __P ((int argc, char *argp[]));
+static int wcputsec __P ((char *buf, int sectnum, size_t cseclen));
+static void usage1 __P ((int exitcode));
+
+#ifdef ENABLE_SYSLOG
+#define DO_SYSLOG(message) do { \
+ if (enable_syslog) { \
+ const char *shortname; \
+ if (!zi->fname) \
+ shortname="no.name"; \
+ else { \
+ shortname=strrchr(zi->fname,'/'); \
+ if (!shortname) \
+ shortname=zi->fname; \
+ else \
+ shortname++; \
+ } \
+ lsyslog message ; \
+ } \
+ } while(0)
+#else
+#define DO_SYSLOG(message) do { } while(0)
+#endif
+
+#define ZSDATA(x,y,z) \
+ do { if (Crc32t) {zsda32(x,y,z); } else {zsdata(x,y,z);}} while(0)
+#ifdef HAVE_MMAP
+#define DATAADR (mm_addr ? ((char *)mm_addr)+zi->bytes_sent : txbuf)
+#else
+#define DATAADR (txbuf)
+#endif
+
+int Filesleft;
+long Totalleft;
+size_t buffersize=16384;
+#ifdef HAVE_MMAP
+int use_mmap=1;
+#endif
+
+/*
+ * Attention string to be executed by receiver to interrupt streaming data
+ * when an error is detected. A pause (0336) may be needed before the
+ * ^C (03) or after it.
+ */
+#ifdef READCHECK
+char Myattn[] = { 0 };
+#else
+char Myattn[] = { 03, 0336, 0 };
+#endif
+
+FILE *input_f;
+
+#define MAX_BLOCK 8192
+char *txbuf;
+
+long vpos = 0; /* Number of bytes read from file */
+
+char Lastrx;
+char Crcflg;
+int Verbose=0;
+int Restricted=0; /* restricted; no /.. or ../ in filenames */
+int Quiet=0; /* overrides logic that would otherwise set verbose */
+int Ascii=0; /* Add CR's for brain damaged programs */
+int Fullname=0; /* transmit full pathname */
+int Unlinkafter=0; /* Unlink file after it is sent */
+int Dottoslash=0; /* Change foo.bar.baz to foo/bar/baz */
+int firstsec;
+int errcnt=0; /* number of files unreadable */
+size_t blklen=128; /* length of transmitted records */
+int Optiong; /* Let it rip no wait for sector ACK's */
+int Totsecs; /* total number of sectors this file */
+int Filcnt=0; /* count of number of files opened */
+int Lfseen=0;
+unsigned Rxbuflen = 16384; /* Receiver's max buffer length */
+unsigned Tframlen = 0; /* Override for tx frame length */
+unsigned blkopt=0; /* Override value for zmodem blklen */
+int Rxflags = 0;
+int Rxflags2 = 0;
+size_t bytcnt;
+int Wantfcs32 = TRUE; /* want to send 32 bit FCS */
+char Lzconv; /* Local ZMODEM file conversion request */
+char Lzmanag; /* Local ZMODEM file management request */
+int Lskipnocor;
+char Lztrans;
+char zconv; /* ZMODEM file conversion request */
+char zmanag; /* ZMODEM file management request */
+char ztrans; /* ZMODEM file transport request */
+int command_mode; /* Send a command, then exit. */
+int Cmdtries = 11;
+int Cmdack1; /* Rx ACKs command, then do it */
+int Exitcode;
+int enable_timesync=0;
+size_t Lastsync; /* Last offset to which we got a ZRPOS */
+int Beenhereb4; /* How many times we've been ZRPOS'd same place */
+
+int no_timeout=FALSE;
+size_t max_blklen=1024;
+size_t start_blklen=0;
+int zmodem_requested;
+time_t stop_time=0;
+char *tcp_server_address=0;
+int tcp_socket=-1;
+int tcp_flag=0;
+
+int error_count;
+#define OVERHEAD 18
+#define OVER_ERR 20
+
+#define MK_STRING(x) #x
+
+#ifdef ENABLE_SYSLOG
+# if defined(ENABLE_SYSLOG_FORCE) || defined(ENABLE_SYSLOG_DEFAULT)
+int enable_syslog=TRUE;
+# else
+int enable_syslog=FALSE;
+# endif
+#endif
+
+jmp_buf intrjmp; /* For the interrupt on RX CAN */
+
+static long min_bps;
+static long min_bps_time;
+
+static int io_mode_fd=0;
+static int zrqinits_sent=0;
+static int play_with_sigint=0;
+
+/* called by signal interrupt or terminate to clean things up */
+RETSIGTYPE
+bibi (int n)
+{
+ canit(STDOUT_FILENO);
+ fflush (stdout);
+ io_mode (io_mode_fd,0);
+ if (n == 99)
+ error (0, 0, _ ("io_mode(,2) in rbsb.c not implemented\n"));
+ else
+ error (0, 0, _ ("caught signal %d; exiting"), n);
+ if (n == SIGQUIT)
+ abort ();
+ exit (128 + n);
+}
+
+/* Called when ZMODEM gets an interrupt (^C) */
+static RETSIGTYPE
+onintr(int n)
+{
+ signal(SIGINT, SIG_IGN);
+ n++; /* use it */
+ longjmp(intrjmp, -1);
+}
+
+int Zctlesc; /* Encode control characters */
+const char *program_name = "sz";
+int Zrwindow = 1400; /* RX window size (controls garbage count) */
+
+static struct option const long_options[] =
+{
+ {"append", no_argument, NULL, '+'},
+ {"twostop", no_argument, NULL, '2'},
+ {"try-8k", no_argument, NULL, '8'},
+ {"start-8k", no_argument, NULL, '9'},
+ {"try-4k", no_argument, NULL, '4'},
+ {"start-4k", no_argument, NULL, '5'},
+ {"ascii", no_argument, NULL, 'a'},
+ {"binary", no_argument, NULL, 'b'},
+ {"bufsize", required_argument, NULL, 'B'},
+ {"cmdtries", required_argument, NULL, 'C'},
+ {"command", required_argument, NULL, 'c'},
+ {"immediate-command", required_argument, NULL, 'i'},
+ {"dot-to-slash", no_argument, NULL, 'd'},
+ {"full-path", no_argument, NULL, 'f'},
+ {"escape", no_argument, NULL, 'e'},
+ {"rename", no_argument, NULL, 'E'},
+ {"help", no_argument, NULL, 'h'},
+ {"crc-check", no_argument, NULL, 'H'},
+ {"1024", no_argument, NULL, 'k'},
+ {"1k", no_argument, NULL, 'k'},
+ {"packetlen", required_argument, NULL, 'L'},
+ {"framelen", required_argument, NULL, 'l'},
+ {"min-bps", required_argument, NULL, 'm'},
+ {"min-bps-time", required_argument, NULL, 'M'},
+ {"newer", no_argument, NULL, 'n'},
+ {"newer-or-longer", no_argument, NULL, 'N'},
+ {"16-bit-crc", no_argument, NULL, 'o'},
+ {"disable-timeouts", no_argument, NULL, 'O'},
+ {"disable-timeout", no_argument, NULL, 'O'}, /* i can't get it right */
+ {"protect", no_argument, NULL, 'p'},
+ {"resume", no_argument, NULL, 'r'},
+ {"restricted", no_argument, NULL, 'R'},
+ {"quiet", no_argument, NULL, 'q'},
+ {"stop-at", required_argument, NULL, 's'},
+ {"syslog", optional_argument, NULL , 2},
+ {"timesync", no_argument, NULL, 'S'},
+ {"timeout", required_argument, NULL, 't'},
+ {"turbo", no_argument, NULL, 'T'},
+ {"unlink", no_argument, NULL, 'u'},
+ {"unrestrict", no_argument, NULL, 'U'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"windowsize", required_argument, NULL, 'w'},
+ {"xmodem", no_argument, NULL, 'X'},
+ {"ymodem", no_argument, NULL, 1},
+ {"zmodem", no_argument, NULL, 'Z'},
+ {"overwrite", no_argument, NULL, 'y'},
+ {"overwrite-or-skip", no_argument, NULL, 'Y'},
+
+ {"delay-startup", required_argument, NULL, 4},
+ {"tcp-server", no_argument, NULL, 6},
+ {"tcp-client", required_argument, NULL, 7},
+ {"no-unixmode", no_argument, NULL, 8},
+ {NULL, 0, NULL, 0}
+};
+
+static void
+show_version(void)
+{
+ printf ("%s (%s) %s\n", program_name, PACKAGE, VERSION);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ char *cp;
+ int npats;
+ int dm;
+ int i;
+ int stdin_files;
+ char **patts;
+ int c;
+ const char *Cmdstr=NULL; /* Pointer to the command string */
+ unsigned int startup_delay=0;
+
+ if (((cp = getenv("ZNULLS")) != NULL) && *cp)
+ Znulls = atoi(cp);
+ if (((cp=getenv("SHELL"))!=NULL) && (strstr(cp, "rsh") || strstr(cp, "rksh")
+ || strstr(cp, "rbash") || strstr(cp,"rshell")))
+ {
+ under_rsh=TRUE;
+ Restricted=1;
+ }
+ if ((cp=getenv("ZMODEM_RESTRICTED"))!=NULL)
+ Restricted=1;
+ from_cu();
+ chkinvok(argv[0]);
+
+#ifdef ENABLE_SYSLOG
+ openlog(program_name,LOG_PID,ENABLE_SYSLOG);
+#endif
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ parse_long_options (argc, argv, show_version, usage1);
+
+ Rxtimeout = 600;
+
+ while ((c = getopt_long (argc, argv,
+ "2+48abB:C:c:dfeEghHi:kL:l:m:M:NnOopRrqsSt:TUuvw:XYy",
+ long_options, (int *) 0))!=EOF)
+ {
+ unsigned long int tmp;
+ char *tmpptr;
+ enum strtol_error s_err;
+
+ switch (c)
+ {
+ case 0:
+ break;
+ case '+': Lzmanag = ZF1_ZMAPND; break;
+ case '2': Twostop = TRUE; break;
+ case '8':
+ if (max_blklen==8192)
+ start_blklen=8192;
+ else
+ max_blklen=8192;
+ break;
+ case '9': /* this is a longopt .. */
+ start_blklen=8192;
+ max_blklen=8192;
+ break;
+ case '4':
+ if (max_blklen==4096)
+ start_blklen=4096;
+ else
+ max_blklen=4096;
+ break;
+ case '5': /* this is a longopt .. */
+ start_blklen=4096;
+ max_blklen=4096;
+ break;
+ case 'a': Lzconv = ZCNL; Ascii = TRUE; break;
+ case 'b': Lzconv = ZCBIN; break;
+ case 'B':
+ if (0==strcmp(optarg,"auto"))
+ buffersize= (size_t) -1;
+ else
+ buffersize=strtol(optarg,NULL,10);
+#ifdef HAVE_MMAP
+ use_mmap=0;
+#endif
+ break;
+ case 'C':
+ s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL);
+ Cmdtries = tmp;
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("command tries"), s_err);
+ break;
+ case 'i':
+ Cmdack1 = ZCACK1;
+ /* **** FALL THROUGH TO **** */
+ case 'c':
+ command_mode = TRUE;
+ Cmdstr = optarg;
+ break;
+ case 'd':
+ ++Dottoslash;
+ /* **** FALL THROUGH TO **** */
+ case 'f': Fullname=TRUE; break;
+ case 'e': Zctlesc = 1; break;
+ case 'E': Lzmanag = ZF1_ZMCHNG; break;
+ case 'h': usage(0,NULL); break;
+ case 'H': Lzmanag = ZF1_ZMCRC; break;
+ case 'k': start_blklen=1024; break;
+ case 'L':
+ s_err = xstrtoul (optarg, NULL, 0, &tmp, "ck");
+ blkopt = tmp;
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("packetlength"), s_err);
+ if (blkopt<24 || blkopt>MAX_BLOCK)
+ {
+ char meld[256];
+ sprintf(meld,
+ _("packetlength out of range 24..%ld"),
+ (long) MAX_BLOCK);
+ usage(2,meld);
+ }
+ break;
+ case 'l':
+ s_err = xstrtoul (optarg, NULL, 0, &tmp, "ck");
+ Tframlen = tmp;
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("framelength"), s_err);
+ if (Tframlen<32 || Tframlen>MAX_BLOCK)
+ {
+ char meld[256];
+ sprintf(meld,
+ _("framelength out of range 32..%ld"),
+ (long) MAX_BLOCK);
+ usage(2,meld);
+ }
+ break;
+ case 'm':
+ s_err = xstrtoul (optarg, &tmpptr, 0, &tmp, "km");
+ min_bps = tmp;
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("min_bps"), s_err);
+ if (min_bps<0)
+ usage(2,_("min_bps must be >= 0"));
+ break;
+ case 'M':
+ s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL);
+ min_bps_time = tmp;
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("min_bps_time"), s_err);
+ if (min_bps_time<=1)
+ usage(2,_("min_bps_time must be > 1"));
+ break;
+ case 'N': Lzmanag = ZF1_ZMNEWL; break;
+ case 'n': Lzmanag = ZF1_ZMNEW; break;
+ case 'o': Wantfcs32 = FALSE; break;
+ case 'O': no_timeout = TRUE; break;
+ case 'p': Lzmanag = ZF1_ZMPROT; break;
+ case 'r':
+ if (Lzconv == ZCRESUM)
+ Lzmanag = ZF1_ZMCRC;
+ else
+ Lzconv = ZCRESUM;
+ break;
+ case 'R': Restricted = TRUE; break;
+ case 'q': Quiet=TRUE; Verbose=0; break;
+ case 's':
+ if (isdigit((unsigned char) (*optarg))) {
+ struct tm *tm;
+ time_t t;
+ int hh,mm;
+ char *nex;
+
+ hh = strtoul (optarg, &nex, 10);
+ if (hh>23)
+ usage(2,_("hour to large (0..23)"));
+ if (*nex!=':')
+ usage(2, _("unparsable stop time\n"));
+ nex++;
+ mm = strtoul (optarg, &nex, 10);
+ if (mm>59)
+ usage(2,_("minute to large (0..59)"));
+
+ t=time(NULL);
+ tm=localtime(&t);
+ tm->tm_hour=hh;
+ tm->tm_min=hh;
+ stop_time=mktime(tm);
+ if (stop_time<t)
+ stop_time+=86400L; /* one day more */
+ if (stop_time - t <10)
+ usage(2,_("stop time to small"));
+ } else {
+ s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL);
+ stop_time = tmp + time(0);
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("stop-at"), s_err);
+ if (tmp<10)
+ usage(2,_("stop time to small"));
+ }
+ break;
+ case 'S': enable_timesync=1; break;
+ case 'T': turbo_escape=1; break;
+ case 't':
+ s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL);
+ Rxtimeout = tmp;
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("timeout"), s_err);
+ if (Rxtimeout<10 || Rxtimeout>1000)
+ usage(2,_("timeout out of range 10..1000"));
+ break;
+ case 'u': ++Unlinkafter; break;
+ case 'U':
+ if (!under_rsh)
+ Restricted=0;
+ else
+ error(1,0,
+ _("security violation: can't do that under restricted shell\n"));
+ break;
+ case 'v': ++Verbose; break;
+ case 'w':
+ s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL);
+ Txwindow = tmp;
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("window size"), s_err);
+ if (Txwindow < 256)
+ Txwindow = 256;
+ Txwindow = (Txwindow/64) * 64;
+ Txwspac = Txwindow/4;
+ if (blkopt > Txwspac
+ || (!blkopt && Txwspac < MAX_BLOCK))
+ blkopt = Txwspac;
+ break;
+ case 'X': protocol=ZM_XMODEM; break;
+ case 1: protocol=ZM_YMODEM; break;
+ case 'Z': protocol=ZM_ZMODEM; break;
+ case 'Y':
+ Lskipnocor = TRUE;
+ /* **** FALLL THROUGH TO **** */
+ case 'y':
+ Lzmanag = ZF1_ZMCLOB; break;
+ case 2:
+#ifdef ENABLE_SYSLOG
+# ifndef ENABLE_SYSLOG_FORCE
+ if (optarg && (!strcmp(optarg,"off") || !strcmp(optarg,"no")))
+ {
+ if (under_rsh)
+ error(0,0, _("cannot turnoff syslog"));
+ else
+ enable_syslog=FALSE;
+ }
+ else
+ enable_syslog=TRUE;
+# else
+ error(0,0, _("cannot turnoff syslog"));
+# endif
+#endif
+ break;
+ case 4:
+ s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL);
+ startup_delay = tmp;
+ if (s_err != LONGINT_OK)
+ STRTOL_FATAL_ERROR (optarg, _("startup delay"), s_err);
+ break;
+ case 6:
+ tcp_flag=2;
+ break;
+ case 7:
+ tcp_flag=3;
+ tcp_server_address=(char *)strdup(optarg);
+ if (!tcp_server_address) {
+ error(1,0,_("out of memory"));
+ }
+ break;
+ case 8: no_unixmode=1; break;
+ default:
+ usage (2,NULL);
+ break;
+ }
+ }
+
+ if (getuid()!=geteuid()) {
+ error(1,0,
+ _("this program was never intended to be used setuid\n"));
+ }
+
+ txbuf=malloc(MAX_BLOCK);
+ if (!txbuf) error(1,0,_("out of memory"));
+
+ zsendline_init();
+
+ if (start_blklen==0) {
+ if (protocol == ZM_ZMODEM) {
+ start_blklen=1024;
+ if (Tframlen) {
+ start_blklen=max_blklen=Tframlen;
+ }
+ }
+ else
+ start_blklen=128;
+ }
+
+ if (argc<2)
+ usage(2,_("need at least one file to send"));
+
+ if (startup_delay)
+ sleep(startup_delay);
+
+#ifdef HAVE_SIGINTERRUPT
+ /* we want interrupted system calls to fail and not to be restarted. */
+ siginterrupt(SIGALRM,1);
+#endif
+
+
+ npats = argc - optind;
+ patts=&argv[optind];
+
+ if (npats < 1 && !command_mode)
+ usage(2,_("need at least one file to send"));
+ if (command_mode && Restricted) {
+ printf(_("Can't send command in restricted mode\n"));
+ exit(1);
+ }
+
+ if (Fromcu && !Quiet) {
+ if (Verbose == 0)
+ Verbose = 2;
+ }
+ vfile("%s %s\n", program_name, VERSION);
+
+ if (tcp_flag==2) {
+ char buf[256];
+#ifdef MAXHOSTNAMELEN
+ char hn[MAXHOSTNAMELEN];
+#else
+ char hn[256];
+#endif
+ char *p,*q;
+ int d;
+
+ /* tell receiver to receive via tcp */
+ d=tcp_server(buf);
+ p=strchr(buf+1,'<');
+ p++;
+ q=strchr(p,'>');
+ *q=0;
+ if (gethostname(hn,sizeof(hn))==-1) {
+ error(1,0, _("hostname too long\n"));
+ }
+ fprintf(stdout,"connect with lrz --tcp-client \"%s:%s\"\n",hn,p);
+ fflush(stdout);
+ /* ok, now that this file is sent we can switch to tcp */
+
+ tcp_socket=tcp_accept(d);
+ dup2(tcp_socket,0);
+ dup2(tcp_socket,1);
+ }
+ if (tcp_flag==3) {
+ char buf[256];
+ char *p;
+ p=strchr(tcp_server_address,':');
+ if (!p)
+ error(1,0, _("illegal server address\n"));
+ *p++=0;
+ sprintf(buf,"[%s] <%s>\n",tcp_server_address,p);
+
+ fprintf(stdout,"connecting to %s\n",buf);
+ fflush(stdout);
+
+ /* we need to switch to tcp mode */
+ tcp_socket=tcp_connect(buf);
+ dup2(tcp_socket,0);
+ dup2(tcp_socket,1);
+ }
+
+
+ {
+ /* we write max_blocklen (data) + 18 (ZModem protocol overhead)
+ * + escape overhead (about 4 %), so buffer has to be
+ * somewhat larger than max_blklen
+ */
+ char *s=malloc(max_blklen+1024);
+ if (!s)
+ {
+ zperr(_("out of memory"));
+ exit(1);
+ }
+#ifdef SETVBUF_REVERSED
+ setvbuf(stdout,_IOFBF,s,max_blklen+1024);
+#else
+ setvbuf(stdout,s,_IOFBF,max_blklen+1024);
+#endif
+ }
+ blklen=start_blklen;
+
+ for (i=optind,stdin_files=0;i<argc;i++) {
+ if (0==strcmp(argv[i],"-"))
+ stdin_files++;
+ }
+
+ if (stdin_files>1) {
+ usage(1,_("can read only one file from stdin"));
+ } else if (stdin_files==1) {
+ io_mode_fd=1;
+ }
+ io_mode(io_mode_fd,1);
+ readline_setup(io_mode_fd, 128, 256);
+
+ if (signal(SIGINT, bibi) == SIG_IGN)
+ signal(SIGINT, SIG_IGN);
+ else {
+ signal(SIGINT, bibi);
+ play_with_sigint=1;
+ }
+ signal(SIGTERM, bibi);
+ signal(SIGPIPE, bibi);
+ signal(SIGHUP, bibi);
+
+ if ( protocol!=ZM_XMODEM) {
+ if (protocol==ZM_ZMODEM) {
+ printf("rz\r");
+ fflush(stdout);
+ }
+ countem(npats, patts);
+ if (protocol == ZM_ZMODEM) {
+ /* throw away any input already received. This doesn't harm
+ * as we invite the receiver to send it's data again, and
+ * might be useful if the receiver has already died or
+ * if there is dirt left if the line
+ */
+#ifdef HAVE_SELECT
+ struct timeval t;
+ unsigned char throwaway;
+ fd_set f;
+#endif
+
+ purgeline(io_mode_fd);
+
+#ifdef HAVE_SELECT
+ t.tv_sec = 0;
+ t.tv_usec = 0;
+
+ FD_ZERO(&f);
+ FD_SET(io_mode_fd,&f);
+
+ while (select(1,&f,NULL,NULL,&t)) {
+ if (0==read(io_mode_fd,&throwaway,1)) /* EOF ... */
+ break;
+ }
+#endif
+
+ purgeline(io_mode_fd);
+ stohdr(0L);
+ if (command_mode)
+ Txhdr[ZF0] = ZCOMMAND;
+ zshhdr(ZRQINIT, Txhdr);
+ zrqinits_sent++;
+#if defined(ENABLE_TIMESYNC)
+ if (Rxflags2 != ZF1_TIMESYNC)
+ /* disable timesync if there are any flags we don't know.
+ * dsz/gsz seems to use some other flags! */
+ enable_timesync=FALSE;
+ if (Rxflags2 & ZF1_TIMESYNC && enable_timesync) {
+ Totalleft+=6; /* TIMESYNC never needs more */
+ Filesleft++;
+ }
+#endif
+ }
+ }
+ fflush(stdout);
+
+ if (Cmdstr) {
+ if (getzrxinit()) {
+ Exitcode=0200; canit(STDOUT_FILENO);
+ }
+ else if (zsendcmd(Cmdstr, strlen(Cmdstr)+1)) {
+ Exitcode=0200; canit(STDOUT_FILENO);
+ }
+ } else if (wcsend(npats, patts)==ERROR) {
+ Exitcode=0200;
+ canit(STDOUT_FILENO);
+ }
+ fflush(stdout);
+ io_mode(io_mode_fd,0);
+ if (Exitcode)
+ dm=Exitcode;
+ else if (errcnt)
+ dm=1;
+ else
+ dm=0;
+ if (Verbose)
+ {
+ fputs("\r\n",stderr);
+ if (dm)
+ fputs(_("Transfer incomplete\n"),stderr);
+ else
+ fputs(_("Transfer complete\n"),stderr);
+ }
+ exit(dm);
+ /*NOTREACHED*/
+}
+
+static int
+send_pseudo(const char *name, const char *data)
+{
+ char *tmp;
+ const char *p;
+ int ret=0; /* ok */
+ size_t plen;
+ int fd;
+ int lfd;
+
+ p = getenv ("TMPDIR");
+ if (!p)
+ p = getenv ("TMP");
+ if (!p)
+ p = "/tmp";
+ tmp=malloc(PATH_MAX+1);
+ if (!tmp)
+ error(1,0,_("out of memory"));
+
+ plen=strlen(p);
+ memcpy(tmp,p,plen);
+ tmp[plen++]='/';
+
+ lfd=0;
+ do {
+ if (lfd++==10) {
+ free(tmp);
+ vstringf (_ ("send_pseudo %s: cannot open tmpfile %s: %s"),
+ name, tmp, strerror (errno));
+ vstring ("\r\n");
+ return 1;
+ }
+ sprintf(tmp+plen,"%s.%lu.%d",name,(unsigned long) getpid(),lfd);
+ fd=open(tmp,O_WRONLY|O_CREAT|O_EXCL,0700);
+ /* is O_EXCL guaranted to not follow symlinks?
+ * I don`t know ... so be careful
+ */
+ if (fd!=-1) {
+ struct stat st;
+ if (0!=lstat(tmp,&st)) {
+ vstringf (_ ("send_pseudo %s: cannot lstat tmpfile %s: %s"),
+ name, tmp, strerror (errno));
+ vstring ("\r\n");
+ unlink(tmp);
+ close(fd);
+ fd=-1;
+ } else {
+ if (S_ISLNK(st.st_mode)) {
+ vstringf (_ ("send_pseudo %s: avoiding symlink trap"),name);
+ vstring ("\r\n");
+ unlink(tmp);
+ close(fd);
+ fd=-1;
+ }
+ }
+ }
+ } while (fd==-1);
+ if (write(fd,data,strlen(data))!=(signed long) strlen(data)
+ || close(fd)!=0) {
+ vstringf (_ ("send_pseudo %s: cannot write to tmpfile %s: %s"),
+ name, tmp, strerror (errno));
+ vstring ("\r\n");
+ free(tmp);
+ return 1;
+ }
+
+ if (wcs (tmp,name) == ERROR) {
+ if (Verbose)
+ vstringf (_ ("send_pseudo %s: failed"),name);
+ else {
+ if (Verbose)
+ vstringf (_ ("send_pseudo %s: ok"),name);
+ Filcnt--;
+ }
+ vstring ("\r\n");
+ ret=1;
+ }
+ unlink (tmp);
+ free(tmp);
+ return ret;
+}
+
+static int
+wcsend (int argc, char *argp[])
+{
+ int n;
+
+ Crcflg = FALSE;
+ firstsec = TRUE;
+ bytcnt = (size_t) -1;
+
+ for (n = 0; n < argc; ++n) {
+ Totsecs = 0;
+ if (wcs (argp[n],NULL) == ERROR)
+ return ERROR;
+ }
+#if defined(ENABLE_TIMESYNC)
+ if (Rxflags2 & ZF1_TIMESYNC && enable_timesync) {
+ /* implement Peter Mandrellas extension */
+ char buf[60];
+ time_t t = time (NULL);
+ struct tm *tm = localtime (&t); /* sets timezone */
+ strftime (buf, sizeof (buf) - 1, "%H:%M:%S", tm);
+ if (Verbose) {
+ vstring ("\r\n");
+ vstringf (_("Answering TIMESYNC at %s"),buf);
+ }
+#if defined(HAVE_TIMEZONE_VAR)
+ sprintf(buf+strlen(buf),"%ld\r\n", timezone / 60);
+ if (Verbose)
+ vstringf (" (%s %ld)\r\n", _ ("timezone"), timezone / 60);
+#else
+ if (Verbose)
+ vstringf (" (%s)\r\n", _ ("timezone unknown"));
+#endif
+ send_pseudo("/$time$.t",buf);
+ }
+#endif
+ Totsecs = 0;
+ if (Filcnt == 0) { /* bitch if we couldn't open ANY files */
+#if 0
+ /* i *really* do not like this */
+ if (protocol != ZM_XMODEM) {
+ const char *Cmdstr; /* Pointer to the command string */
+ command_mode = TRUE;
+ Cmdstr = "echo \"lsz: Can't open any requested files\"";
+ if (getnak ()) {
+ Exitcode = 0200;
+ canit(STDOUT_FILENO);
+ }
+ if (!zmodem_requested)
+ canit(STDOUT_FILENO);
+ else if (zsendcmd (Cmdstr, 1 + strlen (Cmdstr))) {
+ Exitcode = 0200;
+ canit(STDOUT_FILENO);
+ }
+ Exitcode = 1;
+ return OK;
+ }
+#endif
+ canit(STDOUT_FILENO);
+ vstring ("\r\n");
+ vstringf (_ ("Can't open any requested files."));
+ vstring ("\r\n");
+ return ERROR;
+ }
+ if (zmodem_requested)
+ saybibi ();
+ else if (protocol != ZM_XMODEM) {
+ struct zm_fileinfo zi;
+ char *pa;
+ pa=alloca(PATH_MAX+1);
+ *pa='\0';
+ zi.fname = pa;
+ zi.modtime = 0;
+ zi.mode = 0;
+ zi.bytes_total = 0;
+ zi.bytes_sent = 0;
+ zi.bytes_received = 0;
+ zi.bytes_skipped = 0;
+ wctxpn (&zi);
+ }
+ return OK;
+}
+
+static int
+wcs(const char *oname, const char *remotename)
+{
+#if !defined(S_ISDIR)
+ int c;
+#endif
+ struct stat f;
+ char *name;
+ struct zm_fileinfo zi;
+#ifdef HAVE_MMAP
+ int dont_mmap_this=0;
+#endif
+#ifdef ENABLE_SYSLOG
+ const char *shortname;
+ shortname=strrchr(oname,'/');
+ if (shortname)
+ shortname++;
+ else
+ shortname=oname;
+#endif
+
+
+ if (Restricted) {
+ /* restrict pathnames to current tree or uucppublic */
+ if ( strstr(oname, "../")
+#ifdef PUBDIR
+ || (oname[0]== '/' && strncmp(oname, MK_STRING(PUBDIR),
+ strlen(MK_STRING(PUBDIR))))
+#endif
+ ) {
+ canit(STDOUT_FILENO);
+ vchar('\r');
+ error(1,0,
+ _("security violation: not allowed to upload from %s"),oname);
+ }
+ }
+
+ if (0==strcmp(oname,"-")) {
+ char *p=getenv("ONAME");
+ name=alloca(PATH_MAX+1);
+ if (p) {
+ strcpy(name, p);
+ } else {
+ sprintf(name, "s%lu.lsz", (unsigned long) getpid());
+ }
+ input_f=stdin;
+#ifdef HAVE_MMAP
+ dont_mmap_this=1;
+#endif
+ } else if ((input_f=fopen(oname, "r"))==NULL) {
+ int e=errno;
+ error(0,e, _("cannot open %s"),oname);
+ ++errcnt;
+ return OK; /* pass over it, there may be others */
+ } else {
+ name=alloca(PATH_MAX+1);
+ strcpy(name, oname);
+ }
+#ifdef HAVE_MMAP
+ if (!use_mmap || dont_mmap_this)
+#endif
+ {
+ static char *s=NULL;
+ static size_t last_length=0;
+ struct stat st;
+ if (fstat(fileno(input_f),&st)==-1)
+ st.st_size=1024*1024;
+ if (buffersize==(size_t) -1 && s) {
+ if ((size_t) st.st_size > last_length) {
+ free(s);
+ s=NULL;
+ last_length=0;
+ }
+ }
+ if (!s && buffersize) {
+ last_length=16384;
+ if (buffersize==(size_t) -1) {
+ if (st.st_size>0)
+ last_length=st.st_size;
+ } else
+ last_length=buffersize;
+ /* buffer whole pages */
+ last_length=(last_length+4095)&0xfffff000;
+ s=malloc(last_length);
+ if (!s) {
+ zpfatal(_("out of memory"));
+ exit(1);
+ }
+ }
+ if (s) {
+#ifdef SETVBUF_REVERSED
+ setvbuf(input_f,_IOFBF,s,last_length);
+#else
+ setvbuf(input_f,s,_IOFBF,last_length);
+#endif
+ }
+ }
+ vpos = 0;
+ /* Check for directory or block special files */
+ fstat(fileno(input_f), &f);
+#if defined(S_ISDIR)
+ if (S_ISDIR(f.st_mode) || S_ISBLK(f.st_mode)) {
+#else
+ c = f.st_mode & S_IFMT;
+ if (c == S_IFDIR || c == S_IFBLK) {
+#endif
+ error(0,0, _("is not a file: %s"),name);
+ fclose(input_f);
+ return OK;
+ }
+
+ if (remotename) {
+ /* disqualify const */
+ union {
+ const char *c;
+ char *s;
+ } cheat;
+ cheat.c=remotename;
+ zi.fname=cheat.s;
+ } else
+ zi.fname=name;
+ zi.modtime=f.st_mtime;
+ zi.mode=f.st_mode;
+#if defined(S_ISFIFO)
+ zi.bytes_total= (S_ISFIFO(f.st_mode)) ? DEFBYTL : f.st_size;
+#else
+ zi.bytes_total= c == S_IFIFO ? DEFBYTL : f.st_size;
+#endif
+ zi.bytes_sent=0;
+ zi.bytes_received=0;
+ zi.bytes_skipped=0;
+ zi.eof_seen=0;
+ timing(1,NULL);
+
+ ++Filcnt;
+ switch (wctxpn(&zi)) {
+ case ERROR:
+#ifdef ENABLE_SYSLOG
+ if (enable_syslog)
+ lsyslog(LOG_INFO, _("%s/%s: error occured"),protname(),shortname);
+#endif
+ return ERROR;
+ case ZSKIP:
+ error(0,0, _("skipped: %s"),name);
+#ifdef ENABLE_SYSLOG
+ if (enable_syslog)
+ lsyslog(LOG_INFO, _("%s/%s: skipped"),protname(),shortname);
+#endif
+ return OK;
+ }
+ if (!zmodem_requested && wctx(&zi)==ERROR)
+ {
+#ifdef ENABLE_SYSLOG
+ if (enable_syslog)
+ lsyslog(LOG_INFO, _("%s/%s: error occured"),protname(),shortname);
+#endif
+ return ERROR;
+ }
+ if (Unlinkafter)
+ unlink(oname);
+
+ if (Verbose > 1
+#ifdef ENABLE_SYSLOG
+ || enable_syslog
+#endif
+ ) {
+ long bps;
+ double d=timing(0,NULL);
+ if (d==0) /* can happen if timing() uses time() */
+ d=0.5;
+ bps=zi.bytes_sent/d;
+ vchar('\r');
+ if (Verbose > 1)
+ vstringf(_("Bytes Sent:%7ld BPS:%-8ld \n"),
+ (long) zi.bytes_sent,bps);
+#ifdef ENABLE_SYSLOG
+ if (enable_syslog)
+ lsyslog(LOG_INFO, "%s/%s: %ld Bytes, %ld BPS",shortname,
+ protname(), (long) zi.bytes_sent,bps);
+#endif
+ }
+ return 0;
+}
+
+/*
+ * generate and transmit pathname block consisting of
+ * pathname (null terminated),
+ * file length, mode time and file mode in octal
+ * as provided by the Unix fstat call.
+ * N.B.: modifies the passed name, may extend it!
+ */
+static int
+wctxpn(struct zm_fileinfo *zi)
+{
+ register char *p, *q;
+ char *name2;
+ struct stat f;
+
+ name2=alloca(PATH_MAX+1);
+
+ if (protocol==ZM_XMODEM) {
+ if (Verbose && *zi->fname && fstat(fileno(input_f), &f)!= -1) {
+ vstringf(_("Sending %s, %ld blocks: "),
+ zi->fname, (long) (f.st_size>>7));
+ }
+ vstringf(_("Give your local XMODEM receive command now."));
+ vstring("\r\n");
+ return OK;
+ }
+ if (!zmodem_requested)
+ if (getnak()) {
+ vfile("getnak failed");
+ DO_SYSLOG((LOG_INFO, "%s/%s: getnak failed",
+ shortname,protname()));
+ return ERROR;
+ }
+
+ q = (char *) 0;
+ if (Dottoslash) { /* change . to . */
+ for (p=zi->fname; *p; ++p) {
+ if (*p == '/')
+ q = p;
+ else if (*p == '.')
+ *(q=p) = '/';
+ }
+ if (q && strlen(++q) > 8) { /* If name>8 chars */
+ q += 8; /* make it .ext */
+ strcpy(name2, q); /* save excess of name */
+ *q = '.';
+ strcpy(++q, name2); /* add it back */
+ }
+ }
+
+ for (p=zi->fname, q=txbuf ; *p; )
+ if ((*q++ = *p++) == '/' && !Fullname)
+ q = txbuf;
+ *q++ = 0;
+ p=q;
+ while (q < (txbuf + MAX_BLOCK))
+ *q++ = 0;
+ /* note that we may lose some information here in case mode_t is wider than an
+ * int. But i believe sending %lo instead of %o _could_ break compatability
+ */
+ if (!Ascii && (input_f!=stdin) && *zi->fname && fstat(fileno(input_f), &f)!= -1)
+ sprintf(p, "%lu %lo %o 0 %d %ld", (long) f.st_size, f.st_mtime,
+ (unsigned int)((no_unixmode) ? 0 : f.st_mode),
+ Filesleft, Totalleft);
+ if (Verbose)
+ vstringf(_("Sending: %s\n"),txbuf);
+ Totalleft -= f.st_size;
+ if (--Filesleft <= 0)
+ Totalleft = 0;
+ if (Totalleft < 0)
+ Totalleft = 0;
+
+ /* force 1k blocks if name won't fit in 128 byte block */
+ if (txbuf[125])
+ blklen=1024;
+ else { /* A little goodie for IMP/KMD */
+ txbuf[127] = (f.st_size + 127) >>7;
+ txbuf[126] = (f.st_size + 127) >>15;
+ }
+ if (zmodem_requested)
+ return zsendfile(zi,txbuf, 1+strlen(p)+(p-txbuf));
+ if (wcputsec(txbuf, 0, 128)==ERROR) {
+ vfile("wcputsec failed");
+ DO_SYSLOG((LOG_INFO, "%s/%s: wcputsec failed",
+ shortname,protname()));
+ return ERROR;
+ }
+ return OK;
+}
+
+static int
+getnak(void)
+{
+ int firstch;
+ int tries=0;
+
+ Lastrx = 0;
+ for (;;) {
+ tries++;
+ switch (firstch = READLINE_PF(100)) {
+ case ZPAD:
+ if (getzrxinit())
+ return ERROR;
+ Ascii = 0; /* Receiver does the conversion */
+ return FALSE;
+ case TIMEOUT:
+ /* 30 seconds are enough */
+ if (tries==3) {
+ zperr(_("Timeout on pathname"));
+ return TRUE;
+ }
+ /* don't send a second ZRQINIT _directly_ after the
+ * first one. Never send more then 4 ZRQINIT, because
+ * omen rz stops if it saw 5 of them */
+ if ((zrqinits_sent>1 || tries>1) && zrqinits_sent<4) {
+ /* if we already sent a ZRQINIT we are using zmodem
+ * protocol and may send further ZRQINITs
+ */
+ stohdr(0L);
+ zshhdr(ZRQINIT, Txhdr);
+ zrqinits_sent++;
+ }
+ continue;
+ case WANTG:
+ io_mode(io_mode_fd,2); /* Set cbreak, XON/XOFF, etc. */
+ Optiong = TRUE;
+ blklen=1024;
+ case WANTCRC:
+ Crcflg = TRUE;
+ case NAK:
+ return FALSE;
+ case CAN:
+ if ((firstch = READLINE_PF(20)) == CAN && Lastrx == CAN)
+ return TRUE;
+ default:
+ break;
+ }
+ Lastrx = firstch;
+ }
+}
+
+
+static int
+wctx(struct zm_fileinfo *zi)
+{
+ register size_t thisblklen;
+ register int sectnum, attempts, firstch;
+
+ firstsec=TRUE; thisblklen = blklen;
+ vfile("wctx:file length=%ld", (long) zi->bytes_total);
+
+ while ((firstch=READLINE_PF(Rxtimeout))!=NAK && firstch != WANTCRC
+ && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN)
+ ;
+ if (firstch==CAN) {
+ zperr(_("Receiver Cancelled"));
+ return ERROR;
+ }
+ if (firstch==WANTCRC)
+ Crcflg=TRUE;
+ if (firstch==WANTG)
+ Crcflg=TRUE;
+ sectnum=0;
+ for (;;) {
+ if (zi->bytes_total <= (zi->bytes_sent + 896L))
+ thisblklen = 128;
+ if ( !filbuf(txbuf, thisblklen))
+ break;
+ if (wcputsec(txbuf, ++sectnum, thisblklen)==ERROR)
+ return ERROR;
+ zi->bytes_sent += thisblklen;
+ }
+ fclose(input_f);
+ attempts=0;
+ do {
+ purgeline(io_mode_fd);
+ sendline(EOT);
+ flushmo();
+ ++attempts;
+ } while ((firstch=(READLINE_PF(Rxtimeout)) != ACK) && attempts < RETRYMAX);
+ if (attempts == RETRYMAX) {
+ zperr(_("No ACK on EOT"));
+ return ERROR;
+ }
+ else
+ return OK;
+}
+
+static int
+wcputsec(char *buf, int sectnum, size_t cseclen)
+{
+ int checksum, wcj;
+ char *cp;
+ unsigned oldcrc;
+ int firstch;
+ int attempts;
+
+ firstch=0; /* part of logic to detect CAN CAN */
+
+ if (Verbose>1) {
+ vchar('\r');
+ if (protocol==ZM_XMODEM) {
+ vstringf(_("Xmodem sectors/kbytes sent: %3d/%2dk"), Totsecs, Totsecs/8 );
+ } else {
+ vstringf(_("Ymodem sectors/kbytes sent: %3d/%2dk"), Totsecs, Totsecs/8 );
+ }
+ }
+ for (attempts=0; attempts <= RETRYMAX; attempts++) {
+ Lastrx= firstch;
+ sendline(cseclen==1024?STX:SOH);
+ sendline(sectnum);
+ sendline(-sectnum -1);
+ oldcrc=checksum=0;
+ for (wcj=cseclen,cp=buf; --wcj>=0; ) {
+ sendline(*cp);
+ oldcrc=updcrc((0377& *cp), oldcrc);
+ checksum += *cp++;
+ }
+ if (Crcflg) {
+ oldcrc=updcrc(0,updcrc(0,oldcrc));
+ sendline((int)oldcrc>>8);
+ sendline((int)oldcrc);
+ }
+ else
+ sendline(checksum);
+
+ flushmo();
+ if (Optiong) {
+ firstsec = FALSE; return OK;
+ }
+ firstch = READLINE_PF(Rxtimeout);
+gotnak:
+ switch (firstch) {
+ case CAN:
+ if(Lastrx == CAN) {
+cancan:
+ zperr(_("Cancelled")); return ERROR;
+ }
+ break;
+ case TIMEOUT:
+ zperr(_("Timeout on sector ACK")); continue;
+ case WANTCRC:
+ if (firstsec)
+ Crcflg = TRUE;
+ case NAK:
+ zperr(_("NAK on sector")); continue;
+ case ACK:
+ firstsec=FALSE;
+ Totsecs += (cseclen>>7);
+ return OK;
+ case ERROR:
+ zperr(_("Got burst for sector ACK")); break;
+ default:
+ zperr(_("Got %02x for sector ACK"), firstch); break;
+ }
+ for (;;) {
+ Lastrx = firstch;
+ if ((firstch = READLINE_PF(Rxtimeout)) == TIMEOUT)
+ break;
+ if (firstch == NAK || firstch == WANTCRC)
+ goto gotnak;
+ if (firstch == CAN && Lastrx == CAN)
+ goto cancan;
+ }
+ }
+ zperr(_("Retry Count Exceeded"));
+ return ERROR;
+}
+
+/* fill buf with count chars padding with ^Z for CPM */
+static size_t
+filbuf(char *buf, size_t count)
+{
+ int c;
+ size_t m;
+
+ if ( !Ascii) {
+ m = read(fileno(input_f), buf, count);
+ if (m <= 0)
+ return 0;
+ while (m < count)
+ buf[m++] = 032;
+ return count;
+ }
+ m=count;
+ if (Lfseen) {
+ *buf++ = 012; --m; Lfseen = 0;
+ }
+ while ((c=getc(input_f))!=EOF) {
+ if (c == 012) {
+ *buf++ = 015;
+ if (--m == 0) {
+ Lfseen = TRUE; break;
+ }
+ }
+ *buf++ =c;
+ if (--m == 0)
+ break;
+ }
+ if (m==count)
+ return 0;
+ else
+ while (m--!=0)
+ *buf++ = CPMEOF;
+ return count;
+}
+
+/* Fill buffer with blklen chars */
+static size_t
+zfilbuf (struct zm_fileinfo *zi)
+{
+ size_t n;
+
+ n = fread (txbuf, 1, blklen, input_f);
+ if (n < blklen)
+ zi->eof_seen = 1;
+ else {
+ /* save one empty paket in case file ends ob blklen boundary */
+ int c = getc(input_f);
+
+ if (c != EOF || !feof(input_f))
+ ungetc(c, input_f);
+ else
+ zi->eof_seen = 1;
+ }
+ return n;
+}
+
+static void
+usage1 (int exitcode)
+{
+ usage (exitcode, NULL);
+}
+
+static void
+usage(int exitcode, const char *what)
+{
+ FILE *f=stdout;
+
+ if (exitcode)
+ {
+ if (what)
+ fprintf(stderr, "%s: %s\n",program_name,what);
+ fprintf (stderr, _("Try `%s --help' for more information.\n"),
+ program_name);
+ exit(exitcode);
+ }
+
+ fprintf(f, _("%s version %s\n"), program_name,
+ VERSION);
+
+ fprintf(f,_("Usage: %s [options] file ...\n"),
+ program_name);
+ fprintf(f,_(" or: %s [options] -{c|i} COMMAND\n"),program_name);
+ fputs(_("Send file(s) with ZMODEM/YMODEM/XMODEM protocol\n"),f);
+ fputs(_(
+ " (X) = option applies to XMODEM only\n"
+ " (Y) = option applies to YMODEM only\n"
+ " (Z) = option applies to ZMODEM only\n"
+ ),f);
+ /* splitted into two halves for really bad compilers */
+ fputs(_(
+" -+, --append append to existing destination file (Z)\n"
+" -2, --twostop use 2 stop bits\n"
+" -4, --try-4k go up to 4K blocksize\n"
+" --start-4k start with 4K blocksize (doesn't try 8)\n"
+" -8, --try-8k go up to 8K blocksize\n"
+" --start-8k start with 8K blocksize\n"
+" -a, --ascii ASCII transfer (change CR/LF to LF)\n"
+" -b, --binary binary transfer\n"
+" -B, --bufsize N buffer N bytes (N==auto: buffer whole file)\n"
+" -c, --command COMMAND execute remote command COMMAND (Z)\n"
+" -C, --command-tries N try N times to execute a command (Z)\n"
+" -d, --dot-to-slash change '.' to '/' in pathnames (Y/Z)\n"
+" --delay-startup N sleep N seconds before doing anything\n"
+" -e, --escape escape all control characters (Z)\n"
+" -E, --rename force receiver to rename files it already has\n"
+" -f, --full-path send full pathname (Y/Z)\n"
+" -i, --immediate-command CMD send remote CMD, return immediately (Z)\n"
+" -h, --help print this usage message\n"
+" -k, --1k send 1024 byte packets (X)\n"
+" -L, --packetlen N limit subpacket length to N bytes (Z)\n"
+" -l, --framelen N limit frame length to N bytes (l>=L) (Z)\n"
+" -m, --min-bps N stop transmission if BPS below N\n"
+" -M, --min-bps-time N for at least N seconds (default: 120)\n"
+ ),f);
+ fputs(_(
+" -n, --newer send file if source newer (Z)\n"
+" -N, --newer-or-longer send file if source newer or longer (Z)\n"
+" -o, --16-bit-crc use 16 bit CRC instead of 32 bit CRC (Z)\n"
+" -O, --disable-timeouts disable timeout code, wait forever\n"
+" -p, --protect protect existing destination file (Z)\n"
+" -r, --resume resume interrupted file transfer (Z)\n"
+" -R, --restricted restricted, more secure mode\n"
+" -q, --quiet quiet (no progress reports)\n"
+" -s, --stop-at {HH:MM|+N} stop transmission at HH:MM or in N seconds\n"
+" --tcp-server open socket, wait for connection (Z)\n"
+" --tcp-client ADDR:PORT open socket, connect to ... (Z)\n"
+" -u, --unlink unlink file after transmission\n"
+" -U, --unrestrict turn off restricted mode (if allowed to)\n"
+" -v, --verbose be verbose, provide debugging information\n"
+" -w, --windowsize N Window is N bytes (Z)\n"
+" -X, --xmodem use XMODEM protocol\n"
+" -y, --overwrite overwrite existing files\n"
+" -Y, --overwrite-or-skip overwrite existing files, else skip\n"
+" --ymodem use YMODEM protocol\n"
+" -Z, --zmodem use ZMODEM protocol\n"
+"\n"
+"short options use the same arguments as the long ones\n"
+ ),f);
+ exit(exitcode);
+}
+
+/*
+ * Get the receiver's init parameters
+ */
+static int
+getzrxinit(void)
+{
+ static int dont_send_zrqinit=1;
+ int old_timeout=Rxtimeout;
+ int n;
+ struct stat f;
+ size_t rxpos;
+ int timeouts=0;
+
+ Rxtimeout=100; /* 10 seconds */
+ /* XXX purgeline(io_mode_fd); this makes _real_ trouble. why? -- uwe */
+
+ for (n=10; --n>=0; ) {
+ /* we might need to send another zrqinit in case the first is
+ * lost. But *not* if getting here for the first time - in
+ * this case we might just get a ZRINIT for our first ZRQINIT.
+ * Never send more then 4 ZRQINIT, because
+ * omen rz stops if it saw 5 of them.
+ */
+ if (zrqinits_sent<4 && n!=10 && !dont_send_zrqinit) {
+ zrqinits_sent++;
+ stohdr(0L);
+ zshhdr(ZRQINIT, Txhdr);
+ }
+ dont_send_zrqinit=0;
+
+ switch (zgethdr(Rxhdr, 1,&rxpos)) {
+ case ZCHALLENGE: /* Echo receiver's challenge numbr */
+ stohdr(rxpos);
+ zshhdr(ZACK, Txhdr);
+ continue;
+ case ZCOMMAND: /* They didn't see our ZRQINIT */
+ /* ??? Since when does a receiver send ZCOMMAND? -- uwe */
+ continue;
+ case ZRINIT:
+ Rxflags = 0377 & Rxhdr[ZF0];
+ Rxflags2 = 0377 & Rxhdr[ZF1];
+ Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
+ {
+ int old=Zctlesc;
+ Zctlesc |= Rxflags & TESCCTL;
+ /* update table - was initialised to not escape */
+ if (Zctlesc && !old)
+ zsendline_init();
+ }
+ Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
+ if ( !(Rxflags & CANFDX))
+ Txwindow = 0;
+ vfile("Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen);
+ if ( play_with_sigint)
+ signal(SIGINT, SIG_IGN);
+ io_mode(io_mode_fd,2); /* Set cbreak, XON/XOFF, etc. */
+#ifndef READCHECK
+ /* Use MAX_BLOCK byte frames if no sample/interrupt */
+ if (Rxbuflen < 32 || Rxbuflen > MAX_BLOCK) {
+ Rxbuflen = MAX_BLOCK;
+ vfile("Rxbuflen=%d", Rxbuflen);
+ }
+#endif
+ /* Override to force shorter frame length */
+ if (Tframlen && Rxbuflen > Tframlen)
+ Rxbuflen = Tframlen;
+ if ( !Rxbuflen)
+ Rxbuflen = 1024;
+ vfile("Rxbuflen=%d", Rxbuflen);
+
+ /* If using a pipe for testing set lower buf len */
+ fstat(0, &f);
+#if defined(S_ISCHR)
+ if (! (S_ISCHR(f.st_mode))) {
+#else
+ if ((f.st_mode & S_IFMT) != S_IFCHR) {
+#endif
+ Rxbuflen = MAX_BLOCK;
+ }
+ /*
+ * If input is not a regular file, force ACK's to
+ * prevent running beyond the buffer limits
+ */
+ if ( !command_mode) {
+ fstat(fileno(input_f), &f);
+#if defined(S_ISREG)
+ if (!(S_ISREG(f.st_mode))) {
+#else
+ if ((f.st_mode & S_IFMT) != S_IFREG) {
+#endif
+ Canseek = -1;
+ /* return ERROR; */
+ }
+ }
+ /* Set initial subpacket length */
+ if (blklen < 1024) { /* Command line override? */
+ if (Baudrate > 300)
+ blklen = 256;
+ if (Baudrate > 1200)
+ blklen = 512;
+ if (Baudrate > 2400)
+ blklen = 1024;
+ }
+ if (Rxbuflen && blklen>Rxbuflen)
+ blklen = Rxbuflen;
+ if (blkopt && blklen > blkopt)
+ blklen = blkopt;
+ vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
+ vfile("Txwindow = %u Txwspac = %d", Txwindow, Txwspac);
+ Rxtimeout=old_timeout;
+ return (sendzsinit());
+ case ZCAN:
+ case TIMEOUT:
+ if (timeouts++==0)
+ continue; /* force one other ZRQINIT to be sent */
+ return ERROR;
+ case ZRQINIT:
+ if (Rxhdr[ZF0] == ZCOMMAND)
+ continue;
+ default:
+ zshhdr(ZNAK, Txhdr);
+ continue;
+ }
+ }
+ return ERROR;
+}
+
+/* Send send-init information */
+static int
+sendzsinit(void)
+{
+ int c;
+
+ if (Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL)))
+ return OK;
+ errors = 0;
+ for (;;) {
+ stohdr(0L);
+ if (Zctlesc) {
+ Txhdr[ZF0] |= TESCCTL; zshhdr(ZSINIT, Txhdr);
+ }
+ else
+ zsbhdr(ZSINIT, Txhdr);
+ ZSDATA(Myattn, 1+strlen(Myattn), ZCRCW);
+ c = zgethdr(Rxhdr, 1,NULL);
+ switch (c) {
+ case ZCAN:
+ return ERROR;
+ case ZACK:
+ return OK;
+ default:
+ if (++errors > 19)
+ return ERROR;
+ continue;
+ }
+ }
+}
+
+/* Send file name and related info */
+static int
+zsendfile(struct zm_fileinfo *zi, const char *buf, size_t blen)
+{
+ unsigned long crc;
+ size_t rxpos;
+
+ /* we are going to send a ZFILE. There cannot be much useful
+ * stuff in the line right now (*except* ZCAN?).
+ */
+#if 0
+ purgeline(io_mode_fd); /* might possibly fix stefan glasers problems */
+#endif
+
+ for (;;) {
+ int gotblock;
+ int gotchar;
+ Txhdr[ZF0] = Lzconv; /* file conversion request */
+ Txhdr[ZF1] = Lzmanag; /* file management request */
+ if (Lskipnocor)
+ Txhdr[ZF1] |= ZF1_ZMSKNOLOC;
+ Txhdr[ZF2] = Lztrans; /* file transport request */
+ Txhdr[ZF3] = 0;
+ zsbhdr(ZFILE, Txhdr);
+ ZSDATA(buf, blen, ZCRCW);
+again:
+ gotblock = zgethdr(Rxhdr, 1, &rxpos);
+ switch (gotblock) {
+ case ZRINIT:
+ while ((gotchar = READLINE_PF(50)) > 0)
+ if (gotchar == ZPAD) {
+ goto again;
+ }
+ /* **** FALL THRU TO **** */
+ default:
+ continue;
+ case ZRQINIT: /* remote site is sender! */
+ if (Verbose)
+ vstringf(_("got ZRQINIT"));
+ DO_SYSLOG((LOG_INFO, "%s/%s: got ZRQINIT - sz talks to sz",
+ shortname,protname()));
+ return ERROR;
+ case ZCAN:
+ if (Verbose)
+ vstringf(_("got ZCAN"));
+ DO_SYSLOG((LOG_INFO, "%s/%s: got ZCAN - receiver canceled",
+ shortname,protname()));
+ return ERROR;
+ case TIMEOUT:
+ DO_SYSLOG((LOG_INFO, "%s/%s: got TIMEOUT",
+ shortname,protname()));
+ return ERROR;
+ case ZABORT:
+ DO_SYSLOG((LOG_INFO, "%s/%s: got ZABORT",
+ shortname,protname()));
+ return ERROR;
+ case ZFIN:
+ DO_SYSLOG((LOG_INFO, "%s/%s: got ZFIN",
+ shortname,protname()));
+ return ERROR;
+ case ZCRC:
+ crc = 0xFFFFFFFFL;
+#ifdef HAVE_MMAP
+ if (use_mmap && !mm_addr)
+ {
+ struct stat st;
+ /* mmap on files of 0 length can give 0 as result .. under linux 2.2.9 at least */
+ if (fstat (fileno (input_f), &st) == 0 && st.st_size!=0) {
+ mm_size = st.st_size;
+ mm_addr = mmap (0, mm_size, PROT_READ,
+ MAP_SHARED, fileno (input_f), 0);
+ if ((caddr_t) mm_addr == (caddr_t) - 1)
+ mm_addr = NULL;
+ else {
+ fclose (input_f);
+ input_f = NULL;
+ }
+ }
+ }
+ if (mm_addr) {
+ size_t i;
+ size_t count;
+ char *p=mm_addr;
+ count=(rxpos < mm_size && rxpos > 0)? rxpos: mm_size;
+ for (i=0;i<count;i++,p++) {
+ crc = UPDC32(*p, crc);
+ }
+ crc = ~crc;
+ } else
+#endif
+ if (Canseek >= 0) {
+ if (rxpos==0) {
+ struct stat st;
+ if (0==fstat(fileno(input_f),&st)) {
+ rxpos=st.st_size;
+ } else
+ rxpos=-1;
+ }
+ while (rxpos-- && ((gotchar = getc(input_f)) != EOF))
+ crc = UPDC32(gotchar, crc);
+ crc = ~crc;
+ clearerr(input_f); /* Clear EOF */
+ fseek(input_f, 0L, 0);
+ }
+ stohdr(crc);
+ zsbhdr(ZCRC, Txhdr);
+ goto again;
+ case ZSKIP:
+ if (input_f) {
+ fclose(input_f);
+ input_f=NULL;
+ }
+#ifdef HAVE_MMAP
+ else if (mm_addr) {
+ munmap(mm_addr,mm_size);
+ mm_addr=NULL;
+ }
+#endif
+
+ vfile("receiver skipped");
+ DO_SYSLOG((LOG_INFO, "%s/%s: receiver skipped",
+ shortname, protname()));
+ return ZSKIP;
+ case ZRPOS:
+ /*
+ * Suppress zcrcw request otherwise triggered by
+ * lastsync==bytcnt
+ */
+#ifdef HAVE_MMAP
+ if (!mm_addr)
+#endif
+ if (rxpos && fseek(input_f, (long) rxpos, 0)) {
+ int er=errno;
+ vfile("fseek failed: %s", strerror(er));
+ DO_SYSLOG((LOG_INFO, "%s/%s: fseek failed: %s",
+ shortname, protname(), strerror(er)));
+ return ERROR;
+ }
+ if (rxpos)
+ zi->bytes_skipped=rxpos;
+ bytcnt = zi->bytes_sent = rxpos;
+ Lastsync = rxpos -1;
+ return zsendfdata(zi);
+ }
+ }
+}
+
+/* Send the data in the file */
+static int
+zsendfdata (struct zm_fileinfo *zi)
+{
+ static int c;
+ int newcnt;
+ static int junkcount; /* Counts garbage chars received by TX */
+ static size_t last_txpos = 0;
+ static long last_bps = 0;
+ static long not_printed = 0;
+ static long total_sent = 0;
+ static time_t low_bps=0;
+
+#ifdef HAVE_MMAP
+ if (use_mmap && !mm_addr)
+ {
+ struct stat st;
+ if (fstat (fileno (input_f), &st) == 0 && st.st_size!=0) {
+ mm_size = st.st_size;
+ mm_addr = mmap (0, mm_size, PROT_READ,
+ MAP_SHARED, fileno (input_f), 0);
+ if ((caddr_t) mm_addr == (caddr_t) - 1)
+ mm_addr = NULL;
+ else {
+ fclose (input_f);
+ input_f = NULL;
+ }
+ }
+ }
+#endif
+
+ if (play_with_sigint)
+ signal (SIGINT, onintr);
+
+ Lrxpos = 0;
+ junkcount = 0;
+ Beenhereb4 = 0;
+ somemore:
+ if (setjmp (intrjmp)) {
+ if (play_with_sigint)
+ signal (SIGINT, onintr);
+ waitack:
+ junkcount = 0;
+ c = getinsync (zi, 0);
+ gotack:
+ switch (c) {
+ default:
+ if (input_f) {
+ fclose (input_f);
+ input_f=NULL;
+ }
+ DO_SYSLOG((LOG_INFO, "%s/%s: got %d",
+ shortname, protname(), c));
+ return ERROR;
+ case ZCAN:
+ if (input_f) {
+ fclose (input_f);
+ input_f=NULL;
+ }
+ DO_SYSLOG((LOG_INFO, "%s/%s: got ZCAN",
+ shortname, protname()));
+ return ERROR;
+ case ZSKIP:
+ if (input_f) {
+ fclose (input_f);
+ input_f=NULL;
+ }
+ DO_SYSLOG((LOG_INFO, "%s/%s: got ZSKIP",
+ shortname, protname()));
+ return ZSKIP;
+ case ZACK:
+ case ZRPOS:
+ break;
+ case ZRINIT:
+ return OK;
+ }
+#ifdef READCHECK
+ /*
+ * If the reverse channel can be tested for data,
+ * this logic may be used to detect error packets
+ * sent by the receiver, in place of setjmp/longjmp
+ * rdchk(fdes) returns non 0 if a character is available
+ */
+ while (rdchk (io_mode_fd)) {
+#ifdef READCHECK_READS
+ switch (checked)
+#else
+ switch (READLINE_PF (1))
+#endif
+ {
+ case CAN:
+ case ZPAD:
+ c = getinsync (zi, 1);
+ goto gotack;
+ case XOFF: /* Wait a while for an XON */
+ case XOFF | 0200:
+ READLINE_PF (100);
+ }
+ }
+#endif
+ }
+
+ newcnt = Rxbuflen;
+ Txwcnt = 0;
+ stohdr (zi->bytes_sent);
+ zsbhdr (ZDATA, Txhdr);
+
+ do {
+ size_t n;
+ int e;
+ unsigned old = blklen;
+ blklen = calc_blklen (total_sent);
+ total_sent += blklen + OVERHEAD;
+ if (Verbose > 2 && blklen != old)
+ vstringf (_("blklen now %d\n"), blklen);
+#ifdef HAVE_MMAP
+ if (mm_addr) {
+ if (zi->bytes_sent + blklen < mm_size)
+ n = blklen;
+ else {
+ n = mm_size - zi->bytes_sent;
+ zi->eof_seen = 1;
+ }
+ } else
+#endif
+ n = zfilbuf (zi);
+ if (zi->eof_seen) {
+ e = ZCRCE;
+ if (Verbose>3)
+ vstring("e=ZCRCE/eof seen");
+ } else if (junkcount > 3) {
+ e = ZCRCW;
+ if (Verbose>3)
+ vstring("e=ZCRCW/junkcount > 3");
+ } else if (bytcnt == Lastsync) {
+ e = ZCRCW;
+ if (Verbose>3)
+ vstringf("e=ZCRCW/bytcnt == Lastsync == %ld",
+ (unsigned long) Lastsync);
+#if 0
+ /* what is this good for? Rxbuflen/newcnt normally are short - so after
+ * a few KB ZCRCW will be used? (newcnt is never incremented)
+ */
+ } else if (Rxbuflen && (newcnt -= n) <= 0) {
+ e = ZCRCW;
+ if (Verbose>3)
+ vstringf("e=ZCRCW/Rxbuflen(newcnt=%ld,n=%ld)",
+ (unsigned long) newcnt,(unsigned long) n);
+#endif
+ } else if (Txwindow && (Txwcnt += n) >= Txwspac) {
+ Txwcnt = 0;
+ e = ZCRCQ;
+ if (Verbose>3)
+ vstring("e=ZCRCQ/Window");
+ } else {
+ e = ZCRCG;
+ if (Verbose>3)
+ vstring("e=ZCRCG");
+ }
+ if ((Verbose > 1 || min_bps || stop_time)
+ && (not_printed > (min_bps ? 3 : 7)
+ || zi->bytes_sent > last_bps / 2 + last_txpos)) {
+ int minleft = 0;
+ int secleft = 0;
+ time_t now;
+ last_bps = (zi->bytes_sent / timing (0,&now));
+ if (last_bps > 0) {
+ minleft = (zi->bytes_total - zi->bytes_sent) / last_bps / 60;
+ secleft = ((zi->bytes_total - zi->bytes_sent) / last_bps) % 60;
+ }
+ if (min_bps) {
+ if (low_bps) {
+ if (last_bps<min_bps) {
+ if (now-low_bps>=min_bps_time) {
+ /* too bad */
+ if (Verbose) {
+ vstringf(_("zsendfdata: bps rate %ld below min %ld"),
+ last_bps, min_bps);
+ vstring("\r\n");
+ }
+ DO_SYSLOG((LOG_INFO, "%s/%s: bps rate low: %ld <%ld",
+ shortname, protname(), last_bps, min_bps));
+ return ERROR;
+ }
+ } else
+ low_bps=0;
+ } else if (last_bps < min_bps) {
+ low_bps=now;
+ }
+ }
+ if (stop_time && now>=stop_time) {
+ /* too bad */
+ if (Verbose) {
+ vstring(_("zsendfdata: reached stop time"));
+ vstring("\r\n");
+ }
+ DO_SYSLOG((LOG_INFO, "%s/%s: reached stop time",
+ shortname, protname()));
+ return ERROR;
+ }
+
+ if (Verbose > 1) {
+ vchar ('\r');
+ vstringf (_("Bytes Sent:%7ld/%7ld BPS:%-8ld ETA %02d:%02d "),
+ (long) zi->bytes_sent, (long) zi->bytes_total,
+ last_bps, minleft, secleft);
+ }
+ last_txpos = zi->bytes_sent;
+ } else if (Verbose)
+ not_printed++;
+ ZSDATA (DATAADR, n, e);
+ bytcnt = zi->bytes_sent += n;
+ if (e == ZCRCW)
+ goto waitack;
+#ifdef READCHECK
+ /*
+ * If the reverse channel can be tested for data,
+ * this logic may be used to detect error packets
+ * sent by the receiver, in place of setjmp/longjmp
+ * rdchk(fdes) returns non 0 if a character is available
+ */
+ fflush (stdout);
+ while (rdchk (io_mode_fd)) {
+#ifdef READCHECK_READS
+ switch (checked)
+#else
+ switch (READLINE_PF (1))
+#endif
+ {
+ case CAN:
+ case ZPAD:
+ c = getinsync (zi, 1);
+ if (c == ZACK)
+ break;
+ /* zcrce - dinna wanna starta ping-pong game */
+ ZSDATA (txbuf, 0, ZCRCE);
+ goto gotack;
+ case XOFF: /* Wait a while for an XON */
+ case XOFF | 0200:
+ READLINE_PF (100);
+ default:
+ ++junkcount;
+ }
+ }
+#endif /* READCHECK */
+ if (Txwindow) {
+ size_t tcount = 0;
+ while ((tcount = zi->bytes_sent - Lrxpos) >= Txwindow) {
+ vfile ("%ld (%ld,%ld) window >= %u", tcount,
+ (long) zi->bytes_sent, (long) Lrxpos,
+ Txwindow);
+ if (e != ZCRCQ)
+ ZSDATA (txbuf, 0, e = ZCRCQ);
+ c = getinsync (zi, 1);
+ if (c != ZACK) {
+ ZSDATA (txbuf, 0, ZCRCE);
+ goto gotack;
+ }
+ }
+ vfile ("window = %ld", tcount);
+ }
+ } while (!zi->eof_seen);
+
+
+ if (play_with_sigint)
+ signal (SIGINT, SIG_IGN);
+
+ for (;;) {
+ stohdr (zi->bytes_sent);
+ zsbhdr (ZEOF, Txhdr);
+ switch (getinsync (zi, 0)) {
+ case ZACK:
+ continue;
+ case ZRPOS:
+ goto somemore;
+ case ZRINIT:
+ return OK;
+ case ZSKIP:
+ if (input_f) {
+ fclose (input_f);
+ input_f=NULL;
+ }
+ DO_SYSLOG((LOG_INFO, "%s/%s: got ZSKIP",
+ shortname, protname()));
+ return c;
+ default:
+ if (input_f) {
+ fclose (input_f);
+ input_f=NULL;
+ }
+ DO_SYSLOG((LOG_INFO, "%s/%s: got %d",
+ shortname, protname(), c));
+ return ERROR;
+ }
+ }
+}
+
+static int
+calc_blklen(long total_sent)
+{
+ static long total_bytes=0;
+ static int calcs_done=0;
+ static long last_error_count=0;
+ static int last_blklen=0;
+ static long last_bytes_per_error=0;
+ unsigned long best_bytes=0;
+ long best_size=0;
+ long this_bytes_per_error;
+ long d;
+ unsigned int i;
+ if (total_bytes==0)
+ {
+ /* called from countem */
+ total_bytes=total_sent;
+ return 0;
+ }
+
+ /* it's not good to calc blklen too early */
+ if (calcs_done++ < 5) {
+ if (error_count && start_blklen >1024)
+ return last_blklen=1024;
+ else
+ last_blklen/=2;
+ return last_blklen=start_blklen;
+ }
+
+ if (!error_count) {
+ /* that's fine */
+ if (start_blklen==max_blklen)
+ return start_blklen;
+ this_bytes_per_error=LONG_MAX;
+ goto calcit;
+ }
+
+ if (error_count!=last_error_count) {
+ /* the last block was bad. shorten blocks until one block is
+ * ok. this is because very often many errors come in an
+ * short period */
+ if (error_count & 2)
+ {
+ last_blklen/=2;
+ if (last_blklen < 32)
+ last_blklen = 32;
+ else if (last_blklen > 512)
+ last_blklen=512;
+ if (Verbose > 3)
+ vstringf(_("calc_blklen: reduced to %d due to error\n"),
+ last_blklen);
+ }
+ last_error_count=error_count;
+ last_bytes_per_error=0; /* force recalc */
+ return last_blklen;
+ }
+
+ this_bytes_per_error=total_sent / error_count;
+ /* we do not get told about every error, because
+ * there may be more than one error per failed block.
+ * but one the other hand some errors are reported more
+ * than once: If a modem buffers more than one block we
+ * get at least two ZRPOS for the same position in case
+ * *one* block has to be resent.
+ * so don't do this:
+ * this_bytes_per_error/=2;
+ */
+ /* there has to be a margin */
+ if (this_bytes_per_error<100)
+ this_bytes_per_error=100;
+
+ /* be nice to the poor machine and do the complicated things not
+ * too often
+ */
+ if (last_bytes_per_error>this_bytes_per_error)
+ d=last_bytes_per_error-this_bytes_per_error;
+ else
+ d=this_bytes_per_error-last_bytes_per_error;
+ if (d<4)
+ {
+ if (Verbose > 3)
+ {
+ vstringf(_("calc_blklen: returned old value %d due to low bpe diff\n"),
+ last_blklen);
+ vstringf(_("calc_blklen: old %ld, new %ld, d %ld\n"),
+ last_bytes_per_error,this_bytes_per_error,d );
+ }
+ return last_blklen;
+ }
+ last_bytes_per_error=this_bytes_per_error;
+
+calcit:
+ if (Verbose > 3)
+ vstringf(_("calc_blklen: calc total_bytes=%ld, bpe=%ld, ec=%ld\n"),
+ total_bytes,this_bytes_per_error,(long) error_count);
+ for (i=32;i<=max_blklen;i*=2) {
+ long ok; /* some many ok blocks do we need */
+ long failed; /* and that's the number of blocks not transmitted ok */
+ unsigned long transmitted;
+ ok=total_bytes / i + 1;
+ failed=((long) i + OVERHEAD) * ok / this_bytes_per_error;
+ transmitted=total_bytes + ok * OVERHEAD
+ + failed * ((long) i+OVERHEAD+OVER_ERR);
+ if (Verbose > 4)
+ vstringf(_("calc_blklen: blklen %d, ok %ld, failed %ld -> %lu\n"),
+ i,ok,failed,transmitted);
+ if (transmitted < best_bytes || !best_bytes)
+ {
+ best_bytes=transmitted;
+ best_size=i;
+ }
+ }
+ if (best_size > 2*last_blklen)
+ best_size=2*last_blklen;
+ last_blklen=best_size;
+ if (Verbose > 3)
+ vstringf(_("calc_blklen: returned %d as best\n"),
+ last_blklen);
+ return last_blklen;
+}
+
+/*
+ * Respond to receiver's complaint, get back in sync with receiver
+ */
+static int
+getinsync(struct zm_fileinfo *zi, int flag)
+{
+ size_t rxpos;
+
+ for (;;) {
+ int gotblock;
+ gotblock = zgethdr(Rxhdr, 0, &rxpos);
+ switch (gotblock) {
+ case ZCAN:
+ case ZABORT:
+ case ZFIN:
+ case TIMEOUT:
+ return ERROR;
+ case ZRPOS:
+ /* ************************************* */
+ /* If sending to a buffered modem, you */
+ /* might send a break at this point to */
+ /* dump the modem's buffer. */
+ if (input_f)
+ clearerr(input_f); /* In case file EOF seen */
+#ifdef HAVE_MMAP
+ if (!mm_addr)
+#endif
+ if (fseek(input_f, (long) rxpos, 0))
+ return ERROR;
+ zi->eof_seen = 0;
+ bytcnt = Lrxpos = zi->bytes_sent = rxpos;
+ if (Lastsync == rxpos) {
+ error_count++;
+ }
+ Lastsync = rxpos;
+ return ZRPOS;
+ case ZACK:
+ Lrxpos = rxpos;
+ if (flag || zi->bytes_sent == rxpos)
+ return ZACK;
+ continue;
+ case ZRINIT:
+ case ZSKIP:
+ if (input_f) {
+ fclose (input_f);
+ input_f=NULL;
+ }
+#ifdef HAVE_MMAP
+ else if (mm_addr) {
+ munmap(mm_addr,mm_size);
+ mm_addr=NULL;
+ }
+#endif
+ return ZSKIP;
+ case ERROR:
+ default:
+ error_count++;
+ zsbhdr(ZNAK, Txhdr);
+ continue;
+ }
+ }
+}
+
+
+/* Say "bibi" to the receiver, try to do it cleanly */
+static void
+saybibi(void)
+{
+ for (;;) {
+ stohdr(0L); /* CAF Was zsbhdr - minor change */
+ zshhdr(ZFIN, Txhdr); /* to make debugging easier */
+ switch (zgethdr(Rxhdr, 0,NULL)) {
+ case ZFIN:
+ sendline('O');
+ sendline('O');
+ flushmo();
+ case ZCAN:
+ case TIMEOUT:
+ return;
+ }
+ }
+}
+
+/* Send command and related info */
+static int
+zsendcmd(const char *buf, size_t blen)
+{
+ int c;
+ pid_t cmdnum;
+ size_t rxpos;
+
+ cmdnum = getpid();
+ errors = 0;
+ for (;;) {
+ stohdr((size_t) cmdnum);
+ Txhdr[ZF0] = Cmdack1;
+ zsbhdr(ZCOMMAND, Txhdr);
+ ZSDATA(buf, blen, ZCRCW);
+listen:
+ Rxtimeout = 100; /* Ten second wait for resp. */
+ c = zgethdr(Rxhdr, 1, &rxpos);
+
+ switch (c) {
+ case ZRINIT:
+ goto listen; /* CAF 8-21-87 */
+ case ERROR:
+ case TIMEOUT:
+ if (++errors > Cmdtries)
+ return ERROR;
+ continue;
+ case ZCAN:
+ case ZABORT:
+ case ZFIN:
+ case ZSKIP:
+ case ZRPOS:
+ return ERROR;
+ default:
+ if (++errors > 20)
+ return ERROR;
+ continue;
+ case ZCOMPL:
+ Exitcode = rxpos;
+ saybibi();
+ return OK;
+ case ZRQINIT:
+ vfile("******** RZ *******");
+ system("rz");
+ vfile("******** SZ *******");
+ goto listen;
+ }
+ }
+}
+
+/*
+ * If called as lsb use YMODEM protocol
+ */
+static void
+chkinvok (const char *s)
+{
+ const char *p;
+
+ p = s;
+ while (*p == '-')
+ s = ++p;
+ while (*p)
+ if (*p++ == '/')
+ s = p;
+ if (*s == 'v') {
+ Verbose = 1;
+ ++s;
+ }
+ program_name = s;
+ if (*s == 'l')
+ s++; /* lsz -> sz */
+ protocol = ZM_ZMODEM;
+ if (s[0] == 's' && s[1] == 'x')
+ protocol = ZM_XMODEM;
+ if (s[0] == 's' && (s[1] == 'b' || s[1] == 'y')) {
+ protocol = ZM_YMODEM;
+ }
+}
+
+static void
+countem (int argc, char **argv)
+{
+ struct stat f;
+
+ for (Totalleft = 0, Filesleft = 0; --argc >= 0; ++argv) {
+ f.st_size = -1;
+ if (Verbose > 2) {
+ vstringf ("\nCountem: %03d %s ", argc, *argv);
+ }
+ if (access (*argv, R_OK) >= 0 && stat (*argv, &f) >= 0) {
+#if defined(S_ISDIR)
+ if (!S_ISDIR(f.st_mode) && !S_ISBLK(f.st_mode)) {
+#else
+ int c;
+ c = f.st_mode & S_IFMT;
+ if (c != S_IFDIR && c != S_IFBLK) {
+#endif
+ ++Filesleft;
+ Totalleft += f.st_size;
+ }
+ } else if (strcmp (*argv, "-") == 0) {
+ ++Filesleft;
+ Totalleft += DEFBYTL;
+ }
+ if (Verbose > 2)
+ vstringf (" %ld", (long) f.st_size);
+ }
+ if (Verbose > 2)
+ vstringf (_("\ncountem: Total %d %ld\n"),
+ Filesleft, Totalleft);
+ calc_blklen (Totalleft);
+}
+
+/* End of lsz.c */
+
+
diff --git a/protname.c b/protname.c
new file mode 100644
index 0000000..c33657a
--- /dev/null
+++ b/protname.c
@@ -0,0 +1,41 @@
+/*
+ protname.c - return the name of the protocol used
+ Copyright (C) 1996, 1997 Uwe Ohse
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+*/
+#include "zglobal.h"
+
+/* this code was duplicate in lrz.c and lsz.c */
+
+const char *
+protname(void)
+{
+ const char *prot_name;
+ switch(protocol) {
+ case ZM_XMODEM:
+ prot_name="XMODEM";
+ break;
+ case ZM_YMODEM:
+ prot_name="YMODEM";
+ break;
+ default:
+ prot_name="ZMODEM";
+ break;
+ }
+ return prot_name;
+}
diff --git a/rbsb.c b/rbsb.c
new file mode 100644
index 0000000..88b977c
--- /dev/null
+++ b/rbsb.c
@@ -0,0 +1,506 @@
+/*
+ rbsb.c - terminal handling stuff for lrzsz
+ Copyright (C) until 1988 Chuck Forsberg (Omen Technology INC)
+ Copyright (C) 1994 Matt Porter, Michael D. Black
+ Copyright (C) 1996, 1997 Uwe Ohse
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ originally written by Chuck Forsberg
+*/
+
+/*
+ * Rev 05-05-1988
+ * ============== (not quite, but originated there :-). -- uwe
+ */
+#include "zglobal.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#ifndef HAVE_ERRNO_DECLARATION
+extern int errno;
+#endif
+
+#ifdef USE_SGTTY
+# ifdef LLITOUT
+long Locmode; /* Saved "local mode" for 4.x BSD "new driver" */
+long Locbit = LLITOUT; /* Bit SUPPOSED to disable output translations */
+# endif
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#else
+# ifdef MAJOR_IN_SYSMACROS
+# include <sys/sysmacros.h>
+# endif
+#endif
+
+#if defined(HOWMANY) && HOWMANY > 255
+#ifndef NFGVMIN
+Howmany must be 255 or less
+#endif
+#endif
+
+static struct {
+ unsigned baudr;
+ speed_t speedcode;
+} speeds[] = {
+ {110, B110},
+ {300, B300},
+ {600, B600},
+ {1200, B1200},
+ {2400, B2400},
+ {4800, B4800},
+ {9600, B9600},
+#ifdef B19200
+ {19200, B19200},
+#endif
+#ifdef B38400
+ {38400, B38400},
+#endif
+#ifdef B57600
+ {57600, B57600},
+#endif
+#ifdef B115200
+ {115200, B115200},
+#endif
+#ifdef B230400
+ {230400, B230400},
+#endif
+#ifdef B460800
+ {460800, B460800},
+#endif
+#ifdef EXTA
+ {19200, EXTA},
+#endif
+#ifdef EXTB
+ {38400, EXTB},
+#endif
+ {0, 0}
+};
+
+static unsigned getspeed __P((speed_t));
+
+static unsigned
+getspeed(speed_t code)
+{
+ int n;
+ for (n=0; speeds[n].baudr; ++n)
+ if (speeds[n].speedcode == code)
+ return speeds[n].baudr;
+ return 38400; /* Assume fifo if ioctl failed */
+}
+
+/*
+ * return 1 if stdout and stderr are different devices
+ * indicating this program operating with a modem on a
+ * different line
+ */
+int Fromcu; /* Were called from cu or yam */
+int
+from_cu(void)
+{
+#ifdef HAVE_ST_RDEV
+ struct stat a, b;
+#if defined(makedev)
+ dev_t help=makedev(0,0);
+#else
+ int help=0;
+#endif
+
+ /* in case fstat fails */
+ a.st_rdev=b.st_rdev=a.st_dev=b.st_dev=help;
+
+ fstat(1, &a); fstat(2, &b);
+
+#if defined(major) && defined(minor)
+ if (major(a.st_rdev) != major(b.st_rdev)
+ || minor(a.st_rdev) != minor(b.st_rdev))
+ Fromcu=1;
+ else if (major(a.st_dev) != major(b.st_dev)
+ || minor(a.st_dev) != minor(b.st_dev))
+ Fromcu=1;
+ else
+ Fromcu=0;
+#else
+ Fromcu = (a.st_rdev != b.st_rdev) || (a.st_dev != b.st_dev);
+#endif
+#else
+ Fromcu = 1; /* a bad guess .. */
+#endif
+ return Fromcu;
+}
+
+
+
+int Twostop; /* Use two stop bits */
+
+
+#ifdef READCHECK_FIONREAD
+/*
+ * Return non 0 if something to read from io descriptor f
+ */
+int
+rdchk(int fd)
+{
+ static long lf;
+
+ ioctl(fd, FIONREAD, &lf);
+ return ((int) lf);
+}
+#endif
+
+#ifdef READCHECK_GETFL
+unsigned char checked = '\0' ;
+/*
+ * Nonblocking I/O is a bit different in System V, Release 2
+ */
+int
+rdchk(int fd)
+{
+ int lf, savestat;
+
+ savestat = fcntl(fd, F_GETFL) ;
+ if (savestat == -1)
+ return 0;
+#ifdef OVERLY_PARANOID
+ if (-1==fcntl(fd, F_SETFL, savestat | O_NDELAY))
+ return 0;
+ lf = read(fd, &checked, 1) ;
+ if (-1==fcntl(fd, F_SETFL, savestat)) {
+#ifdef ENABLE_SYSLOG
+ if (enable_syslog)
+ lsyslog(LOG_CRIT,"F_SETFL failed in rdchk(): %s",
+ strerror(errno));
+#endif
+ zpfatal("rdchk: F_SETFL failed\n"); /* lose */
+ /* there is really no way to recover. And we can't tell
+ * the other side what's going on if we can't write to
+ * fd, but we try.
+ */
+ canit(fd);
+ exit(1);
+ }
+#else
+ fcntl(fd, F_SETFL, savestat | O_NDELAY);
+ lf = read(fd, &checked, 1) ;
+ fcntl(fd, F_SETFL, savestat);
+#endif
+ return(lf == -1 && errno==EWOULDBLOCK ? 0 : lf) ;
+}
+#endif
+
+
+
+
+
+#ifdef USE_TERMIOS
+struct termios oldtty, tty;
+#else
+# if defined(USE_TERMIO)
+struct termio oldtty, tty;
+# else
+struct sgttyb oldtty, tty;
+struct tchars oldtch, tch;
+# endif
+#endif
+
+
+/*
+ * mode(n)
+ * 3: save old tty stat, set raw mode with flow control
+ * 2: set XON/XOFF for sb/sz with ZMODEM or YMODEM-g
+ * 1: save old tty stat, set raw mode
+ * 0: restore original tty mode
+ */
+int
+io_mode(int fd, int n)
+{
+ static int did0 = FALSE;
+
+ vfile("mode:%d", n);
+
+ switch(n) {
+
+#ifdef USE_TERMIOS
+ case 2: /* Un-raw mode used by sz, sb when -g detected */
+ if(!did0) {
+ did0 = TRUE;
+ tcgetattr(fd,&oldtty);
+ }
+ tty = oldtty;
+
+ tty.c_iflag = BRKINT|IXON;
+
+ tty.c_oflag = 0; /* Transparent output */
+
+ tty.c_cflag &= ~PARENB; /* Disable parity */
+ tty.c_cflag |= CS8; /* Set character size = 8 */
+ if (Twostop)
+ tty.c_cflag |= CSTOPB; /* Set two stop bits */
+
+#ifdef READCHECK
+ tty.c_lflag = protocol==ZM_ZMODEM ? 0 : ISIG;
+ tty.c_cc[VINTR] = protocol==ZM_ZMODEM ? -1 : 030; /* Interrupt char */
+#else
+ tty.c_lflag = 0;
+ tty.c_cc[VINTR] = protocol==ZM_ZMODEM ? 03 : 030; /* Interrupt char */
+#endif
+#ifdef _POSIX_VDISABLE
+ if (((int) _POSIX_VDISABLE)!=(-1)) {
+ tty.c_cc[VQUIT] = _POSIX_VDISABLE; /* Quit char */
+ } else {
+ tty.c_cc[VQUIT] = -1; /* Quit char */
+ }
+#else
+ tty.c_cc[VQUIT] = -1; /* Quit char */
+#endif
+#ifdef NFGVMIN
+ tty.c_cc[VMIN] = 1;
+#else
+ tty.c_cc[VMIN] = 3; /* This many chars satisfies reads */
+#endif
+ tty.c_cc[VTIME] = 1; /* or in this many tenths of seconds */
+
+ tcsetattr(fd,TCSADRAIN,&tty);
+
+ return OK;
+ case 1:
+ case 3:
+ if(!did0) {
+ did0 = TRUE;
+ tcgetattr(fd,&oldtty);
+ }
+ tty = oldtty;
+
+ tty.c_iflag = IGNBRK;
+ if (n==3) /* with flow control */
+ tty.c_iflag |= IXOFF;
+
+ /* Setup raw mode: no echo, noncanonical (no edit chars),
+ * no signal generating chars, and no extended chars (^V,
+ * ^O, ^R, ^W).
+ */
+ tty.c_lflag &= ~(ECHO | ICANON | ISIG | IEXTEN);
+ tty.c_oflag = 0; /* Transparent output */
+
+ tty.c_cflag &= ~(PARENB); /* Same baud rate, disable parity */
+ /* Set character size = 8 */
+ tty.c_cflag &= ~(CSIZE);
+ tty.c_cflag |= CS8;
+ if (Twostop)
+ tty.c_cflag |= CSTOPB; /* Set two stop bits */
+#ifdef NFGVMIN
+ tty.c_cc[VMIN] = 1; /* This many chars satisfies reads */
+#else
+ tty.c_cc[VMIN] = HOWMANY; /* This many chars satisfies reads */
+#endif
+ tty.c_cc[VTIME] = 1; /* or in this many tenths of seconds */
+ tcsetattr(fd,TCSADRAIN,&tty);
+ Baudrate = getspeed(cfgetospeed(&tty));
+ return OK;
+ case 0:
+ if(!did0)
+ return ERROR;
+ tcdrain (fd); /* wait until everything is sent */
+ tcflush (fd,TCIOFLUSH); /* flush input queue */
+ tcsetattr (fd,TCSADRAIN,&oldtty);
+ tcflow (fd,TCOON); /* restart output */
+
+ return OK;
+#endif
+
+#ifdef USE_TERMIO
+ case 2: /* Un-raw mode used by sz, sb when -g detected */
+ if(!did0)
+ (void) ioctl(fd, TCGETA, &oldtty);
+ tty = oldtty;
+
+ tty.c_iflag = BRKINT|IXON;
+
+ tty.c_oflag = 0; /* Transparent output */
+
+ tty.c_cflag &= ~PARENB; /* Disable parity */
+ tty.c_cflag |= CS8; /* Set character size = 8 */
+ if (Twostop)
+ tty.c_cflag |= CSTOPB; /* Set two stop bits */
+
+
+#ifdef READCHECK
+ tty.c_lflag = protocol==ZM_ZMODEM ? 0 : ISIG;
+ tty.c_cc[VINTR] = protocol==ZM_ZMODEM ? -1 : 030; /* Interrupt char */
+#else
+ tty.c_lflag = 0;
+ tty.c_cc[VINTR] = protocol==ZM_ZMODEM ? 03 : 030; /* Interrupt char */
+#endif
+ tty.c_cc[VQUIT] = -1; /* Quit char */
+#ifdef NFGVMIN
+ tty.c_cc[VMIN] = 1;
+#else
+ tty.c_cc[VMIN] = 3; /* This many chars satisfies reads */
+#endif
+ tty.c_cc[VTIME] = 1; /* or in this many tenths of seconds */
+
+ (void) ioctl(fd, TCSETAW, &tty);
+ did0 = TRUE;
+ return OK;
+ case 1:
+ case 3:
+ if(!did0)
+ (void) ioctl(fd, TCGETA, &oldtty);
+ tty = oldtty;
+
+ tty.c_iflag = n==3 ? (IGNBRK|IXOFF) : IGNBRK;
+
+ /* No echo, crlf mapping, delays, no erase/kill */
+ tty.c_lflag &= ~(ECHO | ICANON | ISIG);
+
+ tty.c_oflag = 0; /* Transparent output */
+
+ tty.c_cflag &= ~PARENB; /* Same baud rate, disable parity */
+ tty.c_cflag |= CS8; /* Set character size = 8 */
+ if (Twostop)
+ tty.c_cflag |= CSTOPB; /* Set two stop bits */
+#ifdef NFGVMIN
+ tty.c_cc[VMIN] = 1; /* This many chars satisfies reads */
+#else
+ tty.c_cc[VMIN] = HOWMANY; /* This many chars satisfies reads */
+#endif
+ tty.c_cc[VTIME] = 1; /* or in this many tenths of seconds */
+ (void) ioctl(fd, TCSETAW, &tty);
+ did0 = TRUE;
+ Baudrate = getspeed(tty.c_cflag & CBAUD);
+ return OK;
+ case 0:
+ if(!did0)
+ return ERROR;
+ (void) ioctl(fd, TCSBRK, 1); /* Wait for output to drain */
+ (void) ioctl(fd, TCFLSH, 0); /* Flush input queue */
+ (void) ioctl(fd, TCSETAW, &oldtty); /* Restore modes */
+ (void) ioctl(fd, TCXONC,1); /* Restart output */
+ return OK;
+#endif
+
+
+#ifdef USE_SGTTY
+ /*
+ * NOTE: this should transmit all 8 bits and at the same time
+ * respond to XOFF/XON flow control. If no FIONREAD or other
+ * READCHECK alternative, also must respond to INTRRUPT char
+ * This doesn't work with V7. It should work with LLITOUT,
+ * but LLITOUT was broken on the machine I tried it on.
+ */
+ case 2: /* Un-raw mode used by sz, sb when -g detected */
+ if(!did0) {
+ ioctl(fd, TIOCEXCL, 0);
+ ioctl(fd, TIOCGETP, &oldtty);
+ ioctl(fd, TIOCGETC, &oldtch);
+#ifdef LLITOUT
+ ioctl(fd, TIOCLGET, &Locmode);
+#endif
+ }
+ tty = oldtty;
+ tch = oldtch;
+#ifdef READCHECK
+ tch.t_intrc = Zmodem ? -1:030; /* Interrupt char */
+#else
+ tch.t_intrc = Zmodem ? 03:030; /* Interrupt char */
+#endif
+ tty.sg_flags |= (ODDP|EVENP|CBREAK);
+ tty.sg_flags &= ~(ALLDELAY|CRMOD|ECHO|LCASE);
+ ioctl(fd, TIOCSETP, &tty);
+ ioctl(fd, TIOCSETC, &tch);
+#ifdef LLITOUT
+ ioctl(fd, TIOCLBIS, &Locbit);
+#else
+ bibi(99); /* un-raw doesn't work w/o lit out */
+#endif
+ did0 = TRUE;
+ return OK;
+ case 1:
+ case 3:
+ if(!did0) {
+ ioctl(fd, TIOCEXCL, 0);
+ ioctl(fd, TIOCGETP, &oldtty);
+ ioctl(fd, TIOCGETC, &oldtch);
+#ifdef LLITOUT
+ ioctl(fd, TIOCLGET, &Locmode);
+#endif
+ }
+ tty = oldtty;
+ tty.sg_flags |= RAW;
+ tty.sg_flags &= ~ECHO;
+ ioctl(fd, TIOCSETP, &tty);
+ did0 = TRUE;
+ Baudrate = getspeed(tty.sg_ospeed);
+ return OK;
+ case 0:
+ if(!did0)
+ return ERROR;
+ ioctl(fd, TIOCSETP, &oldtty);
+ ioctl(fd, TIOCSETC, &oldtch);
+ ioctl(fd, TIOCNXCL, 0);
+#ifdef LLITOUT
+ ioctl(fd, TIOCLSET, &Locmode);
+#endif
+#ifdef TIOCFLUSH
+ { int x=1; ioctl(fd,TIOCFLUSH,&x); }
+#endif
+#endif
+
+ return OK;
+ default:
+ return ERROR;
+ }
+}
+
+void
+sendbrk(int fd)
+{
+#ifdef USE_TERMIOS
+ tcsendbreak(fd,0);
+#endif
+#ifdef USE_TERMIO
+ ioctl(fd, TCSBRK, 0);
+#endif
+#ifdef USE_SGTTY
+#ifdef TIOCSBRK
+ sleep(1);
+ ioctl(fd, TIOCSBRK, 0);
+ sleep(1);
+ ioctl(fd, TIOCCBRK, 0);
+#endif
+#endif
+}
+
+void
+purgeline(int fd)
+{
+ readline_purge();
+#ifdef TCFLSH
+ ioctl(fd, TCFLSH, 0);
+#else
+ lseek(fd, 0L, 2);
+#endif
+}
+
+/* End of rbsb.c */
diff --git a/tcp.c b/tcp.c
new file mode 100644
index 0000000..7e1ba3f
--- /dev/null
+++ b/tcp.c
@@ -0,0 +1,169 @@
+/*
+ tcp.c - tcp handling for lrzsz
+ Copyright (C) 1997 Uwe Ohse
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ originally written by Uwe Ohse
+*/
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include "zglobal.h"
+#include <stdlib.h>
+#include "error.h"
+
+static RETSIGTYPE
+tcp_alarm_handler(int dummy)
+{
+ dummy++; /* doesn't need to do anything */
+}
+
+
+/* server/lsz:
+ * Get a TCP socket, bind it, listen, figure out the port,
+ * and build the magic string for lrz in "buf".
+ */
+int
+tcp_server (char *buf)
+{
+ int sock;
+ struct sockaddr_in s;
+ struct sockaddr_in t;
+ int on=1;
+ socklen_t len;
+
+ if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+ error(1,errno,"socket");
+ }
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
+ error(1,errno,"setsockopt (reuse address)");
+ }
+ memset (&s, 0, sizeof (s));
+ s.sin_family = AF_INET;
+ s.sin_port=0; /* let system fill it in */
+ s.sin_addr.s_addr=htonl(INADDR_ANY);
+ if (bind(sock, (struct sockaddr *)&s, sizeof (s)) < 0) {
+ error(1,errno,"bind");
+ }
+ len=sizeof(t);
+ if (getsockname (sock, (struct sockaddr *) &t, &len)) {
+ error(1,errno,"getsockname");
+ }
+ sprintf(buf,"[%s] <%d>\n",inet_ntoa(t.sin_addr),ntohs(t.sin_port));
+
+ if (listen(sock, 1) < 0) {
+ error(1,errno,"listen");
+ }
+ getsockname (sock, (struct sockaddr *) &t, &len);
+
+ return (sock);
+}
+
+/* server/lsz: accept a connection */
+int
+tcp_accept (int d)
+{
+ int so;
+ struct sockaddr_in s;
+ socklen_t namelen;
+ int num=0;
+
+ namelen = sizeof(s);
+ memset((char*)&s,0, namelen);
+
+retry:
+ signal(SIGALRM, tcp_alarm_handler);
+ alarm(30);
+ if ((so = accept(d, (struct sockaddr*)&s, &namelen)) < 0) {
+ if (errno == EINTR) {
+ if (++num<=5)
+ goto retry;
+ }
+ error(1,errno,"accept");
+ }
+ alarm(0);
+ return so;
+}
+
+/* client/lrz:
+ * "Connect" to the TCP socket decribed in "buf" and
+ * return the connected socket.
+ */
+int
+tcp_connect (char *buf)
+{
+ int sock;
+ struct sockaddr_in s_in;
+ char *p;
+ char *q;
+
+ memset(&s_in,0,sizeof(s_in));
+ s_in.sin_family = AF_INET;
+
+ /* i _really_ distrust scanf & co. Or maybe i distrust bad input */
+ if (*buf!='[') {
+ error(1,0,_("tcp_connect: illegal format1\n"));
+ }
+ p=strchr(buf+1,']');
+ if (!p) {
+ error(1,0,_("tcp_connect: illegal format2\n"));
+ }
+ *p++=0;
+ s_in.sin_addr.s_addr=inet_addr(buf+1);
+#ifndef INADDR_NONE
+#define INADDR_NONE (-1)
+#endif
+ if (s_in.sin_addr.s_addr== (unsigned long) INADDR_NONE) {
+ struct hostent *h=gethostbyname(buf+1);
+ if (!h)
+ error(1,0,_("tcp_connect: illegal format3\n"));
+ memcpy(& s_in.sin_addr.s_addr,h->h_addr,h->h_length);
+ }
+ while (isspace((unsigned char)(*p)))
+ p++;
+ if (*p!='<') {
+ error(1,0,_("tcp_connect: illegal format4\n"));
+ }
+ q=strchr(p+1,'>');
+ if (!q)
+ error(1,0,_("tcp_connect: illegal format5\n"));
+ s_in.sin_port = htons(strtol(p+1,NULL,10));
+
+ if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+ error(1,errno,"socket");
+ }
+
+ signal(SIGALRM, tcp_alarm_handler);
+ alarm(30);
+ if (connect (sock, (struct sockaddr *) &s_in, sizeof (s_in)) < 0) {
+ error(1,errno,"connect");
+ }
+ alarm(0);
+ return (sock);
+}
diff --git a/timing.c b/timing.c
new file mode 100644
index 0000000..d776fc7
--- /dev/null
+++ b/timing.c
@@ -0,0 +1,186 @@
+/*
+ timing.c - Timing routines for computing elapsed wall time
+ Copyright (C) 1994 Michael D. Black
+ Copyright (C) 1996, 1997 Uwe Ohse
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ originally written by Michael D. Black, mblack@csihq.com
+*/
+
+#include "zglobal.h"
+
+#include "timing.h"
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#if !defined(TIME_WITH_SYS_TIME) && !defined(HAVE_SYS_TIME_H)
+ /* can't use gettimeofday without struct timeval */
+# undef HAVE_GETTIMEOFDAY
+#endif
+
+/* Prefer gettimeofday to ftime to times. */
+#if defined(HAVE_GETTIMEOFDAY)
+# undef HAVE_FTIME
+# undef HAVE_TIMES
+#else
+# if defined(HAVE_FTIME)
+# undef HAVE_TIMES
+# endif
+#endif
+
+#ifdef HAVE_FTIME
+# include <sys/timeb.h>
+#endif
+
+#ifdef HAVE_TIMES
+# if HAVE_SYS_TIMES_H
+# include <sys/times.h>
+# endif
+# ifdef _SC_CLK_TCK
+# define HAVE_SC_CLK_TCK 1
+# else
+# define HAVE_SC_CLK_TCK 0
+# endif
+/* TIMES_TICK may have been set in policy.h, or we may be able to get
+ it using sysconf. If neither is the case, try to find a useful
+ definition from the system header files. */
+# if !defined(TIMES_TICK) && (!defined(HAVE_SYSCONF) || !defined(HAVE_SC_CLK_TCK))
+# ifdef CLK_TCK
+# define TIMES_TICK CLK_TCK
+# else /* ! defined (CLK_TCK) */
+# ifdef HZ
+# define TIMES_TICK HZ
+# endif /* defined (HZ) */
+# endif /* ! defined (CLK_TCK) */
+#else
+# endif /* TIMES_TICK == 0 && (! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK) */
+# ifndef TIMES_TICK
+# define TIMES_TICK 0
+# endif
+#endif /* HAVE_TIMES */
+
+#ifdef HAVE_GETTIMEOFDAY
+/* collides with Solaris 2.5 prototype? */
+/* int gettimeofday (struct timeval *tv, struct timezone *tz); */
+#endif
+
+double
+timing (int reset, time_t *nowp)
+{
+ static double elaptime, starttime, stoptime;
+ double yet;
+#define NEED_TIME
+#ifdef HAVE_GETTIMEOFDAY
+ struct timeval tv;
+ struct timezone tz;
+
+#ifdef DST_NONE
+ tz.tz_dsttime = DST_NONE;
+#else
+ tz.tz_dsttime = 0;
+#endif
+ gettimeofday (&tv, &tz);
+ yet=tv.tv_sec + tv.tv_usec/1000000.0;
+#undef NEED_TIME
+#endif
+#ifdef HAVE_FTIME
+ static int fbad=0;
+
+ if (! fbad)
+ {
+ struct timeb stime;
+ static struct timeb slast;
+
+ (void) ftime (&stime);
+
+ /* On some systems, such as SCO 3.2.2, ftime can go backwards in
+ time. If we detect this, we switch to using time. */
+ if (slast.time != 0
+ && (stime.time < slast.time
+ || (stime.time == slast.time && stime.millitm < slast.millitm)))
+ fbad = 1;
+ else
+ {
+ yet = stime.millitm / 1000.0 + stime.time;
+ slast = stime;
+ }
+ }
+ if (fbad)
+ yet=(double) time(NULL);
+#undef NEED_TIME
+#endif
+
+#ifdef HAVE_TIMES
+ struct tms s;
+ long i;
+ static int itick;
+
+ if (itick == 0)
+ {
+#if TIMES_TICK == 0
+#if HAVE_SYSCONF && HAVE_SC_CLK_TCK
+ itick = (int) sysconf (_SC_CLK_TCK);
+#else /* ! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK */
+ const char *z;
+
+ z = getenv ("HZ");
+ if (z != NULL)
+ itick = (int) strtol (z, (char **) NULL, 10);
+
+ /* If we really couldn't get anything, just use 60. */
+ if (itick == 0)
+ itick = 60;
+#endif /* ! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK */
+#else /* TIMES_TICK != 0 */
+ itick = TIMES_TICK;
+#endif /* TIMES_TICK == 0 */
+ }
+ yet = ((double) times (&s)) / itick;
+#undef NEED_TIME
+#endif
+
+#ifdef NEED_TIME
+ yet=(double) time(NULL);
+#endif
+ if (nowp)
+ *nowp=(time_t) yet;
+ if (reset) {
+ starttime = yet;
+ return starttime;
+ }
+ else {
+ stoptime = yet;
+ elaptime = stoptime - starttime;
+ return elaptime;
+ }
+}
+
+/*#define TEST*/
+#ifdef TEST
+main()
+{
+ int i;
+ printf("timing %g\n",timing(1));
+ printf("timing %g\n",timing(0));
+ for(i=0;i<20;i++){
+ sleep(1);
+ printf("timing %g\n",timing(0));
+ }
+}
+#endif
diff --git a/timing.h b/timing.h
new file mode 100644
index 0000000..41c7c9d
--- /dev/null
+++ b/timing.h
@@ -0,0 +1 @@
+double timing __P ((int reset,time_t *now));
diff --git a/xstrtol.c b/xstrtol.c
new file mode 100644
index 0000000..d7b4b56
--- /dev/null
+++ b/xstrtol.c
@@ -0,0 +1,180 @@
+/* A more useful interface to strtol.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Jim Meyering (meyering@na-net.ornl.gov) */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef strchr
+# define strchr index
+# endif
+#endif
+
+#define NDEBUG
+#include <assert.h>
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#ifndef ULONG_MAX
+# define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
+#endif
+
+#ifndef LONG_MAX
+# define LONG_MAX ((long int) (ULONG_MAX >> 1))
+#endif
+
+#include "xstrtol.h"
+
+#define BKM_SCALE(x, scale_factor, error_return) \
+ do \
+ { \
+ if ((x) > (double) __ZLONG_MAX / (scale_factor)) \
+ return (error_return); \
+ (x) *= (scale_factor); \
+ } \
+ while (0)
+
+__unsigned long int __strtol ();
+
+/* FIXME: comment. */
+
+strtol_error
+#ifdef __cplusplus
+__xstrtol (const char *s, char **ptr, int base,
+ __unsigned long int *val, const char *valid_suffixes)
+#else
+__xstrtol (s, ptr, base, val, valid_suffixes)
+ const char *s;
+ char **ptr;
+ int base;
+ __unsigned long int *val;
+ const char *valid_suffixes;
+#endif
+{
+ char *t_ptr;
+ char **p;
+ __unsigned long int tmp;
+
+ assert (0 <= base && base <= 36);
+
+ p = (ptr ? ptr : &t_ptr);
+
+ errno = 0;
+ tmp = __strtol (s, p, base);
+ if (errno != 0)
+ return LONGINT_OVERFLOW;
+ if (*p == s)
+ return LONGINT_INVALID;
+ if (!valid_suffixes)
+ {
+ if (**p == '\0')
+ {
+ *val = tmp;
+ return LONGINT_OK;
+ }
+ else
+ return LONGINT_INVALID_SUFFIX_CHAR;
+ }
+
+ if (**p != '\0' && strchr (valid_suffixes, **p))
+ {
+ switch (**p)
+ {
+ case 'b':
+ BKM_SCALE (tmp, 512, LONGINT_OVERFLOW);
+ ++(*p);
+ break;
+
+ case 'c':
+ ++(*p);
+ break;
+
+ case 'B':
+ case 'k':
+ BKM_SCALE (tmp, 1024, LONGINT_OVERFLOW);
+ ++(*p);
+ break;
+
+ case 'm':
+ BKM_SCALE (tmp, 1024 * 1024, LONGINT_OVERFLOW);
+ ++(*p);
+ break;
+
+ case 'w':
+ BKM_SCALE (tmp, 2, LONGINT_OVERFLOW);
+ ++(*p);
+ break;
+
+ default:
+ return LONGINT_INVALID_SUFFIX_CHAR;
+ break;
+ }
+ }
+
+ *val = tmp;
+ return LONGINT_OK;
+}
+
+#ifdef TESTING_XSTRTO
+
+#include <stdio.h>
+#include "error.h"
+
+char *program_name;
+
+int
+main (int argc, char** argv)
+{
+ strtol_error s_err;
+ int i;
+
+ program_name = argv[0];
+ for (i=1; i<argc; i++)
+ {
+ char *p;
+ __unsigned long int val;
+
+ s_err = __xstrtol (argv[i], &p, 0, &val, "bckmw");
+ if (s_err == LONGINT_OK)
+ {
+ printf ("%s->%lu (%s)\n", argv[i], val, p);
+ }
+ else
+ {
+ STRTOL_FATAL_ERROR (argv[i], "arg", s_err);
+ }
+ }
+ exit (0);
+}
+#endif /* TESTING_XSTRTO */
diff --git a/xstrtol.h b/xstrtol.h
new file mode 100644
index 0000000..fd0c97f
--- /dev/null
+++ b/xstrtol.h
@@ -0,0 +1,66 @@
+#ifndef _xstrtol_h_
+#define _xstrtol_h_ 1
+
+#if STRING_TO_UNSIGNED
+# define __xstrtol xstrtoul
+# define __strtol strtoul
+# define __unsigned unsigned
+# define __ZLONG_MAX ULONG_MAX
+#else
+# define __xstrtol xstrtol
+# define __strtol strtol
+# define __unsigned /* empty */
+# define __ZLONG_MAX LONG_MAX
+#endif
+
+#undef __P
+#if defined (__STDC__) && __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+
+enum strtol_error
+ {
+ LONGINT_OK, LONGINT_INVALID, LONGINT_INVALID_SUFFIX_CHAR, LONGINT_OVERFLOW
+ };
+typedef enum strtol_error strtol_error;
+
+strtol_error
+ __xstrtol __P ((const char *s, char **ptr, int base,
+ __unsigned long int *val, const char *valid_suffixes));
+
+#define _STRTOL_ERROR(exit_code, str, argument_type_string, err) \
+ do \
+ { \
+ switch ((err)) \
+ { \
+ case LONGINT_OK: \
+ abort (); \
+ \
+ case LONGINT_INVALID: \
+ error ((exit_code), 0, "invalid %s `%s'", \
+ (argument_type_string), (str)); \
+ break; \
+ \
+ case LONGINT_INVALID_SUFFIX_CHAR: \
+ error ((exit_code), 0, "invalid character following %s `%s'", \
+ (argument_type_string), (str)); \
+ break; \
+ \
+ case LONGINT_OVERFLOW: \
+ /* FIXME: make this message dependent on STRING_TO_UNSIGNED */\
+ error ((exit_code), 0, "%s `%s' larger than maximum long int",\
+ (argument_type_string), (str)); \
+ break; \
+ } \
+ } \
+ while (0)
+
+#define STRTOL_FATAL_ERROR(str, argument_type_string, err) \
+ _STRTOL_ERROR (2, str, argument_type_string, err)
+
+#define STRTOL_FAIL_WARN(str, argument_type_string, err) \
+ _STRTOL_ERROR (0, str, argument_type_string, err)
+
+#endif /* _xstrtol_h_ */
diff --git a/xstrtoul.c b/xstrtoul.c
new file mode 100644
index 0000000..8194c17
--- /dev/null
+++ b/xstrtoul.c
@@ -0,0 +1,2 @@
+#define STRING_TO_UNSIGNED 1
+#include "xstrtol.c"
diff --git a/xstrtoul.h b/xstrtoul.h
new file mode 100644
index 0000000..8251c57
--- /dev/null
+++ b/xstrtoul.h
@@ -0,0 +1,7 @@
+#ifndef _xstrtoul_h_
+#define _xstrtoul_h_ 1
+
+#define STRING_TO_UNSIGNED 1
+#include "xstrtol.h"
+
+#endif /* _xstrtoul_h_ */
diff --git a/zglobal.h b/zglobal.h
new file mode 100644
index 0000000..0f59dba
--- /dev/null
+++ b/zglobal.h
@@ -0,0 +1,463 @@
+#ifndef ZMODEM_GLOBAL_H
+#define ZMODEM_GLOBAL_H
+
+/* zglobal.h - prototypes etcetera for lrzsz
+
+ Copyright (C) until 1998 Chuck Forsberg (OMEN Technology Inc)
+ Copyright (C) 1994 Matt Porter
+ Copyright (C) 1996, 1997 Uwe Ohse
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "config.h"
+#include <sys/types.h>
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+# define HAVE_ALLOCA 1
+#else
+# if defined HAVE_ALLOCA_H || defined _LIBC
+# include <alloca.h>
+# else
+# ifdef _AIX
+#pragma alloca
+# else
+# ifndef alloca
+# ifndef __GLIBC__
+char *alloca ();
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifndef __P
+#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
+#define __P(args) args
+#else
+#define __P(args) ()
+#endif /* GCC. */
+#endif /* Not __P. */
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# define INCLUDED_SYS_TIME
+#else
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# define INCLUDED_SYS_TIME
+# else
+# include <time.h>
+# endif
+#endif
+#ifdef SYS_TIME_WITHOUT_SYS_SELECT
+# ifdef INCLUDED_SYS_TIME
+# undef HAVE_SYS_SELECT_H
+# endif
+#endif
+
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+#ifdef __BEOS__
+ /* BeOS 4.0: sys/select.h is almost completely #ifdefd out */
+#define HAVE_SOCKET_H
+#ifdef HAVE_SOCKET_H
+#include <socket.h>
+#endif
+#endif
+
+#if STDC_HEADERS
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+# include <strings.h>
+# endif
+# ifndef HAVE_STRCHR
+# define strchr index
+# define strrchr rindex
+# endif
+char *strchr (), *strrchr ();
+# ifndef HAVE_MEMCPY
+# define memcpy(d, s, n) bcopy ((s), (d), (n))
+# define memmove(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
+
+#include <sys/stat.h>
+
+/* we need to decide whether readcheck is possible */
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_RDCHK
+# define READCHECK
+#else
+# ifdef FIONREAD
+# define READCHECK_FIONREAD
+# define READCHECK
+# else
+# ifdef F_GETFL
+# define READCHECK
+# define READCHECK_READS
+# define READCHECK_GETFL
+# endif
+# endif
+#endif
+
+/* used to use #elif, but native braindead hpux 9.00 c compiler didn't
+ * understand it */
+#ifdef HAVE_TERMIOS_H
+/* get rid of warnings on SCO ODT 3.2 */
+struct termios;
+# include <termios.h>
+# define USE_TERMIOS
+#else
+# if defined(HAVE_SYS_TERMIOS_H)
+# include <sys/termios.h>
+# define USE_TERMIOS
+# else
+# if defined(HAVE_TERMIO_H)
+# include <termio.h>
+# define USE_TERMIO
+# else
+# if defined(HAVE_SYS_TERMIO_H)
+# include <sys/termio.h>
+# define USE_TERMIO
+# else
+# if defined(HAVE_SGTTY_H)
+# include <sgtty.h>
+# define USE_SGTTY
+# ifdef LLITOUT
+ extern long Locmode; /* Saved "local mode" for 4.x BSD "new driver" */
+ extern long Locbit; /* Bit SUPPOSED to disable output translations */
+# endif
+# else
+# error neither termio.h nor sgtty.h found. Cannot continue.
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef USE_SGTTY
+# ifdef TIOCSBRK
+# define CANBREAK
+# endif
+#endif
+#ifdef USE_TERMIO
+# define CANBREAK
+#endif
+
+
+
+/* Take care of NLS matters. */
+#if HAVE_LOCALE_H
+# include <locale.h>
+#endif
+#if !HAVE_SETLOCALE
+# define setlocale(Category, Locale) /* empty */
+#endif
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(Text) gettext (Text)
+#else
+# define bindtextdomain(Domain, Directory) /* empty */
+# define textdomain(Domain) /* empty */
+# define _(Text) Text
+#endif
+
+#ifndef ENABLE_SYSLOG
+# undef HAVE_SYSLOG
+#else
+# ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+# else
+# if defined(HAVE_SYS_SYSLOG_H)
+# include <sys/syslog.h>
+# else
+# undef HAVE_SYSLOG
+# endif
+# endif
+#endif
+#ifndef ENABLE_SYSLOG
+# define openlog(name,pid,facility) /* void it */
+# define setlogmask(x) /* void it */
+#else
+extern int enable_syslog;
+#endif
+
+#if defined HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+/* The following is from pathmax.h. */
+/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
+ PATH_MAX but might cause redefinition warnings when sys/param.h is
+ later included (as on MORE/BSD 4.3). */
+#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && !defined(__GNUC__))
+# include <limits.h>
+#endif
+
+#ifndef _POSIX_PATH_MAX
+# define _POSIX_PATH_MAX 255
+#endif
+
+#if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
+# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
+#endif
+
+/* Don't include sys/param.h if it already has been. */
+#if defined(HAVE_SYS_PARAM_H) && !defined(PATH_MAX) && !defined(MAXPATHLEN)
+# include <sys/param.h>
+#endif
+
+#if !defined(PATH_MAX) && defined(MAXPATHLEN)
+# define PATH_MAX MAXPATHLEN
+#endif
+
+#if !defined(LONG_MAX) && defined(HAVE_LIMITS_H)
+# include <limits.h>
+#endif
+
+#ifndef PATH_MAX
+# define PATH_MAX _POSIX_PATH_MAX
+#endif
+
+#ifdef __GNUC__
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 5)
+# define LRZSZ_ATTRIB_SECTION(x) __attribute__((section(#x)))
+#endif
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
+# define LRZSZ_ATTRIB_CONST __attribute__((__const__))
+#endif
+
+ /* gcc.info sagt, noreturn wäre ab 2.5 verfügbar. HPUX-gcc 2.5.8
+ * kann es noch nicht - what's this?
+ */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 5)
+# define LRZSZ_ATTRIB_NORET __attribute__((__noreturn__))
+#endif
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 5)
+# define LRZSZ_ATTRIB_PRINTF(formatnr,firstargnr) \
+ __attribute__((__format__ (printf,formatnr,firstargnr)))
+#endif
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 6)
+#define LRZSZ_ATTRIB_UNUSED __attribute__((__unused__))
+#endif
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
+# define LRZSZ_ATTRIB_REGPARM(n) \
+ __attribute__((__regparm__ (n)))
+#endif
+#endif /* __GNUC__ */
+#ifndef LRZSZ_ATTRIB_REGPARM
+#define LRZSZ_ATTRIB_REGPARM(n)
+#endif
+#ifndef LRZSZ_ATTRIB_UNUSED
+#define LRZSZ_ATTRIB_UNUSED
+#endif
+#ifndef LRZSZ_ATTRIB_NORET
+#define LRZSZ_ATTRIB_NORET
+#endif
+#ifndef LRZSZ_ATTRIB_CONST
+#define LRZSZ_ATTRIB_CONST
+#endif
+#ifndef LRZSZ_ATTRIB_PRINTF
+#define LRZSZ_ATTRIB_PRINTF(x,y)
+#endif
+#ifndef LRZSZ_ATTRIB_SECTION
+#define LRZSZ_ATTRIB_SECTION(n)
+#endif
+#undef LRZSZ_ATTRIB_SECTION
+#define LRZSZ_ATTRIB_SECTION(x)
+#undef LRZSZ_ATTRIB_REGPARM
+#define LRZSZ_ATTRIB_REGPARM(x)
+
+
+#define OK 0
+#define FALSE 0
+#define TRUE 1
+#define ERROR (-1)
+
+/* Ward Christensen / CP/M parameters - Don't change these! */
+#define ENQ 005
+#define CAN ('X'&037)
+#define XOFF ('s'&037)
+#define XON ('q'&037)
+#define SOH 1
+#define STX 2
+#define EOT 4
+#define ACK 6
+#define NAK 025
+#define CPMEOF 032
+#define WANTCRC 0103 /* send C not NAK to get crc not checksum */
+#define WANTG 0107 /* Send G not NAK to get nonstop batch xmsn */
+#define TIMEOUT (-2)
+#define RCDO (-3)
+#define WCEOT (-10)
+
+#define RETRYMAX 10
+
+#define UNIXFILE 0xF000 /* The S_IFMT file mask bit for stat */
+
+#define DEFBYTL 2000000000L /* default rx file size */
+
+enum zm_type_enum {
+ ZM_XMODEM,
+ ZM_YMODEM,
+ ZM_ZMODEM
+};
+
+struct zm_fileinfo {
+ char *fname;
+ time_t modtime;
+ mode_t mode;
+ size_t bytes_total;
+ size_t bytes_sent;
+ size_t bytes_received;
+ size_t bytes_skipped; /* crash recovery */
+ int eof_seen;
+};
+
+#define R_BYTESLEFT(x) ((x)->bytes_total-(x)->bytes_received)
+
+extern enum zm_type_enum protocol;
+
+extern const char *program_name; /* the name by which we were called */
+extern int Verbose;
+extern int errors;
+extern int no_timeout;
+extern int Zctlesc; /* Encode control characters */
+extern int under_rsh;
+
+RETSIGTYPE bibi __P ((int n));
+
+#define sendline(c) putchar((c) & 0377)
+#define xsendline(c) putchar(c)
+
+/* zreadline.c */
+extern char *readline_ptr; /* pointer for removing chars from linbuf */
+extern int readline_left; /* number of buffered chars left to read */
+#define READLINE_PF(timeout) \
+ (--readline_left >= 0? (*readline_ptr++ & 0377) : readline_internal(timeout))
+
+int readline_internal __P ((unsigned int timeout));
+void readline_purge __P ((void));
+void readline_setup __P ((int fd, size_t readnum,
+ size_t buffer_size)) LRZSZ_ATTRIB_SECTION(lrzsz_rare);
+
+
+/* rbsb.c */
+extern int Fromcu;
+extern int Twostop;
+#ifdef READCHECK_READS
+extern unsigned char checked;
+#endif
+extern int iofd;
+extern unsigned Baudrate;
+
+void zperr __P ((const char *fmt, ...));
+void zpfatal __P ((const char *fmt, ...));
+void vfile __P ((const char *format, ...));
+#define vchar(x) putc(x,stderr)
+#define vstring(x) fputs(x,stderr)
+
+#ifdef __GNUC__
+#if __GNUC__ > 1
+#define vstringf(format,args...) fprintf(stderr,format, ##args)
+#endif
+#endif
+#ifndef vstringf
+void vstringf __P ((const char *format, ...));
+#endif
+#define VPRINTF(level,format_args) do {if ((Verbose)>=(level)) \
+ vstringf format_args ; } while(0)
+
+/* rbsb.c */
+int from_cu __P ((void)) LRZSZ_ATTRIB_SECTION(lrzsz_rare);
+int rdchk __P ((int fd));
+int io_mode __P ((int fd, int n)) LRZSZ_ATTRIB_SECTION(lrzsz_rare);
+void sendbrk __P ((int fd));
+#define flushmo() fflush(stdout)
+void purgeline __P ((int fd));
+void canit __P ((int fd));
+
+
+/* crctab.c */
+extern unsigned short crctab[256];
+#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
+extern long cr3tab[];
+#define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF))
+
+/* zm.c */
+#include "zmodem.h"
+extern unsigned int Rxtimeout; /* Tenths of seconds to wait for something */
+extern int bytes_per_error; /* generate one error around every x bytes */
+
+/* Globals used by ZMODEM functions */
+extern int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */
+extern int Rxtype; /* Type of header received */
+extern int Zrwindow; /* RX window size (controls garbage count) */
+/* extern int Rxcount; */ /* Count of data bytes received */
+extern char Rxhdr[4]; /* Received header */
+extern char Txhdr[4]; /* Transmitted header */
+extern long Txpos; /* Transmitted file position */
+extern int Txfcs32; /* TURE means send binary frames with 32 bit FCS */
+extern int Crc32t; /* Display flag indicating 32 bit CRC being sent */
+extern int Crc32; /* Display flag indicating 32 bit CRC being received */
+extern int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */
+extern char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */
+
+extern void zsendline __P ((int c));
+extern void zsendline_init __P ((void)) LRZSZ_ATTRIB_SECTION(lrzsz_rare);
+void zsbhdr __P ((int type, char *hdr));
+void zshhdr __P ((int type, char *hdr));
+void zsdata __P ((const char *buf, size_t length, int frameend));
+void zsda32 __P ((const char *buf, size_t length, int frameend));
+int zrdata __P ((char *buf, int length, size_t *received));
+int zgethdr __P ((char *hdr, int eflag, size_t *));
+void stohdr __P ((size_t pos)) LRZSZ_ATTRIB_REGPARM(1);
+long rclhdr __P ((char *hdr)) LRZSZ_ATTRIB_REGPARM(1);
+
+int tcp_server __P ((char *buf)) LRZSZ_ATTRIB_SECTION(lrzsz_rare);
+int tcp_connect __P ((char *buf)) LRZSZ_ATTRIB_SECTION(lrzsz_rare);
+int tcp_accept __P ((int d)) LRZSZ_ATTRIB_SECTION(lrzsz_rare);
+
+
+const char * protname __P ((void)) LRZSZ_ATTRIB_SECTION(lrzsz_rare);
+void lsyslog __P ((int, const char *,...));
+
+
+
+
+#endif
diff --git a/zm.c b/zm.c
new file mode 100644
index 0000000..0d742ab
--- /dev/null
+++ b/zm.c
@@ -0,0 +1,982 @@
+/*
+ zm.c - zmodem protocol handling lowlevelstuff
+ Copyright (C) until 1998 Chuck Forsberg (OMEN Technology Inc)
+ Copyright (C) 1996, 1997 Uwe Ohse
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ originally written by Chuck Forsberg
+*/
+/* historical comment: -- uwe
+ * Z M . C
+ * ZMODEM protocol primitives
+ * 05-09-88 Chuck Forsberg Omen Technology Inc
+ *
+ * Entry point Functions:
+ * zsbhdr(type, hdr) send binary header
+ * zshhdr(type, hdr) send hex header
+ * zgethdr(hdr, eflag) receive header - binary or hex
+ * zsdata(buf, len, frameend) send data
+ * zrdata(buf, len, bytes_received) receive data
+ * stohdr(pos) store position data in Txhdr
+ * long rclhdr(hdr) recover position offset from header
+ */
+
+
+#include "zglobal.h"
+
+#include <stdio.h>
+
+unsigned int Rxtimeout = 100; /* Tenths of seconds to wait for something */
+
+/* Globals used by ZMODEM functions */
+int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */
+int Rxtype; /* Type of header received */
+char Rxhdr[4]; /* Received header */
+char Txhdr[4]; /* Transmitted header */
+long Txpos; /* Transmitted file position */
+int Txfcs32; /* TRUE means send binary frames with 32 bit FCS */
+int Crc32t; /* Display flag indicating 32 bit CRC being sent */
+int Crc32; /* Display flag indicating 32 bit CRC being received */
+int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */
+char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */
+
+static char lastsent; /* Last char we sent */
+int turbo_escape;
+int bytes_per_error=0;
+
+static const char *frametypes[] = {
+ "Carrier Lost", /* -3 */
+ "TIMEOUT", /* -2 */
+ "ERROR", /* -1 */
+#define FTOFFSET 3
+ "ZRQINIT",
+ "ZRINIT",
+ "ZSINIT",
+ "ZACK",
+ "ZFILE",
+ "ZSKIP",
+ "ZNAK",
+ "ZABORT",
+ "ZFIN",
+ "ZRPOS",
+ "ZDATA",
+ "ZEOF",
+ "ZFERR",
+ "ZCRC",
+ "ZCHALLENGE",
+ "ZCOMPL",
+ "ZCAN",
+ "ZFREECNT",
+ "ZCOMMAND",
+ "ZSTDERR",
+ "xxxxx"
+#define FRTYPES 22 /* Total number of frame types in this array */
+ /* not including psuedo negative entries */
+};
+
+#define badcrc _("Bad CRC")
+/* static char *badcrc = "Bad CRC"; */
+static inline int noxrd7 __P ((void));
+static inline int zdlread __P ((void));
+static int zdlread2 __P ((int)) LRZSZ_ATTRIB_REGPARM(1);
+static inline int zgeth1 __P ((void));
+static void zputhex __P ((int c, char *pos));
+static inline int zgethex __P ((void));
+static int zrbhdr __P ((char *hdr));
+static int zrbhdr32 __P ((char *hdr));
+static int zrhhdr __P ((char *hdr));
+static char zsendline_tab[256];
+static int zrdat32 __P ((char *buf, int length, size_t *));
+static void zsbh32 __P ((char *hdr, int type));
+static inline void zsendline_s __P((const char *s, size_t count));
+
+extern int zmodem_requested;
+
+#define sendline(c) putchar((c) & 0377)
+#define xsendline(c) putchar(c)
+
+/*
+ * Read a character from the modem line with timeout.
+ * Eat parity, XON and XOFF characters.
+ */
+static inline int
+noxrd7(void)
+{
+ register int c;
+
+ for (;;) {
+ if ((c = READLINE_PF(Rxtimeout)) < 0)
+ return c;
+ switch (c &= 0177) {
+ case XON:
+ case XOFF:
+ continue;
+ default:
+ if (Zctlesc && !(c & 0140))
+ continue;
+ case '\r':
+ case '\n':
+ case ZDLE:
+ return c;
+ }
+ }
+}
+
+static inline int
+zgeth1(void)
+{
+ register int c, n;
+
+ if ((c = noxrd7()) < 0)
+ return c;
+ n = c - '0';
+ if (n > 9)
+ n -= ('a' - ':');
+ if (n & ~0xF)
+ return ERROR;
+ if ((c = noxrd7()) < 0)
+ return c;
+ c -= '0';
+ if (c > 9)
+ c -= ('a' - ':');
+ if (c & ~0xF)
+ return ERROR;
+ c += (n<<4);
+ return c;
+}
+
+/* Decode two lower case hex digits into an 8 bit byte value */
+static inline int
+zgethex(void)
+{
+ register int c;
+
+ c = zgeth1();
+ VPRINTF(9,("zgethex: %02X", c));
+ return c;
+}
+
+/*
+ * Read a byte, checking for ZMODEM escape encoding
+ * including CAN*5 which represents a quick abort
+ */
+static inline int
+zdlread(void)
+{
+ int c;
+ /* Quick check for non control characters */
+ if ((c = READLINE_PF(Rxtimeout)) & 0140)
+ return c;
+ return zdlread2(c);
+}
+/* no, i don't like gotos. -- uwe */
+static int
+zdlread2(int c)
+{
+ goto jump_over; /* bad style */
+
+again:
+ /* Quick check for non control characters */
+ if ((c = READLINE_PF(Rxtimeout)) & 0140)
+ return c;
+jump_over:
+ switch (c) {
+ case ZDLE:
+ break;
+ case XON:
+ case (XON|0200):
+ case XOFF:
+ case (XOFF|0200):
+ goto again;
+ default:
+ if (Zctlesc && !(c & 0140)) {
+ goto again;
+ }
+ return c;
+ }
+again2:
+ if ((c = READLINE_PF(Rxtimeout)) < 0)
+ return c;
+ if (c == CAN && (c = READLINE_PF(Rxtimeout)) < 0)
+ return c;
+ if (c == CAN && (c = READLINE_PF(Rxtimeout)) < 0)
+ return c;
+ if (c == CAN && (c = READLINE_PF(Rxtimeout)) < 0)
+ return c;
+ switch (c) {
+ case CAN:
+ return GOTCAN;
+ case ZCRCE:
+ case ZCRCG:
+ case ZCRCQ:
+ case ZCRCW:
+ return (c | GOTOR);
+ case ZRUB0:
+ return 0177;
+ case ZRUB1:
+ return 0377;
+ case XON:
+ case (XON|0200):
+ case XOFF:
+ case (XOFF|0200):
+ goto again2;
+ default:
+ if (Zctlesc && ! (c & 0140)) {
+ goto again2;
+ }
+ if ((c & 0140) == 0100)
+ return (c ^ 0100);
+ break;
+ }
+ VPRINTF(2,(_("Bad escape sequence %x"), c));
+ return ERROR;
+}
+
+
+
+/*
+ * Send character c with ZMODEM escape sequence encoding.
+ * Escape XON, XOFF. Escape CR following @ (Telenet net escape)
+ */
+inline void
+zsendline(int c)
+{
+
+ switch(zsendline_tab[(unsigned) (c&=0377)])
+ {
+ case 0:
+ xsendline(lastsent = c);
+ break;
+ case 1:
+ xsendline(ZDLE);
+ c ^= 0100;
+ xsendline(lastsent = c);
+ break;
+ case 2:
+ if ((lastsent & 0177) != '@') {
+ xsendline(lastsent = c);
+ } else {
+ xsendline(ZDLE);
+ c ^= 0100;
+ xsendline(lastsent = c);
+ }
+ break;
+ }
+}
+
+static inline void
+zsendline_s(const char *s, size_t count)
+{
+ const char *end=s+count;
+ while(s!=end) {
+ int last_esc=0;
+ const char *t=s;
+ while (t!=end) {
+ last_esc=zsendline_tab[(unsigned) ((*t) & 0377)];
+ if (last_esc)
+ break;
+ t++;
+ }
+ if (t!=s) {
+ fwrite(s,(size_t)(t-s),1,stdout);
+ lastsent=t[-1];
+ s=t;
+ }
+ if (last_esc) {
+ int c=*s;
+ switch(last_esc) {
+ case 0:
+ xsendline(lastsent = c);
+ break;
+ case 1:
+ xsendline(ZDLE);
+ c ^= 0100;
+ xsendline(lastsent = c);
+ break;
+ case 2:
+ if ((lastsent & 0177) != '@') {
+ xsendline(lastsent = c);
+ } else {
+ xsendline(ZDLE);
+ c ^= 0100;
+ xsendline(lastsent = c);
+ }
+ break;
+ }
+ s++;
+ }
+ }
+}
+
+
+/* Send ZMODEM binary header hdr of type type */
+void
+zsbhdr(int type, char *hdr)
+{
+ register int n;
+ register unsigned short crc;
+
+ VPRINTF(3,("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr)));
+ if (type == ZDATA)
+ for (n = Znulls; --n >=0; )
+ xsendline(0);
+
+ xsendline(ZPAD); xsendline(ZDLE);
+
+ Crc32t=Txfcs32;
+ if (Crc32t)
+ zsbh32(hdr, type);
+ else {
+ xsendline(ZBIN); zsendline(type); crc = updcrc(type, 0);
+
+ for (n=4; --n >= 0; ++hdr) {
+ zsendline(*hdr);
+ crc = updcrc((0377& *hdr), crc);
+ }
+ crc = updcrc(0,updcrc(0,crc));
+ zsendline(crc>>8);
+ zsendline(crc);
+ }
+ if (type != ZDATA)
+ flushmo();
+}
+
+
+/* Send ZMODEM binary header hdr of type type */
+static void
+zsbh32(char *hdr, int type)
+{
+ register int n;
+ register unsigned long crc;
+
+ xsendline(ZBIN32); zsendline(type);
+ crc = 0xFFFFFFFFL; crc = UPDC32(type, crc);
+
+ for (n=4; --n >= 0; ++hdr) {
+ crc = UPDC32((0377 & *hdr), crc);
+ zsendline(*hdr);
+ }
+ crc = ~crc;
+ for (n=4; --n >= 0;) {
+ zsendline((int)crc);
+ crc >>= 8;
+ }
+}
+
+/* Send ZMODEM HEX header hdr of type type */
+void
+zshhdr(int type, char *hdr)
+{
+ register int n;
+ register unsigned short crc;
+ char s[30];
+ size_t len;
+
+ VPRINTF(3,("zshhdr: %s %lx", frametypes[(type & 0x7f)+FTOFFSET], rclhdr(hdr)));
+ s[0]=ZPAD;
+ s[1]=ZPAD;
+ s[2]=ZDLE;
+ s[3]=ZHEX;
+ zputhex(type & 0x7f ,s+4);
+ len=6;
+ Crc32t = 0;
+
+ crc = updcrc((type & 0x7f), 0);
+ for (n=4; --n >= 0; ++hdr) {
+ zputhex(*hdr,s+len);
+ len += 2;
+ crc = updcrc((0377 & *hdr), crc);
+ }
+ crc = updcrc(0,updcrc(0,crc));
+ zputhex(crc>>8,s+len);
+ zputhex(crc,s+len+2);
+ len+=4;
+
+ /* Make it printable on remote machine */
+ s[len++]=015;
+ s[len++]=0212;
+ /*
+ * Uncork the remote in case a fake XOFF has stopped data flow
+ */
+ if (type != ZFIN && type != ZACK)
+ {
+ s[len++]=021;
+ }
+ flushmo();
+ write(1,s,len);
+}
+
+/*
+ * Send binary array buf of length length, with ending ZDLE sequence frameend
+ */
+static const char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"};
+void
+zsdata(const char *buf, size_t length, int frameend)
+{
+ register unsigned short crc;
+
+ VPRINTF(3,("zsdata: %lu %s", (unsigned long) length,
+ Zendnames[(frameend-ZCRCE)&3]));
+ crc = 0;
+ do {
+ zsendline(*buf); crc = updcrc((0377 & *buf), crc);
+ buf++;
+ } while (--length>0);
+ xsendline(ZDLE); xsendline(frameend);
+ crc = updcrc(frameend, crc);
+
+ crc = updcrc(0,updcrc(0,crc));
+ zsendline(crc>>8); zsendline(crc);
+ if (frameend == ZCRCW) {
+ xsendline(XON); flushmo();
+ }
+}
+
+void
+zsda32(const char *buf, size_t length, int frameend)
+{
+ int c;
+ unsigned long crc;
+ int i;
+ VPRINTF(3,("zsdat32: %d %s", length, Zendnames[(frameend-ZCRCE)&3]));
+
+ crc = 0xFFFFFFFFL;
+ zsendline_s(buf,length);
+ for (; length; length--) {
+ c = *buf & 0377;
+ crc = UPDC32(c, crc);
+ buf++;
+ }
+ xsendline(ZDLE); xsendline(frameend);
+ crc = UPDC32(frameend, crc);
+
+ crc = ~crc;
+ for (i=4; --i >= 0;) {
+ c=(int) crc;
+ if (c & 0140)
+ xsendline(lastsent = c);
+ else
+ zsendline(c);
+ crc >>= 8;
+ }
+ if (frameend == ZCRCW) {
+ xsendline(XON); flushmo();
+ }
+}
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ <= 4)
+# undef DEBUG_BLOCKSIZE
+#endif
+
+#ifdef DEBUG_BLOCKSIZE
+struct debug_blocksize {
+ int size;
+ long count;
+};
+struct debug_blocksize blocksizes[]={
+ {32,0},
+ {64,0},
+ {128,0},
+ {256,0},
+ {512,0},
+ {1024,0},
+ {2048,0},
+ {4096,0},
+ {8192,0},
+ {0,0}
+};
+static inline void
+count_blk(int size)
+{
+ int i;
+ for (i=0;blocksizes[i].size;i++) {
+ if (blocksizes[i].size==size) {
+ blocksizes[i].count++;
+ return;
+ }
+ }
+ blocksizes[i].count++;
+}
+
+static void printout_blocksizes(void) __attribute__((__destructor__));
+static void
+printout_blocksizes(void)
+{
+ int i;
+ for (i=0;blocksizes[i].size;i++) {
+ if (blocksizes[i].count) {
+ lsyslog(LOG_DEBUG,"%4d byte: %ld blocks\n",
+ blocksizes[i].size,blocksizes[i].count);
+ }
+ }
+ if (blocksizes[i].count) {
+ lsyslog(LOG_DEBUG,"unk. byte: %ld blocks",
+ blocksizes[i].count);
+ }
+}
+#define COUNT_BLK(x) count_blk(x)
+#else
+#define COUNT_BLK(x)
+#endif
+
+/*
+ * Receive array buf of max length with ending ZDLE sequence
+ * and CRC. Returns the ending character or error code.
+ * NB: On errors may store length+1 bytes!
+ */
+int
+zrdata(char *buf, int length, size_t *bytes_received)
+{
+ register int c;
+ register unsigned short crc;
+ register char *end;
+ register int d;
+
+ *bytes_received=0;
+ if (Rxframeind == ZBIN32)
+ return zrdat32(buf, length, bytes_received);
+
+ crc = 0; end = buf + length;
+ while (buf <= end) {
+ if ((c = zdlread()) & ~0377) {
+crcfoo:
+ switch (c) {
+ case GOTCRCE:
+ case GOTCRCG:
+ case GOTCRCQ:
+ case GOTCRCW:
+ {
+ d = c;
+ c &= 0377;
+ crc = updcrc(c, crc);
+ if ((c = zdlread()) & ~0377)
+ goto crcfoo;
+ crc = updcrc(c, crc);
+ if ((c = zdlread()) & ~0377)
+ goto crcfoo;
+ crc = updcrc(c, crc);
+ if (crc & 0xFFFF) {
+ zperr(badcrc);
+ return ERROR;
+ }
+ *bytes_received = length - (end - buf);
+ COUNT_BLK(*bytes_received);
+ VPRINTF(3,("zrdata: %lu %s", (unsigned long) (*bytes_received),
+ Zendnames[(d-GOTCRCE)&3]));
+ return d;
+ }
+ case GOTCAN:
+ zperr(_("Sender Canceled"));
+ return ZCAN;
+ case TIMEOUT:
+ zperr(_("TIMEOUT"));
+ return c;
+ default:
+ zperr(_("Bad data subpacket"));
+ return c;
+ }
+ }
+ *buf++ = c;
+ crc = updcrc(c, crc);
+ }
+ zperr(_("Data subpacket too long"));
+ return ERROR;
+}
+
+static int
+zrdat32(char *buf, int length, size_t *bytes_received)
+{
+ register int c;
+ register unsigned long crc;
+ register char *end;
+ register int d;
+
+ crc = 0xFFFFFFFFL; end = buf + length;
+ while (buf <= end) {
+ if ((c = zdlread()) & ~0377) {
+crcfoo:
+ switch (c) {
+ case GOTCRCE:
+ case GOTCRCG:
+ case GOTCRCQ:
+ case GOTCRCW:
+ d = c;
+ c &= 0377;
+ crc = UPDC32(c, crc);
+ if ((c = zdlread()) & ~0377)
+ goto crcfoo;
+ crc = UPDC32(c, crc);
+ if ((c = zdlread()) & ~0377)
+ goto crcfoo;
+ crc = UPDC32(c, crc);
+ if ((c = zdlread()) & ~0377)
+ goto crcfoo;
+ crc = UPDC32(c, crc);
+ if ((c = zdlread()) & ~0377)
+ goto crcfoo;
+ crc = UPDC32(c, crc);
+ if (crc != 0xDEBB20E3) {
+ zperr(badcrc);
+ return ERROR;
+ }
+ *bytes_received = length - (end - buf);
+ COUNT_BLK(*bytes_received);
+ VPRINTF(3,("zrdat32: %lu %s", (unsigned long) *bytes_received,
+ Zendnames[(d-GOTCRCE)&3]));
+ return d;
+ case GOTCAN:
+ zperr(_("Sender Canceled"));
+ return ZCAN;
+ case TIMEOUT:
+ zperr(_("TIMEOUT"));
+ return c;
+ default:
+ zperr(_("Bad data subpacket"));
+ return c;
+ }
+ }
+ *buf++ = c;
+ crc = UPDC32(c, crc);
+ }
+ zperr(_("Data subpacket too long"));
+ return ERROR;
+}
+
+/*
+ * Read a ZMODEM header to hdr, either binary or hex.
+ * eflag controls local display of non zmodem characters:
+ * 0: no display
+ * 1: display printing characters only
+ * 2: display all non ZMODEM characters
+ * On success, set Zmodem to 1, set Rxpos and return type of header.
+ * Otherwise return negative on error.
+ * Return ERROR instantly if ZCRCW sequence, for fast error recovery.
+ */
+int
+zgethdr(char *hdr, int eflag, size_t *Rxpos)
+{
+ register int c, cancount;
+ unsigned int max_garbage; /* Max bytes before start of frame */
+ size_t rxpos=0; /* keep gcc happy */
+
+ max_garbage = Zrwindow + Baudrate;
+ Rxframeind = Rxtype = 0;
+
+startover:
+ cancount = 5;
+again:
+ /* Return immediate ERROR if ZCRCW sequence seen */
+ switch (c = READLINE_PF(Rxtimeout)) {
+ case RCDO:
+ case TIMEOUT:
+ goto fifi;
+ case CAN:
+gotcan:
+ if (--cancount <= 0) {
+ c = ZCAN; goto fifi;
+ }
+ switch (c = READLINE_PF(1)) {
+ case TIMEOUT:
+ goto again;
+ case ZCRCW:
+ c = ERROR;
+ /* **** FALL THRU TO **** */
+ case RCDO:
+ goto fifi;
+ default:
+ break;
+ case CAN:
+ if (--cancount <= 0) {
+ c = ZCAN; goto fifi;
+ }
+ goto again;
+ }
+ /* **** FALL THRU TO **** */
+ default:
+agn2:
+ if ( --max_garbage == 0) {
+ zperr(_("Garbage count exceeded"));
+ return(ERROR);
+ }
+ if (eflag && ((c &= 0177) & 0140) && Verbose)
+ vchar(c);
+ else if (eflag > 1 && Verbose)
+ vchar(c);
+ goto startover;
+ case ZPAD|0200: /* This is what we want. */
+ case ZPAD: /* This is what we want. */
+ break;
+ }
+ cancount = 5;
+splat:
+ switch (c = noxrd7()) {
+ case ZPAD:
+ goto splat;
+ case RCDO:
+ case TIMEOUT:
+ goto fifi;
+ default:
+ goto agn2;
+ case ZDLE: /* This is what we want. */
+ break;
+ }
+
+ switch (c = noxrd7()) {
+ case RCDO:
+ case TIMEOUT:
+ goto fifi;
+ case ZBIN:
+ Rxframeind = ZBIN; Crc32 = FALSE;
+ c = zrbhdr(hdr);
+ break;
+ case ZBIN32:
+ Crc32 = Rxframeind = ZBIN32;
+ c = zrbhdr32(hdr);
+ break;
+ case ZHEX:
+ Rxframeind = ZHEX; Crc32 = FALSE;
+ c = zrhhdr(hdr);
+ break;
+ case CAN:
+ goto gotcan;
+ default:
+ goto agn2;
+ }
+ rxpos = hdr[ZP3] & 0377;
+ rxpos = (rxpos<<8) + (hdr[ZP2] & 0377);
+ rxpos = (rxpos<<8) + (hdr[ZP1] & 0377);
+ rxpos = (rxpos<<8) + (hdr[ZP0] & 0377);
+fifi:
+ switch (c) {
+ case GOTCAN:
+ c = ZCAN;
+ /* **** FALL THRU TO **** */
+ case ZNAK:
+ case ZCAN:
+ case ERROR:
+ case TIMEOUT:
+ case RCDO:
+ zperr(_("Got %s"), frametypes[c+FTOFFSET]);
+ /* **** FALL THRU TO **** */
+ default:
+ if (c >= -3 && c <= FRTYPES)
+ VPRINTF(3,("zgethdr: %s %lx", frametypes[c+FTOFFSET], (unsigned long) rxpos));
+ else
+ VPRINTF(3,("zgethdr: %d %lx", c, (unsigned long) rxpos));
+ }
+ if (Rxpos)
+ *Rxpos=rxpos;
+ return c;
+}
+
+/* Receive a binary style header (type and position) */
+static int
+zrbhdr(char *hdr)
+{
+ register int c, n;
+ register unsigned short crc;
+
+ if ((c = zdlread()) & ~0377)
+ return c;
+ Rxtype = c;
+ crc = updcrc(c, 0);
+
+ for (n=4; --n >= 0; ++hdr) {
+ if ((c = zdlread()) & ~0377)
+ return c;
+ crc = updcrc(c, crc);
+ *hdr = c;
+ }
+ if ((c = zdlread()) & ~0377)
+ return c;
+ crc = updcrc(c, crc);
+ if ((c = zdlread()) & ~0377)
+ return c;
+ crc = updcrc(c, crc);
+ if (crc & 0xFFFF) {
+ zperr(badcrc);
+ return ERROR;
+ }
+ protocol = ZM_ZMODEM;
+ zmodem_requested=TRUE;
+ return Rxtype;
+}
+
+/* Receive a binary style header (type and position) with 32 bit FCS */
+static int
+zrbhdr32(char *hdr)
+{
+ register int c, n;
+ register unsigned long crc;
+
+ if ((c = zdlread()) & ~0377)
+ return c;
+ Rxtype = c;
+ crc = 0xFFFFFFFFL; crc = UPDC32(c, crc);
+#ifdef DEBUGZ
+ VPRINTF(3,("zrbhdr32 c=%X crc=%lX", c, crc)i);
+#endif
+
+ for (n=4; --n >= 0; ++hdr) {
+ if ((c = zdlread()) & ~0377)
+ return c;
+ crc = UPDC32(c, crc);
+ *hdr = c;
+#ifdef DEBUGZ
+ VPRINTF(3,("zrbhdr32 c=%X crc=%lX", c, crc));
+#endif
+ }
+ for (n=4; --n >= 0;) {
+ if ((c = zdlread()) & ~0377)
+ return c;
+ crc = UPDC32(c, crc);
+#ifdef DEBUGZ
+ VPRINTF(3,("zrbhdr32 c=%X crc=%lX", c, crc));
+#endif
+ }
+ if (crc != 0xDEBB20E3) {
+ zperr(badcrc);
+ return ERROR;
+ }
+ protocol = ZM_ZMODEM;
+ zmodem_requested=TRUE;
+ return Rxtype;
+}
+
+
+/* Receive a hex style header (type and position) */
+static int
+zrhhdr(char *hdr)
+{
+ register int c;
+ register unsigned short crc;
+ register int n;
+
+ if ((c = zgethex()) < 0)
+ return c;
+ Rxtype = c;
+ crc = updcrc(c, 0);
+
+ for (n=4; --n >= 0; ++hdr) {
+ if ((c = zgethex()) < 0)
+ return c;
+ crc = updcrc(c, crc);
+ *hdr = c;
+ }
+ if ((c = zgethex()) < 0)
+ return c;
+ crc = updcrc(c, crc);
+ if ((c = zgethex()) < 0)
+ return c;
+ crc = updcrc(c, crc);
+ if (crc & 0xFFFF) {
+ zperr(badcrc); return ERROR;
+ }
+ switch ( c = READLINE_PF(1)) {
+ case 0215:
+ /* **** FALL THRU TO **** */
+ case 015:
+ /* Throw away possible cr/lf */
+ READLINE_PF(1);
+ break;
+ }
+ protocol = ZM_ZMODEM;
+ zmodem_requested=TRUE;
+ return Rxtype;
+}
+
+/* Write a byte as two hex digits */
+static void
+zputhex(int c, char *pos)
+{
+ static char digits[] = "0123456789abcdef";
+
+ VPRINTF(9,("zputhex: %02X", c));
+ pos[0]=digits[(c&0xF0)>>4];
+ pos[1]=digits[c&0x0F];
+}
+
+void
+zsendline_init(void)
+{
+ int i;
+ for (i=0;i<256;i++) {
+ if (i & 0140)
+ zsendline_tab[i]=0;
+ else {
+ switch(i)
+ {
+ case ZDLE:
+ case XOFF: /* ^Q */
+ case XON: /* ^S */
+ case (XOFF | 0200):
+ case (XON | 0200):
+ zsendline_tab[i]=1;
+ break;
+ case 020: /* ^P */
+ case 0220:
+ if (turbo_escape)
+ zsendline_tab[i]=0;
+ else
+ zsendline_tab[i]=1;
+ break;
+ case 015:
+ case 0215:
+ if (Zctlesc)
+ zsendline_tab[i]=1;
+ else if (!turbo_escape)
+ zsendline_tab[i]=2;
+ else
+ zsendline_tab[i]=0;
+ break;
+ default:
+ if (Zctlesc)
+ zsendline_tab[i]=1;
+ else
+ zsendline_tab[i]=0;
+ }
+ }
+ }
+}
+
+
+
+/* Store pos in Txhdr */
+void
+stohdr(size_t pos)
+{
+ long lpos=(long) pos;
+ Txhdr[ZP0] = lpos;
+ Txhdr[ZP1] = lpos>>8;
+ Txhdr[ZP2] = lpos>>16;
+ Txhdr[ZP3] = lpos>>24;
+}
+
+/* Recover a long integer from a header */
+long
+rclhdr(char *hdr)
+{
+ long l;
+
+ l = (hdr[ZP3] & 0377);
+ l = (l << 8) | (hdr[ZP2] & 0377);
+ l = (l << 8) | (hdr[ZP1] & 0377);
+ l = (l << 8) | (hdr[ZP0] & 0377);
+ return l;
+}
+
+/* End of zm.c */
diff --git a/zmodem.h b/zmodem.h
new file mode 100644
index 0000000..01c9b2e
--- /dev/null
+++ b/zmodem.h
@@ -0,0 +1,142 @@
+/* zmodem.h - ZMODEM protocol constants
+
+ Copyright (C) until 1998 Chuck Forsberg (OMEN Technology Inc)
+ Copyright (C) 1996, 1997 Uwe Ohse
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ * 05-23-87 Chuck Forsberg Omen Technology Inc
+*/
+#define ZPAD '*' /* 052 Padding character begins frames */
+#define ZDLE 030 /* Ctrl-X Zmodem escape - `ala BISYNC DLE */
+#define ZDLEE (ZDLE^0100) /* Escaped ZDLE as transmitted */
+#define ZBIN 'A' /* Binary frame indicator */
+#define ZHEX 'B' /* HEX frame indicator */
+#define ZBIN32 'C' /* Binary frame with 32 bit FCS */
+
+/* Frame types (see array "frametypes" in zm.c) */
+#define ZRQINIT 0 /* Request receive init */
+#define ZRINIT 1 /* Receive init */
+#define ZSINIT 2 /* Send init sequence (optional) */
+#define ZACK 3 /* ACK to above */
+#define ZFILE 4 /* File name from sender */
+#define ZSKIP 5 /* To sender: skip this file */
+#define ZNAK 6 /* Last packet was garbled */
+#define ZABORT 7 /* Abort batch transfers */
+#define ZFIN 8 /* Finish session */
+#define ZRPOS 9 /* Resume data trans at this position */
+#define ZDATA 10 /* Data packet(s) follow */
+#define ZEOF 11 /* End of file */
+#define ZFERR 12 /* Fatal Read or Write error Detected */
+#define ZCRC 13 /* Request for file CRC and response */
+#define ZCHALLENGE 14 /* Receiver's Challenge */
+#define ZCOMPL 15 /* Request is complete */
+#define ZCAN 16 /* Other end canned session with CAN*5 */
+#define ZFREECNT 17 /* Request for free bytes on filesystem */
+#define ZCOMMAND 18 /* Command from sending program */
+#define ZSTDERR 19 /* Output to standard error, data follows */
+
+/* ZDLE sequences */
+#define ZCRCE 'h' /* CRC next, frame ends, header packet follows */
+#define ZCRCG 'i' /* CRC next, frame continues nonstop */
+#define ZCRCQ 'j' /* CRC next, frame continues, ZACK expected */
+#define ZCRCW 'k' /* CRC next, ZACK expected, end of frame */
+#define ZRUB0 'l' /* Translate to rubout 0177 */
+#define ZRUB1 'm' /* Translate to rubout 0377 */
+
+/* zdlread return values (internal) */
+/* -1 is general error, -2 is timeout */
+#define GOTOR 0400
+#define GOTCRCE (ZCRCE|GOTOR) /* ZDLE-ZCRCE received */
+#define GOTCRCG (ZCRCG|GOTOR) /* ZDLE-ZCRCG received */
+#define GOTCRCQ (ZCRCQ|GOTOR) /* ZDLE-ZCRCQ received */
+#define GOTCRCW (ZCRCW|GOTOR) /* ZDLE-ZCRCW received */
+#define GOTCAN (GOTOR|030) /* CAN*5 seen */
+
+/* Byte positions within header array */
+#define ZF0 3 /* First flags byte */
+#define ZF1 2
+#define ZF2 1
+#define ZF3 0
+#define ZP0 0 /* Low order 8 bits of position */
+#define ZP1 1
+#define ZP2 2
+#define ZP3 3 /* High order 8 bits of file position */
+
+/* Bit Masks for ZRINIT flags byte ZF0 */
+#define CANFDX 0x01 /* Rx can send and receive true FDX */
+#define CANOVIO 0x02 /* Rx can receive data during disk I/O */
+#define CANBRK 0x04 /* Rx can send a break signal */
+#define CANCRY 0x08 /* Receiver can decrypt */
+#define CANLZW 0x10 /* Receiver can uncompress */
+#define CANFC32 0x20 /* Receiver can use 32 bit Frame Check */
+#define ESCCTL 0x40 /* Receiver expects ctl chars to be escaped */
+#define ESC8 0x80 /* Receiver expects 8th bit to be escaped */
+/* Bit Masks for ZRINIT flags byze ZF1 */
+#define ZF1_CANVHDR 0x01 /* Variable headers OK, unused in lrzsz */
+#define ZF1_TIMESYNC 0x02 /* nonstandard, Receiver request timesync */
+
+/* Parameters for ZSINIT frame */
+#define ZATTNLEN 32 /* Max length of attention string */
+/* Bit Masks for ZSINIT flags byte ZF0 */
+#define TESCCTL 0100 /* Transmitter expects ctl chars to be escaped */
+#define TESC8 0200 /* Transmitter expects 8th bit to be escaped */
+
+/* Parameters for ZFILE frame */
+/* Conversion options one of these in ZF0 */
+#define ZCBIN 1 /* Binary transfer - inhibit conversion */
+#define ZCNL 2 /* Convert NL to local end of line convention */
+#define ZCRESUM 3 /* Resume interrupted file transfer */
+/* Management include options, one of these ored in ZF1 */
+#define ZF1_ZMSKNOLOC 0x80 /* Skip file if not present at rx */
+/* Management options, one of these ored in ZF1 */
+#define ZF1_ZMMASK 0x1f /* Mask for the choices below */
+#define ZF1_ZMNEWL 1 /* Transfer if source newer or longer */
+#define ZF1_ZMCRC 2 /* Transfer if different file CRC or length */
+#define ZF1_ZMAPND 3 /* Append contents to existing file (if any) */
+#define ZF1_ZMCLOB 4 /* Replace existing file */
+#define ZF1_ZMNEW 5 /* Transfer if source newer */
+ /* Number 5 is alive ... */
+#define ZF1_ZMDIFF 6 /* Transfer if dates or lengths different */
+#define ZF1_ZMPROT 7 /* Protect destination file */
+#define ZF1_ZMCHNG 8 /* Change filename if destination exists */
+
+/* Transport options, one of these in ZF2 */
+#define ZTLZW 1 /* Lempel-Ziv compression */
+#define ZTCRYPT 2 /* Encryption */
+#define ZTRLE 3 /* Run Length encoding */
+/* Extended options for ZF3, bit encoded */
+#define ZXSPARS 64 /* Encoding for sparse file operations */
+
+/* Parameters for ZCOMMAND frame ZF0 (otherwise 0) */
+#define ZCACK1 1 /* Acknowledge, then do command */
+
+/* Globals used by ZMODEM functions */
+#if 0
+extern int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */
+extern int Rxtype; /* Type of header received */
+extern int Zrwindow; /* RX window size (controls garbage count) */
+extern char Rxhdr[4]; /* Received header */
+extern char Txhdr[4]; /* Transmitted header */
+extern long Txpos; /* Transmitted file position */
+extern int Txfcs32; /* TURE means send binary frames with 32 bit FCS */
+extern int Crc32t; /* Display flag indicating 32 bit CRC being sent */
+extern int Crc32; /* Display flag indicating 32 bit CRC being received */
+extern int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */
+extern char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */
+#endif
+
+/* End of ZMODEM.H */
diff --git a/zperr.c b/zperr.c
new file mode 100644
index 0000000..31963de
--- /dev/null
+++ b/zperr.c
@@ -0,0 +1,113 @@
+/*
+ zperr.c - "stderr" output stuff
+ Copyright (C) 1996, 1997 Uwe Ohse
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ originally written by Uwe Ohse
+*/
+#include "zglobal.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#ifdef __STDC__
+# define WAYTOGO
+# include <stdarg.h>
+# define VA_START(args, lastarg) va_start(args, lastarg)
+#else
+# include <varargs.h>
+# define VA_START(args, lastarg) va_start(args)
+#endif
+
+void
+#ifdef WAYTOGO
+zperr(const char *fmt, ...)
+#else
+zperr(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+ if (Verbose<=0)
+ return;
+ fprintf(stderr,_("Retry %d: "),errors);
+ VA_START(ap, fmt);
+ vfprintf(stderr,fmt, ap);
+ va_end(ap);
+ putc('\n',stderr);
+}
+
+void
+#ifdef WAYTOGO
+zpfatal(const char *fmt, ...)
+#else
+zpfatal(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+ int err=errno;
+
+ if (Verbose<=0)
+ return;
+ fprintf(stderr,"%s: ",program_name);
+ VA_START(ap, fmt);
+ vfprintf(stderr,fmt, ap);
+ va_end(ap);
+ fprintf(stderr,": %s\n",strerror(err));
+}
+
+void
+#ifdef WAYTOGO
+vfile(const char *format, ...)
+#else
+vfile(format, va_alist)
+ const char *format;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+ if (Verbose < 3)
+ return;
+ VA_START(ap, format);
+ vfprintf(stderr,format, ap);
+ va_end(ap);
+ putc('\n',stderr);
+}
+
+#ifndef vstringf
+/* if using gcc this function is not needed */
+void
+#ifdef WAYTOGO
+vstringf(const char *format, ...)
+#else
+vstringf(format, va_alist)
+ const char *format;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+ VA_START(ap, format);
+ vfprintf(stderr,format, ap);
+ va_end(ap);
+}
+#endif
diff --git a/zreadline.c b/zreadline.c
new file mode 100644
index 0000000..dd9736b
--- /dev/null
+++ b/zreadline.c
@@ -0,0 +1,136 @@
+/*
+ zreadline.c - line reading stuff for lrzsz
+ Copyright (C) until 1998 Chuck Forsberg (OMEN Technology Inc)
+ Copyright (C) 1994 Matt Porter
+ Copyright (C) 1996, 1997 Uwe Ohse
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ originally written by Chuck Forsberg
+*/
+/* once part of lrz.c, taken out to be useful to lsz.c too */
+
+#include "zglobal.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "error.h"
+
+
+/* Ward Christensen / CP/M parameters - Don't change these! */
+#define TIMEOUT (-2)
+
+static size_t readline_readnum;
+static int readline_fd;
+static char *readline_buffer;
+int readline_left=0;
+char *readline_ptr;
+
+static RETSIGTYPE
+zreadline_alarm_handler(int dummy)
+{
+ dummy++; /* doesn't need to do anything */
+}
+
+/*
+ * This version of readline is reasonably well suited for
+ * reading many characters.
+ *
+ * timeout is in tenths of seconds
+ */
+int
+readline_internal(unsigned int timeout)
+{
+
+ if (!no_timeout)
+ {
+ unsigned int n;
+ n = timeout/10;
+ if (n < 2 && timeout!=1)
+ n = 3;
+ else if (n==0)
+ n=1;
+ if (Verbose > 5)
+ vstringf("Calling read: alarm=%d Readnum=%d ",
+ n, readline_readnum);
+ signal(SIGALRM, zreadline_alarm_handler);
+ alarm(n);
+ }
+ else if (Verbose > 5)
+ vstringf("Calling read: Readnum=%d ",
+ readline_readnum);
+
+ readline_ptr=readline_buffer;
+ readline_left=read(readline_fd, readline_ptr, readline_readnum);
+ if (!no_timeout)
+ alarm(0);
+ if (readline_left>0 && bytes_per_error) {
+ static long ct=0;
+ static int mod=1;
+ ct+=readline_left;
+ while (ct>bytes_per_error) {
+ readline_ptr[ct % bytes_per_error]^=mod;
+ ct-=bytes_per_error;
+ mod++;
+ if (mod==256)
+ mod=1;
+ }
+ }
+ if (Verbose > 5) {
+ vstringf("Read returned %d bytes\n", readline_left);
+ if (readline_left==-1)
+ vstringf("errno=%d:%s\n", errno,strerror(errno));
+ if (Verbose > 9 && readline_left>0) {
+ int i,j;
+ j=readline_left > 48 ? 48 : readline_left;
+ vstring(" ");
+ for (i=0;i<j;i++) {
+ if (i%24==0 && i)
+ vstring("\n ");
+ vstringf("%02x ", readline_ptr[i] & 0377);
+ }
+ vstringf("\n");
+ }
+ }
+ if (readline_left < 1)
+ return TIMEOUT;
+ --readline_left;
+ return (*readline_ptr++ & 0377);
+}
+
+
+
+void
+readline_setup(int fd, size_t readnum, size_t bufsize)
+{
+ readline_fd=fd;
+ readline_readnum=readnum;
+ readline_buffer=malloc(bufsize > readnum ? bufsize : readnum);
+ if (!readline_buffer)
+ error(1,0,_("out of memory"));
+}
+
+void
+readline_purge(void)
+{
+ readline_left=0;
+ return;
+}
+