home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / top2src.zip / NODES.C < prev    next >
C/C++ Source or Header  |  2000-07-13  |  21KB  |  611 lines

  1. /******************************************************************************
  2. NODES.C      Node handling functions.
  3.  
  4.     Copyright 1993 - 2000 Paul J. Sidorsky
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License, version 2, as
  8.     published by the Free Software Foundation.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19. This module handles just about everything related to nodes.  It contains
  20. functions to manage the two node indexes (NODEIDX.TCH and NODEIDX2.TCH) as
  21. well as more user-interactive functions that show who else is in TOP.
  22. ******************************************************************************/
  23.  
  24. #include "top.h"
  25.  
  26. /* whos_in_pub() - Displays a short summary of people in current channel.
  27.    Parameters:  None.
  28.    Returns:  Nothing.
  29.    Notes:  This function is called when the user hits ENTER by itself, or
  30.            when the user enters a new channel.  Incidentally, this function is
  31.            now misnamed as it only shows people in the current channel.  The
  32.            function name is left over from before TOP had multi-channels.
  33.            The scan_pub() function shows users in all channels.
  34. */
  35. void whos_in_pub(void)
  36. {
  37. XINT ucount = 0, d; /* Flag if other users are present, counter. */
  38.  
  39. /* Refresh the index of nodes online. */
  40. check_nodes_used(TRUE);
  41.  
  42. /* Count the number of nodes in this channel. */
  43. // Should flag then abort this loop when a node is found...
  44. for (d = 0; d < MAXNODES && !ucount; d++)
  45.     {
  46.     if (activenodes[d] == 1 && d != od_control.od_node)
  47.         {
  48.         ucount = 1;
  49.         }
  50.     }
  51.  
  52. if (ucount)
  53.     {
  54.     XINT comma = 0; /* Flag for when to display a comma. */
  55.  
  56.     /* Show header. */
  57.     top_output(OUT_SCREEN, getlang("LookAround"));
  58.  
  59.     /* Loop for each node. */
  60.     for (d = 0; d < MAXNODES; d++)
  61.         {
  62.         /* Only show active nodes in our channel, except this node. */
  63.         if (activenodes[d] == 1 && d != od_control.od_node)
  64.             {
  65.             /* Display the user's handle, followed by either a separator
  66.                (usually a comma) or a prefix, depending on if this is
  67.                the first node to be shown. */
  68.             top_output(OUT_SCREEN, getlang("LookAroundList"),
  69.                        getlang(comma ? "LookAroundSep" : "LookAroundFirst"),
  70.                        handles[d].string);
  71.             /* Flag that a node has been shown so the prefix isn't used
  72.                again. */
  73.             comma = 1;
  74.             }
  75.         }
  76.     }
  77. else
  78.     {
  79.     /* Nobody's here. */
  80.     top_output(OUT_SCREEN, getlang("LookAroundNobody"));
  81.     }
  82. /* Show footer. */
  83. top_output(OUT_SCREEN, getlang("LookAroundAfter"));
  84.  
  85. return;
  86. }
  87.  
  88. /* scan_pub() - Displays who is in all of TOP (SCAN command).
  89.    Parameters:  None.
  90.    Returns:  Nothing.
  91. */
  92. void scan_pub(void)
  93. {
  94. node_idx_typ nodeinfo; /* Node data buffer. */
  95. XINT sd; /* Counter. */
  96. unsigned char chnam[51]; /* Channel name buffer. */
  97.  
  98. /* Show header. */
  99. top_output(OUT_SCREEN, getlang("ScanHeader"));
  100. top_output(OUT_SCREEN, getlang("ScanHeaderSep"));
  101.  
  102. /* The active node index (NODEIDX2.TCH) isn't used as a node's active status
  103.    can be determined directly from the node data.  Using it may save some
  104.    time but in my mind it wasn't worth the extra code. */
  105.  
  106. /* Loop for each node. */
  107. for (sd = 0; sd < MAXNODES; sd++)
  108.     {
  109.     /* If the current node to be displayed cannot possibly be in the
  110.        node index (because the index is too small), break out of the loop. */
  111.     if ((long) sd * (long) sizeof(node_idx_typ) > filelength(nidxfil))
  112.         {
  113.         break;
  114.         }
  115.     /* Clear the data buffer. */
  116.     memset(&nodeinfo, 0, sizeof(node_idx_typ));
  117.     /* If the data was loaded and the handle is not blank, display the
  118.        node. */
  119.     if (!get_node_data(sd, &nodeinfo) && nodeinfo.handle[0])
  120.         {
  121.         long tcrec; /* Channel definition number. */
  122.  
  123.         /* Attempt to find a definition for the user's channel. */
  124.         tcrec = findchannelrec(nodeinfo.channel);
  125.  
  126.         if (!nodeinfo.channellisted || (tcrec > -1 && !chan[tcrec].listed))
  127.             {
  128.             /* Don't display the channel if the user doesn't wish it or if
  129.                the channel is marked unlisted in its definition. */
  130.             strcpy(chnam,
  131.                    top_output(OUT_STRINGNF, getlang("ScanUnlistedChan")));
  132.             }
  133.         else
  134.             {
  135.             /* Display the channel shortname. */
  136.             strcpy(chnam, channelname(nodeinfo.channel));
  137.             }
  138.  
  139.         /* Effectively 0-length outbuf so the string appends below will
  140.            work properly. */
  141.         outbuf[0] = '\0';
  142.         /* Prepare task information. */
  143.         strcat(outbuf, top_output(OUT_STRINGNF,
  144.                                   getlang((nodeinfo.task & TASK_EDITING) ?
  145.                                   "ScanEditing" : "ScanNotEditing")));
  146.         strcat(outbuf, top_output(OUT_STRINGNF,
  147.                            getlang((nodeinfo.task & TASK_PRIVATECHAT) ?
  148.                            "ScanPrivChat" : "ScanNotPrivChat")));
  149.  
  150.         /* Display the node and related information. */
  151.         top_output(OUT_SCREEN, getlang("ScanInfo"), nodeinfo.handle,
  152.                    chnam, outbuf);
  153.         }
  154.     }
  155.  
  156. }
  157.  
  158. /* register_node() - Initializes the node when logging into TOP.
  159.    Parameters:  None.
  160.    Returns:  Nothing.
  161.    Notes:  Any error is considered fatal and the function will abort instead
  162.            of returning.
  163. */
  164. void register_node(void)
  165. {
  166. char tstflg; /* Flag for testing the active node index. */
  167. char tmp; /* Byte to write. */
  168. XINT res; /* Result code. */
  169.  
  170. /* Make sure the node index can hold all nodes. */
  171. chsize(nidx2fil, MAXNODES);
  172.  
  173. /* Read the active status for this node from NODEIDX2.TCH. */
  174. res = lseek(nidx2fil, od_control.od_node, SEEK_SET);
  175. if (res == -1)
  176.     {
  177.     errorabort(ERR_CANTACCESS, top_output(OUT_STRING, "@1NODEIDX2.TOP",
  178.                cfg.topworkpath));
  179.     }
  180. rec_locking(REC_LOCK, nidx2fil, od_control.od_node, 1L);
  181. res = read(nidx2fil, &tstflg, 1L);
  182. rec_locking(REC_UNLOCK, nidx2fil, od_control.od_node, 1L);
  183. if (res == -1)
  184.     {
  185.     errorabort(ERR_CANTREAD, top_output(OUT_STRING, "@1NODEIDX2.TOP",
  186.                cfg.topworkpath));
  187.     }
  188.  
  189. /* If the flag was set and the node is not solid, initialization cannot
  190.    proceed. */
  191. if (tstflg && !nodecfg->solidnode)
  192.     {
  193.     /* The node is in use and cannot be overrided, so inform the user
  194.        and quit. */
  195.     itoa(od_control.od_node, outnum[0], 10);
  196.     top_output(OUT_SCREEN, getlang("NodeInUse"), outnum[0]);
  197.     top_output(OUT_SCREEN, getlang("NodeInUseContact"));
  198.     od_log_write(top_output(OUT_STRING, getlang("LogNodeInUse"), outnum[0]));
  199.     quit_top();
  200.     }
  201.  
  202. /* If the node is solid and the flag is set, it is assumed the node
  203.    crashed on its last run, so a message is logged to let the sysop know
  204.    of a potential problem. */
  205. if (tstflg && nodecfg->solidnode)
  206.     {
  207.     od_log_write(top_output(OUT_STRING, getlang("LogPrevCrashDetect")));
  208.     }
  209.  
  210. /* Superfluous NODEIDX2 size extension. */
  211. if (filelength(nidx2fil) < MAXNODES)
  212.     {
  213.     chsize(nidx2fil, MAXNODES);
  214.     }
  215.  
  216. /* Write TRUE to this node's active byte in NODEIDX2.  This effectively logs
  217.    the node into TOP, making it visible to other nodes. */
  218. res = lseek(nidx2fil, od_control.od_node, SEEK_SET);
  219. if (res == -1)
  220.     {
  221.     errorabort(ERR_CANTACCESS, top_output(OUT_STRING, "@1NODEIDX2.TOP",
  222.                cfg.topworkpath));
  223.     }
  224. rec_locking(REC_LOCK, nidx2fil, od_control.od_node, 1L);
  225. tmp = 1;
  226. res = write(nidx2fil, &tmp, 1L);
  227. rec_locking(REC_UNLOCK, nidx2fil, od_control.od_node, 1L);
  228. if (res == -1)
  229.     {
  230.     errorabort(ERR_CANTWRITE, top_output(OUT_STRING, "@1NODEIDX2.TOP",
  231.                cfg.topworkpath));
  232.     }
  233.  
  234. /* Update the active node and active handle arrays. */
  235. activenodes[od_control.od_node] = 1;
  236. fixname(handles[od_control.od_node].string, user.handle);
  237.  
  238. /* Initialize the NODEIDX information from the user file and door kit
  239.    information. */
  240. memset(node, 0, sizeof(node_idx_typ));
  241. fixname(node->handle, user.handle);
  242. fixname(node->realname, user.realname);
  243. node->speed = od_control.baud;
  244. strcpy(node->location, od_control.user_location);
  245. node->gender = user.gender;
  246. node->channel = curchannel;
  247. node->channellisted = (user.pref2 & PREF2_CHANLISTED);
  248. node->security = user.security;
  249.  
  250. /* Write the node data to the NODEIDX. */
  251. save_node_data(od_control.od_node, node);
  252.  
  253. /* Perform any BBS-specific node initialization if needed. */
  254. if (cfg.bbstype != BBS_UNKNOWN)
  255.     {
  256.     if (bbs_call_login)
  257.         (*bbs_call_login)();
  258.     }
  259.  
  260. /* Flag the node as logged in. */
  261. isregistered = TRUE;
  262.  
  263. if (localmode || lanmode)
  264.     {
  265.     /* Under local and LAN modes, a final display of the status line
  266.        is performed, which will update the name. */
  267.     od_control.od_status_on = TRUE;
  268.     od_kernel();
  269.     od_set_statusline(STATUS_NORMAL);
  270.     od_control.od_status_on = FALSE;
  271.     }
  272.  
  273. /* Clear this node's change index byte.  This is done to block out any
  274.    old unreceived messages that may have been left over if the node
  275.    crashed. */
  276. tmp = 0;
  277. lseek(chgfil, od_control.od_node, SEEK_SET);
  278. rec_locking(REC_LOCK, chgfil, od_control.od_node, 1L);
  279. write(chgfil, &tmp, 1L);
  280. rec_locking(REC_UNLOCK, chgfil, od_control.od_node, 1L);
  281. chsize(midxinfil, 0); chsize(msginfil, 0);
  282.  
  283. /* Attempt to join the default channel. */
  284. res = cmi_join(curchannel);
  285. if (res != CMI_OKAY)
  286.     {
  287.     /* If for some reason the default channel cannot be joined, attempt to
  288.        join the user's personal channel.  This should never occur.  If the
  289.        main channel cannot be joined it likely means the CMI is unstable
  290.        (i.e. CHANIDX.TCH has been corrupted. */
  291.     res = cmi_join(4000000000UL + (unsigned long) od_control.od_node);
  292.     if (res != CMI_OKAY)
  293.         {
  294.         /* If that doesn't work it's pretty much a hopeless situation. */
  295.         top_output(OUT_SCREEN, getlang("SevereJoinError"));
  296.         od_log_write(top_output(OUT_STRING, getlang("LogSevereJoinErr")));
  297.         od_exit(230, FALSE);
  298.         }
  299.     else
  300.         {
  301.         /* We're now in the user's personal channel.  This is only a backup
  302.            condition, and as mentioned there is probably a problem with
  303.            the CMI. */
  304.         curchannel = 4000000000UL + (unsigned long) od_control.od_node;
  305.         }
  306.     }
  307.  
  308. /* Now that we are logged into TOP, time messages from the door kit can
  309.    be processed as if they were TOP messages, which looks nicer. */
  310. od_control.od_time_msg_func = sendtimemsgs;
  311.  
  312. return;
  313. }
  314.  
  315. /* unregister_node() - Logs the node out of TOP.
  316.    Parameters:  errabort - Whether or not to handle errors (see notes).
  317.    Returns:  Nothing.
  318.    Notes:  The errabort flag only controls whether the calling function
  319.            cares if an error occurs or not.  If the flag is TRUE, this
  320.            function will abort on error and display a message.  If it is
  321.            FALSE, the function simply returns.  The flag is usually set FALSE
  322.            when deregistering in an error situation.
  323. */
  324. void unregister_node(char errabort)
  325. {
  326. char tmp; /* Byte to write. */
  327. XINT res; /* Result code. */
  328. long d; /* Counter. */
  329.  
  330. /* Adjust NODEIDX2.TCH size if needed. */
  331. if (filelength(nidx2fil) < MAXNODES)
  332.     {
  333.     chsize(nidx2fil, MAXNODES);
  334.     }
  335.  
  336. /* Write FALSE to this node's byte in NODEIDX2.TCH, effectively logging
  337.    the node out of TOP and making it invisible to other nodes. */
  338. res = lseek(nidx2fil, od_control.od_node, SEEK_SET);
  339. if (res == -1)
  340.     {
  341.     if (errabort)
  342.         {
  343.         errorabort(ERR_CANTACCESS, top_output(OUT_STRING, "@1NODEIDX2.TOP",
  344.                    cfg.topworkpath));
  345.         }
  346.     return;
  347.     }
  348. rec_locking(REC_LOCK, nidx2fil, od_control.od_node, 1);
  349. tmp = 0;
  350. res = write(nidx2fil, &tmp, 1);
  351. rec_locking(REC_UNLOCK, nidx2fil, od_control.od_node, 1);
  352. if (res == -1)
  353.     {
  354.     if (errabort)
  355.         {
  356.         errorabort(ERR_CANTWRITE, top_output(OUT_STRING, "@1NODEIDX2.TOP",
  357.                    cfg.topworkpath));
  358.         }
  359.     return;
  360.     }
  361.  
  362. /* Perform any BBS-specific node deactivation if needed. */
  363. if ((cfg.bbstype != BBS_UNKNOWN) && node_added)
  364.     {
  365.     if (bbs_call_logout)
  366.         (*bbs_call_logout)();
  367.     node_added = FALSE;
  368.     }
  369.  
  370. /* Remove this node from the current channel. */
  371. cmi_unjoin(curchannel);
  372.  
  373. /* This loop iterates through all channel data in CHANIDX.TCH and removes
  374.    this node from all special node lists, so any bans and/or invites won't
  375.    carry over to the next user on this node. */
  376. for (d = 0L; d < (filelength(chidxfil) / sizeof(chan_idx_typ)); d++)
  377.     {
  378.     /* The CMI data is locked and loaded directly (rather than using
  379.        cmi_load() to save a bit of processing time. */
  380.     cmi_lock(d);
  381.     cmi_loadraw(d);
  382.     cmi_setspec(od_control.od_node, 0);
  383.     cmi_saveraw(d);
  384.     cmi_unlock(d);
  385.     }
  386.  
  387. /* Blank this node's NODEIDX data and write the blank data to disk. */
  388. memset(node, 0, sizeof(node_idx_typ));
  389. save_node_data(od_control.od_node, node);
  390.   
  391. /* Flag the node as logged off and disconnect function handlers that are
  392.    only needed when the node is logged in. */
  393. isregistered = FALSE;
  394. od_control.od_ker_exec = NULL;
  395. od_control.od_time_msg_func = NULL;
  396.  
  397. return;
  398. }
  399.  
  400. /* check_nodes_used() - Updates the active node index from NODEIDX2.TCH.
  401.    Parameters:  fatal - Whether or not to abort on error (see notes).
  402.    Returns:  Nothing.
  403.    Notes:  Like unregister_node(), this function's error handling can be
  404.            controlled with the fatal flag.  This flag should be set to TRUE
  405.            if an error is to be handled, and to FALSE if the calling
  406.            function does not care about errors.  Normally this flag is set to
  407.            TRUE when this function is called during initialization or during
  408.            important system routines like message dispatching.  It is normally
  409.            set FALSE when an updated node list is requested before displaying
  410.            information to the user (eg. SCAN command), where inaccurate
  411.            information will only cause minor problems.  The function does not
  412.            return anything for this reason.  The active node index is stored
  413.            in the global activenodes array.
  414. */
  415. void check_nodes_used(char fatal)
  416. {
  417. XINT res, d; /* Result code, counter. */
  418. node_idx_typ tnbuf; /* Node data buffer. */
  419.  
  420. /* Read the entire active node index into memory. */
  421. lseek(nidx2fil, 0L, SEEK_SET);
  422. rec_locking(REC_LOCK, nidx2fil, 0L, MAXNODES);
  423. res = read(nidx2fil, activenodes, MAXNODES);
  424. rec_locking(REC_UNLOCK, nidx2fil, 0L, MAXNODES);
  425. if (res == -1)
  426.     {
  427.     if (fatal)
  428.         {
  429.         errorabort(ERR_CANTREAD, top_output(OUT_STRING, "@1NODEIDX2.TOP",
  430.                    cfg.topworkpath));
  431.         }
  432.     return;
  433.     }
  434.  
  435. /* The lowest active node is stored but not currently used.  It was
  436.    used by poker, which was removed from TOP. */
  437. lowestnode = -1;
  438. /* This loop goes through each node and modifies the active node flag if
  439.    the node is active but not on our current channel.  This provides
  440.    function with a quick way to check if a node is in our channel or not.
  441.    It also updates the active handles index, which although is not really
  442.    needed anymore (it was left over from an older version of the TOP-to-TOP
  443.    file system) is still maintained for speed in some functions. */
  444. for (d = 0; d < MAXNODES; d++)
  445.     {
  446.     /* Blank out the node's active handle. */
  447.     memset(handles[d].string, 0, 31);
  448.     if (activenodes[d])
  449.         {
  450.         /* If the node is active, get the node data. */
  451.         if (get_node_data(d, &tnbuf) == 0)
  452.             {
  453.             /* If the data was obtained successfully, update the active
  454.                handle. */
  455.             fixname(handles[d].string, tnbuf.handle);
  456.             /* If the user's not on our channel, adjust the flag so this
  457.                condition can be detected easily. */
  458.             if (tnbuf.channel != curchannel)
  459.                 {
  460.                 activenodes[d] = 2;
  461.                 }
  462.             }
  463.         }
  464.     /* Clear the forget status for any node that is no longer active.  This
  465.        probably isn't needed but it keeps things cleaner. */
  466.     if (!activenodes[d])
  467.         {
  468.         forgetstatus[d] = 0;
  469.         }
  470.     /* Set the lowest node, which again is not currently used. */
  471.     if (activenodes[d] && lowestnode < 0)
  472.         {
  473.         lowestnode = d;
  474.         }
  475.     }
  476.  
  477. return;
  478. }
  479.  
  480. /* get_node_data() - Reads node data from NODEIDX.TCH.
  481.    Parameters:  recnum - Node number to load data for.
  482.                 nodebuf - Pointer to node data buffer.
  483.    Returns:  FALSE on success, or an ERR_ code plus one on error.
  484.    Notes:  ERR_ codes are zero based so to provide a proper boolean
  485.            return value, 1 has to be added.
  486. */
  487. char get_node_data(XINT recnum, node_idx_typ *nodebuf)
  488. {
  489. XINT res; /* Result code. */
  490.  
  491. /* This function's operation should be straightforward. */
  492.  
  493. res = lseek(nidxfil, (long) recnum * (long) sizeof(node_idx_typ), SEEK_SET);
  494. if (res == -1)
  495.     {
  496.     return (ERR_CANTACCESS + 1);
  497.     }
  498. rec_locking(REC_LOCK, nidxfil, (long) recnum * (long) sizeof(node_idx_typ),
  499.             sizeof(node_idx_typ));
  500. res = read(nidxfil, nodebuf, sizeof(node_idx_typ));
  501. rec_locking(REC_UNLOCK, nidxfil, (long) recnum * (long) sizeof(node_idx_typ),
  502.             sizeof(node_idx_typ));
  503. if (res == -1)
  504.     {
  505.     return (ERR_CANTREAD + 1);
  506.     }
  507.  
  508. return 0;
  509. }
  510.  
  511. /* save_node_data() - Saves node data to NODEIDX.TCH.
  512.    Parameters:  recnum - Node number to save data for.
  513.                 nodebuf - Pointer to node data buffer.
  514.    Returns:  Nothing.
  515.    Notes:  Errors are treated as fatal and the function will abort TOP if
  516.            one occurs.
  517. */
  518. void save_node_data(XINT recnum, node_idx_typ *nodebuf)
  519. {
  520. XINT res; /* Result code. */
  521.  
  522. /* Set the node data length for future backward compatibility. */
  523. nodebuf->structlength = sizeof(node_idx_typ);
  524.  
  525. /* The rest of this function's operation should be straightforward. */
  526.  
  527. res = lseek(nidxfil, (long) recnum * (long) sizeof(node_idx_typ), SEEK_SET);
  528. if (res == -1)
  529.     {
  530.     errorabort(ERR_CANTACCESS, top_output(OUT_STRING, "@1NODEIDX.TOP",
  531.                cfg.topworkpath));
  532.     }
  533. rec_locking(REC_LOCK, nidxfil, (long) recnum * (long) sizeof(node_idx_typ),
  534.             sizeof(node_idx_typ));
  535. res = write(nidxfil, nodebuf, sizeof(node_idx_typ));
  536. rec_locking(REC_UNLOCK, nidxfil, (long) recnum * (long) sizeof(node_idx_typ),
  537.             sizeof(node_idx_typ));
  538. if (res == -1)
  539.     {
  540.     errorabort(ERR_CANTWRITE, top_output(OUT_STRING, "@1NODEIDX.TOP",
  541.                cfg.topworkpath));
  542.     }
  543.  
  544.  return;
  545. }
  546.  
  547. /* Byte-level functions which were left over from an older TOP-to-TOP file
  548.    system that only used one node index.  They could still be used with
  549.    NODEIDX2.TCH by changing "nidxfil" to "nidx2fil".  Since
  550.    check_nodes_used() is used as a shell and handles I/O to the NODEIDX2
  551.    directly, these functions should not be needed. */
  552. /*char set_idx_byte(unsigned char value, unsigned XINT nodenum)
  553.     {
  554.     XINT res;
  555.  
  556.     res = rec_locking(REC_LOCK, nidxfil, (long) nodenum, 1L);
  557.     if (res)
  558.         {
  559.         return 0;
  560.         }
  561.     res = lseek(nidxfil, (long) nodenum, SEEK_SET);
  562.     if (res == -1)
  563.         {
  564.         res = rec_locking(REC_UNLOCK, nidxfil, (long) nodenum, 1L);
  565.         return 0;
  566.         }
  567.     res = write(nidxfil, &value, 1L);
  568.     if (res == -1)
  569.         {
  570.         res = rec_locking(REC_UNLOCK, nidxfil, (long) nodenum, 1L);
  571.         return 0;
  572.         }
  573.     res = rec_locking(REC_UNLOCK, nidxfil, (long) nodenum, 1L);
  574.     if (res)
  575.         {
  576.         return 0;
  577.         }
  578.  
  579.     return 1;
  580.     }
  581.  
  582. char get_idx_byte(unsigned char *valbuf, unsigned XINT nodenum)
  583.     {
  584.     XINT res;
  585.  
  586.     res = rec_locking(REC_LOCK, nidxfil, (long) nodenum, 1L);
  587.     if (res)
  588.         {
  589.         return 0;
  590.         }
  591.     res = lseek(nidxfil, (long) nodenum, SEEK_SET);
  592.     if (res == -1)
  593.         {
  594.         res = rec_locking(REC_UNLOCK, nidxfil, (long) nodenum, 1L);
  595.         return 0;
  596.         }
  597.     res = read(nidxfil, valbuf, 1L);
  598.     if (res == -1)
  599.         {
  600.         res = rec_locking(REC_UNLOCK, nidxfil, (long) nodenum, 1L);
  601.         return 0;
  602.         }
  603.     res = rec_locking(REC_UNLOCK, nidxfil, (long) nodenum, 1L);
  604.     if (res)
  605.         {
  606.         return 0;
  607.         }
  608.  
  609.     return 1;
  610.     }*/
  611.