1 /* prot.c
2 Protocol support routines to move commands and data around.
3
4 Copyright (C) 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 The author of the program may be contacted at ian@airs.com or
23 c/o AIRS, P.O. Box 520, Waltham, MA 02254.
24
25 $Log: prot.c,v $
26 Revision 1.21 1992/04/02 22:51:09 ian
27 Add gcc 2.0 format checking to ulog, and fixed discovered problems
28
29 Revision 1.20 1992/03/30 04:49:10 ian
30 Niels Baggesen: added debugging types abnormal and uucp-proto
31
32 Revision 1.19 1992/03/30 04:07:13 ian
33 Dirk Musstopf: remove temporary file if receive fails
34
35 Revision 1.18 1992/03/13 22:59:25 ian
36 Have breceive_char go through freceive_data
37
38 Revision 1.17 1992/03/12 19:56:10 ian
39 Debugging based on types rather than number
40
41 Revision 1.16 1992/03/11 01:18:15 ian
42 Niels Baggesen: drop the connection on a write failure
43
44 Revision 1.15 1992/03/11 00:18:50 ian
45 Save temporary file if file send fails
46
47 Revision 1.14 1992/02/09 05:21:55 ian
48 Bob Denny: call fmail_transfer before fsysdep_did_work
49
50 Revision 1.13 1992/02/08 19:41:24 ian
51 Simplify pffile calls for ancient stupid compilers
52
53 Revision 1.12 1992/02/08 03:54:18 ian
54 Include <string.h> only in <uucp.h>, added 1992 copyright
55
56 Revision 1.11 1992/01/18 22:48:53 ian
57 Reworked sending of mail and general handling of failed transfers
58
59 Revision 1.10 1992/01/16 18:16:58 ian
60 Niels Baggesen: add some debugging messages
61
62 Revision 1.9 1991/12/31 19:34:19 ian
63 Added number of bytes to pffile protocol entry point
64
65 Revision 1.8 1991/12/30 04:28:30 ian
66 John Theus: check for EOF to work around bug in fread
67
68 Revision 1.7 1991/12/21 23:10:43 ian
69 Terry Gardner: record failed file transfers in statistics file
70
71 Revision 1.6 1991/12/13 04:33:38 ian
72 Franc,ois Pinard: don't bother to warn if the final HY doesn't come in
73
74 Revision 1.5 1991/11/15 21:00:59 ian
75 Efficiency hacks for 'f' and 't' protocols
76
77 Revision 1.4 1991/11/11 19:32:03 ian
78 Added breceive_char to read characters through protocol buffering
79
80 Revision 1.3 1991/11/11 04:21:16 ian
81 Added 'f' protocol
82
83 Revision 1.2 1991/11/10 19:24:22 ian
84 Added pffile protocol entry point for file level control
85
86 Revision 1.1 1991/11/09 18:51:50 ian
87 Initial revision
88
89 */
90
91 #include "uucp.h"
92
93 #if USE_RCS_ID
94 char prot_rcsid[] = "$Id: prot.c,v 1.21 1992/04/02 22:51:09 ian Rel $";
95 #endif
96
97 #include <errno.h>
98
99 #include "system.h"
100 #include "port.h"
101 #include "prot.h"
102
103 /* This file implements the generic UUCP protocol for making and
104 confirming file transfer requests. This involves sending ASCII
105 strings back and forth between the communicating daemons. It would
106 be possible to use a different scheme when designing a new
107 protocol, but this scheme is used by all traditional UUCP
108 protocols. */
109
110 /* Local functions. */
111
112 static boolean fpsendfile_confirm P((void));
113 static boolean fprecfile_confirm P((void));
114 static boolean fploop P((void));
115 static void upadd_cmd P((const char *z, int clen, boolean flast));
116
117 /* Variables visible to the protocol-specific routines. */
118
119 /* Protocol structure. */
120 const struct sprotocol *qProto;
121
122 /* Buffer to hold received data. */
123 char abPrecbuf[CRECBUFLEN];
124
125 /* Index of start of data in abPrecbuf. */
126 int iPrecstart;
127
128 /* Index of end of data (first byte not included in data) in abPrecbuf. */
129 int iPrecend;
130
131 /* Whether an unexpected shutdown is OK now; this is used to avoid
132 giving a warning for systems that hang up in a hurry. */
133 boolean fPerror_ok;
134
135 /* Amount of data sent for current send file; -1 means there is no
136 current send file. */
137 static long cPsent_bytes = -1;
138
139 /* Amount of data received for current receive file; -1 means there is
140 no current receive file. */
141 static long cPreceived_bytes = -1;
142
143 /* Send a file. If we are the master, we must send a command to
144 transfer the file and wait for a confirmation that we can begin
145 sending the file. If we are the slave, the master has sent us a
146 command and is waiting for a reply; we must confirm that we will
147 send the file. Either way, we begin transferring data.
148
149 This function returns FALSE if there is a communication failure.
150 It returns TRUE otherwise, even if the file transfer failed. */
151
152 boolean
fsend_file(fmaster,e,qcmd,zmail,ztosys,fnew)153 fsend_file (fmaster, e, qcmd, zmail, ztosys, fnew)
154 boolean fmaster;
155 openfile_t e;
156 const struct scmd *qcmd;
157 const char *zmail;
158 const char *ztosys;
159 boolean fnew;
160 {
161 if (fmaster)
162 {
163 int clen;
164 char *zsend;
165 const char *zrec;
166
167 /* Send the string
168 S zfrom zto zuser zoptions ztemp imode znotify
169 to the remote system. We put a '-' in front of the (possibly
170 empty) options and a '0' in front of the mode. The remote
171 system will ignore ztemp, but it is supposed to be sent anyhow.
172 If fnew is TRUE, we also send the size; in this case if ztemp
173 is empty we must send it as "". */
174 clen = (strlen (qcmd->zfrom) + strlen (qcmd->zto)
175 + strlen (qcmd->zuser) + strlen (qcmd->zoptions)
176 + strlen (qcmd->ztemp) + strlen (qcmd->znotify)
177 + 50);
178 zsend = (char *) alloca (clen);
179 if (! fnew)
180 sprintf (zsend, "S %s %s %s -%s %s 0%o %s", qcmd->zfrom, qcmd->zto,
181 qcmd->zuser, qcmd->zoptions, qcmd->ztemp, qcmd->imode,
182 qcmd->znotify);
183 else
184 {
185 const char *znotify;
186
187 if (qcmd->znotify[0] != '\0')
188 znotify = qcmd->znotify;
189 else
190 znotify = "\"\"";
191 sprintf (zsend, "S %s %s %s -%s %s 0%o %s %ld", qcmd->zfrom,
192 qcmd->zto, qcmd->zuser, qcmd->zoptions, qcmd->ztemp,
193 qcmd->imode, znotify, qcmd->cbytes);
194 }
195
196 if (! (qProto->pfsendcmd) (zsend))
197 {
198 (void) ffileclose (e);
199 return FALSE;
200 }
201
202 /* Now we must await a reply. */
203
204 zrec = zgetcmd ();
205 if (zrec == NULL)
206 {
207 (void) ffileclose (e);
208 return FALSE;
209 }
210
211 if (zrec[0] != 'S'
212 || (zrec[1] != 'Y' && zrec[1] != 'N'))
213 {
214 ulog (LOG_ERROR, "Bad response to send request");
215 (void) ffileclose (e);
216 return FALSE;
217 }
218
219 if (zrec[1] == 'N')
220 {
221 const char *zerr;
222 boolean fnever;
223
224 fnever = TRUE;
225 if (zrec[2] == '2')
226 zerr = "permission denied";
227 else if (zrec[2] == '4')
228 {
229 zerr = "remote cannot create work files";
230 fnever = FALSE;
231 }
232 else if (zrec[2] == '6')
233 {
234 zerr = "too large for receiver now";
235 fnever = FALSE;
236 }
237 else if (zrec[2] == '7')
238 {
239 /* The file is too large to ever send. */
240 zerr = "too large for receiver";
241 }
242 else
243 {
244 char *zset;
245
246 zset = (char *) alloca (sizeof "unknown reason: "
247 + strlen (zrec));
248 sprintf (zset, "unknown reason: %s", zrec);
249 zerr = zset;
250 }
251
252 ulog (LOG_ERROR, "Can't send %s: %s", qcmd->zfrom, zerr);
253 (void) ffileclose (e);
254 if (fnever)
255 {
256 (void) fmail_transfer (FALSE, qcmd->zuser, zmail, zerr,
257 qcmd->zfrom, zLocalname,
258 qcmd->zto, ztosys,
259 zsysdep_save_temp_file (qcmd->pseq));
260 (void) fsysdep_did_work (qcmd->pseq);
261 }
262 return TRUE;
263 }
264 }
265 else
266 {
267 char absend[20];
268
269 /* We are the slave; confirm that we will send the file. We
270 send the file mode in the confirmation string. */
271
272 sprintf (absend, "RY 0%o", qcmd->imode);
273
274 if (! (qProto->pfsendcmd) (absend))
275 {
276 (void) ffileclose (e);
277 return FALSE;
278 }
279 }
280
281 /* Record the file we are sending, and let the protocol take over. */
282
283 if (! fstore_sendfile (e, qcmd->pseq, qcmd->zfrom, qcmd->zto, ztosys,
284 qcmd->zuser, zmail))
285 return FALSE;
286
287 cPsent_bytes = 0;
288
289 /* Tell the protocol that we are starting to send a file. */
290 if (qProto->pffile != NULL)
291 {
292 boolean (*pffile) P((boolean, boolean, boolean *, long));
293
294 /* Simplify expression for ancient compilers. */
295 pffile = qProto->pffile;
296 if (! pffile (TRUE, TRUE, (boolean *) NULL, qcmd->cbytes))
297 return FALSE;
298 }
299
300 return fploop ();
301 }
302
303 /* Confirm that a file has been received correctly by the other side.
304 Return FALSE for a communication error. We expect the receiving
305 system to send back CY; if an error occurred while moving the
306 received file into its final location, the receiving system will
307 send back CN5. */
308
309 static boolean
fpsendfile_confirm()310 fpsendfile_confirm ()
311 {
312 const char *zrec;
313 long cbytes;
314 const char *zerr;
315
316 zrec = zgetcmd ();
317 if (zrec == NULL)
318 return FALSE;
319
320 cbytes = cPsent_bytes;
321 cPsent_bytes = -1;
322
323 if (zrec[0] != 'C'
324 || (zrec[1] != 'Y' && zrec[1] != 'N'))
325 {
326 zerr = "Bad confirmation for sent file";
327 ulog (LOG_ERROR, zerr);
328 (void) fsent_file (FALSE, cbytes, zerr, FALSE);
329 }
330 else if (zrec[1] == 'N')
331 {
332 if (zrec[2] == '5')
333 zerr = "File could not be stored in final location";
334 else
335 {
336 char *zset;
337
338 zset = (char *) alloca (sizeof "File send failed: " + strlen (zrec));
339 sprintf (zset, "File send failed: %s", zrec);
340 zerr = zset;
341 }
342 ulog (LOG_ERROR, zerr);
343 (void) fsent_file (FALSE, cbytes, zerr, TRUE);
344 }
345 else
346 (void) fsent_file (TRUE, cbytes, (const char *) NULL, FALSE);
347
348 return TRUE;
349 }
350
351 /* Receive a file. If we are the master, we must set up a file
352 request and wait for the other side to confirm it. If we are the
353 slave, we must confirm a request made by the other side. We then
354 start receiving the file.
355
356 This function must return FALSE if there is a communication error
357 and TRUE otherwise. We return TRUE even if the file transfer
358 fails. */
359
360 boolean
freceive_file(fmaster,e,qcmd,zmail,zfromsys,fnew)361 freceive_file (fmaster, e, qcmd, zmail, zfromsys, fnew)
362 boolean fmaster;
363 openfile_t e;
364 const struct scmd *qcmd;
365 const char *zmail;
366 const char *zfromsys;
367 boolean fnew;
368 {
369 unsigned int imode;
370
371 if (fmaster)
372 {
373 int clen;
374 char *zsend;
375 const char *zrec;
376
377 /* We send the string
378 R from to user options
379 We put a dash in front of options. If we are talking to a
380 counterpart, we also send the maximum size file we are
381 prepared to accept, as returned by esysdep_open_receive. */
382
383 clen = (strlen (qcmd->zfrom) + strlen (qcmd->zto)
384 + strlen (qcmd->zuser) + strlen (qcmd->zoptions) + 30);
385 zsend = (char *) alloca (clen);
386
387 if (! fnew)
388 sprintf (zsend, "R %s %s %s -%s", qcmd->zfrom, qcmd->zto,
389 qcmd->zuser, qcmd->zoptions);
390 else
391 sprintf (zsend, "R %s %s %s -%s %ld", qcmd->zfrom, qcmd->zto,
392 qcmd->zuser, qcmd->zoptions, qcmd->cbytes);
393
394 if (! (qProto->pfsendcmd) (zsend))
395 {
396 (void) ffileclose (e);
397 (void) remove (qcmd->ztemp);
398 return FALSE;
399 }
400
401 /* Wait for a reply. */
402
403 zrec = zgetcmd ();
404 if (zrec == NULL)
405 {
406 (void) ffileclose (e);
407 (void) remove (qcmd->ztemp);
408 return FALSE;
409 }
410
411 if (zrec[0] != 'R'
412 || (zrec[1] != 'Y' && zrec[1] != 'N'))
413 {
414 ulog (LOG_ERROR, "Bad response to receive request");
415 (void) ffileclose (e);
416 (void) remove (qcmd->ztemp);
417 return FALSE;
418 }
419
420 if (zrec[1] == 'N')
421 {
422 const char *zerr;
423
424 if (zrec[2] == '2')
425 zerr = "no such file";
426 else if (zrec[2] == '6')
427 {
428 /* We sent over the maximum file size we were prepared
429 to receive, and the remote system is telling us that
430 the file is larger than that. Try again later. It
431 would be better if we could know whether there will
432 ever be enough room. */
433 ulog (LOG_ERROR, "Can't receive %s: too large",
434 qcmd->zfrom);
435 (void) ffileclose (e);
436 (void) remove (qcmd->ztemp);
437 return TRUE;
438 }
439 else
440 {
441 char *zset;
442
443 zset = (char *) alloca (sizeof "unknown reason: "
444 + strlen (zrec));
445 sprintf (zset, "unknown reason: %s", zrec);
446 zerr = zset;
447 }
448 ulog (LOG_ERROR, "Can't receive %s: %s", qcmd->zfrom, zerr);
449 (void) ffileclose (e);
450 (void) remove (qcmd->ztemp);
451 (void) fmail_transfer (FALSE, qcmd->zuser, zmail, zerr,
452 qcmd->zfrom, zfromsys,
453 qcmd->zto, zLocalname,
454 (const char *) NULL);
455 (void) fsysdep_did_work (qcmd->pseq);
456 return TRUE;
457 }
458
459 /* The mode should have been sent as "RY 0%o". If it wasn't,
460 we use 0666. */
461 imode = (unsigned int) strtol (zrec + 2, (char **) NULL, 8);
462 if (imode == 0)
463 imode = 0666;
464 }
465 else
466 {
467 /* Tell the other system to go ahead and send. */
468
469 if (! (qProto->pfsendcmd) ("SY"))
470 {
471 (void) ffileclose (e);
472 (void) remove (qcmd->ztemp);
473 return FALSE;
474 }
475 imode = qcmd->imode;
476 }
477
478 if (! fstore_recfile (e, qcmd->pseq, qcmd->zfrom, qcmd->zto, zfromsys,
479 qcmd->zuser, imode, zmail, qcmd->ztemp))
480 return FALSE;
481
482 cPreceived_bytes = 0;
483
484 /* Tell the protocol that we are starting to receive a file. */
485 if (qProto->pffile != NULL)
486 {
487 boolean (*pffile) P((boolean, boolean, boolean *, long));
488
489 /* Simplify expression for ancient compilers. */
490 pffile = qProto->pffile;
491 if (! pffile (TRUE, FALSE, (boolean *) NULL, (long) -1))
492 return FALSE;
493 }
494
495 return fploop ();
496 }
497
498 /* Confirm that a file was received correctly. */
499
500 static boolean
fprecfile_confirm()501 fprecfile_confirm ()
502 {
503 long cbytes;
504
505 cbytes = cPreceived_bytes;
506 cPreceived_bytes = -1;
507
508 if (freceived_file (TRUE, cbytes, (const char *) NULL, FALSE))
509 return (qProto->pfsendcmd) ("CY");
510 else
511 return (qProto->pfsendcmd) ("CN5");
512 }
513
514 /* Send a transfer request. This is only called by the master. It
515 ignored the pseq entry in the scmd structure. */
516
517 boolean
fxcmd(qcmd,pfnever)518 fxcmd (qcmd, pfnever)
519 const struct scmd *qcmd;
520 boolean *pfnever;
521 {
522 int clen;
523 char *zsend;
524 const char *zrec;
525
526 *pfnever = FALSE;
527
528 /* We send the string
529 X from to user options
530 We put a dash in front of options. */
531
532 clen = (strlen (qcmd->zfrom) + strlen (qcmd->zto)
533 + strlen (qcmd->zuser) + strlen (qcmd->zoptions) + 7);
534 zsend = (char *) alloca (clen);
535
536 sprintf (zsend, "X %s %s %s -%s", qcmd->zfrom, qcmd->zto,
537 qcmd->zuser, qcmd->zoptions);
538
539 if (! (qProto->pfsendcmd) (zsend))
540 return FALSE;
541
542 /* Wait for a reply. */
543
544 zrec = zgetcmd ();
545 if (zrec == NULL)
546 return FALSE;
547
548 if (zrec[0] != 'X'
549 || (zrec[1] != 'Y' && zrec[1] != 'N'))
550 {
551 ulog (LOG_ERROR, "Bad response to wildcard request");
552 return FALSE;
553 }
554
555 if (zrec[1] == 'N')
556 {
557 ulog (LOG_ERROR, "Work request denied");
558 *pfnever = TRUE;
559 return TRUE;
560 }
561
562 return TRUE;
563 }
564
565 /* Confirm a transfer request. */
566
567 boolean
fxcmd_confirm()568 fxcmd_confirm ()
569 {
570 return (qProto->pfsendcmd) ("XY");
571 }
572
573 /* Signal a file transfer failure to the other side. This is only called
574 by the slave. */
575
576 boolean
ftransfer_fail(bcmd,twhy)577 ftransfer_fail (bcmd, twhy)
578 int bcmd;
579 enum tfailure twhy;
580 {
581 const char *z;
582
583 switch (bcmd)
584 {
585 case 'S':
586 switch (twhy)
587 {
588 case FAILURE_PERM:
589 z = "SN2";
590 break;
591 case FAILURE_OPEN:
592 z = "SN4";
593 break;
594 case FAILURE_SIZE:
595 z = "SN6";
596 break;
597 default:
598 z = "SN";
599 break;
600 }
601 break;
602 case 'R':
603 switch (twhy)
604 {
605 case FAILURE_PERM:
606 case FAILURE_OPEN:
607 z = "RN2";
608 break;
609 case FAILURE_SIZE:
610 z = "RN6";
611 break;
612 default:
613 z = "RN";
614 break;
615 }
616 break;
617 case 'X':
618 z = "XN";
619 break;
620 default:
621 #if DEBUG > 0
622 ulog (LOG_ERROR, "ftransfer_fail: Can't happen");
623 #endif
624 return FALSE;
625 }
626
627 return (qProto->pfsendcmd) (z);
628 }
629
630 /* Get and parse a command from the other system. Handle hangups
631 specially. */
632
633 boolean
fgetcmd(fmaster,qcmd)634 fgetcmd (fmaster, qcmd)
635 boolean fmaster;
636 struct scmd *qcmd;
637 {
638 static char *z;
639 static int c;
640
641 while (TRUE)
642 {
643 const char *zcmd;
644 int clen;
645
646 zcmd = zgetcmd ();
647 if (zcmd == NULL)
648 return FALSE;
649
650 clen = strlen (zcmd);
651 if (clen + 1 > c)
652 {
653 c = clen + 1;
654 z = (char *) xrealloc ((pointer) z, c);
655 }
656 strcpy (z, zcmd);
657
658 if (! fparse_cmd (z, qcmd))
659 continue;
660
661 /* Handle hangup commands specially. If it's just 'H', return
662 it. If it's 'N', the other side is denying a hangup request
663 which we can just ignore (since the top level code assumes
664 that hangup requests are denied). If it's 'Y', the other
665 side is confirming a hangup request. In this case we confirm
666 with an "HY", wait for yet another "HY" from the other side,
667 and then finally shut down the protocol (I don't know why it
668 works this way, but it does). We then return a 'Y' command
669 to the top level code. */
670
671 if (qcmd->bcmd == 'N')
672 {
673 #if DEBUG > 0
674 if (fmaster)
675 ulog (LOG_ERROR, "Got hangup reply as master");
676 #endif
677 continue;
678 }
679
680 if (qcmd->bcmd == 'Y')
681 {
682 #if DEBUG > 0
683 if (fmaster)
684 ulog (LOG_ERROR, "Got hangup reply as master");
685 #endif
686 /* Don't check errors rigorously here, since the other side
687 might jump the gun and hang up. */
688
689 if (! (qProto->pfsendcmd) ("HY"))
690 return TRUE;
691 fPerror_ok = TRUE;
692 zcmd = zgetcmd ();
693 fPerror_ok = FALSE;
694 if (zcmd == NULL)
695 return TRUE;
696 #if DEBUG > 1
697 if (strcmp (zcmd, "HY") != 0)
698 DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO | DEBUG_ABNORMAL,
699 "fgetcmd: Got \"%s\" when expecting \"HY\"",
700 zcmd);
701 #endif
702 (void) (qProto->pfshutdown) ();
703 return TRUE;
704 }
705
706 return TRUE;
707 }
708
709 /*NOTREACHED*/
710 }
711
712 /* Hangup. */
713
714 boolean
fhangup_request()715 fhangup_request ()
716 {
717 return (qProto->pfsendcmd) ("H");
718 }
719
720 /* Reply to a hangup request. This is only called by the slave. If
721 fconfirm is TRUE, we are closing down the protocol. We send an HY
722 message. The master responds with an HY message. We send another
723 HY message, and then shut down the protocol. */
724
725 boolean
fhangup_reply(fconfirm)726 fhangup_reply (fconfirm)
727 boolean fconfirm;
728 {
729 if (! fconfirm)
730 return (qProto->pfsendcmd) ("HN");
731 else
732 {
733 const char *z;
734
735 if (! (qProto->pfsendcmd) ("HY"))
736 return FALSE;
737
738 z = zgetcmd ();
739 if (z == NULL)
740 return FALSE;
741 if (strcmp (z, "HY") != 0)
742 ulog (LOG_ERROR, "Got \"%s\" when expecting \"HY\"", z);
743 else
744 {
745 if (! (qProto->pfsendcmd) ("HY"))
746 return FALSE;
747 }
748
749 return (qProto->pfshutdown) ();
750 }
751 }
752
753 /* Loop sending and/or receiving data. If there is a file to send,
754 this will send it until the entire file has been sent or a command
755 has been received from the remote system or a complete file has
756 been received from the remote system. Otherwise this will simply
757 call the protocol to wait until a complete file or command has been
758 received from the remote system. */
759
760 static boolean
fploop()761 fploop ()
762 {
763 boolean fexit;
764
765 DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "fploop: Main protocol loop");
766
767 if (ffileisopen (eSendfile))
768 {
769 int iend;
770
771 iend = iPrecend;
772
773 while (TRUE)
774 {
775 /* We keep sending out packets until we have something
776 in the receive buffer. */
777 while (iend == iPrecend)
778 {
779 char *zdata;
780 int cdata;
781
782 /* Get a packet and fill it with data. */
783
784 zdata = (qProto->pzgetspace) (&cdata);
785 if (zdata == NULL)
786 return FALSE;
787
788 if (ffileeof (eSendfile))
789 cdata = 0;
790 else
791 {
792 cdata = cfileread (eSendfile, zdata, cdata);
793 if (ffilereaderror (eSendfile, cdata))
794 {
795 /* The protocol gives us no way to report a file
796 sending error, so we just drop the connection.
797 What else can we do? */
798 ulog (LOG_ERROR, "read: %s", strerror (errno));
799 usendfile_error ();
800 return FALSE;
801 }
802 }
803
804 if (! (qProto->pfsenddata) (zdata, cdata))
805 return FALSE;
806
807 cPsent_bytes += cdata;
808
809 /* If we have reached the end of the file, tell the
810 protocol that the file is finished (the protocol
811 could also detect this by looking for zero passed as
812 the data length to the send data routine, but would
813 have no convenient way to tell us to redo the file
814 send). If we are not supposed to redo the file
815 transfer, wait for confirmation and return out to get
816 the next file. */
817
818 if (cdata == 0)
819 {
820 if (qProto->pffile != NULL)
821 {
822 boolean fredo;
823 boolean (*pffile) P((boolean, boolean, boolean *,
824 long));
825
826 /* Simplify expression for ancient compilers. */
827 pffile = qProto->pffile;
828 if (! pffile (FALSE, TRUE, &fredo, (long) -1))
829 return FALSE;
830
831 if (fredo)
832 {
833 ulog (LOG_NORMAL, "Resending file");
834 if (! ffilerewind (eSendfile))
835 {
836 ulog (LOG_ERROR, "rewind: %s",
837 strerror (errno));
838 usendfile_error ();
839 return FALSE;
840 }
841 continue;
842 }
843 }
844
845 return fpsendfile_confirm ();
846 }
847 }
848
849 /* Process the data in the receive buffer, and decide
850 whether it's time to get out. */
851 if (! (qProto->pfprocess) (&fexit))
852 return FALSE;
853 if (fexit)
854 return TRUE;
855
856 iend = iPrecend;
857 }
858 }
859
860 #if DEBUG > 0
861 /* If there is no file to send, there really should be a file to
862 receive. */
863
864 if (! ffileisopen(eRecfile))
865 ulog (LOG_FATAL, "fploop: No send or receive file");
866 #endif
867
868 /* We have no file to send. Wait for data to come in. */
869
870 return (qProto->pfwait) ();
871 }
872
873 /* This function is called by the protocol routines when data has
874 arrived. Some protocols may know whether the data is for a command
875 or a file; for others, if a receive file is open it is for the file
876 and is otherwise for a command. This function will set *pfexit to
877 TRUE if it has received a complete file (assumed to be true if
878 cdata is zero) or a complete command (assumed to be true if the
879 argument data contains a null byte). It will return FALSE on
880 error. */
881
882 boolean
fgot_data(zdata,cdata,fcmd,ffile,pfexit)883 fgot_data (zdata, cdata, fcmd, ffile, pfexit)
884 const char *zdata;
885 int cdata;
886 boolean fcmd;
887 boolean ffile;
888 boolean *pfexit;
889 {
890 *pfexit = FALSE;
891
892 if (! fcmd && ! ffile)
893 {
894 if (ffileisopen (eRecfile))
895 ffile = TRUE;
896 else
897 fcmd = TRUE;
898 }
899
900 #if DEBUG > 0
901 if (ffile && ! ffileisopen (eRecfile))
902 ulog (LOG_FATAL, "fgot_data: No file to receive into");
903 #endif
904
905 if (ffile)
906 {
907 if (cdata == 0)
908 {
909 /* The file transfer is complete. If the protocol has a
910 file level routine, call it to see whether we have to
911 receive the file again. */
912 if (qProto->pffile != NULL)
913 {
914 boolean fredo;
915 boolean (*pffile) P((boolean, boolean, boolean *, long));
916
917 /* Simplify expression for ancient compilers. */
918 pffile = qProto->pffile;
919 if (! pffile (FALSE, FALSE, &fredo, (long) -1))
920 return FALSE;
921
922 if (fredo)
923 {
924 ulog (LOG_NORMAL, "File being resent");
925 if (! frecfile_rewind ())
926 return FALSE;
927 return TRUE;
928 }
929 }
930
931 if (! fprecfile_confirm ())
932 return FALSE;
933 *pfexit = TRUE;
934 return TRUE;
935 }
936 else
937 {
938 int cwrote;
939
940 /* Cast zdata to avoid warnings because of erroneous
941 prototypes on Ultrix. */
942 cwrote = cfilewrite (eRecfile, (char *) zdata, cdata);
943 if (cwrote != cdata)
944 {
945 const char *zerr;
946
947 if (cwrote < 0)
948 zerr = strerror (errno);
949 else
950 zerr = "could not write all data";
951 ulog (LOG_ERROR, "write: %s", zerr);
952 urecfile_error ();
953
954 /* Any write error is almost certainly a temporary
955 condition, or else UUCP would not be functioning at
956 all. If we continue to accept the file, we will wind
957 up rejecting it at the end (what else could we do?)
958 and the remote system will throw away the request.
959 We're better off just dropping the connection, which
960 is what happens when we return FALSE, and trying
961 again later. */
962 return FALSE;
963 }
964
965 cPreceived_bytes += cdata;
966
967 return TRUE;
968 }
969 }
970 else
971 {
972 const char *z;
973
974 /* We want to add this data to the current command string. If
975 there is no null character in the data, this string will be
976 continued by the next packet. Otherwise this must be the
977 last string in the command, and we don't care about what
978 comes after the null byte. */
979
980 z = (const char *) memchr ((constpointer) zdata, '\0', cdata);
981 if (z == NULL)
982 upadd_cmd (zdata, cdata, FALSE);
983 else
984 {
985 upadd_cmd (zdata, z - zdata, TRUE);
986 *pfexit = TRUE;
987 }
988
989 return TRUE;
990 }
991 }
992
993 /* This function is called by fgot_data when a command string is
994 received. We must queue up received commands since we don't know
995 when we'll be able to get to them (for example, the
996 acknowledgements for the last few packets of a sent file may
997 contain the string indicating whether the file was received
998 correctly). */
999
1000 struct spcmdqueue
1001 {
1002 struct spcmdqueue *qnext;
1003 int csize;
1004 int clen;
1005 char *z;
1006 };
1007
1008 static struct spcmdqueue *qPcmd_queue;
1009 static struct spcmdqueue *qPcmd_free;
1010
1011 static void
upadd_cmd(z,clen,flast)1012 upadd_cmd (z, clen, flast)
1013 const char *z;
1014 int clen;
1015 boolean flast;
1016 {
1017 struct spcmdqueue *q;
1018
1019 q = qPcmd_free;
1020 if (q == NULL)
1021 {
1022 q = (struct spcmdqueue *) xmalloc (sizeof (struct spcmdqueue));
1023 q->qnext = NULL;
1024 q->csize = 0;
1025 q->clen = 0;
1026 q->z = NULL;
1027 qPcmd_free = q;
1028 }
1029
1030 if (q->clen + clen + 1 > q->csize)
1031 {
1032 q->csize = q->clen + clen + 1;
1033 q->z = (char *) xrealloc ((pointer) q->z, q->csize);
1034 }
1035
1036 memcpy (q->z + q->clen, z, clen);
1037 q->clen += clen;
1038 q->z[q->clen] = '\0';
1039
1040 /* If the last string in this command, add it to the queue of
1041 finished commands. */
1042
1043 if (flast)
1044 {
1045 struct spcmdqueue **pq;
1046
1047 for (pq = &qPcmd_queue; *pq != NULL; pq = &(*pq)->qnext)
1048 ;
1049 *pq = q;
1050 qPcmd_free = q->qnext;
1051 q->qnext = NULL;
1052 }
1053 }
1054
1055 /* Get a command string. We just have to wait until the receive
1056 packet function gives us something in qPcmd_queue. The return
1057 value of this may be treated as a static buffer; it will last
1058 at least until the next packet is received. */
1059
1060 const char *
zgetcmd()1061 zgetcmd ()
1062 {
1063 struct spcmdqueue *q;
1064
1065 /* Wait until a command comes in. */
1066 while (qPcmd_queue == NULL)
1067 {
1068 DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "zgetcmd: Waiting for packet");
1069
1070 if (! (qProto->pfwait) ())
1071 return NULL;
1072 }
1073
1074 q = qPcmd_queue;
1075 qPcmd_queue = q->qnext;
1076
1077 q->clen = 0;
1078
1079 /* We must not replace qPcmd_free, because it may already be
1080 receiving a new command string. */
1081 if (qPcmd_free == NULL)
1082 {
1083 q->qnext = NULL;
1084 qPcmd_free = q;
1085 }
1086 else
1087 {
1088 q->qnext = qPcmd_free->qnext;
1089 qPcmd_free->qnext = q;
1090 }
1091
1092 DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "zgetcmd: Got command \"%s\"", q->z);
1093
1094 return q->z;
1095 }
1096
1097 /* We want to output and input at the same time, if supported on this
1098 machine. If we have something to send, we send it all while
1099 accepting a large amount of data. Once we have sent everything we
1100 look at whatever we have received. If data comes in faster than we
1101 can send it, we may run out of buffer space. */
1102
1103 boolean
fsend_data(zsend,csend,fdoread)1104 fsend_data (zsend, csend, fdoread)
1105 const char *zsend;
1106 int csend;
1107 boolean fdoread;
1108 {
1109 if (! fdoread)
1110 return fport_write (zsend, csend);
1111
1112 while (csend > 0)
1113 {
1114 char *zrec;
1115 int crec, csent;
1116
1117 if (iPrecend < iPrecstart)
1118 {
1119 zrec = abPrecbuf + iPrecend;
1120 crec = iPrecstart - iPrecend - 1;
1121 }
1122 else if (iPrecend < CRECBUFLEN)
1123 {
1124 zrec = abPrecbuf + iPrecend;
1125 crec = CRECBUFLEN - iPrecend;
1126 }
1127 else
1128 {
1129 zrec = abPrecbuf;
1130 crec = iPrecstart - 1;
1131 }
1132
1133 csent = csend;
1134
1135 if (! fport_io (zsend, &csent, zrec, &crec))
1136 return FALSE;
1137
1138 csend -= csent;
1139 zsend += csent;
1140
1141 iPrecend = (iPrecend + crec) % CRECBUFLEN;
1142 }
1143
1144 return TRUE;
1145 }
1146
1147 /* Read data from the other system when we have nothing to send. The
1148 argument cneed is the amount of data the caller wants, and ctimeout
1149 is the timeout in seconds. The function sets *pcrec to the amount
1150 of data which was actually received, which may be less than cneed
1151 if there isn't enough room in the receive buffer. If no data is
1152 received before the timeout expires, *pcrec will be returned as 0.
1153 If an error occurs, the function returns FALSE. If the freport
1154 argument is FALSE, no error should be reported. */
1155
1156 boolean
freceive_data(cneed,pcrec,ctimeout,freport)1157 freceive_data (cneed, pcrec, ctimeout, freport)
1158 int cneed;
1159 int *pcrec;
1160 int ctimeout;
1161 boolean freport;
1162 {
1163 /* Set *pcrec to the maximum amount of data we can read. fport_read
1164 expects *pcrec to be the buffer size, and sets it to the amount
1165 actually received. */
1166 if (iPrecend < iPrecstart)
1167 *pcrec = iPrecstart - iPrecend - 1;
1168 else
1169 {
1170 *pcrec = CRECBUFLEN - iPrecend;
1171 if (iPrecstart == 0)
1172 --(*pcrec);
1173 }
1174
1175 #if DEBUG > 0
1176 /* If we have no room in the buffer, we're in trouble. The
1177 protocols must be written to ensure that this can't happen. */
1178 if (*pcrec == 0)
1179 ulog (LOG_FATAL, "freceive_data: No room in buffer");
1180 #endif
1181
1182 /* If we don't have room for all the data the caller wants, we
1183 simply have to expect less. We'll get the rest later. */
1184 if (*pcrec < cneed)
1185 cneed = *pcrec;
1186
1187 if (! fport_read (abPrecbuf + iPrecend, pcrec, cneed, ctimeout, freport))
1188 return FALSE;
1189
1190 iPrecend = (iPrecend + *pcrec) % CRECBUFLEN;
1191
1192 return TRUE;
1193 }
1194
1195 /* Read a single character. Get it out of the receive buffer if it's
1196 there, otherwise ask freceive_data for at least one character.
1197 This is used because as a protocol is shutting down freceive_data
1198 may read ahead and eat characters that should be read outside the
1199 protocol routines. We call freceive_data rather than fport_read
1200 with an argument of 1 so that we can get all the available data in
1201 a single system call. The ctimeout argument is the timeout in
1202 seconds; the freport argument is FALSE if no error should be
1203 reported. This returns a character, or -1 on timeout or -2 on
1204 error. */
1205
1206 int
breceive_char(ctimeout,freport)1207 breceive_char (ctimeout, freport)
1208 int ctimeout;
1209 boolean freport;
1210 {
1211 char b;
1212
1213 if (iPrecstart == iPrecend)
1214 {
1215 int crec;
1216
1217 if (! freceive_data (1, &crec, ctimeout, freport))
1218 return -2;
1219 if (crec == 0)
1220 return -1;
1221 }
1222
1223 b = abPrecbuf[iPrecstart];
1224 iPrecstart = (iPrecstart + 1) % CRECBUFLEN;
1225 return BUCHAR (b);
1226 }
1227
1228 /* This routine is called when an error occurred and we are crashing
1229 out of the connection. It is only used to report statistics on
1230 failed transfers to the statistics file. Note that the number of
1231 bytes we report as having been sent has little or nothing to do
1232 with the number of bytes the remote site actually received. */
1233
1234 void
ustats_failed()1235 ustats_failed ()
1236 {
1237 long cbytes;
1238
1239 if (cPsent_bytes != -1)
1240 {
1241 cbytes = cPsent_bytes;
1242 cPsent_bytes = -1;
1243 (void) fsent_file (FALSE, cbytes, "connection failure", FALSE);
1244 }
1245
1246 if (cPreceived_bytes != -1)
1247 {
1248 cbytes = cPreceived_bytes;
1249 cPreceived_bytes = -1;
1250 (void) freceived_file (FALSE, cbytes, "connection failure", FALSE);
1251 }
1252 }
1253