From:	CSBVAX::MRGATE!SCS7317%OCVAXB@VB.CC.CMU.EDU@SMTP 26-MAY-1988 19:44
To:	ARISIA::EVERHART
Subj:	NEWS(DECNET/VMS)  USENET on VMS  reader user agent and DECNET mapper


Received: from VB.CC.CMU.EDU by KL.SRI.COM with TCP; Tue 24 May 88 16:00:11-PDT
Date: Tue, 24 May 88 19:00 EDT
From: Christopher Seline <SCS7317%OCVAXB@VB.CC.CMU.EDU>
Subject: NEWS(DECNET/VMS)  USENET on VMS  reader user agent and DECNET mapper
To: info-vax@KL.SRI.COM
X-VMS-To: CMCCVB::IN%"info-vax@kl.sri.com"

$!..............................................................................
$! VAX/VMS archive file created by VMS_SHAR V-5.01 01-Oct-1987
$! which was written by Michael Bednarek (U3369429@ucsvc.dn.mu.oz.au)
$! To unpack, simply save and execute (@) this file.
$!
$! This archive was created by SCS7317
$! on Tuesday 24-MAY-1988 18:55:41.32
$!
$! It contains the following 3 files:
$! MAP.BAS MAP.PAS NEWS.TPU
$!==============================================================================
$ Set Symbol/Scope=(NoLocal,NoGlobal)
$ Version=F$GetSYI("VERSION") ! See what VMS version we have here:
$ If Version.ges."V4.4" then goto Version_OK
$ Write SYS$Output "Sorry, you are running VMS ",Version, -
                ", but this procedure requires V4.4 or higher."
$ Exit 44
$Version_OK: CR[0,8]=13
$ Pass_or_Failed="failed!,passed."
$ Goto Start
$Convert_File:
$ Read/Time_Out=0/Error=No_Error1/Prompt="creating ''File_is'" SYS$Command ddd
$No_Error1: Define/User_Mode SYS$Output NL:
$ Edit/TPU/NoSection/NoDisplay/Command=SYS$Input/Output='File_is' -
        VMS_SHAR_DUMMY.DUMMY
