|
|
1.1 ! root 1: /* rec.c ! 2: Routines to receive a file. ! 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 [email protected] or ! 23: c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. ! 24: */ ! 25: ! 26: #include "uucp.h" ! 27: ! 28: #if USE_RCS_ID ! 29: const char rec_rcsid[] = "$Id: rec.c,v 1.1 93/07/30 07:53:56 bin Exp Locker: bin $"; ! 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: ! 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: ! 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: ! 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: ! 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, ! 311: (const char *) NULL); ! 312: if (qinfo->ztemp == NULL) ! 313: { ! 314: urrec_free (qtrans); ! 315: return FALSE; ! 316: } ! 317: ! 318: /* Check the amount of free space available for both the temporary ! 319: file and the real file. */ ! 320: cbytes = csysdep_bytes_free (qinfo->ztemp); ! 321: cbytes2 = csysdep_bytes_free (qinfo->zfile); ! 322: if (cbytes < cbytes2) ! 323: cbytes = cbytes2; ! 324: if (cbytes != -1) ! 325: { ! 326: cbytes -= qdaemon->qsys->uuconf_cfree_space; ! 327: if (cbytes < 0) ! 328: cbytes = 0; ! 329: } ! 330: ! 331: if (qdaemon->clocal_size != -1 ! 332: && (cbytes == -1 || qdaemon->clocal_size < cbytes)) ! 333: cbytes = qdaemon->clocal_size; ! 334: ! 335: /* We send the string ! 336: R from to user options ! 337: ! 338: We put a dash in front of options. If we are talking to a ! 339: counterpart, we also send the maximum size file we are prepared ! 340: to accept, as returned by esysdep_open_receive. */ ! 341: clen = (strlen (qtrans->s.zfrom) + strlen (qtrans->s.zto) ! 342: + strlen (qtrans->s.zuser) + strlen (qtrans->s.zoptions) + 30); ! 343: zsend = zbufalc (clen); ! 344: if ((qdaemon->ifeatures & FEATURE_SIZES) == 0) ! 345: sprintf (zsend, "R %s %s %s -%s", qtrans->s.zfrom, qtrans->s.zto, ! 346: qtrans->s.zuser, qtrans->s.zoptions); ! 347: else if ((qdaemon->ifeatures & FEATURE_V103) == 0) ! 348: sprintf (zsend, "R %s %s %s -%s 0x%lx", qtrans->s.zfrom, qtrans->s.zto, ! 349: qtrans->s.zuser, qtrans->s.zoptions, (unsigned long) cbytes); ! 350: else ! 351: sprintf (zsend, "R %s %s %s -%s %ld", qtrans->s.zfrom, qtrans->s.zto, ! 352: qtrans->s.zuser, qtrans->s.zoptions, cbytes); ! 353: ! 354: fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, qtrans->ilocal, ! 355: qtrans->iremote); ! 356: ubuffree (zsend); ! 357: if (! fret) ! 358: { ! 359: urrec_free (qtrans); ! 360: return FALSE; ! 361: } ! 362: ! 363: qtrans->fcmd = TRUE; ! 364: qtrans->precfn = flocal_rec_await_reply; ! 365: ! 366: return fqueue_receive (qdaemon, qtrans); ! 367: } ! 368: ! 369: /* This is called when a reply is received for the request. */ ! 370: ! 371: /*ARGSUSED*/ ! 372: static boolean ! 373: flocal_rec_await_reply (qtrans, qdaemon, zdata, cdata) ! 374: struct stransfer *qtrans; ! 375: struct sdaemon *qdaemon; ! 376: const char *zdata; ! 377: size_t cdata; ! 378: { ! 379: struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; ! 380: long crestart; ! 381: const char *zlog; ! 382: ! 383: if (zdata[0] != 'R' ! 384: || (zdata[1] != 'Y' && zdata[1] != 'N')) ! 385: { ! 386: ulog (LOG_ERROR, "%s: bad response to receive request: \"%s\"", ! 387: qtrans->s.zfrom, zdata); ! 388: urrec_free (qtrans); ! 389: return FALSE; ! 390: } ! 391: ! 392: if (zdata[1] == 'N') ! 393: { ! 394: boolean fnever; ! 395: const char *zerr; ! 396: ! 397: fnever = TRUE; ! 398: if (zdata[2] == '2') ! 399: zerr = "no such file"; ! 400: else if (zdata[2] == '6') ! 401: { ! 402: /* We sent over the maximum file size we were prepared to ! 403: receive, and the remote system is telling us that the ! 404: file is larger than that. Try again later. It would be ! 405: better if we could know whether there will ever be enough ! 406: room. */ ! 407: zerr = "too large to receive now"; ! 408: fnever = FALSE; ! 409: } ! 410: else ! 411: zerr = "unknown reason"; ! 412: ! 413: if (fnever) ! 414: return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys, zerr); ! 415: ! 416: ulog (LOG_ERROR, "%s: %s", qtrans->s.zfrom, zerr); ! 417: ! 418: urrec_free (qtrans); ! 419: ! 420: return TRUE; ! 421: } ! 422: ! 423: /* The mode should have been sent as "RY 0%o". If it wasn't, we use ! 424: 0666. */ ! 425: qtrans->s.imode = (unsigned int) strtol ((char *) (zdata + 2), ! 426: (char **) NULL, 8); ! 427: if (qtrans->s.imode == 0) ! 428: qtrans->s.imode = 0666; ! 429: ! 430: /* Open the file to receive into. We just ignore any restart count, ! 431: since we have no way to tell it to the other side. SVR4 may have ! 432: some way to do this, but I don't know what it is. */ ! 433: qtrans->e = esysdep_open_receive (qdaemon->qsys, qinfo->zfile, ! 434: (const char *) NULL, qinfo->ztemp, ! 435: &crestart); ! 436: if (! ffileisopen (qtrans->e)) ! 437: return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys, ! 438: "cannot open file"); ! 439: ! 440: if (qinfo->fspool) ! 441: zlog = qtrans->s.zto; ! 442: else ! 443: zlog = qinfo->zfile; ! 444: qtrans->zlog = zbufalc (sizeof "Receiving " + strlen (zlog)); ! 445: sprintf (qtrans->zlog, "Receiving %s", zlog); ! 446: ! 447: if (qdaemon->qproto->pffile != NULL) ! 448: { ! 449: boolean fhandled; ! 450: ! 451: if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, FALSE, ! 452: (long) -1, &fhandled)) ! 453: { ! 454: (void) ffileclose (qtrans->e); ! 455: return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys, ! 456: (const char *) NULL); ! 457: } ! 458: if (fhandled) ! 459: return TRUE; ! 460: } ! 461: ! 462: qtrans->frecfile = TRUE; ! 463: qtrans->psendfn = frec_file_send_confirm; ! 464: qtrans->precfn = frec_file_end; ! 465: ! 466: return fqueue_receive (qdaemon, qtrans); ! 467: } ! 468: ! 469: /* Make sure there is still enough disk space available to receive a ! 470: file. */ ! 471: ! 472: boolean ! 473: frec_check_free (qtrans, cfree_space) ! 474: struct stransfer *qtrans; ! 475: long cfree_space; ! 476: { ! 477: struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; ! 478: long cfree1, cfree2; ! 479: ! 480: cfree1 = csysdep_bytes_free (qinfo->ztemp); ! 481: cfree2 = csysdep_bytes_free (qinfo->zfile); ! 482: if (cfree1 < cfree2) ! 483: cfree1 = cfree2; ! 484: if (cfree1 != -1 && cfree1 < cfree_space) ! 485: { ! 486: ulog (LOG_ERROR, "%s: too big to receive now", qinfo->zfile); ! 487: return FALSE; ! 488: } ! 489: ! 490: return TRUE; ! 491: } ! 492: ! 493: /* A remote request to send a file to the local system, meaning that ! 494: we are going to receive a file. ! 495: ! 496: If we are using a protocol which does not support multiple ! 497: channels, the remote system will not start sending us the file ! 498: until it has received our confirmation. In that case, the order of ! 499: functions is as follows: ! 500: ! 501: fremote_send_file_init (open file) --> fqueue_remote ! 502: fremote_send_reply (send SY, call pffile) --> fqueue_receive ! 503: receive file ! 504: frec_file_end (close and move file, call pffile) --> fqueue_send ! 505: frec_file_send_confirm (send CY) ! 506: ! 507: If the protocol supports multiple channels, then the remote system ! 508: will start sending the file immediately after the send request. ! 509: That means that the data may come in before remote_send_reply is ! 510: called, so frec_file_end may be called before fremote_send_reply. ! 511: Note that this means the pffile entry points may be called in ! 512: reverse order for such a protocol. ! 513: ! 514: If the send request is rejected, via fremote_send_fail, and the ! 515: protocol supports multiple channels, we must accept and discard ! 516: data until a zero byte buffer is received from the other side, ! 517: indicating that it has received our rejection. ! 518: ! 519: This code also handles execution requests, which are very similar ! 520: to send requests. */ ! 521: ! 522: boolean ! 523: fremote_send_file_init (qdaemon, qcmd, iremote) ! 524: struct sdaemon *qdaemon; ! 525: struct scmd *qcmd; ! 526: int iremote; ! 527: { ! 528: const struct uuconf_system *qsys; ! 529: boolean fspool; ! 530: char *zfile; ! 531: openfile_t e; ! 532: char *ztemp; ! 533: long cbytes, cbytes2; ! 534: long crestart; ! 535: struct srecinfo *qinfo; ! 536: struct stransfer *qtrans; ! 537: const char *zlog; ! 538: ! 539: qsys = qdaemon->qsys; ! 540: ! 541: if (! qsys->uuconf_frec_request) ! 542: { ! 543: ulog (LOG_ERROR, "%s: not permitted to receive files from remote", ! 544: qcmd->zfrom); ! 545: return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote); ! 546: } ! 547: ! 548: fspool = fspool_file (qcmd->zto); ! 549: ! 550: /* We don't accept remote command files. An execution request may ! 551: only send a simple data file. */ ! 552: if ((fspool && qcmd->zto[0] == 'C') ! 553: || (qcmd->bcmd == 'E' ! 554: && (! fspool || qcmd->zto[0] != 'D'))) ! 555: { ! 556: ulog (LOG_ERROR, "%s: not permitted to receive", qcmd->zfrom); ! 557: return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote); ! 558: } ! 559: ! 560: /* See if we have already received this file in a previous ! 561: conversation. */ ! 562: if (fsysdep_already_received (qsys, qcmd->zto, qcmd->ztemp)) ! 563: return fremote_send_fail (qdaemon, qcmd, FAILURE_RECEIVED, iremote); ! 564: ! 565: if (fspool) ! 566: { ! 567: zfile = zsysdep_spool_file_name (qsys, qcmd->zto, (pointer) NULL); ! 568: if (zfile == NULL) ! 569: return FALSE; ! 570: } ! 571: else ! 572: { ! 573: zfile = zsysdep_local_file (qcmd->zto, qsys->uuconf_zpubdir); ! 574: if (zfile != NULL) ! 575: { ! 576: char *zadd; ! 577: ! 578: zadd = zsysdep_add_base (zfile, qcmd->zfrom); ! 579: ubuffree (zfile); ! 580: zfile = zadd; ! 581: } ! 582: if (zfile == NULL) ! 583: return FALSE; ! 584: ! 585: /* Check permissions. */ ! 586: if (! fin_directory_list (zfile, qsys->uuconf_pzremote_receive, ! 587: qsys->uuconf_zpubdir, TRUE, ! 588: FALSE, (const char *) NULL)) ! 589: { ! 590: ulog (LOG_ERROR, "%s: not permitted to receive", zfile); ! 591: ubuffree (zfile); ! 592: return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote); ! 593: } ! 594: ! 595: if (strchr (qcmd->zoptions, 'f') == NULL) ! 596: { ! 597: if (! fsysdep_make_dirs (zfile, TRUE)) ! 598: { ! 599: ubuffree (zfile); ! 600: return fremote_send_fail (qdaemon, qcmd, FAILURE_OPEN, ! 601: iremote); ! 602: } ! 603: } ! 604: } ! 605: ! 606: ztemp = zsysdep_receive_temp (qsys, zfile, qcmd->ztemp); ! 607: ! 608: /* Adjust the number of bytes we are prepared to receive according ! 609: to the amount of free space we are supposed to leave available ! 610: and the maximum file size we are permitted to transfer. */ ! 611: cbytes = csysdep_bytes_free (ztemp); ! 612: cbytes2 = csysdep_bytes_free (zfile); ! 613: if (cbytes < cbytes2) ! 614: cbytes = cbytes2; ! 615: ! 616: if (cbytes != -1) ! 617: { ! 618: cbytes -= qsys->uuconf_cfree_space; ! 619: if (cbytes < 0) ! 620: cbytes = 0; ! 621: } ! 622: ! 623: if (qdaemon->cremote_size != -1 ! 624: && (cbytes == -1 || qdaemon->cremote_size < cbytes)) ! 625: cbytes = qdaemon->cremote_size; ! 626: ! 627: /* If the number of bytes we are prepared to receive is less than ! 628: the file size, we must fail. If the remote did not tell us the ! 629: file size, arbitrarily assumed that it is 10240 bytes. */ ! 630: if (cbytes != -1) ! 631: { ! 632: long csize; ! 633: ! 634: csize = qcmd->cbytes; ! 635: if (csize == -1) ! 636: csize = CASSUMED_FILE_SIZE; ! 637: if (cbytes < csize) ! 638: { ! 639: ulog (LOG_ERROR, "%s: too big to receive", zfile); ! 640: ubuffree (ztemp); ! 641: ubuffree (zfile); ! 642: return fremote_send_fail (qdaemon, qcmd, FAILURE_SIZE, iremote); ! 643: } ! 644: } ! 645: ! 646: /* Open the file to receive into. This may find an old copy of the ! 647: file, which will be used for file restart if the other side ! 648: supports it. */ ! 649: e = esysdep_open_receive (qsys, zfile, qcmd->ztemp, ztemp, &crestart); ! 650: if (! ffileisopen (e)) ! 651: { ! 652: ubuffree (ztemp); ! 653: ubuffree (zfile); ! 654: return fremote_send_fail (qdaemon, qcmd, FAILURE_OPEN, iremote); ! 655: } ! 656: ! 657: if (crestart > 0) ! 658: { ! 659: if ((qdaemon->ifeatures & FEATURE_RESTART) == 0) ! 660: crestart = -1; ! 661: else ! 662: { ! 663: DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, ! 664: "fremote_send_file_init: Restarting receive from %ld", ! 665: crestart); ! 666: if (! ffileseek (e, crestart)) ! 667: { ! 668: ulog (LOG_ERROR, "seek: %s", strerror (errno)); ! 669: (void) ffileclose (e); ! 670: ubuffree (ztemp); ! 671: ubuffree (zfile); ! 672: return FALSE; ! 673: } ! 674: } ! 675: } ! 676: ! 677: qinfo = (struct srecinfo *) xmalloc (sizeof (struct srecinfo)); ! 678: if (strchr (qcmd->zoptions, 'n') == NULL) ! 679: qinfo->zmail = NULL; ! 680: else ! 681: qinfo->zmail = zbufcpy (qcmd->znotify); ! 682: qinfo->zfile = zfile; ! 683: qinfo->ztemp = ztemp; ! 684: qinfo->fspool = fspool; ! 685: qinfo->flocal = FALSE; ! 686: qinfo->freceived = FALSE; ! 687: qinfo->freplied = FALSE; ! 688: ! 689: qtrans = qtransalc (qcmd); ! 690: qtrans->psendfn = fremote_send_reply; ! 691: qtrans->precfn = frec_file_end; ! 692: qtrans->iremote = iremote; ! 693: qtrans->pinfo = (pointer) qinfo; ! 694: qtrans->frecfile = TRUE; ! 695: qtrans->e = e; ! 696: if (crestart > 0) ! 697: qtrans->ipos = crestart; ! 698: ! 699: if (qcmd->bcmd == 'E') ! 700: zlog = qcmd->zcmd; ! 701: else ! 702: { ! 703: if (qinfo->fspool) ! 704: zlog = qcmd->zto; ! 705: else ! 706: zlog = qinfo->zfile; ! 707: } ! 708: qtrans->zlog = zbufalc (sizeof "Receiving " + strlen (zlog)); ! 709: sprintf (qtrans->zlog, "Receiving %s", zlog); ! 710: ! 711: return fqueue_remote (qdaemon, qtrans); ! 712: } ! 713: ! 714: /* Reply to a send request, and prepare to receive the file. */ ! 715: ! 716: static boolean ! 717: fremote_send_reply (qtrans, qdaemon) ! 718: struct stransfer *qtrans; ! 719: struct sdaemon *qdaemon; ! 720: { ! 721: struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; ! 722: char ab[50]; ! 723: ! 724: ab[0] = qtrans->s.bcmd; ! 725: ab[1] = 'Y'; ! 726: if (qtrans->ipos <= 0) ! 727: ab[2] = '\0'; ! 728: else ! 729: sprintf (ab + 2, " 0x%lx", (unsigned long) qtrans->ipos); ! 730: ! 731: if (! (*qdaemon->qproto->pfsendcmd) (qdaemon, ab, qtrans->ilocal, ! 732: qtrans->iremote)) ! 733: { ! 734: (void) ffileclose (qtrans->e); ! 735: (void) remove (qinfo->ztemp); ! 736: urrec_free (qtrans); ! 737: return FALSE; ! 738: } ! 739: ! 740: qinfo->freplied = TRUE; ! 741: ! 742: if (qdaemon->qproto->pffile != NULL) ! 743: { ! 744: boolean fhandled; ! 745: ! 746: if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, FALSE, ! 747: (long) -1, &fhandled)) ! 748: { ! 749: (void) ffileclose (qtrans->e); ! 750: (void) remove (qinfo->ztemp); ! 751: urrec_free (qtrans); ! 752: return FALSE; ! 753: } ! 754: if (fhandled) ! 755: return TRUE; ! 756: } ! 757: ! 758: /* If the file has been completely received, we just want to send ! 759: the final confirmation. Otherwise, we must wait for the file ! 760: first. */ ! 761: qtrans->psendfn = frec_file_send_confirm; ! 762: if (qinfo->freceived) ! 763: return fqueue_send (qdaemon, qtrans); ! 764: else ! 765: return fqueue_receive (qdaemon, qtrans); ! 766: } ! 767: ! 768: /* If we can't receive a file, queue up a response to the remote ! 769: system. */ ! 770: ! 771: static boolean ! 772: fremote_send_fail (qdaemon, qcmd, twhy, iremote) ! 773: struct sdaemon *qdaemon; ! 774: struct scmd *qcmd; ! 775: enum tfailure twhy; ! 776: int iremote; ! 777: { ! 778: struct srecfailinfo *qinfo; ! 779: struct stransfer *qtrans; ! 780: ! 781: qinfo = (struct srecfailinfo *) xmalloc (sizeof (struct srecfailinfo)); ! 782: qinfo->twhy = twhy; ! 783: qinfo->fsent = FALSE; ! 784: ! 785: /* If the protocol does not support multiple channels (cchans <= 1), ! 786: then we have essentially already received the entire file. */ ! 787: qinfo->freceived = qdaemon->qproto->cchans <= 1; ! 788: ! 789: qtrans = qtransalc (qcmd); ! 790: qtrans->psendfn = fremote_send_fail_send; ! 791: qtrans->precfn = fremote_discard; ! 792: qtrans->iremote = iremote; ! 793: qtrans->pinfo = (pointer) qinfo; ! 794: ! 795: return fqueue_remote (qdaemon, qtrans); ! 796: } ! 797: ! 798: /* Send a failure string for a send command to the remote system; ! 799: this is called when we are ready to reply to the command. */ ! 800: ! 801: static boolean ! 802: fremote_send_fail_send (qtrans, qdaemon) ! 803: struct stransfer *qtrans; ! 804: struct sdaemon *qdaemon; ! 805: { ! 806: struct srecfailinfo *qinfo = (struct srecfailinfo *) qtrans->pinfo; ! 807: char ab[4]; ! 808: boolean fret; ! 809: ! 810: ab[0] = qtrans->s.bcmd; ! 811: ab[1] = 'N'; ! 812: ! 813: switch (qinfo->twhy) ! 814: { ! 815: case FAILURE_PERM: ! 816: ab[2] = '2'; ! 817: break; ! 818: case FAILURE_OPEN: ! 819: ab[2] = '4'; ! 820: break; ! 821: case FAILURE_SIZE: ! 822: ab[2] = '6'; ! 823: break; ! 824: case FAILURE_RECEIVED: ! 825: /* Remember this file as though we successfully received it; ! 826: when the other side acknowledges our rejection, we know that ! 827: we no longer have to remember that we received this file. */ ! 828: usent_receive_ack (qdaemon, qtrans); ! 829: ab[2] = '8'; ! 830: break; ! 831: default: ! 832: ab[2] = '\0'; ! 833: break; ! 834: } ! 835: ! 836: ab[3] = '\0'; ! 837: ! 838: fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, ab, qtrans->ilocal, ! 839: qtrans->iremote); ! 840: ! 841: qinfo->fsent = TRUE; ! 842: ! 843: /* Wait for the end of file marker if we haven't gotten it yet. */ ! 844: if (! qinfo->freceived) ! 845: { ! 846: if (! fqueue_receive (qdaemon, qtrans)) ! 847: fret = FALSE; ! 848: } ! 849: else ! 850: { ! 851: xfree (qtrans->pinfo); ! 852: utransfree (qtrans); ! 853: } ! 854: ! 855: return fret; ! 856: } ! 857: ! 858: /* Discard data until we reach the end of the file. This is used for ! 859: a protocol with multiple channels, since the remote system may ! 860: start sending the file before the confirmation is sent. If we ! 861: refuse the file, the remote system will get us back in synch by ! 862: sending an empty buffer, which is what we look for here. */ ! 863: ! 864: /*ARGSUSED*/ ! 865: static boolean ! 866: fremote_discard (qtrans, qdaemon, zdata, cdata) ! 867: struct stransfer *qtrans; ! 868: struct sdaemon *qdaemon; ! 869: const char *zdata; ! 870: size_t cdata; ! 871: { ! 872: struct srecfailinfo *qinfo = (struct srecfailinfo *) qtrans->pinfo; ! 873: ! 874: DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, ! 875: "fremote_discard: Discarding %lu bytes", ! 876: (unsigned long) cdata); ! 877: ! 878: if (cdata != 0) ! 879: return TRUE; ! 880: ! 881: qinfo->freceived = TRUE; ! 882: ! 883: /* If we have already sent the denial, we are done. */ ! 884: if (qinfo->fsent) ! 885: { ! 886: xfree (qtrans->pinfo); ! 887: utransfree (qtrans); ! 888: } ! 889: ! 890: return TRUE; ! 891: } ! 892: ! 893: /* This is called when a file has been completely received. It sends ! 894: a response to the remote system. */ ! 895: ! 896: /*ARGSUSED*/ ! 897: static boolean ! 898: frec_file_end (qtrans, qdaemon, zdata, cdata) ! 899: struct stransfer *qtrans; ! 900: struct sdaemon *qdaemon; ! 901: const char *zdata; ! 902: size_t cdata; ! 903: { ! 904: struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; ! 905: const char *zerr; ! 906: boolean fnever; ! 907: ! 908: DEBUG_MESSAGE3 (DEBUG_UUCP_PROTO, "frec_file_end: %s to %s (freplied %s)", ! 909: qtrans->s.zfrom, qtrans->s.zto, ! 910: qinfo->freplied ? "TRUE" : "FALSE"); ! 911: ! 912: if (qdaemon->qproto->pffile != NULL) ! 913: { ! 914: boolean fhandled; ! 915: ! 916: if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, FALSE, FALSE, ! 917: (long) -1, &fhandled)) ! 918: { ! 919: (void) ffileclose (qtrans->e); ! 920: (void) remove (qinfo->ztemp); ! 921: urrec_free (qtrans); ! 922: return FALSE; ! 923: } ! 924: if (fhandled) ! 925: return TRUE; ! 926: } ! 927: ! 928: qinfo->freceived = TRUE; ! 929: ! 930: fnever = FALSE; ! 931: ! 932: if (! ffileclose (qtrans->e)) ! 933: { ! 934: zerr = strerror (errno); ! 935: ulog (LOG_ERROR, "%s: close: %s", qtrans->s.zto, zerr); ! 936: } ! 937: else if (! fsysdep_move_file (qinfo->ztemp, qinfo->zfile, qinfo->fspool, ! 938: FALSE, ! qinfo->fspool, ! 939: (qinfo->flocal ! 940: ? qtrans->s.zuser ! 941: : (const char *) NULL))) ! 942: { ! 943: zerr = "could not move to final location"; ! 944: ulog (LOG_ERROR, "%s: %s", qinfo->zfile, zerr); ! 945: fnever = TRUE; ! 946: } ! 947: else ! 948: { ! 949: if (! qinfo->fspool) ! 950: { ! 951: unsigned int imode; ! 952: ! 953: /* Unless we can change the ownership of the file, the only ! 954: choice to make about these bits is whether to set the ! 955: execute bit or not. */ ! 956: if ((qtrans->s.imode & 0111) != 0) ! 957: imode = 0777; ! 958: else ! 959: imode = 0666; ! 960: (void) fsysdep_change_mode (qinfo->zfile, imode); ! 961: } ! 962: ! 963: zerr = NULL; ! 964: } ! 965: ! 966: if (zerr != NULL) ! 967: (void) remove (qinfo->ztemp); ! 968: ! 969: ustats (zerr == NULL, qtrans->s.zuser, qdaemon->qsys->uuconf_zname, ! 970: FALSE, qtrans->cbytes, qtrans->isecs, qtrans->imicros, ! 971: qdaemon->fmaster); ! 972: ! 973: if (zerr == NULL) ! 974: { ! 975: if (qinfo->zmail != NULL && *qinfo->zmail != '\0') ! 976: (void) fmail_transfer (TRUE, qtrans->s.zuser, qinfo->zmail, ! 977: (const char *) NULL, ! 978: qtrans->s.zfrom, qdaemon->qsys->uuconf_zname, ! 979: qtrans->s.zto, (const char *) NULL, ! 980: (const char *) NULL); ! 981: ! 982: if (qtrans->s.pseq != NULL) ! 983: (void) fsysdep_did_work (qtrans->s.pseq); ! 984: ! 985: if (! qinfo->flocal) ! 986: { ! 987: /* Remember that we have received this file, so that if the ! 988: connection drops at this point we won't receive it again. ! 989: We could check the return value here, but if we return ! 990: FALSE we couldn't do anything but drop the connection, ! 991: which would hardly be reasonable. Instead we trust that ! 992: the administrator will notice and handle any error ! 993: messages, which are very unlikely to occur if everything ! 994: is set up correctly. */ ! 995: (void) fsysdep_remember_reception (qdaemon->qsys, qtrans->s.zto, ! 996: qtrans->s.ztemp); ! 997: } ! 998: } ! 999: else ! 1000: { ! 1001: /* If the transfer failed, we send mail if it was requested ! 1002: locally and if it can never succeed. */ ! 1003: if (qinfo->flocal && fnever) ! 1004: { ! 1005: (void) fmail_transfer (FALSE, qtrans->s.zuser, qinfo->zmail, ! 1006: zerr, qtrans->s.zfrom, ! 1007: qdaemon->qsys->uuconf_zname, ! 1008: qtrans->s.zto, (const char *) NULL, ! 1009: (const char *) NULL); ! 1010: (void) fsysdep_did_work (qtrans->s.pseq); ! 1011: } ! 1012: } ! 1013: ! 1014: /* If this is an execution request, we must create the execution ! 1015: file itself. */ ! 1016: if (qtrans->s.bcmd == 'E' && zerr == NULL) ! 1017: { ! 1018: char *zxqt, *zxqtfile, *ztemp; ! 1019: FILE *e; ! 1020: boolean fbad; ! 1021: ! 1022: /* We get an execution file name by simply replacing the leading ! 1023: D in the received file name with an X. This pretty much ! 1024: always has to work since we can always receive a file name ! 1025: starting with X, so the system dependent code must be ! 1026: prepared to see one. */ ! 1027: zxqt = zbufcpy (qtrans->s.zto); ! 1028: zxqt[0] = 'X'; ! 1029: zxqtfile = zsysdep_spool_file_name (qdaemon->qsys, zxqt, ! 1030: (pointer) NULL); ! 1031: ubuffree (zxqt); ! 1032: ! 1033: if (zxqtfile == NULL) ! 1034: { ! 1035: urrec_free (qtrans); ! 1036: return FALSE; ! 1037: } ! 1038: ! 1039: /* We have to write via a temporary file, because otherwise ! 1040: uuxqt might pick up the file before we have finished writing ! 1041: it. */ ! 1042: e = NULL; ! 1043: ztemp = zsysdep_receive_temp (qdaemon->qsys, zxqtfile, "D.0"); ! 1044: if (ztemp != NULL) ! 1045: e = esysdep_fopen (ztemp, FALSE, FALSE, TRUE); ! 1046: ! 1047: if (e == NULL) ! 1048: { ! 1049: ubuffree (zxqtfile); ! 1050: ubuffree (ztemp); ! 1051: urrec_free (qtrans); ! 1052: return FALSE; ! 1053: } ! 1054: ! 1055: fprintf (e, "U %s %s\n", qtrans->s.zuser, qdaemon->qsys->uuconf_zname); ! 1056: fprintf (e, "F %s\n", qtrans->s.zto); ! 1057: fprintf (e, "I %s\n", qtrans->s.zto); ! 1058: if (strchr (qtrans->s.zoptions, 'N') != NULL) ! 1059: fprintf (e, "N\n"); ! 1060: if (strchr (qtrans->s.zoptions, 'Z') != NULL) ! 1061: fprintf (e, "Z\n"); ! 1062: if (strchr (qtrans->s.zoptions, 'R') != NULL) ! 1063: fprintf (e, "R %s\n", qtrans->s.znotify); ! 1064: if (strchr (qtrans->s.zoptions, 'e') != NULL) ! 1065: fprintf (e, "e\n"); ! 1066: fprintf (e, "C %s\n", qtrans->s.zcmd); ! 1067: ! 1068: fbad = FALSE; ! 1069: if (fclose (e) == EOF) ! 1070: { ! 1071: ulog (LOG_ERROR, "fclose: %s", strerror (errno)); ! 1072: (void) remove (ztemp); ! 1073: fbad = TRUE; ! 1074: } ! 1075: ! 1076: if (! fbad) ! 1077: { ! 1078: if (! fsysdep_move_file (ztemp, zxqtfile, TRUE, FALSE, FALSE, ! 1079: (const char *) NULL)) ! 1080: fbad = TRUE; ! 1081: } ! 1082: ! 1083: ubuffree (zxqtfile); ! 1084: ubuffree (ztemp); ! 1085: ! 1086: if (fbad) ! 1087: { ! 1088: urrec_free (qtrans); ! 1089: return FALSE; ! 1090: } ! 1091: } ! 1092: ! 1093: /* Prepare to send the completion string to the remote system. If ! 1094: we have not yet replied to the remote send request, we leave the ! 1095: transfer structure on the remote queue. Otherwise we add it to ! 1096: the send queue. The psendfn field will already be set. */ ! 1097: qinfo->fmoved = zerr == NULL; ! 1098: if (qinfo->freplied) ! 1099: return fqueue_send (qdaemon, qtrans); ! 1100: ! 1101: return TRUE; ! 1102: } ! 1103: ! 1104: /* Send the final confirmation string to the remote system. */ ! 1105: ! 1106: static boolean ! 1107: frec_file_send_confirm (qtrans, qdaemon) ! 1108: struct stransfer *qtrans; ! 1109: struct sdaemon *qdaemon; ! 1110: { ! 1111: struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; ! 1112: const char *zsend; ! 1113: boolean fret; ! 1114: ! 1115: if (! qinfo->fmoved) ! 1116: zsend = "CN5"; ! 1117: else if (! qdaemon->frequest_hangup) ! 1118: zsend = "CY"; ! 1119: else ! 1120: { ! 1121: #if DEBUG > 0 ! 1122: if (qdaemon->fmaster) ! 1123: ulog (LOG_FATAL, "frec_file_send_confirm: Can't happen"); ! 1124: #endif ! 1125: ! 1126: DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, ! 1127: "frec_send_file_confirm: Requesting remote to transfer control"); ! 1128: zsend = "CYM"; ! 1129: } ! 1130: ! 1131: fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, ! 1132: qtrans->ilocal, qtrans->iremote); ! 1133: ! 1134: /* Now, if that was a remote command, then when the confirmation ! 1135: message is acked we no longer have to remember that we received ! 1136: that file. */ ! 1137: if (! qinfo->flocal && qinfo->fmoved) ! 1138: usent_receive_ack (qdaemon, qtrans); ! 1139: ! 1140: urrec_free (qtrans); ! 1141: return fret; ! 1142: } ! 1143: ! 1144: /* Discard a temporary file if it is not useful. A temporary file is ! 1145: useful if it could be used to restart a receive. This is called if ! 1146: the connection is lost. It is only called if qtrans->frecfile is ! 1147: TRUE. */ ! 1148: ! 1149: boolean ! 1150: frec_discard_temp (qdaemon, qtrans) ! 1151: struct sdaemon *qdaemon; ! 1152: struct stransfer *qtrans; ! 1153: { ! 1154: struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; ! 1155: ! 1156: if ((qdaemon->ifeatures & FEATURE_RESTART) == 0 ! 1157: || qtrans->s.ztemp == NULL ! 1158: || qtrans->s.ztemp[0] != 'D' ! 1159: || strcmp (qtrans->s.ztemp, "D.0") == 0) ! 1160: (void) remove (qinfo->ztemp); ! 1161: return TRUE; ! 1162: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.