home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / r / rusn-09.zip / RUSNEWS.PAS < prev    next >
Pascal/Delphi Source File  |  1992-11-03  |  58KB  |  2,279 lines

  1. program rusnews;  {read news}
  2.  
  3. {
  4.  
  5. KNOWN SHORTCOMINGS (but don't let them scare you away)
  6.  
  7. does not 'f'ollow up to postings or post new ones
  8. works with only Waffle 1.64 password file format (for fullname)
  9.   (but can use environment variables or command-line paramaters
  10.     as quick fix for newer versions) (but this is a dumb idea)
  11. not tested with Waffle 1.65 directory structure (possibly only seqf changes)
  12. does not handle multiple DEFAULT lines the way waffle does
  13. assumes all mail goes out to smarthost
  14.   (cannot mail to local users (without it leaving the site first!))
  15.   (does not use paths file information)
  16. cannot 'G'oto an already-read group - must edit join file by hand
  17. at most 600 articles/group selectable (but you can usually go back for more)
  18.   online version: 200 articles/group
  19. at most 200 groups in join file (for crossposting detection)
  20. very limited kill files
  21.   no regular expressions/substring searches in kill files
  22.   kill files restricted to Subject: and From: only
  23.   at most 200 killed items/group
  24.     online version: 50 killed items/group
  25. doesn't create directories as needed - must already exist
  26. threading doesn't use References: data as much as it could
  27. doesn't log outgoing mail in ~waffle/admin/mail
  28. doesn't guess when daylight savings hits
  29.   (you have to change the clock on your pc anyway!)
  30.  
  31. KNOWN WEIRDNESS
  32.  
  33. 'W'rite not implemented in selection screen
  34. 'r'eply makes you be careful with sig (but it works)
  35. needs headers while browsing (3 more, last, 70% through this article, etc.)
  36. 'P'revious group needs work (same as 'G'oto)
  37. 'U'njoin not there
  38. tabs not expanded (but no one should be using tabs - it's interesting)
  39. lines greater than 80 chars not wrapped (again, no one should use them)
  40.   (author uses `e' to pop into auto-wrapping editor when an interesting one
  41.    is shown)
  42.   (but they are indicated by < on right-hand margin)
  43.  
  44. ENVIRONMENT VARIABLES
  45.  
  46. (required) WAFFLE - same as waffle requires it
  47. NET_NAME - users' waffle name
  48.   also -u/--user
  49. EDITOR - full path+extension of editor (default: c:\usr\bin\vi.exe)
  50.   also -e/--editor - see also -o/--options
  51. TZ - time zone; default: `MST' (if not found in static file)
  52. FULLNAME - full non-computer name of user
  53.   also -f/--fullname (underscores changed to spaces)
  54. WAFVERSION - version of waffle; default: `1.64'
  55.  
  56. CREDITS
  57.  
  58. Kim Storm, for the `nn' newsreader (a much more powerful newsreader
  59.   for Unix, whose keystrokes were used as a model (not Unix, nn))
  60.  
  61. }
  62.  
  63. {$define nontiny}
  64.  
  65. {use tiny for a default-to-fossil-port-0 version, with smaller limits}
  66. {this is usually called rusnews0.exe.  use with any __small__}
  67. {fossil-compatible editor, such as trived.exe from same author}
  68.  
  69. {trived is a trivial editor implementing a small subset of vi on the}
  70. {console _or_ out a fossil - no ANSI.SYS required on console 50k required}
  71.  
  72. {$ifdef tiny}
  73. {$M 32768,0,80000}
  74. {$else}
  75. {$M 32768,0,200000}
  76. {$endif}
  77.  
  78. {$define verbose}
  79. {$undef debug}
  80.  
  81. uses dos,crt;
  82.  
  83. const
  84.  
  85.   newsreadername='rusnews';
  86.   newsreaderversion='v0.9';
  87.  
  88. {$ifdef tiny}
  89.   maxarts=200;
  90.   maxkills=50;
  91.   lpp=22;
  92.   sellpp=19;
  93. {$else}
  94.   maxarts=600;
  95.   maxkills=200;
  96.   lpp=23;
  97.   sellpp=20;
  98. {$endif}
  99.  
  100.   headerlines=1;
  101.   headerbufsize=2048;
  102.   maxjoined=200;
  103.  
  104. type
  105.   subjstringt=string[70];
  106.   fnstringt=string[14];
  107.   datestringt=string[8];
  108.   fromstringt=string[20];
  109.   groupstringt=string[40];
  110.   fnarray=array[1..maxarts] of fnstringt;
  111.   fromarray=array[1..maxarts] of fromstringt;
  112.   datearray=array[1..maxarts] of datestringt;
  113.   headerbuft=array[1..headerbufsize] of char;
  114.   killsarr=array[1..maxkills] of string;
  115.  
  116. var
  117.   basedir: string;
  118.   basedirsuf: string;
  119.   username: string;
  120.   numarts: integer;
  121.   numjoined: integer;
  122.   indents: array[1..maxarts] of integer;
  123.   sizeink: array[1..maxarts] of integer;
  124.   basesubjs: array[1..maxarts] of subjstringt;
  125.   joinedgroups: array[1..maxjoined] of groupstringt;
  126.   filenamesp: ^fnarray;
  127.   fromsp: ^fromarray;
  128.   datesp: ^datearray;
  129.   i: integer;
  130.   selected: array[1..maxarts] of boolean;
  131.   highestart: integer;
  132.   highestread: integer;
  133.   wafenv: string;
  134.   spooldir,temporarydir,userdir,waffledir: string;
  135.   uucpname,node,smarthost,organ,timezone: string;
  136.   home: string;
  137.   join,kill: string;
  138.   joinf,killf: text;
  139.   alreadyread: integer;
  140.   currgroup: string;
  141.   headerinmem: string;
  142.   headerbuf: headerbuft;
  143.   headerbytesinmem: integer;
  144.   currart: integer;
  145.   donegroup: boolean;
  146.   browsedir: integer;
  147.   mainnewsdir: string;
  148.   mainnewsdirsuf: string;
  149.   alreadyingroup: boolean;
  150.   nextwhilereading: boolean;
  151.   editor: string;
  152.   edoptions: string;
  153.   killsubjsp,killfromsp: ^killsarr;
  154.   killtextp: ^killsarr;
  155.   haskillfile: boolean;
  156.   killfileinmem: boolean;
  157.   numkills: integer;
  158.   numkillss,numkillfs: integer;
  159.   fullname: string;
  160.   wafversion: string;
  161.   console: boolean;
  162.   port: integer;
  163.   trusted: boolean;
  164.   forumset: string;
  165.  
  166. {$I rusn-io.pas}
  167.  
  168. procedure usage;
  169.  
  170. begin
  171.   xwritelnsss('usage: ',newsreadername,' [options]');
  172.   xwritelns('  -u --user username');
  173.   xwritelns('  -n --newsgroup newsgroup (jumps directly to that newsgroup)');
  174.   xwritelns('  -p --port port (uses that fossil port)');
  175.   xwritelns('  -f --fullname Full_Name (underscores will become spaces)');
  176.   xwritelns('  -e --editor d:/path/editor.exe (uses this editor)');
  177.   xwritelns('  -o --options !_w:\user\%A (editor non-filename options)');
  178.   xwritelns('  -s --forumset usenet (uses this forum set)');
  179.   xwritelns('  -t --trusted (allows dialin users to edit articles)');
  180.   halt(1);
  181. end;
  182.  
  183. {$I rusn-fun.pas}
  184.  
  185. procedure getfullname;
  186.  
  187. const
  188.   passwordblocksize=256;
  189.  
  190. type
  191.   passwordpasswordbuft=array[1..passwordblocksize] of char;
  192.  
  193. var
  194.   passwordbuf: passwordpasswordbuft;
  195.   passwordf: file;
  196.  
  197. function passwordentry(fieldnum: integer): string;
  198.  
  199. var
  200.   i: integer;
  201.   lfs: integer;
  202.   result: string;
  203.  
  204. begin
  205.   result := '';
  206.   lfs := 0;
  207.   for i := 1 to passwordblocksize do
  208.     begin
  209.       if passwordbuf[i]=#10 then
  210.         inc(lfs);
  211.       if (lfs=fieldnum) and (passwordbuf[i]<>#10) then
  212.         result := result+passwordbuf[i];
  213.     end;
  214.   passwordentry := result;
  215. end;
  216.  
  217. begin
  218.   fullname := '';
  219.   assign(passwordf,waffledir+'\admin\'+'password');
  220.   reset(passwordf,1);
  221.   blockread(passwordf,passwordbuf,passwordblocksize);
  222.   while (fullname='') and not eof(passwordf) do
  223.     begin
  224.       blockread(passwordf,passwordbuf,passwordblocksize);
  225.       if passwordentry(0)=username then
  226.         fullname := passwordentry(5);
  227.     end;
  228.   close(passwordf);
  229. end;
  230.  
  231. procedure updatejoin;
  232.  
  233. var
  234.   s: string;
  235.   tempf: text;
  236.  
  237. begin
  238.   if alreadyread<highestread then
  239.     begin
  240.       xwritelns('Updating join file...');
  241.       assign(tempf,temporarydir+'\'+username);
  242.       reset(joinf);
  243.       rewrite(tempf);
  244.       while not eof(joinf) do
  245.         begin
  246.           readln(joinf,s);
  247.           if getgroup(s)=currgroup then
  248.             writeln(tempf,currgroup,' ',highestread)
  249.           else
  250.             writeln(tempf,s);
  251.         end;
  252.       close(joinf);
  253.       close(tempf);
  254.  
  255.       reset(tempf);
  256.       rewrite(joinf);
  257.       while not eof(tempf) do
  258.         begin
  259.           readln(tempf,s);
  260.           writeln(joinf,s);
  261.         end;
  262.       close(tempf);
  263.       close(joinf);
  264.  
  265.       erase(tempf);
  266.  
  267.       reset(joinf);
  268.     end;
  269. end;
  270.  
  271. procedure addtokill(header,words: string; isglobal: boolean);
  272.  
  273. var
  274.   s: string;
  275.   tempf: text;
  276.   newkillwritten: boolean;
  277.  
  278. begin
  279.   xwritelns('Updating kill file...');
  280.  
  281. {}{} killfileinmem := false;
  282.  
  283. {}{} {must check if out of bounds!}
  284.  
  285.   if header='Subject' then
  286.     begin
  287.       inc(numkillss);
  288.       killsubjsp^[numkillss] := words;
  289.     end
  290.   else
  291.     begin
  292.       inc(numkillfs);
  293.       killfromsp^[numkillfs] := words;
  294.     end;
  295.   if haskillfile then
  296.     begin
  297.       newkillwritten := false;
  298.       assign(tempf,temporarydir+'\'+username);
  299.       reset(killf);
  300.       rewrite(tempf);
  301.       if isglobal then
  302.         begin
  303.           writeln(tempf,header,': ',words);
  304.           newkillwritten := true;
  305.         end;
  306.       while not eof(killf) do
  307.         begin
  308.           readln(killf,s);
  309.           if (parseheadername(s)='Newsgroups') and
  310.            (parseheadervalue(s)=currgroup) then
  311.             begin
  312.               writeln(tempf,s);
  313.               writeln(tempf,header,': ',words);
  314.               newkillwritten := true;
  315.             end
  316.           else
  317.             writeln(tempf,s);
  318.         end;
  319.       if not newkillwritten then {that group had no kill information}
  320.         begin
  321.           writeln(tempf,'Newsgroups:',' ',currgroup);
  322.           writeln(tempf,header,': ',words);
  323.           newkillwritten := true;
  324.         end;
  325.       close(killf);
  326.       close(tempf);
  327.       reset(tempf);
  328.       rewrite(killf);
  329.       while not eof(tempf) do
  330.         begin
  331.           readln(tempf,s);
  332.           writeln(killf,s);
  333.         end;
  334.       close(tempf);
  335.       close(killf);
  336.  
  337.       erase(tempf);
  338.     end
  339.   else
  340.     begin
  341.       haskillfile := true;
  342.       assign(killf,kill);
  343.       rewrite(killf);
  344.       if not isglobal then
  345.         writeln(killf,'Newsgroups: ',currgroup);
  346.       writeln(killf,header,': ',words);
  347.     end;
  348.  
  349.   reset(killf);
  350. end;
  351.  
  352. procedure backupjoin;
  353.  
  354. var
  355.   s: string;
  356.   tempf: text;
  357.   createjoined: boolean;
  358.  
  359. begin
  360.   xwritelns('Backing up join file...');
  361.   createjoined := (numjoined=0);
  362.   assign(tempf,home+'\join.bak');
  363.   reset(joinf);
  364.   rewrite(tempf);
  365.   while not eof(joinf) do
  366.     begin
  367.       readln(joinf,s);
  368.       writeln(tempf,s);
  369.       if createjoined and (numjoined<maxjoined) then
  370.         begin
  371.           inc(numjoined);
  372.           joinedgroups[numjoined] := getgroup(s);
  373.         end;
  374.     end;
  375.   close(tempf);
  376.   reset(joinf);
  377. end;
  378.  
  379. procedure backupkill;
  380.  
  381. var
  382.   s: string;
  383.   tempf: text;
  384.  
  385. begin
  386.   killfileinmem := true;
  387.   numkills := 0;
  388.   if haskillfile then
  389.     begin
  390.       xwritelns('Backing up kill file...');
  391.       assign(tempf,home+'\kill.bak');
  392.       reset(killf);
  393.       rewrite(tempf);
  394.       while not eof(killf) do
  395.         begin
  396.           readln(killf,s);
  397.           writeln(tempf,s);
  398.           if numkills<maxkills then
  399.             begin
  400.               inc(numkills);
  401.               killtextp^[numkills] := s;
  402.             end
  403.           else
  404.             killfileinmem := false;
  405.         end;
  406.       close(tempf);
  407.       reset(killf);
  408.     end;
  409. end;
  410.  
  411. procedure swapart(a,b: integer);
  412.  
  413. var
  414.   tempsubj: string;
  415.   tempfilename: fnstringt;
  416.   tempdate: datestringt;
  417.   tempindents: integer;
  418.   tempsizeink: integer;
  419.   tempfrom: fromstringt;
  420.  
  421. begin
  422.   tempsubj := basesubjs[a];
  423.   tempfilename := filenamesp^[a];
  424.   tempdate := datesp^[a];
  425.   tempindents := indents[a];
  426.   tempsizeink := sizeink[a];
  427.   tempfrom := fromsp^[a];
  428.   basesubjs[a] := basesubjs[b];
  429.   filenamesp^[a] := filenamesp^[b];
  430.   datesp^[a] := datesp^[b];
  431.   indents[a] := indents[b];
  432.   sizeink[a] := sizeink[b];
  433.   fromsp^[a] := fromsp^[b];
  434.   basesubjs[b] := tempsubj;
  435.   filenamesp^[b] := tempfilename;
  436.   datesp^[b] := tempdate;
  437.   indents[b] := tempindents;
  438.   sizeink[b] := tempsizeink;
  439.   fromsp^[b] := tempfrom;
  440. end;
  441.  
  442. procedure sortitall;
  443.  
  444. var
  445.   i,j: integer;
  446.   dateptrs,subjptrs,finalptrs,revfinalptrs: array[1..maxarts] of integer;
  447.   tempint: integer;
  448.   dateptrsdone: integer;
  449.   finalptrsdone: integer;
  450.   finalstart: integer;
  451.   currsubjptr: integer;
  452.   currsubj: string;
  453.  
  454. begin
  455.   for i := 1 to numarts do
  456.     dateptrs[i] := i;
  457.   for i := 1 to numarts-1 do
  458.     for j := i+1 to numarts do
  459.       if (datesp^[dateptrs[i]]>datesp^[dateptrs[j]]) or
  460.        ((datesp^[dateptrs[i]]=datesp^[dateptrs[j]]) and
  461.        (basesubjs[dateptrs[i]]>basesubjs[dateptrs[j]])) then
  462. {that dates equal but subjects not test is for comp.sources.* etc. v29i033}
  463. {hopefully will help part 1/6 posts too (eg alt.sources)}
  464.         begin
  465.           tempint := dateptrs[i];
  466.           dateptrs[i] := dateptrs[j];
  467.           dateptrs[j] := tempint;
  468.         end;
  469.   for i := 1 to numarts do
  470.     subjptrs[i] := i;
  471.   for i := 1 to numarts-1 do
  472.     for j := i+1 to numarts do
  473.       if basesubjs[subjptrs[i]]>basesubjs[subjptrs[j]] then
  474.         begin
  475.           tempint := subjptrs[i];
  476.           subjptrs[i] := subjptrs[j];
  477.           subjptrs[j] := tempint;
  478.         end;
  479.  
  480.   dateptrsdone := 0;
  481.   finalptrsdone := 0;
  482.   while finalptrsdone<numarts do
  483.     begin
  484.       inc(dateptrsdone);
  485.  
  486.       if dateptrs[dateptrsdone]>0 then
  487.         begin
  488.           currsubj := basesubjs[dateptrs[dateptrsdone]];
  489.  
  490.           currsubjptr := 1;
  491.           while currsubj>basesubjs[subjptrs[currsubjptr]] do
  492.             inc(currsubjptr);
  493.  
  494.           finalstart := finalptrsdone+1;
  495.           while currsubj=basesubjs[subjptrs[currsubjptr]] do
  496.             begin
  497.               inc(finalptrsdone);
  498.               finalptrs[finalptrsdone] := subjptrs[currsubjptr];
  499.               inc(currsubjptr);
  500.             end;
  501.  
  502.           for i := finalstart to finalptrsdone-1 do
  503.             for j := i+1 to finalptrsdone do
  504.               if not firstartfirst(finalptrs[i],finalptrs[j]) then
  505.                 begin
  506.                   tempint := finalptrs[i];
  507.                   finalptrs[i] := finalptrs[j];
  508.                   finalptrs[j] := tempint;
  509.                 end;
  510.  
  511.           for i := 1 to numarts do
  512.             if basesubjs[dateptrs[i]]=currsubj then
  513.               dateptrs[i] := -dateptrs[i];
  514.  
  515.         end;
  516.     end;
  517.  
  518.   for i := 1 to numarts do
  519.     revfinalptrs[finalptrs[i]] := i;
  520.  
  521.   for i := 1 to numarts-1 do
  522.     if finalptrs[i]<>i then
  523.       begin
  524.         swapart(i,finalptrs[i]);
  525.         finalptrs[revfinalptrs[i]] := finalptrs[i];
  526.         revfinalptrs[finalptrs[i]] := revfinalptrs[i];
  527.         finalptrs[i] := i;
  528.         revfinalptrs[i] := i;
  529.       end;
  530.  
  531. end;
  532.  
  533. procedure browseart(artnum: integer);
  534.  
  535. var
  536.   s: string;
  537.   artfn: string;
  538.   artf: text;
  539.   newlinesshown: integer;
  540.   lineon: integer;
  541.   newart: boolean;
  542.   artsubject: string;
  543.   artfrom: string;
  544.   numheaderlines: integer;
  545.  
  546. procedure newbrowsescreen;
  547.  
  548. begin
  549.   xclrscr;
  550. end;
  551.  
  552. procedure rereadfromline(i: integer);
  553.  
  554. var
  555.   gottoline: integer;
  556.  
  557. begin
  558.   newbrowsescreen;
  559.   reset(artf);
  560.   gottoline := 0;
  561.   lineon := i;
  562.   while gottoline<=lineon-lpp do
  563.     begin
  564.       readln(artf,s);
  565.       inc(gottoline);
  566.     end;
  567.   newlinesshown := 0;
  568.   while gottoline<=lineon do
  569.     begin
  570.       readln(artf,s);
  571.       xwritelns(screenline(s));
  572.       inc(newlinesshown);
  573.       inc(gottoline);
  574.     end;
  575. end;
  576.  
  577. procedure browsehelppage;
  578.  
  579. var
  580.   ch: char;
  581.  
  582. begin
  583.   xclrscr;
  584.   writexy(1,1,newsreadername+' '+newsreaderversion+
  585.    ' - newsreader-under-development');
  586.   writexy(1,2,'russell@alpha3.ersys.edmonton.ab.ca (921103)');
  587.   writexy(1,4,'space,d,CR - forward 1 page, 1/2 page, 1 line');
  588.   writexy(1,5,'u - back 1 page');
  589.   writexy(1,6,'^ - top line');
  590.   writexy(1,7,'n,p - next, previous article');
  591.   writexy(1,8,'r - reply to author (in mail)');
  592.   writexy(1,9,'f - followup (in netnews) (not yet)');
  593.   writexy(1,10,'k - kill by subject or author (will not display again)');
  594.   writexy(1,11,'e - edit article on disk');
  595.   writexy(1,12,'w - write article to a file');
  596.   writexy(1,20,'? - help');
  597.   writexy(1,22,'press any key to return');
  598.   ch := xreadkey;
  599.   newbrowsescreen;
  600.   rereadfromline(0);
  601. end;
  602.  
  603. procedure morelines(lines: integer);
  604.  
  605. begin
  606.   if eof(artf) then
  607.     newart := true
  608.   else
  609.     begin
  610.       dec(newlinesshown,lines);
  611.       while not eof(artf) and (newlinesshown<lpp) do
  612.         begin
  613.           readln(artf,s);
  614.           xwritelns(screenline(s));
  615.           inc(newlinesshown);
  616.           inc(lineon);
  617.         end;
  618.     end;
  619. end;
  620.  
  621. procedure writeart;
  622.  
  623. var
  624.   outfilen: string;
  625.   outfile: text;
  626.  
  627. begin
  628.   xclreolxy(1,lpp);
  629.   xwrites('file name: ');
  630.   xreadlns(outfilen);
  631.   assign(outfile,unslash(outfilen));
  632.   {$I-}
  633.   append(outfile);
  634.   {$I-}
  635.   if ioresult<>0 then
  636.     begin
  637.       {$I-}
  638.       rewrite(outfile);
  639.       {$I+}
  640.     end;
  641.   if ioresult=0 then
  642.     begin
  643.       reset(artf);
  644.       while not eof(artf) do
  645.         begin
  646.           readln(artf,s);
  647.           writeln(outfile,s);
  648.         end;
  649.       close(outfile);
  650.     end;
  651.   rereadfromline(0);
  652. end;
  653.  
  654. procedure mailart;
  655.  
  656. begin
  657. end;
  658.  
  659. procedure editart;
  660.  
  661. var
  662.   doserr: integer;
  663.  
  664. begin
  665.   if trusted then
  666.     begin
  667.       close(artf);
  668.       exec(editor,edoptions+' '+artfn);
  669.       doserr := doserror;
  670.       if doserr<>0 then
  671.         begin
  672.           xwritesis('edit failed - error number ',doserr,
  673.            ' - press any key ');
  674.           inc(doserr,0*ord(xreadkey));
  675.         end;
  676.       rereadfromline(0);
  677.     end;
  678. end;
  679.  
  680. procedure followtoart;
  681.  
  682. var
  683.   subject: string;
  684.   messageid: string;
  685.   replyaddr: string;
  686.   newreplyaddr: string;
  687.   replyname: string;
  688.   ccaddr: string;
  689.   mailfn: string;
  690.   mailf: text;
  691.   maillffn: string;
  692.   maillff: text;
  693.   sigfn: string;
  694.   sigf: text;
  695.   foundblank: boolean;
  696.   s: string;
  697.   sendeditquit: char;
  698.   seqstr: string;
  699.   outmailfn: string;
  700.   outmailf: text;
  701.   outmailnum: integer;
  702.   gotafile: boolean;
  703.   basesite: string;
  704.   lineno: integer;
  705.   doserr: integer;
  706.  
  707. begin
  708. {$ifdef followiswritten}
  709.   close(artf);
  710.   subject := getheaderline(artfn,'subject:');
  711.   if copy(subject,1,4)<>'Re: ' then
  712.     subject := 'Re: '+subject;
  713.   messageid := getheaderline(artfn,'message-id:');
  714.   replyaddr := getheaderline(artfn,'reply-to:');
  715.   if replyaddr='' then
  716.     replyaddr := getheaderline(artfn,'from:');
  717.   if replyaddr='' then
  718.     begin
  719.     end
  720.   else
  721.     begin
  722.       xclreolxy(1,lpp);
  723.       xwrites('Reply-To: ');
  724.       xreadlns(newreplyaddr);
  725.       if newreplyaddr='' then
  726.         begin
  727.           replyname := getfromname(replyaddr);
  728.           replyaddr := getfromaddr(replyaddr);
  729.         end
  730.       else
  731.         begin
  732.           replyaddr := newreplyaddr;
  733.           replyname := '';
  734.         end;
  735.       xclreolxy(1,lpp);
  736. {
  737.       xwrites('CC: ');
  738.       xreadlns(ccaddr);
  739.       xclreolxy(1,lpp);
  740. }
  741.       mailfn := temporarydir+'\'+username+'.mai';
  742.       assign(mailf,mailfn);
  743.       rewrite(mailf);
  744.       writeln(mailf,'From ',username,'  ',copy(cdow,1,3),', ',dayofmonth,' ',
  745.        copy(monthname,1,3),' ',year mod 100,' ',time,' ',timezone,' ',
  746.        'remote from ',uucpname);
  747.       writeln(mailf,'Received: by ',node,' ('+newsreadername+')');
  748.       writeln(mailf,'       via UUCP; ',copy(cdow,1,3),', ',dayofmonth,' ',
  749.        copy(monthname,1,3),' ',year mod 100,' ',time,' ',timezone);
  750.       writeln(mailf,'       for ',replyaddr);
  751.       write(mailf,'To: ',replyaddr);
  752.       if replyname='' then
  753.         writeln(mailf)
  754.       else
  755.         writeln(mailf,' (',replyname,')');
  756.       writeln(mailf,'Subject: ',subject);
  757.       writeln(mailf,'From: ',username,'@',node,' (',fullname,')');
  758.       writeln(mailf,'Message-ID: ',newmessageid);
  759.       writeln(mailf,'Date: ',copy(cdow,1,3),', ',dayofmonth,' ',
  760.        copy(monthname,1,3),' ',year mod 100,' ',time,' ',timezone);
  761.       writeln(mailf,'In-Reply-To: ',messageid);
  762.       writeln(mailf,'Organization: ',organ);
  763.       writeln(mailf,'X-Newsreader: ',newsreadername,' ',newsreaderversion);
  764.       writeln(mailf);
  765.       writeln(mailf,'In ',currgroup,' you write:');
  766.       writeln(mailf);
  767.       reset(artf);
  768.       foundblank := false;
  769.       while not eof(artf) and not foundblank do
  770.         begin
  771.           readln(artf,s);
  772.           if s='' then
  773.             foundblank := true;
  774.         end;
  775.       while not eof(artf) do
  776.         begin
  777.           readln(artf,s);
  778.           writeln(mailf,'> ',s);
  779.         end;
  780.       close(artf);
  781.       sigfn := home+'\mailsig';
  782.       assign(sigf,sigfn);
  783.       {$I-}
  784.       reset(sigf);
  785.       {$I+}
  786.       if ioresult=0 then
  787.         begin
  788.           readln(sigf,s);
  789.           if s<>'-- ' then
  790.             write(mailf,'-- ');
  791.           reset(sigf);
  792.           while not eof(sigf) do
  793.             begin
  794.               readln(sigf,s);
  795.               writeln(mailf,s);
  796.             end;
  797.           close(sigf);
  798.         end;
  799.       close(mailf);
  800.  
  801.       repeat
  802.         exec(editor,edoptions+' '+mailfn);
  803.         doserr := doserror;
  804.         if doserr<>0 then
  805.           begin
  806.             xwritesis('edit failed - error number ',doserr,
  807.              ' - press any key ');
  808.             inc(doserr,0*ord(xreadkey));
  809.           end;
  810.  
  811.         repeat
  812.           xclreolxy(1,lpp);
  813.           xwrites('<s>end <e>dit <q>uit ');
  814.           sendeditquit := xreadkey;
  815.         until (sendeditquit='s') or (sendeditquit='e') or (sendeditquit='q');
  816.       until (sendeditquit='s') or (sendeditquit='q');
  817.       if sendeditquit='q' then
  818.         xwritelns('quit');
  819.       if sendeditquit='s' then
  820.         begin
  821.           xwritelns('send');
  822.           seqstr := integertozstring(newseqnumber,4);
  823.           { here copy mailf to maillff - strip carriage returns }
  824.           maillffn := spooldir+'\'+smarthost+'\'+seqstr+'.xqt';
  825.           assign(maillff,maillffn);
  826.           rewrite(maillff);
  827.           write(maillff,'U ',username,' ',uucpname,#10);
  828.           write(maillff,'Z',#10);
  829.           write(maillff,'F D.',uucpname,seqstr,#10);
  830.           write(maillff,'I D.',uucpname,seqstr,#10);
  831.           write(maillff,'C rmail ',replyaddr,#10);
  832.           close(maillff);
  833.  
  834.           maillffn := spooldir+'\'+smarthost+'\'+seqstr+'.dat';
  835.           assign(maillff,maillffn);
  836.           rewrite(maillff);
  837.           assign(mailf,mailfn);
  838.           reset(mailf);
  839.           while not eof(mailf) do
  840.             begin
  841.               readln(mailf,s);
  842.               write(maillff,s,#10);
  843.             end;
  844.           close(mailf);
  845.           close(maillff);
  846.  
  847.           mailfn := spooldir+'\'+smarthost+'\'+seqstr+'.cmd';
  848.           assign(mailf,mailfn);
  849.           rewrite(mailf);
  850.           writeln(mailf,'S ',seqstr,'.DAT D.',uucpname,seqstr,' ',
  851.            username,' - ',seqstr,'.DAT 0666');
  852.           writeln(mailf,'S ',seqstr,'.XQT X.',uucpname,seqstr,' ',
  853.            username,' - ',seqstr,'.XQT 0666');
  854.           close(mailf);
  855.  
  856.           basesite := copy(basesitename(replyaddr),1,8);
  857.           outmailfn := spooldir+'\outbox\'+basesite;
  858.           gotafile := false;
  859.           outmailnum := 1;
  860.           while not gotafile do
  861.             begin
  862.               assign(outmailf,outmailfn+'.'+itoa(outmailnum));
  863.               {$I-}
  864.               reset(outmailf);
  865.               {$I+}
  866.               if ioresult<>0 then
  867.                 gotafile := true
  868.               else
  869.                 begin
  870.                   inc(outmailnum);
  871.                   close(outmailf);
  872.                 end;
  873.             end;
  874.           outmailfn := outmailfn+'.'+itoa(outmailnum);
  875.           assign(outmailf,outmailfn);
  876.           rewrite(outmailf);
  877.           mailfn := temporarydir+'\'+username+'.mai';
  878.           assign(mailf,mailfn);
  879.           reset(mailf);
  880.           lineno := 1;
  881.           while not eof(mailf) do
  882.             begin
  883.               readln(mailf,s);
  884.               if lineno=1 then
  885.                 writeln(outmailf,copy(s,1,length(s)-
  886.                  length(' remote from '+uucpname)))
  887.               else if lineno>4 then
  888.                 writeln(outmailf,s);
  889.               inc(lineno);
  890.             end;
  891.           close(mailf);
  892.           close(outmailf);
  893.         end;
  894.     end;
  895.   reset(artf);
  896. {$endif}
  897.   rereadfromline(0);
  898. end;
  899.  
  900. procedure killart;
  901.  
  902. var
  903.   subjectfromoops: char;
  904.   i: integer;
  905.  
  906. begin
  907.   repeat
  908.     xclreolxy(1,lpp);
  909.     xwrites('this group: <s>ubject <f>rom; always <S>ubject <F>rom; <o>ops');
  910.     subjectfromoops := xreadkey;
  911.   until
  912.    (subjectfromoops='s') or
  913.    (subjectfromoops='f') or
  914.    (subjectfromoops='S') or
  915.    (subjectfromoops='F') or
  916.    (subjectfromoops='o');
  917.   xclreolxy(1,lpp);
  918.   if subjectfromoops<>'o' then
  919.     begin
  920.       if (subjectfromoops='s') or (subjectfromoops='S') then
  921.         begin
  922.           addtokill('Subject',basesubjs[artnum],(subjectfromoops='S'));
  923. {}{} {too much checking here}
  924.           for i := 1 to numarts do
  925.             if subjkilled(basesubjs[i]) then
  926.               selected[i] := false;
  927.         end
  928.       else
  929.         begin
  930.           addtokill('From',
  931.            getfromaddr(fromsp^[artnum]),(subjectfromoops='F'));
  932. {}{} {too much checking here}
  933.           for i := 1 to numarts do
  934.             if fromkilled(fromsp^[i]) then
  935.               selected[i] := false;
  936.         end;
  937.       newart := true;
  938.     end;
  939. end;
  940.  
  941. procedure replytoart;
  942.  
  943. var
  944.   thisfrom: string;
  945.   subject: string;
  946.   messageid: string;
  947.   replyaddr: string;
  948.   newreplyaddr: string;
  949.   replyname: string;
  950.   defaultreply: boolean;
  951.   ccaddr: string;
  952.   mailfn: string;
  953.   mailf: text;
  954.   maillffn: string;
  955.   maillff: text;
  956.   rereadblankfound: boolean;
  957.   sigfn: string;
  958.   sigf: text;
  959.   foundblank: boolean;
  960.   s: string;
  961.   sendeditquit: char;
  962.   seqstr: string;
  963.   outmailfn: string;
  964.   outmailf: text;
  965.   outmailnum: integer;
  966.   gotafile: boolean;
  967.   basesite: string;
  968.   lineno: integer;
  969.   doserr: integer;
  970.  
  971. begin
  972.   thisfrom := username+'@'+node;
  973.  
  974.   close(artf);
  975.   subject := getheaderline(artfn,'subject:');
  976.   if copy(subject,1,4)<>'Re: ' then
  977.     subject := 'Re: '+subject;
  978.   messageid := getheaderline(artfn,'message-id:');
  979.  
  980.   replyaddr := getheaderline(artfn,'reply-to:');
  981.   if replyaddr='' then
  982.     replyaddr := getheaderline(artfn,'from:');
  983.   if replyaddr='' then
  984.     replyaddr := thisfrom;
  985.  
  986.   thisfrom := thisfrom+' ('+fullname+')';
  987.  
  988.   xclreolxy(1,lpp);
  989.   xwrites('Reply-To: ');
  990.   xreadlns(newreplyaddr);
  991.   defaultreply := (newreplyaddr='');
  992.   if defaultreply then
  993.     begin
  994.       replyname := getfromname(replyaddr);
  995.       replyaddr := getfromaddr(replyaddr);
  996.     end
  997.   else
  998.     begin
  999.       replyaddr := newreplyaddr;
  1000.       replyname := '';
  1001.     end;
  1002.  
  1003. {handle one-line user/x/forward files}
  1004.  
  1005.   mailfn := userdir+'\'+replyaddr+'\forward';
  1006.   assign(mailf,mailfn);
  1007.   {$I-}
  1008.   reset(mailf);
  1009.   {$I+}
  1010.   if ioresult=0 then
  1011.     begin
  1012.       readln(mailf,replyaddr);
  1013.       close(mailf);
  1014.     end;
  1015.  
  1016.   xclreolxy(1,lpp);
  1017.  
  1018. {
  1019.   xwrites('CC: ');
  1020.   xreadlns(ccaddr);
  1021.   xclreolxy(1,lpp);
  1022. }
  1023.  
  1024.   mailfn := temporarydir+'\'+username+'.mai';
  1025.   assign(mailf,mailfn);
  1026.   rewrite(mailf);
  1027.   writeln(mailf,'From ',username,'  ',copy(cdow,1,3),', ',dayofmonth,' ',
  1028.    copy(monthname,1,3),' ',year mod 100,' ',time,' ',timezone,' ',
  1029.    'remote from ',uucpname);
  1030.   writeln(mailf,'Received: by ',node,' ('+newsreadername+')');
  1031.   writeln(mailf,'       via UUCP; ',copy(cdow,1,3),', ',dayofmonth,' ',
  1032.    copy(monthname,1,3),' ',year mod 100,' ',time,' ',timezone);
  1033.   writeln(mailf,'       for ',replyaddr);
  1034.   write(mailf,'To: ',replyaddr);
  1035.   if replyname='' then
  1036.     writeln(mailf)
  1037.   else
  1038.     writeln(mailf,' (',replyname,')');
  1039.   writeln(mailf,'Subject: ',subject);
  1040.   writeln(mailf,'From: ',thisfrom);
  1041.   writeln(mailf,'Message-ID: ',newmessageid);
  1042.   writeln(mailf,'Date: ',copy(cdow,1,3),', ',dayofmonth,' ',
  1043.    copy(monthname,1,3),' ',year mod 100,' ',time,' ',timezone);
  1044.   writeln(mailf,'In-Reply-To: ',messageid);
  1045.   writeln(mailf,'Organization: ',organ);
  1046.   writeln(mailf,'X-Newsreader: ',newsreadername,' ',newsreaderversion);
  1047.   writeln(mailf);
  1048.   if defaultreply then
  1049.     writeln(mailf,'In ',currgroup,' you write:')
  1050.   else
  1051.     writeln(mailf,'In ',currgroup,' it is written:');
  1052.   writeln(mailf);
  1053.   reset(artf);
  1054.   foundblank := false;
  1055.   while not eof(artf) and not foundblank do
  1056.     begin
  1057.       readln(artf,s);
  1058.       if s='' then
  1059.         foundblank := true;
  1060.     end;
  1061.   while not eof(artf) do
  1062.     begin
  1063.       readln(artf,s);
  1064.       writeln(mailf,'> ',s);
  1065.     end;
  1066.   close(artf);
  1067.   sigfn := home+'\mailsig';
  1068.   assign(sigf,sigfn);
  1069.   {$I-}
  1070.   reset(sigf);
  1071.   {$I+}
  1072.   if ioresult=0 then
  1073.     begin
  1074.       readln(sigf,s);
  1075.       if s<>'-- ' then
  1076.         write(mailf,'-- ');
  1077.       reset(sigf);
  1078.       while not eof(sigf) do
  1079.         begin
  1080.           readln(sigf,s);
  1081.           writeln(mailf,s);
  1082.         end;
  1083.       close(sigf);
  1084.     end;
  1085.   close(mailf);
  1086.  
  1087.   repeat
  1088.     exec(editor,edoptions+' '+mailfn);
  1089.     doserr := doserror;
  1090.     if doserr<>0 then
  1091.       begin
  1092.         xwritesis('edit failed - error number ',doserr,
  1093.          ' - press any key ');
  1094.         inc(doserr,0*ord(xreadkey));
  1095.       end;
  1096.  
  1097.     repeat
  1098.       xclreolxy(1,lpp);
  1099.       xwrites('<s>end <e>dit <q>uit ');
  1100.       sendeditquit := xreadkey;
  1101.     until (sendeditquit='s') or (sendeditquit='e') or (sendeditquit='q');
  1102.   until (sendeditquit='s') or (sendeditquit='q');
  1103.   if sendeditquit='q' then
  1104.     xwritelns('quit');
  1105.   if sendeditquit='s' then
  1106.     begin
  1107.       xwritelns('send');
  1108.       seqstr := integertozstring(newseqnumber,4);
  1109.       { here copy mailf to maillff - strip carriage returns }
  1110.       maillffn := spooldir+'\'+smarthost+'\'+seqstr+'.xqt';
  1111.       assign(maillff,maillffn);
  1112.       rewrite(maillff);
  1113.       write(maillff,'U ',username,' ',uucpname,#10);
  1114.       write(maillff,'Z',#10);
  1115.       write(maillff,'F D.',uucpname,seqstr,#10);
  1116.       write(maillff,'I D.',uucpname,seqstr,#10);
  1117.       write(maillff,'C rmail ',replyaddr,#10);
  1118.       close(maillff);
  1119.  
  1120.       maillffn := spooldir+'\'+smarthost+'\'+seqstr+'.dat';
  1121.       assign(maillff,maillffn);
  1122.       rewrite(maillff);
  1123.  
  1124.       assign(mailf,mailfn);
  1125.       reset(mailf);
  1126.  
  1127. {check for changed From: lines on non-trusted users and replace}
  1128.  
  1129.       rereadblankfound := false;
  1130.       while not eof(mailf) do
  1131.         begin
  1132.           readln(mailf,s);
  1133.           if not trusted then
  1134.             begin
  1135.               if s='' then
  1136.                 rereadblankfound := true
  1137.               else if not rereadblankfound then
  1138.                 if copy(s,1,6)='From: ' then
  1139.                   if s<>'From: '+thisfrom then
  1140.                     begin
  1141.                       xclreolxy(1,1);
  1142.                       xclreolxy(1,2);
  1143.                       xclreolxy(1,3);
  1144.                       xclreolxy(1,4);
  1145.                       xclreolxy(1,5);
  1146.                       xclreolxy(1,6);
  1147.                       xclreolxy(1,7);
  1148.                       writexy(1,1,'From: line was changed from');
  1149.                       writexy(1,2,s+' to');
  1150.                       writexy(1,3,thisfrom);
  1151.                       writexy(1,4,'and has been changed back.  if you need');
  1152.                       writexy(1,5,'to change From:, run as a trusted user.');
  1153.                       writexy(1,6,'adding a Reply-To: is probably better');
  1154.                       s := 'From: '+thisfrom;
  1155.                     end;
  1156.             end;
  1157.           write(maillff,s,#10);
  1158.         end;
  1159.       close(mailf);
  1160.       close(maillff);
  1161.  
  1162.       mailfn := spooldir+'\'+smarthost+'\'+seqstr+'.cmd';
  1163.       assign(mailf,mailfn);
  1164.       rewrite(mailf);
  1165.       writeln(mailf,'S ',seqstr,'.DAT D.',uucpname,seqstr,' ',
  1166.        username,' - ',seqstr,'.DAT 0666');
  1167.       writeln(mailf,'S ',seqstr,'.XQT X.',uucpname,seqstr,' ',
  1168.        username,' - ',seqstr,'.XQT 0666');
  1169.       close(mailf);
  1170.  
  1171.       basesite := copy(basesitename(replyaddr),1,8);
  1172.       outmailfn := spooldir+'\outbox\'+basesite;
  1173.  
  1174. {$ifdef oldandsillymethod}
  1175.       gotafile := false;
  1176.       outmailnum := 1;
  1177.       while not gotafile do
  1178.         begin
  1179.           assign(outmailf,outmailfn+'.'+itoa(outmailnum));
  1180.           {$I-}
  1181.           reset(outmailf);
  1182.           {$I+}
  1183.           if ioresult<>0 then
  1184.             gotafile := true
  1185.           else
  1186.             begin
  1187.               inc(outmailnum);
  1188.               close(outmailf);
  1189.             end;
  1190.         end;
  1191.       outmailfn := outmailfn+'.'+itoa(outmailnum);
  1192. {$endif}
  1193.  
  1194.       outmailfn := getuniqfile(spooldir+'\outbox\'+basesite);
  1195.  
  1196.       assign(outmailf,outmailfn);
  1197.       rewrite(outmailf);
  1198.  
  1199.       mailfn := temporarydir+'\'+username+'.mai';
  1200.       assign(mailf,mailfn);
  1201.       reset(mailf);
  1202.  
  1203.       rereadblankfound := false;
  1204.       lineno := 1;
  1205.       while not eof(mailf) do
  1206.         begin
  1207.           readln(mailf,s);
  1208.           if lineno=1 then
  1209.             writeln(outmailf,copy(s,1,length(s)-
  1210.              length(' remote from '+uucpname)))
  1211.           else if lineno>4 then
  1212.             begin
  1213.               if not trusted then
  1214.                 begin
  1215.                   if s='' then
  1216.                     rereadblankfound := true
  1217.                   else if not rereadblankfound then
  1218.                     if copy(s,1,6)='From: ' then
  1219.                       if s<>'From: '+thisfrom then
  1220.                         s := 'From: '+thisfrom;
  1221.                 end;
  1222.               writeln(outmailf,s);
  1223.             end;
  1224.           inc(lineno);
  1225.         end;
  1226.       close(mailf);
  1227.       close(outmailf);
  1228.     end;
  1229.  
  1230.   reset(artf);
  1231.   rereadfromline(0);
  1232. end;
  1233.  
  1234. procedure geteopkey;
  1235.  
  1236. var
  1237.   ch: char;
  1238.  
  1239. begin
  1240.   ch := xreadkey;
  1241.   if ch='?' then browsehelppage
  1242.   else if ch='n' then newart := true
  1243.   else if ch='p' then begin newart := true; browsedir := -1; end
  1244.   else if ch='u' then rereadfromline(max(0,lineon-lpp div 2))
  1245.   else if ch='^' then rereadfromline(0)
  1246.   else if ch=#13 then morelines(1)
  1247.   else if ch=' ' then morelines(lpp-2)
  1248.   else if ch='d' then morelines(lpp div 2)
  1249.   else if ch='w' then writeart
  1250.   else if ch='m' then mailart
  1251.   else if ch='r' then replytoart
  1252.   else if ch='f' then followtoart
  1253.   else if ch='k' then killart
  1254.   else if ch='e' then editart;
  1255. end;
  1256.  
  1257. begin
  1258.   newbrowsescreen;
  1259.   newlinesshown := 0;
  1260.   lineon := 0;
  1261.  
  1262.   artfrom := fromsp^[artnum];
  1263.   artsubject := basesubjs[artnum];
  1264.  
  1265.   artfn := basedir+basedirsuf+filenamesp^[artnum];
  1266.   assign(artf,artfn);
  1267.   reset(artf);
  1268.  
  1269.   newart := false;
  1270.   while not newart do
  1271.     begin
  1272.       if eof(artf) then
  1273.         newart := true
  1274.       else
  1275.         begin
  1276.           while (not eof(artf)) and not newart do
  1277.             begin
  1278.               readln(artf,s);
  1279.               xwritelns(screenline(s));
  1280.               inc(newlinesshown);
  1281.               inc(lineon);
  1282.               while (newlinesshown>=lpp) and not newart do
  1283.                 geteopkey;
  1284.             end;
  1285.           if (newlinesshown>0) and not newart then
  1286.             geteopkey;
  1287.         end;
  1288.     end;
  1289.   close(artf);
  1290. end;
  1291.  
  1292. procedure getindents(filename: string; var numindents: integer);
  1293.  
  1294. var
  1295.   references: string;
  1296.   i: integer;
  1297.  
  1298. begin
  1299.   references := getheaderline(filename,'references:');
  1300.   if references<>'' then
  1301.     begin
  1302.       if pos('<',references)>0 then
  1303.         numindents := 0;
  1304.       while pos('<',references)>0 do
  1305.         begin
  1306.           inc(numindents,1);
  1307.           references := copy(references,pos('<',references)+1,255);
  1308.         end;
  1309.     end;
  1310. end;
  1311.  
  1312. procedure readinarts;
  1313.  
  1314. var
  1315.   fileinfo: searchrec;
  1316.   subject: string;
  1317.   from: string;
  1318.   newsgroups: string;
  1319.   filename: string;
  1320.   datestr: string;
  1321.   ch: char;
  1322.   i: integer;
  1323.   workwithit: boolean;
  1324.   readnomore: boolean;
  1325.  
  1326. begin
  1327.   nextwhilereading := false;
  1328.   readnomore := false;
  1329.   highestart := 0;
  1330.   findfirst(basedir+basedirsuf+'*.*',archive,fileinfo);
  1331.   while (doserror=0) and (numarts<maxarts) and not nextwhilereading and
  1332.    not readnomore do
  1333.     begin
  1334.       if xkeypressed then
  1335.         begin
  1336.           ch := xreadkey;
  1337.           if ch='N' then
  1338.             nextwhilereading := true
  1339.           else if ch='O' then
  1340.             readnomore := true
  1341.           else if ch='Q' then
  1342.             begin
  1343.               nextwhilereading := true;
  1344.               alreadyingroup := true;
  1345.               currgroup := '';
  1346.             end;
  1347.         end;
  1348.       if not nextwhilereading and not readnomore and
  1349.        (atoi(fileinfo.name)>alreadyread) then
  1350.         begin
  1351.  
  1352.           filename := basedir+basedirsuf+fileinfo.name;
  1353.           subject := getheaderline(filename,'subject:');
  1354.           from := getheaderline(filename,'from:');
  1355.           newsgroups := getheaderline(filename,'newsgroups:');
  1356.  
  1357.           workwithit := (subject<>'') and
  1358.            not subjkilled(subject) and
  1359.            not fromkilled(from);
  1360.  
  1361.           xwrites(fileinfo.name);
  1362.           if workwithit then
  1363.             begin
  1364.               if alreadyseen(newsgroups) then
  1365.                 begin
  1366.                   workwithit := false;
  1367.                   xwrites('s');
  1368.                 end
  1369.             end
  1370.           else
  1371.             xwrites('k');
  1372.  
  1373.           xwrites(' ');
  1374.  
  1375.           if workwithit then
  1376.             begin
  1377.               inc(numarts);
  1378.               filenamesp^[numarts] := fileinfo.name;
  1379.               basesubjs[numarts] := subject;
  1380.               fromsp^[numarts] := getfromname(from);
  1381.               if fromsp^[numarts]='' then
  1382.                 fromsp^[numarts] := getfromaddr(from);
  1383.               sizeink[numarts] :=
  1384.                longint(fileinfo.size+1023) div longint(1024);
  1385.               indents[numarts] := 0;
  1386.               while copy(basesubjs[numarts],1,4)='Re: ' do
  1387.                 begin
  1388.                   inc(indents[numarts]);
  1389.                   basesubjs[numarts] := copy(basesubjs[numarts],5,255);
  1390.                 end;
  1391.               getindents(filename,indents[numarts]);
  1392.               datestr := getheaderline(filename,'date:');
  1393.               datesp^[numarts] := stringtodatestring(datestr);
  1394.               if atoi(fileinfo.name)>highestart then
  1395.                 highestart := atoi(fileinfo.name);
  1396.             end;
  1397.         end;
  1398.       findnext(fileinfo);
  1399.     end;
  1400.  
  1401.   if numarts=0 then
  1402.     xwritelns('no new articles')
  1403.   else
  1404.     xwriteln;
  1405.  
  1406. end;
  1407.  
  1408. procedure viewarts(lowest,highest: integer; updatehighestread: boolean);
  1409.  
  1410. begin
  1411.  
  1412.   currart := lowest;
  1413.   donegroup := false;
  1414.   browsedir := 1;
  1415.   while not donegroup do
  1416.     begin
  1417.       while (currart>=lowest) and (currart<=highest) and
  1418.        not selected[currart] do
  1419.         inc(currart,browsedir);
  1420.       if currart>highest then
  1421.         donegroup := true;
  1422.       if currart<lowest then
  1423.         browsedir := 1;
  1424.       if (currart>=lowest) and (currart<=highest) then
  1425.         begin
  1426.           browsedir := 1;
  1427.           browseart(currart);
  1428.           if (atoi(filenamesp^[currart])>highestread) and
  1429.            updatehighestread then
  1430.             highestread := atoi(filenamesp^[currart]);
  1431.         end;
  1432.       inc(currart,browsedir);
  1433.     end;
  1434. end;
  1435.  
  1436. procedure selectarts;
  1437.  
  1438. var
  1439.   i: integer;
  1440.   donepagesel: boolean;
  1441.   donegroupsel: boolean;
  1442.   topline,botline: integer;
  1443.   selsubjs: array[1..sellpp] of string;
  1444.   inkey,lastinkey: char;
  1445.   highestletteronscreen: char;
  1446.  
  1447. function issellet(ch: char): boolean;
  1448.  
  1449. begin
  1450.   issellet := islower(ch) and (ch<=highestletteronscreen);
  1451. end;
  1452.  
  1453. procedure writeselln(lineno: integer);
  1454.  
  1455. var
  1456.   ycoord: integer;
  1457.   printsubj: string;
  1458.   i: integer;
  1459.  
  1460. begin
  1461.   if selected[lineno] then
  1462.     xhighvideo
  1463.   else
  1464.     xlowvideo;
  1465.   ycoord := lineno-topline+1+headerlines+1;
  1466.   writexy(1,ycoord,chr(ord('a')+lineno-topline));
  1467.   writexy(3,ycoord,copy(fromsp^[lineno],1,20));
  1468.   xgotoxy(24,ycoord);
  1469.   xwriteiw(sizeink[lineno],4);
  1470.   printsubj := '';
  1471.   for i := 1 to indents[lineno] do
  1472.     printsubj := printsubj+'>';
  1473.   printsubj := printsubj+selsubjs[lineno-topline+1];
  1474.   if printsubj='' then
  1475.     writexy(29,ycoord,'-')
  1476.   else
  1477.     writexy(29,ycoord,copy(printsubj,1,50));
  1478.   xlowvideo;
  1479.   xgotoxy(1,sellpp+headerlines+4);
  1480. end;
  1481.  
  1482. procedure showselscreen;
  1483.  
  1484. var
  1485.   i: integer;
  1486.   prevsubj: string;
  1487.   percent: integer;
  1488.  
  1489. begin
  1490.   prevsubj := '';
  1491.   xclrscr;
  1492.   xgotoxy(1,1);
  1493.   xwritessis(currgroup,' Articles: ',numarts,'                      ');
  1494.   botline := topline-1;
  1495.   for i := topline to min(topline+sellpp-1,numarts) do
  1496.     begin
  1497.       if basesubjs[i]=prevsubj then
  1498.         selsubjs[i-topline+1] := ''
  1499.       else
  1500.         selsubjs[i-topline+1] := basesubjs[i];
  1501.       prevsubj := basesubjs[i];
  1502.       writeselln(i);
  1503.       botline := i;
  1504.     end;
  1505.   if numarts>100 then
  1506.     percent := (10*botline) div (numarts div 10)
  1507.   else
  1508.     percent := (100*botline) div numarts;
  1509.   xgotoxy(1,sellpp+headerlines+3);
  1510.   xwritelnsssisis('?=help  ',time,'   ',percent,'% through this group   ',
  1511.    numarts-botline,' more on later screen(s)');
  1512.   xclreol;
  1513.   xgotoxy(1,sellpp+headerlines+4);
  1514.   highestletteronscreen := chr(ord('a')+(botline-topline+1)-1);
  1515. end;
  1516.  
  1517. procedure togglekey(inkey: char);
  1518.  
  1519. var
  1520.   inkeyint: integer;
  1521.   artnum: integer;
  1522.  
  1523. begin
  1524.   inkeyint := ord(inkey)-ord('a');
  1525.   artnum := inkeyint+topline;
  1526.   if artnum<=botline then
  1527.     begin
  1528.       selected[artnum] := not selected[artnum];
  1529.       writeselln(artnum);
  1530.     end;
  1531. end;
  1532.  
  1533. procedure selreversepage;
  1534.  
  1535. var
  1536.   artnum: integer;
  1537.  
  1538. begin
  1539.   for artnum := topline to botline do
  1540.     begin
  1541.       selected[artnum] := not selected[artnum];
  1542.       writeselln(artnum);
  1543.     end;
  1544. end;
  1545.  
  1546. procedure dostar(inkey: char);
  1547.  
  1548. var
  1549.   inkeyint: integer;
  1550.   artnum: integer;
  1551.   currsubj: string;
  1552.  
  1553. begin
  1554.   inkeyint := ord(inkey)-ord('a');
  1555.   artnum := inkeyint+topline;
  1556.   currsubj := basesubjs[artnum];
  1557.   while (artnum<=numarts) and (currsubj=basesubjs[artnum]) do
  1558.     begin
  1559.       if not selected[artnum] then
  1560.         begin
  1561.           selected[artnum] := true;
  1562.           if artnum<=botline then
  1563.             writeselln(artnum);
  1564.         end;
  1565.       inc(artnum);
  1566.     end;
  1567. end;
  1568.  
  1569. procedure dodash(inkey: char);
  1570.  
  1571. var
  1572.   inkeyint: integer;
  1573.   artnum: integer;
  1574.   currsubj: string;
  1575.   newkey: char;
  1576.   newkeyint: integer;
  1577.  
  1578. begin
  1579.   inkeyint := ord(inkey)-ord('a');
  1580.   xclreolxy(1,lpp);
  1581.   xwritess(inkey,'-');
  1582.   newkey := xreadkey;
  1583.   if issellet(newkey) then
  1584.     begin
  1585.       newkeyint := ord(newkey)-ord('a');
  1586.       if (newkeyint<botline-topline+1) and (newkeyint>=inkeyint) then
  1587.         for artnum := topline+inkeyint to topline+newkeyint do
  1588.           if not selected[artnum] then
  1589.             begin
  1590.               selected[artnum] := true;
  1591.               writeselln(artnum);
  1592.             end;
  1593.     end;
  1594.   xclreolxy(1,lpp);
  1595. end;
  1596.  
  1597. procedure backpage;
  1598.  
  1599. begin
  1600.   if topline=1 then
  1601.     begin
  1602.       topline := numarts-((numarts-1) mod sellpp);
  1603.       showselscreen;
  1604.     end
  1605.   else
  1606.     begin
  1607.       dec(topline,sellpp);
  1608.       showselscreen;
  1609.     end;
  1610. end;
  1611.  
  1612. procedure forwardpage;
  1613.  
  1614. begin
  1615.   if botline=numarts then
  1616.     begin
  1617.       topline := 1;
  1618.       showselscreen;
  1619.     end
  1620.   else
  1621.     begin
  1622.       inc(topline,sellpp);
  1623.       showselscreen;
  1624.     end;
  1625. end;
  1626.  
  1627. procedure browsehighlightedarts;
  1628.  
  1629. var
  1630.   currart: integer;
  1631.  
  1632. begin
  1633.   viewarts(topline,botline,false);
  1634.   for currart := topline to botline do
  1635.     selected[currart] := false;
  1636.   showselscreen;
  1637. end;
  1638.  
  1639. procedure writehighlightedarts;
  1640.  
  1641. var
  1642.   currart: integer;
  1643.   ch: char;
  1644.  
  1645. begin
  1646. end;
  1647.  
  1648. procedure gotonewgroup;
  1649.  
  1650. var
  1651.   possgroup: string;
  1652.  
  1653. begin
  1654.   xclreolxy(1,lpp);
  1655.   xwrites('New Group: ');
  1656.   xreadlns(possgroup);
  1657.   if joinedtogroup(possgroup) then
  1658.     begin
  1659.       alreadyingroup := true;
  1660.       currgroup := possgroup;
  1661.       donegroupsel := true;
  1662.     end
  1663.   else
  1664.     xclreolxy(1,lpp);
  1665. end;
  1666.  
  1667. procedure selprevgroup;
  1668.  
  1669. var
  1670.   prevgroup: string;
  1671.   foundgroup: string;
  1672.  
  1673. begin
  1674.   prevgroup := '..invalid..';
  1675.   foundgroup := prevgroup;
  1676.   reset(joinf);
  1677.   repeat
  1678.     prevgroup := foundgroup;
  1679.     readln(joinf,foundgroup);
  1680.     foundgroup := getgroup(foundgroup);
  1681.   until foundgroup=currgroup;
  1682. {}{should check eof - I guess}
  1683.   if prevgroup<>'..invalid..' then
  1684.     begin
  1685.       currgroup := prevgroup;
  1686.       donegroupsel := true;
  1687.       alreadyingroup := true;
  1688.     end;
  1689. {}{need more error checking here...}
  1690. {}{also, it just goes back 1 group - not to the one with something to read!}
  1691. end;
  1692.  
  1693. procedure selcatch;
  1694.  
  1695. begin
  1696.   donegroupsel := true;
  1697.   highestread := highestart;
  1698. end;
  1699.  
  1700. procedure selquit;
  1701.  
  1702. var
  1703.   i: integer;
  1704.  
  1705. begin
  1706.   alreadyingroup := true;
  1707.   currgroup := '';
  1708.   donegroupsel := true;
  1709.   for i := 1 to numarts do
  1710.     selected[i] := false;
  1711. end;
  1712.  
  1713. procedure selhelppage;
  1714.  
  1715. var
  1716.   ch: char;
  1717.  
  1718. begin
  1719.   xclrscr;
  1720.   writexy(1,1,newsreadername+' '+newsreaderversion+
  1721.    ' - newsreader-under-development');
  1722.   writexy(1,2,'russell@alpha3.ersys.edmonton.ab.ca (921103)');
  1723.   writexy(1,4,'letter - toggle whether or not to read that article');
  1724.   writexy(1,5,'c-f - highlight c through and including f');
  1725.   writexy(1,6,'g*  - highlight g and all with same subject');
  1726.   writexy(1,7,'N   - go to next group (but browse first)');
  1727.   writexy(1,8,'X   - like N, but mark _all_ articles as read after');
  1728.   writexy(1,9,'P   - go to previous group');
  1729.   writexy(1,11,'@   - reverse all selections on this page');
  1730.   writexy(1,14,'<   - go back a page');
  1731.   writexy(1,15,'>   - go forward a page');
  1732.   writexy(1,16,'Z   - browse articles on this page (not marked as read)');
  1733.   writexy(1,17,'W   - write selected articles (this or all pages) (not yet)');
  1734.   writexy(1,20,'?   - help');
  1735.   writexy(1,22,'press any key to return');
  1736.   ch := xreadkey;
  1737.   showselscreen;
  1738. end;
  1739.  
  1740. begin
  1741.   for i := 1 to numarts do
  1742.     selected[i] := false;
  1743.   donegroupsel := (numarts=0);
  1744.   lastinkey := ' ';
  1745.   topline := 1;
  1746.   while not donegroupsel do
  1747.     begin
  1748.       donepagesel := false;
  1749.       showselscreen;
  1750.       while not donegroupsel and not donepagesel do
  1751.         begin
  1752.           inkey := xreadkey;
  1753.           if inkey='?' then selhelppage
  1754.           else if issellet(inkey) then togglekey(inkey)
  1755.           else if inkey='<' then backpage
  1756.           else if inkey='>' then forwardpage
  1757.           else if (inkey=' ') or (inkey=#13) then donepagesel := true
  1758.           else if (inkey='*') and issellet(lastinkey) then dostar(lastinkey)
  1759.           else if (inkey='-') and issellet(lastinkey) then dodash(lastinkey)
  1760.           else if inkey='Z' then browsehighlightedarts
  1761.           else if inkey='W' then writehighlightedarts
  1762.           else if inkey='G' then gotonewgroup
  1763.           else if inkey='N' then donegroupsel := true
  1764.           else if inkey='@' then selreversepage
  1765.           else if inkey='X' then selcatch
  1766.           else if inkey='P' then selprevgroup
  1767.           else if inkey='Q' then selquit;
  1768.           lastinkey := inkey;
  1769.         end;
  1770.       if botline<numarts then
  1771.         inc(topline,sellpp)
  1772.       else
  1773.         donegroupsel := true;
  1774.     end;
  1775. end;
  1776.  
  1777. procedure getmainnewsdir;
  1778.  
  1779. var
  1780.   infilen: string;
  1781.   infile: text;
  1782.   foundit: boolean;
  1783.   s: string;
  1784.  
  1785. begin
  1786.   mainnewsdir := '';
  1787.   infilen := waffledir+'\system\'+forumset;
  1788.   assign(infile,infilen);
  1789.   {$I-}
  1790.   reset(infile);
  1791.   {$I+}
  1792.   if ioresult=0 then
  1793.     begin
  1794.       foundit := false;
  1795.       while not eof(infile) and not foundit do
  1796.         begin
  1797.           readln(infile,s);
  1798.           if (copy(ltrim(s),1,length('DEFAULT'))='DEFAULT') and
  1799.            (pos('/dir=',s)>0) then
  1800.             begin
  1801.               foundit := true;
  1802.               mainnewsdir := trim(ltrim(copy(s,pos('/dir=',s)+5,255)));
  1803.               mainnewsdir := unquote(unslash(mainnewsdir));
  1804.             end;
  1805.         end;
  1806.       close(infile);
  1807.     end
  1808.   else
  1809.     begin
  1810.       xwritelnss('could not open forum set file ',infilen);
  1811.       halt(1);
  1812.     end;
  1813. end;
  1814.  
  1815. procedure groupinit;
  1816.  
  1817. procedure groupinitkills;
  1818.  
  1819. var
  1820.   s: string;
  1821.   killgroup: string;
  1822.   killline: integer;
  1823.  
  1824. function killeof: boolean;
  1825.  
  1826. begin
  1827.   if killfileinmem then
  1828.     killeof := (killline>=numkills)
  1829.   else
  1830.     killeof := eof(killf);
  1831. end;
  1832.  
  1833. function nextkillline: string;
  1834.  
  1835. var
  1836.   s: string;
  1837.  
  1838. begin
  1839.   if killfileinmem then
  1840.     begin
  1841.       inc(killline);
  1842.       nextkillline := killtextp^[killline];
  1843.     end
  1844.   else
  1845.     begin
  1846.       readln(killf,s);
  1847.       nextkillline := s;
  1848.     end;
  1849. end;
  1850.  
  1851. begin
  1852.  
  1853. {read in kill file for this group}
  1854.  
  1855.   numkillss := 0;
  1856.   numkillfs := 0;
  1857.   killline := 0;
  1858.  
  1859.   if haskillfile then
  1860.     begin
  1861.       if not killfileinmem then
  1862.         begin
  1863. {} xwritelns('reading in kill file...');
  1864.           reset(killf);
  1865.         end;
  1866.  
  1867. {allow defaults to come before the first Newsgroups line}
  1868.  
  1869.       killgroup := currgroup;
  1870.       while not killeof do
  1871.         begin
  1872.           s := nextkillline;
  1873.           if parseheadername(s)='Newsgroups' then
  1874.             killgroup := parseheadervalue(s);
  1875.           if killgroup=currgroup then
  1876.             begin
  1877.  
  1878. {} if parseheadername(s)='Subject' then xwritelnss('kill: ',s);
  1879.  
  1880.               if parseheadername(s)='Subject' then
  1881.                 begin
  1882.                   if numkillss<maxkills then
  1883.                     begin
  1884.                       inc(numkillss);
  1885.                       killsubjsp^[numkillss] := parseheadervalue(s);
  1886.                     end
  1887.                   else
  1888.                     begin
  1889.                       {too many subject kills - ignore}
  1890.                     end;
  1891.                 end
  1892.               else if parseheadername(s)='From' then
  1893.                 begin
  1894.                   if numkillss<maxkills then
  1895.                     begin
  1896.                       inc(numkillfs);
  1897.                       killfromsp^[numkillfs] := parseheadervalue(s);
  1898.                     end
  1899.                   else
  1900.                     begin
  1901.                       {too many from kills - ignore}
  1902.                     end;
  1903.                 end
  1904.               else
  1905.                 begin
  1906.                   {invalid entry in kill file - ignore}
  1907.                 end;
  1908.             end;
  1909.         end;
  1910.     end;
  1911. end;
  1912.  
  1913. begin
  1914.   numarts := 0;
  1915.   basedir := getbasedir(currgroup);
  1916.   headerinmem := '';
  1917.   highestread := 0;
  1918.   if (copy(basedir,length(basedir),1)=':') then
  1919.     basedirsuf := ''
  1920.   else
  1921.     basedirsuf := '\';
  1922.  
  1923. {$ifdef verbose}
  1924.   xwritelnssss('basedir=',basedir,', basedirsuf=',basedirsuf);
  1925. {$endif}
  1926.  
  1927.   groupinitkills;
  1928. end;
  1929.  
  1930. procedure findhighest;
  1931.  
  1932. var
  1933.   s: string;
  1934.  
  1935. begin
  1936.   reset(joinf);
  1937.   alreadyread := -1;
  1938.   while (alreadyread<0) and not eof(joinf) do
  1939.     begin
  1940.       readln(joinf,s);
  1941.       if getgroup(s)=currgroup then
  1942.         alreadyread := getalreadyread(s);
  1943.     end;
  1944.  
  1945. { only needed for initial single-group stuff }
  1946.  
  1947.   if alreadyread<0 then
  1948.     begin
  1949.       xwritelnss('not joined to ',currgroup);
  1950.       halt(1);
  1951.     end;
  1952.  
  1953. { end of only needed part }
  1954.  
  1955. end;
  1956.  
  1957. procedure initialize;
  1958.  
  1959. var
  1960.   currparmi: integer;
  1961.   currparm: string;
  1962.   nextparm: string;
  1963.  
  1964. begin
  1965.   randomize;
  1966.   new(filenamesp);
  1967.   new(fromsp);
  1968.   new(datesp);
  1969.   new(killsubjsp);
  1970.   new(killfromsp);
  1971.   new(killtextp);
  1972.   username := '';
  1973.   currgroup := '';
  1974.   forumset := '';
  1975.  
  1976. {$ifdef tiny}
  1977.   console := false;
  1978.   port := 0;
  1979.   trusted := false;
  1980. {$else}
  1981.   console := true;
  1982.   port := -1;
  1983.   trusted := true;
  1984. {$endif}
  1985.  
  1986.   fullname := '';
  1987.   editor := '';
  1988.   edoptions := '';
  1989.  
  1990.   alreadyingroup := false;
  1991.  
  1992.   currparmi := 1;
  1993.   while currparmi<=paramcount do
  1994.     begin
  1995.       currparm := paramstr(currparmi);
  1996.       if currparmi<paramcount then
  1997.         nextparm := paramstr(currparmi+1)
  1998.       else
  1999.         nextparm := '';
  2000.  
  2001.       if (currparm='-u') or (currparm='--user') then
  2002.         begin
  2003.           username := nextparm;
  2004.           inc(currparmi);
  2005.         end
  2006.       else if (currparm='-n') or (currparm='--newsgroup') then
  2007.         begin
  2008.           currgroup := nextparm;
  2009.           if currgroup<>'' then
  2010.             alreadyingroup := true;
  2011.           inc(currparmi);
  2012.         end
  2013.       else if (currparm='-p') or (currparm='--port') then
  2014.         begin
  2015.           console := false;
  2016.           port := atoi(nextparm);
  2017.           trusted := false;
  2018.           inc(currparmi);
  2019.         end
  2020.       else if (currparm='-f') or (currparm='--fullname') then
  2021.         begin
  2022.           fullname := ununderscore(nextparm);
  2023.           inc(currparmi);
  2024.         end
  2025.       else if (currparm='-e') or (currparm='--editor') then
  2026.         begin
  2027.           editor := nextparm;
  2028.           inc(currparmi);
  2029.         end
  2030.       else if (currparm='-o') or (currparm='--options') then
  2031.         begin
  2032.           edoptions := ununderscore(nextparm);
  2033.           inc(currparmi);
  2034.         end
  2035.       else if (currparm='-s') or (currparm='--forumset') then
  2036.         begin
  2037.           forumset := nextparm;
  2038.           inc(currparmi);
  2039.         end
  2040.       else if (currparm='-t') or (currparm='--trusted') then
  2041.         begin
  2042.           trusted := true;
  2043.         end
  2044.       else
  2045.         begin
  2046.  
  2047. {
  2048.  
  2049. compatability switch with earlier releases - now obsolete
  2050.  
  2051.           xwritelnss('unknown option: ',currparm);
  2052.           halt(1);
  2053.  
  2054. }
  2055.  
  2056.           username := currparm;
  2057.           xwritelns('warning: obsolete usage of username');
  2058.           xwritelns('use -u or --user instead');
  2059.         end;
  2060.       inc(currparmi);
  2061.     end;
  2062.  
  2063.   if username='' then
  2064.     username := lower(getenv('NET_NAME'));
  2065.  
  2066.   if username='' then
  2067.     usage;
  2068.  
  2069.   if not console and (port<>0) and (port<>1) then
  2070.     begin
  2071.       xwritelns('error: -p or --port specified without valid port number');
  2072.       xwritelns('  valid numbers are 0 (COM1) and 1 (COM2)');
  2073.       halt(1);
  2074.     end;
  2075.  
  2076.   wafenv := unslash(getenv('WAFFLE'));
  2077.   if wafenv='' then
  2078.     begin
  2079.       xwritelns('must set WAFFLE environment variable');
  2080.       halt(1);
  2081.     end;
  2082.  
  2083.   spooldir := unslash(getstaticvalue('spool'));
  2084.   temporarydir := unslash(getstaticvalue('temporary'));
  2085.   userdir := unslash(getstaticvalue('user'));
  2086.   waffledir := unslash(getstaticvalue('waffle'));
  2087.  
  2088.   if forumset='' then
  2089.     begin
  2090.       forumset := getstaticvalue('forums');
  2091.       if pos(' ',forumset)<>0 then
  2092.         begin
  2093.           if pos(' usenet ',' '+forumset+' ')<>0 then
  2094.             forumset := 'usenet'
  2095.           else
  2096.             forumset := copy(forumset,1,pos(' ',forumset)-1);
  2097.         end;
  2098.     end;
  2099.  
  2100.   xwritelnss('forum set: ',forumset);
  2101.  
  2102.   if fullname='' then
  2103.     begin
  2104.       getfullname;
  2105.       if fullname='' then
  2106.         begin
  2107.           xwritelnsss('user ',username,' has no name in the password file');
  2108.           xwritelns('  and environment variable FULLNAME not set');
  2109.           xwritelns('  and options -f and --fullname not used');
  2110.           halt(1);
  2111.         end;
  2112.     end;
  2113.  
  2114.   if editor='' then
  2115.     editor := getenv('EDITOR');
  2116.   if editor='' then
  2117.     editor := 'c:\usr\bin\vi.exe';
  2118.  
  2119.   uucpname := getstaticvalue('uucpname');
  2120.   node := getstaticvalue('node');
  2121.   smarthost := getstaticvalue('smarthost');
  2122.   organ := getstaticvalue('organ');
  2123.  
  2124.   timezone := getenv('TZ');
  2125.   if timezone='' then
  2126.     timezone := getstaticvalue('timezone');
  2127.   if timezone='' then
  2128.     timezone := 'MST'
  2129.   else if pos(' ',timezone)>1 then
  2130.     timezone := copy(timezone,1,pos(' ',timezone)-1);
  2131.  
  2132.   xwritelnss('time zone: ',timezone);
  2133.  
  2134.  
  2135.   wafversion := getenv('WAFVERSION');
  2136.   if wafversion='' then
  2137.     wafversion := '1.64';
  2138.   if length(wafversion)<>4 then
  2139.     begin
  2140.       xwritelns('WAFVERSION environment variable in wrong format');
  2141.       xwritelns('should be similar to `1.64'' (without the quotes)');
  2142.       halt(1);
  2143.     end;
  2144.  
  2145.   home := userdir+'\'+username;
  2146.   join := home+'\join';
  2147.   assign(joinf,join);
  2148.   {$I-}
  2149.   reset(joinf);
  2150.   {$I+}
  2151.   if ioresult<>0 then
  2152.     begin
  2153.       xwritelnsss('join file ',join,' not found.');
  2154.       halt(1);
  2155.     end;
  2156.  
  2157.   haskillfile := true;
  2158.   kill := home+'\kill';
  2159.   assign(killf,kill);
  2160.   {$I-}
  2161.   reset(killf);
  2162.   {$I+}
  2163.   if ioresult<>0 then
  2164.     begin
  2165.       haskillfile := false;
  2166.       xwritelns('(no kill file found)');
  2167.     end;
  2168.  
  2169.   xwritelnss('user: ',username);
  2170.  
  2171.   mainnewsdirsuf := '';
  2172.   getmainnewsdir;
  2173.   if mainnewsdir='' then
  2174.     begin
  2175.       xwritelns('could not find main news directory');
  2176. { no longer halts - user may have /dir= on each and every entry - allow it }
  2177.     end
  2178.   else
  2179.     begin
  2180.  
  2181.       if copy(mainnewsdir,length(mainnewsdir),1)=':' then
  2182.         begin
  2183.           xwritelns('invalid main news dir - cannot end in ":"');
  2184.           mainnewsdir := mainnewsdir+'\';
  2185.           xwritelnsss('rewritten as ',mainnewsdir,
  2186.            ' for Waffle compatability');
  2187.           halt(1);
  2188.         end;
  2189.  
  2190. {
  2191.  
  2192. it'd be better if it always had the : in it, but it's not... well... wrong
  2193.  
  2194.       if pos(':',mainnewsdir)=0 then
  2195.         begin
  2196.           xwritelns('invalid main news dir - must have ":"');
  2197.           halt(1);
  2198.         end;
  2199.  
  2200. }
  2201.  
  2202.       if copy(mainnewsdir,length(mainnewsdir),1)<>'\' then
  2203.         mainnewsdirsuf := '\';
  2204.     end;
  2205.  
  2206.   if currgroup<>'' then
  2207.     if not joinedtogroup(currgroup) then
  2208.       begin
  2209.         xwritelnsss('not joined to ',currgroup,
  2210.          ' - starting at top of join file');
  2211.         currgroup := '';
  2212.         alreadyingroup := false;
  2213.       end;
  2214.  
  2215.   numjoined := 0;
  2216.   backupjoin;
  2217.   backupkill;
  2218. end;
  2219.  
  2220. procedure shutdown;
  2221.  
  2222. begin
  2223.   close(joinf);
  2224.   if haskillfile then
  2225.     close(killf);
  2226.   xgotoxy(1,lpp);
  2227.   xwriteln;
  2228. end;
  2229.  
  2230. begin
  2231.   initialize;
  2232.  
  2233. {$ifdef debug}
  2234.   exec('c:\usr\bin\freem.exe','');
  2235.   xwrites('rusnews: freem: doserror=');
  2236.   xwritei(doserror);
  2237.   xwriteln;
  2238. {$endif}
  2239.  
  2240.   repeat
  2241.     if alreadyingroup then
  2242.       alreadyingroup := false
  2243.     else
  2244.       currgroup := getnextgroup;
  2245.     if currgroup<>'' then
  2246.       begin
  2247.  
  2248. {$ifdef verbose}
  2249.         xwritelnss('group found=',currgroup);
  2250. {$endif}
  2251.  
  2252.         groupinit;
  2253.         findhighest;
  2254.         xwritelns('Reading...');
  2255.         readinarts;
  2256.         if not nextwhilereading then
  2257.           begin
  2258.  
  2259. {all these routines handle numarts=0 just fine - but it cuts down on output}
  2260.             if numarts>0 then
  2261.               begin
  2262.                 xwritelns('Sorting...');
  2263.                 sortitall;
  2264.  
  2265.           {
  2266.             for i := 1 to numarts do
  2267.               xwritelnsssssss(filenamesp^[i]:14,' ',datesp^[i],' ',
  2268.                indents[i]:1,' ',copy(basesubjs[i],1,55));
  2269.           }
  2270.  
  2271.                 selectarts;
  2272.                 viewarts(1,numarts,true);
  2273.                 updatejoin;
  2274.               end;
  2275.           end;
  2276.       end;
  2277.   until currgroup='';
  2278.   shutdown;
  2279. end.