f:=Get_Info(Command_Line,"File_Name");b:=Create_Buffer("",f);
o:=Get_Info(Command_Line,"Output_File");Set(Output_File,b,o);
Position(Beginning_of(b));Loop x:=Erase_Character(1);Loop ExitIf x<>"V";
Move_Vertical(1);x:=Erase_Character(1);Append_Line;
Move_Horizontal(-Current_Offset);EndLoop;Move_Vertical(1);
ExitIf Mark(None)=End_of(b) EndLoop;Position(Beginning_of(b));Loop
x:=Search("`",Forward,Exact);ExitIf x=0;Position(x);Erase_Character(1);
If Current_Character='`' then Move_Horizontal(1);else
Copy_Text(ASCII(INT(Erase_Character(3))));EndIf;EndLoop;Exit;
$ Delete VMS_SHAR_DUMMY.DUMMY;*
$ Checksum 'File_is
$ Success=F$Element(Check_Sum_is.eq.CHECKSUM$CHECKSUM,",",Pass_or_Failed)+CR
$ Read/Time_Out=0/Error=No_Error2/Prompt=" CHECKSUM ''Success'" SYS$Command ddd
$No_Error2: Return
$Start:
$ File_is="MAP.BAS"
$ Check_Sum_is=1149044145
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X10 rem MAP -  hack tolook for news on a DECNET
X20 rem it isn't pretty (and it doesn't use DAP (which it should)) but
X30 rem it works.  Which is the number one important thing in the real world
X40 rem and all you programmers out there had better not forget it.
X100 print "Map -- Check your entire DECNET for sites running USENET"
X105 print
X130 print "It checks invisible nodes...and dead nodes....infact"
X140 print "It checks every possible node........"
X150 print
X200 for a = 1 to 74000
X202 if a = 68 then goto 400
X205 e = 0
X207 close #1
X210 when error in
X220 open str$(a)+'::"/usr/lib/news/active"' as file #1, access read
X230 use
X240 e = 1
X250 print a ,ert$(err)
X260 end when
X300 if e = 0 then close #1
X305 if e = 1 then goto 400
X310 print using "######",a;
X320 print " active"
X330 ac$=ac$ + " " + str$(a)
X400 next a
X510 print
V520 if ac$="" then print "No news easily found.  A more sophisticated utility i
Xs needed."
X530 if ac$<>"" then print "news at "; ac$
X540 print
X550 print "done."
$ GoSub Convert_File
$ File_is="MAP.PAS"
$ Check_Sum_is=1867919516
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
Xprogram map (input,output);
X
X(* MAP.PAS`009This is a unsupported part of the NEWS(DECNET/VMS) suite.
X
X   MAP.PAS`009Looks around your DECNET from any node suitably configured
X`009 `009for NEWS(DECNET/VMS).  You should pick the one closest to
X`009`009you, and DEFINE it as NEWS_FARSITE.
X
X   MAP.PAS`009works in the most crude way possible.  A more sophisticated
X`009`009technique (using DAP) would be nice, but...then again, 
X`009`009this works.
X*)
X
XVAR node, stat : integer;
X    node_spec : varying [200] of char :='';
X    infil : text;
X
XBEGIN
X   WRITELN('MAP X01  --  Map Your DECNET');
X   WRITELN('             Looking for sites suitable to be NEWS_FARSITE');
X   WRITELN;
X   for node := 1  TO 99000 DO
X`009BEGIN
X`009   node_spec := dec(node,5) + '::"/usr/lib/news/active"';
X`009   write(dec(node,5) + '::  ');
X`009   OPEN(`009file_variable `009:= infil,
X`009`009`009file_name`009:= node_spec,
X`009`009`009history`009`009:= READONLY,
X`009`009`009sharing`009`009:= READONLY,
X`009`009    `009error`009`009:= CONTINUE);
X`009   stat := status(infil);
X`009   IF (stat = 0)
X`009`009THEN writeln('SUCCESS!!!  This could be used as news_farsite')
X`009`009ELSE 
X`009`009`009begin
X`009`009`009write   ('Not this node. STATUS :=');
X`009`009`009writeln (stat);
X`009`009`009end;
X`009   CLOSE(infil, error`009`009:= CONTINUE);
X`009
X
X`009END;
X                    
X
XEND.
X                           
$ GoSub Convert_File
$ File_is="NEWS.TPU"
$ Check_Sum_is=1728655159
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X! NEWS-news.tpu - a program to let people read news in comfort (scrolling
X! backwards, automatic pause, etc) 
X!
X!`009news.tpu Copyright 1988 (c) Christopher Seline
X!`009ALL RIGHTS RESERVED
X!
X!`009TO USE THIS PRODUCT YOU MUST OBTAIN A LICENSE
X!
X!`009USE OF THIS PRODUCT MORE THAN FIVE (5) TIMES
X!`009WITHOUT A LICENSE IS A CRIME.  TO OBTAIN A LICENSE
X!`009SEND THE LICENSING FEE TO:
X!`009`009Christopher Seline
X!`009`009127 Green Bay Rd.
X!`009`009Winnetka, IL  60093
X!
X!`009LICENSING FEE:
X!`009`009Cluster license $250`009(per cluster)
X!`009`009Machine license $100`009(per machine)
X!`009`009Personal license$020`009(per user)
X!
X!
X 
X`012
V!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
X++++++++++++++++++++++++++++++++++++++++++++++++++++
X!                                                     installing this program
V!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
X++++++++++++++++++++++++++++++++++++++++++++++++++++
X!
X! If you have lost the detailed instructions:
X! rename this file to SYS$LOGIN:NEWS.TPU
X! issue the DCL command  EDIT/TPU/NOSEC/COM=SYS$LOGIN:NEWS.TPU
X!`009Now, the following command will invoke news
X!`009`009$ edit/tpu/sec=sys$login:news
X!`009Don't forget to define NEWS_FARSITE to some decnet node.
X!`009`009use MAP.PAS or MAP.BAS to figureout what to name it.
X!
X
X`012
V!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
X++++++++++++++++++++++++++++++++++++++++++++++++++++
X!                                                    INITIALIZATION PROCEDURES
V!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
X++++++++++++++++++++++++++++++++++++++++++++++++++++
X
X
XPROCEDURE tpu$init_procedure;
X! TPU calls this procedure automatically when it starts up.
X! After it exits, TPU will wait for bound keys and do their routines.
X    init_define_constants;
X    init_first; 
X    init_determine_mode;
X    init_PopUp_intro_text;
X    init_subscribe;                 
X    init_moveto_first_group_with_news;
XENDPROCEDURE;
X
X!----------
XPROCEDURE init_define_constants;
X
V    message_window_length := 3;  `009`009`009`009! size of the message window, 
Xin lines
V    status_text := "(X03.50) ^Z to exit    ? for help    ";`009! text to be dis
Xplayed on the window's status line
X    spool_dir := "news_spool:";`009`009`009`009! spool area if enabled
X    page_scroll_amount := 19;
X
V    $remote := 1; $sync := 2; $local := 3; $unknown := -1;  $mode := $unknown;`
X009`009`009! GLOBAL MODE
V!`009$mode indicates what mode NEWS operates in.  That is, where it looks for f
Xiles 
X!`009`009$remote`009`009--  All files are on NEWS_FARSITE
V!`009`009$sync`009`009--  active. is on NEWS_FARSITE, but some news articles ar
Xe kept in NEWS_SPOOL,
X!`009`009`009`009    so check there first
X!`009`009$local`009`009--  All files are in NEWS_SPOOL (including active).
V!`009`009`009`009    In $local mode, NEWS does not use DECNET at all.  (unless 
Xyou've defined
X!`009`009`009`009    NEWS_SPOOL to be on a DECNET NODE.
X
V    no := 0; yes := 1; help_visited := no; keypad_help_visited := no;`009`009! 
XGLOBAL HELP BUFFER STATUS
V                                                                               
X         ! change these to $ form
XENDPROCEDURE;
X
X!---------                
XPROCEDURE init_first
XLOCAL main_window_length;
Xon_error`009! kill error messages
Xendon_error;
X                              
V    main_window_length := GET_INFO(SCREEN, "visible_length") - message_window_l
Xength;
X    SET(PROMPT_AREA, main_window_length+1, 1, NONE);    
X                          
V    text_buffer := CREATE_BUFFER("Text");`009`009! create a buffer to hold the 
Xtext
X    SET(EOB_TEXT, text_buffer, "[END OF NEWS ITEM]");
X    SET(NO_WRITE, text_buffer);
X 
V    text_window := CREATE_WINDOW(1, main_window_length, ON);`009! create the ma
Xin text window
X    MAP(text_window, text_buffer);
X
V    message_buffer := CREATE_BUFFER("Message Buffer");`009! Create a message bu
Xffer for TPU messages,
V    SET(NO_WRITE, message_buffer); `009`009`009! for debugging, and map it into
X a window
X    SET(SYSTEM, message_buffer);
X    SET(EOB_TEXT, message_buffer, "");
V    message_window := CREATE_WINDOW(25-message_window_length, message_window_le
Xngth, OFF);
X    MAP(message_window, message_buffer);
X
X
XSET(FACILITY_NAME, "NEWS");`009`009`009`009! some initializtion   
XSET(MESSAGE_FLAGS, 15);`009`009`009`009`009! all message info
XSET(SUCCESS, OFF);
XSET(INFORMATIONAL, OFF);
X
Vjournal_open('nl:');`009`009`009`009`009! hack to prevent W-TPU$NOJOURNAL messa
Xge
X
Xenable_bell;
X
XENDPROCEDURE;
X
X
X!----------         
XPROCEDURE    init_determine_mode
Xlocal junk, junk1;
Xon_error 
Vjunk1 := 1;`009`009`009`009`009! indicate error, we expect an error when checki
Xng for local spooling
Xendon_error;
X
Xunmap(message_window);`009`009`009`009! stiffle RMS error messages
X
X! this procedure also creates active                                           
Xactive := CREATE_BUFFER ('active');`009`009! buffer holds /usr/lib/news/active
XPOSITION (active);
XSET (NO_WRITE, active);
XSET (SYSTEM, active);       
XSET (TIMER, ON, "Loading active");
X
Vmessage("");message("");message("");message("");! why can we intercept them w/ 
Xon ERR!!!!
X
XREAD_FILE(spool_dir + 'active.');
XIF beginning_of(active) = end_of(active) THEN
X   READ_FILE('news_farsite::"/usr/lib/news/active"');
X   $mode := $remote
X   ELSE
X   $mode := $local;
XENDIF;
X
XSET (TIMER, OFF);
X
XIF end_of(active) = beginning_of(active) THEN
X   message("I could not load active.");
X   message("USE q TO ABORT");
X   message("USE q TO ABORT");
X   message("USE q TO ABORT");
X   five_map;
X   abort;
XENDIF;
X
X
XIF $mode = $remote THEN
X! determine if spooling exists.....
Xjunk := create_buffer("junk");
Xposition(junk);
Xjunk1 := 0;
XREAD_FILE (spool_dir + 'news-spooling-exists.');
VIF junk1 <> 1 then $mode := $sync; ENDIF;`009! if the file was sucessfully open
Xed then we have local spooling of remote files
X
XENDIF;
X                                     
XIF $mode = $remote THEN`009MESSAGE("NEWS(DECNET/VMS) V00.90 (remote)") ELSE
XIF $mode = $local  THEN`009MESSAGE("NEWS(DECNET/VMS) V00.90 (local)")  ELSE
XIF $mode = $sync   THEN`009MESSAGE("NEWS(DECNET/VMS) V00.90 (sync)")   ELSE
X`009`009`009MESSAGE("NEWS(DECNET/VMS) V00.90 (BUG)");
XENDIF;ENDIF;ENDIF;`009! why can't the CASE statement deal with variables!
X
Xmap(message_window,message_buffer);`009`009! UNstiffle messages
X
XENDPROCEDURE;
X
X!----------
XPROCEDURE init_PopUp_intro_text;
XPOSITION (BEGINNING_OF(text_buffer));
X
X! THIS IS WHERE INTRODUCTORY TEXT GOES
X
V copy_text("                news.tpu Copyright (c) 1988 Christopher Seline"); s
Xplit_line;
X copy_text("                              ALL RIGHTS RESERVED "); split_line;
X copy_text(" "); split_line;
V!copy_text("    USE OF THIS PRODUCT MORE THAN FIVE (5) TIMES WITHOUT A LICENSE 
XIS A"); split_line;
V!copy_text("    CRIME.  TO OBTAIN A LICENSE SEND THE LICENSING FEE TO: "); spli
Xt_line;
X!copy_text("    `009Christopher Seline "); split_line;
X!copy_text("`009127 Green Bay Rd."); split_line;
X!copy_text("`009Winnetka, IL  60093 "); split_line;
X!copy_text(" "); split_line;
X!copy_text("    LICENSING FEE:"); split_line;
X!copy_text("         Cluster license $250`009(per cluster)"); split_line;
X!copy_text("         Machine license $100`009(per machine)"); split_line;
X!copy_text("         Personal license$020`009(per user)"); split_line;
X copy_text(" "); split_line;
X copy_text(" "); split_line;
X 
V copy_text("                  Press the SPACE BAR for next USENET message"); sp
Xlit_line;
X!
XENDPROCEDURE; 
X
X
X!----------
XPROCEDURE init_subscribe
X
Xsubscribe := CREATE_BUFFER ('subscribe','sys$login:News_Subscribe.dat');
XSET (NO_WRITE, subscribe);
XSET (SYSTEM, subscribe);
XPOSITION (subscribe);
XIF (BEGINNING_OF (subscribe) = END_OF (subscribe)) ! null or file not found
X   THEN                                    
X   message ("Can't find your news subscription -- subscribing for you.");
X   message ("This takes several minutes -- so sit back and relax...");
X   subscribe_create;
XENDIF;
Xupdate_banner;
XENDPROCEDURE;
X                                                                         
X
X           
V!------------------------------------------------------------------------------
X-
XPROCEDURE subscribe_create
XLOCAL a,b;
XPOSITION (subscribe);
VCOPY_TEXT (active);`009`009`009`009`009! copy active buffer into subscribe buff
Xer
X
XIF (BEGINNING_OF (subscribe) = END_OF (subscribe)) ! null or file not found
X   THEN                                    
X   message ("!!BUG -- reached subscribe_create with NULL active buffer");
X   abort;
XENDIF;            
X
X
X! now we need to massage the data   
VMAP (text_window, subscribe);`009`009`009`009! let them watch us massage the da
Xta
VPOSITION (BEGINNING_OF (subscribe));`009`009`009! leave only column one and two
X, delete column three and four
Xloop
X    exitif mark(none) = END_OF(subscribe);`009`009! exit loop at end of buffer
X
X    a := select_column_two;`009`009`009`009! set last message read column
V    b := INT(a) - 20;`009`009   `009`009`009! 20 is a magic number for how many
X messages to mark as unread
X    IF b < 1 THEN b := 1; ENDIF;
X    replace_column_two (b);
X
X    position (search(' ',FORWARD));`009`009`009! delete last two columns
X    move_horizontal (+1);
X    position (search(' ',FORWARD));
X    split_line;
X    erase_line;
Xupdate(current_window);
Xendloop;
X                   
V!move_group_to_top ("comp.os.vms");                      ! these groups will be
X read first
X!move_group_to_top ("rec.arts.comics");
X!move_group_to_top ("rec.humor");
X!move_group_to_top ("rec.arts.drwho");
X!move_group_to_top ("rec.arts.startrek");
Xmove_group_to_top ("news.announce.newusers");
X
VPOSITION (BEGINNING_OF (subscribe)); `009`009`009`009! unsubscribe control grou
Xp
Xposition(SEARCH (LINE_BEGIN & 'control', FORWARD, NO_EXACT));
Xreplace_column_two (99999);`009! 99999 magic number for unsubscribed
X
X
XPOSITION (BEGINNING_OF (subscribe));
Xmap(text_window,text_buffer);
XENDPROCEDURE;
X
X
V!------------------------------------------------------------------------------
X-
XPROCEDURE move_group_to_top (group_name)
XLOCAL group_name, j1, j2;
X! move a group to the top of subscribe buffer
V! note, unlike most routines, this one does not restore original position in bu
Xffers
X
XPOSITION (BEGINNING_OF (subscribe));
Xj1 := SEARCH (LINE_BEGIN & group_name & ' ', FORWARD, NO_EXACT);
XIF j1 = 0 THEN return; ENDIF;`009`009`009! return if it doesn't exist
Xposition(j1);
X
Xj2 := current_line;
Xerase_line;
XPOSITION (BEGINNING_OF (subscribe));
Xcopy_text(j2);
Xsplit_line;
XENDPROCEDURE;
X      
X
X
V!------------------------------------------------------------------------------
X-
VPROCEDURE     init_moveto_first_group_with_news;`009`009! move to first group w
Xith something in it to read 
X
Xmove_to_group_with_pending_news;
X
XENDPROCEDURE;
X 
X`012
V!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
X++++++++++++++++++++++++++++++++++++++++++++++++++++
V!                                    PROCEDURES -- MANY BOUND TO KEYS -- MANY H
XELPER FUNCTIONS
V!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
X++++++++++++++++++++++++++++++++++++++++++++++++++++
X
X
X
V!------------------------------------------------------------------------------
X-
XPROCEDURE page_down;
X! scroll down almost one screensworth
X    SCROLL(text_window, page_scroll_amount);
XENDPROCEDURE;
X
X                                  
X             
V!------------------------------------------------------------------------------
X-             
XPROCEDURE page_up;
X! scroll up almost one screensworth                                            
X    SCROLL(text_window, -page_scroll_amount);
XENDPROCEDURE;
X
X
X             
V!------------------------------------------------------------------------------
X-                                       
XPROCEDURE line_down 
Xlocal a;
X! scroll down one line
X    a:=mark(none);
X    SCROLL(text_window, 1);
X    If a = mark(none) THEN`009`009`009`009! we haven't moved
X      move_vertical(+1);
X    ENDIF;
XENDPROCEDURE;
X
X
X             
V!------------------------------------------------------------------------------
X-
XPROCEDURE line_up
Xlocal a;
X! scroll up one line
X    a:=mark(none);
X    SCROLL(text_window, -1);
X    If (a = mark(none)) THEN`009`009`009`009! we haven't moved
X      move_vertical(-1);
X    ENDIF;
XENDPROCEDURE;
X
X             
V!------------------------------------------------------------------------------
X-
XPROCEDURE go_to_group;
Xmessage("Go to exact group is no longer supported");
XENDPROCEDURE;   
X
X
V!------------------------------------------------------------------------------
X-
XPROCEDURE go_to_group_NOexact
XLOCAL group_name, j1,j2,j3;                                                    
X! go to a new group....no need to find exact name
X
Xon_error`009! kill error messages
X!    if error = tpu$_strnotfound then
X!`009message ("couldn't find it");
X!    endif;
Xendon_error;
X      
X
Xj1 := CURRENT_BUFFER;
XPOSITION (subscribe);            
Xj3 := MARK (none);`009! where we were if search fails
X              
Xgroup_name := READ_LINE ('GO TO WHICH GROUP (NOexact name): ');
X
Xmove_vertical(+1);`009`009`009! so we don't find current line
Xj2 := SEARCH ( group_name , FORWARD, NO_EXACT);
X
XIF j2 = 0 THEN       `009`009`009`009! try from beginning of buffer
X`009POSITION (BEGINNING_OF (subscribe));
X`009j2 := SEARCH ( group_name , FORWARD, NO_EXACT);
XENDIF;                                          
X
XIF j2 = 0 THEN`009`009`009`009`009! couldn't find it anywhere
X   MESSAGE ("Can't find the group you refered to: "+ group_name);
X   POSITION (j3);`009! move to old place in subscribe
X   POSITION (j1);`009! move to old buffer
X   RETURN(0);             
XENDIF;                                          
X
XPOSITION (j2);
Xposition (search (LINE_BEGIN, REVERSE, EXACT));
X
Vif mark(none) = j3 then message ("This is the only group that matches: "+ group
X_name); 
X   endif;
X
Xposition(text_buffer);      
Xzero_text_buffer;
Xupdate_banner;`009`009`009`009`009! indicate new group and position
X      `009
XENDPROCEDURE;   
X
V!------------------------------------------------------------------------------
X-
XPROCEDURE update_banner`009`009! update status_line to current grp & position
VLOCAL s1,s2, subs_current, a2, active_top, active_bot, diff,arg;               
X                
X
Vposition (subscribe);   `009`009`009`009! get subscribed group & next mesg. num
Xber
Xs1 := select_column_one;
Xs2 := select_column_two;
Xsubs_current := INT(s2);                                                   
X
Vposition (BEGINNING_OF(active));`009`009`009!move to same group in active as in
X subscribe                       
Xarg := SEARCH (LINE_BEGIN & s1 & ' ', FORWARD, NO_EXACT);
Vif arg = 0 THEN   `009`009`009`009`009! subscribe has groups that no longer exi
Xst in active;
X   sync_subscribe;
X   return(0); 
XENDIF;
Xposition(arg);
Xa2 := select_column_two;        
Xactive_top    := int (a2);  
Xactive_bot    := int (select_column_three);
XIF active_bot > subs_current THEN subs_current := active_bot; ENDIF;
Xdiff := active_top - subs_current;
XIF diff < 0 THEN diff := 0; ENDIF;                
X
XIF subs_current = 99999 then
VSET(STATUS_LINE, text_window, REVERSE, status_text + '    ' + s1 + ': Unsubscri
Xbed');
X`009ELSE
VSET(STATUS_LINE, text_window, REVERSE, status_text + '    ' + s1 + ':' + STR(su
Xbs_current)+'     '+str(diff)+' left');
X      `009ENDIF;
Xupdate(current_window);
XENDPROCEDURE;
X                                                                               
X
V`012                                                                           
X    
V!------------------------------------------------------------------------------
X-
Xprocedure sync_subscribe`009`009`009`009! called if subscribe is out of whack
V;!!!!!LOCAL ac_tmp, sub_tmp, a, b;`009       `009`009! this happens if a new gr
Xoup is added or deleted from active
X
Xdisable_bell;
Xmessage("Since I last checked groups have been added or deleted from active");
Xmessage("So, I'm going to sync subscribe to active.");
Xmessage ("This takes several minutes -- so sit back and relax...");
X
X! first makes copies of subscribe and active
X
X
Xac_tmp := CREATE_BUFFER("ac_tmp");  
Xset(No_write, ac_tmp);
Xposition(ac_tmp);  copy_text(active);
X
Xsub_tmp := CREATE_BUFFER("sub_tmp");  set(No_write, sub_tmp);
Xposition(sub_tmp); copy_text(subscribe);
X
Xmap(text_window,sub_tmp);
Xposition(beginning_of(sub_tmp));
Vloop`009`009`009! check each group in subscribe, if it isn't in active then del
Xete it from subscribe
X    exitif mark(none) = END_OF(sub_tmp);
X    a1:= mark(none);
X    a := select_column_one;
X    position(beginning_of(ac_tmp));
X    b := search(LINE_BEGIN & a & ' ', FORWARD, NO_EXACT);
X    if b = 0 then
X       position(a1);
X       erase_line;
X       message ("Deleted "+a);
X     ELSE
X       position(b); 
X       erase_line;`009! erase each line -- any left will be not in subscribe
X       position(a1);
X       move_vertical (+1);
X    ENDIF;
X    update(text_window);
Xendloop;
X      
Xif beginning_of(ac_tmp) <> end_of(ac_tmp) THEN
X   map(text_Window,ac_tmp);
V   POSITION (BEGINNING_OF (ac_tmp));`009`009`009! leave only column one and two
X, delete column three and four
X   loop
X       exitif mark(none) = END_OF(ac_tmp);`009`009! exit loop at end of buffer
X       message('Added ' + select_column_one);
X       a := select_column_two;`009`009`009`009! set last message read column
V       b := INT(a) - 20;`009`009   `009`009! 20 is a magic number for how many 
Xmessages to mark as unread
X       IF b < 1 THEN b := 1; ENDIF;
X       replace_column_two (b);
X
X       position (search(' ',FORWARD));`009`009`009! delete last two columns
X       move_horizontal (+1);
X       position (search(' ',FORWARD));
X       split_line;
X       erase_line;
X   update(text_window);
X   endloop;
X   position(sub_tmp);
X   copy_text(ac_tmp);
X   update(text_window);
XENDIF;
X
Xerase(subscribe);
Xposition(subscribe);
Xcopy_text(sub_tmp);
X    
Xposition(beginning_of(subscribe));
Xposition(beginning_of(active));
Xposition(beginning_of(text_buffer));
Xmap(text_window,text_buffer);      
Xenable_bell;
XENDPROCEDURE;
X
X
X
V!------------------------------------------------------------------------------
X-
XPROCEDURE catch_up`009`009! mark current group as read
XLOCAL s1, a2, active_top,x;
Xx := mark(none);
Xposition (subscribe);   `009! get subscribed group & next mesg. #
Xs1 := select_column_one;
X
Xposition (BEGINNING_OF(active));! move to same group in active
Xposition(SEARCH (LINE_BEGIN & s1 & ' ', FORWARD, NO_EXACT));
Xa2 := select_column_two;
Xactive_top    := int (a2);
X
Xposition(subscribe);
Xreplace_column_two (active_top);`009! update subscribe mesg#
X
Xupdate_banner;
Xzero_text_buffer;
Xposition(x);
XENDPROCEDURE;
X           
X                                                       
V!------------------------------------------------------------------------------
X-
XPROCEDURE UN_catch_up`009`009! mark this group as UNread
XLOCAL s1, a3, active_bottom, old_pos;
X
Xold_pos := mark(none);
Xposition (subscribe);   `009! get subscribed group & next mesg. #
Xs1 := select_column_one;
X
Xposition (BEGINNING_OF(active));! move to same group in active
Xposition(SEARCH (LINE_BEGIN & s1 & ' ', FORWARD, NO_EXACT));
Xa3 := select_column_three;
Xactive_bottom := int (a3);
X                          
Xposition(subscribe);
Xreplace_column_two (active_bottom);`009! update subscribe mesg#
X
Xposition(old_pos);
Xzero_text_buffer; 
Xupdate_banner;
XENDPROCEDURE;
X
X
V!------------------------------------------------------------------------------
X-
XPROCEDURE Unsubscribe
XLOCAL x;
Xx := mark(none);
Xposition(subscribe); 
Xreplace_column_two (99999);`009! 99999 magic number for unsubscribed
Xposition(x);  `009   `009`009! This will be a bug when a group his 99999
Xzero_text_buffer;
Xupdate_banner;
XENDPROCEDURE
X
X
V!------------------------------------------------------------------------------
X-
VPROCEDURE Subscribe_proc`009`009`009`009! resubscribe to unsubscribed news grou
Xp
XLOCAL x;
Xx := mark(none);
Xposition(subscribe); 
XUn_catch_up;
Xposition(x);
Xupdate_banner;
XENDPROCEDURE
X
X
X
X                                                       
X`012
V!------------------------------------------------------------------------------
X-
XPROCEDURE next_news_message     
VLOCAL i3,j1,j2,j3,s1,s2,s1a, s4,spool,news_file,subs_current,i,a1,a2,a3,active_
Xbottom,active_top,spool_file;
X! read in next message
X
X
Xupdate_banner;`009`009`009! Indicate which group and message this is
Xdisable_bell;`009`009`009! no beeping
X
Xposition (subscribe);   `009! get subscribed group & next mesg. #
Xs1 := select_column_one;
Xs1a:= s1;
Xs2 := select_column_two;
Xsubs_current := INT(s2);
X
XIF subs_current = 99999 THEN `009! if unsubscribed then recurse till OK
X`009next_group;
X      `009next_news_message;
X`009return(0);
XENDIF;
X                
X!move to same group in active as in subscribe                       
Xposition (BEGINNING_OF(active));
Xi := SEARCH (LINE_BEGIN & s1 & ' ', FORWARD, NO_EXACT);
Xposition(i);
X           
Xa1 := select_column_one;
Xa2 := select_column_two;
Xa3 := select_column_three;
Xactive_bottom := int (a3);      
Xactive_top    := int (a2);                                          
X                
X! create file name
XIF subs_current < active_bottom THEN subs_current := active_bottom; ENDIF;
XIF subs_current > active_top    THEN`009! Nothing Left to READ?
V`009message('Nothing left to read in group ' + s1 + ' -- Moving to next Group')
X;
X`009next_group; RETURN; ENDIF;
X                                     
Xspool := s1;
XTRANSLATE(spool,'_', '.');`009`009! convert to VMS  Name
XTRANSLATE(s1,   '/', '.');         `009! convert to Unix Name
X
Vnews_file := 'news_farsite::"/usr/spool/news/' + s1 + '/' + STR(subs_current) +
X '"' ;
X     
Xspool_file := spool_dir + spool + '_' + STR(subs_current)+ '.';
X                                  
Xsubs_current := subs_current + 1;
Xposition(subscribe); 
Xreplace_column_two (subs_current);`009! update subscribe mesg#
X
X!read in file                                          
XPOSITION (text_buffer);
XERASE (text_buffer);
XSET (TIMER, ON, 'Retrieving.');
X
XIf ($mode = $local)  or ($mode = $sync) THEN READ_FILE ( spool_file ); ENDIF;
X  
XIf ($mode = $remote) `009`009`009THEN READ_FILE ( news_file );  ENDIF;
X
XIf ($mode = $sync) and (BEGINNING_OF (text_buffer)= END_OF (text_buffer))
X   THEN READ_FILE ( news_file ); ENDIF;                      
X
XPOSITION (BEGINNING_OF (text_buffer));
VIF (BEGINNING_OF (text_buffer)= END_OF (text_buffer))`009! null or file not fou
Xnd
X   THEN 
X     message ("Null News Body -- Hope that's OK");
X     message("");
X   ELSE
V     underline_subject_line;          `009`009`009! underline subject if got ne
Xws
XENDIF;                      
X
X
XSET (TIMER, OFF);
Xenable_bell;
X
XENDPROCEDURE;                                                         
X
X
X`012
V!------------------------------------------------------------------------------
X-
VPROCEDURE next_group;`009`009`009      ! still needs to skip comletely read gro
Xups
X
Xposition(subscribe);            
Xif mark(none) = end_of(current_buffer)then 
X`009message ('ARGH -- End of News Groups (no more to read)'); 
X`009move_vertical(-1);
X`009return(0);
XENDIF;
Xmove_vertical(+1);`009`009`009`009! move to next group
Xmove_to_group_with_pending_news;
X
Xupdate_banner;        
X
XENDPROCEDURE;
X                                                                               
X
V!------------------------------------------------------------------------------
X-
XPROCEDURE move_to_group_with_pending_news
X! checks current group -- if current group has news it does not move forward
X
XLOCAL s1,s2,subs_current,a2,active_top,active_bot,diff;
X
Xposition(subscribe);
X! check for end of news groups
Xif mark(none) = end_of(current_buffer)then 
X`009message ('argh -- End of News Groups (no more to read)'); 
X`009move_vertical(-1);                                      
X`009return(0);
XENDIF;
X
X! if its an unsubscribed group, skip it
Xs1 := select_column_one;
Xs2 := select_column_two;
Xsubs_current := INT(s2);                                        
X
XIF subs_current = 99999 THEN `009! if unsubscribed then recurse till OK
X`009next_group;
X`009return(0);
XENDIF;
X
Vposition (BEGINNING_OF(active));`009`009`009!move to same group in active as in
X subscribe                       
Xposition(SEARCH (LINE_BEGIN & s1 & ' ', FORWARD, NO_EXACT));
Xa2 := select_column_two;        
Xactive_top    := int (a2);  
Xactive_bot    := int (select_column_three);
XIF active_bot > subs_current THEN subs_current := active_bot; ENDIF;
Xdiff := active_top - subs_current;
XIF diff < 0 THEN diff := 0; ENDIF;                
X
XIF diff = 0 THEN`009`009`009! recurse till locate group with items to read
X   next_group;
X   return(0);
XENDIF;       
X
XENDPROCEDURE;
X
X
V!------------------------------------------------------------------------------
X-
XPROCEDURE zero_text_buffer;`009`009`009`009! erase text buffer
VIF end_of(text_buffer) <> beginning_of(text_buffer) THEN! but don't bother unle
Xss there is text in it
X   erase(text_buffer);
XENDIF;
XENDPROCEDURE;
X
X
V!------------------------------------------------------------------------------
X-
XPROCEDURE space_bar
XLOCAL here;                                                             
Xhere := MARK(none);
Xpage_down;
XIF here = mark(none) THEN`009`009`009`009! we didn't move
X   next_news_message;`009`009`009`009`009! so at end of mesg
XENDIF;
XENDPROCEDURE;
X      
X
X             
V!------------------------------------------------------------------------------
X-
XPROCEDURE exit_news;
X
XWRITE_FILE (subscribe, 'sys$login:NEWS_SUBSCRIBE.dat');
Xdisable_bell;
Xmessage ('Thank You For Using NEWS(DECNET/VMS)`009  `009:-)');
Xquit;
XENDPROCEDURE;                                                  
X
X             
V!------------------------------------------------------------------------------
X-
XPROCEDURE keypad_help;
X
XIf keypad_help_visited = no THEN
X  keypad_help_init;
X  keypad_help_visited := yes;
X  return;
XENDIF;                
X                     
XMAP(text_window, keypad_help_buffer);
X
XENDPROCEDURE
X
X
X
XPROCEDURE keypad_help_init;
Xkeypad_help_buffer := create_buffer('keypad_help_buffer');
XSET(NO_WRITE, keypad_help_buffer);
XSET(SYSTEM, keypad_help_buffer);
XSET(EOB_TEXT, keypad_help_buffer, "");
X          
XMAP(text_window, keypad_help_buffer);
Xposition(keypad_help_buffer);
X
X!`012
Xcopy_text ('NEWS keypad for VT100 series terminals'); split_line;
Xcopy_text (''); split_line;
Vcopy_text ('      _________________________________     _______________________
X__________'); split_line;  
Vcopy_text ('      |   ^   |   |   |       |       |     |       |       |      
X |       |'); split_line;
Vcopy_text ('      |   |   |   V   |       |       |     | Find  | Help  | Pause
X |       |'); split_line;
Vcopy_text ('      |_______|_______|_______|_______|     |_______|_______|______
X_|_______|'); split_line;
Vcopy_text ('                                            |       |       |      
X |       |'); split_line;
Vcopy_text ('                                            |       |       |      
X |       |'); split_line;
Vcopy_text ('                                            |_______|_______|______
X_|_______|'); split_line;
Vcopy_text ('                                            |       |       |      
X | Next  |'); split_line;
Vcopy_text ('                                            |       |       |      
X | Group |'); split_line;
Vcopy_text ('                                            |_______|_______|______
X_|_______|'); split_line;
Vcopy_text ('                                            |       |       |      
X |       |'); split_line;
Vcopy_text ('                                            |       |       |      
X |       |'); split_line;
Vcopy_text ('        CTRL/R    - Refresh                 |_______|_______|______
X_| Next  |'); split_line;
Vcopy_text ('        CTRL/Z    - Exit                    |     Next      |Prev  
X |Message|'); split_line;
Vcopy_text ('                                            |     Screen    |Screen
X |       |'); split_line;
Vcopy_text ('                                            |_______________|______
X_|_______|'); split_line;
Xcopy_text (''); split_line;
Xposition(beginning_of(keypad_help_buffer));
X
X!    
XENDPROCEDURE;
X
X
V!------------------------------------------------------------------------------
X-
XPROCEDURE news_help;
X! give them help                                                               
X
XIf help_visited = no THEN
X  news_help_init;
X  help_visited := yes;
X  return;
XENDIF;
X                     
XMAP(text_window, help_buffer);
X
XENDPROCEDURE
X
X
X
XPROCEDURE news_help_init;
Xhelp_buffer := create_buffer('help_buffer');
XSET(NO_WRITE, help_buffer);
XSET(SYSTEM, help_buffer);
XSET(EOB_TEXT, help_buffer, "");
X
XMAP(text_window, help_buffer);
Xposition(help_buffer);
X
Vcopy_text(' NEWS keyboard help:                                                
X            '); split_line;
Vcopy_text('              n      - get next message                             
X            '); split_line;
Vcopy_text('              N      - moves to next group                          
X            '); split_line;
Vcopy_text('                                                                    
X            '); split_line;
Vcopy_text('              s      - Saves current message to a file              
X            '); split_line;
Vcopy_text('              g      - go to a group by name                        
X            '); split_line;
Vcopy_text('                                                                    
X            '); split_line;
Vcopy_text('              c      - Catch-up    (marks all messages in current gr
Xoup as read)'); split_line;
Vcopy_text("              u      - Unsubscribe           (you'll never see this 
Xgroup again)"); split_line;
Vcopy_text('              #      - read article by number       (skips interveni
Xng articles)'); split_line;
Vcopy_text('                                                                    
X            '); split_line;
Vcopy_text('         CTRL/W      - refresh screen                               
X            '); split_line;
Vcopy_text('         CTRL/Z      - exit                                         
X            '); split_line;
Vcopy_text('                                                                    
X            '); split_line;
Vcopy_text('         <Space Bar> - Displays next screen full of text            
X            '); split_line;
Vcopy_text('                     - If there is no more text, it gets next messag
Xe           '); split_line;
Vcopy_text('                                                                    
X            '); split_line;
Vcopy_text('                                                                    
X            '); split_line;
Xcopy_text("                            Press <1> to Exit Help"); 
XENDPROCEDURE;                              
X              
X
V!------------------------------------------------------------------------------
X-
XPROCEDURE disable_bell;
VSET (BELL, ALL      ,OFF);                                                     
X                           
XSET (BELL, BROADCAST, ON);
XENDPROCEDURE;        
X
XPROCEDURE enable_bell;
XSET (BELL, ALL      ,ON );
XENDPROCEDURE;
X
X
V!------------------------------------------------------------------------------
X-
XPROCEDURE my_undefined_key;
Xmessage ('');`009`009`009! this rings bell as long as broadcast is set = all
XENDPROCEDURE;
X                                      
XPROCEDURE one_map;`009`009! map text_buffer with USENET news to screen
XMAP(text_window, text_buffer);
Xupdate_banner;
XENDPROCEDURE;
X
XPROCEDURE two_map;`009`009! map subscribe to screen
X`009`009`009`009! allow arrows keys to select group
XMAP (text_window, subscribe);
XENDPROCEDURE;
X                                           
XPROCEDURE three_map;
XMAP (text_window, active);
XENDPROCEDURE; 
X
XPROCEDURE five_map;
XMAP (text_window, message_buffer);
XENDPROCEDURE;
X
XPROCEDURE six_map;
XMAP (text_window, ac_tmp);
XENDPROCEDURE; 
X
XPROCEDURE seven_map;
XMAP (text_window, sub_tmp);
XENDPROCEDURE; 
X
X
X
XPROCEDURE end_of_line
Xposition (search (LINE_END, FORWARD, EXACT));
XENDPROCEDURE;                    
X
X
XPROCEDURE begin_of_line;
Xposition (search (LINE_BEGIN, REVERSE, EXACT));
XENDPROCEDURE;        
X
X
XPROCEDURE save_mesg`009`009`009! write current message to disk
XLOCAL save_name;
Xsave_name := READ_LINE ('Save current message to file: ');
Xif length(save_name) = 0 then return(0); endif;
XWRITE_FILE (text_buffer, save_name);
Xmessage('file written');`009! add: check if written sucessfully
XENDPROCEDURE;
X            
X                                         
XPROCEDURE select_column_one
XLOCAL j1;   `009`009`009`009! returns column one as a string
Xposition (search (LINE_BEGIN, REVERSE, EXACT));
Xj1 := search (LINE_BEGIN & SCAN(' '),FORWARD);
XRETURN (SUBSTR(j1,1,999));
XENDPROCEDURE;
X                
X                   
XPROCEDURE select_column_two 
XLOCAL a, b, c, d;       ! returns column two as a string
X
Xposition (search (LINE_BEGIN, REVERSE, EXACT));
X
Xa  := current_line + ' ';
Xb  := INDEX  (a, ' ');
Xa  := SUBSTR (a, b+1, 999);
X
Xc  := INDEX  (a, ' ');
Xd  := SUBSTR (a, 1, c - 1);
X                            
XRETURN(SUBSTR(d,1,999));
XENDPROCEDURE;                                  
X                 
X
XPROCEDURE select_column_three
XLOCAL a, b, c, d, e; `009`009`009`009`009! returns column three as a string
X
Xposition (search (LINE_BEGIN, REVERSE, EXACT));`009`009! LINE ->> STRING
Xa  := current_line + ' ';
X
Xb  := INDEX  (a, ' ');
Xa  := SUBSTR (a, b+1, 999);
X
Xc  := INDEX  (a, ' ');
Xa  := SUBSTR (a, c+1, 999);
X                         
Xd  := INDEX  (a, ' ');`009`009`009! extract column three
Xe  := SUBSTR (a, 1, d-1);
X
XRETURN (SUBSTR(e,1,999));
XENDPROCEDURE;          
X
X     
XPROCEDURE replace_column_two (thing)
XLOCAL  a, aa, aaa, line, x3, b, c, d, thing1;
X
Xthing1 := STR(thing);`009`009`009! precede w/ 0's
XIF LENGTH(thing1) < 5 THEN thing1 := "0"+thing1; ENDIF;
XIF LENGTH(thing1) < 5 THEN thing1 := "0"+thing1; ENDIF;
XIF LENGTH(thing1) < 5 THEN thing1 := "0"+thing1; ENDIF;
XIF LENGTH(thing1) < 5 THEN thing1 := "0"+thing1; ENDIF;
XIF LENGTH(thing1) < 5 THEN thing1 := "0"+thing1; ENDIF;
X
Xposition (search (LINE_BEGIN, REVERSE, EXACT));       `009! LINE ->> STRING
Xa  := current_line + ' ';
X
Xb  := INDEX  (a, ' ');
Xaa  := SUBSTR (a, b+1, 999);
X
Xc  := INDEX  (aa, ' ');
Xaaa:= SUBSTR (aa, c, 999);
X
Xline := SUBSTR(a,1,b) + thing1 + aaa;
Xedit (line, TRIM_TRAILING);
Xposition (search (LINE_BEGIN, REVERSE, EXACT));
Xcopy_text(line); 
Xsplit_line;
Xerase_line;                            
Xmove_vertical (-1);
XENDPROCEDURE;                                  
X                                    
X                         
XPROCEDURE go_to_article
XLOCAL a1, numb , x;
X
Xa1 := READ_LINE ('Go to which article number: ');
Xif a1 = "" THEN return(0); ENDIF;
Xnumb := INT(a1);
Xif numb = 0 then return; endif;
X
Xx := mark(none);
Xposition(subscribe); 
Xreplace_column_two (numb); 
Xposition(x);
Xnext_news_message;
X
XENDPROCEDURE;
X
X
XPROCEDURE top_of_buf;
Xposition(beginning_of(current_buffer));
XENDPROCEDURE;
X           
X
XPROCEDURE bot_of_buf;
Xposition(end_of(current_buffer));
XENDPROCEDURE;
X            
X
Xprocedure author;
Xmessage("Written By Christopher Seline (11/Apr/88)");
Xmessage("SCS7317@oberlin.bitnet");
XENDPROCEDURE;
X
XPROCEDURE try;
Xmessage('try1');
X                       
XENDPROCEDURE;
X              
XPROCEDURE underline_line
XLOCAL r1,r2;
X! bug -- only underlines in one buffer at a time
Xposition (search (LINE_BEGIN, REVERSE, EXACT));
Xr1 := MARK (none);
Xposition (search (LINE_END, FORWARD, EXACT));
Xr2 := MARK (none);
X                
Xunderline_x2 := CREATE_RANGE (r1,r2,UNDERLINE);
Xr1 := 0; 
Xr2 := 0;             
XENDPROCEDURE;                                   
X
XPROCEDURE underline_subject_line
XLOCAL 
X   r1,r2,j3 ;
X        
Xj3 := mark (none);
Xr1 := search ('subject',FORWARD,NO_EXACT);
XIF r1 = 0 THEN return(0); ENDIF; !No Subject
Xposition (r1);
X
Xposition (search (LINE_BEGIN, REVERSE, EXACT));
Xr1 := MARK (none);
Xposition (search (LINE_END, FORWARD, EXACT));
Xr2 := MARK (none);
X
Xunderline_i1 := CREATE_RANGE (r1,r2,UNDERLINE);
Xr1 := 0; 
Xr2 := 0;             
X
Xposition (j3);
XENDPROCEDURE;
X
X
X
X
VPROCEDURE scroll_line_to(dest_line)`009`009`009`009! scrolls the screen so that
X the current line is at the line # specified by dest_line
VLOCAL old_position;`009`009`009`009`009`009! preserves the cursor position thro
Xugh the scroll
X    old_position := MARK(NONE);
X    SCROLL(CURRENT_WINDOW,
X           GET_INFO(CURRENT_WINDOW, "current_row")-dest_line);
X    POSITION(old_position);
XENDPROCEDURE;
X
X
X`012
V!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
X+++++++++++++++++++++++++++++++++++++++++++++++++
X!                                                     K E Y   B I N D I N G S
V!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
X+++++++++++++++++++++++++++++++++++++++++++++++++
X    
VSET(SELF_INSERT, "TPU$KEY_MAP_LIST", OFF);`009! make it so typing keys won't se
Xlf-insert
VSET(UNDEFINED_KEY, "TPU$KEY_MAP_LIST", "my_undefined_key");`009! and specify wh
Xat to do when an undefined key is pressed
XDEFINE_KEY("exit_news", CTRL_Z_KEY);`009`009! exit
XDEFINE_KEY("quit",KEY_NAME('q')); 
XDEFINE_KEY("author", KEY_NAME("A"));
XDEFINE_KEY("page_down", KP0);`009`009`009! page down
XDEFINE_KEY("page_up", PERIOD);`009`009`009! page up
XDEFINE_KEY("line_down", DOWN);`009`009`009! scroll down
XDEFINE_KEY("line_up", UP);`009`009`009! scroll up 
XDEFINE_KEY("go_to_article", KEY_NAME("#"));`009! goto article #
XDEFINE_KEY("go_to_group", KEY_NAME("G"));`009! Goto Group EXACT
XDEFINE_KEY("go_to_group_NOexact", KEY_NAME("g"));! Goto Group NOEXACT
XDEFINE_KEY("go_to_group_NOexact", PF1);`009`009! Goto Group NOEXACT
XDEFINE_KEY("next_group", KEY_NAME('N'));`009! next group
XDEFINE_KEY("next_group", COMMA        );`009! next group
XDEFINE_KEY("space_bar", KEY_NAME(" "));`009     `009! NEXT THING
XDEFINE_KEY("next_news_message", ENTER);
XDEFINE_KEY("next_news_message", KEY_NAME('n'));
XDEFINE_KEY("attach", KEY_NAME('P'));`009`009! PAUSE news
XDEFINE_KEY("attach", PF3          );
XDEFINE_KEY("catch_up",KEY_NAME('c'));  `009`009! mark group as read
XDEFINE_KEY("UN_catch_up",KEY_NAME('C'));`009`009! mark group as UNread
XDEFINE_KEY("keypad_help", PF2);
XDEFINE_KEY("news_help", KEY_NAME('?'));    
XDEFINE_KEY("news_help", KEY_NAME('h'));
XDEFINE_KEY ("one_map", KEY_NAME("1"));
XDEFINE_KEY ("two_map", KEY_NAME("2"));     
XDEFINE_KEY ("three_map", KEY_NAME("3"));   
XDEFINE_KEY ("five_map", KEY_NAME("5"));
XDEFINE_KEY ("six_map", KEY_NAME("6"));
XDEFINE_KEY ("seven_map", KEY_NAME("7"));
X
XDEFINE_KEY ("top_of_buf",KEY_NAME("<"));
XDEFINE_KEY ("bot_of_buf",KEY_NAME(">"));
XDEFINE_KEY ("save_mesg", KEY_NAME('s'));`009`009! save to disk
XDEFINE_KEY ("subscribe_proc", KEY_NAME('U'));`009`009! UNunsubscribe
XDEFINE_KEY ("unsubscribe", KEY_NAME('u'));
XDEFINE_KEY ("refresh",   CTRL_L_KEY);
XDEFINE_KEY ("refresh",   CTRL_R_KEY);
XDEFINE_KEY ("refresh",   CTRL_W_KEY);
X                               
X! for debugging
X
XDEFINE_KEY ("try"              , KEY_NAME("~"));
X                                         
X
X
V!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
X+++++++++++++++++++++++++++++++++++++++++++++++++
X
X!SAVE("SYS$LOGIN:news");
XSAVE("students:[scs7317.trans]news_inprog");
XQUIT;
X
$ GoSub Convert_File
$ Exit
