;OFFLINE.WAS v1.00(beta)   Off-line News reader.

;*****************************************************************************
;* Written by:  Symantec ASPECT Assist                                       *
;*                                                                           *                                                                             
;* This script file will give the user the option of either capturing data   *
;* in half hour increments, or in 24 hour increments. The Capture file will  *
;* close after a predefined period of inactivity on the port.                *
;*                                                                           *
;* This ASPECT script is intended only as a sample of ASPECT programming.    *
;* Symantec makes no warranty of any kind, express or implied, including     *
;* without limitation, any warranties of merchantability and/or fitness      *
;* for a particular purpose.  Use of this program is at your own risk.       *
;*                                                                           *
;* Technical Support is not provided on this script.                         *                                                                          *
;*****************************************************************************

;*****************************************************************************

;*****************************************************************************
;*   MACRO DEFINITIONS                                                       *
;*****************************************************************************

#define FID_PWNEWSRC 3                 
#define FID_GRPLST 4                  
#define FID_READLIST 11               
#define FID_LISTWRITE 7
#define FID_LISTREAD 0
#define FID_CONTROL 15
#define FID_ARTICLE 5
#define FID_SUBJECT 25
#define FID_FILELIST 30
#define FID_SUBLIST 35
#define FID_CHCEFILE 40
#define FID_SAVEFILE 55
#define FID_BODYTEMP 60
#define FID_REPLYFILE 65
#define FID_INI 70
#define FID_SIGFILE 75
#define FID_EDITLIST 80



;*****************************************************************************
;*   INCLUDED FILES                                                          *
;*   This script requires the programs listed in this section to compile.    *
;*****************************************************************************

#include "RSETUP.INC"
#include "BROWSE.INC"
#include "SUBJECT.INC"
#include "NEWSEDIT.INC"



;*****************************************************************************
;*   GLOBAL VARIABLES                                                        *
;*****************************************************************************


long FilePointer                       ;Postition of entries in PWNEWSRC.
string EndList                         ;Last entry in the current article list.
string StartConnect                    ;Data connection at startup.
string ArticleList                     ;List of article numbers for group.
string FileRead                        ;Current file for writing data.
string PostChoice                      ;Name of group chosen for posting.
integer NoRXData                       ;High when not receiving data.
integer StatusID                       ;Windows ID of the status dialog.
integer Connecting                     ;High while connecting to server.
integer IntBlockCount                  ;Number of 128 byte blocks per article.
integer StartMode                      ;Mode of PROCOMM on startup.
integer StartDuplex                    ;Duplex setting for the port at startup.
integer Continue                       ;Controller for main loop.
integer Waiting                        ;Counter to time the start of SUPERTCP.




proc Main

;*****************************************************************************
;*                                                                           *
;* MAIN                                                                      *
;* The Main procedure makes sure that the directories needed for this script *
;* are in place, then cycles through the various routines used for getting,  *
;* reading, and (eventually) replying to messages from the News Server.      *
;*                                                                           *
;* Calls:  CleanUp, NewsQueue, Selection, Browse, RSetup, PostSelect,        *
;*         Delivery                                                          *
;* Modifies globals: StartMode, StartConnect, NewsIn, NewsOut, StartDuplex,  *
;*                   Continue                                                *
;*                                                                           *
;*****************************************************************************

   string HomePath                     ;PW home directory
   string Banner                       ;Full path to Banner wmf.
   integer MainLoop                    ;Controller for Main loop.
   integer MainDialog                  ;Controller for dlgevent loop.
   integer Event                       ;Choice from Main dialog.
   integer DlgID                       ;Windows ID of dialog box.
   
   set aspect errormsg OFF
   HomePath = $PWLOCALPATH             ;Get the PROWIN3 local directory.
   StartMode = $PWMODE                 ;Get the starting mode of PW3.
   fetch modem connection StartConnect ;Grab the startup data connection.
   strfmt NewsIn "%s%s" HomePath "`\NEWSIN"
                                       ;Format the News input directory.
   strfmt NewsOut "%s%s" HomePath "`\NEWSOUT"
                                       ;Format the News output directory.
   strfmt Banner "%s`\ASPECT`\SERVICE`\BANNER.WMF" HomePath
   chdir NewsIn                        ;See if the input directory exists.
   if FAILURE                          ;If not,
      mkdir NewsIn                     ;Create it.
   else                                ;If so,
      chdir HomePath                   ;Change back to the default path.
   endif
   chdir NewsOut                       ;See if the output directory exists.
   if FAILURE                          ;If not,
      mkdir NewsOut                    ;Create it.
   else                                ;If so,
      chdir HomePath                   ;Change back to the default path.
   endif
   fetch port duplex StartDuplex       ;Get the current port duplex setting.
   set port duplex FULL                ;Make sure that commands will not be
                                       ; echoed back to the screen.
   when USEREXIT call CleanUp          ;Restore startup defaults on exit.
   MainLoop = 1
   while MainLoop
      Continue = 1
      dialogbox 100 145 30 232 265 7 "PROCOMM PLUS  Off-line News Reader v1.0"
         metafile 1 6 12 219 114 Banner
         text 2 39 132 152 8 "PROCOMM PLUS Off-line News Reader v1.0" LEFT
         text 3 28 142 174 8 "Copyright (C) 1996 DATASTORM Technologies, Inc." \
         LEFT
         pushbutton 4 22 154 184 14 "Download Latest Articles" DEFAULT
         pushbutton 5 22 168 184 14 "View Previously Downloaded Articles"
         pushbutton 6 22 237 184 14 "Get On With Your Life"
         pushbutton 7 22 224 184 14 "Setup Reply/Post Options"
         pushbutton 8 22 182 184 14 "Write A New Article"
         pushbutton 9 22 209 184 14 "Post Articles/Deliver Mail"
         pushbutton 10 22 196 184 13 "Edit Posts/Replies"
      enddialog
      dlgwin 100 DlgID
      MainDialog = 1
      while MainDialog
         dlgevent 100 Event                                
         switch Event
            case 4
               dlgdestroy 100 CANCEL
               MainDialog = 0
               NewsQueue()             ;Fetch the current list of groups.
               if Continue
                  Selection()          ;Ask the user which groups need to be
                                       ; accessed during this session.
                  if Continue
                     Browse()          ;Read news files.
                  endif
               endif
            endcase
            case 5
               dlgdestroy 100 OK       
               MainDialog = 0          ;Head straight to the Browse procedure.
               Browse()
            endcase
            case 6
               dlgdestroy 100 OK       ;Exit the script.
               MainDialog = 0
               MainLoop = 0
            endcase
            case 7
               dlgdestroy 100 CANCEL   ;Call the setup routine.
               MainDialog = 0
               RSetup()
            endcase
            case 8
               dlgdestroy 100 CANCEL
               MainDialog = 0
               NewsQueue()             ;Get a list of newsgroups.
               if Continue             
                  PostSelect()         ;Start a new thread.
               endif
            endcase
            case 9
               dlgdestroy 100 CANCEL
               MainDialog = 0
               Delivery()
            endcase
            case 10
               dlgdestroy 100 CANCEL
               MainDialog = 0
               NewsEdit()
            endcase
            default
               winexists DlgID         ;Exit if the Win95 X is selected.
               if FAILURE
                  MainDialog = 0
                  MainLoop = 0
               endif
            endcase
         endswitch
      endwhile
   endwhile
   Cleanup()                           ;Restore startup defaults.
endproc



proc NewsQueue

;*****************************************************************************
;*                                                                           *
;* NEWSQUEUE                                                                 *
;* Calls GetQueue to grab all News-class entries from the Connection         * 
;* Directory if a NewsGroup list is not already present.  If a listing is    *
;* already present, it calls CheckQueue to see if any new entries are        *
;* present.  It then calls Selection to allow the user to choose which       *
;* groups are going to be read during this session.                          *
;*                                                                           *
;* Calls: GetQueue, CheckQueue, Selection, CleanUp                           *
;* Called by: Main                                                           *
;* Modifies globals: NewsIn                                                  *
;*                                                                           *
;*****************************************************************************

   string Queue                        ;Path and name of Queue file
   string GroupList                    ;File containing just list of groups.
   string CurrentConnDir               ;Name of the Connection Directory 
                                       ; currently being used.
   string Message                      ;Text line from Message dialog.
   string NewsStamp                    ;Registers the conditions under which
                                       ; the PWNEWSRC was created.
   long ConnDirSize                    ;Size of the current Connection
                                       ; Directory when the PWNEWSRC is
                                       ; first created.
   long QueueSize                      ;Size of the PWNEWSRC.
   integer QueueFile                   ;High if Queue file already exists.
   integer EntryCount                  ;Number of entries in the current 
                                       ; directory.
   integer Choice                      ;User choice from message dialogs.
   
   strfmt Queue "%s%s" NewsIn "`\PWNEWSRC"
                                       ;Format the name of the PWNEWSRC file.
   strfmt GroupList "%s%s" NewsIn "`\GRPLIST"
                                       ;Format the name of the list file.
   isfile Queue QueueFile              ;Check to see if a PWNEWSRC exists.
   if SUCCESS
      fileget Queue SIZE QueueSize     ;Get the size of the PWNEWSRC.
      if QueueSize == 0                ;If an aborted run of this script left
                                       ; an empty PWNEWSRC on the hard drive,
         QueueFile = 0                 ;Tell the script that the file was not
                                       ; found.
      endif
   endif
   fopen FID_PWNEWSRC Queue READWRITE             ;Try to open the group list.
   while FAILURE
      Choice = 8
      strfmt Message "Unable to open file:`r`n`r`n%s" Queue
      sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
      if Choice != 8
         CleanUp()
      endif
      fopen FID_PWNEWSRC Queue READWRITE
   endwhile
   
   fopen FID_GRPLST GroupList READWRITE
                                       ;If a list file can be opened,
   while FAILURE
      Choice = 8
      strfmt Message "Unable to open file:`r`n`r`n%s" GroupList
      sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
      if Choice != 8
         CleanUp()
      endif
      fopen FID_PWNEWSRC Queue READWRITE
   endwhile
   
   if ! QueueFile                      ;If this is a new list,

      CurrentConnDir = $DDIRFNAME
                                       ;Get the name of the current
                                       ; Connection Directory.
      fileget CurrentConnDir SIZE ConnDirSize
      dialcount NEWS EntryCount
                                       ;Get the size of the current Directory.
      if EntryCount == 0         ;If there are no News-class entries,
         errormsg "There are no News-class entries in the current \
Connection Directory!!!`r`n`r`nPlease remedy this situation!!!"
         CleanUp()
      endif
      strfmt NewsStamp "%s%li000%03i`r`n" CurrentConnDir\
 ConnDirSize EntryCount
                                       ;Format the NewsStamp for the PWNEWSRC.
      fputs FID_PWNEWSRC NewsStamp                ;Write the NewsStamp to the PWNEWSRC.
      GetQueue()                       ;Get the PWNEWSRC and GRPLIST.
      fclose FID_GRPLST
   else                                ;If this is an old list,
      CheckQueue()                     ;See if any new entries have been made.
      fclose FID_GRPLST 
   endif
endproc



proc GetQueue

