home *** CD-ROM | disk | FTP | other *** search
/ CD Shareware Magazine 1996 December / CD_shareware_12-96.iso / WIN / INTERNET / MLUTL110.ZIP / ML_INC.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-10-16  |  9.5 KB  |  360 lines

  1. (* This is an "INCLUDE" file for "MLAdd.pas" and "MLDrop.pas", by DDA *)
  2.  
  3. TYPE
  4.   ListLink = ^NameRecord;
  5.   NameRecord = RECORD
  6.                  Name   : STRING[70];
  7.                  Next   : ListLink;
  8.                END;
  9.  
  10. {$IFDEF MLDROP}
  11.  
  12. PROCEDURE ExitOnError (err : BYTE; msg : STRING);
  13. CONST
  14.   NL = #13#10;
  15. BEGIN
  16.   WriteLn ('MLDrop v1.10 - Free DOS utility: Drop names from an Internet mailing list.');
  17.   WriteLn ('Oct. 16th, 1996. Copyright (c) 1996 by David Daniel Anderson - Reign Ware.'+NL);
  18.   WriteLn ('Usage:   MLDrop  MasterList  drop_list(s)'+NL);
  19.   WriteLn ('Example: MLDrop  friends  enemies'+NL);
  20.   IF err > 0 THEN BEGIN
  21.     IF err > 1 THEN Write(#7);
  22.     WriteLn ('Error encountered (#', err, '):');
  23.     WriteLn (msg);
  24.   END;
  25.   Halt (err);
  26. END;
  27.  
  28. {$ENDIF}
  29. {$IFDEF MLADD}
  30.  
  31. PROCEDURE ExitOnError (err : BYTE; msg : STRING);
  32. CONST
  33.   NL = #13#10;
  34. BEGIN
  35.   WriteLn ('MLAdd v1.10 - Free DOS utility: Add names to an Internet mailing list.');
  36.   WriteLn ('Oct. 16th, 1996. Copyright (c) 1996 by David Daniel Anderson - Reign Ware.'+NL);
  37.   WriteLn ('Usage:   MLAdd  MasterList  [add_list(s)]'+NL);
  38.   WriteLn ('Example: MLAdd  friends  buddies'+NL);
  39.   IF err > 0 THEN BEGIN
  40.     IF err > 1 THEN Write(#7);
  41.     WriteLn ('Error encountered (#', err, '):');
  42.     WriteLn (msg);
  43.   END;
  44.   Halt (err);
  45. END;
  46.  
  47. {$ENDIF}
  48.  
  49. PROCEDURE CheckIO;
  50. BEGIN
  51.   IF IOResult <> 0 THEN ExitOnError (7, 'File handling error.');
  52. END;
  53.  
  54. FUNCTION Upper (lstr : STRING): STRING;
  55.   PROCEDURE UpFast (VAR Str: STRING);  {** from SWAG **}
  56.   INLINE($8C/$DA/$5E/$1F/$FC/$AC/$30/$E4/$89/$C1/$E3/$12/$BB/Ord('a')/Ord('z')/
  57.        $AC/$38/$D8/$72/$08/$38/$F8/$77/$04/$80/$6C/$FF/$20/$E2/$F1/$8E/$DA);
  58. BEGIN
  59.   UpFast (lstr);
  60.   Upper := lstr;
  61. END;
  62.  
  63. FUNCTION IsFile (CONST FileName: PATHSTR): BOOLEAN;
  64. VAR
  65.   Attr  : WORD;
  66.   cFile : FILE;
  67. BEGIN
  68.   Assign (cFile, FileName);
  69.   GetFAttr (cFile, Attr);
  70.   IF (DosError = 0) AND ((Attr AND Directory) <> Directory)
  71.     THEN IsFile := TRUE
  72.     ELSE IsFile := FALSE;
  73. END;
  74.  
  75. FUNCTION IsDir (CONST FileName: PATHSTR): BOOLEAN;
  76. VAR
  77.   Attr  : WORD;
  78.   cFile : FILE;
  79. BEGIN
  80.   Assign (cFile, FileName);
  81.   GetFAttr (cFile, Attr);
  82.   IF (DosError = 0) AND ((Attr AND Directory) = Directory)
  83.     THEN IsDir := TRUE
  84.     ELSE IsDir := FALSE;
  85. END;
  86.  
  87. PROCEDURE EraseFile (CONST FileName : STRING);
  88. VAR
  89.   cFile : FILE;
  90. BEGIN
  91.   IF IsFile (FileName) THEN BEGIN
  92.     Assign (cFile, FileName);
  93.     SetFAttr (cFile, 0);
  94.     Erase (cFile); CheckIO;
  95.   END;
  96. END;
  97.  
  98. FUNCTION GetFilePath (CONST PSTR: STRING; VAR sDir: DIRSTR): PATHSTR;
  99. VAR
  100.   jPath     : PATHSTR;  { file path,       }
  101.   jDir      : DIRSTR;   {      directory,  }
  102.   jName     : NAMESTR;  {      name,       }
  103.   jExt      : EXTSTR;   {      extension.  }
  104. BEGIN
  105.   jPath := PSTR;
  106.   IF jPath = '' THEN jPath := '*.*';
  107.   IF (NOT (jPath [Length (jPath)] IN [':', '\'])) AND IsDir (jPath) THEN
  108.     jPath := jPath + '\';
  109.   IF (jPath [Length (jPath)] IN [':', '\']) THEN
  110.     jPath := jPath + '*.*';
  111.  
  112.   FSplit (FExpand (jPath), jDir, jName, jExt);
  113.   jPath := jDir + jName+ jExt;
  114.  
  115.   sDir := jDir;
  116.   GetFilePath := jPath;
  117. END;
  118.  
  119. FUNCTION FindName (Address: STRING): STRING;
  120. (*
  121. │ Allowed characters:                │ Disallowed characters:
  122. ├────────────────────────────────────┼──────────────────────────────
  123. │                                    │   0-32   Control chars + Space
  124. │                                    │  33-34   !"
  125. │#                            35     │  36-44   $%&'()*+,
  126. │-.                           45- 46 │  47      /
  127. │0123456789                   48- 57 │  58-63   :;<=>?
  128. │@                            64     │  64      @       (valid ONCE)
  129. │ABCDEFGHIJKLMNOPQRSTUVWXYZ   65- 90 │  91-94   [\]^
  130. │_                            95     │  96      `
  131. │abcdefghijklmnopqrstuvwxyz   97-122 │ 123-126  {|}~
  132. │                                    │ 127-255  Upper ASCII
  133. *)
  134. VAR
  135.   EmailChars,
  136.   NoDelimits : SET OF CHAR;
  137.   aPos, first, last : BYTE;
  138.   DONE : BOOLEAN;
  139.  
  140. BEGIN
  141.   EmailChars := ['#','-','.','0'..'9','A'..'Z','_','a'..'z'];
  142.   NoDelimits := ['#','-','.','_'];
  143.  
  144.   aPos := Pos ('@', Address);
  145.   IF aPos > 0 THEN
  146.   BEGIN
  147.     first := aPos;
  148.     DONE := FALSE;
  149.     WHILE NOT DONE DO
  150.       IF ((first-1) = 0) OR (NOT (Address[first-1] IN EmailChars))
  151.         THEN DONE := TRUE
  152.         ELSE Dec (first);
  153.  
  154.     last := aPos;
  155.     DONE := FALSE;
  156.     WHILE NOT DONE DO
  157.       IF ((last+1) > Length (Address)) OR (NOT (Address[last+1] IN EmailChars))
  158.         THEN DONE := TRUE
  159.         ELSE Inc (last);
  160.  
  161.     Address := Copy (Address, first, 1+last-first);
  162.  
  163.     WHILE Address[1] IN NoDelimits DO
  164.       Address := Copy (Address, 2, Length (Address) - 1);
  165.     WHILE Address[Length (Address)] IN NoDelimits DO
  166.       Address := Copy (Address, 1, Length (Address) - 1);
  167.  
  168.     IF (Address[1] = '@') OR (Address[Length (Address)] = '@') THEN
  169.       Address := '';
  170.  
  171.     IF Address <> '' THEN
  172.     BEGIN
  173.       aPos := Pos ('@', Address) + 2;
  174.       last := Length (Address);
  175.       DONE := FALSE;
  176.       WHILE (aPos <= last) AND (NOT DONE) DO
  177.       BEGIN
  178.         IF Address[aPos] = '.' THEN DONE := TRUE;
  179.         Inc (aPos);
  180.       END;
  181.       IF NOT DONE THEN Address := '';
  182.     END;
  183.   END
  184.   ELSE
  185.     Address := '';
  186.  
  187.   FindName := Address;
  188. END;
  189.  
  190. PROCEDURE AddToList (VAR NameList: ListLink; fName: STRING; VAR TotalMems: WORD);
  191. VAR
  192.   NewName    : STRING;
  193.   Anchor,
  194.   NameNode : ListLink;
  195.   InFile     : TEXT;
  196.  
  197. BEGIN
  198.   Anchor := NameList;
  199.   IF NameList <> NIL THEN    { advance to end of list }
  200.     WHILE (NameList^.Next) <> NIL DO NameList := NameList^.Next;
  201.  
  202.   NameNode := NIL;
  203.  
  204.   IF IsFile (fName) THEN BEGIN
  205.     Assign (InFile, fName);
  206.     Reset (InFile); CheckIO;
  207.     Write ('Reading names to add from: ', fName, ', please wait ... ');
  208.  
  209.     WHILE NOT SeekEof (InFile) DO
  210.     BEGIN
  211.       ReadLn (InFile, NewName); CheckIO;   { fill in new data }
  212.       NewName := FindName (NewName);       { extract email address from line }
  213.  
  214.       IF (Length (NewName) > 1) AND (NewName[1] <> '@') THEN
  215.       BEGIN
  216.  
  217.         Inc (TotalMems);
  218.         New (NameNode);
  219.  
  220.         NameNode^.Name := Copy (NewName, 1, 80);
  221.         NameNode^.Next := NIL;
  222.  
  223.         IF NameList = NIL                    { add to end of list }
  224.           THEN Anchor := NameNode            { point to first node }
  225.           ELSE NameList^.Next := NameNode;
  226.  
  227.         NameList := NameNode;                { point to last node }
  228.       END;
  229.     END; {while}
  230.  
  231.     Close (InFile); CheckIO;
  232.     NameList := Anchor;
  233.   END;
  234.  
  235.   WriteLn ('done!');
  236.   NameList := Anchor;
  237. END;
  238.  
  239. PROCEDURE EditList (VAR NameList: ListLink; VAR TotalMems: WORD);
  240. VAR
  241.   TempName : STRING;
  242.   Anchor,
  243.   TempNode,
  244.   Chain : ListLink;
  245. BEGIN
  246.   Anchor := NameList;
  247.  
  248.   WHILE (NameList <> NIL) AND (NameList^.Next <> NIL) DO
  249.   BEGIN
  250.     { Take one name at a time, and go through rest of list, deleting dups }
  251.  
  252.     TempName := Upper (NameList^.Name);
  253.  
  254.     Chain := NameList;
  255.     WHILE (Chain <> NIL) AND (Chain^.Next <> NIL) DO
  256.     BEGIN
  257.       IF Upper (Chain^.Next^.Name) = TempName THEN
  258.       BEGIN
  259.         TempNode := Chain^.Next;
  260.         Chain^.Next := Chain^.Next^.Next;
  261.         Dispose (TempNode);
  262.         Dec (TotalMems, 1);
  263.       END
  264.       ELSE
  265.         Chain := Chain^.Next;
  266.     END;
  267.  
  268.     NameList := NameList^.Next;
  269.   END;
  270.   NameList := Anchor;
  271. END;
  272.  
  273. PROCEDURE WriteList (VAR NameList: ListLink; fName: STRING; VAR TotalMems: WORD);
  274. VAR
  275.   MemList : TEXT;
  276.   Chain : ListLink;
  277. BEGIN
  278.   Assign (MemList, fName);
  279.   Rewrite (MemList);
  280.   IF (IOResult <> 0) THEN
  281.     ExitOnError (4, 'Cannot create file for new master mailing list.');
  282.  
  283.   WHILE NameList <> NIL DO
  284.   BEGIN
  285.     WriteLn (MemList, NameList^.Name);
  286.     Chain := NameList;
  287.     NameList := NameList^.Next;
  288.     Dispose (Chain);
  289.   END;
  290.   Close (MemList); CheckIO;
  291. END;
  292.  
  293. PROCEDURE DropFromList (VAR NameList: ListLink; fName: STRING; VAR TotalMems: WORD);
  294. VAR
  295.   TempName    : STRING;
  296.   Anchor,
  297.   TempNode,
  298.   Chain : ListLink;
  299.   InFile     : TEXT;
  300.  
  301. BEGIN
  302.   Anchor := NameList;
  303.  
  304.   IF IsFile (fName) THEN BEGIN
  305.     Assign (InFile, fName);
  306.     Reset (InFile); CheckIO;
  307.     WriteLn ('Reading names to drop from: ', fName);
  308.  
  309.     WHILE NOT SeekEof (InFile) DO
  310.     BEGIN
  311.       ReadLn (InFile, TempName); CheckIO;   { fill in new data }
  312.       TempName := FindName (TempName);       { extract email address from line }
  313.  
  314.       IF (Length (TempName) > 1) AND (TempName[1] <> '@') THEN
  315.       BEGIN
  316.         TempName := Upper (TempName);
  317.  
  318.         NameList := Anchor;
  319.         IF (NameList <> NIL) THEN
  320.         BEGIN
  321.           Chain := NameList;
  322.           { Take temp name, and go through entire list, deleting dups }
  323.  
  324.           WHILE (Chain <> NIL) AND (Upper (Chain^.Name) = TempName) DO
  325.           BEGIN
  326.             TempNode := Chain;
  327.  
  328.             Chain := Chain^.Next;  { advance EVERYTHING! }
  329.             NameList := Chain;
  330.             Anchor := Chain;
  331.  
  332.             Dispose (TempNode);
  333.             Dec (TotalMems, 1);
  334.           END;
  335.  
  336.           WHILE (Chain <> NIL) AND (Chain^.Next <> NIL) DO
  337.           BEGIN
  338.             IF Upper (Chain^.Next^.Name) = TempName THEN
  339.             BEGIN
  340.               WriteLn ('Dropped "', Chain^.Next^.Name, '" from list.');
  341.               TempNode := Chain^.Next;
  342.               Chain^.Next := Chain^.Next^.Next;
  343.               Dispose (TempNode);
  344.               Dec (TotalMems, 1);
  345.             END
  346.             ELSE
  347.               Chain := Chain^.Next;
  348.           END;
  349.  
  350.         END;
  351.       END;
  352.     END;
  353.  
  354.     WriteLn ('Finished dropping names.');
  355.     Close (InFile); CheckIO;
  356.   END;
  357.  
  358.   NameList := Anchor;
  359. END;
  360.