1/* prott.c
2   The 't' protocol.
3
4   Copyright (C) 1991, 1992, 2002 Ian Lance Taylor
5
6   This file is part of the Taylor UUCP package.
7
8   This program is free software; you can redistribute it and/or
9   modify it under the terms of the GNU General Public License as
10   published by the Free Software Foundation; either version 2 of the
11   License, or (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
21
22   The author of the program may be contacted at ian@airs.com.
23   */
24
25#include "uucp.h"
26
27#if USE_RCS_ID
28const char prott_rcsid[] = "$Id: prott.c,v 1.32 2002/03/05 19:10:41 ian Rel $";
29#endif
30
31#include "uudefs.h"
32#include "uuconf.h"
33#include "conn.h"
34#include "trans.h"
35#include "system.h"
36#include "prot.h"
37
38/* This implementation is based on code written by Rick Adams.
39
40   This code implements the 't' protocol, which does no error checking
41   whatsoever and thus requires an end-to-end verified eight bit
42   communication line, such as is provided by TCP.  Using it with a
43   modem is unadvisable, since errors can occur between the modem and
44   the computer.  */
45
46/* The buffer size we use.  */
47#define CTBUFSIZE (1024)
48
49/* The offset in the buffer to the data.  */
50#define CTFRAMELEN (4)
51
52/* Commands are sent in multiples of this size.  */
53#define CTPACKSIZE (512)
54
55/* A pointer to the buffer we will use.  */
56static char *zTbuf;
57
58/* True if we are receiving a file.  */
59static boolean fTfile;
60
61/* The timeout we use.  */
62static int cTtimeout = 120;
63
64struct uuconf_cmdtab asTproto_params[] =
65{
66  { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cTtimeout, NULL },
67  { NULL, 0, NULL, NULL }
68};
69
70/* Local function.  */
71
72static boolean ftprocess_data P((struct sdaemon *qdaemon, boolean *pfexit,
73				 size_t *pcneed));
74
75/* Start the protocol.  */
76
77boolean
78ftstart (qdaemon, pzlog)
79     struct sdaemon *qdaemon;
80     char **pzlog;
81{
82  *pzlog = NULL;
83  if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE,
84		   STRIPSETTING_EIGHTBITS, XONXOFF_OFF))
85    return FALSE;
86  zTbuf = (char *) xmalloc (CTBUFSIZE + CTFRAMELEN);
87  /* The first two bytes of the buffer are always zero.  */
88  zTbuf[0] = 0;
89  zTbuf[1] = 0;
90  fTfile = FALSE;
91  usysdep_sleep (2);
92  return TRUE;
93}
94
95/* Stop the protocol.  */
96
97/*ARGSUSED*/
98boolean
99ftshutdown (qdaemon)
100     struct sdaemon *qdaemon ATTRIBUTE_UNUSED;
101{
102  xfree ((pointer) zTbuf);
103  zTbuf = NULL;
104  cTtimeout = 120;
105  return TRUE;
106}
107
108/* Send a command string.  We send everything up to and including the
109   null byte.  The number of bytes we send must be a multiple of
110   TPACKSIZE.  */
111
112/*ARGSUSED*/
113boolean
114ftsendcmd (qdaemon, z, ilocal, iremote)
115     struct sdaemon *qdaemon;
116     const char *z;
117     int ilocal ATTRIBUTE_UNUSED;
118     int iremote ATTRIBUTE_UNUSED;
119{
120  size_t clen, csend;
121  char *zalc;
122  boolean fret;
123
124  DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "ftsendcmd: Sending command \"%s\"", z);
125
126  clen = strlen (z);
127
128  /* We need to send the smallest multiple of CTPACKSIZE which is
129     greater than clen (not equal to clen, since we need room for the
130     null byte).  */
131  csend = ((clen / CTPACKSIZE) + 1) * CTPACKSIZE;
132
133  zalc = zbufalc (csend);
134  memcpy (zalc, z, clen);
135  if (csend > clen)
136    bzero (zalc + clen, csend - clen);
137
138  fret = fsend_data (qdaemon->qconn, zalc, csend, TRUE);
139  ubuffree (zalc);
140  return fret;
141}
142
143/* Get space to be filled with data.  We provide a buffer which has
144   four bytes at the start available to hold the length.  */
145
146/*ARGSIGNORED*/
147char *
148ztgetspace (qdaemon, pclen)
149     struct sdaemon *qdaemon ATTRIBUTE_UNUSED;
150     size_t *pclen;
151{
152  *pclen = CTBUFSIZE;
153  return zTbuf + CTFRAMELEN;
154}
155
156/* Send out some data.  We are allowed to modify the four bytes
157   preceding the buffer.  This allows us to send the entire block with
158   header bytes in a single call.  */
159
160/*ARGSIGNORED*/
161boolean
162ftsenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos)
163     struct sdaemon *qdaemon;
164     char *zdata;
165     size_t cdata;
166     int ilocal ATTRIBUTE_UNUSED;
167     int iremote ATTRIBUTE_UNUSED;
168     long ipos ATTRIBUTE_UNUSED;
169{
170  /* Here we do htonl by hand, since it doesn't exist everywhere.  We
171     know that the amount of data cannot be greater than CTBUFSIZE, so
172     the first two bytes of this value will always be 0.  They were
173     set to 0 in ftstart so we don't touch them here.  This is useful
174     because we cannot portably right shift by 24 or 16, since we
175     might be dealing with sixteen bit integers.  */
176  zdata[-2] = (char) ((cdata >> 8) & 0xff);
177  zdata[-1] = (char) (cdata & 0xff);
178
179  /* We pass FALSE to fsend_data since we don't expect the other side
180     to be sending us anything just now.  */
181  return fsend_data (qdaemon->qconn, zdata - CTFRAMELEN, cdata + CTFRAMELEN,
182		     FALSE);
183}
184
185/* Process data and return the amount we need in *pfneed.  */
186
187static boolean
188ftprocess_data (qdaemon, pfexit, pcneed)
189     struct sdaemon *qdaemon;
190     boolean *pfexit;
191     size_t *pcneed;
192{
193  int cinbuf, cfirst, clen;
194
195  *pfexit = FALSE;
196
197  cinbuf = iPrecend - iPrecstart;
198  if (cinbuf < 0)
199    cinbuf += CRECBUFLEN;
200
201  if (! fTfile)
202    {
203      /* We are not receiving a file.  Commands are read in chunks of
204	 CTPACKSIZE.  */
205      while (cinbuf >= CTPACKSIZE)
206	{
207	  cfirst = CRECBUFLEN - iPrecstart;
208	  if (cfirst > CTPACKSIZE)
209	    cfirst = CTPACKSIZE;
210
211	  DEBUG_MESSAGE1 (DEBUG_PROTO,
212			  "ftprocess_data: Got %d command bytes",
213			  cfirst);
214
215	  if (! fgot_data (qdaemon, abPrecbuf + iPrecstart,
216			   (size_t) cfirst, abPrecbuf,
217			   (size_t) CTPACKSIZE - cfirst,
218			   -1, -1, (long) -1, TRUE, pfexit))
219	    return FALSE;
220
221	  iPrecstart = (iPrecstart + CTPACKSIZE) % CRECBUFLEN;
222
223	  if (*pfexit)
224	    return TRUE;
225
226	  cinbuf -= CTPACKSIZE;
227	}
228
229      if (pcneed != NULL)
230	*pcneed = CTPACKSIZE - cinbuf;
231
232      return TRUE;
233    }
234
235  /* Here we are receiving a file.  The data comes in blocks.  The
236     first four bytes contain the length, followed by that amount of
237     data.  */
238
239  while (cinbuf >= CTFRAMELEN)
240    {
241      /* The length is stored in network byte order, MSB first.  */
242
243      clen = (((((((abPrecbuf[iPrecstart] & 0xff) << 8)
244		  + (abPrecbuf[(iPrecstart + 1) % CRECBUFLEN] & 0xff)) << 8)
245		+ (abPrecbuf[(iPrecstart + 2) % CRECBUFLEN] & 0xff)) << 8)
246	      + (abPrecbuf[(iPrecstart + 3) % CRECBUFLEN] & 0xff));
247
248      if (cinbuf < clen + CTFRAMELEN)
249	{
250	  if (pcneed != NULL)
251	    *pcneed = clen + CTFRAMELEN - cinbuf;
252	  return TRUE;
253	}
254
255      iPrecstart = (iPrecstart + CTFRAMELEN) % CRECBUFLEN;
256
257      cfirst = CRECBUFLEN - iPrecstart;
258      if (cfirst > clen)
259	cfirst = clen;
260
261      DEBUG_MESSAGE1 (DEBUG_PROTO,
262		      "ftprocess_data: Got %d data bytes",
263		      clen);
264
265      if (! fgot_data (qdaemon, abPrecbuf + iPrecstart,
266		       (size_t) cfirst, abPrecbuf, (size_t) (clen - cfirst),
267		       -1, -1, (long) -1, TRUE, pfexit))
268	return FALSE;
269
270      iPrecstart = (iPrecstart + clen) % CRECBUFLEN;
271
272      if (*pfexit)
273	return TRUE;
274
275      cinbuf -= clen + CTFRAMELEN;
276    }
277
278  if (pcneed != NULL)
279    *pcneed = CTFRAMELEN - cinbuf;
280
281  return TRUE;
282}
283
284/* Wait for data to come in and process it until we've reached the end
285   of a command or a file.  */
286
287boolean
288ftwait (qdaemon)
289     struct sdaemon *qdaemon;
290{
291  while (TRUE)
292    {
293      boolean fexit;
294      size_t cneed, crec;
295
296      if (! ftprocess_data (qdaemon, &fexit, &cneed))
297	return FALSE;
298      if (fexit)
299	return TRUE;
300
301      if (! freceive_data (qdaemon->qconn, cneed, &crec, cTtimeout, TRUE))
302	return FALSE;
303
304      if (crec == 0)
305	{
306	  ulog (LOG_ERROR, "Timed out waiting for data");
307	  return FALSE;
308	}
309    }
310}
311
312/* File level routine, to set fTfile correctly.  */
313
314/*ARGSUSED*/
315boolean
316ftfile (qdaemon, qtrans, fstart, fsend, cbytes, pfhandled)
317     struct sdaemon *qdaemon ATTRIBUTE_UNUSED;
318     struct stransfer *qtrans ATTRIBUTE_UNUSED;
319     boolean fstart;
320     boolean fsend;
321     long cbytes ATTRIBUTE_UNUSED;
322     boolean *pfhandled;
323{
324  *pfhandled = FALSE;
325
326  if (! fsend)
327    fTfile = fstart;
328
329  return TRUE;
330}
331