;*****************************************************************************
;*                                                                           *
;* GETQUEUE  	                                                             *
;* Grabs all News-class entries from the Connection Directory, putting them  *
;* into the PWNEWSRC file for later reference.                               *
;*                                                                           *
;* Calls: <none>                                                             *
;* Called by: NewsQueue                                                      *
;* Modifies globals: <none>                                                  *
;*                                                                           *
;*****************************************************************************

   integer GroupCount                  ;Number of NEWS-class entries in the
                                       ; Connection Directory.
   integer StampLength                 ;Length of NewsStamp.
   integer GroupLoop                   ;Loop controller.
   integer ListEnd                     ;FEOF test for group list.
   integer Searching                   ;Verification loop controller.
   integer Found                       ;Search results.
   integer TokenLoop                   ;Loop for STRTOK operation.
   integer CompareGroup                ;Result of group-name comparison.
   integer EntryCount = 0              ;Initialize count of PWNEWSRC entries.
   integer NewCount                    ;New total of entries for PWNEWSRC.
   integer EntryLength                 ;Length of group from Directory.
   integer NewsLength                  ;Length of group from GRPLIST.
   long DirSize                        ;Size of the current Directory.
   string SearchString                 ;Comparison string
   string EntryName                    ;Name of Connection Directory entry.
   string GroupName                    ;Contains the group name contained in
                                       ; the current Connection Directory entry.
   string AddGroup                     ;Full entry for the PWNEWSRC file.
   string NewsStamp                    ;PWNEWSRC creation stamp.
   string StampField[4]                ;Array for the fields of NewsStamp
   string DirName                      ;Name of the current Directory.
   
   dialcount NEWS GroupCount           ;See how many entries there are.
   GroupCount -= 1                     ;Make GroupCount zero-indexed.
   for GroupLoop = 0 upto GroupCount
                                       ;Do a loop based on GroupCount
      dialname NEWS GroupLoop EntryName
                                       ;Get the name of the current entry.
      set dialentry access NEWS EntryName
                                       ;Get access to that entry.
      fetch dialentry ipaddress GroupName
                                       ;Take the groupnames from the Directory,
      strlwr GroupName                 ;Group names are case-sensitive, and need
                                       ; to be lower case.
      strlen GroupName EntryLength     ;Get the length of the Directory group.
      Searching = 1                    ;Initialize search controller.
      Found = 0                        ;Clear the locater flag.
      rewind FID_GRPLST                         ;Set list pointer to beginning of file.
      while Searching                  ;Start the search loop.
         feof FID_GRPLST ListEnd                ;Check for end of file.
         if ListEnd   
            Searching = 0              ;Exit loop if eof.
         else
            fgets FID_GRPLST SearchString       ;Grab the first group from the existing
                                       ; list of groups.
            strlen SearchString NewsLength
                                       ;Get the length of the News group.
            if NewsLength == EntryLength
                                       ;If the names are the same length,
               strcmp GroupName SearchString CompareGroup
                                       ;See if they are the same name.
               if CompareGroup == 0    ;If the group name was found,
                  Found = 1            ;Set Found flag.
                  Searching = 0        ;Exit loop.
               endif
            endif
         endif
      endwhile
      if ! Found                       ;If this is a new entry,  
         strfmt AddGroup "NEWS%04i%s`r`n" GroupLoop GroupName
                                       ;Format the PWNEWSRC entry.
         strcat GroupName "`r`n"       ;Add a CR/LF pair.
         fputs FID_PWNEWSRC AddGroup              ;Write the PWNEWSRC entry.
         fputs FID_GRPLST GroupName             ;Write the group name to the group list.
         EntryCount += 1               ;Add one to the entry count.
      endif
      set dialentry access OFF         ;Close Connection Directory access.
   endfor
   rewind FID_PWNEWSRC                            ;Set PWNEWSRC pointer to SOF.
   fgets FID_PWNEWSRC NewsStamp                   ;Grab the current NewsStamp.
   strlen NewsStamp StampLength        ;Get the length of the NewsStamp.
   for TokenLoop = 0 upto 3
      strtok StampField[TokenLoop] NewsStamp ""
   endfor
   atoi StampField[2] NewCount         ;Convert count to integer format.
   NewCount += EntryCount              ;Get new count total.
   GroupCount += 1                     ;GroupCount no longer zero-referenced.
   DirName = $DDIRFNAME
   fileget DirName SIZE DirSize
   strfmt NewsStamp "%s%li%03i%03i`r`n" StampField[0] DirSize NewCount\
 GroupCount 
                                       ;Format the new NewsStamp. 
   rewind FID_PWNEWSRC                            ;Go back to beginning of PWNEWSRC.
   fdelblock FID_PWNEWSRC StampLength             ;Get rid of the old stamp.
   strlen NewsStamp StampLength        ;Get the length of the new stamp.
   finsblock FID_PWNEWSRC StampLength             ;Put in the new stamp.
   fputs FID_PWNEWSRC NewsStamp
endproc



proc CheckQueue

;*****************************************************************************
;*                                                                           *
;* CHECKQUEUE  	                                                             *
;* Checks the Connection Directory to see if any new entries are present.    *
;* This procedure will add any new entries to the PWNEWSRC file.             *
;*                                                                           *
;* Calls:  NewDirectory, NewGroups                                           *
;* Called by: NewsQueue                                                      *
;* Modifies globals: <none>                                                  *
;*                                                                           *
;*****************************************************************************
   
   string NewsStamp                    ;Creation stamp taken from the PWNEWSRC.
   string CurrentConnDir               ;Name of the current Connection 
                                       ; Directory.
   string StampField[4]                ;Fields from NewsStamp.
   long OldDirSize                     ;Size of Directory in NewsStamp.
   long NewDirSize                     ;Size of current Directory.
   integer StampLength                 ;Length of the NewsStamp string.
   integer CountLength                 ;Length of last NewsStamp token.
   integer TokenLoop                   ;Loop for STRTOK operation.
   integer OldEntryCount               ;Number of entries from NewsStamp.
   integer EntryCount                  ;Number of entries in the Directory.
   integer ChangeName                  ;Result of strcmp of Directory names.
   integer ChangeSize                  ;Result of comparison of Directory sizes.
   integer ChangeCount                 ;Result of entry count comparison.
   
   rewind FID_PWNEWSRC                            ;Shouldn't be anywhere else at this 
                                       ; point, but make sure the pointer for
                                       ; the PWNEWSRC is at start of file.
   fgets FID_PWNEWSRC NewsStamp                   ;Pull the NewsStamp from the PWNEWSRC.
   strlen NewsStamp StampLength        ;Get the length of the NewsStamp string.
   for TokenLoop = 0 upto 3            ;Initialize STRTOK loop.
      strtok StampField[TokenLoop] NewsStamp ""
   endfor
   strlen StampField[3] CountLength    ;Get the length of the last token.
   CountLength -= 2                    ;Take two off of that length.
   substr StampField[2] StampField[2] 0 CountLength
                                       ;Strip CR/LF from last token.
   dialcount NEWS EntryCount           ;Get current number of entries.
   atoi StampField[3] OldEntryCount    ;Change number of entries into integer.
   CurrentConnDir = $DDIRFNAME         ;Grab the name of the current Directory.
   fileget CurrentConnDir Size NewDirSize
                                       ;Get the size of the current Directory.
   atol StampField[1] OldDirSize       ;Convert from ASCII to long value.
   stricmp CurrentConnDir StampField[0] ChangeName
                                       ;Compare the two Directory names.
   ChangeSize = NewDirSize - OldDirSize
                                       ;Compare the two file sizes.
   ChangeCount = EntryCount - OldEntryCount
                                       ;Compare the number of entries.
   if ChangeName != 0
      NewDirectory()
   elseif (ChangeCount != 0) || (ChangeSize != 0)
      NewGroups()
   endif
endproc



proc NewDirectory

;*****************************************************************************
;*                                                                           *
;* NEWDIRECTORY                                                              *
;* Called when a Connection Directory other than the one originally used for *
;* the PWNEWSRC file is the current Connection Directory.                    *
;*                                                                           *
;* Calls: CleanUp, NewsQueue                                                 *
;* Called by: CheckQueue                                                     *
;* Modifies globals:  NewsIn                                                 *
;*                                                                           *
;*****************************************************************************

   integer UserChoice                  ;Object chosen from dialog box.
   string HomePath                     ;Home directory of PROWIN3.
   string DosCommand                   ;Formatted DOS command.
   integer DosTask                     ;Task ID of DOS window.
   
   sdlgmsgbox "Current Connection Directory" "The current Connection Directory\
 is not the one that was used`r`nfor your current News files.  Do you want to\
 use the current `r`nConnection Directory to download your News groups?`r`n`r`n\
          (All current files will be lost if you say YES)" QUESTION\
 YESNOCANCEL UserChoice                ;Show dialog box for user decision.
 
   switch UserChoice                   ;See which button was pressed.
      case 2                           ;Exit on CANCEL.
         CleanUp()
      endcase
      case 6                           ;Wipe all files and start over for YES.
         fclose FID_PWNEWSRC
         HomePath = $PWLOCALPATH
         chdir HomePath
         strfmt DosCommand "deltree /Y %s`\NEWSIN"
         dos DosCommand HIDDEN DosTask
         while taskexists DosTask
            yield
         endwhile
         mkdir NewsIn
         chdir NewsIn
         NewsQueue()
      endcase
      case 7                           ;Use the current files if NO was chosen.
      endcase
   endswitch 
endproc


  
proc NewGroups

;*****************************************************************************
;*                                                                           *
;* NEWGROUPS  	                                                             *
;* Called when the current Connection Directory has a different size than    *
;* it did when creating the PWNEWSRC file.                                   *
;*                                                                           *
;* Calls: CleanUp, DeleteList, AddList, NewList                              *
;* Called by: CheckQueue                                                     *
;* Modifies globals: <none>                                                  *
;*                                                                           *
;*****************************************************************************
  
   integer UserChoice                  ;Choice from the dialog box.
   
   sdlgmsgbox "Connection Directory" "The contents of your Connection Directory\
 have changed.`r`nThis may or may not have affected your News-class entries.\
`r`nWould you like to update your current list?" QUESTION YESNOCANCEL UserChoice  
                                       ;Present user with list of options.
   switch UserChoice                   ;See which button was pressed.
      case 2                           ;Exit on CANCEL.
         CleanUp()               
      endcase
      case 6                           ;Update files on YES.
         DeleteList()
         AddList()
         NewList()
      endcase
      case 7                           ;Use current setup on NO.
      endcase
   endswitch
   NewList()
endproc



proc AddList

