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

  1. /******************************************************************************
  2. USER.C       User management 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 contains functions that manipulate the user file.  It also contains
  20. functions like the user search function and the new user signup function.
  21. ******************************************************************************/
  22.  
  23. #include "top.h"
  24.  
  25. /* The user login procedure writes to the debug log. */
  26. extern void wdl(char *msg);
  27.  
  28. /* search_for_user() - Displays welcome and finds a user in USERS.TOP.
  29.    Parameters:  None.
  30.    Returns:  Nothing.
  31.    Notes:  The actual user searching has been moved to the
  32.            find_user_from_name() function, leaving this function somewhat
  33.            misnamed.  This function is intended to be called after the
  34.            initialization has been completed.
  35. */
  36. void search_for_user(void)
  37. {
  38. char tmp[256]; /* Temporary input buffer. */
  39. #if defined(__OS2__) || defined(__WIN32__)
  40. struct date mydate; /* 2-byte int date holder for 32 bit systems. */
  41. #endif
  42.  
  43. wdl("User search function has begun");
  44.  
  45. welcomescreen();
  46.  
  47. wdl("Welcome screen displayed");
  48.  
  49. if (localmode || lanmode)
  50.     {
  51.     char tfix; /* Temporary name fix flag.  Used but has no effect. */
  52.  
  53.     /* Since local and LAN modes do not use a drop file, the user must
  54.        be asked to enter a name. */
  55.     do
  56.         {
  57.         top_output(OUT_SCREEN, getlang("EnterName"));
  58.         od_input_str(tmp, 30, ' ', MAXASCII);
  59.         }
  60.     while(!tmp[0] || censorinput(tmp));
  61.     filter_string(tmp, tmp);
  62.     trim_string(od_control.user_name, tmp, 0);
  63.     /* Local users are usually sysops so they are given the highest
  64.        possible security to start.  If the user is later found in the
  65.        user file, their normal security value will be used instead of
  66.        65535. */
  67.     user.security = 65535;
  68.     /* There were plans to make name fixing configurable until some
  69.        problems occured relating to the door kit.  This section
  70.        is supposed to temporarily override the configured setting to
  71.        force fixing of the user's real name, which it does, but obviously
  72.        with there being no FixNames setting available to the user in
  73.        TOP.CFG there is no need to temporarily preserve the value. */
  74.     tfix = cfg.fixnames;
  75.     cfg.fixnames = 1;
  76.     fixname(od_control.user_name, od_control.user_name);
  77.     cfg.fixnames = tfix;
  78.     od_log_write(top_output(OUT_STRING, getlang("LogNameUsed"),
  79.                  od_control.user_name));
  80. wdl("Local name obtained from user");
  81.     }
  82. else wdl("Local name not needed");
  83.  
  84. fixname(od_control.user_name, od_control.user_name);
  85. top_output(OUT_SCREEN, getlang("Searching"), od_control.user_name);
  86.  
  87. wdl("Pre-search completed");
  88.  
  89. /* Find the user in the user file.  As mentioned in the notes, this was
  90.    previously done directly inside this function.  However, as TOP's
  91.    development progressed the need arose for user name searching to occur
  92.    elsewhere, so it was functionalized for efficiency. */
  93. user_rec_num = find_user_from_name(od_control.user_name, &user,
  94.                                    UFIND_REALNAME);
  95.  
  96. wdl("User search completed");
  97.  
  98. if (user_rec_num < 0)
  99.     {
  100.     /* No valid user record found. */
  101.  
  102. wdl("New user - running new user function");
  103.     user_rec_num = filelength(userfil) / sizeof(user_data_typ);
  104.     make_new_user(user_rec_num);
  105.     }
  106. else
  107.     {
  108.     /* User record found. */
  109.  
  110.     XINT tries = 0;
  111. wdl("Old user found");
  112.  
  113.     /* Get the user's TOP password if one exists. */
  114.     if (user.password[0])
  115.            {
  116.         do
  117.             {
  118.             top_output(OUT_SCREEN, getlang("EnterPW"));
  119.             get_password(tmp, 15);
  120.             if (stricmp(user.password, tmp))
  121.                 {
  122.                 top_output(OUT_SCREEN, getlang("InvalidPW"));
  123.                 tries++;
  124.                 }
  125.             }
  126.         while(stricmp(user.password, tmp) && tries < MAXPWTRIES);
  127.         if (tries == MAXPWTRIES)
  128.             {
  129.             itoa(MAXPWTRIES, outnum[0], 10);
  130.             top_output(OUT_SCREEN, getlang("MaxPW"), outnum[0]);
  131.             od_log_write(top_output(OUT_STRING, getlang("LogMaxPW")));
  132.             quit_top();
  133.             }
  134. wdl("Password obtained from user");
  135.         }
  136. else wdl("No password needed");
  137.  
  138.     fixname(user.handle, user.handle);
  139.     itoa(user_rec_num + 1, outnum[0], 10);
  140.     itoa(calc_days_ago(&user.last_use), outnum[1], 10);
  141.     top_output(OUT_SCREEN, getlang("Greeting"), user.handle,
  142.                outnum[0], outnum[1]);
  143.     top_output(OUT_SCREEN, getlang("Setup"));
  144.     }
  145.  
  146. wdl("Greeting displayed - now setting up");
  147.  
  148. #if defined(__OS2__) || defined(__WIN32__)
  149. /* OS/2's and Win95's date struct use regular int variables, which under
  150.    those compilers are 4-bytes long.  However, USERS.TOP stores a date
  151.    with 2-byte int variables.  This is solved by simple assignment from
  152.    a temporary 4-byte int date. */
  153. getdate(&mydate);
  154. /* The user file uses a 2-byte int XDATE struct, as defined in TOP.H. */
  155. user.last_use.da_year = mydate.da_year;
  156. user.last_use.da_day = mydate.da_day;
  157. user.last_use.da_mon = mydate.da_mon;
  158. #else
  159. getdate(&user.last_use);
  160. #endif
  161.  
  162. /* More code related to configurable name fixing. */
  163. /*if (forcefix)
  164.     {
  165.     if (cfg.allownewhandles)
  166.         {
  167.         if (!stricmp(user.handle, od_control.user_handle))
  168.             {
  169.             if (strcmp(user.handle, od_control.user_handle))
  170.                 {
  171.                 strcpy(user.handle, od_control.user_handle);
  172.                 }
  173.             }
  174.         else
  175.             {
  176.             if (!stricmp(user.handle, od_control.user_name))
  177.                 {
  178.                 if (strcmp(user.handle, od_control.user_name))
  179.                     {
  180.                     strcpy(user.handle, od_control.user_name);
  181.                     }
  182.                 }
  183.             }
  184.         }
  185.     else
  186.         {
  187.         if (cfg.allowhandles && od_control.user_handle[0])
  188.             {
  189.             if (!stricmp(user.handle, od_control.user_handle))
  190.                 {
  191.                 if (strcmp(user.handle, od_control.user_handle))
  192.                     {
  193.                     strcpy(user.handle, od_control.user_handle);
  194.                     }
  195.                 }
  196.             }
  197.         else
  198.             {
  199.             if (!stricmp(user.handle, od_control.user_name))
  200.                 {
  201.                 if (strcmp(user.handle, od_control.user_name))
  202.                     {
  203.                     strcpy(user.handle, od_control.user_name);
  204.                     }
  205.                 }
  206.             }
  207.         }
  208.     }*/
  209.  
  210. save_user_data(user_rec_num, &user);
  211. wdl("User data updated");
  212.  
  213. /* Force the user to fill out their bio before proceeding if the sysop has
  214.    so configured. */
  215. if (cfg.forcebio)
  216.     {
  217.     if (!biocheckalldone())
  218.         {
  219.         top_output(OUT_SCREEN, getlang("BioForcePrefix"));
  220.         while(biogetall() != numbioques)
  221.             {
  222.             top_output(OUT_SCREEN, getlang("BioForceAllNotDone"));
  223.             }
  224.         }
  225.     }
  226.  
  227. /* Initialize personal actions. */
  228. if (!loadpersactions())
  229.     {
  230.     od_exit(206, FALSE);
  231.     }
  232. register_node();
  233. wdl("Node registered and logged in");
  234. od_log_write(top_output(OUT_STRING, getlang("LogHandle"), user.handle));
  235.  
  236. wdl("Post-registry completed");
  237.  
  238. if (localmode || lanmode)
  239.     {
  240.     /* Force some door kit variables in local/LAN mode. */
  241.     od_control.user_timelimit = 1440;
  242.     od_control.user_security = user.security;
  243.     od_control.od_status_on = TRUE;
  244.     /* Update the status line one last time to show the user's real name
  245.        and location. */
  246.     od_set_statusline(STATUS_NONE);
  247.     trim_string(od_control.user_location, od_control.user_location, 0);
  248.     od_set_statusline(STATUS_NORMAL);
  249.     od_kernel();
  250.     od_control.od_status_on = FALSE;
  251. wdl("Secondary local init completed");
  252.     }
  253. else wdl("No local init needed");
  254.  
  255. wdl("User search completed");
  256. wdl("If TOP made it here, everything should be okay");
  257.  
  258. return;
  259. }
  260.  
  261. /* load_user_data() - Loads a user record from USERS.TOP.
  262.    Parameters:  recnum - Record number (0-based) of user to load.
  263.                 buffer - Pointer to buffer to hold user data.
  264.    Returns:  TRUE on success, FALSE if an error occurred.
  265. */
  266. char load_user_data(XINT recnum, user_data_typ *buffer)
  267. {
  268. XINT res; /* Result code. */
  269.  
  270. /* Abort if the user file can't possibly contain the requested record
  271.    because it is too small. */
  272. if (filelength(userfil) <= (long) recnum * (long) sizeof(user_data_typ))
  273.     {
  274.     return 0;
  275.     }
  276.  
  277. /* Read in user data. */
  278. res = lseek(userfil, (long) recnum * (long) sizeof(user_data_typ), SEEK_SET);
  279. if (res == -1)
  280.     {
  281.     return 0;
  282.     }
  283. rec_locking(REC_LOCK, userfil, (long) recnum * (long) sizeof(user_data_typ),
  284.             sizeof(user_data_typ));
  285. res = read(userfil, buffer, sizeof(user_data_typ));
  286. rec_locking(REC_UNLOCK, userfil, (long) recnum * (long) sizeof(user_data_typ),
  287.             sizeof(user_data_typ));
  288. if (res == -1)
  289.     {
  290.     return 0;
  291.     }
  292.  
  293. return 1;
  294. }
  295.  
  296. /* save_user_data() - Saves a user record to USERS.TOP.
  297.    Parameters:  recnum - Record number (0-based) of user to save.
  298.                 buffer - Pointer to buffer holding user data.
  299.    Returns:  TRUE on success, FALSE if an error occurred.
  300. */
  301. char save_user_data(XINT recnum, user_data_typ *buffer)
  302. {
  303. XINT res; /* Result code. */
  304.  
  305. /* Write the data. */
  306. res = lseek(userfil, (long) recnum * (long) sizeof(user_data_typ),
  307.             SEEK_SET);
  308. if (res == -1)
  309.     {
  310.     return 0;
  311.     }
  312. rec_locking(REC_LOCK, userfil, (long) recnum * (long) sizeof(user_data_typ),
  313.             sizeof(user_data_typ));
  314.  
  315. res = write(userfil, buffer, sizeof(user_data_typ));
  316. rec_locking(REC_UNLOCK, userfil, (long) recnum * (long) sizeof(user_data_typ),
  317.             sizeof(user_data_typ));
  318. if (res == -1)
  319.     {
  320.     return 0;
  321.     }
  322.  
  323. return 1;
  324. }
  325.  
  326. /* make_new_user() - New user signup function.
  327.    Parameters:  recnum - User file record number to hold new user data.
  328.    Returns:  Nothing.
  329. */
  330. void make_new_user(XINT recnum)
  331. {
  332. XINT res; /* Result code. */
  333. char mtmp[256]; /* Temporary input buffer. */
  334. #if defined(__OS2__) || defined(__WIN32__)
  335. struct date mydate; /* 2-byte int date holder for 32 bit systems. */
  336. #endif
  337.  
  338. memset(&user, 0, sizeof(user_data_typ));
  339.  
  340. top_output(OUT_SCREEN, getlang("NewUserScrnPrefix"));
  341. newuserscreen();
  342. od_log_write(top_output(OUT_STRING, getlang("LogStartSignOn")));
  343.  
  344. if (cfg.allownewhandles)
  345.     {
  346.     /* Ask the user for a new handle. */
  347.  
  348.     /* Loop until a valid handle is input. */
  349.     do
  350.         {
  351.         do
  352.             {
  353.             top_output(OUT_SCREEN, getlang("EnterHandle"));
  354.             od_input_str(user.handle, 30, ' ', MAXASCII);
  355.             }
  356.         while(censorinput(user.handle));
  357.  
  358.         fixname(user.handle, user.handle);
  359.  
  360.         /* Abort if the user just hits ENTER. */
  361.         if (user.handle[0] == '\0')
  362.             {
  363.             od_log_write(top_output(OUT_STRING, getlang("LogAbortSignOn")));
  364.             quit_top();
  365.             }
  366.  
  367.         trim_string(user.handle, user.handle, 0);
  368.         res = check_dupe_handles(user.handle);
  369.         if (res)
  370.             {
  371.             top_output(OUT_SCREEN, getlang("HandleInUse"));
  372.             }
  373.         }
  374.     while(res);
  375.     }
  376. else
  377.     {
  378.     /* Select the right name (real or handle) to use based on how TOP is
  379.        configured. */
  380.     if (cfg.allowhandles && od_control.user_handle[0])
  381.         {
  382.         fixname(user.handle, od_control.user_handle);
  383.         }
  384.     else
  385.         {
  386.         fixname(user.handle, od_control.user_name);
  387.         }
  388.     }
  389.  
  390. /* User description is no longer used. */
  391. /* memset(user.description, '\0', 61); */
  392.  
  393. /* Under local and LAN modes it is possible for any user to login under any
  394.    name so to protect new users signing on in these modes, TOP will ask for
  395.    a password. */
  396. if (localmode || lanmode)
  397.     {
  398.     XINT pwok = 0; /* Flag if the password is confirmed. */
  399.  
  400.     do
  401.         {
  402.         top_output(OUT_SCREEN, getlang("EnterNewPW"));
  403.         get_password(user.password, 15);
  404.         top_output(OUT_SCREEN, getlang("ConfirmPW"));
  405.         get_password(mtmp, 15);
  406.         if (stricmp(user.password, mtmp))
  407.             {
  408.             top_output(OUT_SCREEN, getlang("PWNoMatch"));
  409.             pwok = 0;
  410.             }
  411.         else
  412.             {
  413.             pwok = 1;
  414.             }
  415.         }
  416.     while(!pwok);
  417.     top_output(OUT_SCREEN, getlang("LocalLANStartPref"));
  418.     }
  419.  
  420. user.gender = 0;
  421.  
  422. /* Under CHAIN.TXT and RA 2.xx's EXITINFO.BBS, the user's gender is
  423.    included in the drop file so there is no need to ask. */
  424. if (od_control.od_info_type != RA2EXITINFO &&
  425.     od_control.od_info_type != CHAINTXT)
  426.     {
  427.     top_output(OUT_SCREEN, getlang("GenderPrompt"));
  428.     od_control.user_sex = od_get_answer(getlang("GenderKeys"));
  429.     if (od_control.user_sex == getlangchar("GenderKeys", 1))
  430.         {
  431.         top_output(OUT_SCREEN, getlang("Female"));
  432.         }
  433.     if (od_control.user_sex == getlangchar("GenderKeys", 0))
  434.         {
  435.         top_output(OUT_SCREEN, getlang("Male"));
  436.         }
  437.     top_output(OUT_SCREEN, getlang("GenderPromptSuffix"));
  438.     }
  439. if (od_control.user_sex == getlangchar("GenderKeys", 1))
  440.        {
  441.     user.gender = 1;
  442.     }
  443. if (od_control.user_sex == getlangchar("GenderKeys", 0))
  444.        {
  445.     user.gender = 0;
  446.     }
  447.  
  448. /* User description is no longer used. */
  449. /*top_output(OUT_SCREEN, getlang("EnterDescPrompt"));
  450. od_input_str(user.description, 60, ' ', MAXASCII);*/
  451.  
  452. top_output(OUT_SCREEN, getlang("Creating"));
  453.  
  454. /*trim_string(user.description, user.description, 0);*/
  455. // trim_string(user.realname, user.realname, 0);
  456. fixname(user.realname, od_control.user_name);
  457.  
  458. /* See search_for_user() for explanation of this section. */
  459. #if defined(__OS2__) || defined(__WIN32__)
  460. getdate(&mydate);
  461. user.last_use.da_year = mydate.da_year;
  462. user.last_use.da_day = mydate.da_day;
  463. user.last_use.da_mon = mydate.da_mon;
  464. #else
  465. getdate(&user.last_use);
  466. #endif
  467.  
  468. /* Original preferences from before they were configurable. */
  469. // user.pref1 = PREF1_ECHOACTIONS | PREF1_ECHOTALKTYP | PREF1_ECHOTALKMSG |
  470. //             PREF1_MSGSENT | PREF1_ECHOGA | PREF1_TALKMSGSENT;
  471. // user.pref2 = 0; user.pref3 = 0;
  472.  
  473. user.pref1 = cfg.defaultprefs[0];
  474. user.pref2 = cfg.defaultprefs[1];
  475. user.pref3 = cfg.defaultprefs[2];
  476.  
  477. if (cfg.newusersec == 0)
  478.     {
  479.     user.security = od_control.user_security;
  480.     }
  481. else
  482.     {
  483.     user.security = cfg.newusersec;
  484.     }
  485.  
  486. save_user_data(recnum, &user);
  487.  
  488. return;
  489. }
  490.  
  491. /* The active handle index used to be updated by this function, until I
  492.    found out that I was calling it just about every time check_nodes_used()
  493.    was called.  The index is now updated by check_nodes_used(). */
  494. /*void load_online_handles(void)
  495. {
  496. XINT d;
  497. node_idx_typ nodeon;
  498.  
  499. check_nodes_used(TRUE);
  500.  
  501. for (d = 0; d < MAXNODES; d++)
  502.     {
  503.     if (activenodes[d])
  504.         {
  505.         get_node_data(d, &nodeon);
  506.         fixname(handles[d].string, nodeon.handle);
  507.         }
  508.     }
  509.  
  510. return;
  511. }*/
  512.  
  513. /* Old pre-bio user lookup.  It is still used by a function in MAINT.C. */
  514. void lookup(char *string)
  515. {
  516. user_data_typ udat;
  517. char tmp[256]; // Dynam with MAXSTRLEN!
  518. XINT d, u, ns = 0;
  519. long siz;
  520. struct ffblk udatdat;
  521.  
  522. if (!string[0])
  523.     {
  524.     top_output(OUT_SCREEN, getlang("LookUpPrompt"));
  525.  
  526.     od_input_str(tmp, 30, ' ', MAXASCII);
  527.     }
  528. else
  529.     {
  530.     strcpy(tmp, string);
  531.     top_output(OUT_SCREEN, getlang("LookUpPrefix"));
  532.     }
  533.  
  534. filter_string(tmp, tmp);
  535. trim_string(tmp, tmp, 0);
  536.  
  537. siz = 0L;
  538. sprintf(outbuf, "%sUSERS.TOP", cfg.toppath);
  539. d = findfirst(outbuf, &udatdat, 0);
  540. if (!d)
  541.     {
  542.     siz = udatdat.ff_fsize;
  543.     }
  544.  
  545. if (tmp[0])
  546.     {
  547.     top_output(OUT_SCREEN, getlang("LookUpSearching"), tmp);
  548.     }
  549.  
  550. d = 0; u = 0;
  551. while((long) d * (long) sizeof(user_data_typ) < siz)
  552.     {
  553.     char sex[2];
  554.  
  555.     load_user_data(d, &udat);
  556.     filter_string(udat.handle, udat.handle);
  557.     if ((strstr(strupr(udat.handle), strupr(tmp)) || !tmp[0]) &&
  558.         udat.realname[0])
  559.         {
  560.         if (udat.gender == 0)
  561.             {
  562.             sex[0] = 'M';
  563.             }
  564.         if (udat.gender == 1)
  565.             {
  566.             sex[0] = 'F';
  567.             }
  568.         sex[1] = '\0';
  569.         top_output(OUT_SCREEN, getlang("LookUpSep"));
  570.         if (cfg.usehandles)
  571.             {
  572.             filter_string(outbuf, udat.handle);
  573.             fixname(outbuf, udat.handle);
  574.             }
  575.         else
  576.             {
  577.             fixname(outbuf, udat.realname);
  578.             }
  579.         itoa(d, outnum[0], 10);
  580.         top_output(OUT_SCREEN, getlang("LookUpDisplay1"), outnum[0],
  581.                    getlang(cfg.usehandles ? "LookUpHandle" :
  582.                            "LookUpRealName"), outbuf, sex);
  583.         itoa(udat.last_use.da_mon, outnum[0], 10);
  584.         itoa(udat.last_use.da_day, outnum[1], 10);
  585.         itoa(udat.last_use.da_year, outnum[2], 10);
  586.         top_output(OUT_SCREEN, getlang("LookUpDisplay2"), outnum[0],
  587.                    outnum[1], outnum[2]);
  588. /*        filter_string(outbuf, udat.description);*/
  589.         top_output(OUT_SCREEN, getlang("LookUpDisplay3"), outbuf);
  590.         u++;
  591.         }
  592.     d++;
  593.     if (u == 5 && !ns && ((long) d * (long) sizeof(user_data_typ) < siz))
  594.         {
  595.         XINT key;
  596.  
  597.         u = 0;
  598.         top_output(OUT_SCREEN, getlang("LookUpSep"));
  599.         ns = moreprompt();
  600.         if (ns == -1)
  601.             {
  602.             break;
  603.             }
  604.         }
  605.     }
  606.  
  607. top_output(OUT_SCREEN, getlang("LookUpSep"));
  608. top_output(OUT_SCREEN, getlang("LookUpSuffix1"));
  609. top_output(OUT_SCREEN, getlang("PressAnyKey"));
  610. od_get_key(TRUE);
  611. top_output(OUT_SCREEN, getlang("LookUpSuffix2"));
  612.  
  613. return;
  614. }
  615.  
  616. /* check_dupe_handles() - Checks for a duplicate handle in USERS.TOP.
  617.    Parameters:  string - Handle to check for duplication.
  618.    Returns:  TRUE if a duplicate exists, FALSE if the specified handle
  619.              is unique.
  620. */
  621. char check_dupe_handles(char *string)
  622. {
  623. XINT d, res; /* Counter, result code. */
  624. unsigned char thandstr[31]; /* Temporary handle holder. */
  625. char ctt[256]; /* Holds a filtered and trimmed version of string. */
  626.  
  627. filter_string(ctt, string);
  628. trim_string(ctt, ctt, 0);
  629. sprintf(outbuf, "%sUSERS.TOP", cfg.toppath);
  630. if (access(outbuf, 0))
  631.     {
  632.     return 0;
  633.     }
  634.  
  635. /* Loop for each user record. */
  636. for (d = 0; d < (filelength(userfil) / (long) sizeof(user_data_typ)); d++)
  637.     {
  638.     /* This function does not use find_user_from_name() for two reasons.
  639.        The first is that it only needs the handle, which means it only
  640.        needs the first 31 bytes of the user file.  The second is that
  641.        find_user_from_name() loads the entire user record once a match
  642.        is found, which is unneeded here. */
  643.     res = lseek(userfil, ((long) d * (long) sizeof(user_data_typ)) + 41L,
  644.                 SEEK_SET);
  645.     if (res == -1)
  646.         {
  647.         errorabort(ERR_CANTACCESS, "USERS.TOP");
  648.         }
  649.     rec_locking(REC_LOCK, userfil,
  650.                 ((long) d * (long) sizeof(user_data_typ)) + 41L,
  651.                 sizeof(user_data_typ));
  652.     res = read(userfil, thandstr, 31);
  653.     rec_locking(REC_UNLOCK, userfil,
  654.                 ((long) d * (long) sizeof(user_data_typ)) + 41L,
  655.                 sizeof(user_data_typ));
  656.     if (res == -1)
  657.         {
  658.         errorabort(ERR_CANTREAD, "USERS.TOP");
  659.         }
  660.     filter_string(thandstr, thandstr);
  661.     if (!stricmp(thandstr, ctt))
  662.         {
  663.         return 1;
  664.         }
  665.     }
  666.  
  667. return 0;
  668. }
  669.  
  670. /* find_user_from_name() - Load a user record from a name or handle.
  671.    Parameters:  uname - String holding the name to match.
  672.                 ubuf - Pointer to buffer to hold the loaded user data.
  673.                 nuse - Matching option (UFIND_ constant).
  674.    Returns:  Record number of the user if one was found, or -1 on no
  675.              match. */
  676. XINT find_user_from_name(unsigned char *uname, user_data_typ *ubuf,
  677.                          XINT nuse)
  678.     {
  679.     XINT unum = -1, d; /* User record number, counter. */
  680.     long s; /* Size of user file, in records. */
  681.  
  682.     /* Use the configured matching criteria. */
  683.     if (nuse == UFIND_USECFG)
  684.         {
  685.         nuse = cfg.usehandles + 1;
  686.         }
  687.     s = filelength(userfil) / sizeof(user_data_typ);
  688.     /* Loop for each user record. */
  689.     for (d = 0; d < s && unum < 0; d++)
  690.         {
  691.         rec_locking(REC_LOCK, userfil, (long) d * sizeof(user_data_typ),
  692.                     sizeof(user_data_typ));
  693.         lseek(userfil, (long) d * sizeof(user_data_typ), SEEK_SET);
  694.         /* Only load the first 72 bytes for speed, which contains the
  695.            handle and real name of the user. */
  696.         read(userfil, ubuf, 72L);
  697.         rec_locking(REC_UNLOCK, userfil, (long) d * sizeof(user_data_typ),
  698.                     sizeof(user_data_typ));
  699.         if (!stricmp(uname,
  700.                      nuse == UFIND_HANDLE ? ubuf->handle : ubuf->realname))
  701.             {
  702.             /* Match found, load the user data. */
  703.             unum = d;
  704.             if (ubuf != NULL)
  705.                 {
  706.                 load_user_data(unum, ubuf);
  707.                 }
  708.             }
  709.         }
  710.  
  711.     return unum;
  712.     }
  713.