Commit | Line | Data |
---|---|---|
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 | 29 | const 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. */ | |
47 | struct 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. */ | |
69 | struct 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 | ||
81 | static void urrec_free P((struct stransfer *qtrans)); | |
82 | static boolean flocal_rec_fail P((struct stransfer *qtrans, | |
83 | struct scmd *qcmd, | |
84 | const struct uuconf_system *qsys, | |
85 | const char *zwhy)); | |
86 | static boolean flocal_rec_send_request P((struct stransfer *qtrans, | |
87 | struct sdaemon *qdaemon)); | |
88 | static boolean flocal_rec_await_reply P((struct stransfer *qtrans, | |
89 | struct sdaemon *qdaemon, | |
90 | const char *zdata, | |
91 | size_t cdata)); | |
92 | static boolean fremote_send_reply P((struct stransfer *qtrans, | |
93 | struct sdaemon *qdaemon)); | |
94 | static boolean fremote_send_fail P((struct sdaemon *qdaemon, | |
95 | struct scmd *qcmd, | |
96 | enum tfailure twhy, | |
97 | int iremote)); | |
98 | static boolean fremote_send_fail_send P((struct stransfer *qtrans, | |
99 | struct sdaemon *qdaemon)); | |
100 | static boolean fremote_discard P((struct stransfer *qtrans, | |
101 | struct sdaemon *qdaemon, | |
102 | const char *zdata, size_t cdata)); | |
103 | static boolean frec_file_end P((struct stransfer *qtrans, | |
104 | struct sdaemon *qdaemon, | |
105 | const char *zdata, size_t cdata)); | |
106 | static boolean frec_file_send_confirm P((struct stransfer *qtrans, | |
107 | struct sdaemon *qdaemon)); | |
108 | \f | |
109 | /* Free up a receive stransfer structure. */ | |
110 | ||
111 | static void | |
112 | urrec_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 | ||
141 | boolean | |
142 | flocal_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 | ||
275 | static boolean | |
276 | flocal_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 | ||
299 | static boolean | |
300 | flocal_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*/ | |
376 | static boolean | |
377 | flocal_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 | ||
497 | boolean | |
498 | frec_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 | ||
547 | boolean | |
548 | fremote_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 | ||
769 | static boolean | |
770 | fremote_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 | ||
827 | static boolean | |
828 | fremote_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 | ||
857 | static boolean | |
858 | fremote_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*/ | |
922 | static boolean | |
923 | fremote_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*/ | |
954 | static boolean | |
955 | frec_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 | ||
1230 | static boolean | |
1231 | frec_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 | ||
1273 | boolean | |
1274 | frec_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 | } |