;*****************************************************************************
;*                                                                           *
;* ADDLIST                                                                   *
;* Adds new entries to the list of groups that can be read.                  *
;*                                                                           *
;* Calls:  CleanUp                                                           *
;* Called by: CheckQueue                                                     *
;* Modifies globals: <none>                                                  *
;*                                                                           *
;*****************************************************************************
 
   long DirSize                        ;New Directory size for the NewsStamp.
   string NewsStamp                    ;Creation stamp of the PWNEWSRC file.
   string PWNEWSRCField[3]             ;Array for STRTOK operations.
   string StampField[4]                ;Array for STRTOK on NewsStamp.
   string NewEntry                     ;New entry for PWNEWSRC.
   string NewsIndex                    ;Index from PWNEWSRC.
   string ReadPWNEWSRC                 ;String read from the PWNEWSRC file.
   string EntryName                    ;Name of Connection Directory entry.
   string GroupName                    ;Contains the group name contained in
                                       ; the current Connection Directory entry.
   string Index                        ;Numerical index for PWNEWSRC entries.
   string CurrentConDir                ;Name and path of current connection 
                                       ; directory.
   integer GroupCount                  ;Number of NEWS-class entries in the
                                       ; Connection Directory.
   integer Searching                   ;Loop controller.
   integer GroupLoop                   ;Loop controller.
   integer EntryLoop                   ;Loop controller.
   integer TokenLoop                   ;Loop controller.
   integer Extension                   ;Numerical index for PWNEWSRC entries.
   integer Found                       ;High if group is found in PWNEWSRC.
   integer GroupCompare                ;Result of group name comparisons.
   integer EndSearch                   ;Goes high to exit search loop.
   integer StampLength                 ;Length of old news stamp.
   integer StampCount                  ;Directory count in PWNEWSRC.
   integer EntryCount                  ;Count of PWNEWSRC entries in NewsStamp.
   integer SameIndex                   ;Comparison of index strings.
   integer NewStampLength              ;Length of new news stamp.
   integer AddCount = 0                ;Number of new groups added.
   integer Group1Length                ;Length of group name in Directory.
   integer Group2Length                ;Length of group name in PWNEWSRC.
   
   dialcount NEWS GroupCount           ;See how many entries there are.
   StampCount = GroupCount             ;Hold on to the count of entries.
   CurrentConDir = $DDIRFNAME          ;Grab the name of the current Directory.
   fileget CurrentConDir SIZE DirSize  ;Get the size of the Directory. 
   if GroupCount == 0
      errormsg "Your current Connection Directory does not contain any`r`n\
News-class entries!  Please remedy this situation."
                                       ;Error and exit if News empty.
      Cleanup()
   endif
   GroupCount -=1                      ;Make GroupCount zero-referenced.
   for GroupLoop = 0 upto GroupCount
                                       ;Do a loop based on GroupCount
      dialname NEWS GroupLoop EntryName
                                       ;Get the name of the current entry.
      set dialentry access NEWS EntryName
                                       ;Get access to that entry.
      fetch dialentry ipaddress GroupName
                                       ;Take the groupnames from the Directory,
      strlwr GroupName                 ;Group names are case-sensitive, and need
                                       ; to be lower case.
      strlen GroupName Group1Length    ;Get the length of the group name.
      rewind FID_PWNEWSRC                         ;Make sure that the PWNEWSRC is at the 
                                       ; beginning of the file.
      fgets FID_PWNEWSRC NewsStamp                ;Pull the NewsStamp out of the file. 
      Searching = 1                    ;Initialize the secondary loop. 
      Found = 0                        ;Set the flag to 'not found'.
      while Searching             
         fgets FID_PWNEWSRC ReadPWNEWSRC
                                       ;Pull out the next entry in the 
                                       ; PWNEWSRC.
         for EntryLoop = 0 upto 2      ;Initialize STRTOK loop.
            strtok PWNEWSRCField[EntryLoop] ReadPWNEWSRC ""
         endfor
         strlen PWNEWSRCField[1] Group2Length
         if Group1Length == Group2Length
            strcmp PWNEWSRCField[1] GroupName GroupCompare
                                       ;Compare the two group names.
            if GroupCompare == 0       ;If the names are the same,
               Found = 1               ;Indicate that the name was found.
               Searching = 0           ;Exit the search loop.
            endif
         endif
         feof FID_PWNEWSRC EndSearch   ;Check for the end of the PWNEWSRC file.
         if EndSearch                  ;If the end of the file has been reached,
            Searching = 0              ; exit the search loop.
         endif
      endwhile
      if ! Found                       ;If a matching entry was not found,
         Searching = 1                 ;Initialize the search loop.
         Extension = 0                 ;Set the folder extension.
         while Searching
            rewind FID_PWNEWSRC        ;Back to sof for PWNEWSRC.
            fgets FID_PWNEWSRC NewsStamp
                                       ;Get the PWNEWSRC creation stamp.
            strlen NewsStamp StampLength
                                       ;Get the length of the stamp.
            for TokenLoop = 0 upto 3   ;Parse the NewsStamp into tokens.
               strtok StampField[TokenLoop] NewsStamp ""
            endfor
            atoi StampField[2] EntryCount
                                       ;Get the count of PWNEWSRC entries.
            strfmt Index "NEWS%04i" Extension
                                       ;Set the first index name.
            for EntryLoop = 1 upto EntryCount
                                       ;Loop through the PWNEWSRC.
               fgets FID_PWNEWSRC ReadPWNEWSRC    ;Get the next PWNEWSRC entry.
               strtok NewsIndex ReadPWNEWSRC ""
                                       ;Get the index for that entry.
               strcmp Index NewsIndex SameIndex
                                       ;See if it is the same as Index.
               if SameIndex == 0       ;If they are the same,
                  Extension ++         ;Add one to the extension and try again.
                  exitfor
               endif
            endfor
            if (SameIndex != 0)        ;If no matching Index was found,
               Searching = 0           ;Exit the main loop.
            endif
         endwhile
         strfmt NewEntry "%s%s`r`n" Index GroupName
                                       ;Format the new entry for the PWNEWSRC. 
         fseek FID_PWNEWSRC 0 2                   ;Go to the end of the PWNEWSRC.
         fputs FID_PWNEWSRC NewEntry              ;Insert the new entry
         rewind FID_PWNEWSRC                      ;Go to the start of the PWNEWSRC.
         EntryCount ++                 ;Add one to the count of PWNEWSRC
                                       ; PWNEWSRC entries.
         strfmt NewsStamp "%s%li%03i%03i`r`n" StampField[0] DirSize\
 EntryCount StampCount                 ;Format updated NewsStamp
         strlen NewsStamp NewStampLength
                                       ;Get the length of the new stamp.
         fdelblock FID_PWNEWSRC StampLength       ;Wipe out the old NewsStamp
         finsblock FID_PWNEWSRC NewStampLength    ;Insert the new stamp.
         fputs FID_PWNEWSRC NewsStamp
      endif
      set dialentry access OFF         ;Close Connection Directory access.
   endfor
endproc



proc DeleteList

;*****************************************************************************
;*                                                                           *
;* DELETELIST                                                                *
;* Entries that have been removed from the Connection Directory are removed  *
;* from the list of NewsGroups that can be read.                             *
;*                                                                           *
;* Calls:  <none>                                                            *
;* Called by: NewGroups                                                      *
;* Modifies globals:  NewsIn                                                 *
;*                                                                           *
;*****************************************************************************

   integer GroupCount                  ;Number of NEWS-class entries in the
                                       ; Connection Directory.
   integer EntryLength                 ;Length of entry pulled from PWNEWSRC.
   integer Searching                   ;Loop controller.
   integer TokenLoop                   ;Loop controller.
   integer EntryLoop                   ;Loop controller.
   integer Found                       ;High if group is found in Directory.
   integer Group1Length                ;Length of group name in Directory.
   integer Group2Length                ;Length of group name in PWNEWSRC.
   integer GroupCompare                ;Result of group name comparisons.
   integer StampLength                 ;Length of old news stamp.
   integer OldCount                    ;Number of entries in PWNEWSRC.
   integer NewCount                    ;New total of entries.
   integer DosTask                     ;Task ID for DOS window.
   integer NewStampLength              ;Length of new news stamp.
   integer AddCount = 0                ;Number of new groups added.
   long NewSize                        ;New Directory size for the NewsStamp.
   long EntryStart                     ;Start of an entry in the PWNEWSRC.
   string NewsStamp                    ;Creation stamp of the PWNEWSRC file.
   string ReadPWNEWSRC                 ;String read from the PWNEWSRC file.
   string EntryName                    ;Name of Connection Directory entry.
   string StampField[4]                ;Tokens from NewsStamp
   string PWNEWSRCField[3]             ;Tokens from PWNEWSRC entries.
   string GroupName                    ;Contains the group name contained in
                                       ; the current Connection Directory entry.
   string DelPath                      ;Path of current entry files.
   string DosCommand                   ;DelTree statement for DOS.
   string CurrentConDir                ;Name and path of current connection 
                                       ; directory.
   

   rewind FID_PWNEWSRC                 ;Set pointer to start of file.
   fgets FID_PWNEWSRC NewsStamp        ;Pull the NewsStamp out of the file.
   strlen NewsStamp StampLength
   for TokenLoop = 0 upto 3            ;Start the STRTOK loop.
      strtok StampField[TokenLoop] NewsStamp ""
                                       ;Break up the NewsStamp into tokens.
   endfor
   atoi StampField[2] OldCount         ;Convert the entry count to integer.
   dialcount NEWS GroupCount           ;Get number of News-Class entries.
   GroupCount -= 1                     ;Make GroupCount zero-referenced.
   for EntryLoop = 1 upto OldCount     ;Loop through the PWNEWSRC.
      ftell FID_PWNEWSRC EntryStart    ;Get start position of next entry.
      fgets FID_PWNEWSRC ReadPWNEWSRC  ;Grab next entry in PWNEWSRC.
      strlen ReadPWNEWSRC EntryLength  ;Get length of this entry.     
      for TokenLoop = 0 upto 2         ;Start STRTOK loop.
         strtok PWNEWSRCField[TokenLoop] ReadPWNEWSRC ""
                                       ;Break up the entry into tokens.
      endfor
      Found = 0                        ;Set search to "not found".
      for Searching = 0 upto GroupCount
                                       ;Loop throught the Connection Directory.
         dialname NEWS Searching EntryName
                                       ;Get the name of the next entry.
         set dialentry access NEWS EntryName
                                       ;Gain access to the next entry.
         fetch dialentry ipaddress GroupName
                                       ;Get the group name associated with this
                                       ; Connection Directory entry.
         strlwr GroupName              ;Set name to lower case.
         strlen GroupName Group1Length ;Get the length of the first name.
         strlen PWNEWSRCField[1] Group2Length
                                       ;Get the length of the second name.
         if Group1Length == Group2Length
            strcmp GroupName PWNEWSRCField[1] GroupCompare
                                       ;Compare the two group names.
            if GroupCompare == 0
               Found = 1
               exitfor
            endif
         endif
         set dialentry access OFF      ;Close access to the current entry.
      endfor
      if ! Found
         AddCount -= 1
         fseek FID_PWNEWSRC EntryStart 0          
                                       ;Go to start of currentPWNEWSRC entry.
         fdelblock FID_PWNEWSRC EntryLength
                                       ;Wipe the current entry.
         strfmt DelPath "%s`\%s" NewsIn PWNEWSRCField[0]
                                       ;Format the path to be deleted.
         chdir DelPath                 ;See if the path actually exists.
         if SUCCESS                    ;If the path exists,
            chdir NewsIn               ;Change back to the NEWSIN directory.
            strfmt DosCommand "DELTREE /Y %s" DelPath
                                       ;Format a DELTREE command.
            dos DosCommand HIDDEN DosTask
                                       ;Delete the folder in question.
            while taskexists DosTask   ;Loop while folder is being 
                                       ; deleted.
               yield
            endwhile
         endif
      endif
   endfor
   NewCount = OldCount + AddCount      ;Take the deleted folder off of the 
                                       ; count of PWNEWSRC entries.
   CurrentConDir = $DDIRFNAME          ;Get the name of the current directory.
   fileget CurrentConDir SIZE NewSize  ;Get the size of the current directory.
   GroupCount += 1                     ;GroupCount no longer zero-referenced.
   strfmt NewsStamp "%s%li%03i%03i`r`n" CurrentConDir NewSize NewCount\
 GroupCount                            ;Format the new NewsStamp.
   strlen NewsStamp NewStampLength     ;Get the length of the new NewsStamp.
   rewind FID_PWNEWSRC                 ;Go to the start of the PWNEWSRC.
   fdelblock FID_PWNEWSRC StampLength  ;Delete the old NewsStamp.
   finsblock FID_PWNEWSRC NewStampLength          
                                       ;Insert the new NewsStamp.
   fputs FID_PWNEWSRC NewsStamp
endproc



proc NewList

;*****************************************************************************
;*                                                                           *
;* NEWLIST  	                                                             *
;* Called when the PWNEWSRC file has changed, and a new list of news groups  *
;* is needed for the user.                                                   *
;*                                                                           *
;* Calls:  CleanUp                                                           *
;* Called by: NewGroups                                                      *
;* Modifies globals: NewsIn                                                  *
;*                                                                           *
;*****************************************************************************

   integer TokenLoop                   ;Loop for STRTOK on NewsStamp
   integer ListLoop                    ;Loop for writing new group list.
   integer EntryCount                  ;Number of entries in PWNEWSRC.
   integer EntryLoop                   ;Loop for STRTOK on PWNEWSRC entries.
   integer Choice                      ;User choice from message dialog.
   string StampField[4]                ;Array for STRTOK on NewsStamp.
   string ReadPWNEWSRC                 ;String for data from PWNEWSRC.
   string NewsStamp                    ;Creation stamp from PWNEWSRC.
   string GroupList                    ;Path to list of groups.
   string NewsEntry[3]                 ;Array for STRTOK
   string Message                      ;Text field of message dialog.
   
   fclose FID_GRPLST                   ;Close the old group list.
   strfmt GroupList "%s`\GRPLIST" NewsIn 
                                       ;Format the path and name of the list.
   fopen FID_GRPLST GroupList CREATE   ;Wipe the old list by creating it again.
   while FAILURE
      Choice = 8
      strfmt Message "Unable to open file:`r`n`r`n%s" GroupList
      sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
      if Choice != 4
         CleanUp()
      endif
      fopen FID_GRPLST GroupList CREATE
   endwhile
   
   rewind FID_PWNEWSRC                 ;Set PWNEWSRC pointer to start of file.
   fgets FID_PWNEWSRC NewsStamp        ;Grab the news stamp.
   for TokenLoop = 0 upto 3            ;Parse the stamp into tokens.
      strtok StampField[TokenLoop] NewsStamp ""
   endfor
   atoi StampField[2] EntryCount       ;Get the count of PWNEWSRC entries.
   for ListLoop = 1 upto EntryCount    ;Loop through the number of entries.
      fgets FID_PWNEWSRC ReadPWNEWSRC             ;Grab the next PWNEWSRC entry.
      for EntryLoop = 0 upto 2         ;Parse the entry into tokens.
         strtok NewsEntry[EntryLoop] ReadPWNEWSRC ""
      endfor
      strcat NewsEntry[1] "`r`n"
      fputs FID_GRPLST NewsEntry[1]    ;Put the groupname token into list file.
   endfor
