home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c004 / 4.ddi / NETBIOS / CTSMSG.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-04-18  |  15.5 KB  |  744 lines

  1. /*
  2.  *    System Dependent Server Message Handling
  3.  *    Net Bios
  4.  *
  5.  *    This program is the CONFIDENTIAL and PROPRIETARY property 
  6.  *    of FairCom(R) Corporation. Any unauthorized use, reproduction or
  7.  *    transfer of this program is strictly prohibited.
  8.  *
  9.  *      Copyright (c) 1987, 1988, 1989 FairCom Corporation
  10.  *    (Subject to limited distribution and
  11.  *     restricted disclosure only.)
  12.  *    *** ALL RIGHTS RESERVED ***
  13.  *
  14.  *    4006 West Broadway
  15.  *    Columbia, MO 65203
  16.  *
  17.  *
  18.  *    c-tree(R)    Version 4.3
  19.  *            Release C
  20.  *            February 7, 1989 17:30
  21.  *
  22.  */
  23.  
  24. #include "ctstdr.h"
  25. #include "ctoptn.h"
  26. #include "ctstrc.h"
  27. #include "cterrc.h"
  28. #include "ctcomm.h"
  29.  
  30. #include "ctnbio.h"
  31. #include "ctnbcfg.h"
  32.  
  33. #ifdef FOREGROUND
  34. #include <dos.h>
  35. #endif
  36.  
  37. LOCAL UCOUNT idle  = 0;
  38. LOCAL UCOUNT kbcnt = 0;
  39. #define STRETCH    100
  40. #define KBFREQ    100
  41.  
  42. typedef struct {
  43.     short ax,bx,cx,dx,si,di,cflag;
  44.     } XREGS;
  45.  
  46. typedef struct {
  47.     short es,cs,ss,ds;
  48.     } SREGS;
  49.  
  50.  
  51. #define NOT_A_SESN 0xff        /* illegal value for session number */
  52.  
  53. #ifdef DEBUG
  54.  #ifdef LOCAL
  55.   #undef LOCAL
  56.   #define LOCAL /* */
  57.  #endif
  58. #endif
  59.  
  60. typedef struct xncb
  61. {
  62.     UCOUNT f;        /* completed flag, set to 1 by anr */
  63.     NCB    n;
  64. } XNCB;
  65.  
  66. LOCAL XNCB ncb;            /* misc netbios control block */
  67. LOCAL XNCB lstncb;        /* listen netbios control block */
  68. UTEXT srvname[] = SRV_NETNAME;    /* server network name */
  69. LOCAL COUNT namenum = 0;    /* name's number */
  70. LOCAL UTEXT *usr_to_ses;    /* xlate ctree user number to netbios ses */
  71. LOCAL TEXT *usr_to_name;    /* xlate to netbios name */
  72. LOCAL TEXT lastname[16];    /* name rcvd on TST_MSGSIZ message */
  73. LOCAL UTEXT act_ses[256];    /* 1 if session number of active session */
  74. LOCAL UCOUNT msgsiz;        /* max message size */
  75. LOCAL UCOUNT usrmax;        /* max number of users */
  76. LOCAL XNCB **rncb;        /* ptrs to recv ncbs */
  77. LOCAL XNCB **sncb;        /* ptrs to send ncbs */
  78. LOCAL UTEXT **rbuf;        /* ptrs to recv bufs */
  79. LOCAL UTEXT **sbuf;        /* ptrs to send ncbs */
  80. LOCAL UTEXT *contextbuf;    /* used by asm to save dos state */
  81.  
  82. LOCAL UCOUNT (far *fnulf)() = 0L; /* null int routine */
  83.  
  84. extern UCOUNT far fanrf();    /* int routine called when ncb cmd complete */
  85.  
  86. #ifndef FOREGROUND
  87.     extern UCOUNT far task_wait(UCOUNT);
  88.     extern UCOUNT far task_init(UTEXT far *);
  89.     extern UCOUNT far task_preinit();
  90.     extern UCOUNT far clear_task_events();
  91. #else
  92.     extern VOID far fg_init();
  93. #endif
  94.  
  95.  
  96. extern COUNT uerr_cod;
  97. extern TEXT  ct_buf[];
  98.  
  99.  
  100. TEXT *mballc();
  101.  
  102.  
  103. #ifdef FOREGROUND
  104. dlaymos()
  105. {
  106.     XREGS dr;
  107.  
  108.     dr.ax = 0x0702;
  109.     dr.bx = 0x0001;
  110.  
  111.     int86(0x38,&dr,&dr);
  112. }
  113.  
  114. #endif
  115.  
  116. /*
  117.  * hook up to the network.
  118.  */
  119.  
  120. TEXT *getmid(sizmsg, maxusr)
  121. UCOUNT         sizmsg;
  122. COUNT             maxusr;
  123. {
  124.     TEXT *retval;
  125.     UCOUNT e, i, t;
  126.     UTEXT *memcush;        /* holds alloc'd mem to be freed */
  127.                 /*   before term/stay resident */
  128.     UCOUNT ctxsize;
  129.  
  130.     uerr_cod = 0;        /* in case no error */
  131.  
  132.     usrmax = maxusr;    /* save (used when cvrting sesn to usrn) */
  133.  
  134.     /* check for netbios installed */
  135.  
  136.     if (nb_install_check()) {
  137.         uerr_cod = SSKY_ERR;
  138.         return (NULL);
  139.     }
  140.  
  141.     msgsiz = sizmsg;    /* local max msg size for start_recv's */
  142.  
  143. #ifndef FOREGROUND
  144.     /* get size of task switch buffers (rets 0 if !dos3) */
  145.     if (0 == (ctxsize = task_preinit())) {
  146.         uerr_cod = SSKY_ERR;        /* not dos 3.x */
  147.         return (NULL);
  148.     }
  149. #endif
  150.  
  151.     /* get current dir */
  152.     if (get_default_dir())
  153.         return (NULL);
  154.  
  155.     /*
  156.      * allocate
  157.      *  retval - return to ctsrvr for message buffer
  158.      *  usr_to_ses - logical user to netbios session xlate table
  159.      *  usr_to_name - logical user to netbios name table
  160.      *  rbuf (sbuf) - ptr to array of ptrs to recv (send) bufs
  161.      *  rncb (sncb) - ptr to array of ptrs to recv (send) ncbs
  162.      *  contextbuf - used by asm lang (ctstsr) for task switch
  163.      *  memcush - reserve some space for alloc's after asm lang
  164.      *            cuts off ability to get mem from OS (will be
  165.      *            freed before returning)
  166.      */
  167.     if ( (usr_to_ses = (UTEXT *) mballc(maxusr + 1, sizeof(UTEXT))) == NULL
  168.         || (usr_to_name = (TEXT *) mballc(maxusr, 16)) == NULL
  169.         || (retval = (UTEXT *) mballc(1, sizmsg + sizeof(UCOUNT))) == NULL
  170.         || (rbuf = (UTEXT **) mballc(SRV_RNCBS, sizeof(*rbuf))) == NULL
  171.         || (rncb = (XNCB **) mballc(SRV_RNCBS, sizeof(*rncb))) == NULL
  172.         || (sbuf = (UTEXT **) mballc(SRV_SNCBS, sizeof(*sbuf))) == NULL
  173.         || (sncb = (XNCB **) mballc(SRV_SNCBS, sizeof(*sncb))) == NULL
  174.         || (rbuf[0] = (UTEXT *) mballc(SRV_RNCBS, sizmsg)) == NULL
  175.         || (rncb[0] = (XNCB *) mballc(SRV_RNCBS, sizeof(XNCB))) == NULL
  176.         || (sbuf[0] = (UTEXT *) mballc(SRV_SNCBS, sizmsg)) == NULL
  177.         || (sncb[0] = (XNCB *) mballc(SRV_SNCBS, sizeof(XNCB))) == NULL
  178.         || (contextbuf = (UTEXT *) mballc(1, ctxsize)) == NULL
  179.         || (memcush = (UTEXT *) mballc(1, MEM_CUSHION)) == NULL  ) {
  180.          uerr_cod = SSPC_ERR;
  181.          return (NULL);
  182.      }
  183.  
  184.     /*
  185.      * init the usernum/sesnum xlate table
  186.      */
  187.  
  188.     memset(usr_to_ses, NOT_A_SESN, maxusr+1);
  189.  
  190.     /* first word of ctsrvr's buffer is hidden and used here to
  191.      * remember which session for last recv
  192.      */
  193.  
  194.     retval += sizeof(UCOUNT);
  195.  
  196.     /* add name to network */
  197.  
  198.     if (e = nb_addname(&ncb.n, 0, fnulf, srvname)) {
  199.         uerr_cod = SSID_ERR;
  200.         return (NULL);
  201.     }
  202.  
  203.     namenum = ncb.n.namenum;    /* used to start recvs */
  204.  
  205.     /* init listen ncb */
  206.  
  207.     start_listen();
  208.  
  209.     /* init recv ncbs */
  210.  
  211.     for (i=0; i< SRV_RNCBS; i++) {
  212.         /* finish building array of ptrs */
  213.         rncb[i] = rncb[0] + i;
  214.         rbuf[i] = rbuf[0] + i*sizmsg;
  215.         start_recv(i);        /* enable recvs */
  216.     }
  217.  
  218.     /* init send ncbs */
  219.     for (i=0; i< SRV_SNCBS; i++) {
  220.         /* finish building array of ptrs */
  221.         sncb[i] = sncb[0] + i;
  222.         sbuf[i] = sbuf[0] + i*sizmsg;
  223.         sncb[i]->f = 2;        /* 2 means free send buffer */
  224.     }
  225.  
  226.     /* fix up to allow eventual term/stay resident */
  227. #ifndef FOREGROUND
  228.     task_init((UTEXT far *) contextbuf);
  229. #else
  230.     fg_init();
  231. #endif
  232.  
  233.     free(memcush);    /* return mem for alloc users */
  234.  
  235. #ifdef FOREGROUND
  236.     display_menu();
  237. #endif
  238.  
  239.     return (retval);        
  240. }
  241.  
  242. /*
  243.  * undo the comm link
  244.  */
  245.  
  246. COUNT ridmid()
  247. {
  248.     VOID far disconnect();
  249.  
  250.     disconnect();
  251.     return (0);
  252. }
  253.  
  254.  
  255. /*
  256.  * getumsg associates logical user number with session number
  257.  * of last recv'd message.  ctsrvr use's 0 to max-1 for logged in
  258.  * users.  uses the max-th entry for temporarily remembering a user
  259.  * that, for examp., may not 'log in'.
  260.  */
  261.  
  262. LONG getumsg(pmsg, usrn, msgptr)
  263. MESSAGE     *pmsg;
  264. COUNT           usrn;
  265. TEXT            *msgptr;
  266. {
  267.     if (usrn >= 0)
  268.         usr_to_ses[usrn] = (UTEXT) * ( ((UCOUNT *) msgptr) - 1 );
  269.     if (usrn < usrmax)
  270.         cpybuf(&usr_to_name[usrn*16], lastname, 16);
  271.     return ((LONG) usr_to_ses[usrn]);
  272. }
  273.  
  274. /*
  275.  * if disconnect, call stop user
  276.  */
  277.  
  278. stpses(sesnum)
  279. UCOUNT sesnum;
  280. {
  281.     FAST COUNT usrn;
  282.  
  283.     for (usrn = 0; usrn < usrmax; usrn++)
  284.         if (sesnum == usr_to_ses[usrn]) {
  285.             usr_to_ses[usrn] = NOT_A_SESN;
  286.             stpusr(usrn);
  287.             break;
  288.         }
  289. }
  290.  
  291. /*
  292.  * when new user, stop previous login of same
  293.  */
  294.  
  295. stpname(name)
  296. TEXT * name;
  297. {
  298.     FAST COUNT usrn;
  299.  
  300.     for (usrn = 0; usrn < usrmax; usrn++)
  301.         if (NOT_A_SESN != usr_to_ses[usrn]
  302.                && !strncmp(name, &usr_to_name[usrn*16], 16)) {
  303.             usr_to_ses[usrn] = NOT_A_SESN;
  304.             stpusr(usrn);
  305.             break;
  306.         }
  307. }
  308.  
  309.  
  310. COUNT dedusr(msgid)
  311. LONG         msgid;
  312. {
  313.     return(-1);
  314. }
  315.  
  316. /*
  317.  * wait for request from user
  318.  */
  319.  
  320. COUNT ctrqst(msgadr,pmsg)
  321. PFAST TEXT **msgadr;        /* ptr to message area */
  322. MESSAGE           *pmsg;    /* ptr to message header */
  323. {
  324.     static UCOUNT nexti = 0;
  325.     FAST UCOUNT i;
  326.     FAST UCOUNT j;
  327.     FILEPARM   *fpm;
  328.  
  329.     do {
  330. #ifndef FOREGROUND
  331.         clear_task_events();    /* since going to poll all */
  332. #else
  333.         if ((++kbcnt % KBFREQ) == 0 && kbhit())
  334.             console_service();
  335. #endif
  336.         /* check if a new session established
  337.          * if so, mark in active table and restart listen
  338.          */
  339.  
  340.         if (lstncb.f) {
  341.             if (!lstncb.n.err)
  342.                 act_ses[lstncb.n.lsn] = 1;
  343.             start_listen();
  344.             idle = 0;
  345.         }
  346.  
  347.         /*
  348.          * see if any send's completed - send_done checks
  349.          * for session lost and flags send buffer as free
  350.          */
  351.  
  352.         for (i = 0; i < SRV_SNCBS; i++) {
  353.             if (sncb[i]->f == 1) {
  354.                 idle = 0;
  355.                 send_done(i);
  356.             }
  357.         }
  358.  
  359.         /*
  360.          * look for completed recv_anys - if error, then
  361.          * it means a user has disconnected so update
  362.          * active table - if no error then drop out of
  363.          * this event poll loop with i indexing the recv
  364.          * data.  note: nexti is used because heavy traffic
  365.          * might cause higher indexed buffers to never get
  366.          * serviced if always started checking with 0-th.
  367.          */
  368.  
  369.         for (i = nexti, j = 0; j < SRV_RNCBS; i++, j++) {
  370.             if (i >= SRV_RNCBS)
  371.                 i = 0;
  372.             if (rncb[i]->f == 1) {
  373.                 idle = 0;
  374.                 if (rncb[i]->n.err) {
  375.                     act_ses[rncb[i]->n.lsn] = 0;
  376.                     stpses(rncb[i]->n.lsn);
  377.                     start_recv(i);
  378.                 }
  379.                 else
  380.                     break;
  381.             }
  382.         }
  383. #ifndef FOREGROUND
  384.         if (j == SRV_RNCBS)
  385.             task_wait(0);
  386. #else
  387.         if (++idle > STRETCH)
  388.             dlaymos();
  389. #endif
  390.     } while (j == SRV_RNCBS);
  391.  
  392.     /* a receive has completed */
  393.  
  394.     nexti = i;        /* set next rncb to check */
  395.  
  396.     /* save the session number in hidden (to ctsrvr) part of
  397.      * buffer in case ctsrvr wants to associate this session
  398.      * with a user id
  399.      */
  400.  
  401.     *( ((UCOUNT *) (*msgadr)) - 1 ) = (UCOUNT) rncb[i]->n.lsn;
  402.  
  403.     /* copy message to ctsrvr's buffer */
  404.  
  405.     cpybuf(*msgadr, rbuf[i], rncb[i]->n.buflen);
  406.  
  407.     /* restart recv_any */
  408.  
  409.     start_recv(i);
  410.  
  411.     /* copy to ctsrvr's msg header buffer */
  412.  
  413.     cpybuf(pmsg, *msgadr, sizeof(MESSAGE));
  414.  
  415.     /* got a message.  if its a
  416.      * login (TST_MSGSIZ), then the user's machine name has
  417.      * been appended on the end by ctamsg.  If so, use it to
  418.      * search for duplicate user.
  419.      */
  420.  
  421.     if (pmsg->mfunc == TST_MSGSIZ && pmsg->mdlen >= 16)
  422.     {
  423.         pmsg->mdlen -= 16;
  424.         ((MESSAGE *)(*msgadr))->mdlen -=16;
  425.         /* save name for later association with usrn in getumsg */
  426.         cpybuf(lastname, *msgadr + sizeof(MESSAGE) + pmsg->mdlen, 16);
  427.         stpname(lastname);    /* kill any with same name */
  428.     }
  429.  
  430.     /* check for file name conversion to absolute */
  431.  
  432.     if (pmsg->mfunc == FN_OPNFIL || pmsg->mfunc == FN_CREDAT ||
  433.         pmsg->mfunc == FN_CREIDX || pmsg->mfunc == FN_CREMEM) {
  434.         fpm = (FILEPARM *) (((TEXT *) *msgadr) + sizeof(MESSAGE));
  435.         strcpy(ct_buf,fpm->fpnam);
  436.         fulnam(fpm->fpnam,ct_buf,MAX_NAME);
  437.     }
  438.  
  439.     return (NO_ERROR);
  440. }
  441.  
  442. /*
  443.  * send data to user
  444.  */
  445.  
  446. COUNT ctrspn(msgadr, pmsg, sizmsg, usrn)
  447. PFAST TEXT  *msgadr;
  448. MESSAGE                 *pmsg;
  449. UCOUNT               sizmsg;
  450. COUNT                   usrn;
  451. {
  452.     FAST UCOUNT i;
  453.     UCOUNT e;
  454.     UTEXT sesn;
  455.  
  456.     if (usrn < 0) {         /* signals a call from TST_STPUSR */
  457.         usrn = - (usrn + 1);
  458.         sesn = usr_to_ses[usrn];
  459.         if (usrn < usrmax)
  460.             usr_to_ses[usrn] = NOT_A_SESN;    /* user logged out */
  461.     }
  462.     else {
  463.         sesn = usr_to_ses[usrn];
  464.     }
  465.  
  466.     cpybuf(msgadr, pmsg, sizeof(MESSAGE));
  467.  
  468.     /* wait for a free send buffer */
  469.  
  470.     do {
  471.         for (i = 0; i < SRV_SNCBS; i++) {
  472.             if (sncb[i]->f == 1)
  473.                 send_done(i);
  474.             if (sncb[i]->f == 2)
  475.                 break;
  476.         }
  477. #ifndef FOREGROUND
  478.         if (i == SRV_SNCBS)
  479.             task_wait(0);    /* let others have cpu */
  480. #endif
  481.     } while (i == SRV_SNCBS);
  482.  
  483.     cpybuf(sbuf[i], msgadr, sizmsg);
  484.  
  485.     sncb[i]->f = 0;            /* flag in use and not done */
  486.  
  487.     /* start the send */
  488.     e = nb_send(&sncb[i]->n,NCBanr,fanrf,sesn,sbuf[i],sizmsg);
  489.  
  490.     if (e)
  491.         send_done(i);
  492.  
  493. /* ???? */
  494. if (e) printf("\nSend error #%d (%dx)\n",e,e);
  495.  
  496.     return (e ? (uerr_cod = SRSP_ERR) : NO_ERROR);
  497. }
  498.  
  499. /*
  500.  * check status of user - return YES if session lost
  501.  */
  502.  
  503. COUNT norspn(usrn)
  504. COUNT         usrn;
  505. {
  506.     return NO;    /* session lost always caught elsewhere */
  507. }
  508.  
  509. /*
  510.  * start asynchronous listen
  511.  */
  512.  
  513. start_listen()
  514. {
  515.     lstncb.f = 0;
  516.     nb_listen(&lstncb.n, NCBanr, fanrf, srvname, "*", NBRTO, NBSTO);
  517. }
  518.  
  519. /*
  520.  * start async receive using i-th recv ncb
  521.  */
  522.  
  523. start_recv(i)
  524. UCOUNT     i;
  525. {
  526.     rncb[i]->f = 0;
  527.     nb_recvany(&rncb[i]->n, NCBanr, fanrf, namenum, rbuf[i], msgsiz);
  528. }
  529.  
  530.  
  531. /*
  532.  * called when a send completes
  533.  * set flag that send buffer is available
  534.  */
  535.  
  536. send_done(i)
  537. UCOUNT    i;
  538. {
  539.     if (sncb[i]->n.err != 0)            /* if error then session lost */
  540.         {
  541.         act_ses[sncb[i]->n.lsn] = 0;
  542.         stpses(sncb[i]->n.lsn);
  543.         }
  544.     sncb[i]->f = 2;
  545. }
  546.  
  547.  
  548. /*
  549.  * close all sessions, cancel async commands and remove name from netbios
  550.  */
  551.  
  552. VOID far disconnect()
  553. {
  554.     UCOUNT i;
  555.  
  556.     /* let any sends in progress finish */
  557.  
  558.     do {
  559.         for (i = 0; i < SRV_SNCBS; i++) {
  560.             if (sncb[i]->f == 0) {
  561. #ifndef FOREGROUND
  562.                 task_wait(0); /* sleep while waiting */
  563. #endif
  564.                 break;
  565.             }
  566.         }
  567.     } while (i != SRV_SNCBS);
  568.  
  569.     /* wait for timeout, to make sure that not calling from
  570.      * fanrf with sync nbios command
  571.      */
  572.  
  573. #ifndef FOREGROUND
  574.     while (!task_wait(1))
  575.         ;
  576. #endif
  577.  
  578.     /* cancel the async listen */
  579.  
  580.     if (lstncb.n.doneflag == 0xff) {    /* if command was started */
  581.         nb_cancel(&ncb.n, &lstncb.n);
  582.         lstncb.n.doneflag = 0;    /* in case disconnect called again */
  583.     }
  584.  
  585.     /* close all active sessions */
  586.  
  587.     for (i=1; i<255; i++) {
  588.         if (act_ses[i]) {
  589.             act_ses[i] = 0;
  590.             nb_hangup(&ncb.n, 0, fnulf, i);
  591.         }
  592.     }
  593.  
  594.     /* cancel all recv_any's in progress */
  595.  
  596.     for (i=0; i<SRV_RNCBS; i++) {
  597.         if (rncb[i]->n.doneflag == 0xff) {    /* if was started */
  598.             nb_cancel(&ncb.n, &rncb[i]->n);
  599.             rncb[i]->n.doneflag = 0; /* in case called again */
  600.         }
  601.     }
  602.     if (namenum)
  603.         nb_delname(&ncb.n, 0, fnulf, srvname);
  604.     namenum = 0;                 /* in case called again */
  605. }
  606.  
  607. chkusrtim(usrtim,usrmap,usrtrn)
  608. LONG     *usrtim;
  609. COUNT        *usrmap;
  610. LONG               *usrtrn;
  611. {
  612.  
  613.     /* called from login */
  614.     /* note, sessions lost & duplicate sessions caught elsewhere */
  615.     return(NO_ERROR);
  616. }
  617.  
  618.  
  619. /*
  620.  * rest of code for FOREGROUND
  621.  */
  622.  
  623. #ifdef FOREGROUND
  624.  
  625. /*
  626.  * called from ctnbios.c
  627.  */
  628.  
  629. UCOUNT far do_nb(ncb)
  630. NCB          far *ncb;
  631. {
  632.     union REGS r;
  633.     struct SREGS sr;
  634.  
  635.     ncb->lana = 0;            /* always adapter 0 */
  636.  
  637.     sr.es = sr.ds = (UCOUNT) ( ((ULONG) (NCB far *) ncb) >> 16 );
  638.     r.x.bx = (UCOUNT) ncb;
  639.     int86x(0x5c, &r, &r, &sr);
  640.     return ((UCOUNT) r.h.al);
  641. }
  642.  
  643.  
  644.  
  645. /*
  646.  * dedicated server console routines
  647.  */
  648.  
  649. display_menu()
  650. {
  651.     printf("\nDedicated server active\n");
  652.     printf("\nStop or display Users (S or U)? ");
  653. }
  654.  
  655. /* called when kbhit detected */
  656. console_service()
  657. {
  658.     static COUNT pflg;    /* flag if sub-func wants next char */
  659.     static COUNT (*pfunc)(COUNT);    /* addr of sub-func */
  660.     COUNT c;
  661.  
  662.     COUNT stops(COUNT);
  663.     COUNT display_users(COUNT);
  664.  
  665.     c = getche();
  666.     printf("\n");
  667.     if (pflg) {
  668.         pflg = (*pfunc)(c);
  669.     }
  670.     else {        
  671.         switch (c) {
  672.             /* note, all functions return !0 if they want the
  673.              * next character
  674.              */
  675.         case 'S':
  676.         case 's':
  677.             pfunc = stops;
  678.             pflg = stops(0);
  679.             break;
  680.         case 'U':
  681.         case 'u':
  682.             pfunc = display_users;
  683.             pflg = display_users(0);
  684.             break;
  685.         default:
  686.             printf("Unrecognized command\n");
  687.         }
  688.     }
  689.     if (!pflg)
  690.         display_menu();
  691. }
  692.  
  693.  
  694. COUNT stops(mode)        /* returns != 0 if answer pending */
  695. COUNT mode;        /* either 0 or answer to y/n */
  696. {
  697.     FAST COUNT usrn;
  698.     COUNT had = 0;
  699.  
  700.     if (!mode) {
  701.         for (usrn = 0; usrn < usrmax; usrn++)
  702.             if (NOT_A_SESN != usr_to_ses[usrn])
  703.                 had ++;
  704.         if (had) {
  705.             printf("%d users active ... are you sure? ",had);
  706.             return (1);
  707.         }
  708.     }
  709.     else {
  710.         if (mode != 'y' && mode != 'Y')
  711.             return (0);
  712.     }
  713.     if (stpsrv(0L,1,-1)) {
  714.         printf("user has transaction in progress ... cannot stop\n");
  715.     }
  716.     else {
  717.         ridmid();
  718.         srvexit("Successful c-tree Termination",0,0);
  719.     }
  720.     return (0);
  721. }
  722.  
  723. COUNT display_users(mode)
  724. COUNT mode;    /* not used */
  725. {
  726.     FAST COUNT usrn;
  727.     COUNT had = 0;
  728.     for (usrn = 0; usrn < usrmax; usrn++)
  729.         if (NOT_A_SESN != usr_to_ses[usrn]) {
  730.             printf("%.16s\n", &usr_to_name[usrn*16]);
  731.             had ++;
  732.         }
  733.     if (!had)
  734.         printf("No");
  735.     else
  736.         printf("%d", had);
  737.     printf(" active users\n");
  738.     return (0);
  739. }
  740.  
  741. #endif
  742.  
  743. /* end of ctsmsg.c */
  744.