Upgrade to version 1.05
[unix-history] / gnu / libexec / uucp / uucico / rec.c
CommitLineData
41c799d4
C
1/* rec.c
2 Routines to receive a file.
3
3469b437 4 Copyright (C) 1991, 1992, 1993, 1994 Ian Lance Taylor
41c799d4
C
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
3469b437 23 c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
41c799d4
C
24 */
25
26#include "uucp.h"
27
28#if USE_RCS_ID
3469b437 29const char rec_rcsid[] = "$Id: rec.c,v 1.34 1994/04/04 03:25:12 ian Rel $";
41c799d4
C
30#endif
31
32#include <errno.h>
33
34#include "uudefs.h"
35#include "uuconf.h"
36#include "system.h"
37#include "prot.h"
38#include "trans.h"
39\f
40/* If the other side does not tell us the size of a file it wants to
41 send us, we assume it is this long. This is only used for free
42 space checking. */
43#define CASSUMED_FILE_SIZE (10240)
44
45/* We keep this information in the pinfo field of the stransfer
46 structure. */
47struct srecinfo
48{
49 /* Local user to send mail to (may be NULL). */
50 char *zmail;
51 /* Full file name. */
52 char *zfile;
53 /* Temporary file name. */
54 char *ztemp;
55 /* TRUE if this is a spool directory file. */
56 boolean fspool;
57 /* TRUE if this was a local request. */
58 boolean flocal;
59 /* TRUE if the file has been completely received. */
60 boolean freceived;
61 /* TRUE if remote request has been replied to. */
62 boolean freplied;
63 /* TRUE if we moved the file to the final destination. */
64 boolean fmoved;
65};
66
67/* This structure is kept in the pinfo field if we are refusing a
68 remote request. */
69struct srecfailinfo
70{
71 /* Reason for refusal. */
72 enum tfailure twhy;
73 /* TRUE if we have sent the reason for refusal. */
74 boolean fsent;
75 /* TRUE if we have seen the end of the file. */
76 boolean freceived;
77};
78\f
79/* Local functions. */
80
81static void urrec_free P((struct stransfer *qtrans));
82static boolean flocal_rec_fail P((struct stransfer *qtrans,
83 struct scmd *qcmd,
84 const struct uuconf_system *qsys,
85 const char *zwhy));
86static boolean flocal_rec_send_request P((struct stransfer *qtrans,
87 struct sdaemon *qdaemon));
88static boolean flocal_rec_await_reply P((struct stransfer *qtrans,
89 struct sdaemon *qdaemon,
90 const char *zdata,
91 size_t cdata));
92static boolean fremote_send_reply P((struct stransfer *qtrans,
93 struct sdaemon *qdaemon));
94static boolean fremote_send_fail P((struct sdaemon *qdaemon,
95 struct scmd *qcmd,
96 enum tfailure twhy,
97 int iremote));
98static boolean fremote_send_fail_send P((struct stransfer *qtrans,
99 struct sdaemon *qdaemon));
100static boolean fremote_discard P((struct stransfer *qtrans,
101 struct sdaemon *qdaemon,
102 const char *zdata, size_t cdata));
103static boolean frec_file_end P((struct stransfer *qtrans,
104 struct sdaemon *qdaemon,
105 const char *zdata, size_t cdata));
106static boolean frec_file_send_confirm P((struct stransfer *qtrans,
107 struct sdaemon *qdaemon));
108\f
109/* Free up a receive stransfer structure. */
110
111static void
112urrec_free (qtrans)
113 struct stransfer *qtrans;
114{
115 struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
116
117 if (qinfo != NULL)
118 {
119 ubuffree (qinfo->zmail);
120 ubuffree (qinfo->zfile);
121 ubuffree (qinfo->ztemp);
122 xfree (qtrans->pinfo);
123 }
124
125 utransfree (qtrans);
126}
127\f
128/* Set up a request for a file from the remote system. This may be
129 called before the remote system has been called.
130
131 This is the order of function calls:
132
133 flocal_rec_file_init --> fqueue_local
134 flocal_rec_send_request (send R ...) --> fqueue_receive
135 flocal_rec_await_reply (open file, call pffile) --> fqueue_receive
136 receive file
137 frec_file_end (close and move file, call pffile) --> fqueue_send
138 frec_file_send_confirm (send CY)
139 */
140
141boolean
142flocal_rec_file_init (qdaemon, qcmd)
143 struct sdaemon *qdaemon;
144 struct scmd *qcmd;
145{
146 const struct uuconf_system *qsys;
147 boolean fspool;
148 char *zfile;
149 struct srecinfo *qinfo;
150 struct stransfer *qtrans;
151
152 qsys = qdaemon->qsys;
153
154 /* Make sure we are permitted to transfer files. */
155 if (qdaemon->fcaller
156 ? ! qsys->uuconf_fcall_transfer
157 : ! qsys->uuconf_fcalled_transfer)
158 {
159 /* This case will have been checked by uucp or uux, but it could
160 have changed. */
161 if (! qsys->uuconf_fcall_transfer
162 && ! qsys->uuconf_fcalled_transfer)
163 return flocal_rec_fail ((struct stransfer *) NULL, qcmd, qsys,
164 "not permitted to request files");
165 return TRUE;
166 }
167
168 fspool = fspool_file (qcmd->zto);
169
170 if (fspool)
171 {
172 pointer puuconf;
173 int iuuconf;
174 const char *zlocalname;
175 struct uuconf_system slocalsys;
176
177 /* Normal users are not allowed to request files to be received
178 into the spool directory. To support uux forwarding, we use
179 the special option '9'. This permits a file to be received
180 into the spool directory for the local system only without
181 the usual checking. This is only done for local requests, of
182 course. */
183 if (qcmd->zto[0] != 'D'
184 || strchr (qcmd->zoptions, '9') == NULL)
185 return flocal_rec_fail ((struct stransfer *) NULL, qcmd, qsys,
186 "not permitted to receive");
187
188 puuconf = qdaemon->puuconf;
189 iuuconf = uuconf_localname (puuconf, &zlocalname);
190 if (iuuconf == UUCONF_NOT_FOUND)
191 {
192 zlocalname = zsysdep_localname ();
193 if (zlocalname == NULL)
194 return FALSE;
195 }
196 else if (iuuconf != UUCONF_SUCCESS)
197 {
198 ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
199 return FALSE;
200 }
201
202 iuuconf = uuconf_system_info (puuconf, zlocalname, &slocalsys);
203 if (iuuconf == UUCONF_NOT_FOUND)
204 {
205 iuuconf = uuconf_system_local (puuconf, &slocalsys);
206 if (iuuconf != UUCONF_SUCCESS)
207 {
208 ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
209 return FALSE;
210 }
211 }
212 else if (iuuconf != UUCONF_SUCCESS)
213 {
214 ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
215 return FALSE;
216 }
217
218 zfile = zsysdep_spool_file_name (&slocalsys, qcmd->zto, qcmd->pseq);
219
220 (void) uuconf_system_free (puuconf, &slocalsys);
221
222 if (zfile == NULL)
223 return FALSE;
224 }
225 else
226 {
227 zfile = zsysdep_add_base (qcmd->zto, qcmd->zfrom);
228 if (zfile == NULL)
229 return FALSE;
230
231 /* Check permissions. */
232 if (! fin_directory_list (zfile, qsys->uuconf_pzlocal_receive,
233 qsys->uuconf_zpubdir, TRUE,
234 FALSE, qcmd->zuser))
235 {
236 ubuffree (zfile);
237 return flocal_rec_fail ((struct stransfer *) NULL, qcmd, qsys,
238 "not permitted to receive");
239 }
240
241 /* The 'f' option means that directories should not
242 be created if they do not already exist. */
243 if (strchr (qcmd->zoptions, 'f') == NULL)
244 {
245 if (! fsysdep_make_dirs (zfile, TRUE))
246 {
247 ubuffree (zfile);
248 return flocal_rec_fail ((struct stransfer *) NULL, qcmd,
249 qsys, "cannot create directories");
250 }
251 }
252 }
253
254 qinfo = (struct srecinfo *) xmalloc (sizeof (struct srecinfo));
255 if (strchr (qcmd->zoptions, 'm') == NULL)
256 qinfo->zmail = NULL;
257 else
258 qinfo->zmail = zbufcpy (qcmd->zuser);
259 qinfo->zfile = zfile;
260 qinfo->ztemp = NULL;
261 qinfo->fspool = fspool;
262 qinfo->flocal = TRUE;
263 qinfo->freceived = FALSE;
264 qinfo->freplied = TRUE;
265
266 qtrans = qtransalc (qcmd);
267 qtrans->psendfn = flocal_rec_send_request;
268 qtrans->pinfo = (pointer) qinfo;
269
270 return fqueue_local (qdaemon, qtrans);
271}
272
273/* Report an error for a local receive request. */
274
275static boolean
276flocal_rec_fail (qtrans, qcmd, qsys, zwhy)
277 struct stransfer *qtrans;
278 struct scmd *qcmd;
279 const struct uuconf_system *qsys;
280 const char *zwhy;
281{
282 if (zwhy != NULL)
283 {
284 ulog (LOG_ERROR, "%s: %s", qcmd->zfrom, zwhy);
285 (void) fmail_transfer (FALSE, qcmd->zuser, (const char *) NULL, zwhy,
286 qcmd->zfrom, qsys->uuconf_zname,
287 qcmd->zto, (const char *) NULL,
288 (const char *) NULL);
289 (void) fsysdep_did_work (qcmd->pseq);
290 }
291 if (qtrans != NULL)
292 urrec_free (qtrans);
293 return TRUE;
294}
295
296/* This is called when we are ready to send the actual request to the
297 other system. */
298
299static boolean
300flocal_rec_send_request (qtrans, qdaemon)
301 struct stransfer *qtrans;
302 struct sdaemon *qdaemon;
303{
304 struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
305 long cbytes, cbytes2;
306 size_t clen;
307 char *zsend;
308 boolean fret;
309
310 qinfo->ztemp = zsysdep_receive_temp (qdaemon->qsys, qinfo->zfile,
3469b437
AC
311 (const char *) NULL,
312 (qdaemon->qproto->frestart
313 && (qdaemon->ifeatures
314 & FEATURE_RESTART) != 0));
41c799d4
C
315 if (qinfo->ztemp == NULL)
316 {
317 urrec_free (qtrans);
318 return FALSE;
319 }
320
3469b437
AC
321 qtrans->fcmd = TRUE;
322 qtrans->precfn = flocal_rec_await_reply;
323
324 if (! fqueue_receive (qdaemon, qtrans))
325 return FALSE;
326
41c799d4
C
327 /* Check the amount of free space available for both the temporary
328 file and the real file. */
329 cbytes = csysdep_bytes_free (qinfo->ztemp);
330 cbytes2 = csysdep_bytes_free (qinfo->zfile);
331 if (cbytes < cbytes2)
332 cbytes = cbytes2;
333 if (cbytes != -1)
334 {
335 cbytes -= qdaemon->qsys->uuconf_cfree_space;
336 if (cbytes < 0)
337 cbytes = 0;
338 }
339
340 if (qdaemon->clocal_size != -1
341 && (cbytes == -1 || qdaemon->clocal_size < cbytes))
342 cbytes = qdaemon->clocal_size;
343
344 /* We send the string
345 R from to user options
346
347 We put a dash in front of options. If we are talking to a
348 counterpart, we also send the maximum size file we are prepared
349 to accept, as returned by esysdep_open_receive. */
350 clen = (strlen (qtrans->s.zfrom) + strlen (qtrans->s.zto)
351 + strlen (qtrans->s.zuser) + strlen (qtrans->s.zoptions) + 30);
352 zsend = zbufalc (clen);
353 if ((qdaemon->ifeatures & FEATURE_SIZES) == 0)
354 sprintf (zsend, "R %s %s %s -%s", qtrans->s.zfrom, qtrans->s.zto,
355 qtrans->s.zuser, qtrans->s.zoptions);
356 else if ((qdaemon->ifeatures & FEATURE_V103) == 0)
357 sprintf (zsend, "R %s %s %s -%s 0x%lx", qtrans->s.zfrom, qtrans->s.zto,
358 qtrans->s.zuser, qtrans->s.zoptions, (unsigned long) cbytes);
359 else
360 sprintf (zsend, "R %s %s %s -%s %ld", qtrans->s.zfrom, qtrans->s.zto,
361 qtrans->s.zuser, qtrans->s.zoptions, cbytes);
362
363 fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, qtrans->ilocal,
364 qtrans->iremote);
365 ubuffree (zsend);
41c799d4 366
3469b437
AC
367 if (! fret)
368 urrec_free (qtrans);
41c799d4 369
3469b437 370 return fret;
41c799d4
C
371}
372
373/* This is called when a reply is received for the request. */
374
375/*ARGSUSED*/
376static boolean
377flocal_rec_await_reply (qtrans, qdaemon, zdata, cdata)
378 struct stransfer *qtrans;
379 struct sdaemon *qdaemon;
380 const char *zdata;
381 size_t cdata;
382{
383 struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
41c799d4 384 const char *zlog;
3469b437 385 char *zend;
41c799d4
C
386
387 if (zdata[0] != 'R'
388 || (zdata[1] != 'Y' && zdata[1] != 'N'))
389 {
390 ulog (LOG_ERROR, "%s: bad response to receive request: \"%s\"",
391 qtrans->s.zfrom, zdata);
392 urrec_free (qtrans);
393 return FALSE;
394 }
395
396 if (zdata[1] == 'N')
397 {
398 boolean fnever;
399 const char *zerr;
400
401 fnever = TRUE;
402 if (zdata[2] == '2')
403 zerr = "no such file";
404 else if (zdata[2] == '6')
405 {
406 /* We sent over the maximum file size we were prepared to
407 receive, and the remote system is telling us that the
408 file is larger than that. Try again later. It would be
409 better if we could know whether there will ever be enough
410 room. */
411 zerr = "too large to receive now";
412 fnever = FALSE;
413 }
3469b437
AC
414 else if (zdata[2] == '9')
415 {
416 /* Remote has run out of channels. */
417 zerr = "too many channels for remote";
418 fnever = FALSE;
419
420 /* Drop one channel; using exactly one channel causes
421 slightly different behahaviour in a few places, so don't
422 decrement to one. */
423 if (qdaemon->cchans > 2)
424 --qdaemon->cchans;
425 }
41c799d4
C
426 else
427 zerr = "unknown reason";
428
429 if (fnever)
430 return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys, zerr);
431
432 ulog (LOG_ERROR, "%s: %s", qtrans->s.zfrom, zerr);
433
434 urrec_free (qtrans);
435
436 return TRUE;
437 }
438
439 /* The mode should have been sent as "RY 0%o". If it wasn't, we use
440 0666. */
441 qtrans->s.imode = (unsigned int) strtol ((char *) (zdata + 2),
3469b437 442 &zend, 8);
41c799d4
C
443 if (qtrans->s.imode == 0)
444 qtrans->s.imode = 0666;
445
3469b437
AC
446 /* If there is an M after the mode, the remote has requested a
447 hangup. */
448 if (*zend == 'M' && qdaemon->fmaster)
449 {
450 DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO,
451 "flocal_rec_await_reply: Remote has requested transfer of control");
452 qdaemon->fhangup_requested = TRUE;
453 }
454
41c799d4
C
455 /* Open the file to receive into. We just ignore any restart count,
456 since we have no way to tell it to the other side. SVR4 may have
457 some way to do this, but I don't know what it is. */
458 qtrans->e = esysdep_open_receive (qdaemon->qsys, qinfo->zfile,
459 (const char *) NULL, qinfo->ztemp,
3469b437 460 (long *) NULL);
41c799d4
C
461 if (! ffileisopen (qtrans->e))
462 return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys,
463 "cannot open file");
464
465 if (qinfo->fspool)
466 zlog = qtrans->s.zto;
467 else
468 zlog = qinfo->zfile;
469 qtrans->zlog = zbufalc (sizeof "Receiving " + strlen (zlog));
470 sprintf (qtrans->zlog, "Receiving %s", zlog);
471
472 if (qdaemon->qproto->pffile != NULL)
473 {
474 boolean fhandled;
475
476 if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, FALSE,
477 (long) -1, &fhandled))
478 {
479 (void) ffileclose (qtrans->e);
480 return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys,
481 (const char *) NULL);
482 }
483 if (fhandled)
484 return TRUE;
485 }
486
487 qtrans->frecfile = TRUE;
488 qtrans->psendfn = frec_file_send_confirm;
489 qtrans->precfn = frec_file_end;
490
491 return fqueue_receive (qdaemon, qtrans);
492}
493\f
494/* Make sure there is still enough disk space available to receive a
495 file. */
496
497boolean
498frec_check_free (qtrans, cfree_space)
499 struct stransfer *qtrans;
500 long cfree_space;
501{
502 struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
503 long cfree1, cfree2;
504
505 cfree1 = csysdep_bytes_free (qinfo->ztemp);
506 cfree2 = csysdep_bytes_free (qinfo->zfile);
507 if (cfree1 < cfree2)
508 cfree1 = cfree2;
509 if (cfree1 != -1 && cfree1 < cfree_space)
510 {
511 ulog (LOG_ERROR, "%s: too big to receive now", qinfo->zfile);
512 return FALSE;
513 }
514
515 return TRUE;
516}
517\f
518/* A remote request to send a file to the local system, meaning that
519 we are going to receive a file.
520
521 If we are using a protocol which does not support multiple
522 channels, the remote system will not start sending us the file
523 until it has received our confirmation. In that case, the order of
524 functions is as follows:
525
526 fremote_send_file_init (open file) --> fqueue_remote
527 fremote_send_reply (send SY, call pffile) --> fqueue_receive
528 receive file
529 frec_file_end (close and move file, call pffile) --> fqueue_send
530 frec_file_send_confirm (send CY)
531
532 If the protocol supports multiple channels, then the remote system
533 will start sending the file immediately after the send request.
534 That means that the data may come in before remote_send_reply is
535 called, so frec_file_end may be called before fremote_send_reply.
536 Note that this means the pffile entry points may be called in
537 reverse order for such a protocol.
538
539 If the send request is rejected, via fremote_send_fail, and the
540 protocol supports multiple channels, we must accept and discard
541 data until a zero byte buffer is received from the other side,
542 indicating that it has received our rejection.
543
544 This code also handles execution requests, which are very similar
545 to send requests. */
546
547boolean
548fremote_send_file_init (qdaemon, qcmd, iremote)
549 struct sdaemon *qdaemon;
550 struct scmd *qcmd;
551 int iremote;
552{
553 const struct uuconf_system *qsys;
554 boolean fspool;
555 char *zfile;
556 openfile_t e;
557 char *ztemp;
558 long cbytes, cbytes2;
559 long crestart;
560 struct srecinfo *qinfo;
561 struct stransfer *qtrans;
562 const char *zlog;
563
564 qsys = qdaemon->qsys;
565
566 if (! qsys->uuconf_frec_request)
567 {
568 ulog (LOG_ERROR, "%s: not permitted to receive files from remote",
569 qcmd->zfrom);
570 return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote);
571 }
572
573 fspool = fspool_file (qcmd->zto);
574
575 /* We don't accept remote command files. An execution request may
576 only send a simple data file. */
577 if ((fspool && qcmd->zto[0] == 'C')
578 || (qcmd->bcmd == 'E'
579 && (! fspool || qcmd->zto[0] != 'D')))
580 {
581 ulog (LOG_ERROR, "%s: not permitted to receive", qcmd->zfrom);
582 return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote);
583 }
584
585 /* See if we have already received this file in a previous
586 conversation. */
587 if (fsysdep_already_received (qsys, qcmd->zto, qcmd->ztemp))
588 return fremote_send_fail (qdaemon, qcmd, FAILURE_RECEIVED, iremote);
589
590 if (fspool)
591 {
592 zfile = zsysdep_spool_file_name (qsys, qcmd->zto, (pointer) NULL);
593 if (zfile == NULL)
594 return FALSE;
595 }
596 else
597 {
3469b437
AC
598 boolean fbadname;
599
600 zfile = zsysdep_local_file (qcmd->zto, qsys->uuconf_zpubdir,
601 &fbadname);
602 if (zfile == NULL && fbadname)
603 {
604 ulog (LOG_ERROR, "%s: bad local file name", qcmd->zto);
605 return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote);
606 }
41c799d4
C
607 if (zfile != NULL)
608 {
609 char *zadd;
610
611 zadd = zsysdep_add_base (zfile, qcmd->zfrom);
612 ubuffree (zfile);
613 zfile = zadd;
614 }
615 if (zfile == NULL)
616 return FALSE;
617
618 /* Check permissions. */
619 if (! fin_directory_list (zfile, qsys->uuconf_pzremote_receive,
620 qsys->uuconf_zpubdir, TRUE,
621 FALSE, (const char *) NULL))
622 {
623 ulog (LOG_ERROR, "%s: not permitted to receive", zfile);
624 ubuffree (zfile);
625 return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote);
626 }
627
628 if (strchr (qcmd->zoptions, 'f') == NULL)
629 {
630 if (! fsysdep_make_dirs (zfile, TRUE))
631 {
632 ubuffree (zfile);
633 return fremote_send_fail (qdaemon, qcmd, FAILURE_OPEN,
634 iremote);
635 }
636 }
637 }
638
3469b437
AC
639 ztemp = zsysdep_receive_temp (qsys, zfile, qcmd->ztemp,
640 (qdaemon->qproto->frestart
641 && (qdaemon->ifeatures
642 & FEATURE_RESTART) != 0));
41c799d4
C
643
644 /* Adjust the number of bytes we are prepared to receive according
645 to the amount of free space we are supposed to leave available
646 and the maximum file size we are permitted to transfer. */
647 cbytes = csysdep_bytes_free (ztemp);
648 cbytes2 = csysdep_bytes_free (zfile);
649 if (cbytes < cbytes2)
650 cbytes = cbytes2;
651
652 if (cbytes != -1)
653 {
654 cbytes -= qsys->uuconf_cfree_space;
655 if (cbytes < 0)
656 cbytes = 0;
657 }
658
659 if (qdaemon->cremote_size != -1
660 && (cbytes == -1 || qdaemon->cremote_size < cbytes))
661 cbytes = qdaemon->cremote_size;
662
663 /* If the number of bytes we are prepared to receive is less than
664 the file size, we must fail. If the remote did not tell us the
665 file size, arbitrarily assumed that it is 10240 bytes. */
666 if (cbytes != -1)
667 {
668 long csize;
669
670 csize = qcmd->cbytes;
671 if (csize == -1)
672 csize = CASSUMED_FILE_SIZE;
673 if (cbytes < csize)
674 {
675 ulog (LOG_ERROR, "%s: too big to receive", zfile);
676 ubuffree (ztemp);
677 ubuffree (zfile);
678 return fremote_send_fail (qdaemon, qcmd, FAILURE_SIZE, iremote);
679 }
680 }
681
682 /* Open the file to receive into. This may find an old copy of the
683 file, which will be used for file restart if the other side
684 supports it. */
3469b437
AC
685 crestart = -1;
686 e = esysdep_open_receive (qsys, zfile, qcmd->ztemp, ztemp,
687 ((qdaemon->qproto->frestart
688 && (qdaemon->ifeatures
689 & FEATURE_RESTART) != 0)
690 ? &crestart
691 : (long *) NULL));
41c799d4
C
692 if (! ffileisopen (e))
693 {
694 ubuffree (ztemp);
695 ubuffree (zfile);
696 return fremote_send_fail (qdaemon, qcmd, FAILURE_OPEN, iremote);
697 }
698
699 if (crestart > 0)
700 {
3469b437
AC
701 DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO,
702 "fremote_send_file_init: Restarting receive from %ld",
703 crestart);
704 if (! ffileseek (e, crestart))
41c799d4 705 {
3469b437
AC
706 ulog (LOG_ERROR, "seek: %s", strerror (errno));
707 (void) ffileclose (e);
708 ubuffree (ztemp);
709 ubuffree (zfile);
710 return FALSE;
41c799d4
C
711 }
712 }
713
714 qinfo = (struct srecinfo *) xmalloc (sizeof (struct srecinfo));
715 if (strchr (qcmd->zoptions, 'n') == NULL)
716 qinfo->zmail = NULL;
717 else
718 qinfo->zmail = zbufcpy (qcmd->znotify);
719 qinfo->zfile = zfile;
720 qinfo->ztemp = ztemp;
721 qinfo->fspool = fspool;
722 qinfo->flocal = FALSE;
723 qinfo->freceived = FALSE;
724 qinfo->freplied = FALSE;
725
726 qtrans = qtransalc (qcmd);
727 qtrans->psendfn = fremote_send_reply;
728 qtrans->precfn = frec_file_end;
729 qtrans->iremote = iremote;
730 qtrans->pinfo = (pointer) qinfo;
731 qtrans->frecfile = TRUE;
732 qtrans->e = e;
733 if (crestart > 0)
734 qtrans->ipos = crestart;
735
736 if (qcmd->bcmd == 'E')
737 zlog = qcmd->zcmd;
738 else
739 {
740 if (qinfo->fspool)
741 zlog = qcmd->zto;
742 else
743 zlog = qinfo->zfile;
744 }
3469b437
AC
745 qtrans->zlog = zbufalc (sizeof "Receiving ( bytes resume at )"
746 + strlen (zlog) + 50);
41c799d4 747 sprintf (qtrans->zlog, "Receiving %s", zlog);
3469b437
AC
748 if (crestart > 0 || qcmd->cbytes > 0)
749 {
750 strcat (qtrans->zlog, " (");
751 if (qcmd->cbytes > 0)
752 {
753 sprintf (qtrans->zlog + strlen (qtrans->zlog), "%ld bytes",
754 qcmd->cbytes);
755 if (crestart > 0)
756 strcat (qtrans->zlog, " ");
757 }
758 if (crestart > 0)
759 sprintf (qtrans->zlog + strlen (qtrans->zlog), "resume at %ld",
760 crestart);
761 strcat (qtrans->zlog, ")");
762 }
41c799d4
C
763
764 return fqueue_remote (qdaemon, qtrans);
765}
766
767/* Reply to a send request, and prepare to receive the file. */
768
769static boolean
770fremote_send_reply (qtrans, qdaemon)
771 struct stransfer *qtrans;
772 struct sdaemon *qdaemon;
773{
774 struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
3469b437 775 boolean fret;
41c799d4
C
776 char ab[50];
777
3469b437
AC
778 /* If the file has been completely received, we just want to send
779 the final confirmation. Otherwise, we must wait for the file
780 first. */
781 qtrans->psendfn = frec_file_send_confirm;
782 if (qinfo->freceived)
783 fret = fqueue_send (qdaemon, qtrans);
784 else
785 fret = fqueue_receive (qdaemon, qtrans);
786 if (! fret)
787 return FALSE;
788
41c799d4
C
789 ab[0] = qtrans->s.bcmd;
790 ab[1] = 'Y';
791 if (qtrans->ipos <= 0)
792 ab[2] = '\0';
793 else
794 sprintf (ab + 2, " 0x%lx", (unsigned long) qtrans->ipos);
795
796 if (! (*qdaemon->qproto->pfsendcmd) (qdaemon, ab, qtrans->ilocal,
797 qtrans->iremote))
798 {
799 (void) ffileclose (qtrans->e);
800 (void) remove (qinfo->ztemp);
801 urrec_free (qtrans);
802 return FALSE;
803 }
804
805 qinfo->freplied = TRUE;
806
807 if (qdaemon->qproto->pffile != NULL)
808 {
809 boolean fhandled;
810
811 if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, FALSE,
812 (long) -1, &fhandled))
813 {
814 (void) ffileclose (qtrans->e);
815 (void) remove (qinfo->ztemp);
816 urrec_free (qtrans);
817 return FALSE;
818 }
41c799d4
C
819 }
820
3469b437 821 return TRUE;
41c799d4
C
822}
823
824/* If we can't receive a file, queue up a response to the remote
825 system. */
826
827static boolean
828fremote_send_fail (qdaemon, qcmd, twhy, iremote)
829 struct sdaemon *qdaemon;
830 struct scmd *qcmd;
831 enum tfailure twhy;
832 int iremote;
833{
834 struct srecfailinfo *qinfo;
835 struct stransfer *qtrans;
836
837 qinfo = (struct srecfailinfo *) xmalloc (sizeof (struct srecfailinfo));
838 qinfo->twhy = twhy;
839 qinfo->fsent = FALSE;
840
841 /* If the protocol does not support multiple channels (cchans <= 1),
842 then we have essentially already received the entire file. */
3469b437 843 qinfo->freceived = qdaemon->cchans <= 1;
41c799d4
C
844
845 qtrans = qtransalc (qcmd);
846 qtrans->psendfn = fremote_send_fail_send;
847 qtrans->precfn = fremote_discard;
848 qtrans->iremote = iremote;
849 qtrans->pinfo = (pointer) qinfo;
850
851 return fqueue_remote (qdaemon, qtrans);
852}
853
854/* Send a failure string for a send command to the remote system;
855 this is called when we are ready to reply to the command. */
856
857static boolean
858fremote_send_fail_send (qtrans, qdaemon)
859 struct stransfer *qtrans;
860 struct sdaemon *qdaemon;
861{
862 struct srecfailinfo *qinfo = (struct srecfailinfo *) qtrans->pinfo;
863 char ab[4];
864 boolean fret;
865
3469b437
AC
866 /* Wait for the end of file marker if we haven't gotten it yet. */
867 if (! qinfo->freceived)
868 {
869 if (! fqueue_receive (qdaemon, qtrans))
870 return FALSE;
871 }
872
41c799d4
C
873 ab[0] = qtrans->s.bcmd;
874 ab[1] = 'N';
875
876 switch (qinfo->twhy)
877 {
878 case FAILURE_PERM:
879 ab[2] = '2';
880 break;
881 case FAILURE_OPEN:
882 ab[2] = '4';
883 break;
884 case FAILURE_SIZE:
885 ab[2] = '6';
886 break;
887 case FAILURE_RECEIVED:
888 /* Remember this file as though we successfully received it;
889 when the other side acknowledges our rejection, we know that
890 we no longer have to remember that we received this file. */
891 usent_receive_ack (qdaemon, qtrans);
892 ab[2] = '8';
893 break;
894 default:
895 ab[2] = '\0';
896 break;
897 }
898
899 ab[3] = '\0';
900
901 fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, ab, qtrans->ilocal,
902 qtrans->iremote);
903
904 qinfo->fsent = TRUE;
905
3469b437 906 if (qinfo->freceived)
41c799d4
C
907 {
908 xfree (qtrans->pinfo);
909 utransfree (qtrans);
910 }
911
912 return fret;
913}
914
915/* Discard data until we reach the end of the file. This is used for
916 a protocol with multiple channels, since the remote system may
917 start sending the file before the confirmation is sent. If we
918 refuse the file, the remote system will get us back in synch by
919 sending an empty buffer, which is what we look for here. */
920
921/*ARGSUSED*/
922static boolean
923fremote_discard (qtrans, qdaemon, zdata, cdata)
924 struct stransfer *qtrans;
925 struct sdaemon *qdaemon;
926 const char *zdata;
927 size_t cdata;
928{
929 struct srecfailinfo *qinfo = (struct srecfailinfo *) qtrans->pinfo;
930
931 DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO,
932 "fremote_discard: Discarding %lu bytes",
933 (unsigned long) cdata);
934
935 if (cdata != 0)
936 return TRUE;
937
938 qinfo->freceived = TRUE;
939
940 /* If we have already sent the denial, we are done. */
941 if (qinfo->fsent)
942 {
943 xfree (qtrans->pinfo);
944 utransfree (qtrans);
945 }
946
947 return TRUE;
948}
949\f
950/* This is called when a file has been completely received. It sends
951 a response to the remote system. */
952
953/*ARGSUSED*/
954static boolean
955frec_file_end (qtrans, qdaemon, zdata, cdata)
956 struct stransfer *qtrans;
957 struct sdaemon *qdaemon;
958 const char *zdata;
959 size_t cdata;
960{
961 struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
3469b437 962 char *zalc;
41c799d4
C
963 const char *zerr;
964 boolean fnever;
965
966 DEBUG_MESSAGE3 (DEBUG_UUCP_PROTO, "frec_file_end: %s to %s (freplied %s)",
967 qtrans->s.zfrom, qtrans->s.zto,
968 qinfo->freplied ? "TRUE" : "FALSE");
969
970 if (qdaemon->qproto->pffile != NULL)
971 {
972 boolean fhandled;
973
974 if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, FALSE, FALSE,
975 (long) -1, &fhandled))
976 {
977 (void) ffileclose (qtrans->e);
978 (void) remove (qinfo->ztemp);
979 urrec_free (qtrans);
980 return FALSE;
981 }
982 if (fhandled)
983 return TRUE;
984 }
985
986 qinfo->freceived = TRUE;
987
988 fnever = FALSE;
989
3469b437
AC
990 zalc = NULL;
991
41c799d4
C
992 if (! ffileclose (qtrans->e))
993 {
994 zerr = strerror (errno);
995 ulog (LOG_ERROR, "%s: close: %s", qtrans->s.zto, zerr);
3469b437 996 (void) remove (qinfo->ztemp);
41c799d4
C
997 }
998 else if (! fsysdep_move_file (qinfo->ztemp, qinfo->zfile, qinfo->fspool,
999 FALSE, ! qinfo->fspool,
1000 (qinfo->flocal
1001 ? qtrans->s.zuser
1002 : (const char *) NULL)))
1003 {
3469b437
AC
1004 long cspace;
1005
1006 /* Keep the temporary file if there is 1.5 times the amount of
1007 required free space. This is just a random guess, to make an
1008 unusual situtation potentially less painful. */
1009 cspace = csysdep_bytes_free (qinfo->ztemp);
1010 if (cspace == -1)
1011 cspace = FREE_SPACE_DELTA;
1012 cspace -= (qdaemon->qsys->uuconf_cfree_space
1013 + qdaemon->qsys->uuconf_cfree_space / 2);
1014 if (cspace < 0)
1015 {
1016 (void) remove (qinfo->ztemp);
1017 zerr = "could not move to final location";
1018 }
1019 else
1020 {
1021 const char *az[20];
1022 int i;
1023
1024 zalc = zbufalc (sizeof "could not move to final location (left as )"
1025 + strlen (qinfo->ztemp));
1026 sprintf (zalc, "could not move to final location (left as %s)",
1027 qinfo->ztemp);
1028 zerr = zalc;
1029
1030 i = 0;
1031 az[i++] = "The file\n\t";
1032 az[i++] = qinfo->ztemp;
1033 az[i++] =
1034 "\nwas saved because the move to the final location failed.\n";
1035 az[i++] = "See the UUCP logs for more details.\n";
1036 az[i++] = "The file transfer was from\n\t";
1037 az[i++] = qdaemon->qsys->uuconf_zname;
1038 az[i++] = "!";
1039 az[i++] = qtrans->s.zfrom;
1040 az[i++] = "\nto\n\t";
1041 az[i++] = qtrans->s.zto;
1042 az[i++] = "\nand was requested by\n\t";
1043 az[i++] = qtrans->s.zuser;
1044 az[i++] = "\n";
1045 (void) fsysdep_mail (OWNER, "UUCP temporary file saved", i, az);
1046 }
41c799d4
C
1047 ulog (LOG_ERROR, "%s: %s", qinfo->zfile, zerr);
1048 fnever = TRUE;
1049 }
1050 else
1051 {
1052 if (! qinfo->fspool)
1053 {
1054 unsigned int imode;
1055
1056 /* Unless we can change the ownership of the file, the only
1057 choice to make about these bits is whether to set the
1058 execute bit or not. */
1059 if ((qtrans->s.imode & 0111) != 0)
1060 imode = 0777;
1061 else
1062 imode = 0666;
1063 (void) fsysdep_change_mode (qinfo->zfile, imode);
1064 }
1065
1066 zerr = NULL;
1067 }
1068
41c799d4
C
1069 ustats (zerr == NULL, qtrans->s.zuser, qdaemon->qsys->uuconf_zname,
1070 FALSE, qtrans->cbytes, qtrans->isecs, qtrans->imicros,
1071 qdaemon->fmaster);
3469b437 1072 qdaemon->creceived += qtrans->cbytes;
41c799d4
C
1073
1074 if (zerr == NULL)
1075 {
1076 if (qinfo->zmail != NULL && *qinfo->zmail != '\0')
1077 (void) fmail_transfer (TRUE, qtrans->s.zuser, qinfo->zmail,
1078 (const char *) NULL,
1079 qtrans->s.zfrom, qdaemon->qsys->uuconf_zname,
1080 qtrans->s.zto, (const char *) NULL,
1081 (const char *) NULL);
1082
1083 if (qtrans->s.pseq != NULL)
1084 (void) fsysdep_did_work (qtrans->s.pseq);
1085
1086 if (! qinfo->flocal)
1087 {
1088 /* Remember that we have received this file, so that if the
1089 connection drops at this point we won't receive it again.
1090 We could check the return value here, but if we return
1091 FALSE we couldn't do anything but drop the connection,
1092 which would hardly be reasonable. Instead we trust that
1093 the administrator will notice and handle any error
1094 messages, which are very unlikely to occur if everything
1095 is set up correctly. */
1096 (void) fsysdep_remember_reception (qdaemon->qsys, qtrans->s.zto,
1097 qtrans->s.ztemp);
1098 }
1099 }
1100 else
1101 {
1102 /* If the transfer failed, we send mail if it was requested
1103 locally and if it can never succeed. */
1104 if (qinfo->flocal && fnever)
1105 {
1106 (void) fmail_transfer (FALSE, qtrans->s.zuser, qinfo->zmail,
1107 zerr, qtrans->s.zfrom,
1108 qdaemon->qsys->uuconf_zname,
1109 qtrans->s.zto, (const char *) NULL,
1110 (const char *) NULL);
1111 (void) fsysdep_did_work (qtrans->s.pseq);
1112 }
1113 }
1114
3469b437
AC
1115 ubuffree (zalc);
1116
41c799d4
C
1117 /* If this is an execution request, we must create the execution
1118 file itself. */
1119 if (qtrans->s.bcmd == 'E' && zerr == NULL)
1120 {
1121 char *zxqt, *zxqtfile, *ztemp;
1122 FILE *e;
1123 boolean fbad;
1124
1125 /* We get an execution file name by simply replacing the leading
1126 D in the received file name with an X. This pretty much
1127 always has to work since we can always receive a file name
1128 starting with X, so the system dependent code must be
1129 prepared to see one. */
1130 zxqt = zbufcpy (qtrans->s.zto);
1131 zxqt[0] = 'X';
1132 zxqtfile = zsysdep_spool_file_name (qdaemon->qsys, zxqt,
1133 (pointer) NULL);
1134 ubuffree (zxqt);
1135
1136 if (zxqtfile == NULL)
1137 {
1138 urrec_free (qtrans);
1139 return FALSE;
1140 }
1141
1142 /* We have to write via a temporary file, because otherwise
1143 uuxqt might pick up the file before we have finished writing
1144 it. */
1145 e = NULL;
3469b437
AC
1146 ztemp = zsysdep_receive_temp (qdaemon->qsys, zxqtfile, "D.0",
1147 (qdaemon->qproto->frestart
1148 && (qdaemon->ifeatures
1149 & FEATURE_RESTART) != 0));
41c799d4
C
1150 if (ztemp != NULL)
1151 e = esysdep_fopen (ztemp, FALSE, FALSE, TRUE);
1152
1153 if (e == NULL)
1154 {
1155 ubuffree (zxqtfile);
1156 ubuffree (ztemp);
1157 urrec_free (qtrans);
1158 return FALSE;
1159 }
1160
1161 fprintf (e, "U %s %s\n", qtrans->s.zuser, qdaemon->qsys->uuconf_zname);
1162 fprintf (e, "F %s\n", qtrans->s.zto);
1163 fprintf (e, "I %s\n", qtrans->s.zto);
1164 if (strchr (qtrans->s.zoptions, 'N') != NULL)
1165 fprintf (e, "N\n");
1166 if (strchr (qtrans->s.zoptions, 'Z') != NULL)
1167 fprintf (e, "Z\n");
1168 if (strchr (qtrans->s.zoptions, 'R') != NULL)
1169 fprintf (e, "R %s\n", qtrans->s.znotify);
1170 if (strchr (qtrans->s.zoptions, 'e') != NULL)
1171 fprintf (e, "e\n");
1172 fprintf (e, "C %s\n", qtrans->s.zcmd);
1173
1174 fbad = FALSE;
1175 if (fclose (e) == EOF)
1176 {
1177 ulog (LOG_ERROR, "fclose: %s", strerror (errno));
1178 (void) remove (ztemp);
1179 fbad = TRUE;
1180 }
1181
1182 if (! fbad)
1183 {
1184 if (! fsysdep_move_file (ztemp, zxqtfile, TRUE, FALSE, FALSE,
1185 (const char *) NULL))
3469b437
AC
1186 {
1187 (void) remove (ztemp);
1188 fbad = TRUE;
1189 }
41c799d4
C
1190 }
1191
1192 ubuffree (zxqtfile);
1193 ubuffree (ztemp);
1194
1195 if (fbad)
1196 {
1197 urrec_free (qtrans);
1198 return FALSE;
1199 }
1200 }
1201
3469b437
AC
1202 /* See if we should spawn a uuxqt process. */
1203 if (zerr == NULL
1204 && (qtrans->s.bcmd == 'E'
1205 || (qinfo->fspool && qtrans->s.zto[0] == 'X')))
1206 {
1207 ++qdaemon->cxfiles_received;
1208 if (qdaemon->irunuuxqt > 0
1209 && qdaemon->cxfiles_received >= qdaemon->irunuuxqt)
1210 {
1211 if (fspawn_uuxqt (TRUE, qdaemon->qsys->uuconf_zname,
1212 qdaemon->zconfig))
1213 qdaemon->cxfiles_received = 0;
1214 }
1215 }
1216
41c799d4
C
1217 /* Prepare to send the completion string to the remote system. If
1218 we have not yet replied to the remote send request, we leave the
1219 transfer structure on the remote queue. Otherwise we add it to
1220 the send queue. The psendfn field will already be set. */
1221 qinfo->fmoved = zerr == NULL;
1222 if (qinfo->freplied)
1223 return fqueue_send (qdaemon, qtrans);
1224
1225 return TRUE;
1226}
1227
1228/* Send the final confirmation string to the remote system. */
1229
1230static boolean
1231frec_file_send_confirm (qtrans, qdaemon)
1232 struct stransfer *qtrans;
1233 struct sdaemon *qdaemon;
1234{
1235 struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
1236 const char *zsend;
1237 boolean fret;
1238
1239 if (! qinfo->fmoved)
1240 zsend = "CN5";
1241 else if (! qdaemon->frequest_hangup)
1242 zsend = "CY";
1243 else
1244 {
1245#if DEBUG > 0
1246 if (qdaemon->fmaster)
1247 ulog (LOG_FATAL, "frec_file_send_confirm: Can't happen");
1248#endif
1249
1250 DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO,
1251 "frec_send_file_confirm: Requesting remote to transfer control");
1252 zsend = "CYM";
1253 }
1254
1255 fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend,
1256 qtrans->ilocal, qtrans->iremote);
1257
1258 /* Now, if that was a remote command, then when the confirmation
1259 message is acked we no longer have to remember that we received
1260 that file. */
1261 if (! qinfo->flocal && qinfo->fmoved)
1262 usent_receive_ack (qdaemon, qtrans);
1263
1264 urrec_free (qtrans);
1265 return fret;
1266}
1267\f
1268/* Discard a temporary file if it is not useful. A temporary file is
1269 useful if it could be used to restart a receive. This is called if
1270 the connection is lost. It is only called if qtrans->frecfile is
1271 TRUE. */
1272
1273boolean
1274frec_discard_temp (qdaemon, qtrans)
1275 struct sdaemon *qdaemon;
1276 struct stransfer *qtrans;
1277{
1278 struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo;
1279
1280 if ((qdaemon->ifeatures & FEATURE_RESTART) == 0
1281 || qtrans->s.ztemp == NULL
1282 || qtrans->s.ztemp[0] != 'D'
1283 || strcmp (qtrans->s.ztemp, "D.0") == 0)
1284 (void) remove (qinfo->ztemp);
1285 return TRUE;
1286}