endproc
   


proc Selection

;*****************************************************************************
;*                                                                           *
;* SELECTION  	                                                             *
;* Displays the newsgroups listed in the Connection Directory, allowing the  *
;* user to select which groups are to be read.  Once the user has finished   *
;* selecting, the relevant procedures for connecting to the server and       *
;* downloading the articles are called.                                      *
;*                                                                           *
;* Calls:  RSetup, CleanUp, ServerConnect, GetNews                           *
;* Called by: Main                                                           *
;* Modifies globals: Offline_INI, NewsIn, Continue                           *
;*                                                                           *
;*****************************************************************************

   string GroupList                    ;Path and name of GRPLIST
   string ReadListFile                 ;Path and name of READLIST
   string Message                      ;Text line in dialog box.
   string NewsServerName               ;Domain name of news server.
   string ServerPort                   ;Port to connect to on news server.
   integer True = 1                    ;Loop controller
   integer Count                       ;Number of items in the list.
   integer Selected                    ;Number of selected items.
   integer Event                       ;Dlgevent id holder
   integer DlgID                       ;Window ID of dialog box.
   integer Choice                      ;User choice in dialog box.
   
   strfmt Offline_INI "%s`\OFFLINE.INI" $PWLOCALPATH
                                       ;Define the path to the .ini file.
   isfile Offline_INI                  ;See if the .ini already exists.
   while FAILURE                       ;Create the .ini if not found.
      RSetup()
      isfile Offline_INI
   endwhile
   
   profilerd Offline_INI "PostReply" "NewsServer" NewsServerName
   ServerPort = "119"
   strfmt GroupList "%s%s" NewsIn "`\GRPLIST"
                                       ;File for groups from the Connection 
                                       ; directory
   strfmt ReadListFile "%s%s" NewsIn "`\READLIST"
                                       ;Groups chosen for viewing by the user.
   fopen 6 ReadListFile CREATE         ;Wipe the current choice list.
   while FAILURE
      Choice = 8
      strfmt Message "Unable to open file:`r`n`r`n%s" ReadListFile
      sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
      if Choice != 4
         CleanUp()
      endif
      fopen 6 ReadListFile CREATE
   endwhile
   fclose 6

   dialogbox 5 89 57 278 230 7 "Select Groups for Reading:"
                                       ;Draw the dialog box that allows the
                                       ; user to choose the groups to be
                                       ; viewed.
      flistbox 1 17 19 232 166 GroupList MULTIPLE ReadListFile HSCROLL SORT
                                       ;Choices come from GROUPLIST, the choices
                                       ; made are output to READLIST
      pushbutton 2 57 204 40 14 "Done" DEFAULT
      pushbutton 3 174 203 40 14 "Cancel"
   enddialog
   dlgwin 5 DlgID
   dlglist 5 1 ITEMCOUNT Count Selected
   if Selected == 0
      disable DLGCTRL 5 2
   endif
   while True
      dlgevent 5 Event                 ;Check for dialog box events.
      switch Event
         case 1                        
            dlglist 5 1 ITEMCOUNT Count Selected
            if Selected == 0
               disable DLGCTRL 5 2
            else
               enable DLGCTRL 5 2
            endif
         endcase
         case 2                        ;If Done was pushed,
            dlgdestroy 5 OK            ;Destroy this dialog and exit
            True = 0                   ; the dlgevent loop.
            ServerConnect(NewsServerName, ServerPort)           
                                       ;Connect to the News server.
            if Continue                ;If the connection was made,
               GetNews()               ;Collect all articles.
               transmit "quit^M^J"     ;Quit the server connection.
               if $PWTCPACTIVE         ;If the SUPERTCP stack is active,
                  menuselect PWMENU 363      
                                       ; disconnect from the Internet.
               endif
            endif
         endcase
         case 3                        ;If Cancel was pushed,
            dlgdestroy 5 CANCEL        ;Destroy this dialog and exit the script.
            True = 0
            Continue = 0
         endcase
         default
            winexists DlgID
            if FAILURE
               True = 0
               Continue = 0
            endif
         endcase
      endswitch
   endwhile
endproc



proc PostSelect

;*****************************************************************************
;*                                                                           *
;* POSTSELECT  	                                                             *
;* Displays the newsgroups listed in the Connection Directory, allowing the  *
;* user to select which group is to receive a posting.  Note that the author *
;* of this script is extremely offended by spamming, and so cross-posting    *
;* of articles is not allowed within this script.                            *
;* Once the user has made a choice, the procedure for actually entering the  *
;* the article is called.                                                    *
;*                                                                           *
;* Calls:  CleanUp, NewThread                                                *
;* Called by: Main                                                           *
;* Modifies globals: NewsIn, PostChoice, Continue                            *
;*                                                                           *
;*****************************************************************************

   string GroupList                    ;Path and name of GRPLIST
   string Message                      ;Text field in message dialog.
   integer Choice                      ;User choice in message dialog.
   integer True = 1                    ;Loop controller
   integer Event                       ;Dlgevent id holder
   integer DlgID                       ;Window ID of dialog box.
   
   strfmt GroupList "%s%s" NewsIn "`\GRPLIST"
                                       ;File for groups from the Connection 
                                       ; directory

   fopen FID_GRPLST GroupList READ
   while FAILURE
      Choice = 8
      strfmt Message "Unable to open file:`r`n`r`n%s" GroupList
      sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
      if Choice != 4
         CleanUp()
      endif
   endwhile
   fgets FID_GRPLST PostChoice
   fclose FID_GRPLST
   
   dialogbox 6 89 57 278 230 7 "Select Group for Posting:"
                                       ;Draw the dialog box that allows the
                                       ; user to choose the groups to be
                                       ; viewed.
      flistbox 1 17 19 232 166 GroupList SINGLE PostChoice HSCROLL SORT
                                       ;Choices come from GROUPLIST, the choice
                                       ; made is stored in PostChoice.
      pushbutton 2 57 204 40 14 "Done" DEFAULT
      pushbutton 3 174 203 40 14 "Cancel"
   enddialog
   dlgwin 6 DlgID
   while True
      dlgevent 6 Event                 ;Check for dialog box events.
      switch Event
         case 1                        
         endcase
         case 2                        ;If Done was pushed,
            dlgdestroy 6 OK            ;Destroy this dialog and exit
            True = 0                   ; the dlgevent loop.
            NewThread()
         endcase
         case 3                        ;If Cancel was pushed,
            dlgdestroy 6 CANCEL        ;Destroy this dialog and exit the script.
            True = 0
         endcase
         default
            winexists DlgID
            if FAILURE
               True = 0
               Continue = 0
            endif
         endcase
      endswitch
   endwhile
endproc



proc ServerConnect

;*****************************************************************************
;*                                                                           *
;* SERVERCONNECT                                                             *
;* Checks to see if there is an active TCP/IP connection.  If none is found, *
;* gives error message, else tries for connection to News server listed in   *
;* the Setup options.                                                        *
;*                                                                           *
;* Calls: RSetup, NoConnect, CleanUp, SConnected                             *
;* Called by: Main                                                           *
;* Modifies globals: Offline_INI, StartMode, Connecting, Continue            *
;*                                                                           *
;*****************************************************************************

param string ServerName
param string ServerPort
   
   string CurrentServerAddress
   integer UseSuperTCP                 ;External Network/Dialer connection.
   integer NetConnected                ;Is the PROCOMM PLUS stack active?
   integer Waiting
   
   strfmt Offline_INI "%s\OFFLINE.INI" $PWLOCALPATH
   isfile Offline_INI
   while FAILURE
      RSetup()
      isfile Offline_INI
   endwhile
   profilerd Offline_INI "PostReply" "UseSuperTCP" UseSuperTCP
   
   NetConnected = $PWTCPACTIVE         ;Get the current state of PROCOMM PLUS'S
                                       ; TCP/IP stack.
                                       
   if ((UseSuperTCP == 1) && (NetConnected == 0))
                                       ;If set for dialup connection and the 
                                       ; SUPERTCP stack is not active,
      when USEREXIT CLEAR              ;Don't call CleanUp on exit.
      when USEREXIT call NoConnect     ;Call NoConnect on exit.
      set aspect spawn ON              ;Allow the login script to run.
      menuselect PWMENU 363            ;Try to connect to the Internet.
      Waiting = 0                      ;Initialize timer.
      while ! NetConnected             ;Loop until Internet connection.
         NetConnected = $PWTCPACTIVE   ;See if the SUPERTCP stack is up.
         if ! NetConnected             ;If the stack is NOT up,
            Waiting += 1               ; add one to the timing variable.
         endif
         if Waiting > 500              ;If the attempt times out,
            NetConnected = 1           ;Exit this loop.
         endif
         yield                         ;Allow other functions to process.
      endwhile
      when USEREXIT CLEAR              ;Don't call NoConnect any more.
      when USEREXIT call CleanUp       ;Go back to calling CleanUp on exit.
      if Waiting > 500                 ;If connection timed out,
         NetConnected = 0              ;Indicate that the stack is not active.
      endif
   endif
   if ((UseSuperTCP == 0) || NetConnected)
                                       ;If the current stack is External, or if
                                       ;PROCOMM'S stack is active,
                                       
      strfmt CurrentServerAddress "%s:%s" ServerName ServerPort
      if StartMode != 5
         pwmode TELNET                 ; change to Telnet mode.
      endif
      connectmanual TELNET CurrentServerAddress
                                       ;Establish the server connection.
      if SUCCESS                       ;If the connection to the server
                                       ; is now established,
         Connecting = 1
         Waiting = 0
         waitfor "2" 5                 ;If the server gives an OK response,
         when target 0 "500" call SConnected
         transmit "`r`n"               ;Transmit an "end of line" to clear
                                       ; any garbage characters in the 
                                       ; server's receive buffer.
         
         while Connecting
            Waiting += 1
            if Waiting > 500
               Connecting = 0
            endif
            yield
         endwhile
         
         if Waiting > 500
            errormsg "Server Connection Not Active!"
            Continue = 0
         endif
         mspause 100
         clear                         ;Clear the screen.
      else
         errormsg "Unable to establish connection to server:`r`n`r`n%s" \
         ServerName
                                       ;Error if Telnet connection to the 
                                       ; News server could not be made.
         Continue = 0
      endif
   else
      errormsg "No TCP/IP stack is active!  Please check your network\
`r`nconfiguration and try again."
                                       ;If the stack was not found, give an
                                       ; error message and don't continue.
      Continue = 0
   endif
endproc



proc SConnected

;*****************************************************************************
;*                                                                           *
;* SCONNECTED                                                                *
;* Just exits the loop that waits for server connection.                     *
;*                                                                           *
;* Calls:  <none>                                                            *
;* Called by: ServerConnect                                                  *
;* Modifies globals:  Connecting                                             *
;*                                                                           *
;*****************************************************************************


   Connecting = 0
   
endproc



proc NoConnect

