home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 3 Comm / 03-Comm.zip / TE2DD121.ZIP / TE2DDIR.C
C/C++ Source or Header  |  1992-07-26  |  20KB  |  573 lines

  1. //
  2. //  Te2DDir.C -- TE/2 Dialing Directory Manipulation Functions
  3. //
  4. //    CopyRight 1990-1992 by Oberon Software, Mankato, MN
  5. //    All Rights Reserved
  6. //
  7. //  The code in this file may be freely used for the creation of utility
  8. //  programs which manipulate TE/2 Dialing Directories such as:
  9. //      Sorting Utilities
  10. //      Printing Utilities
  11. //      Conversion Utilities
  12. //
  13. //  You may not commericially distribute and/or charge for any program
  14. //  made which contains any of the code contained in this file.  If you
  15. //  do create a useful utility for manipulating TE/2 Directory Files with
  16. //  some or all of this code you are urged to upload the program to the
  17. //  Oberon Software User Support BBS (507-388-1154) so that it may be
  18. //  made available to other users.
  19. //
  20.  
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24.  
  25. #define INCL_BASE
  26. #include <os2.h>
  27.  
  28.  
  29. // --------------------------------------------------------------------------
  30. // ---- Constants
  31.  
  32.   // ---- Parity designation codes for directory entries
  33. #define NO_PARITY         0       // No Parity
  34. #define ODD_PARITY        1       // Odd Parity
  35. #define EVEN_PARITY       2       // Even Parity
  36. #define MARK_PARITY       3       // Mark Parity
  37. #define SPACE_PARITY      4       // Space Parity
  38.  
  39.   // ---- StopBit designation codes for directory entries
  40. #define STOPBITS_1        0       // 1 Stopbit
  41. #define STOPBITS_15       1       // 1.5 Stopbits
  42. #define STOPBITS_2        2       // 2 Stopbits
  43.  
  44.   // ---- Protocol designation codes for directory entries
  45. #define PROTOCOL_ASCII    0       // Ascii protocol (upload only)
  46. #define PROTOCOL_XMODEM   1       // XModem (CRC)
  47. #define PROTOCOL_XMODEM1K 2       // XModem-1K
  48. #define PROTOCOL_YMODEM   3       // YModem
  49. #define PROTOCOL_ZMODEM   4       // ZModem
  50. #define PROTOCOL_YMODEMG  5       // YModem-G (not used before 1.00c)
  51. #define PROTOCOL_CISQB    6       // CIS BPlus (for future use)
  52.  
  53.   // ---- Emulation designation codes for directory entries
  54. #define EMULATE_TTY       0       // Teletype emulation
  55. #define EMULATE_ANSI      1       // ANSI-BBS
  56. #define EMULATE_XANSI     2       // ANSI-TE/2
  57. #define EMULATE_VT100     3       // VT100
  58.  
  59.   // ---- Other important constants
  60. #define ORIG_MAXDENTRY    50      // # of entries in pre-1.00c files
  61. #define MAXDENTRY         200     // # of entries in files since 1.00c
  62. #define TAGLEN            5       // Length of TAG field
  63. #define NAMELEN           25      // Length of NAME field
  64. #define NUMLEN            29      // Length of NUMBER field
  65. #define SCRIPTLEN         63      // Length of SCRIPT field
  66. #define ACCCODES          10      // Number of access code entries/file
  67. #define ACCCLEN           NUMLEN  // Length of access code entry
  68. #define RDF_BUFSIZ        80      // Length of a utility buffer
  69.  
  70.  
  71. // --------------------------------------------------------------------------
  72. // ---- Typedefs
  73.  
  74.   // ---- Directory entry structure
  75. typedef struct _DDENTRY
  76. {
  77.   char     tag[TAGLEN+1];       // May be any asciiz data
  78.   char     name[NAMELEN+1];     // May be any asciiz data
  79.   char     number[NUMLEN+1];    // May be any asciiz data
  80.   USHORT   baud;                // 110, 150, 300, 600, 1200, 2400, 4800, 9600,
  81.                                 //   19200, 38400, or 57600
  82.   USHORT   parity;              // NO_PARITY, ODD_PARITY, EVEN_PARITY,
  83.                                 //   MARK_PARITY, or SPACE_PARITY
  84.   USHORT   wordlen;             // 7 or 8
  85.   USHORT   stopbits;            // STOPBITS_1, STOPBITS_15, or STOPBITS_2
  86.   USHORT   duplex;              // TRUE == Half Duplex, FALSE == Full Duplex
  87.   USHORT   protocol;            // PROTOCOL_ASCII, PROTOCOL_XMODEM,
  88.                                 //   PROTOCOL_XMODEM1K, PROTOCOL_YMODEM,
  89.                                 //   PROTOCOL_ZMODEM, PROTOCOL_YMODEMG, or
  90.                                 //   PROTOCOL_CISQB
  91.   USHORT   emulate;             // EMULATE_TTY, EMULATE_ANSI, EMULATE_XANSI,
  92.                                 //   or EMULATE_VT100
  93.   char     script[SCRIPTLEN+1]; // May be any asciiz data
  94.   USHORT   connected;           // Count of times connected
  95.   DATETIME lastconnect;         // Date/Time of last connect
  96.   char     password[NAMELEN+1]; // May be any asciiz data
  97. } DDENTRY;
  98.  
  99.  
  100. // --------------------------------------------------------------------------
  101. // ---- Local data
  102.  
  103.   // ---- Array of pointers to directory entries, will be allocated and
  104.   //      filled by ReadDirectoryFile()
  105. static DDENTRY *directory[MAXDENTRY];
  106.  
  107.   // ---- Array of string buffers to hold access codes associated with
  108.   //      a dialing directory file.
  109. static char accCodes[ACCCODES][ACCCLEN+1];
  110.  
  111.   // ---- Signiture strings found in the header record of a directory
  112.   //      file from various versions of TE/2
  113. static char *dirFileSig_v0    = "TE/2 Directory v1.0";
  114. static char *dirFileSig_v100F = "TE/2 Directory v1.00α1";
  115. static char *dirFileSig_v110D = "TE/2 Directory v1.00α2";
  116. static char *dirFileSig       = "TE/2 Directory v1.10.E";
  117.  
  118.   // ---- An empty DATETIME structure used for default value of "lastconnect"
  119.   //      in older directory files
  120. static DATETIME nulDate   = { '\0', '\0', '\0', '\0', '\0', '\0', 0, 0, '\0' };
  121.  
  122.  
  123. // --------------------------------------------------------------------------
  124.  
  125.   // ---- Function prototypes
  126.  
  127. static int freadStrg(char *buf, FILE *fp);  // Read asciiz from file
  128. static int fwriteStrg(char *buf, FILE *fp); // Write asciiz to file
  129.  
  130. static int ReadV0Directory(FILE *fp);       // Read a very old dir file
  131. static int ReadV100FDirectory(FILE *fp);    // Read an old dir file
  132. static int ReadCurrentDirectory(FILE *fp, BOOL f)  // Read a current dir file
  133.  
  134. int  ReadDirectoryFile(char *fname);        // Read any vsn dir file
  135. int  WriteDirectoryFile(char *fname);       // Write a current vsn dir file
  136.  
  137. void EmptyDirectory(void);                  // free all allocated memory
  138.  
  139.  
  140. // --------------------------------------------------------------------------
  141. // ---- Functions
  142.  
  143.  
  144.   // -----------------------------------------------------------------------
  145.   // Read an ASCIIZ string from a file, expects 'buf' to be large enough
  146.   // to hold any conceivable number of characters (i.e., there is no
  147.   // error checking).
  148.  
  149. static int freadStrg(char *buf, FILE *fp)
  150. {
  151.   int  i = 0, err = FALSE;
  152.   char c;
  153.  
  154.   do
  155.   {
  156.     if (fread(&c, sizeof(char), 1, fp) != 1)
  157.     {
  158.       err = TRUE;
  159.       break;
  160.     }
  161.     buf[i++] = c;
  162.   }
  163.   while (c);
  164.  
  165.   return err;
  166. }
  167.  
  168.  
  169.  
  170.   // -----------------------------------------------------------------------
  171.   // Write an ASCIIZ string to a file
  172.  
  173. static int fwriteStrg(char *buf, FILE *fp)
  174. {
  175.   int  i = 0, err = FALSE;
  176.   char c;
  177.  
  178.   do
  179.   {
  180.     c = buf[i++];
  181.     if (fwrite(&c, sizeof(char), 1, fp) != 1)
  182.     {
  183.       err = TRUE;
  184.       break;
  185.     }
  186.   }
  187.   while (c);
  188.  
  189.   return err;
  190. }
  191.  
  192.  
  193. // --------------------------------------------------------------------------
  194.  
  195.  
  196.   // -----------------------------------------------------------------------
  197.   // General Notes about the Read*Directory() functions:
  198.   //
  199.   //   The "directory" array is an array of pointers to directory entry
  200.   //   structures, it contains all NULL pointers by default.  Each
  201.   //   function will allocate entries as needed as it encounters valid
  202.   //   entries in the directory file.  Empty entries in the file consist
  203.   //   of a single, zero byte.  When an empty entry is encountered, it's
  204.   //   pointer in the array is left NULL.
  205.   //
  206.   //   These functions may be called more than once to reread the same
  207.   //   or other directory files.  Space for entries will be reused,
  208.   //   allocated, and/or freed as required.
  209.   //
  210.   //   Each function returns TRUE if the file was read with no errors
  211.   //   detected, FALSE if any error occured.  If FALSE is returned, the
  212.   //   directory may be partially read and available for examination.
  213.   //
  214.   //   After the caller is done with the "directory" array, the
  215.   //   EmptyDirectory() function should be called to make sure that all
  216.   //   allocated memory has been freed.
  217.   // -----------------------------------------------------------------------
  218.  
  219.  
  220.   // -----------------------------------------------------------------------
  221.   // Read a "version 0" directory file into memory.  This is the file format
  222.   // created by TE/2 Version 1.00b.  Expects the current position in the
  223.   // file to be pointing past the header information at the first real entry.
  224.  
  225. static int ReadV0Directory(FILE *fp)
  226. {
  227.   int  i, j, err;
  228.   char buf = 0;
  229.  
  230.   for (i = 0; i < ORIG_MAXDENTRY; i++)
  231.   {
  232.     if (fread(&buf, sizeof(char), 1, fp) == 1)
  233.     {
  234.       if (buf)  // If there is an entry at this position
  235.       {
  236.         // Either create an entry structure if this is a first read or
  237.         //   clean up an existing one for reuse.
  238.         if (!directory[i])
  239.           directory[i] = calloc(1, sizeof(DDENTRY));
  240.         else
  241.           memset(directory[i], 0, sizeof(DDENTRY));
  242.  
  243.         // Read the data that's there
  244.         err  =  freadStrg(directory[i]->tag, fp);
  245.         err |=  freadStrg(directory[i]->name, fp);
  246.         err |=  freadStrg(directory[i]->number, fp);
  247.         err |= (fread(&(directory[i]->baud),     sizeof(USHORT), 1, fp) != 1);
  248.         err |= (fread(&(directory[i]->parity),   sizeof(USHORT), 1, fp) != 1);
  249.         err |= (fread(&(directory[i]->wordlen),  sizeof(USHORT), 1, fp) != 1);
  250.         err |= (fread(&(directory[i]->stopbits), sizeof(USHORT), 1, fp) != 1);
  251.         err |= (fread(&(directory[i]->duplex),   sizeof(USHORT), 1, fp) != 1);
  252.         err |= (fread(&(directory[i]->protocol), sizeof(USHORT), 1, fp) != 1);
  253.         err |=  freadStrg(directory[i]->script, fp);
  254.         if (err) break;
  255.  
  256.         // Insert default values, this version of the file didn't contain
  257.         //   these fields.
  258.         directory[i]->emulate = EMULATE_XANSI;
  259.         directory[i]->connected = 0;
  260.         directory[i]->lastconnect = nulDate;
  261.       }
  262.       else if (directory[i])
  263.       {
  264.         // No entry at this position in this file.  If there was already
  265.         // space allocated, free it.
  266.         free(directory[i]);
  267.         directory[i] = NULL;
  268.       }
  269.     }
  270.     else
  271.       break;
  272.   }
  273.  
  274.   if (!err)
  275.   {
  276.     // This version of the file did not contain as many records as later
  277.     // ones.  Make up the difference here with NULL entries.
  278.     for (j = i; j < MAXDENTRY; j++)
  279.       if (directory[j])
  280.       {
  281.         free(directory[j]);
  282.         directory[j] = NULL;
  283.       }
  284.  
  285.     // This version of the file didn't contain any Access Codes.  Fill in
  286.     // with NULL entries.
  287.     for (j = 0; j < ACCCODES; j++)
  288.       memset(accCodes[j], 0, ACCCLEN+1);
  289.   }
  290.  
  291.   // Return TRUE on a successful read, FALSE if an error occured
  292.   return (i == ORIG_MAXDENTRY);
  293. }
  294.  
  295.  
  296.  
  297.  
  298.   // -----------------------------------------------------------------------
  299.   // Read a "version 100F" directory file into memory.  This is the file
  300.   // format created by TE/2 starting with Version 1.00c and continued
  301.   // through version 1.00f. Expects the current position in the file to
  302.   // be pointing past the header information at the first real entry.
  303.  
  304. static int ReadV100FDirectory(FILE *fp)
  305. {
  306.   int  i, j, err;
  307.   char buf = 0;
  308.  
  309.   for (i = 0; i < MAXDENTRY; i++)
  310.   {
  311.     if (fread(&buf, sizeof(char), 1, fp) == 1)
  312.     {
  313.       if (buf)
  314.       {
  315.         // Either create an entry structure if this is a first read or
  316.         //   clean up an existing one for reuse.
  317.         if (!directory[i])
  318.           directory[i] = calloc(1, sizeof(DDENTRY));
  319.         else
  320.           memset(directory[i], 0, sizeof(DDENTRY));
  321.  
  322.         // Read the data that's there
  323.         err  =  freadStrg(directory[i]->tag, fp);
  324.         err |=  freadStrg(directory[i]->name, fp);
  325.         err |=  freadStrg(directory[i]->number, fp);
  326.         err |= (fread(&(directory[i]->baud),     sizeof(USHORT), 1, fp) != 1);
  327.         err |= (fread(&(directory[i]->parity),   sizeof(USHORT), 1, fp) != 1);
  328.         err |= (fread(&(directory[i]->wordlen),  sizeof(USHORT), 1, fp) != 1);
  329.         err |= (fread(&(directory[i]->stopbits), sizeof(USHORT), 1, fp) != 1);
  330.         err |= (fread(&(directory[i]->duplex),   sizeof(USHORT), 1, fp) != 1);
  331.         err |= (fread(&(directory[i]->protocol), sizeof(USHORT), 1, fp) != 1);
  332.         err |= (fread(&(directory[i]->emulate),  sizeof(USHORT), 1, fp) != 1);
  333.         err |=  freadStrg(directory[i]->script, fp);
  334.         if (err) break;
  335.  
  336.         // Insert default values, this version of the file didn't contain
  337.         //   these fields.
  338.         directory[i]->connected = 0;
  339.         directory[i]->lastconnect = nulDate;
  340.       }
  341.       else if (directory[i])
  342.       {
  343.         // No entry at this position in this file.  If there was already
  344.         // space allocated, free it.
  345.         free(directory[i]);
  346.         directory[i] = NULL;
  347.       }
  348.     }
  349.     else
  350.       break;
  351.   }
  352.  
  353.   if (!err)
  354.   {
  355.     // This version of the file didn't contain any Access Codes.  Fill in
  356.     // with NULL entries.
  357.     for (j = 0; j < ACCCODES; j++)
  358.       memset(accCodes[j], 0, ACCCLEN+1);
  359.   }
  360.  
  361.   // Return TRUE on a successful read, FALSE if an error occured
  362.   return (i == MAXDENTRY);
  363. }
  364.  
  365.  
  366.  
  367.  
  368.   // -----------------------------------------------------------------------
  369.   // Read a "current version" directory file into memory.  This is the
  370.   // file format created by TE/2 starting with Version 1.10a. Expects
  371.   // the current position in the file to be pointing past the header
  372.   // information at the first real entry.
  373.   // -----------------------------------------------------------------------
  374.   // Note regarding the f110EFlag: The only change in the 1.10e file format
  375.   // from the previous version is the including of the password field at the
  376.   // end of the record.  We can use the same routine to ready both
  377.   // versions.
  378.  
  379. static int ReadCurrentDirectory(FILE *fp, BOOL f110EFlag)
  380. {
  381.   int  i, j, err;
  382.   char buf = 0;
  383.  
  384.   for (i = 0; i < MAXDENTRY; i++)
  385.   {
  386.     if (fread(&buf, sizeof(char), 1, fp) == 1)
  387.     {
  388.       if (buf)
  389.       {
  390.         // Either create an entry structure if this is a first read or
  391.         //   clean up an existing one for reuse.
  392.         if (!directory[i])
  393.           directory[i] = calloc(1, sizeof(DDENTRY));
  394.         else
  395.           memset(directory[i], 0, sizeof(DDENTRY));
  396.  
  397.         // Read the data
  398.         err  =  freadStrg(directory[i]->tag, fp);
  399.         err |=  freadStrg(directory[i]->name, fp);
  400.         err |=  freadStrg(directory[i]->number, fp);
  401.         err |= (fread(&(directory[i]->baud),        sizeof(USHORT),   1, fp) != 1);
  402.         err |= (fread(&(directory[i]->parity),      sizeof(USHORT),   1, fp) != 1);
  403.         err |= (fread(&(directory[i]->wordlen),     sizeof(USHORT),   1, fp) != 1);
  404.         err |= (fread(&(directory[i]->stopbits),    sizeof(USHORT),   1, fp) != 1);
  405.         err |= (fread(&(directory[i]->duplex),      sizeof(USHORT),   1, fp) != 1);
  406.         err |= (fread(&(directory[i]->protocol),    sizeof(USHORT),   1, fp) != 1);
  407.         err |= (fread(&(directory[i]->emulate),     sizeof(USHORT),   1, fp) != 1);
  408.         err |=  freadStrg(directory[i]->script, fp);
  409.         err |= (fread(&(directory[i]->connected),   sizeof(USHORT),   1, fp) != 1);
  410.         err |= (fread(&(directory[i]->lastconnect), sizeof(DATETIME), 1, fp) != 1);
  411.         if (f110EFlag) err |=  freadStrg(directory[i]->password, fp);
  412.         if (err) break;
  413.       }
  414.       else if (directory[i])
  415.       {
  416.         // No entry at this position in this file.  If there was already
  417.         // space allocated, free it.
  418.         free(directory[i]);
  419.         directory[i] = NULL;
  420.       }
  421.     }
  422.     else
  423.       break;
  424.   }
  425.  
  426.   if (!err && !feof(fp))
  427.   {
  428.     // Read the Access Codes associated with this directory
  429.     for (j = 0; j < ACCCODES && !err; j++)
  430.       err |= freadStrg(accCodes[j], fp);
  431.   }
  432.  
  433.   // Return TRUE on a successful read, FALSE if an error occured
  434.   return ((i == MAXDENTRY) && !err);
  435. }
  436.  
  437.  
  438.  
  439.  
  440.   // -----------------------------------------------------------------------
  441.   // Read any format directory file into memory.
  442.  
  443. int ReadDirectoryFile(char *fname)
  444. {
  445.   FILE *fp;
  446.   int  i, rVal = FALSE;
  447.   char buf[RDF_BUFSIZ];
  448.  
  449.   if (fp = fopen(fname, "rb"))
  450.   {
  451.     // "dirFileSig", the signiture on a current version directory file is
  452.     // the longest signiture in any version.  We'll read enough of the
  453.     // header to get the whole string; we may need to seek back in the
  454.     // file if it's an older version.
  455.  
  456.     i = strlen(dirFileSig);
  457.     if (fread(buf, sizeof(char), i, fp) == i)
  458.     {
  459.       if (strncmp(buf, dirFileSig, i) == 0)
  460.       {
  461.         // Current style directory, Version 1.10.e on
  462.         rVal = ReadCurrentDirectory(fp, TRUE);
  463.       }
  464.       else if (strncmp(buf, dirFileSig_v110D, strlen(dirFileSig_v110D)) == 0)
  465.       {
  466.         // Version 1.10.a through 1.10.d style directory
  467.         rVal = ReadCurrentDirectory(fp, FALSE);
  468.       }
  469.       else if (strncmp(buf, dirFileSig_v100F, strlen(dirFileSig_v100F)) == 0)
  470.       {
  471.         // Version 1.00.c through 1.00.f style directory
  472.         fseek(fp, (long)(strlen(dirFileSig_v100F)), SEEK_SET);
  473.         rVal = ReadV100FDirectory(fp);
  474.       }
  475.       else if (strncmp(buf, dirFileSig_v0, strlen(dirFileSig_v0)) == 0)
  476.       {
  477.         // Earliest style, first alpha
  478.         fseek(fp, (long)(strlen(dirFileSig_v0)), SEEK_SET);
  479.         rVal = ReadV0Directory(fp);
  480.       }
  481.     }
  482.     fclose(fp);
  483.   }
  484.  
  485.   return rVal;
  486. }
  487.  
  488.  
  489.  
  490.   // -----------------------------------------------------------------------
  491.   // Write a directory file of the current format.
  492.  
  493. int WriteDirectoryFile(char *fname)
  494. {
  495.   FILE *fp;
  496.   int  i, j, err, rVal = FALSE;
  497.   char c;
  498.  
  499.   if (fp = fopen(fname, "wb"))
  500.   {
  501.     i = strlen(dirFileSig);
  502.     if (fwrite(dirFileSig, sizeof(char), i, fp) == i)
  503.     {
  504.       for (i = 0; i < MAXDENTRY; i++)
  505.       {
  506.         if (directory[i])
  507.         {
  508.           c = 1;
  509.           if (fwrite(&c, sizeof(char), 1, fp) == 1)
  510.           {
  511.             err  =  fwriteStrg(directory[i]->tag, fp);
  512.             err |=  fwriteStrg(directory[i]->name, fp);
  513.             err |=  fwriteStrg(directory[i]->number, fp);
  514.             err |= (fwrite(&(directory[i]->baud),        sizeof(USHORT),   1, fp) != 1);
  515.             err |= (fwrite(&(directory[i]->parity),      sizeof(USHORT),   1, fp) != 1);
  516.             err |= (fwrite(&(directory[i]->wordlen),     sizeof(USHORT),   1, fp) != 1);
  517.             err |= (fwrite(&(directory[i]->stopbits),    sizeof(USHORT),   1, fp) != 1);
  518.             err |= (fwrite(&(directory[i]->duplex),      sizeof(USHORT),   1, fp) != 1);
  519.             err |= (fwrite(&(directory[i]->protocol),    sizeof(USHORT),   1, fp) != 1);
  520.             err |= (fwrite(&(directory[i]->emulate),     sizeof(USHORT),   1, fp) != 1);
  521.             err |=  fwriteStrg(directory[i]->script, fp);
  522.             err |= (fwrite(&(directory[i]->connected),   sizeof(USHORT),   1, fp) != 1);
  523.             err |= (fwrite(&(directory[i]->lastconnect), sizeof(DATETIME), 1, fp) != 1);
  524.             err |=  fwriteStrg(directory[i]->password, fp);
  525.             if (err) break;
  526.           }
  527.           else
  528.             break;
  529.         }
  530.         else
  531.         {
  532.           c = 0;
  533.           if (fwrite(&c, sizeof(char), 1, fp) != 1)
  534.             break;
  535.         }
  536.       }
  537.       rVal = (i == MAXDENTRY);
  538.  
  539.       if (!err && !feof(fp))
  540.       {
  541.         for (j = 0; j < ACCCODES; j++)
  542.           err |= fwriteStrg(accCodes[j], fp);
  543.       }
  544.  
  545.     }
  546.     fclose(fp);
  547.   }
  548.  
  549.   return rVal;
  550. }
  551.  
  552.  
  553.  
  554.   // -----------------------------------------------------------------------
  555.   // Free all allocated memory associated with the directory
  556.  
  557.  
  558. void EmptyDirectory()
  559. {
  560.   int i;
  561.  
  562.   for (i = 0; i < MAXDENTRY; i++)
  563.   {
  564.     if (directory[i])
  565.     {
  566.       free(directory[i]);
  567.       directory[i] = NULL;
  568.     }
  569.   }
  570. }
  571.  
  572.  
  573.