home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / lora299s.zip / USER.CPP < prev    next >
C/C++ Source or Header  |  1998-05-12  |  39KB  |  1,368 lines

  1.  
  2. // LoraBBS Version 2.99 Free Edition
  3. // Copyright (C) 1987-98 Marco Maccaferri
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 2 of the License, or
  8. // (at your option) any later version.
  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., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19. #include "_ldefs.h"
  20. #include "lora_api.h"
  21.  
  22. /*
  23. static ULONG cr3tab[] = {
  24.    0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
  25.    0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
  26.    0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
  27.    0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
  28.    0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
  29.    0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
  30.    0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
  31.    0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
  32.    0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
  33.    0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
  34.    0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
  35.    0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
  36.    0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
  37.    0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
  38.    0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
  39.    0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
  40.    0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
  41.    0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
  42.    0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
  43.    0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
  44.    0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
  45.    0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
  46.    0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
  47.    0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
  48.    0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
  49.    0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
  50.    0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
  51.    0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
  52.    0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
  53.    0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
  54.    0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
  55.    0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
  56. };
  57.  
  58. static ULONG StringCrc32 (CHAR *pszString, ULONG ulCrc)
  59. {
  60.    while (*pszString) {
  61.       ulCrc = (cr3tab[((ULONG)ulCrc ^ (UCHAR)*pszString) & 0xFF] ^ ((ulCrc >> 8) & 0x00FFFFFFL));
  62.       pszString++;
  63.    }
  64.  
  65.    return (ulCrc);
  66. }
  67. */
  68.  
  69. TUser::TUser (void)
  70. {
  71.    strcpy (DatFile, "users.dat");
  72.    strcpy (IdxFile, "users.idx");
  73.    fdDat = fdIdx = -1;
  74.  
  75.    MsgTag = new TMsgTag;
  76.    FileTag = new TFileTag;
  77. }
  78.  
  79. TUser::TUser (PSZ pszUserFile)
  80. {
  81.    strcpy (DatFile, pszUserFile);
  82.    strcat (DatFile, ".dat");
  83.    strcpy (IdxFile, pszUserFile);
  84.    strcat (IdxFile, ".idx");
  85.    fdDat = fdIdx = -1;
  86.  
  87.    MsgTag = new TMsgTag (pszUserFile);
  88.    FileTag = new TFileTag (pszUserFile);
  89. }
  90.  
  91. TUser::~TUser (void)
  92. {
  93.    if (fdDat != -1)
  94.       close (fdDat);
  95.    if (fdIdx != -1)
  96.       close (fdIdx);
  97.  
  98.    if (FileTag != NULL)
  99.       delete FileTag;
  100.    if (MsgTag != NULL)
  101.       delete MsgTag;
  102. }
  103.  
  104. VOID TUser::Struct2Class (VOID)
  105. {
  106.    strcpy (Name, Usr.Name);
  107.    Password = Usr.Password;
  108.    strcpy (RealName, Usr.RealName);
  109.    strcpy (Company, Usr.Company);
  110.    strcpy (Address, Usr.Address);
  111.    strcpy (City, Usr.City);
  112.    strcpy (DayPhone, Usr.DayPhone);
  113.    Ansi = Usr.Ansi;
  114.    Avatar = Usr.Avatar;
  115.    Color = Usr.Color;
  116.    HotKey = Usr.HotKey;
  117.    Sex = Usr.Sex;
  118.    FullEd = Usr.FullEd;
  119.    FullReader = Usr.FullReader;
  120.    NoDisturb = Usr.NoDisturb;
  121.    AccessFailed = Usr.AccessFailed;
  122.    ScreenHeight = Usr.ScreenHeight;
  123.    ScreenWidth = Usr.ScreenWidth;
  124.    Level = Usr.Level;
  125.    AccessFlags = Usr.AccessFlags;
  126.    DenyFlags = Usr.DenyFlags;
  127.    CreationDate = Usr.CreationDate;
  128.    LastCall = Usr.LastCall;
  129.    TotalCalls = Usr.TotalCalls;
  130.    TodayTime = Usr.TodayTime;
  131.    WeekTime = Usr.WeekTime;
  132.    MonthTime = Usr.MonthTime;
  133.    YearTime = Usr.YearTime;
  134.    strcpy (MailBox, Usr.MailBox);
  135.    strcpy (LimitClass, Usr.LimitClass);
  136.    strcpy (Language, Usr.Language);
  137.    strcpy (FtpHost, Usr.FtpHost);
  138.    strcpy (FtpName, Usr.FtpName);
  139.    strcpy (FtpPwd, Usr.FtpPwd);
  140.    strcpy (LastMsgArea, Usr.LastMsgArea);
  141.    strcpy (LastFileArea, Usr.LastFileArea);
  142.    UploadFiles = Usr.UploadFiles;
  143.    UploadBytes = Usr.UploadBytes;
  144.    DownloadFiles = Usr.DownloadFiles;
  145.    DownloadBytes = Usr.DownloadBytes;
  146.    FilesToday = Usr.FilesToday;
  147.    BytesToday = Usr.BytesToday;
  148.    ImportPOP3Mail = Usr.ImportPOP3Mail;
  149.    UseInetAddress = Usr.UseInetAddress;
  150.    strcpy (InetAddress, Usr.InetAddress);
  151.    strcpy (Pop3Pwd, Usr.Pop3Pwd);
  152.    strcpy (Archiver, Usr.Archiver);
  153.    strcpy (Protocol, Usr.Protocol);
  154.    strcpy (Signature, Usr.Signature);
  155.    FullScreen = Usr.FullScreen;
  156.    IBMChars = Usr.IBMChars;
  157.    MorePrompt = Usr.MorePrompt;
  158.    ScreenClear = Usr.ScreenClear;
  159.    InUserList = Usr.InUserList;
  160.    MailCheck = Usr.MailCheck;
  161.    NewFileCheck = Usr.NewFileCheck;
  162.    BirthDay = Usr.BirthDay;
  163.    BirthMonth = Usr.BirthMonth;
  164.    BirthYear = Usr.BirthYear;
  165.    LastPwdChange = Usr.LastPwdChange;
  166.    PwdLength = Usr.PwdLength;
  167.    strcpy (PwdText, Usr.PwdText);
  168.  
  169.    CurrentCRC = StringCrc32 (Name, 0xFFFFFFFFL);
  170. }
  171.  
  172. VOID TUser::Class2Struct (VOID)
  173. {
  174.    memset (&Usr, 0, sizeof (Usr));
  175.    Usr.Size = sizeof (Usr);
  176.    strcpy (Usr.Name, Name);
  177.    Usr.Password = Password;
  178.    strcpy (Usr.RealName, RealName);
  179.    strcpy (Usr.Company, Company);
  180.    strcpy (Usr.Address, Address);
  181.    strcpy (Usr.City, City);
  182.    strcpy (Usr.DayPhone, DayPhone);
  183.    Usr.Ansi = Ansi;
  184.    Usr.Avatar = Avatar;
  185.    Usr.Color = Color;
  186.    Usr.HotKey = HotKey;
  187.    Usr.Sex = Sex;
  188.    Usr.FullEd = FullEd;
  189.    Usr.FullReader = FullReader;
  190.    Usr.NoDisturb = NoDisturb;
  191.    Usr.AccessFailed = AccessFailed;
  192.    Usr.ScreenHeight = ScreenHeight;
  193.    Usr.ScreenWidth = ScreenWidth;
  194.    Usr.Level = Level;
  195.    Usr.AccessFlags = AccessFlags;
  196.    Usr.DenyFlags = DenyFlags;
  197.    Usr.CreationDate = CreationDate;
  198.    Usr.LastCall = LastCall;
  199.    Usr.TotalCalls = TotalCalls;
  200.    Usr.TodayTime = TodayTime;
  201.    Usr.WeekTime = WeekTime;
  202.    Usr.MonthTime = MonthTime;
  203.    Usr.YearTime = YearTime;
  204.    strcpy (Usr.MailBox, MailBox);
  205.    strcpy (Usr.LimitClass, LimitClass);
  206.    strcpy (Usr.Language, Language);
  207.    strcpy (Usr.FtpHost, FtpHost);
  208.    strcpy (Usr.FtpName, FtpName);
  209.    strcpy (Usr.FtpPwd, FtpPwd);
  210.    strcpy (Usr.LastMsgArea, LastMsgArea);
  211.    strcpy (Usr.LastFileArea, LastFileArea);
  212.    Usr.UploadFiles = UploadFiles;
  213.    Usr.UploadBytes = UploadBytes;
  214.    Usr.DownloadFiles = DownloadFiles;
  215.    Usr.DownloadBytes = DownloadBytes;
  216.    Usr.FilesToday = FilesToday;
  217.    Usr.BytesToday = BytesToday;
  218.    Usr.ImportPOP3Mail = ImportPOP3Mail;
  219.    Usr.UseInetAddress = UseInetAddress;
  220.    strcpy (Usr.InetAddress, InetAddress);
  221.    strcpy (Usr.Pop3Pwd, Pop3Pwd);
  222.    strcpy (Usr.Archiver, Archiver);
  223.    strcpy (Usr.Protocol, Protocol);
  224.    strcpy (Usr.Signature, Signature);
  225.    Usr.FullScreen = FullScreen;
  226.    Usr.IBMChars = IBMChars;
  227.    Usr.MorePrompt = MorePrompt;
  228.    Usr.ScreenClear = ScreenClear;
  229.    Usr.InUserList = InUserList;
  230.    Usr.MailCheck = MailCheck;
  231.    Usr.NewFileCheck = NewFileCheck;
  232.    Usr.BirthDay = BirthDay;
  233.    Usr.BirthMonth = BirthMonth;
  234.    Usr.BirthYear = BirthYear;
  235.    Usr.LastPwdChange = LastPwdChange;
  236.    Usr.PwdLength = PwdLength;
  237.    strcpy (Usr.PwdText, PwdText);
  238. }
  239.  
  240. USHORT TUser::Add (VOID)
  241. {
  242.    USHORT RetVal = FALSE;
  243.  
  244.    if (fdDat == -1)
  245.       fdDat = sopen (DatFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  246.    if (fdIdx == -1)
  247.       fdIdx = sopen (IdxFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  248.  
  249.    if (fdDat != -1 && fdIdx != -1) {
  250.       lseek (fdDat, 0L, SEEK_END);
  251.       lseek (fdIdx, 0L, SEEK_END);
  252.  
  253.       memset (&Idx, 0, sizeof (Idx));
  254.       Idx.Deleted = FALSE;
  255.       Idx.NameCrc = StringCrc32 (Name, 0xFFFFFFFFL);
  256.       Idx.RealNameCrc = StringCrc32 (RealName, 0xFFFFFFFFL);
  257.       Idx.Position = tell (fdDat);
  258.  
  259.       CurrentCRC = Idx.NameCrc;
  260.       Class2Struct ();
  261.  
  262.       write (fdDat, &Usr, sizeof (Usr));
  263.       write (fdIdx, &Idx, sizeof (Idx));
  264.  
  265.       MsgTag->UserId = Idx.NameCrc;
  266.       MsgTag->Load ();
  267.       FileTag->UserId = Idx.NameCrc;
  268.       FileTag->Load ();
  269.  
  270.       RetVal = TRUE;
  271.    }
  272.  
  273.    return (RetVal);
  274. }
  275.  
  276. USHORT TUser::Age (VOID)
  277. {
  278.    USHORT RetVal = 0;
  279.    struct dosdate_t d_date;
  280.  
  281.    _dos_getdate (&d_date);
  282.  
  283.    if (BirthDay != 0 && BirthMonth != 0 && BirthYear > 1880 && BirthYear < d_date.year) {
  284.       RetVal = (USHORT)(d_date.year - BirthYear);
  285.       if (d_date.month < BirthMonth)
  286.          RetVal--;
  287.       else if (d_date.month == BirthMonth && d_date.day < BirthDay)
  288.          RetVal--;
  289.    }
  290.  
  291.    return (RetVal);
  292. }
  293.  
  294. VOID TUser::ChangeLimitClass (PSZ pszOld, PSZ pszNew)
  295. {
  296.    if (fdDat == -1)
  297.       fdDat = sopen (DatFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  298.  
  299.    if (fdDat != -1) {
  300.       lseek (fdDat, 0L, SEEK_SET);
  301.       while (read (fdDat, &Usr, sizeof (Usr)) == sizeof (Usr)) {
  302.          if (!stricmp (Usr.LimitClass, pszOld)) {
  303.             strcpy (Usr.LimitClass, pszNew);
  304.             lseek (fdDat, tell (fdDat) - sizeof (Usr), SEEK_SET);
  305.             write (fdDat, &Usr, sizeof (Usr));
  306.          }
  307.       }
  308.    }
  309.  
  310.    if (fdDat != -1) {
  311.       close (fdDat);
  312.       fdDat = -1;
  313.    }
  314. }
  315.  
  316. USHORT TUser::CheckPassword (PSZ pszPassword)
  317. {
  318.    USHORT RetVal = FALSE;
  319.  
  320.    if (Password == StringCrc32 (strupr (pszPassword), 0xFFFFFFFFL))
  321.       RetVal = TRUE;
  322.  
  323.    return (RetVal);
  324. }
  325.  
  326. VOID TUser::Clear (VOID)
  327. {
  328.    memset (&Usr, 0, sizeof (USER));
  329.    Struct2Class ();
  330.  
  331.    MsgTag->Clear ();
  332.    FileTag->Clear ();
  333. }
  334.  
  335. USHORT TUser::Delete (VOID)
  336. {
  337.    USHORT RetVal = FALSE, DoClose = FALSE;
  338.    ULONG NameCrc;
  339.  
  340.    if (fdDat == -1) {
  341.       fdDat = sopen (DatFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  342.       DoClose = TRUE;
  343.    }
  344.    if (fdIdx == -1) {
  345.       fdIdx = sopen (IdxFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  346.       DoClose = TRUE;
  347.    }
  348.  
  349.    if (fdDat != -1 && fdIdx != -1) {
  350.       NameCrc = StringCrc32 (Name, 0xFFFFFFFFL);
  351.       lseek (fdIdx, 0L, SEEK_SET);
  352.       while (RetVal == FALSE && read (fdIdx, &Idx, sizeof (Idx)) == sizeof (Idx)) {
  353.          if (Idx.Deleted == FALSE && Idx.NameCrc == NameCrc)
  354.             RetVal = TRUE;
  355.       }
  356.  
  357.       if (RetVal == TRUE) {
  358.          Idx.Deleted = TRUE;
  359.          lseek (fdIdx, tell (fdIdx) - sizeof (Idx), SEEK_SET);
  360.          write (fdIdx, &Idx, sizeof (Idx));
  361.       }
  362.    }
  363.  
  364.    if (DoClose == TRUE) {
  365.       if (fdDat != -1) {
  366.          close (fdDat);
  367.          fdDat = -1;
  368.       }
  369.       if (fdIdx != -1) {
  370.          close (fdIdx);
  371.          fdIdx = -1;
  372.       }
  373.    }
  374.  
  375.    return (RetVal);
  376. }
  377.  
  378. USHORT TUser::First (VOID)
  379. {
  380.    USHORT RetVal = FALSE;
  381.  
  382.    if (fdDat == -1)
  383.       fdDat = sopen (DatFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  384.    if (fdIdx == -1)
  385.       fdIdx = sopen (IdxFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  386.  
  387.    if (fdDat != -1 && fdIdx != -1) {
  388.       lseek (fdIdx, 0L, SEEK_SET);
  389.       lseek (fdDat, 0L, SEEK_SET);
  390.       RetVal = Next ();
  391.    }
  392.  
  393.    return (RetVal);
  394. }
  395.  
  396. USHORT TUser::GetData (PSZ pszName, USHORT fCheckRealName)
  397. {
  398.    USHORT RetVal = FALSE, DoClose = FALSE;
  399.    ULONG TestCrc;
  400.  
  401.    if (fdDat == -1) {
  402.       fdDat = sopen (DatFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  403.       DoClose = TRUE;
  404.    }
  405.    if (fdIdx == -1) {
  406.       fdIdx = sopen (IdxFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  407.       DoClose = TRUE;
  408.    }
  409.  
  410.    if (fdDat != -1 && fdIdx != -1) {
  411.       Clear ();
  412.  
  413.       TestCrc = StringCrc32 (pszName, 0xFFFFFFFFL);
  414.  
  415.       lseek (fdIdx, 0L, SEEK_SET);
  416.       while (RetVal == FALSE && read (fdIdx, &Idx, sizeof (Idx)) == sizeof (Idx)) {
  417.          if (Idx.Deleted == FALSE && Idx.NameCrc == TestCrc)
  418.             RetVal = TRUE;
  419.       }
  420.       if (RetVal == FALSE && fCheckRealName == TRUE) {
  421.          lseek (fdIdx, 0L, SEEK_SET);
  422.          while (RetVal == FALSE && read (fdIdx, &Idx, sizeof (Idx)) == sizeof (Idx)) {
  423.             if (Idx.Deleted == FALSE && Idx.RealNameCrc == TestCrc)
  424.                RetVal = TRUE;
  425.          }
  426.       }
  427.       if (RetVal == TRUE) {
  428.          lseek (fdDat, Idx.Position, SEEK_SET);
  429.          read (fdDat, &Usr, sizeof (Usr));
  430.  
  431.          Struct2Class ();
  432.  
  433.          MsgTag->UserId = Idx.NameCrc;
  434.          MsgTag->Load ();
  435.          FileTag->UserId = Idx.NameCrc;
  436.          FileTag->Load ();
  437.       }
  438.    }
  439.  
  440.    if (DoClose == TRUE) {
  441.       if (fdDat != -1) {
  442.          close (fdDat);
  443.          fdDat = -1;
  444.       }
  445.       if (fdIdx != -1) {
  446.          close (fdIdx);
  447.          fdIdx = -1;
  448.       }
  449.    }
  450.  
  451.    return (RetVal);
  452. }
  453.  
  454. USHORT TUser::Next (VOID)
  455. {
  456.    USHORT RetVal = FALSE;
  457.  
  458.    if (fdDat != -1 && fdIdx != -1) {
  459.       while (RetVal == FALSE && read (fdIdx, &Idx, sizeof (Idx)) == sizeof (Idx)) {
  460.          if (Idx.Deleted == FALSE)
  461.             RetVal = TRUE;
  462.       }
  463.  
  464.       if (RetVal == TRUE) {
  465.          Clear ();
  466.          lseek (fdDat, Idx.Position, SEEK_SET);
  467.          read (fdDat, &Usr, sizeof (Usr));
  468.          Struct2Class ();
  469.       }
  470.    }
  471.  
  472.    return (RetVal);
  473. }
  474.  
  475. VOID TUser::SetPassword (PSZ pszPassword)
  476. {
  477.    Password = StringCrc32 (strupr (pszPassword), 0xFFFFFFFFL);
  478. }
  479.  
  480. VOID TUser::Pack (VOID)
  481. {
  482.    int fdNew;
  483.  
  484.    if (fdDat == -1)
  485.       fdDat = sopen (DatFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  486.    if (fdIdx == -1)
  487.       fdIdx = sopen (IdxFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  488.  
  489.    fdNew = sopen ("users.new", O_RDWR|O_BINARY|O_CREAT|O_TRUNC, SH_DENYNO, S_IREAD|S_IWRITE);
  490.  
  491.    if (fdNew != -1 && fdDat != -1 && fdIdx != -1) {
  492.       lseek (fdIdx, 0L, SEEK_SET);
  493.       lseek (fdDat, 0L, SEEK_SET);
  494.  
  495.       while (read (fdIdx, &Idx, sizeof (Idx)) == sizeof (Idx)) {
  496.          if (Idx.Deleted == FALSE) {
  497.             lseek (fdDat, Idx.Position, SEEK_SET);
  498.             read (fdDat, &Usr, sizeof (Usr));
  499.             write (fdNew, &Usr, sizeof (Usr));
  500.          }
  501.       }
  502.  
  503.       lseek (fdIdx, 0L, SEEK_SET);
  504.       lseek (fdDat, 0L, SEEK_SET);
  505.       lseek (fdNew, 0L, SEEK_SET);
  506.  
  507.       while (read (fdNew, &Usr, sizeof (Usr)) == sizeof (Usr)) {
  508.          memset (&Idx, 0, sizeof (Idx));
  509.          Idx.Deleted = FALSE;
  510.          Idx.NameCrc = StringCrc32 (Usr.Name, 0xFFFFFFFFL);
  511.          Idx.RealNameCrc = StringCrc32 (Usr.RealName, 0xFFFFFFFFL);
  512.          Idx.Position = tell (fdDat);
  513.  
  514.          write (fdDat, &Usr, sizeof (Usr));
  515.          write (fdIdx, &Idx, sizeof (Idx));
  516.       }
  517.  
  518.       chsize (fdDat, tell (fdDat));
  519.       chsize (fdIdx, tell (fdIdx));
  520.    }
  521.  
  522.    if (fdNew != -1) {
  523.       close (fdNew);
  524.       unlink ("users.new");
  525.    }
  526.  
  527.    if (fdIdx != -1) {
  528.       close (fdIdx);
  529.       fdIdx = -1;
  530.    }
  531.    if (fdDat != -1) {
  532.       close (fdDat);
  533.       fdDat = -1;
  534.    }
  535. }
  536.  
  537. USHORT TUser::Previous (VOID)
  538. {
  539.    USHORT RetVal = FALSE;
  540.  
  541.    if (fdDat == -1)
  542.       fdDat = sopen (DatFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  543.    if (fdIdx == -1)
  544.       fdIdx = sopen (IdxFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  545.  
  546.    if (fdDat != -1 && fdIdx != -1 && (tell (fdIdx) - sizeof (Idx)) >= sizeof (Idx)) {
  547.       do {
  548.          lseek (fdIdx, tell (fdIdx) - sizeof (Idx) * 2, SEEK_SET);
  549.          if (read (fdIdx, &Idx, sizeof (Idx)) == sizeof (Idx)) {
  550.             if (Idx.Deleted == FALSE)
  551.                RetVal = TRUE;
  552.          }
  553.       } while (RetVal == FALSE && tell (fdIdx) >= sizeof (Idx) * 2);
  554.  
  555.       if (RetVal == TRUE) {
  556.          Clear ();
  557.          lseek (fdDat, Idx.Position, SEEK_SET);
  558.          read (fdDat, &Usr, sizeof (Usr));
  559.          Struct2Class ();
  560.       }
  561.    }
  562.  
  563.    return (RetVal);
  564. }
  565.  
  566. VOID TUser::Reindex (VOID)
  567. {
  568.    ULONG Position;
  569.  
  570.    if (fdDat != -1)
  571.       close (fdDat);
  572.    if (fdIdx != -1)
  573.       close (fdIdx);
  574.  
  575.    fdDat = sopen (DatFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  576.    fdIdx = sopen (IdxFile, O_RDWR|O_BINARY|O_CREAT|O_TRUNC, SH_DENYNO, S_IREAD|S_IWRITE);
  577.  
  578.    if (fdDat != -1 && fdIdx != -1) {
  579.       lseek (fdDat, 0L, SEEK_SET);
  580.  
  581.       Position = tell (fdDat);
  582.       while (read (fdDat, &Usr, sizeof (Usr)) == sizeof (Usr)) {
  583.          if (Usr.Size == sizeof (Usr)) {
  584.             memset (&Idx, 0, sizeof (Idx));
  585.             Idx.Deleted = FALSE;
  586.             Idx.NameCrc = StringCrc32 (Usr.Name, 0xFFFFFFFFL);
  587.             Idx.RealNameCrc = StringCrc32 (Usr.RealName, 0xFFFFFFFFL);
  588.             Idx.Position = Position;
  589.             write (fdIdx, &Idx, sizeof (Idx));
  590.          }
  591.          Position = tell (fdDat);
  592.       }
  593.    }
  594.  
  595.    if (fdDat != -1) {
  596.       close (fdDat);
  597.       fdDat = -1;
  598.    }
  599.    if (fdIdx != -1) {
  600.       close (fdIdx);
  601.       fdIdx = -1;
  602.    }
  603. }
  604.  
  605. // Aggiorna i dati relativi ad un nominativo.
  606. // -----------------------------------------------------------------------------
  607. USHORT TUser::Update (VOID)
  608. {
  609.    USHORT RetVal = FALSE, DoClose = FALSE;
  610.  
  611.    // Verifica se i file dati devono essere aperti, nel qual caso attiva il flag
  612.    // DoClose per poi forzarne la chiusura al termine della funzione.
  613.    if (fdDat == -1) {
  614.       fdDat = sopen (DatFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  615.       DoClose = TRUE;
  616.    }
  617.    if (fdIdx == -1) {
  618.       fdIdx = sopen (IdxFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE);
  619.       DoClose = TRUE;
  620.    }
  621.  
  622.    if (fdDat != -1 && fdIdx != -1) {
  623.       // Cerca tramite l'indice il record corrispondente all'ultimo nominativo
  624.       // selezionato. Non si puo' utilizzare il nome nella classe perche' potrebbe
  625.       // non essere piu' quello letto originariamente.
  626.       lseek (fdIdx, 0L, SEEK_SET);
  627.       while (read (fdIdx, &Idx, sizeof (Idx)) == sizeof (Idx)) {
  628.          if (Idx.Deleted == FALSE && Idx.NameCrc == CurrentCRC) {
  629.             RetVal = TRUE;
  630.             break;
  631.          }
  632.       }
  633.  
  634.       if (RetVal == TRUE) {
  635.          // Copia tutti i dati della classe nella struttura dati da scrivere
  636.          // nel record.
  637.          Class2Struct ();
  638.  
  639.          // Aggiorna il CRC di nome e alias nell'indice, nel caso in cui questi
  640.          // dati fossero stati cambiati.
  641.          Idx.NameCrc = StringCrc32 (Name, 0xFFFFFFFFL);
  642.          Idx.RealNameCrc = StringCrc32 (RealName, 0xFFFFFFFFL);
  643.          lseek (fdIdx, tell (fdIdx) - sizeof (Idx), SEEK_SET);
  644.          write (fdIdx, &Idx, sizeof (Idx));
  645.  
  646.          // Aggiorna il record dati vero e proprio.
  647.          lseek (fdDat, Idx.Position, SEEK_SET);
  648.          write (fdDat, &Usr, sizeof (Usr));
  649.  
  650.          // Se e' stato cambiato il nome dell'utente, cambia anche le associazioni
  651.          // con i file contenenti i puntatori agli ultimi messaggi letti e i files
  652.          // marcati per il download.
  653.          if (CurrentCRC != Idx.NameCrc) {
  654.             MsgTag->Change (CurrentCRC, Idx.NameCrc);
  655.             FileTag->Change (CurrentCRC, Idx.NameCrc);
  656.             CurrentCRC = Idx.NameCrc;
  657.          }
  658.  
  659.          // Aggiorna il file contenenti i puntatori agli ultimi messaggi letti.
  660.          MsgTag->UserId = Idx.NameCrc;
  661.          MsgTag->Save ();
  662.          // Aggiorna il file contenente i nome dei file marcati per il download.
  663.          FileTag->UserId = Idx.NameCrc;
  664.          FileTag->Save ();
  665.       }
  666.    }
  667.  
  668.    // Se i file non erano gia' aperti prima di invocare questa funzione, vengono
  669.    // chiusi automaticamente per non lasciare handle aperti inutilmente.
  670.    if (DoClose == TRUE) {
  671.       if (fdDat != -1) {
  672.          close (fdDat);
  673.          fdDat = -1;
  674.       }
  675.       if (fdIdx != -1) {
  676.          close (fdIdx);
  677.          fdIdx = -1;
  678.       }
  679.    }
  680.  
  681.    return (RetVal);
  682. }
  683.  
  684. // --------------------------------------------------------------------------
  685.  
  686. TMsgTag::TMsgTag (void)
  687. {
  688.    Data.Clear ();
  689.    strcpy (DatFile, "msgtags.dat");
  690. }
  691.  
  692. TMsgTag::TMsgTag (PSZ pszUserFile)
  693. {
  694.    CHAR *p;
  695.  
  696.    Data.Clear ();
  697.    strcpy (DatFile, pszUserFile);
  698.  
  699.    p = &DatFile[strlen (DatFile)];
  700.    while (*p != '\\' && *p != '/' && *p != ':' && p > DatFile)
  701.       p--;
  702.    if (*p == '\\' || *p == '/')
  703.       p++;
  704.  
  705.    strcpy (p, "msgtags.dat");
  706. }
  707.  
  708. TMsgTag::~TMsgTag (void)
  709. {
  710.    Data.Clear ();
  711. }
  712.  
  713. VOID TMsgTag::Add (VOID)
  714. {
  715.    MSGTAGS Buffer;
  716.  
  717.    memset (&Buffer, 0, sizeof (MSGTAGS));
  718.  
  719.    Buffer.Free = FALSE;
  720.    Buffer.Tagged = Tagged;
  721.    Buffer.UserId = UserId;
  722.    strcpy (Buffer.Area, Area);
  723.    Buffer.LastRead = LastRead;
  724.    Buffer.OlderMsg = OlderMsg;
  725.    Data.Add (&Buffer, sizeof (MSGTAGS));
  726. }
  727.  
  728. // Cambia il nome di un'area
  729. // -----------------------------------------------------------------------------
  730. VOID TMsgTag::Change (PSZ pszOldName, PSZ pszNewName)
  731. {
  732.    int fd, i, Count, Changed;
  733.    ULONG Position;
  734.    MSGTAGS *Buffer;
  735.  
  736.    if ((fd = sopen (DatFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE)) != -1) {
  737.       if ((Buffer = (MSGTAGS *)malloc (sizeof (MSGTAGS) * MSGTAGS_INDEX)) != NULL) {
  738.          do {
  739.             Changed = FALSE;
  740.  
  741.             Position = tell (fd);
  742.             Count = read (fd, Buffer, sizeof (MSGTAGS) * MSGTAGS_INDEX) / sizeof (MSGTAGS);
  743.             for (i = 0; i < Count; i++) {
  744.                if (Buffer[i].Free == FALSE && !stricmp (Buffer[i].Area, pszOldName)) {
  745.                   strcpy (Buffer[i].Area, pszNewName);
  746.                   Changed = TRUE;
  747.                }
  748.             }
  749.  
  750.             if (Changed == TRUE) {
  751.                lseek (fd, Position, SEEK_SET);
  752.                write (fd, Buffer, sizeof (MSGTAGS) * Count);
  753.             }
  754.          } while (Count == MSGTAGS_INDEX);
  755.          free (Buffer);
  756.       }
  757.  
  758.       close (fd);
  759.    }
  760. }
  761.  
  762. // Cambia l'ID dell'utente associato ai record.
  763. // -----------------------------------------------------------------------------
  764. VOID TMsgTag::Change (ULONG OldId, ULONG NewId)
  765. {
  766.    int fd, i, Count, Changed;
  767.    ULONG Position;
  768.    MSGTAGS *Buffer;
  769.  
  770.    if ((fd = sopen (DatFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE)) != -1) {
  771.       if ((Buffer = (MSGTAGS *)malloc (sizeof (MSGTAGS) * MSGTAGS_INDEX)) != NULL) {
  772.          do {
  773.             Changed = FALSE;
  774.  
  775.             Position = tell (fd);
  776.             Count = read (fd, Buffer, sizeof (MSGTAGS) * MSGTAGS_INDEX) / sizeof (MSGTAGS);
  777.             for (i = 0; i < Count; i++) {
  778.                if (Buffer[i].Free == FALSE && Buffer[i].UserId == OldId) {
  779.                   Buffer[i].UserId = NewId;
  780.                   Changed = TRUE;
  781.                }
  782.             }
  783.  
  784.             if (Changed == TRUE) {
  785.                lseek (fd, Position, SEEK_SET);
  786.                write (fd, Buffer, sizeof (MSGTAGS) * Count);
  787.             }
  788.          } while (Count == MSGTAGS_INDEX);
  789.          free (Buffer);
  790.       }
  791.  
  792.       close (fd);
  793.    }
  794. }
  795.  
  796. VOID TMsgTag::Clear (VOID)
  797. {
  798.    Data.Clear ();
  799.  
  800.    Tagged = FALSE;
  801.    Area[0] = '\0';
  802.    LastRead = 0L;
  803.    OlderMsg = 0L;
  804. }
  805.  
  806. USHORT TMsgTag::First (VOID)
  807. {
  808.    USHORT RetVal = FALSE;
  809.    MSGTAGS *Buffer;
  810.  
  811.    if ((Buffer = (MSGTAGS *)Data.First ()) != NULL) {
  812.       Tagged = Buffer->Tagged;
  813.       strcpy (Area, Buffer->Area);
  814.       LastRead = Buffer->LastRead;
  815.       OlderMsg = Buffer->OlderMsg;
  816.       RetVal = TRUE;
  817.    }
  818.  
  819.    return (RetVal);
  820. }
  821.  
  822. VOID TMsgTag::Load (VOID)
  823. {
  824.    int fd, i, Count;
  825.    MSGTAGS *Buffer;
  826.  
  827.    Data.Clear ();
  828.  
  829.    if ((fd = sopen (DatFile, O_RDONLY|O_BINARY, SH_DENYNO, S_IREAD|S_IWRITE)) != -1) {
  830.       if ((Buffer = (MSGTAGS *)malloc (sizeof (MSGTAGS) * MSGTAGS_INDEX)) != NULL) {
  831.          do {
  832.             Count = read (fd, Buffer, sizeof (MSGTAGS) * MSGTAGS_INDEX) / sizeof (MSGTAGS);
  833.             for (i = 0; i < Count; i++) {
  834.                if (Buffer[i].Free == FALSE && Buffer[i].UserId == UserId)
  835.                   Data.Add (&Buffer[i], sizeof (MSGTAGS));
  836.             }
  837.          } while (Count == MSGTAGS_INDEX);
  838.          free (Buffer);
  839.       }
  840.       close (fd);
  841.    }
  842.  
  843.    if ((Buffer = (MSGTAGS *)Data.First ()) != NULL) {
  844.       Tagged = Buffer->Tagged;
  845.       strcpy (Area, Buffer->Area);
  846.       LastRead = Buffer->LastRead;
  847.       OlderMsg = Buffer->OlderMsg;
  848.    }
  849. }
  850.  
  851. VOID TMsgTag::New (VOID)
  852. {
  853.    Tagged = FALSE;
  854.    Area[0] = '\0';
  855.    LastRead = 0L;
  856.    OlderMsg = 0L;
  857. }
  858.  
  859. USHORT TMsgTag::Next (VOID)
  860. {
  861.    USHORT RetVal = FALSE;
  862.    MSGTAGS *Buffer;
  863.  
  864.    if ((Buffer = (MSGTAGS *)Data.Next ()) != NULL) {
  865.       Tagged = Buffer->Tagged;
  866.       strcpy (Area, Buffer->Area);
  867.       LastRead = Buffer->LastRead;
  868.       OlderMsg = Buffer->OlderMsg;
  869.       RetVal = TRUE;
  870.    }
  871.  
  872.    return (RetVal);
  873. }
  874.  
  875. USHORT TMsgTag::Previous (VOID)
  876. {
  877.    USHORT RetVal = FALSE;
  878.    MSGTAGS *Buffer;
  879.  
  880.    if ((Buffer = (MSGTAGS *)Data.Previous ()) != NULL) {
  881.       Tagged = Buffer->Tagged;
  882.       strcpy (Area, Buffer->Area);
  883.       LastRead = Buffer->LastRead;
  884.       OlderMsg = Buffer->OlderMsg;
  885.       RetVal = TRUE;
  886.    }
  887.  
  888.    return (RetVal);
  889. }
  890.  
  891. USHORT TMsgTag::Read (PSZ pszArea)
  892. {
  893.    USHORT RetVal = FALSE;
  894.  
  895.    if (First () == TRUE)
  896.       do {
  897.          if (!stricmp (pszArea, Area)) {
  898.             RetVal = TRUE;
  899.             break;
  900.          }
  901.       } while (Next () == TRUE);
  902.  
  903.    return (RetVal);
  904. }
  905.  
  906. VOID TMsgTag::Save (VOID)
  907. {
  908.    int fd, i, Count, Changed;
  909.    ULONG Position;
  910.    MSGTAGS *Buffer, *Record;
  911.  
  912.    if ((fd = sopen (DatFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE)) != -1) {
  913.       Record = (MSGTAGS *)Data.First ();
  914.  
  915.       if ((Buffer = (MSGTAGS *)malloc (sizeof (MSGTAGS) * MSGTAGS_INDEX)) != NULL) {
  916.          do {
  917.             Changed = FALSE;
  918.  
  919.             Position = tell (fd);
  920.             Count = read (fd, Buffer, sizeof (MSGTAGS) * MSGTAGS_INDEX) / sizeof (MSGTAGS);
  921.             for (i = 0; i < Count && Record != NULL; i++) {
  922.                if (Buffer[i].UserId == Record->UserId || Buffer[i].Free == TRUE) {
  923.                   memcpy (&Buffer[i], Record, sizeof (MSGTAGS));
  924.                   Buffer[i].Free = FALSE;
  925.                   Record = (MSGTAGS *)Data.Next ();
  926.                   Changed = TRUE;
  927.                }
  928.             }
  929.  
  930.             for (; i < Count; i++) {
  931.                if (Buffer[i].UserId == UserId) {
  932.                   memset (&Buffer[i], 0, sizeof (MSGTAGS));
  933.                   Buffer[i].Free = TRUE;
  934.                   Changed = TRUE;
  935.                }
  936.             }
  937.  
  938.             if (Changed == TRUE) {
  939.                lseek (fd, Position, SEEK_SET);
  940.                write (fd, Buffer, sizeof (MSGTAGS) * Count);
  941.             }
  942.          } while (Count == MSGTAGS_INDEX);
  943.          free (Buffer);
  944.       }
  945.  
  946.       if (Record != NULL) {
  947.          do {
  948.             write (fd, Record, sizeof (MSGTAGS));
  949.          } while ((Record = (MSGTAGS *)Data.Next ()) != NULL);
  950.       }
  951.  
  952.       close (fd);
  953.    }
  954. }
  955.  
  956. VOID TMsgTag::Update (VOID)
  957. {
  958.    MSGTAGS Buffer;
  959.  
  960.    if (Data.Value () != NULL) {
  961.       memcpy (&Buffer, Data.Value (), sizeof (MSGTAGS));
  962.       Buffer.Tagged = Tagged;
  963.       strcpy (Buffer.Area, Area);
  964.       Buffer.LastRead = LastRead;
  965.       Buffer.OlderMsg = OlderMsg;
  966.       memcpy (Data.Value (), &Buffer, sizeof (MSGTAGS));
  967.    }
  968. }
  969.  
  970. // --------------------------------------------------------------------------
  971.  
  972. TFileTag::TFileTag (void)
  973. {
  974.    TotalFiles = 0;
  975.    TotalBytes = 0L;
  976.    Data.Clear ();
  977.  
  978.    strcpy (DatFile, "filetags.dat");
  979.    New ();
  980. }
  981.  
  982. TFileTag::TFileTag (PSZ pszUserFile)
  983. {
  984.    CHAR *p;
  985.  
  986.    TotalFiles = 0;
  987.    TotalBytes = 0L;
  988.    Data.Clear ();
  989.  
  990.    strcpy (DatFile, pszUserFile);
  991.    New ();
  992.  
  993.    p = &DatFile[strlen (DatFile)];
  994.    while (*p != '\\' && *p != '/' && *p != ':' && p > DatFile)
  995.       p--;
  996.    if (*p == '\\' || *p == '/')
  997.       p++;
  998.  
  999.    strcpy (p, "filetags.dat");
  1000. }
  1001.  
  1002. TFileTag::~TFileTag (void)
  1003. {
  1004.    Data.Clear ();
  1005. }
  1006.  
  1007. USHORT TFileTag::Add (VOID)
  1008. {
  1009.    USHORT RetVal = FALSE;
  1010.    FILETAGS Buffer;
  1011.  
  1012.    memset (&Buffer, 0, sizeof (FILETAGS));
  1013.  
  1014.    Buffer.Free = FALSE;
  1015.    Buffer.UserId = UserId;
  1016.    strcpy (Buffer.Area, Area);
  1017.    strcpy (Buffer.Name, Name);
  1018.    strcpy (Buffer.Complete, Complete);
  1019.    Buffer.Size = Size;
  1020.    Buffer.DeleteAfter = DeleteAfter;
  1021.    Buffer.CdRom = CdRom;
  1022.    Buffer.Index = Index = (USHORT)(Data.Elements + 1);
  1023.  
  1024.    if ((RetVal = Data.Add (&Buffer, sizeof (FILETAGS))) == TRUE) {
  1025.       TotalFiles++;
  1026.       TotalBytes += Size;
  1027.    }
  1028.  
  1029.    return (RetVal);
  1030. }
  1031.  
  1032. VOID TFileTag::Change (PSZ pszOldName, PSZ pszNewName)
  1033. {
  1034.    int fd, i, Count, Changed;
  1035.    ULONG Position;
  1036.    FILETAGS *Buffer;
  1037.  
  1038.    if ((fd = sopen (DatFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE)) != -1) {
  1039.       if ((Buffer = (FILETAGS *)malloc (sizeof (FILETAGS) * FILETAGS_INDEX)) != NULL) {
  1040.          do {
  1041.             Changed = FALSE;
  1042.  
  1043.             Position = tell (fd);
  1044.             Count = read (fd, Buffer, sizeof (FILETAGS) * FILETAGS_INDEX) / sizeof (FILETAGS);
  1045.             for (i = 0; i < Count; i++) {
  1046.                if (Buffer[i].Free == FALSE && !stricmp (Buffer[i].Area, pszOldName)) {
  1047.                   strcpy (Buffer[i].Area, pszNewName);
  1048.                   Changed = TRUE;
  1049.                }
  1050.             }
  1051.  
  1052.             if (Changed == TRUE) {
  1053.                lseek (fd, Position, SEEK_SET);
  1054.                write (fd, Buffer, sizeof (FILETAGS) * Count);
  1055.             }
  1056.          } while (Count == FILETAGS_INDEX);
  1057.          free (Buffer);
  1058.       }
  1059.  
  1060.       close (fd);
  1061.    }
  1062. }
  1063.  
  1064. VOID TFileTag::Change (ULONG OldId, ULONG NewId)
  1065. {
  1066.    int fd, i, Count, Changed;
  1067.    ULONG Position;
  1068.    FILETAGS *Buffer;
  1069.  
  1070.    if ((fd = sopen (DatFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE)) != -1) {
  1071.       if ((Buffer = (FILETAGS *)malloc (sizeof (FILETAGS) * FILETAGS_INDEX)) != NULL) {
  1072.          do {
  1073.             Changed = FALSE;
  1074.  
  1075.             Position = tell (fd);
  1076.             Count = read (fd, Buffer, sizeof (FILETAGS) * FILETAGS_INDEX) / sizeof (FILETAGS);
  1077.             for (i = 0; i < Count; i++) {
  1078.                if (Buffer[i].Free == FALSE && Buffer[i].UserId == OldId) {
  1079.                   Buffer[i].UserId = NewId;
  1080.                   Changed = TRUE;
  1081.                }
  1082.             }
  1083.  
  1084.             if (Changed == TRUE) {
  1085.                lseek (fd, Position, SEEK_SET);
  1086.                write (fd, Buffer, sizeof (FILETAGS) * Count);
  1087.             }
  1088.          } while (Count == FILETAGS_INDEX);
  1089.          free (Buffer);
  1090.       }
  1091.  
  1092.       close (fd);
  1093.    }
  1094. }
  1095.  
  1096. USHORT TFileTag::Check (PSZ pszName)
  1097. {
  1098.    USHORT RetVal = FALSE;
  1099.    FILETAGS *ft;
  1100.  
  1101.    if ((ft = (FILETAGS *)Data.First ()) != NULL)
  1102.       do {
  1103.          if (!stricmp (ft->Name, pszName)) {
  1104.             strcpy (Area, ft->Area);
  1105.             strcpy (Name, ft->Name);
  1106.             strcpy (Complete, ft->Complete);
  1107.             Size = ft->Size;
  1108.             DeleteAfter = ft->DeleteAfter;
  1109.             CdRom = ft->CdRom;
  1110.             Index = ft->Index;
  1111.             RetVal = TRUE;
  1112.          }
  1113.       } while (RetVal == FALSE && (ft = (FILETAGS *)Data.Next ()) != NULL);
  1114.  
  1115.    return (RetVal);
  1116. }
  1117.  
  1118. VOID TFileTag::Clear (VOID)
  1119. {
  1120.    Data.Clear ();
  1121.    New ();
  1122.    Index = 0;
  1123.    TotalFiles = 0;
  1124. }
  1125.  
  1126. USHORT TFileTag::First (VOID)
  1127. {
  1128.    USHORT RetVal = FALSE;
  1129.    FILETAGS *Buffer;
  1130.  
  1131.    if ((Buffer = (FILETAGS *)Data.First ()) != NULL) {
  1132.       strcpy (Area, Buffer->Area);
  1133.       strcpy (Name, Buffer->Name);
  1134.       strcpy (Complete, Buffer->Complete);
  1135.       Size = Buffer->Size;
  1136.       DeleteAfter = Buffer->DeleteAfter;
  1137.       CdRom = Buffer->CdRom;
  1138.       Index = Buffer->Index;
  1139.       RetVal = TRUE;
  1140.    }
  1141.  
  1142.    return (RetVal);
  1143. }
  1144.  
  1145. VOID TFileTag::Load (VOID)
  1146. {
  1147.    int fd, i, Count;
  1148.    FILETAGS *Buffer;
  1149.  
  1150.    Data.Clear ();
  1151.  
  1152.    if ((fd = sopen (DatFile, O_RDONLY|O_BINARY, SH_DENYNO, S_IREAD|S_IWRITE)) != -1) {
  1153.       if ((Buffer = (FILETAGS *)malloc (sizeof (FILETAGS) * FILETAGS_INDEX)) != NULL) {
  1154.          do {
  1155.             Count = read (fd, Buffer, sizeof (FILETAGS) * FILETAGS_INDEX) / sizeof (FILETAGS);
  1156.             for (i = 0; i < Count; i++) {
  1157.                if (Buffer[i].Free == FALSE && Buffer[i].UserId == UserId) {
  1158.                   Buffer[i].Index = Index = (USHORT)(Data.Elements + 1);
  1159.                   if (Data.Add (&Buffer[i], sizeof (FILETAGS)) == TRUE) {
  1160.                      TotalFiles++;
  1161.                      TotalBytes += Buffer[i].Size;
  1162.                   }
  1163.                }
  1164.             }
  1165.          } while (Count == FILETAGS_INDEX);
  1166.          free (Buffer);
  1167.       }
  1168.       close (fd);
  1169.    }
  1170.  
  1171.    if ((Buffer = (FILETAGS *)Data.First ()) != NULL) {
  1172.       strcpy (Area, Buffer->Area);
  1173.       strcpy (Name, Buffer->Name);
  1174.       strcpy (Complete, Buffer->Complete);
  1175.       Size = Buffer->Size;
  1176.       DeleteAfter = Buffer->DeleteAfter;
  1177.       CdRom = Buffer->CdRom;
  1178.       Index = Buffer->Index;
  1179.    }
  1180. }
  1181.  
  1182. VOID TFileTag::New (VOID)
  1183. {
  1184.    Area[0] = '\0';
  1185.    Name[0] = '\0';
  1186.    Complete[0] = '\0';
  1187.    Size = 0L;
  1188.    CdRom = DeleteAfter = FALSE;
  1189.    Index = (USHORT)(Data.Elements + 1);
  1190. }
  1191.  
  1192. USHORT TFileTag::Next (VOID)
  1193. {
  1194.    USHORT RetVal = FALSE;
  1195.    FILETAGS *Buffer;
  1196.  
  1197.    if ((Buffer = (FILETAGS *)Data.Next ()) != NULL) {
  1198.       strcpy (Area, Buffer->Area);
  1199.       strcpy (Name, Buffer->Name);
  1200.       strcpy (Complete, Buffer->Complete);
  1201.       Size = Buffer->Size;
  1202.       DeleteAfter = Buffer->DeleteAfter;
  1203.       CdRom = Buffer->CdRom;
  1204.       Index = Buffer->Index;
  1205.       RetVal = TRUE;
  1206.    }
  1207.  
  1208.    return (RetVal);
  1209. }
  1210.  
  1211. USHORT TFileTag::Previous (VOID)
  1212. {
  1213.    USHORT RetVal = FALSE;
  1214.    FILETAGS *Buffer;
  1215.  
  1216.    if ((Buffer = (FILETAGS *)Data.Previous ()) != NULL) {
  1217.       strcpy (Area, Buffer->Area);
  1218.       strcpy (Name, Buffer->Name);
  1219.       strcpy (Complete, Buffer->Complete);
  1220.       Size = Buffer->Size;
  1221.       DeleteAfter = Buffer->DeleteAfter;
  1222.       CdRom = Buffer->CdRom;
  1223.       Index = Buffer->Index;
  1224.       RetVal = TRUE;
  1225.    }
  1226.  
  1227.    return (RetVal);
  1228. }
  1229.  
  1230. VOID TFileTag::Reindex (VOID)
  1231. {
  1232.    USHORT LastIndex;
  1233.    FILETAGS *ft;
  1234.  
  1235.    LastIndex = 1;
  1236.    if ((ft = (FILETAGS *)Data.First ()) != NULL)
  1237.       do {
  1238.          ft->Index = LastIndex++;
  1239.       } while ((ft = (FILETAGS *)Data.Next ()) != NULL);
  1240. }
  1241.  
  1242. VOID TFileTag::Remove (PSZ pszName)
  1243. {
  1244.    USHORT RetVal = FALSE;
  1245.    FILETAGS *ft, *Buffer;
  1246.  
  1247.    if (pszName != NULL) {
  1248.       if ((ft = (FILETAGS *)Data.First ()) != NULL) {
  1249.          do {
  1250.             if (!stricmp (ft->Name, pszName))
  1251.                RetVal = TRUE;
  1252.          } while (RetVal == FALSE && (ft = (FILETAGS *)Data.Next ()) != NULL);
  1253.       }
  1254.       if (RetVal == TRUE) {
  1255.          if (ft->DeleteAfter == TRUE)
  1256.             unlink (ft->Complete);
  1257.          Data.Remove ();
  1258.          TotalFiles--;
  1259.          TotalBytes -= ft->Size;
  1260.       }
  1261.    }
  1262.    else {
  1263.       if (DeleteAfter == TRUE)
  1264.          unlink (Complete);
  1265.       Data.Remove ();
  1266.       TotalFiles--;
  1267.       TotalBytes -= Size;
  1268.    }
  1269.  
  1270.    if ((Buffer = (FILETAGS *)Data.Value ()) != NULL) {
  1271.       strcpy (Area, Buffer->Area);
  1272.       strcpy (Name, Buffer->Name);
  1273.       strcpy (Complete, Buffer->Complete);
  1274.       Size = Buffer->Size;
  1275.       DeleteAfter = Buffer->DeleteAfter;
  1276.       CdRom = Buffer->CdRom;
  1277.       Index = Buffer->Index;
  1278.    }
  1279. }
  1280.  
  1281. USHORT TFileTag::Select (USHORT usIndex)
  1282. {
  1283.    USHORT RetVal = FALSE;
  1284.    FILETAGS *ft;
  1285.  
  1286.    if ((ft = (FILETAGS *)Data.First ()) != NULL)
  1287.       do {
  1288.          if (ft->Index == usIndex) {
  1289.             strcpy (Area, ft->Area);
  1290.             strcpy (Name, ft->Name);
  1291.             strcpy (Complete, ft->Complete);
  1292.             Size = ft->Size;
  1293.             DeleteAfter = ft->DeleteAfter;
  1294.             CdRom = ft->CdRom;
  1295.             Index = ft->Index;
  1296.             RetVal = TRUE;
  1297.          }
  1298.       } while (RetVal == FALSE && (ft = (FILETAGS *)Data.Next ()) != NULL);
  1299.  
  1300.    return (RetVal);
  1301. }
  1302.  
  1303. VOID TFileTag::Save (VOID)
  1304. {
  1305.    int fd, i, Count, Changed;
  1306.    ULONG Position;
  1307.    FILETAGS *Buffer, *Record;
  1308.  
  1309.    if ((fd = sopen (DatFile, O_RDWR|O_BINARY|O_CREAT, SH_DENYNO, S_IREAD|S_IWRITE)) != -1) {
  1310.       Record = (FILETAGS *)Data.First ();
  1311.  
  1312.       if ((Buffer = (FILETAGS *)malloc (sizeof (FILETAGS) * FILETAGS_INDEX)) != NULL) {
  1313.          do {
  1314.             Changed = FALSE;
  1315.  
  1316.             Position = tell (fd);
  1317.             Count = read (fd, Buffer, sizeof (FILETAGS) * FILETAGS_INDEX) / sizeof (FILETAGS);
  1318.             for (i = 0; i < Count && Record != NULL; i++) {
  1319.                if (Buffer[i].UserId == Record->UserId || Buffer[i].Free == TRUE) {
  1320.                   memcpy (&Buffer[i], Record, sizeof (FILETAGS));
  1321.                   Record = (FILETAGS *)Data.Next ();
  1322.                   Changed = TRUE;
  1323.                }
  1324.             }
  1325.  
  1326.             for (; i < Count; i++) {
  1327.                if (Buffer[i].UserId == UserId) {
  1328.                   memset (&Buffer[i], 0, sizeof (FILETAGS));
  1329.                   Buffer[i].Free = TRUE;
  1330.                   Changed = TRUE;
  1331.                }
  1332.             }
  1333.  
  1334.             if (Changed == TRUE) {
  1335.                lseek (fd, Position, SEEK_SET);
  1336.                write (fd, Buffer, sizeof (FILETAGS) * Count);
  1337.             }
  1338.          } while (Count == FILETAGS_INDEX);
  1339.          free (Buffer);
  1340.       }
  1341.  
  1342.       if (Record != NULL) {
  1343.          do {
  1344.             write (fd, Record, sizeof (FILETAGS));
  1345.          } while ((Record = (FILETAGS *)Data.Next ()) != NULL);
  1346.       }
  1347.  
  1348.       close (fd);
  1349.    }
  1350. }
  1351.  
  1352. VOID TFileTag::Update (VOID)
  1353. {
  1354.    FILETAGS *Buffer;
  1355.  
  1356.    if ((Buffer = (FILETAGS *)Data.Value ()) != NULL) {
  1357.       TotalBytes -= Buffer->Size;
  1358.       strcpy (Buffer->Area, Area);
  1359.       strcpy (Buffer->Name, Name);
  1360.       strcpy (Buffer->Complete, Complete);
  1361.       Buffer->Size = Size;
  1362.       Buffer->DeleteAfter = DeleteAfter;
  1363.       Buffer->CdRom = CdRom;
  1364.       TotalBytes += Size;
  1365.    }
  1366. }
  1367.  
  1368.