;*****************************************************************************
;*                                                                           *
;* NOCONNECT                                                                 *
;* Resets PROCOMM to defaults without exiting the script.                    *
;*                                                                           *
;* Calls:  <none>                                                            *
;* Called by:  ServerConnect                                                 *
;* Modifies globals:  StartMode, StartConnect, Waiting                       *
;*                                                                           *
;*****************************************************************************

   pwmode StartMode
   set data connection StartConnect
   Waiting = 501
endproc



proc GetNews

;*****************************************************************************
;*                                                                           *
;* GETNEWS                                                                   *
;* This procedure sets up a loop to read all chosen newsgroups, assigning a  *
;* file for each group to be written to, ending the process when the         *
;* ReadNews file tests out on FEOF.                                          *
;*                                                                           *
;* Calls:  CleanUp, DrawStatus, ReadList, GetLast, NewsRead                  *
;* Called by: Main                                                           *
;* Modifies globals:  CancelFlag, NewsIn, CurrentGroup, FilePointer,         *
;*                    CurrentFolder, Folder, CurrentStatus                   *
;*                                                                           *
;*****************************************************************************

   integer ReadingNews = 1             ;Main loop controller for this proc. 
   integer ReadingGroups               ;Secondary loop controller.
   integer GroupLength                 ;Length of the current group name.
   integer SameGroup                   ;Zero when correct PWNEWSRC entry has 
                                       ; been found.
   integer ValidGroup                  ;Verifies that the current group 
                                       ; actually exists.
   integer ReadLoop                    ;Loop for STRTOK operation.
   integer ReadLength                  ;Length of group from PWNEWSRC.
   integer Choice                      ;User choice at message dialog.
   string ReadPWNEWSRC                 ;Entry read from the PWNEWSRC.
   string NewsStamp                    ;Creation stamp from PWNEWSRC.
   string UserList                     ;READLIST file.
   string PWNEWSRCPath                 ;Path to PWNEWSRC.
   string ReadField[3]                 ;Array for STRTOK of ReadPWNEWSRC.
   string Message                      ;Text line from message dialog.
   
   
   CancelFlag = 1
   strfmt UserList "%s`\%s" NewsIn "READLIST"
                                       ;Define the location of READLIST.
   strfmt PWNEWSRCPath "%s`\%s" NewsIn "PWNEWSRC"
                                       ;Location of PWNEWSRC
   fopen FID_READLIST UserList READ TEXT         
                                       ;Try to open the list of user choices.
   while FAILURE
      Choice = 8
      strfmt Message "Unable to open file:`r`n`r`n%s" UserList
      sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
      if Choice != 4
         CleanUp()
      endif
      fopen FID_READLIST UserList READ TEXT
   endwhile
   while ReadingNews                   ;Set up main loop.
      rewind FID_PWNEWSRC              ;Make sure the PWNEWSRC is set to the
                                       ; beginning of the file.
      fgets FID_READLIST CurrentGroup  ;Grab the next user choice.
      strcmp CurrentGroup "" ValidGroup
                                       ;Make sure an actual group was grabbed.
      if ValidGroup != 0
         ReadingGroups = 1             ;Set up the secondary loop to find the
                                       ; correct folder name for this group.
         fgets FID_PWNEWSRC NewsStamp  ;Pull out the creation stamp so that it
                                       ; is not compared as a group name.
         while ReadingGroups    
            ftell FID_PWNEWSRC FilePointer
                                       ;Position of next entry in PWNEWSRC.    
            fgets FID_PWNEWSRC ReadPWNEWSRC
                                       ;Grab the next PWNEWSRC entry.
            for ReadLoop = 0 upto 2
                                       ;Initialize the STRTOK loop.
               strtok ReadField[ReadLoop] ReadPWNEWSRC ""
                                       ;Parse the PWNEWSRC entry into tokens.
            endfor
            strlen CurrentGroup GroupLength
                                       ;Get the length of the current group 
                                       ; name.
            strlen ReadField[1] ReadLength
                                       ;Get the length of the group name from
                                       ; the PWNEWSRC.
            if ReadLength == GroupLength
                                       ;If both names have the same length,
               strnicmp ReadField[1] CurrentGroup GroupLength SameGroup
                                       ;See if the two group names match.
               if SameGroup == 0       ;If the groupnames match,
                  CurrentFolder = ReadField[0]
                                       ;Grab the folder name for this entry.
                  ReadingGroups = 0 
                                       ;Exit the secondary loop.
               endif
            endif
         endwhile
         strfmt Folder "%s`\%s" NewsIn CurrentFolder
                                       ;Get the path of the current folder.
         chdir Folder                  ;Make sure that a directory for the
                                       ; current folder actually exists.
         if FAILURE
            mkdir Folder
            chdir Folder
         endif
         CurrentStatus = "Getting Article List....."
         DrawStatus()
         ReadList()                    ;Get article list for this group.
         GetLast()                     ;Get the number of the last article.
         NewsRead()                    ;Get each article in the list.
         if feof FID_READLIST          ;Exit main loop when no more choices.
            ReadingNews = 0
         endif
      else
         ReadingNews = 0
      endif
   endwhile
   dlgdestroy 17 CANCEL
endproc
   
   

proc DrawStatus

;*****************************************************************************
;*                                                                           *
;* DRAWSTATUS                                                                *
;* Draws the dialog box that shows message retrieval status.  Messages will  *
;* update this dialog box as different procedures are called.                *
;*                                                                           *
;* Calls:  CancelStatus                                                      *
;* Called by:  GetNews                                                       *
;* Modifies globals:  StatusHeader, TopStatus, BottomStatus, CurrentGroup,   *
;*                    CurrentStatus, StatusID                                *
;*                                                                           *
;*****************************************************************************

   StatusHeader = "Retrieving Articles"
                                       ;Initial title of dialog box.
   TopStatus = "Group"                 ;Header for group-box.
   BottomStatus = "Retrieval Status"   ;Header for group-box.
   
   dialogbox 17 159 110 262 106 3 StatusHeader
      text 2 23 17 210 12 CurrentGroup left
      groupbox 4 16 45 225 34 BottomStatus
      text 3 24 58 210 13 CurrentStatus left
      pushbutton 5 112 84 40 14 "Cancel" DEFAULT
      groupbox 1 16 5 225 33 TopStatus
   enddialog
   dlgwin 17 StatusID
   when DIALOG 17 call CancelStatus
endproc



proc CancelStatus

