Annotation of coherent/g/usr/lib/uucp/tay104/trans.c, revision 1.1

1.1     ! root        1: /* trans.c
        !             2:    Routines to handle file transfers.
        !             3: 
        !             4:    Copyright (C) 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 trans_rcsid[] = "$Id: trans.c,v 1.1 93/07/30 07:54:20 bin Exp Locker: bin $";
        !            30: #endif
        !            31: 
        !            32: #include <errno.h>
        !            33: 
        !            34: #include "uudefs.h"
        !            35: #include "uuconf.h"
        !            36: #include "prot.h"
        !            37: #include "system.h"
        !            38: #include "trans.h"
        !            39: 
        !            40: /* Local functions.  */
        !            41: 
        !            42: static void utqueue P((struct stransfer **, struct stransfer *,
        !            43:                       boolean fhead));
        !            44: static void utdequeue P((struct stransfer *));
        !            45: static void utchanalc P((struct sdaemon *qdaemon, struct stransfer *qtrans));
        !            46: __inline__ static struct stransfer *qtchan P((int ichan));
        !            47: __inline__ static void utchanfree P((struct stransfer *qtrans));
        !            48: static boolean ftcharge P((struct sdaemon *qdaemon,
        !            49:                           struct stransfer *qtrans,
        !            50:                           boolean fsend, boolean fforce));
        !            51: static boolean fcheck_queue P((struct sdaemon *qdaemon));
        !            52: static boolean ftadd_cmd P((struct sdaemon *qdaemon, const char *z,
        !            53:                            size_t cdata, int iremote, boolean flast));
        !            54: static boolean fremote_hangup_reply P((struct stransfer *qtrans,
        !            55:                                       struct sdaemon *qdaemon));
        !            56: static boolean flocal_poll_file P((struct stransfer *qtrans,
        !            57:                                   struct sdaemon *qdaemon));
        !            58: 
        !            59: /* Queue of transfer structures that are ready to start which have
        !            60:    been requested by the local system.  These are only permitted to
        !            61:    start when the local system is the master.  */
        !            62: static struct stransfer *qTlocal;
        !            63: 
        !            64: /* Queue of transfer structures that are ready to start which have
        !            65:    been requested by the remote system.  These are responses to
        !            66:    commands received from the remote system, and should be started as
        !            67:    soon as possible.  */
        !            68: static struct stransfer *qTremote;
        !            69: 
        !            70: /* Queue of transfer structures that have been started and want to
        !            71:    send information.  This should be static, but the 'a' protocol
        !            72:    looks at it, at least for now.  */
        !            73: struct stransfer *qTsend;
        !            74: 
        !            75: /* Queue of transfer structures that have been started and are waiting
        !            76:    to receive information.  */
        !            77: static struct stransfer *qTreceive;
        !            78: 
        !            79: /* Queue of free transfer structures.  */
        !            80: static struct stransfer *qTavail;
        !            81: 
        !            82: /* Array of transfer structures indexed by local channel number.  This
        !            83:    is maintained for local jobs.  */
        !            84: static struct stransfer *aqTchan[IMAX_CHAN + 1];
        !            85: 
        !            86: /* Number of local channel numbers currently allocated.  */
        !            87: static int cTchans;
        !            88: 
        !            89: /* Next channel number to allocate.  */
        !            90: static int iTchan;
        !            91: 
        !            92: /* Array of transfer structures indexed by remote channel number.
        !            93:    This is maintained for remote jobs.  */
        !            94: static struct stransfer *aqTremote[IMAX_CHAN + 1];
        !            95: 
        !            96: /* A structure used to charge time to file transfers.  */
        !            97: struct scharge
        !            98: {
        !            99:   /* The transfer we are currently charging.  */
        !           100:   struct stransfer *qtrans;
        !           101:   /* The time at the last update.  */
        !           102:   long isecs;
        !           103:   long imicros;
        !           104: };
        !           105: 
        !           106: /* We are always charging one send and one receive.  */
        !           107: static struct scharge sTsend;
        !           108: static struct scharge sTreceive;
        !           109: 
        !           110: /* The minimum amount of time, in seconds, to wait between times we
        !           111:    check the spool directory, if we are busy transferring data.  If we
        !           112:    have nothing to do, we will check the spool directory regardless of
        !           113:    how long ago the last check was.  This should probably be
        !           114:    configurable.  */
        !           115: #define CCHECKWAIT (600)
        !           116: 
        !           117: /* The time we last checked the spool directory for work.  This is set
        !           118:    from the return value of ixsysdep_process_time, not ixsysdep_time,
        !           119:    for convenience in the routines which use it.  */
        !           120: static long iTchecktime;
        !           121: 
        !           122: /* The size of the command we have read so far in ftadd_cmd.  */
        !           123: static size_t cTcmdlen;
        !           124: 
        !           125: /* The structure we use when waiting for an acknowledgement of a
        !           126:    confirmed received file in fsent_receive_ack, and a list of those
        !           127:    structures.  */
        !           128: 
        !           129: struct sreceive_ack
        !           130: {
        !           131:   struct sreceive_ack *qnext;
        !           132:   char *zto;
        !           133:   char *ztemp;
        !           134:   boolean fmarked;
        !           135: };
        !           136: 
        !           137: static struct sreceive_ack *qTreceive_ack;
        !           138: 
        !           139: /* Queue up a transfer structure before *pq.  This puts it at the head
        !           140:    or the tail of the list headed by *pq.  */
        !           141: 
        !           142: static void
        !           143: utqueue (pq, q, fhead)
        !           144:      struct stransfer **pq;
        !           145:      struct stransfer *q;
        !           146:      boolean fhead;
        !           147: {
        !           148:   if (*pq == NULL)
        !           149:     {
        !           150:       *pq = q;
        !           151:       q->qprev = q->qnext = q;
        !           152:     }
        !           153:   else
        !           154:     {
        !           155:       q->qnext = *pq;
        !           156:       q->qprev = (*pq)->qprev;
        !           157:       q->qprev->qnext = q;
        !           158:       q->qnext->qprev = q;
        !           159:       if (fhead)
        !           160:        *pq = q;
        !           161:     }
        !           162:   q->pqqueue = pq;
        !           163: }
        !           164: 
        !           165: /* Dequeue a transfer structure.  */
        !           166: 
        !           167: static void
        !           168: utdequeue (q)
        !           169:      struct stransfer *q;
        !           170: {
        !           171:   if (q->pqqueue != NULL)
        !           172:     {
        !           173:       if (*(q->pqqueue) == q)
        !           174:        {
        !           175:          if (q->qnext == q)
        !           176:            *(q->pqqueue) = NULL;
        !           177:          else
        !           178:            *(q->pqqueue) = q->qnext;
        !           179:        }
        !           180:       q->pqqueue = NULL;
        !           181:     }
        !           182:   if (q->qprev != NULL)
        !           183:     q->qprev->qnext = q->qnext;
        !           184:   if (q->qnext != NULL)
        !           185:     q->qnext->qprev = q->qprev;
        !           186:   q->qprev = NULL;
        !           187:   q->qnext = NULL;
        !           188: }
        !           189: 
        !           190: /* Queue up a transfer structure requested by the local system.  */
        !           191: 
        !           192: /*ARGSIGNORED*/
        !           193: boolean
        !           194: fqueue_local (qdaemon, qtrans)
        !           195:      struct sdaemon *qdaemon;
        !           196:      struct stransfer *qtrans;
        !           197: {
        !           198:   utdequeue (qtrans);
        !           199:   utqueue (&qTlocal, qtrans, FALSE);
        !           200:   return TRUE;
        !           201: }
        !           202: 
        !           203: /* Queue up a transfer structure requested by the remote system.  The
        !           204:    stransfer structure should have the iremote field set.  We need to
        !           205:    record it, so that any subsequent data associated with this
        !           206:    channel can be routed to the right place.  */
        !           207: 
        !           208: boolean
        !           209: fqueue_remote (qdaemon, qtrans)
        !           210:      struct sdaemon *qdaemon;
        !           211:      struct stransfer *qtrans;
        !           212: {
        !           213:   DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fqueue_remote: Channel %d",
        !           214:                  qtrans->iremote);
        !           215:   if (qtrans->iremote > 0)
        !           216:     aqTremote[qtrans->iremote] = qtrans;
        !           217:   utdequeue (qtrans);
        !           218:   utqueue (&qTremote, qtrans, FALSE);
        !           219: 
        !           220:   /* We just received data for this transfer, so start charging.  */
        !           221:   return ftcharge (qdaemon, qtrans, FALSE, FALSE);
        !           222: }
        !           223: 
        !           224: /* Queue up a transfer with something to send.  */
        !           225: 
        !           226: boolean
        !           227: fqueue_send (qdaemon, qtrans)
        !           228:      struct sdaemon *qdaemon;
        !           229:      struct stransfer *qtrans;
        !           230: {
        !           231: #if DEBUG > 0
        !           232:   if (qtrans->psendfn == NULL)
        !           233:     ulog (LOG_FATAL, "fqueue_send: Bad call");
        !           234: #endif
        !           235:   utdequeue (qtrans);
        !           236:   utqueue (&qTsend, qtrans, FALSE);
        !           237: 
        !           238:   /* Since we're now going to wait to send data, don't charge this
        !           239:      transfer for receive time.  */
        !           240:   if (qtrans == sTreceive.qtrans)
        !           241:     return ftcharge (qdaemon, (struct stransfer *) NULL, FALSE, FALSE);
        !           242:   return TRUE;
        !           243: }
        !           244: 
        !           245: /* Queue up a transfer with something to receive.  */
        !           246: 
        !           247: boolean
        !           248: fqueue_receive (qdaemon, qtrans)
        !           249:      struct sdaemon *qdaemon;
        !           250:      struct stransfer *qtrans;
        !           251: {
        !           252: #if DEBUG > 0
        !           253:   if (qtrans->precfn == NULL)
        !           254:     ulog (LOG_FATAL, "fqueue_receive: Bad call");
        !           255: #endif
        !           256:   utdequeue (qtrans);
        !           257:   utqueue (&qTreceive, qtrans, FALSE);
        !           258: 
        !           259:   /* Since we are now going to wait to receive data, don't charge this
        !           260:      transfer for send time.  */
        !           261:   if (qtrans == sTsend.qtrans)
        !           262:     return ftcharge (qdaemon, (struct stransfer *) NULL, TRUE, FALSE);
        !           263:   return TRUE;
        !           264: }
        !           265: 
        !           266: /* Get a new local channel number.  */
        !           267: 
        !           268: static void
        !           269: utchanalc (qdaemon, qtrans)
        !           270:      struct sdaemon *qdaemon;
        !           271:      struct stransfer *qtrans;
        !           272: {
        !           273:   do
        !           274:     {
        !           275:       ++iTchan;
        !           276:       if (iTchan > qdaemon->qproto->cchans)
        !           277:        iTchan = 1;
        !           278:     }
        !           279:   while (aqTchan[iTchan] != NULL);
        !           280: 
        !           281:   qtrans->ilocal = iTchan;
        !           282:   aqTchan[iTchan] = qtrans;
        !           283:   ++cTchans;
        !           284: }
        !           285: 
        !           286: /* Return the transfer for a channel number.  */
        !           287: 
        !           288: __inline__
        !           289: static struct stransfer *
        !           290: qtchan (ic)
        !           291:      int ic;
        !           292: {
        !           293:   return aqTchan[ic];
        !           294: }
        !           295: 
        !           296: /* Clear the channel number for a transfer.  */
        !           297: 
        !           298: __inline__
        !           299: static void
        !           300: utchanfree (qt)
        !           301:      struct stransfer *qt;
        !           302: {
        !           303:   if (qt->ilocal != 0)
        !           304:     {
        !           305:       aqTchan[qt->ilocal] = NULL;
        !           306:       qt->ilocal = 0;
        !           307:       --cTchans;
        !           308:     }
        !           309: }
        !           310: 
        !           311: /* Allocate a new transfer structure.  */
        !           312: 
        !           313: struct stransfer *
        !           314: qtransalc (qcmd)
        !           315:      struct scmd *qcmd;
        !           316: {
        !           317:   register struct stransfer *q;
        !           318: 
        !           319:   q = qTavail;
        !           320:   if (q != NULL)
        !           321:     utdequeue (q);
        !           322:   else
        !           323:     q = (struct stransfer *) xmalloc (sizeof (struct stransfer));
        !           324:   q->qnext = NULL;
        !           325:   q->qprev = NULL;
        !           326:   q->pqqueue = NULL;
        !           327:   q->psendfn = NULL;
        !           328:   q->precfn = NULL;
        !           329:   q->pinfo = NULL;
        !           330:   q->fsendfile = FALSE;
        !           331:   q->frecfile = FALSE;
        !           332:   q->e = EFILECLOSED;
        !           333:   q->ipos = 0;
        !           334:   q->fcmd = FALSE;
        !           335:   q->zcmd = NULL;
        !           336:   q->ccmd = 0;
        !           337:   q->ilocal = 0;
        !           338:   q->iremote = 0;
        !           339:   if (qcmd != NULL)
        !           340:     {
        !           341:       q->s = *qcmd;
        !           342:       q->s.zfrom = zbufcpy (qcmd->zfrom);
        !           343:       q->s.zto = zbufcpy (qcmd->zto);
        !           344:       q->s.zuser = zbufcpy (qcmd->zuser);
        !           345:       q->s.zoptions = zbufcpy (qcmd->zoptions);
        !           346:       q->s.ztemp = zbufcpy (qcmd->ztemp);
        !           347:       q->s.znotify = zbufcpy (qcmd->znotify);
        !           348:       q->s.zcmd = zbufcpy (qcmd->zcmd);
        !           349:     }
        !           350:   else
        !           351:     {
        !           352:       q->s.zfrom = NULL;
        !           353:       q->s.zto = NULL;
        !           354:       q->s.zuser = NULL;
        !           355:       q->s.zoptions = NULL;
        !           356:       q->s.ztemp = NULL;
        !           357:       q->s.znotify = NULL;
        !           358:       q->s.zcmd = NULL;
        !           359:     }
        !           360:   q->isecs = 0;
        !           361:   q->imicros = 0;
        !           362:   q->cbytes = 0;
        !           363: 
        !           364:   return q;
        !           365: }
        !           366: 
        !           367: /* Free a transfer structure.  This does not free any pinfo
        !           368:    information that may have been allocated.  */
        !           369: 
        !           370: void
        !           371: utransfree (q)
        !           372:      struct stransfer *q;
        !           373: {
        !           374:   ubuffree (q->zcmd);
        !           375:   ubuffree ((char *) q->s.zfrom);
        !           376:   ubuffree ((char *) q->s.zto);
        !           377:   ubuffree ((char *) q->s.zuser);
        !           378:   ubuffree ((char *) q->s.zoptions);
        !           379:   ubuffree ((char *) q->s.ztemp);
        !           380:   ubuffree ((char *) q->s.znotify);
        !           381:   ubuffree ((char *) q->s.zcmd);
        !           382:   
        !           383:   utchanfree (q);    
        !           384:   if (q->iremote > 0)
        !           385:     {
        !           386:       aqTremote[q->iremote] = NULL;
        !           387:       q->iremote = 0;
        !           388:     }
        !           389: 
        !           390: #if DEBUG > 0
        !           391:   q->zcmd = NULL;
        !           392:   q->s.zfrom = NULL;
        !           393:   q->s.zto = NULL;
        !           394:   q->s.zuser = NULL;
        !           395:   q->s.zoptions = NULL;
        !           396:   q->s.ztemp = NULL;
        !           397:   q->s.znotify = NULL;
        !           398:   q->s.zcmd = NULL;
        !           399:   q->psendfn = NULL;
        !           400:   q->precfn = NULL;
        !           401: #endif
        !           402: 
        !           403:   /* Don't try to charge time to this structure any longer.  */
        !           404:   if (sTsend.qtrans == q)
        !           405:     sTsend.qtrans = NULL;
        !           406:   if (sTreceive.qtrans == q)
        !           407:     sTreceive.qtrans = NULL;
        !           408: 
        !           409:   utdequeue (q);
        !           410:   utqueue (&qTavail, q, FALSE);
        !           411: }
        !           412: 
        !           413: /* Handle timing of file tranfers.  This is called when processing
        !           414:    starts for a transfer structure.  All time up to the next call to
        !           415:    this function is charged to that transfer structure.  Sending time
        !           416:    and receiving time are charged separately.  Normally if we are
        !           417:    about to start charging the same structure we are already charging,
        !           418:    we do nothing; but if the fforce argument is TRUE, we charge the
        !           419:    time anyhow.  */
        !           420: 
        !           421: static boolean
        !           422: ftcharge (qdaemon, qtrans, fsend, fforce)
        !           423:      struct sdaemon *qdaemon;
        !           424:      struct stransfer *qtrans;
        !           425:      boolean fsend;
        !           426:      boolean fforce;
        !           427: {
        !           428:   struct scharge *qcharge, *qother;
        !           429:   long inextsecs, inextmicros;
        !           430: 
        !           431:   if (fsend)
        !           432:     {
        !           433:       qcharge = &sTsend;
        !           434:       qother = &sTreceive;
        !           435:     }
        !           436:   else
        !           437:     {
        !           438:       qcharge = &sTreceive;
        !           439:       qother = &sTsend;
        !           440:     }
        !           441: 
        !           442:   if (! fforce && qtrans == qcharge->qtrans)
        !           443:     return TRUE;
        !           444: 
        !           445:   inextsecs = ixsysdep_process_time (&inextmicros);
        !           446:   if (qcharge->qtrans != NULL)
        !           447:     {
        !           448:       qcharge->qtrans->isecs += inextsecs - qcharge->isecs;
        !           449:       qcharge->qtrans->imicros += inextmicros - qcharge->imicros;
        !           450: 
        !           451:       /* If we are charging the same structure for both send and
        !           452:         receive, update the time we are not currently charging so
        !           453:         that we don't charge twice for the same time.  */
        !           454:       if (qcharge->qtrans == qother->qtrans)
        !           455:        {
        !           456:          qother->isecs = inextsecs;
        !           457:          qother->imicros = inextmicros;
        !           458:        }         
        !           459:     }
        !           460:   
        !           461:   qcharge->qtrans = qtrans;
        !           462:   qcharge->isecs = inextsecs;
        !           463:   qcharge->imicros = inextmicros;
        !           464: 
        !           465:   /* If enough time has elapsed since the last time we checked the
        !           466:      queue, check it again.  We do this here because we have already
        !           467:      gone to the trouble of getting the time.  */
        !           468:   if (inextsecs - iTchecktime >= CCHECKWAIT)
        !           469:     {
        !           470:       if (! fcheck_queue (qdaemon))
        !           471:        return FALSE;
        !           472:     }
        !           473: 
        !           474:   return TRUE;
        !           475: }
        !           476: 
        !           477: 
        !           478: /* Gather local commands and queue them up for later processing.  Also
        !           479:    recompute time based control values.  */
        !           480: 
        !           481: boolean
        !           482: fqueue (qdaemon, pfany)
        !           483:      struct sdaemon *qdaemon;
        !           484:      boolean *pfany;
        !           485: {
        !           486:   const struct uuconf_system *qsys;
        !           487:   int bgrade;
        !           488:   struct uuconf_timespan *qlocal_size, *qremote_size;
        !           489: 
        !           490:   if (pfany != NULL)
        !           491:     *pfany = FALSE;
        !           492: 
        !           493:   qsys = qdaemon->qsys;
        !           494: 
        !           495:   /* If we are not the caller, the grade will be set during the
        !           496:      initial handshake.  */
        !           497:   if (! qdaemon->fcaller)
        !           498:     bgrade = qdaemon->bgrade;
        !           499:   else
        !           500:     {
        !           501:       long ival;
        !           502: 
        !           503:       if (! ftimespan_match (qsys->uuconf_qtimegrade, &ival,
        !           504:                             (int *) NULL))
        !           505:        bgrade = '\0';
        !           506:       else
        !           507:        bgrade = (char) ival;
        !           508:     }
        !           509: 
        !           510:   /* Determine the maximum sizes we can send and receive.  */
        !           511:   if (qdaemon->fcaller)
        !           512:     {
        !           513:       qlocal_size = qsys->uuconf_qcall_local_size;
        !           514:       qremote_size = qsys->uuconf_qcall_remote_size;
        !           515:     }
        !           516:   else
        !           517:     {
        !           518:       qlocal_size = qsys->uuconf_qcalled_local_size;
        !           519:       qremote_size = qsys->uuconf_qcalled_remote_size;
        !           520:     }
        !           521: 
        !           522:   if (! ftimespan_match (qlocal_size, &qdaemon->clocal_size, (int *) NULL))
        !           523:     qdaemon->clocal_size = (long) -1;
        !           524:   if (! ftimespan_match (qremote_size, &qdaemon->cremote_size, (int *) NULL))
        !           525:     qdaemon->cremote_size = (long) -1;
        !           526: 
        !           527:   if (bgrade == '\0')
        !           528:     return TRUE;
        !           529: 
        !           530:   if (! fsysdep_get_work_init (qsys, bgrade))
        !           531:     return FALSE;
        !           532: 
        !           533:   while (TRUE)
        !           534:     {
        !           535:       struct scmd s;
        !           536: 
        !           537:       if (! fsysdep_get_work (qsys, bgrade, &s))
        !           538:        return FALSE;
        !           539: 
        !           540:       if (s.bcmd == 'H')
        !           541:        {
        !           542:          ulog_user ((const char *) NULL);
        !           543:          break;
        !           544:        }
        !           545: 
        !           546:       if (s.bcmd == 'P')
        !           547:        {
        !           548:          struct stransfer *qtrans;
        !           549: 
        !           550:          /* A poll file.  */
        !           551:          ulog_user ((const char *) NULL);
        !           552:          qtrans = qtransalc (&s);
        !           553:          qtrans->psendfn = flocal_poll_file;
        !           554:          if (! fqueue_local (qdaemon, qtrans))
        !           555:            return FALSE;
        !           556:          continue;
        !           557:        }
        !           558: 
        !           559:       ulog_user (s.zuser);
        !           560: 
        !           561:       switch (s.bcmd)
        !           562:        {
        !           563:        case 'S':
        !           564:        case 'E':
        !           565:          if (! flocal_send_file_init (qdaemon, &s))
        !           566:            return FALSE;
        !           567:          break;
        !           568:        case 'R':
        !           569:          if (! flocal_rec_file_init (qdaemon, &s))
        !           570:            return FALSE;
        !           571:          break;
        !           572:        case 'X':
        !           573:          if (! flocal_xcmd_init (qdaemon, &s))
        !           574:            return FALSE;
        !           575:          break;
        !           576: #if DEBUG > 0
        !           577:        default:
        !           578:          ulog (LOG_FATAL, "fqueue: Can't happen");
        !           579:          break;
        !           580: #endif
        !           581:        }
        !           582:     }    
        !           583: 
        !           584:   if (pfany != NULL)
        !           585:     *pfany = qTlocal != NULL;
        !           586: 
        !           587:   iTchecktime = ixsysdep_process_time ((long *) NULL);
        !           588: 
        !           589:   return TRUE;
        !           590: }
        !           591: 
        !           592: /* Clear everything off the work queue.  This is used when the call is
        !           593:    complete, or if the call is never made.  */
        !           594: 
        !           595: void
        !           596: uclear_queue (qdaemon)
        !           597:      struct sdaemon *qdaemon;
        !           598: {
        !           599:   int i;
        !           600: 
        !           601:   usysdep_get_work_free (qdaemon->qsys);
        !           602: 
        !           603:   qTlocal = NULL;
        !           604:   qTremote = NULL;
        !           605:   qTsend = NULL;
        !           606:   qTreceive = NULL;
        !           607:   cTchans = 0;
        !           608:   iTchan = 0;
        !           609:   sTsend.qtrans = NULL;
        !           610:   sTreceive.qtrans = NULL;
        !           611:   cTcmdlen = 0;
        !           612:   qTreceive_ack = NULL;
        !           613:   for (i = 0; i < IMAX_CHAN + 1; i++)
        !           614:     {
        !           615:       aqTchan[i] = NULL;
        !           616:       aqTremote[i] = NULL;
        !           617:     }
        !           618: }
        !           619: 
        !           620: /* Recheck the work queue during a conversation.  This is only called
        !           621:    if it's been more than CCHECKWAIT seconds since the last time the
        !           622:    queue was checked.  */
        !           623: 
        !           624: static boolean
        !           625: fcheck_queue (qdaemon)
        !           626:      struct sdaemon *qdaemon;
        !           627: {
        !           628:   int cchans;
        !           629: 
        !           630:   /* Only check if we are the master, or if there are multiple
        !           631:      channels, or if we aren't already trying to get the other side to
        !           632:      hang up.  Otherwise, there's nothing we can do with any new jobs
        !           633:      we might find.  */
        !           634:   if ((qdaemon->ireliable & UUCONF_RELIABLE_FULLDUPLEX) == 0)
        !           635:     cchans = 1;
        !           636:   else
        !           637:     cchans = qdaemon->qproto->cchans;
        !           638:   if (qdaemon->fmaster
        !           639:       || cchans > 1
        !           640:       || ! qdaemon->frequest_hangup)
        !           641:     {
        !           642:       boolean fany;
        !           643: 
        !           644:       DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO,
        !           645:                      "fcheck_queue: Rechecking work queue");
        !           646:       if (! fqueue (qdaemon, &fany))
        !           647:        return FALSE;
        !           648: 
        !           649:       /* If we found something to do, and we're not the master, and we
        !           650:         don't have multiple channels to send new jobs over, try to
        !           651:         get the other side to hang up.  */
        !           652:       if (fany && ! qdaemon->fmaster && cchans <= 1)
        !           653:        qdaemon->frequest_hangup = TRUE;
        !           654:     }
        !           655: 
        !           656:   return TRUE;
        !           657: }
        !           658: 
        !           659: /* The main transfer loop.  The uucico daemon spends essentially all
        !           660:    its time in this function.  */
        !           661: 
        !           662: boolean
        !           663: floop (qdaemon)
        !           664:      struct sdaemon *qdaemon;
        !           665: {
        !           666:   int cchans;
        !           667:   boolean fret;
        !           668: 
        !           669:   /* If we are using a half-duplex line, act as though we have only a
        !           670:      single channel; otherwise we might start a send and a receive at
        !           671:      the same time.  */
        !           672:   if ((qdaemon->ireliable & UUCONF_RELIABLE_FULLDUPLEX) == 0)
        !           673:     cchans = 1;
        !           674:   else
        !           675:     cchans = qdaemon->qproto->cchans;
        !           676: 
        !           677:   fret = TRUE;
        !           678: 
        !           679:   while (! qdaemon->fhangup)
        !           680:     {
        !           681:       register struct stransfer *q;
        !           682: 
        !           683: #if DEBUG > 1
        !           684:       /* If we're doing any debugging, close the log and debugging
        !           685:         files regularly.  This will let people copy them off and
        !           686:         remove them while the conversation is in progresss.  */
        !           687:       if (iDebug != 0)
        !           688:        {
        !           689:          ulog_close ();
        !           690:          ustats_close ();
        !           691:        }
        !           692: #endif
        !           693: 
        !           694:       if (qdaemon->fmaster)
        !           695:        {
        !           696:          boolean fhangup;
        !           697: 
        !           698:          /* We've managed to become the master, so we no longer want
        !           699:             to request a hangup.  */
        !           700:          qdaemon->frequest_hangup = FALSE;
        !           701: 
        !           702:          fhangup = FALSE;
        !           703: 
        !           704:          if (qdaemon->fhangup_requested
        !           705:              && qTsend == NULL)
        !           706:            {
        !           707:              /* The remote system has requested that we transfer
        !           708:                 control by sending CYM after receiving a file.  */
        !           709:              DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO,
        !           710:                              "floop: Transferring control at remote request");
        !           711:              fhangup = TRUE;
        !           712:            }
        !           713:          else if (qTremote == NULL
        !           714:                   && qTlocal == NULL
        !           715:                   && qTsend == NULL
        !           716:                   && qTreceive == NULL)
        !           717:            {
        !           718:              /* We don't have anything to do.  Try to find some new
        !           719:                 jobs.  If we can't, transfer control.  */
        !           720:              if (! fqueue (qdaemon, (boolean *) NULL))
        !           721:                {
        !           722:                  fret = FALSE;
        !           723:                  break;
        !           724:                }
        !           725:              if (qTlocal == NULL)
        !           726:                {
        !           727:                  DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO,
        !           728:                                  "floop: No work for master");
        !           729:                  fhangup = TRUE;
        !           730:                }
        !           731:            }
        !           732: 
        !           733:          if (fhangup)
        !           734:            {
        !           735:              if (! (*qdaemon->qproto->pfsendcmd) (qdaemon, "H", 0, 0))
        !           736:                {
        !           737:                  fret = FALSE;
        !           738:                  break;
        !           739:                }
        !           740:              qdaemon->fmaster = FALSE;
        !           741:            }
        !           742:        }
        !           743: 
        !           744:       /* If we are no long the master, clear any requested hangup.  We
        !           745:         may have already hung up before checking this variable in the
        !           746:         block above.  */
        !           747:       if (! qdaemon->fmaster)
        !           748:        qdaemon->fhangup_requested = FALSE;
        !           749: 
        !           750:       /* Immediately queue up any remote jobs.  We don't need local
        !           751:         channel numbers for them, since we can disambiguate based on
        !           752:         the remote channel number.  */
        !           753:       while (qTremote != NULL)
        !           754:        {
        !           755:          q = qTremote;
        !           756:          utdequeue (q);
        !           757:          utqueue (&qTsend, q, TRUE);
        !           758:        }
        !           759: 
        !           760:       /* If we are the master, or if we have multiple channels, try to
        !           761:         queue up additional local jobs.  */
        !           762:       if (qdaemon->fmaster || cchans > 1)
        !           763:        {
        !           764:          while (qTlocal != NULL && cTchans < cchans)
        !           765:            {
        !           766:              /* We have room for an additional channel.  */
        !           767:              q = qTlocal;
        !           768:              if (! fqueue_send (qdaemon, q))
        !           769:                {
        !           770:                  fret = FALSE;
        !           771:                  break;
        !           772:                }
        !           773:              utchanalc (qdaemon, q);
        !           774:            }
        !           775:          if (! fret)
        !           776:            break;
        !           777:        }
        !           778: 
        !           779:       q = qTsend;
        !           780: 
        !           781:       if (q == NULL)
        !           782:        {
        !           783:          ulog_user ((const char *) NULL);
        !           784:          DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "floop: Waiting for data");
        !           785:          if (! (*qdaemon->qproto->pfwait) (qdaemon))
        !           786:            {
        !           787:              fret = FALSE;
        !           788:              break;
        !           789:            }
        !           790:        }
        !           791:       else
        !           792:        {
        !           793:          ulog_user (q->s.zuser);
        !           794: 
        !           795:          if (! q->fsendfile)
        !           796:            {
        !           797:              if (! ftcharge (qdaemon, q, TRUE, TRUE))
        !           798:                {
        !           799:                  fret = FALSE;
        !           800:                  break;
        !           801:                }
        !           802: 
        !           803:              if (! (*q->psendfn) (q, qdaemon))
        !           804:                {
        !           805:                  fret = FALSE;
        !           806:                  break;
        !           807:                }
        !           808:            }
        !           809:          else
        !           810:            {
        !           811:              if (! ftcharge (qdaemon, q, TRUE, FALSE))
        !           812:                {
        !           813:                  fret = FALSE;
        !           814:                  break;
        !           815:                }
        !           816: 
        !           817:              if (q->zlog != NULL)
        !           818:                {
        !           819:                  ulog (LOG_NORMAL, "%s", q->zlog);
        !           820:                  ubuffree (q->zlog);
        !           821:                  q->zlog = NULL;
        !           822:                }
        !           823: 
        !           824:              /* We can read the file in a tight loop until qTremote
        !           825:                 changes or until we have transferred the entire file.
        !           826:                 We can disregard any changes to qTlocal since we
        !           827:                 already have something to send anyhow.  */
        !           828:              while (qTremote == NULL)
        !           829:                {
        !           830:                  char *zdata;
        !           831:                  size_t cdata;
        !           832:                  long ipos;
        !           833: 
        !           834:                  zdata = (*qdaemon->qproto->pzgetspace) (qdaemon, &cdata);
        !           835:                  if (zdata == NULL)
        !           836:                    {
        !           837:                      fret = FALSE;
        !           838:                      break;
        !           839:                    }
        !           840: 
        !           841:                  if (ffileeof (q->e))
        !           842:                    cdata = 0;
        !           843:                  else
        !           844:                    {
        !           845:                      cdata = cfileread (q->e, zdata, cdata);
        !           846:                      if (ffilereaderror (q->e, cdata))
        !           847:                        {
        !           848:                          /* There is no way to report a file reading
        !           849:                             error, so we just drop the connection.  */
        !           850:                          ulog (LOG_ERROR, "read: %s", strerror (errno));
        !           851:                          fret = FALSE;
        !           852:                          break;
        !           853:                        }
        !           854:                    }
        !           855: 
        !           856:                  ipos = q->ipos;
        !           857:                  q->ipos += cdata;
        !           858:                  q->cbytes += cdata;
        !           859: 
        !           860:                  if (! (*qdaemon->qproto->pfsenddata) (qdaemon, zdata,
        !           861:                                                        cdata, q->ilocal,
        !           862:                                                        q->iremote, ipos))
        !           863:                    {
        !           864:                      fret = FALSE;
        !           865:                      break;
        !           866:                    }
        !           867: 
        !           868:                  /* It is possible that this transfer has just been
        !           869:                     cancelled.  */
        !           870:                  if (q != qTsend || ! q->fsendfile)
        !           871:                    break;
        !           872: 
        !           873:                  if (cdata == 0)
        !           874:                    {
        !           875:                      /* We must update the time now, because this
        !           876:                         call may make an entry in the statistics
        !           877:                         file.  */
        !           878:                      if (! ftcharge (qdaemon, q, TRUE, TRUE))
        !           879:                        fret = FALSE;
        !           880:                      q->fsendfile = FALSE;
        !           881:                      if (! (*q->psendfn) (q, qdaemon))
        !           882:                        fret = FALSE;
        !           883:                      break;
        !           884:                    }
        !           885:                }
        !           886: 
        !           887:              if (! fret)
        !           888:                break;
        !           889:            }
        !           890:        }
        !           891:     }
        !           892: 
        !           893:   ulog_user ((const char *) NULL);
        !           894: 
        !           895:   (void) (*qdaemon->qproto->pfshutdown) (qdaemon);
        !           896: 
        !           897:   if (fret)
        !           898:     uwindow_acked (qdaemon, TRUE);
        !           899:   else
        !           900:     ufailed (qdaemon);
        !           901: 
        !           902:   return fret;
        !           903: }
        !           904: 
        !           905: /* This is called by the protocol routines when they have received
        !           906:    some data.  If pfexit is not NULL, *pfexit should be set to TRUE if
        !           907:    the protocol receive loop should exit back to the main floop
        !           908:    routine, above.  It is only important to set *pfexit to TRUE if the
        !           909:    main loop called the pfwait entry point, so we need never set it to
        !           910:    TRUE if we just receive data for a file.  This routine never sets
        !           911:    *pfexit to FALSE.  */
        !           912: 
        !           913: boolean 
        !           914: fgot_data (qdaemon, zfirst, cfirst, zsecond, csecond, ilocal, iremote, ipos,
        !           915:           fallacked, pfexit)
        !           916:      struct sdaemon *qdaemon;
        !           917:      const char *zfirst;
        !           918:      size_t cfirst;
        !           919:      const char *zsecond;
        !           920:      size_t csecond;
        !           921:      int ilocal;
        !           922:      int iremote;
        !           923:      long ipos;
        !           924:      boolean fallacked;
        !           925:      boolean *pfexit;
        !           926: {
        !           927:   struct stransfer *q;
        !           928:   int cwrote;
        !           929:   boolean fret;
        !           930: 
        !           931:   if (fallacked && qTreceive_ack != NULL)
        !           932:     uwindow_acked (qdaemon, TRUE);
        !           933: 
        !           934:   /* Now we have to decide which transfer structure gets the data.  If
        !           935:      ilocal is -1, it means that the protocol does not know where to
        !           936:      route the data.  In that case we route it to the first transfer
        !           937:      that is waiting for data, or, if none, as a new command.  If
        !           938:      ilocal is 0, we either select based on the remote channel number
        !           939:      or we have a new command.  */
        !           940:   if (ilocal == -1 && qTreceive != NULL)
        !           941:     q = qTreceive;
        !           942:   else if (ilocal == 0 && iremote > 0 && aqTremote[iremote] != NULL)
        !           943:     q = aqTremote[iremote];
        !           944:   else if (ilocal <= 0)
        !           945:     {
        !           946:       const char *znull;
        !           947: 
        !           948:       ulog_user ((const char *) NULL);
        !           949: 
        !           950:       /* This data is part of a command.  If there is no null
        !           951:         character in the data, this string will be continued by the
        !           952:         next packet.  Otherwise this must be the last string in the
        !           953:         command, and we don't care about what comes after the null
        !           954:         byte.  */
        !           955:       znull = (const char *) memchr (zfirst, '\0', cfirst);
        !           956:       if (znull != NULL)
        !           957:        fret = ftadd_cmd (qdaemon, zfirst, (size_t) (znull - zfirst),
        !           958:                          iremote, TRUE);
        !           959:       else
        !           960:        {
        !           961:          fret = ftadd_cmd (qdaemon, zfirst, cfirst, iremote, FALSE);
        !           962:          if (fret && csecond > 0)
        !           963:            {
        !           964:              znull = (const char *) memchr (zsecond, '\0', csecond);
        !           965:              if (znull != NULL)
        !           966:                fret = ftadd_cmd (qdaemon, zsecond,
        !           967:                                  (size_t) (znull - zsecond), iremote, TRUE);
        !           968:              else
        !           969:                fret = ftadd_cmd (qdaemon, zsecond, csecond, iremote, FALSE);
        !           970:            }
        !           971:        }
        !           972: 
        !           973:       if (pfexit != NULL && (qdaemon->fhangup || qTremote != NULL))
        !           974:        *pfexit = TRUE;
        !           975: 
        !           976:       return fret;
        !           977:     }
        !           978:   else
        !           979:     {
        !           980:       /* Get the transfer structure this data is intended for.  */
        !           981: 
        !           982:       q = qtchan (ilocal);
        !           983:     }
        !           984: 
        !           985: #if DEBUG > 0
        !           986:   if (q == NULL || q->precfn == NULL)
        !           987:     {
        !           988:       ulog (LOG_ERROR, "Protocol error: %lu bytes remote %d local %d",
        !           989:            (unsigned long) (cfirst + csecond),
        !           990:            iremote, ilocal);
        !           991:       return FALSE;
        !           992:     }
        !           993: #endif
        !           994: 
        !           995:   ulog_user (q->s.zuser);
        !           996: 
        !           997:   fret = TRUE;
        !           998: 
        !           999:   /* If we're receiving a command, then accumulate it up to the null
        !          1000:      byte.  */
        !          1001:   if (q->fcmd)
        !          1002:     {
        !          1003:       const char *znull;
        !          1004: 
        !          1005:       znull = NULL;
        !          1006:       while (cfirst > 0)
        !          1007:        {
        !          1008:          size_t cnew;
        !          1009:          char *znew;
        !          1010: 
        !          1011:          znull = (const char *) memchr (zfirst, '\0', cfirst);
        !          1012:          if (znull != NULL)
        !          1013:            cnew = znull - zfirst;
        !          1014:          else
        !          1015:            cnew = cfirst;
        !          1016:          znew = zbufalc (q->ccmd + cnew + 1);
        !          1017:          memcpy (znew, q->zcmd, q->ccmd);
        !          1018:          memcpy (znew + q->ccmd, zfirst, cnew);
        !          1019:          znew[q->ccmd + cnew] = '\0';
        !          1020:          ubuffree (q->zcmd);
        !          1021:          q->zcmd = znew;
        !          1022:          q->ccmd += cnew;
        !          1023: 
        !          1024:          if (znull != NULL)
        !          1025:            break;
        !          1026: 
        !          1027:          zfirst = zsecond;
        !          1028:          cfirst = csecond;
        !          1029:          csecond = 0;
        !          1030:        }
        !          1031: 
        !          1032:       if (znull != NULL)
        !          1033:        {
        !          1034:          char *zcmd;
        !          1035:          size_t ccmd;
        !          1036: 
        !          1037:          if (! ftcharge (qdaemon, q, FALSE, TRUE))
        !          1038:            fret = FALSE;
        !          1039:          zcmd = q->zcmd;
        !          1040:          ccmd = q->ccmd;
        !          1041:          q->fcmd = FALSE;
        !          1042:          q->zcmd = NULL;
        !          1043:          q->ccmd = 0;
        !          1044:          if (! (*q->precfn) (q, qdaemon, zcmd, ccmd + 1))
        !          1045:            fret = FALSE;
        !          1046:          ubuffree (zcmd);
        !          1047:        }
        !          1048:       else
        !          1049:        {
        !          1050:          if (! ftcharge (qdaemon, q, FALSE, FALSE))
        !          1051:            fret = FALSE;
        !          1052:        }
        !          1053: 
        !          1054:       if (pfexit != NULL
        !          1055:          && (qdaemon->fhangup
        !          1056:              || qdaemon->fmaster
        !          1057:              || qTsend != NULL))
        !          1058:        *pfexit = TRUE;
        !          1059:     }
        !          1060:   else if (! q->frecfile || cfirst == 0)
        !          1061:     {
        !          1062:       /* We're either not receiving a file or the file transfer is
        !          1063:         complete.  */
        !          1064:       if (! ftcharge (qdaemon, q, FALSE, TRUE))
        !          1065:        fret = FALSE;
        !          1066:       q->frecfile = FALSE;
        !          1067:       if (! (*q->precfn) (q, qdaemon, zfirst, cfirst))
        !          1068:        fret = FALSE;
        !          1069:       if (fret && csecond > 0)
        !          1070:        return fgot_data (qdaemon, zsecond, csecond,
        !          1071:                          (const char *) NULL, (size_t) 0,
        !          1072:                          ilocal, iremote, ipos + (long) cfirst,
        !          1073:                          FALSE, pfexit);
        !          1074:       if (pfexit != NULL
        !          1075:          && (qdaemon->fhangup
        !          1076:              || qdaemon->fmaster
        !          1077:              || qTsend != NULL))
        !          1078:        *pfexit = TRUE;
        !          1079:     }
        !          1080:   else
        !          1081:     {
        !          1082:       if (! ftcharge (qdaemon, q, FALSE, FALSE))
        !          1083:        fret = FALSE;
        !          1084: 
        !          1085:       if (q->zlog != NULL)
        !          1086:        {
        !          1087:          ulog (LOG_NORMAL, "%s", q->zlog);
        !          1088:          ubuffree (q->zlog);
        !          1089:          q->zlog = NULL;
        !          1090:        }
        !          1091: 
        !          1092:       if (ipos != -1 && ipos != q->ipos)
        !          1093:        {
        !          1094:          DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO,
        !          1095:                          "fgot_data: Seeking to %ld", ipos);
        !          1096:          if (! ffileseek (q->e, ipos))
        !          1097:            {
        !          1098:              ulog (LOG_ERROR, "seek: %s", strerror (errno));
        !          1099:              fret = FALSE;
        !          1100:            }
        !          1101:          q->ipos = ipos;
        !          1102:        }
        !          1103: 
        !          1104:       if (fret)
        !          1105:        {
        !          1106:          while (cfirst > 0)
        !          1107:            {
        !          1108:              cwrote = cfilewrite (q->e, (char *) zfirst, cfirst);
        !          1109:              if (cwrote == cfirst)
        !          1110:                {
        !          1111: #if FREE_SPACE_DELTA > 0
        !          1112:                  long cfree_space;
        !          1113: 
        !          1114:                  /* Check that there is still enough space on the
        !          1115:                     disk.  If there isn't, we drop the connection,
        !          1116:                     because we have no way to abort a file transfer
        !          1117:                     in progress.  */
        !          1118:                  cfree_space = qdaemon->qsys->uuconf_cfree_space;
        !          1119:                  if (cfree_space > 0
        !          1120:                      && ((q->cbytes / FREE_SPACE_DELTA)
        !          1121:                          != (q->cbytes + cfirst) / FREE_SPACE_DELTA)
        !          1122:                      && ! frec_check_free (q, cfree_space))
        !          1123:                    {
        !          1124:                      fret = FALSE;
        !          1125:                      break;
        !          1126:                    }
        !          1127: #endif
        !          1128:                  q->cbytes += cfirst;
        !          1129:                  q->ipos += cfirst;
        !          1130:                }
        !          1131:              else
        !          1132:                {
        !          1133:                  if (cwrote < 0)
        !          1134:                    ulog (LOG_ERROR, "write: %s", strerror (errno));
        !          1135:                  else
        !          1136:                    ulog (LOG_ERROR,
        !          1137:                          "Wrote %d to file when trying to write %lu",
        !          1138:                          cwrote, (unsigned long) cfirst);
        !          1139: 
        !          1140:                  /* Any write error is almost certainly a temporary
        !          1141:                     condition, or else UUCP would not be functioning
        !          1142:                     at all.  If we continue to accept the file, we
        !          1143:                     will wind up rejecting it at the end (what else
        !          1144:                     could we do?)  and the remote system will throw
        !          1145:                     away the request.  We're better off just dropping
        !          1146:                     the connection, which is what happens when we
        !          1147:                     return FALSE, and trying again later.  */
        !          1148:                  fret = FALSE;
        !          1149:                  break;
        !          1150:                }
        !          1151: 
        !          1152:              zfirst = zsecond;
        !          1153:              cfirst = csecond;
        !          1154:              csecond = 0;
        !          1155:            }
        !          1156:        }
        !          1157: 
        !          1158:       if (pfexit != NULL && qdaemon->fhangup)
        !          1159:        *pfexit = TRUE;
        !          1160:     }
        !          1161: 
        !          1162:   return fret;
        !          1163: }
        !          1164: 
        !          1165: /* Accumulate a string into a command.  If the command is complete,
        !          1166:    start up a new transfer.  */
        !          1167: 
        !          1168: static boolean
        !          1169: ftadd_cmd (qdaemon, z, clen, iremote, flast)
        !          1170:      struct sdaemon *qdaemon;
        !          1171:      const char *z;
        !          1172:      size_t clen;
        !          1173:      int iremote;
        !          1174:      boolean flast;
        !          1175: {
        !          1176:   static char *zbuf;
        !          1177:   static size_t cbuf;
        !          1178:   size_t cneed;
        !          1179:   struct scmd s;
        !          1180: 
        !          1181:   cneed = cTcmdlen + clen + 1;
        !          1182:   if (cneed > cbuf)
        !          1183:     {
        !          1184:       zbuf = (char *) xrealloc ((pointer) zbuf, cneed);
        !          1185:       cbuf = cneed;
        !          1186:     }
        !          1187: 
        !          1188:   memcpy (zbuf + cTcmdlen, z, clen);
        !          1189:   zbuf[cTcmdlen + clen] = '\0';
        !          1190: 
        !          1191:   if (! flast)
        !          1192:     {
        !          1193:       cTcmdlen += clen;
        !          1194:       return TRUE;
        !          1195:     }
        !          1196: 
        !          1197:   /* Don't save this string for next time.  */
        !          1198:   cTcmdlen = 0;
        !          1199: 
        !          1200:   DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO,
        !          1201:                  "ftadd_cmd: Got command \"%s\"", zbuf);
        !          1202: 
        !          1203:   if (! fparse_cmd (zbuf, &s))
        !          1204:     {
        !          1205:       ulog (LOG_ERROR, "Received garbled command \"%s\"", zbuf);
        !          1206:       return TRUE;
        !          1207:     }
        !          1208: 
        !          1209:   if (s.bcmd != 'H' && s.bcmd != 'Y' && s.bcmd != 'N')
        !          1210:     ulog_user (s.zuser);
        !          1211:   else
        !          1212:     ulog_user ((const char *) NULL);
        !          1213: 
        !          1214:   switch (s.bcmd)
        !          1215:     {
        !          1216:     case 'S':
        !          1217:     case 'E':
        !          1218:       return fremote_send_file_init (qdaemon, &s, iremote);
        !          1219:     case 'R':
        !          1220:       return fremote_rec_file_init (qdaemon, &s, iremote);
        !          1221:     case 'X':
        !          1222:       return fremote_xcmd_init (qdaemon, &s, iremote);
        !          1223:     case 'H':
        !          1224:       /* This is a remote request for a hangup.  We close the log
        !          1225:         files so that they may be moved at this point.  */
        !          1226:       ulog_close ();
        !          1227:       ustats_close ();
        !          1228:       {
        !          1229:        struct stransfer *q;
        !          1230: 
        !          1231:        q = qtransalc ((struct scmd *) NULL);
        !          1232:        q->psendfn = fremote_hangup_reply;
        !          1233:        q->iremote = iremote;
        !          1234:        return fqueue_remote (qdaemon, q);
        !          1235:       }
        !          1236:     case 'N':
        !          1237:       /* This means a hangup request is being denied; we just ignore
        !          1238:         this and wait for further commands.  */
        !          1239:       return TRUE;
        !          1240:     case 'Y':
        !          1241:       /* This is a remote confirmation of a hangup.  We reconfirm.  */
        !          1242:       if (qdaemon->fhangup)
        !          1243:        return TRUE;
        !          1244: #if DEBUG > 0
        !          1245:       if (qdaemon->fmaster)
        !          1246:        ulog (LOG_ERROR, "Got hangup reply as master");
        !          1247: #endif
        !          1248:       /* Don't check errors rigorously here, since the other side
        !          1249:         might jump the gun and hang up.  The fLog_sighup variable
        !          1250:         will get set TRUE again when the port is closed.  */
        !          1251:       fLog_sighup = FALSE;
        !          1252:       (void) (*qdaemon->qproto->pfsendcmd) (qdaemon, "HY", 0, iremote);
        !          1253:       qdaemon->fhangup = TRUE;
        !          1254:       return TRUE;
        !          1255: #if DEBUG > 0
        !          1256:     default:
        !          1257:       ulog (LOG_FATAL, "ftadd_cmd: Can't happen");
        !          1258:       return FALSE;
        !          1259: #endif
        !          1260:     }
        !          1261: }
        !          1262: 
        !          1263: /* The remote system is requesting a hang up.  If we have something to
        !          1264:    do, send an HN.  Otherwise send two HY commands (the other side is
        !          1265:    presumed to send an HY command between the first and second, but we
        !          1266:    don't bother to wait for it) and hang up.  */
        !          1267: 
        !          1268: static boolean
        !          1269: fremote_hangup_reply (qtrans, qdaemon)
        !          1270:      struct stransfer *qtrans;
        !          1271:      struct sdaemon *qdaemon;
        !          1272: {
        !          1273:   boolean fret;
        !          1274: 
        !          1275:   utransfree (qtrans);
        !          1276: 
        !          1277:   if (qTremote == NULL
        !          1278:       && qTlocal == NULL
        !          1279:       && qTsend == NULL
        !          1280:       && qTreceive == NULL)
        !          1281:     {
        !          1282:       if (! fqueue (qdaemon, (boolean *) NULL))
        !          1283:        return FALSE;
        !          1284: 
        !          1285:       if (qTlocal == NULL)
        !          1286:        {
        !          1287:          DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "fremote_hangup_reply: No work");
        !          1288:          fret = ((*qdaemon->qproto->pfsendcmd) (qdaemon, "HY", 0, 0)
        !          1289:                  && (*qdaemon->qproto->pfsendcmd) (qdaemon, "HY", 0, 0));
        !          1290:          qdaemon->fhangup = TRUE;
        !          1291:          return fret;
        !          1292:        }
        !          1293:     }
        !          1294: 
        !          1295:   DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "fremote_hangup_reply: Found work");
        !          1296:   fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, "HN", 0, 0);
        !          1297:   qdaemon->fmaster = TRUE;
        !          1298:   return fret;
        !          1299: }
        !          1300: 
        !          1301: /* As described in system.h, we need to keep track of which files have
        !          1302:    been successfully received for which we do not know that the other
        !          1303:    system has received our acknowledgement.  This routine is called to
        !          1304:    keep a list of such files.  */
        !          1305: 
        !          1306: static struct sreceive_ack *qTfree_receive_ack;
        !          1307: 
        !          1308: void
        !          1309: usent_receive_ack (qdaemon, qtrans)
        !          1310:      struct sdaemon *qdaemon;
        !          1311:      struct stransfer *qtrans;
        !          1312: {
        !          1313:   struct sreceive_ack *q;
        !          1314: 
        !          1315:   if (qTfree_receive_ack == NULL)
        !          1316:     q = (struct sreceive_ack *) xmalloc (sizeof (struct sreceive_ack));
        !          1317:   else
        !          1318:     {
        !          1319:       q = qTfree_receive_ack;
        !          1320:       qTfree_receive_ack = q->qnext;
        !          1321:     }
        !          1322: 
        !          1323:   q->qnext = qTreceive_ack;
        !          1324:   q->zto = zbufcpy (qtrans->s.zto);
        !          1325:   q->ztemp = zbufcpy (qtrans->s.ztemp);
        !          1326:   q->fmarked = FALSE;
        !          1327: 
        !          1328:   qTreceive_ack = q;
        !          1329: }
        !          1330: 
        !          1331: /* This routine is called by the protocol code when either all
        !          1332:    outstanding data has been acknowledged or one complete window has
        !          1333:    passed.  It may be called directly by the protocol, or it may be
        !          1334:    called via fgot_data.  If one complete window has passed, then all
        !          1335:    unmarked receives are marked, and we know that all marked ones have
        !          1336:    been acked.  */
        !          1337: 
        !          1338: void
        !          1339: uwindow_acked (qdaemon, fallacked)
        !          1340:      struct sdaemon *qdaemon;
        !          1341:      boolean fallacked;
        !          1342: {
        !          1343:   register struct sreceive_ack **pq;
        !          1344: 
        !          1345:   pq = &qTreceive_ack;
        !          1346:   while (*pq != NULL)
        !          1347:     {
        !          1348:       if (fallacked || (*pq)->fmarked)
        !          1349:        {
        !          1350:          struct sreceive_ack *q;
        !          1351: 
        !          1352:          q = *pq;
        !          1353:          (void) fsysdep_forget_reception (qdaemon->qsys, q->zto,
        !          1354:                                           q->ztemp);
        !          1355:          ubuffree (q->zto);
        !          1356:          ubuffree (q->ztemp);
        !          1357:          *pq = q->qnext;
        !          1358:          q->qnext = qTfree_receive_ack;
        !          1359:          qTfree_receive_ack = q;
        !          1360:        }
        !          1361:       else
        !          1362:        {
        !          1363:          (*pq)->fmarked = TRUE;
        !          1364:          pq = &(*pq)->qnext;
        !          1365:        }
        !          1366:     }
        !          1367: }
        !          1368: 
        !          1369: /* This routine is called when an error occurred and we are crashing
        !          1370:    out of the connection.  It is used to report statistics on failed
        !          1371:    transfers to the statistics file, and it also discards useless
        !          1372:    temporary files for file receptions.  Note that the number of bytes
        !          1373:    we report as having been sent has little or nothing to do with the
        !          1374:    number of bytes the remote site actually received.  */
        !          1375: 
        !          1376: void
        !          1377: ufailed (qdaemon)
        !          1378:      struct sdaemon *qdaemon;
        !          1379: {
        !          1380:   register struct stransfer *q;
        !          1381: 
        !          1382:   /* Update the transfer times, but avoid looking in the queue.  */
        !          1383:   iTchecktime = ixsysdep_process_time ((long *) NULL);
        !          1384:   (void) ftcharge (qdaemon, (struct stransfer *) NULL, TRUE, TRUE);
        !          1385:   (void) ftcharge (qdaemon, (struct stransfer *) NULL, FALSE, TRUE);
        !          1386: 
        !          1387:   if (qTsend != NULL)
        !          1388:     {
        !          1389:       q = qTsend;
        !          1390:       do
        !          1391:        {
        !          1392:          if ((q->fsendfile || q->frecfile)
        !          1393:              && q->cbytes > 0)
        !          1394:            ustats (FALSE, q->s.zuser, qdaemon->qsys->uuconf_zname,
        !          1395:                    q->fsendfile, q->cbytes, q->isecs, q->imicros,
        !          1396:                    FALSE);
        !          1397:          if (q->frecfile)
        !          1398:            (void) frec_discard_temp (qdaemon, q);
        !          1399:          q = q->qnext;
        !          1400:        }
        !          1401:       while (q != qTsend);
        !          1402:     }
        !          1403: 
        !          1404:   if (qTreceive != NULL)
        !          1405:     {
        !          1406:       q = qTreceive;
        !          1407:       do
        !          1408:        {
        !          1409:          if ((q->fsendfile || q->frecfile)
        !          1410:              && q->cbytes > 0)
        !          1411:            ustats (FALSE, q->s.zuser, qdaemon->qsys->uuconf_zname,
        !          1412:                    q->fsendfile, q->cbytes, q->isecs, q->imicros,
        !          1413:                    FALSE);
        !          1414:          if (q->frecfile)
        !          1415:            (void) frec_discard_temp (qdaemon, q);
        !          1416:          q = q->qnext;
        !          1417:        }
        !          1418:       while (q != qTreceive);
        !          1419:     }
        !          1420: }
        !          1421: 
        !          1422: /* When a local poll file is found, it is entered on the queue like
        !          1423:    any other job.  When it is pulled off the queue, this function is
        !          1424:    called.  It just calls fsysdep_did_work, which will remove the poll
        !          1425:    file.  This ensures that poll files are only removed if the system
        !          1426:    is actually called.  */
        !          1427: 
        !          1428: /*ARGSUSED*/
        !          1429: static boolean
        !          1430: flocal_poll_file (qtrans, qdaemon)
        !          1431:      struct stransfer *qtrans;
        !          1432:      struct sdaemon *qdaemon;
        !          1433: {
        !          1434:   boolean fret;
        !          1435: 
        !          1436:   fret = fsysdep_did_work (qtrans->s.pseq);
        !          1437:   utransfree (qtrans);
        !          1438:   return fret;
        !          1439: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.