;*****************************************************************************
;*                                                                           *
;* CANCELSTATUS                                                              *
;* Destroys the Status dialog box and deletes all incomplete files.          *
;*                                                                           *
;* Calls:  CleanUp                                                           *
;* Called by:  DrawStatus                                                    *
;* Modifies globals:  CancelFlag, FileRead, ArticleList, InputFile,          *
;*                    ControlFile, SubjectFile, StatusID                     *
;*                                                                           *
;*****************************************************************************

   string Message                      ;Text field in message dialog.
   integer Choice                      ;User choice in message dialog.
   integer Event                       ;Control accessed in status dialog.
   
   dlgevent 17 Event                   ;Grab the control id.
   switch Event                        ;See which control was accessed.
      case 1                           ;Ignore all text fields.
      case 2
      case 3
      case 4
      endcase
      case 5                           ;If cancel button was selected, check
                                       ; to see what procedure is currently
                                       ; being followed.
         switch CancelFlag             
            case 1                     ;If grabbing article list,
               fclose FID_PWNEWSRC     ;Close the PWNEWSRC.
               fclose FID_READLIST     ;Close the List file (in READ mode).
               fclose FID_LISTWRITE    ;Close the list file (in WRITE mode).
               delfile FileRead        ;Delete the current list file.
               CleanUp()               ;Exit the script.
            endcase
            case 2                     ;If grabbing articles,
               fclose FID_LISTREAD     ;Close the list file.
               fclose FID_CONTROL      ;Close the control file.
               fclose FID_PWNEWSRC     ;Close the PWNEWSRC.
               fclose FID_ARTICLE      ;Close the article file.
               delfile ArticleList     ;Delete the list file.
               delfile InputFile       ;Delete the article file.
               delfile ControlFile     ;Delete the control file.
               CleanUp()               ;Exit this script.
            endcase
            case 3                     ;If formatting subject headers,
               Choice = 8              ;Ask user if they really want to quit.
               strfmt Message "Almost finished, are you sure you want to quit?"
               sdlgmsgbox "Formatting Subject Headers" Message QUESTION\
               YESNO Choice
               if Choice != 7          ;If user chooses YES,
                  fclose FID_LISTREAD  ;Close the article file.
                  fclose FID_CONTROL   ;Close the control file.
                  fclose FID_PWNEWSRC  ;Close the PWNEWSRC.
                  fclose FID_ARTICLE   ;Close the article file.
                  fclose FID_SUBJECT   ;Close the subject file.
                  delfile SubjectFile  ;Delete the subject file.
                  delfile ControlFile  ;Delete the control file.
                  delfile InputFile    ;Delete the article file.
                  delfile ArticleList  ;Delete the list file.
                  CleanUp()            ;Exit the script.
               endif
            endcase
         endswitch
      endcase
      default                          ;If the Win95 X was accessed,
         winexists StatusID            ;See if the dialog still exists.
         if FAILURE                    ;If the dialog box is gone,
            ;(Haven't figured out what I want here yet).
         endif
      endcase
   endswitch
endproc



proc ReadList

;*****************************************************************************
;*                                                                           *
;* READLIST                                                                  *
;* Grabs the list of articles for the current newsgroup.                     *
;*                                                                           *
;* Calls: ListRead                                                           *
;* Called by:  GetNews                                                       *
;* Modifies globals: FileRead, NewsIn, CurrentFolder, NoRXDATA, CurrentGroup *
;*                                                                           *
;*****************************************************************************

   string ListCommand                  ;Command to be sent to the news server.
   integer WaitCount                   ;Time to wait for server response.
   
   rxflush
   set aspect rxdata ON                ;Let this script handle all further input.
   strfmt FileRead "%s`\%s%s" NewsIn CurrentFolder "`\NEWSLIST.CAP"
                                       ;Add the filename for the list of 
                                       ; article numbers to the capture path.
   statmsg "Getting article list....."
   if isfile FileRead                  ;Get rid of any old article lists.
      delfile FileRead
   endif
   NoRXData = 1                        ;No data yet received.
   when $RXDATA call ListRead          ;Call I/O routine when data received.
   strfmt ListCommand "listgroup %s`r`n" CurrentGroup
                                       ;Set up the list command.
   waitcount = 0
   transmit ListCommand                ;Transmit command to news server.

   while NoRXData                      ;Wait until data is received.
      waitcount += 1
      if waitcount > 1000              ;Exit loop if timeout value is reached.
         waitcount = 0
         ListRead()
      endif
      yield
   endwhile 
   when $RXDATA CLEAR                  ;Clear the call to the I/O routine.  
endproc

         

proc ListRead

;*****************************************************************************
;*                                                                           *
;* LISTREAD                                                                  *
;* This procedure is called whenever incoming data is detected in the        *
;* READLIST procedure.  It opens a file, puts the incoming data into         *
;* that file, then closes that file and returns.                             *
;*                                                                           *
;* Calls:  CleanUp                                                           *
;* Called by: ReadList                                                       *
;* Modifies globals: FileRead, NoRXData                                      *
;*                                                                           *
;*****************************************************************************

   integer DataIn                      ;Holds the value of $RXDATA
   string ArticleBody                  ;Actual data received from the port.
   string Message                      ;Text line for message dialog.
   integer DataCount                   ;Amount of data to pull from the buffer.
   integer Choice                      ;User choice from message dialog.
   
   when $RXDATA	CLEAR                  ;Clear the WHEN statement that calls
                                       ; this procedure.
   fopen FID_LISTWRITE FileRead CREATE             ;Open the above mentioned file.
   while FAILURE
      Choice = 8
      strfmt Message "Unable to open file:`r`n`r`n%s" FileRead
      sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
      if Choice != 4
         CleanUp()
      endif
      fopen FID_LISTWRITE FileRead CREATE
   endwhile
      mspause 100
      DataIn = $RXCOUNT                ;Grab the amount of data in the buffer.
      while DataIn                     ;Loop while data is incoming.
         if DataIn > 255               ;Set the length of data to be read to
                                       ; a standard string length or less.
            DataCount = 255
         else
            DataCount = DataIn
         endif
         comread ArticleBody DataCount 5
                                       ;Grab data from the receive buffer.
         while FAILURE
            Choice = 8
            strcpy Message "Error Reading Data from the Port!"
            sdlgmsgbox "I/O Error!" Message EXCLAMATION RETRYCANCEL Choice
            if Choice != 4
               CleanUp()
            endif
            comread ArticleBody DataCount 5
         endwhile
         fputs FID_LISTWRITE ArticleBody
                                       ;And put that character into the file.
         DataIn = $RXCOUNT
      endwhile
      fclose FID_LISTWRITE             ;Close the data file.
   when $RXDATA call ListRead          ;Re-establish the WHEN statement that 
                                       ; calls this procedure
   NoRXData = 0                        ;Tell calling procedure that data was 
                                       ; received.
endproc



proc GetLast

;*****************************************************************************
;*                                                                           *
;* GETLAST                                                                   *
;* Gets the number of the last article in the current list.                  *
;*                                                                           *
;* Calls:  CleanUp                                                           *
;* Called by:  GetNews                                                       *
;* Modifies globals:  FileRead, EndList                                      *
;*                                                                           *
;*****************************************************************************

   string Message                      ;Text field for message dialog.
   integer ReadEntry                   ;String read from the list file.
   integer Choice                      ;User choice from message dialog.
   integer Searching                   ;Loop for searching list file.
   
   
   fopen FID_LISTWRITE FileRead READ   ;Keep trying to open the list file 
                                       ; until the file opens or the user exits.
   while FAILURE
      Choice = 8
      strfmt Message "Unable to open file:`r`n`r`n%s" FileRead
      sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
      if Choice != 4
         CleanUp()
      endif
      fopen FID_LISTWRITE FileRead READ
   endwhile
   fseek FID_LISTWRITE (-6) 2          ;Back over the `r`n.`r`n at end of file.
   for Searching = 1 upto 10           ;Get the previous data character.
      fgetc FID_LISTWRITE ReadEntry
      if ReadEntry == 10               ;If the character is a line feed,
         fgets FID_LISTWRITE EndList   ;Grab the string that follows it.
         Searching = 20                ;Exit this loop.
      endif
      fseek FID_LISTWRITE (-2) 1       ;If the charcter grabbed was not a LF,
                                       ; back up to the character that 
                                       ; preceded it.
   endfor
   if Searching == 11
      EndList = $NULLSTR
   endif
   fclose FID_LISTWRITE
endproc



proc NewsRead

;*****************************************************************************
;*                                                                           *
;* NEWSREAD                                                                  *
;* Grabs the articles for the current newsgroup.                             *
;*                                                                           *
;* Calls:ReadNews                                                            *
;* Called by: GetNews                                                        *
;* Modifies globals:   CancelFlag, ArticleList, NewsIn, CurrentFolder,       *
;*                     FileRead, InputFile, ControlFile, FilePointer,        *
;*                     NoRXData, CurrentStatus, EndList, IntBlockCount,      *
;*                     CurrentGroup                                          *
;*                                                                           *
;*****************************************************************************

   integer EndList0                    ;Checks for last file entry.
   integer EndList1 = 0                ;Checks for end of file
   integer EndList2                    ;Length of EndList
   integer DataWait
   integer True = 1                    ;Local loop counter
   integer What                        ;Garbage response from server.
   integer BadArticle                  ;Tells if a terminating CR was left in
                                       ; the article list.
   integer NumLength                   ;Length of the ReadList string.
   integer OldFile                     ;High if the folder being created already
                                       ; exists.
   integer EntryLength                 ;Length of entry from PWNEWSRC.
   integer NewLength                   ;Length of new entry from PWNEWSRC.
   integer EntryLoop                   ;Loop controller for STRTOK.
   integer NewEntryLength              ;Length of new control entry.
   integer ShortLength                 ;28 - NewEntryLength.
   integer AddLength                   ;Loop to lengthen ControlString.
   integer Extension                   ;Numeric extension of the folder for
                                       ; the current group.
   integer LastLength                  ;Length of last article field.
   integer ListCount
   integer Choice                      ;User choice in message dialog.
   long CurrentNumber                  ;Current article number.
   long HighCount                      ;Last article read from the current
                                       ; news group.
   string ReadData                     ;Data read from the article list.
   string ReadPWNEWSRC                 ;String read from the PWNEWSRC.
   string NewEntry                     ;String written to PWNEWSRC.
   string Article = "ARTICLE "         ;Define the ARTICLE command.
   string EntryField[3]                ;Array for STRTOK operation.
   string Request                      ;Formatted ARTICLE command
   string Message                      ;Text field for message dialogs.
   string ControlString                ;Write string for ControlFile.
   string LastArticle                  ;Last article number read.
   long ArticleStart                   ;Position of each article in data file.

   clear
   CancelFlag = 2
   set aspect rxdata ON                    
   when $RXCOUNT call ReadNews         ;Call I/O routine when input is 
                                       ; detected.
   strfmt ArticleList "%s`\%s%s" NewsIn CurrentFolder "`\NEWSLIST.CAP"
                                       ;Define the file containing the list
                                       ; of articles in the current group.
   fopen FID_LISTREAD ArticleList READ TEXT       ;Open the list of articles.
   while FAILURE
      Choice = 8
      strfmt Message "Unable to open file:`r`n`r`n%s" ArticleList
      sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
      if Choice != 4
         CleanUp()
      endif
      fopen FID_LISTREAD ArticleList READ TEXT
   endwhile

   fgets FID_LISTREAD ReadData         ;Pass up status message on first line.
   strcmp ReadData "500 What?" What
                                       ;If server timing gave a garbage 
                                       ; response,
   if What == 0
      fgets FID_LISTREAD ReadData      ;Pass up status message on second line.
   endif
   strfmt FileRead "%s`\%s`\%s" NewsIn CurrentFolder CurrentFolder
                                       ;Format the folder name.
   OldFile = 1                         ;Initialize the loop controller.
   Extension = 0                       ;Initialize file counter.
   while OldFile                       ;Loop until a non-existent filename
                                       ; has been found.
      strfmt InputFile "%s.%03i" FileRead Extension
                                       ;Check the next available filename.
      if isfile InputFile              ;If the file already exists
         Extension ++                  ;Try the next extension.
         if Extension > 999            ;If the extensions are all used up,
            errormsg "Unable to create any more folders for this group\
!!!`r`nPlease delete some existing folders and try again!!!"
                                       ;Give an error message requesting that
                                       ; the user free up some file names.
            Cleanup()                  ;Exit the script.
         endif
      else
         OldFile = 0                   ;Exit the loop if an empty folder has
                                       ; been found.
      endif
   endwhile
   strfmt ControlFile "%03i.CTL" Extension
                                       ;Format the name for the control file for
                                       ; the current folder.
   fopen FID_CONTROL ControlFile APPEND
                                       ;Open the current control file.
   while FAILURE  
      Choice = 8         
      strfmt Message "Unable to open file:`r`n`r`n%s" ControlFile
      sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
      if Choice != 4
         CleanUp()
      endif
      fopen FID_CONTROL ControlFile APPEND
   endwhile
   mspause 100                         ;Timing issue with the compiler.
   fseek FID_PWNEWSRC FilePointer 0    ;Go to the start of the current PWNEWSRC
                                       ; entry.
   fgets FID_PWNEWSRC ReadPWNEWSRC     ;Grab the current PWNEWSRC entry.
   strlen ReadPWNEWSRC EntryLength     ;Get the length of this entry.
   for EntryLoop = 0 upto 2            ;Parse entry into tokens.
      strtok EntryField[EntryLoop] ReadPWNEWSRC ""
   endfor
   strlen EntryField[2] LastLength     ;Get the length of last article field.
   LastLength -= 2                     ;Back up over the CR/LF pair.
   if LastLength != 0
      substr EntryField[2] EntryField[2] 0 LastLength
                                       ;Knock the CR/LF pair out of the string.
      atol EntryField[2] HighCount     ;String to long value.
   else
      HighCount = 0                    ;No articles previously read.
   endif
   fopen FID_ARTICLE InputFile APPEND  ;Open the data file.
   while FAILURE
      Choice = 8
      strfmt Message "Unable to open file:`r`n`r`n%s" InputFile
      sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
      if Choice != 4
         CleanUp()
      endif
      fopen FID_ARTICLE InputFile APPEND
   endwhile
   ListCount = 0

   while True                          ;Loop forever.
      fgets FID_LISTREAD ReadData      ;Grab the next article number from the 
                                       ; file.
      strchr ReadData 13 BadArticle 
                                       ;See if the the current article number
                                       ; has a garbage carriage return at the
                                       ; end of its string (a timing error found
                                       ; during testing causes this sometimes. 
                                       ; The error was fixed, but this routine
                                       ; was left in, just in case).
      if (BadArticle >= 0)             ;If the carriage return was found,
         strlen ReadData NumLength
                                       ;Get the length of the article number.
         NumLength --                  ;Subtract one from the article length.
         substr ReadData ReadData 0 NumLength
                                       ;Get rid of the terminating CR.
      endif   
      strcmp ReadData "." EndList0
                                       ;Check for a period ("End of Record" for
                                       ; NNTP)
      strlen EndList EndList2
      if (((EndList0 == 0) || EndList1) || ! EndList2) 
                                       ;If this is the last line of the file,
         exitwhile                     ;Exit this loop.
      else
         atol ReadData CurrentNumber
                                       ;Express the current article number as
                                       ; a long variable for comparison.
         if (HighCount - CurrentNumber) > 10000
                                       ;If the high count number is more than
                                       ; 10000 above the current list, the 
                                       ; group count has probably been reset,
                                       ; and we need to start over at zero.
            HighCount = -1
         endif
         if CurrentNumber > HighCount
            flength FID_ARTICLE ArticleStart
            NoRXData = 1
            strfmt CurrentStatus "Fetching Article Number %s of %s" \
            ReadData EndList
            dlgupdate 17 3
            strfmt Request "%s%s`r`n" Article ReadData
                                       ;Define the ARTICLE command.
            statmsg "Retrieving article number %s" ReadData
            DataWait = 0
            transmit Request           ;Send the ARTICLE command to the 
                                       ; News server.
            while NoRXData             ;Loop until receive buffer fills.
               DataWait += 1           ;Start timing loop
               if DataWait > 1000
                                       ;If it takes more than a few seconds to
                                       ; receive data,
                  NoRXData = 0         ;Exit this loop and get the next article.
               endif
               yield             
            endwhile
            strfmt ControlString "%s%li%i%i" ReadData ArticleStart\
 IntBlockCount ListCount
                                       ;Format the record for the control file.
                                       ;Each record will consist of the article
                                       ; number, the position in the file that
                                       ; the article starts at, and the number
                                       ; of 128 byte blocks that the article
                                       ; is using in the file.
            strlen ControlString NewEntryLength
                                       ;Get the length of the new control entry.
            ShortLength = 28 - NewEntryLength
                                       ;See how many bytes need to be added to 
                                       ; the ControlString to make it 28 long.
            if ShortLength > 0   ;If the ControlString is too short,
               for AddLength = 1 upto ShortLength
                                       ;Add whitespace until it's 28 long.
                  strcat ControlString " "
               endfor
            endif
            strcat ControlString "`r`n" 
                                       ;Add a terminating CR/LF pair, bringing
                                       ; the length of ControlString to 30.
            fputs FID_CONTROL ControlString  
                                       ;Write the control string to the control
                                       ; file.
            feof FID_LISTREAD EndList1            ;See if actual end of file has occured.
         endif
      endif
      LastArticle = ReadData
      ListCount += 1
   endwhile
   EntryField[2] = LastArticle         ;Grab the last article number
   strfmt NewEntry "%s%s%s`r`n" EntryField[0] EntryField[1]\
 EntryField[2]                         ;Format the entry for the PWNEWSRC with
                                       ; the updated HighCount marker.
   strlen NewEntry NewLength           ;Get the length of the new entry.
   fseek FID_PWNEWSRC FilePointer 0               ;Go back to the start of the current
                                       ; PWNEWSRC entry.
   fdelblock FID_PWNEWSRC EntryLength             ;Wipe the old entry.
   finsblock FID_PWNEWSRC NewLength               ;Insert the new entry.
   fputs FID_PWNEWSRC NewEntry                   

   when $RXCOUNT CLEAR                 ;Clear the call to the input routine.
   fclose FID_CONTROL                  ;Close the Control file.
   fclose FID_ARTICLE                  ;Close the article file.
   rxflush                             ;Clear the receive buffer.
   statmsg "Formatting Subject Headers......"      
                                       ;Let user know what's going on.
   strfmt CurrentStatus "Formatting Subject Headers......"
   dlgupdate 17 3
   Subject(Extension)                  ;Create an XXX.SUB file for this group.
   statclear
   strfmt CurrentStatus "Finished retrieving %s" CurrentGroup
                                       ;Let user know what's going on.
   dlgupdate 17 3
   mspause 500
endproc



proc ReadNews

;*****************************************************************************
;*                                                                           *
;* READNEWS                                                                  *
;* This procedure is called whenever incoming data is detected in the        *
;* NEWSREAD procedure.  It opens a file, puts the incoming data into         *
;* that file, then closes that file and returns.                             *
;*                                                                           *
;* Calls: CleanUp                                                            *
;* Called by: NewsRead                                                       *
;* Modifies globals: IntBlockCount, NoRXData                                 *
;*                                                                           *
;*****************************************************************************

   integer DataIn                      ;Holds the value of $RXDATA
   string ArticleBody                  ;Actual data received from the port.
   string Message                      ;Text field in message dialog.
   integer DataCount                   ;Amount of data to pull from the buffer.
   integer FileBuffer                  ;Pad characters for 128 byte blocks.
   integer BufferCount                 ;Loop controller for pad characters.
   integer Choice                      ;User choice in message dialog.
   
   when $RXCOUNT CLEAR                 ;Clear the WHEN statement that calls
                                       ; this procedure.
   IntBlockCount = 0
   mspause 100
   DataIn = $RXCOUNT                   ;Grab the amount of data in the buffer.
   while DataIn                        ;Loop while data is incoming.
      if DataIn >= 128                 ;Set the length of data to be read to
                                       ; a standard string length or less.
         DataCount = 128
         FileBuffer = 0
      elseif DataIn > 0
         DataCount = DataIn
         FileBuffer = 128 - DataCount
      endif
      comread ArticleBody DataCount 5
                                       ;Grab data from the receive buffer.
      while FAILURE
         Choice = 8
         strcpy Message "Error Reading Data from the Port!"
         sdlgmsgbox "I/O Error!" Message EXCLAMATION RETRYCANCEL Choice
         if Choice != 4
            CleanUp()
         endif
         comread ArticleBody DataCount 5
      endwhile
      
      fputs FID_ARTICLE ArticleBody    ;And put that data into the file.
      if FileBuffer                    ;If pad characters are needed,
         for BufferCount = 1 upto FileBuffer
            fputc FID_ARTICLE ' '
         endfor
      endif
      IntBlockCount += 1
      DataIn = $RXCOUNT                ;See if there is any more data.
   endwhile
   when $RXCOUNT call ReadNews         ;Re-establish the WHEN statement that 
                                       ; calls this procedure
   NoRXData = 0                        ;Tell calling procedure that data was 
                                       ; received.
endproc

    

proc NewThread

;*****************************************************************************
;*                                                                           *
;* NEWTHREAD                                                                 *
;* This procedure writes a new article for posting to a news group.          *
;*                                                                           *
;* Calls:  CleanUp                                                           *
;* Called by:  Main                                                          *
;* Modifies globals: Offline_INI, ZoneSelect, NewsOut, PostChoice            *
;*                                                                           *
;*****************************************************************************

   string Message                      ;Text field for all message dialogs.
   string UserEMail                    ;E-Mail address from the INI file.
   string SaveReply                    ;Name of file to save reply in.
   string SigFile                      ;Signature file.
   string ReadSig                      ;Reads characters from signature file.
   string FromHeader                   ;From: header for reply file.
   string DateHeader                   ;Date: header for reply file.
   string ReplyName                    ;User name.
   string SubjectHeader                ;Subject: header for reply file.
   string BodyTemp                     ;Temp file for reply body.
   string ReadTemp                     ;String for reading from temp file.
   string ReplyToHeader                ;Reply-To header for news post.
   integer Extension                   ;File extension for reply file.
   integer Choice                      ;User choice in all message dialogs.
   integer Searching                   ;Loop controller for file-name search.
   integer DoneCopy                    ;EOF test on data files.
   integer Event                       ;Event holder for DLGEVENT statement.
   integer DlgID                       ;Windows ID of this dialog box.
   integer WritingReply                ;TRUE while main dialog exists.
   integer StillThere                  ;TRUE if the dialog has not been closed
                                       ; with the Win95 X.


   strfmt Offline_INI "%s`\OFFLINE.INI" $PWLOCALPATH
   
   profilerd Offline_INI "PostReply" "UserName" ReplyName
   profilerd Offline_INI "PostReply" "EMailAddress" UserEMail
                                       ;Get user's e-mail address from INI.
   profilerd Offline_INI "PostReply" "TimeZone" ZoneSelect
   profilerd Offline_INI "PostReply" "SigFile" SigFile
   
   strfmt FromHeader "%s <%s>`r`n" ReplyName UserEMail
   
   Extension = 0                       ;Set the file extension to 000.
   Searching = 1                       ;Initialize the search loop.
   while Searching
      strfmt SaveReply "%s`\POST.%03i" NewsOut  Extension
                                       ;Format a file name for a NEWS reply.
      if isfile SaveReply              ;If the file already exists,
         Extension += 1                ;Add one to the file extension
      else                             ; and try again, otherwise exit
         Searching = 0                 ; this loop.
      endif
   endwhile
     
   
   strfmt BodyTemp "%s`\TEMP2.TMP" NewsOut
                                       ;Format the name of the file that will
                                       ; hold the text to be edited.
   fopen FID_REPLYFILE BodyTemp CREATE ;Open the edit file.
   while FAILURE
      Choice = 8
      strfmt Message "Unable to open file:`r`n`r`n%s" SaveReply
      sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
      if Choice != 4
         CleanUp()
      endif
      fopen FID_REPLYFILE BodyTemp CREATE
   endwhile
   
   fclose FID_REPLYFILE                ;Close the edit file.

      
   dialogbox 60 110 85 350 275 7 "PROCOMMM PLUS v3.0 Off-line News Reader - New Article"
      text 1 4 43 20 8 "Date:" LEFT
      text 2 2 3 30 8 "From:" LEFT
      text 3 3 14 40 8 "NewsGroup:" LEFT
      text 4 2 28 32 8 "Subject:" LEFT
      text 5 46 43 270 8 DateHeader LEFT
      text 6 46 3 270 8 ReplyName LEFT
      text 7 47 14 270 8 PostChoice LEFT
      feditbox 9 4 58 341 185 BodyTemp
      pushbutton 10 232 253 40 14 "Cancel" CANCEL
      pushbutton 11 79 253 40 14 "Done"
      editbox 8 48 27 290 11 SubjectHeader 80
   enddialog
   dlgwin 60 DlgID                     ;Get the Windows ID of the dialog box.
   WritingReply = 1                    ;Initialize the DLGEVENT loop.
   mspause 200
   while WritingReply
      dlgevent 60 Event                ;Get the last dialog event.
      switch Event
         case 1                        ;Ignore all non-pushbutton controls.
         case 2
         case 3
         case 4
         case 5
         case 6
         case 7
         case 8
         case 9
         endcase
         case 10 
            dlgdestroy 60 CANCEL       ;Exit on Cancel.
            WritingReply = 0
         endcase
         case 11
            dlgdestroy 60 OK
            
            fopen FID_BODYTEMP SaveReply CREATE
                                       ;On DONE, open the reply file, write all
                                       ; write all necessary headers into the
                                       ; file, then copy the edit file into it.
            while FAILURE
               strfmt Message "Unable to open file:`r`n`r`n%s" SaveReply
               sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL \
               Choice
               if Choice == 2
                  CleanUp()
               endif
               fopen FID_BODYTEMP SaveReply CREATE
            endwhile
               
            fopen FID_REPLYFILE BodyTemp READ
            while FAILURE
               strfmt Message "Unable to open file:`r`n`r`n%s" SaveReply
               sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
               if Choice == 2
                  CleanUp()
               endif
               fopen FID_REPLYFILE BodyTemp READ
            endwhile
            
            strcat PostChoice "`r`n"   ;Add CR/LF pair to end of header.
            strcat SubjectHeader "`r`n"
                                       ;Add CR/LF pair to end of header.
            strfmt ReplyToHeader "Reply-To: %s`r`n" UserEMail
                                       ;Format the recipient's address for the
                                       ; TO: header line.
            
            fputs FID_BODYTEMP "From: "          
                                       ;Write the FROM header to file.
            fputs FID_BODYTEMP FromHeader
            fputs FID_BODYTEMP "Newsgroups: "    
                                       ;Write the NEWSGROUPS header to file.
            fputs FID_BODYTEMP PostChoice
            fputs FID_BODYTEMP "Subject: "
            fputs FID_BODYTEMP SubjectHeader     
                                       ;Write the SUBJECT header to file.
            fputs FID_BODYTEMP ReplyToHeader     
                                       ;Write the REPLY-TO header to file.
            fputs FID_BODYTEMP "Distribution: world`r`n"
                                       ;Tell server not to restrict 
                                       ; distribution of this article.
            fputs FID_BODYTEMP "`r`n"  ;Add a blank line for SOT.
            DoneCopy = 0
            while ! DoneCopy
               fgets FID_REPLYFILE ReadTemp       
                                       ;Grab the next line of the temp file.
               fputs FID_BODYTEMP ReadTemp       
                                       ;Put the line into the reply file.
               feof FID_REPLYFILE DoneCopy        
                                       ;Exit loop on eof of temp file.
            endwhile
            if isfile SigFile          ;If a signature file exists,
               fopen FID_SIGFILE SigFile READ   
                                       ;Open the signature file.
               while FAILURE
                  strfmt Message "Unable to open file:`r`n`r`n%s" SigFile
                  sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
                  if Choice == 2
                     CleanUp()
                  endif
                  fopen FID_SIGFILE SigFile READ
               endwhile
               feof FID_SIGFILE DoneCopy
               while ! DoneCopy        ;Copy the contents of the sig file to
                  fgets FID_SIGFILE ReadSig     
                                       ; the end of the reply file.
                  fputs FID_BODYTEMP ReadSig
                  feof FID_SIGFILE DoneCopy
               endwhile
            endif
            fputs FID_BODYTEMP "`r`n.`r`n"       
                                       ;Add period on line by itself for EOT.
            WritingReply = 0           ;Exit main loop.
            fclose FID_REPLYFILE       ;Close reply file.
            fclose FID_BODYTEMP        ;Close the temp file.
            delfile BodyTemp           ;Finished with temp file, delete it.
         endcase
         default                       ;If no controls were accessed, but an
                                       ; event still registers,
            winexists DlgID StillThere
                                       ;See if this dialog box still exists.
            if ! StillThere            ;If the dialog is gone, the X from 
                                       ; Windows 95 has been selected, and this
                                       ; loop needs to be exited.
               dlgdestroy 60 CANCEL
               WritingReply = 0
            endif
         endcase
      endswitch
   endwhile
endproc



proc Delivery

;*****************************************************************************
;*                                                                           *
;* DELIVERY                                                                  *
;* This function sends all POST.*, RPLY*.*, and MAIL*.* files to their       *
;* appropriate servers, using transmission across a Telnet connection.       *
;*                                                                           *
;* Calls:  RSetup, ServerConnect, SendNewsText, SendMailText                 *
;* Called by:  Main                                                          *
;* Modifies globals: Offline_INI, NewsOut, Continue                          *
;*                                                                           *
;*****************************************************************************

   string NewsFiles                    ;Filespec for new postings.
   string ReplyFiles                   ;Filespec for News replies.
   string MailFiles                    ;Filespec for Mail replies.
   string NewsServerName               ;Name from Offline_INI.
   string MailServerName               ;Name from Offline_INI.
   string UserEMail                    ;Address from Offline_INI.
   string TempEMail                    ;Copy of address for STRTOK operation.
   string ServerPort                   ;Port to pass to ServerConnect.
   string DomainName                   ;Name for HELO command in mail.
   string TransmitString               ;String for sending to server.

   strfmt Offline_INI "%s`\OFFLINE.INI" $PWLOCALPATH
                                       ;Format the path to the .INI file.
   isfile Offline_INI                  ;Look for the INI file.
   while FAILURE                       ;If the .INI file is not found, loop
      RSetup()                         ; until the user creates it.
      isfile Offline_INI
   endwhile
   
   strfmt NewsFiles "%s`\POST.*" NewsOut
                                       ;Define the filespec for new posts.
   if findfirst NewsFiles              ;If any new posts exist,
      profilerd Offline_INI "PostReply" "NewsServer" NewsServerName
                                       ;Get the name of the news server.
      ServerPort = "119"               ;NNTP port = 119.
      Continue = 1                     ;Reset ServerConnect.
      ServerConnect(NewsServerName, ServerPort)
                                       ;Connect to the news server.
      if Continue                      ;If successfully connected,
         findfirst NewsFiles           ;Get the next (or first) post file.
         while SUCCESS                 ;If found, 
            SendNewsText()             ;Send the posting to the news server.
            delfile $FILESPEC          ;Delete the sent file.
            findfirst NewsFiles        ;Find the next file.
         endwhile
         pause 1
      endif
      waitfor "2" 3                    ;Give the news server time to clean up.
      transmit "quit`r`n"              ;Disconnect from the news server.
   endif
   
   strfmt ReplyFiles "%s`\RPLY*.*" NewsOut
                                       ;Define the filespec for reply files.
   if findfirst ReplyFiles             ;If there are any reply files,
      profilerd Offline_INI "PostReply" "NewsServer" NewsServerName
                                       ;Connect to the news server.
      ServerPort = "119"
      Continue = 1
      ServerConnect(NewsServerName, ServerPort)
      if Continue                      ;If successfully connected,
         findfirst ReplyFiles          ;Grab the first reply file.
         while Success
            SendNewsText()             ;Post the reply file.
            delfile $FILESPEC          ;Delete the posted file.
            findfirst ReplyFiles       ;Look for another reply file.
         endwhile
         pause 1
      endif
      waitfor "2" 3                    ;Wait for server response.
      transmit "quit`r`n"              ;Disconnect from the server.
   endif
   
   strfmt MailFiles "%s`\MAIL*.*" NewsOut
                                       ;Define the filespec for mail files.
   if findfirst MailFiles              ;Look for a mail file.
      profilerd Offline_INI "PostReply" "MailServer" MailServerName
                                       ;Get the name of the mail server.
      profilerd Offline_INI "PostReply" "EMailAddress" UserEMail
                                       ;Get address.
      ServerPort = "25"                ;SMTP port = 25.
      Continue = 1      
      ServerConnect(MailServerName, ServerPort)
                                       ;Connect to the mail server.
      if Continue                      ;If connection is active.
         strcpy TempEMail UserEMail    ;Make a copy of the email address.
         transmit "`r`n"               ;Clear server's receive buffer.
         mspause 100
         strtok DomainName TempEMail "@"
                                       ;Reduce address to just domain name.
         strtok DomainName TempEMail "@"
         strfmt TransmitString "HELO %s`r`n" DomainName
                                       ;Send the SMTP HELO command.
         transmit TransmitString       
         waitfor "2" 3                 ;Wait for server response.
         SendMailText()                ;Send all mail postings.
      endif
      waitfor "2" 3                    ;Wait for server response.
      transmit "quit`r`n"              ;Disconnect from mail server.
   endif
endproc

        
      
proc SendNewsText

;*****************************************************************************
;*                                                                           *
;* SENDNEWSTEXT                                                              *
;* This procedure sends the text of whatever current posting is being read,  *
;* to the server that is currently being spoken to (news.)                   *
;*                                                                           *
;* Calls: CleanUp                                                            *
;* Called by:  Delivery                                                      *
;* Modifies Globals:  <none>                                                 *
;*                                                                           *
;*****************************************************************************

   string Message                      ;Text line for message dialogs.
   string ReadArticle                  ;String for reading from article file.
   string TransmitString               ;Data to send to news server.
   string PostGroup                    ;Group being posted to.
   integer Choice                      ;User choice in message dialogs.
   integer Searching                   ;String for finding headers.
   integer NotFound                    ;False while search not concluded.
   integer EndReply                    ;TRUE when EOF on post file.
    
   fopen FID_REPLYFILE $FILESPEC READ  ;Open the current post file.
   while FAILURE                       ;Loop until file opens or user exits.
      Choice = 8
      strfmt Message "Unable to open file:`r`n`r`n%s" $FILESPEC
      sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
      if Choice != 4
         CleanUp()
      endif
      fopen FID_REPLYFILE $FILESPEC READ 
   endwhile
         
   Searching = 1                       ;Initialize search loop.
   while Searching                     ;While NEWSGROUPS header is not found,
      fgets FID_REPLYFILE ReadArticle  ;Get the next header line.
      strnicmp ReadArticle "NewsGroups:" 11 NotFound
                                       ;See if this line is the search target.
      if NotFound == 0                 ;If target is found,
         Searching = 0                 ;Exit this loop.
         strtok PostGroup ReadArticle " " 
                                       ;Pull out the name of the newsgroup.
         strtok PostGroup ReadArticle " "
      endif
   endwhile
   fclose FID_REPLYFILE
         
   pause 1
   strfmt TransmitString "group %s" PostGroup
                                       ;Point server to target newsgroup.
   transmit TransmitString
   pause 1
   strfmt TransmitString "post`r`n"    ;See if the server likes a POST command.
   transmit TransmitString
   waitfor "340" 10                    ;Wait for a server response.
   if SUCCESS                          ;If server allows posting,
      pause 1
      fopen FID_REPLYFILE $FILESPEC READ          
                                       ;Open the posting file.
      while FAILURE
         Choice = 8
         strfmt Message "Unable to open file:`r`n`r`n%s" $FILESPEC
         sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
         if Choice != 4
            CleanUp()
         endif
         fopen FID_REPLYFILE $FILESPEC READ 
      endwhile
      transmit "`r`n"                  ;Clear server's receive buffer.
      feof FID_REPLYFILE EndReply      ;Test for end-of-file on post file.
      while ! EndReply                 ;Loop until eof is reached.
         fgets FID_REPLYFILE TransmitString       
                                       ;Read a line from the file.
         transmit TransmitString       ;Transmit the read line.
         mspause 100                   ;Let server process the data.
         feof FID_REPLYFILE EndReply   ;Test for eof again.
      endwhile
   else
      usermsg "Posting to group:`r`n`r`n%s`r`nis not allowed!" PostGroup
                                       ;Error if server does not allow posting
                                       ; in the chosen news group.
   endif
   delfile $FILESPEC                   ;Delete the posted file.
endproc



proc SendMailText

;*****************************************************************************
;*                                                                           *
;* SENDMAILTEXT                                                              *
;* This procedure sends the text of whatever current posting is being read,  *
;* to the server that is currently being spoken to (mail.)                   *
;*                                                                           *
;* Calls: CleanUp                                                            *
;* Called by:  Delivery                                                      *
;* Modifies Globals: Offline_INI, NewsOut                                    *
;*                                                                           *
;*****************************************************************************

   string Message                      ;Text field in message dialog.
   string ReadArticle                  ;String for reading from post file.
   string Recipient                    ;Address for sending mail.
   string MailFiles                    ;Filespec for mail replies.
   string UserEMail                    ;Address from .INI file.
   string TransmitString               ;Data to send to server.
   integer Choice                      ;User choice in message dialogs.
   integer DoneSending                 ;Flag for exiting post loop.
   integer Searching                   ;String for finding text.
   integer NotFound                    ;Flag for exiting search loop.
         
   strfmt Offline_INI "%s`\OFFLINE.INI" $PWLOCALPATH
                                       ;Format path to OFFLINE.INI.
   profilerd Offline_INI "PostReply" "EMailAddress" UserEMail
                                       ;Get user's email address.
   
   strfmt MailFiles "%s`\MAIL*.*" NewsOut
                                       ;Define filespec for mail files.
   findfirst MailFiles                 ;Get the name of the first mail file.
   while SUCCESS                       ;Loop while new files are found.
      fopen FID_REPLYFILE $FILESPEC READ          ;Open the current mail file.
      while FAILURE
         Choice = 8
         strfmt Message "Unable to open file:`r`n`r`n%s" $FILESPEC
         sdlgmsgbox "File Error!" Message EXCLAMATION RETRYCANCEL Choice
         if Choice != 4
            CleanUp()
         endif
         fopen FID_REPLYFILE $FILESPEC READ
      endwhile
      
      Searching = 1                    ;Initialize the search loop.
      while Searching
         fgets FID_REPLYFILE ReadArticle          
                                       ;Grab the first mail header.
         strnicmp ReadArticle "To:" 3 NotFound
                                       ;See if this is the TO: header.
         if NotFound == 0              ;If the target is found,
            Searching = 0              ;Exit the loop.
            strtok Recipient ReadArticle ":"
                                       ;Reduce string to just an address.
            strtok Recipient ReadArticle ":"
         endif
      endwhile
      
      strfmt TransmitString "MAIL From:%s`r`n" UserEmail
                                       ;Send SMTP Mail command.
      transmit TransmitString
      waitfor "2" 3
      strfmt TransmitString "RCPT To:%s`r`n" Recipient
                                       ;Tell server who to send to.
      transmit TransmitString
      waitfor "2" 3
      transmit "DATA`r`n"              ;Tell server to receive mail data.
      waitfor "354" 5
    
      rewind FID_REPLYFILE             ;Go to start of Mail file.
      feof FID_REPLYFILE DoneSending
      while ! DoneSending              ;Loop until eof on mail file.
         fgets FID_REPLYFILE ReadArticle          
                                       ;Grab next line of mail file.
         transmit ReadArticle          ;Send line of mail file.
         mspause 100
         feof FID_REPLYFILE DoneSending           
                                       ;Test for eof.
      endwhile
      fclose FID_REPLYFILE             ;Close mail file when done sending.
      delfile $FILESPEC                ;Delete the transmitted file.
      findfirst MailFiles
   endwhile
endproc



proc CleanUp

;*****************************************************************************
;*                                                                           *
;* CLEANUP                                                                   *
;* This procedure closes any open files before exiting, and also restores    *
;* the Setup to a pre-startup condition.                                     *
;*                                                                           *
;* Calls:  <none>                                                            *
;* Called by:  Pretty much everything.                                       *
;* Modifies globals: StartMode, StartConnect, StartDuplex                    *
;*                                                                           *
;*****************************************************************************

   integer EndDuplex
   
   statmsg "Restoring Startup Defaults......."
                                       ;Let the user know why the script is
                                       ; pausing.
   set aspect rxdata OFF               ;Let PROCOMM handle input once more.
   if $CARRIER	
      transmit "QUIT^M^J"              ;Make sure to close the connection
   endif
                                       ; with the News Server.
   dlgdestroy 0 CANCEL                 ;Close the feditbox.
   pause 1                             ;Give the file time to close,
   pwmode StartMode                    ;Go back to the startup mode.
   set modem connection StartConnect   ;Go back to the startup connection. 
   fetch port duplex EndDuplex         ;Grab the current port duplex.
   if EndDuplex != StartDuplex         ;Make sure duplex is at start setting.
      if StartDuplex == 0
         set port duplex FULL
      else
         set port duplex HALF
      endif
   endif
   statclear
   clear
   exit
endproc
      

