[comp.os.vms] uw nntp news reader part b

dorl@vms.macc.wisc.edu (Michael Dorl - MACC) (07/29/88)

	End Do

	If (.not. Done) Then
	  Goto 1
	EndIf

C Disconnect from server

	Status = Srv_Cmd ('quit', Buf, Lg)
	If (.not. Status) Then
	  Print '(A)', ' Server failed'
	  Stop
	EndIf

	Call SMG_All_Print (' ', '|')
	Call SMG_All_Print 
     $    ('Closing News server connection...', '|')
	Call SMG_All_Print (Buf(1:Lg), '|')

	Status = Srv_NetClose ()
	If (.not. Status) Then
	  Print '(A)', ' Socket failure'
	  Stop
	EndIf

C Update xx.newsrc

	Call SMG_All_Print (' ', '|')
	Call SMG_All_Print ('Updating XX.Newsrc...', '|')
	Status = Close_Newsrc ()
	If (.not. Status) Then
	  Print '(A)', ' Error closing XX.NEWSRC'
	  Stop
	End If

	End ! News


	Integer Function UnRead (G)

	Include 'News.Def'

C Parameter definitions

	Integer G

C Local definitions

	Integer   *4	E, R, RS, RE, RU, S

C Begin UnRead

	S = Group(G).Active_Start
	E = Group(G).Active_End
	If (S .eq. 0) Then
	  S = 1
	EndIf

	UnRead = E - S + 1

	R = Group(G).Range_First

	Do While (R .ne. 0)

	  If (Range(R).Start .lt. S) Then
	    RS = S
	  Else
	    RS = Range(R).Start
	  EndIf

	  If (Range(R).End .gt. E) Then
	    RE = E
	  Else
	    RE = Range(R).End
	  EndIf

	  RU = RE - RS + 1
	  If (RU .gt. 0) Then
	    UnRead = UnRead - RU
	  EndIf

	  R = Range(R).Next

	EndDo

	If (UnRead .lt. 0) Then
	  UnRead = 0
	EndIf

	End ! Unread


	Subroutine Down_Case (Str)

	Implicit None

C Parameter definitions

	Character *(*)		Str

C Local definitions

	Integer   *4		X, Lg

C Begin Down_Case

	Lg = Len (Str)
	Do X = 1, Lg
	  If ((Str(X:X) .ge. 'A') .and. (Str(X:X) .le. 'Z')) Then
	    Str(X:X) = Char (IChar(Str(X:X)) + IChar(' '))
	  EndIf
	EndDo

	End ! Down_Case


	Subroutine Rotate (Str)

C Parameter definitions

	Character *(*)	Str

C Local definitions

	Integer   *4	Lg, N, X
	Character *(1)  C

C Begin Rotate

	Lg = Len(Str)
	Do X = 1, Lg
	  C = Str(X:X)
	  If (
     $        ((C .ge. 'a') .and. (C .le. 'z')) 
     $       .or. 
     $        ((C .ge. 'A') .and. (C .le. 'Z'))
     $       ) Then
	    N = IChar(C)
	    If (IAnd(N,31) .le. 13) Then
	      N = N + 13
	    Else
	      N = N - 13
	    EndIf
	    Str(X:X) = Char(N)
	  EndIf
	EndDo

	End ! Rotate


	Subroutine Read_Init

	Include 'News.Def'

C Local definitions

	Logical		Eof
	Integer   *4	Status
	Integer   *4	I
	Character *256	Img
	Integer   *4	Img_Lg
	Character *64	Img_Field
	Integer   *4	IP
	Byte		IP_Byte
	Equivalence     (IP,IP_Byte)
	Character *15	IP_Number
	Integer   *4	X

C Begin Read_Init

	SiteId = ' '
	Distribution_Count = 0

	Open
     $    (
     $	   Unit		= LU_Init,
     $     File		= 'NewsDir:Config.Dat',
     $     ReadOnly,
     $     Shared,
     $     Status	= 'Old',
     $	   IOStat	= Status
     $    )

	If (Status .ne. 0) Then
	  Call SMG_All_Print ('Error opening NewsDir:Config.Dat', '|')
	  Stop
	EndIf

	Eof = .false.
	Do While (.not. Eof)
	  Read (LU_Init, '(Q,A)', IOStat = Status) Img_Lg, Img
	  If (Status .eq. 0) Then
	    X = Index (Img(1:Img_Lg),':')
	    If (X .eq. 0) Then
	      X = Img_Lg
	    EndIf
	    If (Img(1:X) .eq. 'distribution:') Then
	      X = X + 1
	      Do While (X .lt. Img_Lg)
	        Call Field (Img(1:Img_Lg), X, Img_Field) 
	        If (Img_Field .ne. ' ') Then
		  Distribution_Count = Distribution_Count + 1
		  Distribution(Distribution_Count) = Img_Field
	  	EndIf
	      EndDo
	    ElseIf (Img(1:X) .eq. 'siteid:') Then
	      X = X + 1
	      Call Field (Img(1:Img_Lg), X, SiteId)
	    ElseIf (Img(1:X) .eq. 'organization:') Then
	      X = X + 1
	      Organization = Img(X:Img_Lg)
	    ElseIf (Img(1:X) .eq. 'server:') Then
	      X = X + 1
	      Call Field (Img(1:Img_Lg), X, IP_Number)
	      IP = 0
	      I = 1
	      Do X = 1,15
	        If (IP_Number(X:X) .eq. '.') Then
	          Server_IP_Number(I) = IP_Byte
	          IP = 0
		  I = I + 1
	        Else If (IP_Number(X:X) .eq. ' ') Then
	        Else If 
     $            (
     $             (IP_Number(X:X) .ge. '0')
     $            .and. 
     $             (IP_Number(X:X) .le. '9')
     $		  ) 
     $            Then
	          IP = 10 * IP + IChar(IP_Number(X:X)) - IChar('0')
	        EndIF
	      EndDo
	      Server_IP_Number(I) = IP_Byte
	    ElseIf (Img(1:X) .eq. ' ') Then

	    Else
	      Call SMG_All_Print
     $	        ('Unrecognized initialization image', '|')
	      Call SMG_All_Print (Img(1:Img_Lg), '|')
	      Stop
	    EndIf
	  Else
	    Eof = .true.
	  EndIf
	EndDo

	Close (LU_Init)

	Return

	End ! Read_Init


	Subroutine Field (Src, Src_X, Dst)

	Implicit None

C Parameter definition

	Character *(*)	Src,Dst
	Integer   *4	Src_X

C Local definitions

	Integer   *4	Src_Lg, Dst_Lg, Dst_X
	Logical		Done

C Begin Field

	Done = .false.
	Src_Lg = Len (Src)
	Dst_Lg = Len (Dst)
	Dst_X = 1
	Dst= ' '

	Do While ((.not. Done) .and. (Src_X .le. Src_Lg))
	  If (Src(Src_X:Src_X) .eq. ' ') Then

	  Else If (Src(Src_X:Src_X) .eq. ',') Then
	    Done = .true.
	  Else
	    If (Dst_X .le. Dst_Lg) Then
	      Dst(Dst_X:Dst_X) = Src(Src_X:Src_X)
	      Dst_X = Dst_X + 1
	    EndIf
	  EndIf
	  Src_X = Src_X + 1
	EndDo

	End ! Field


	Subroutine Unavail_Print (S,E)

	Implicit None

	Integer   *4	S, E

C Local definitions

	Character *8	S_C, E_C
	Integer   *4	S_Lg, E_Lg

C Begin Unavail_Print

	Call ItoS (S, S_C, S_Lg)
	If (E .eq. S) Then
	  Call SMG_All_Print
     $	    (
     $	     'Skipped unavailable article ' //
     $	       S_C(1:S_Lg),
     $	     '|'
     $      )
	Else
	  Call ItoS (E, E_C, E_Lg)
	  Call SMG_All_Print
     $	    (
     $	     'Skipped unavailable articles ' //
     $	       S_C(1:S_Lg) // '-' // E_C(1:E_Lg),
     $	     '|'
     $      )
	EndIf

	S = 0
	E = 0

	End ! Unavail_Print


       Integer Function GetUserName (UserId)

C Description:
C
C   Function to obtain the user's name
C   Returns success or failure.

	Include 'News.Def'

C Parameter Definitions

       Character *32	UserId

C External Routines

       External Sys$GetJPI
       Integer  Sys$GetJPI

C Local Definitions

       Include '($JPIDEF)'

       Character 	*32		LUserId
       Integer		*4		LUserIdLg

       Integer		*2 		WJPIItmLst(12)
       Integer 		*4		JPIItmLst(6)
       Equivalence 			(JPIItmLst,WJPIItmLst)

C Begin GetUserName

       WJPIItmLst(1) = 32
       WJPIItmLst(2) = JPI$_UserName
       JPIItmLst(2)  = %Loc(LUserId)
       JPIItmLst(3)  = %Loc(LUserIdLg)
       JPIItmLst(4)  = 0

       GetUserName = Sys$GetJPI (,,,JPIItmLst,,,)
       If (GetUserName) Then
         UserId = LUserId(1:LUserIdLg)
	 Call Down_Case (UserName)
       EndIf

       Return

       End ! GetUserName


	Integer Function GetUserDirectory (Dir)

	Include 'News.Def'

C Parameter definitions

	Character *(*) Dir

C External definitions

        Integer  Sys$GetUAI
        Integer  TrimLg

C Local Definitions

        Include '($UAIDEF)'

        Character	*16		Device
        Integer		*4		DeviceLg
        Character	*64		Directory
        Integer		*4		DirectoryLg
        Integer		*4		DirItmLst(9)
        Integer		*2		WDirItmLst(18)
        Equivalence      		(DirItmLst,WDirItmLst)

C Begin GetUserDirectory

        WDirItmLst(1) = 64
        WDirItmLst(2) = UAI$_DefDir
        DirItmLst(2)  = %Loc(Directory)
        DirItmLst(3)  = %Loc(DirectoryLg)
        WDirItmLst(7) = 16
        WDirItmLst(8) = UAI$_DefDev
        DirItmLst(5)  = %Loc(Device)
        DirItmLst(6)  = %Loc(DeviceLg)
        DirItmLst(7)  = 0

        GetUserDirectory = Sys$GetUAI (,,UserName,DirItmLst,,,)
        If (GetUserDirectory) Then
        Else
         Return
        EndIf

        DeviceLg = IChar(Device(1:1))
        DirectoryLg = IChar(Directory(1:1))

        Dir = Device(2:DeviceLg+1) // 
     1        Directory(2:DirectoryLg) //
     2	      '.NEWS]'

	Return 

	End ! GetUserDirectory


	Integer Function Group_Find (Name)

	Include 'News.Def'

C Parameter definition

	Character *(*)	Name

C Local definitions

	Integer   *4	I

C Begin Group_Find

	Group_Find = 0

	I = 1
	Do While ((I .le. Group_Count) .and. (Group_Find .eq. 0))
	  If (Name .eq. Group(I).Name) Then
	  Group_Find = I
	Else
	  I = I + 1
	  EndIf
	EndDo

	Return

	End ! Group_Find


	Subroutine Cmd_GroupNone

	Implicit None

	Call SMG_All_Print ('No group selected.', '|')

	End ! Cmd_GroupNone


	Subroutine Cmd_GroupList (Cmd)

	Include 'News.Def'

C Parameter definition

	Character *(*)		Cmd

C External routines

	Logical			SMG_More_Print
	Integer			Str$Match_Wild
	Integer			TrimLg
	
C Local definitions

	Character *1		Active
	Logical			Any
	Integer   *4		G
	Character *80		Text
	Integer   *4 		R
	Character *1		Subscribed
	Logical			Ok
	Character *32		Pattern
	Character *1 		Post
	Integer	  *4		X

C Begin Cmd_GroupList

	Pattern = ' '
	X = Index (Cmd,' ')
	If (X .ne. 0) Then
	  Do While ((X .lt. Len(Cmd)) .and. (Cmd(X:X) .eq. ' '))
	    X = X + 1
	  EndDo
	  Pattern = Cmd(X:Len(Cmd))
	  Call Down_Case (Pattern)
	EndIf

	Ok = .true.
        G = 0
	Any = .false.
	Do While (Ok .and. (G .lt. Group_Count))

	  G = G + 1

	  If
     $      (
     $       (Pattern .eq. ' ') 
     $      .or.
     $       (
     $        Str$Match_Wild
     $          (
     $		 Group(G).Name(1:TrimLg(Group(G).Name)),
     $           Pattern(1:TrimLg(Pattern))
     $          )
     $	     )
     $      )
     $    Then

	    Any =.true.

	    If (Group(G).Subscribed) Then
	      Subscribed = 'y'
	    Else
	      Subscribed = 'n'
	    EndIf

	    If (Group(G).Active_File) Then
	      Active = 'y'
	    Else
	      Active = 'n'
	    EndIf

	    If (Group(G).Active_Post) Then
	      Post = 'y'
	    Else
	      Post = 'n'
	    EndIf

            Write (Text,'(4(x,A),2I7)')
     $        Group(G).Name,
     $        Active,
     $        Subscribed,
     $        Post,
     $        Group(G).Active_Start,
     $        Group(G).Active_End

	    Ok = SMG_More_Print (Text, '|')

	    R = Group(G).Range_First
	    Do While (Ok .and. (R .ne. 0))
	      Write (Text, '(x,I,A,I)')
     $	        Range(R).Start, ':', Range(R).End
	      Ok = SMG_More_Print (Text, '|')
	      R = Range(R).Next
	    End Do

	  EndIf

	EndDo

	If (.not. Any) Then
	  Call SMG_All_Print 
     $      (
     $       'No groups matching ' // Pattern(1:TrimLg(Pattern)) //
     $       ' found.',
     $       '|'
     $      )
	EndIf

	Return

	End ! Cmd_GroupList

	
	Subroutine Cmd_ArticleList (G, CatchUp_Cmd)

	Include 'News.Def'
	Include 'SMG.Def'

C Description
C
C   Handles the....
C
C     Dir [article]
C
C   command.  Produces a short list of the subject lines
C   of un read articles in the group starting with article.
C   Default article is first available from the active file.

C Parameter definitions

	Integer   *4	G
	Character *(*)	CatchUp_Cmd

C External Routines

	Integer   	Range_Find
	Integer   	Srv_Cmd
	Integer		Srv_RdTxt
	Integer		TrimLg

C Local definitions

	Integer   *4	A
	Integer   *4	X
	Integer   *4	Subject_Lg
	Character *128  Subject
	
C Begin Cmd_ArticleList

	Call More_Heading
	More_Input = ' '

C Get the article number

	X = Index (CatchUp_Cmd, ' ')
	A = 0
	Do While ((X .ne. 0) .and. (X .le. Len(CatchUp_Cmd)))
	  If
     $      (
     $       (CatchUp_Cmd(X:X) .ge. '0')
     $      .and.
     $       (CatchUp_Cmd(X:X) .le. '9')
     $      )
     $    Then
	    A = 10 * A + IChar(CatchUp_Cmd(X:X)) - IChar('0')
	  EndIf
	  X = X + 1
	EndDo

	If (A .eq. 0) Then
	  A = Group(G).Active_Start
	EndIf

C Get all the subject lines

	Do While
     $    (
     $     (A .le. Group(G).Active_End)
     $    .and. 
     $     (More_Input .eq. ' ')
     $    )

	  If (Range_Find (G, A, .false.) .eq. 0) Then

	    Call CacheHdr (G, A, Subject, Subject_Lg)
	    Call SMG_More_Print (Subject(1:Subject_Lg), '|')

	  EndIf

	  A = A + 1

	End Do

	Return

	End ! Cmd_ArticleList


	Subroutine Cmd_ArticleMark (G, A, U)

	Include 'News.Def'

C Parameter definition

	Integer   *4	G		! Group number
	Integer   *4 	A		! Article number
	Integer   *4	U		! Unread article count, updated

C External routines

	Integer		Range_Allocate

C Local definitions

	Logical		Found
	Integer   *4	P, Q, R

C Begin Cmd_ArticleMark

C Find range contining this article

	Found = .false.
	P = 0
	R = Group(G).Range_First
	Do While ((.not. Found) .and. (R .ne. 0))
	  If ((A .ge. Range(R).Start) .and. (A .le. Range(R).End)) Then
	    Found = .true.
	  Else
	    P = R
	    R = Range(R).Next
	  EndIf
	EndDo

C If no range found for this article, then we are done since its already
C marked as unread.

	If (.not. Found) Then
	  Return
	EndIf

C Range found, three cases can arise

	If (A . eq. Range(R).Start) Then

C Article is first in range

	  Range(R).Start = Range(R).Start + 1

	ElseIf (A .eq. Range(R).End) Then

C Article is last in range

	  Range(R).End = Range(R).End - 1

	Else

C Article is within the range but not at either end point

C Get a new range and set it up from the old start through A - 1

	  Q = Range_Allocate ()
	  Range(Q).Start = Range(R).Start
	  Range(Q).End = A - 1

C The old range becomes the end of the range from A+1 through the old end

	  Range(R).Start = A + 1

C Chain P -> Q -> R

	  Range(Q).Next = R
	  If (P .ne. 0) Then
	    Range(P).Next = Q
	  Else
	    Group(G).Range_First = Q
	  EndIf

	  P = Q	

	EndIf

C Now, we may have left a nonsense group at R

	If (Range(R).Start .gt. Range(R).End) Then
	  If (P .ne. 0) Then
	    Range(P).Next = Range(R).Next
	    If (Group(G).Range_Last .eq. R) Then
	      Group(G).Range_Last = P
	    EndIf
	  Else
	    Group(G).Range_First = Range(R).Next
	    If (Group(G).Range_Last .eq. R) Then
	      Group(G).Range_Last = Group(G).Range_First
	    EndIf
	  EndIf

	  Range(R).Next = 0
	  Call Range_Deallocate (R)

	EndIf

C Finally, update unread count

	U = U + 1

C That's all folks

	Return

	End ! Cmd_ArticleMark


	Subroutine Cmd_ArticlePost (G, Cmd)

	Include 'News.Def'

C Parameter definitions

	Integer   	G	! Group number
	Integer         A	! Article number
        Character       *(*)Cmd ! Command text
C External routines

	Integer		Edt$Edit
	Integer		Group_Find
	Integer		SMG_Prompt
	Integer		Srv_Cmd
	Integer		Srv_Recv
	Integer		Srv_Send
	Integer		TrimLg
	Integer		User_Edit

C Local definitions

	Character *22			Date_Time
	Character *128			Distribution_Fld
	Logical				Eof
	Character *(File_Name_Size)	File_In
	Character *(File_Name_Size)	File_Out
	Character *32			Fld
	Logical				FollowUp
	Character *128			From
	Character *128			Group_Name
	Integer   *4			Group_Name_Lg
	Integer   *4			I
	Character *256			Img
	Integer	  *4			Img_Lg
	Logical   *4			InHeader
	Character *128			MessageID
        Logical   *4			Rotx
	Integer   *4			Status
	Character *128			Subject
	Integer   *4			Subject_Lg
	Integer   *4			X
	
C Begin Cmd_ArticlePost

	FollowUp = .false.

	Group_Name = ' '
	Group_Name_Lg = 0
	Subject = ' '
	Distribution_Fld = ' '

	Goto 1

C Begin Cmd_ArticleFollowUp

	Entry Cmd_ArticleFollowUp (G, A, Cmd)

	FollowUp = .true.
	Write (Img, '(A,I8)') 'head ', A
	Status = Srv_Cmd (Img(1:13), Img, Img_Lg)
	If (.not. Status) Then
	  Call SMG_All_Print ('Server failed', '|')
	  Stop
	EndIf
	If (Img(1:3) .ne. '221') Then
	  Call SMG_All_Print ('Unexpected server reply', '|')
	  Call Smg_All_Print (Img(1:Img_Lg), '|')
	  Stop
	EndIf

	From = ' '
	Group_Name = ' '
	Group_Name_Lg = 0
	MessageID = ' '
	Subject = ' '
	Distribution_Fld = ' '

	Do While (Img(1:Img_Lg) .ne. '.')
	  Status = Srv_Recv (Img, Img_Lg)
	  If (.not. Status) Then
	    Call SMG_All_Print ('Server failed', '|')
	    Stop
 	  EndIf
	  If (Img(1:13) .eq. 'Distribution:') Then
	    If (Img_Lg .ge. 15) Then
	      Distribution_Fld = Img(15:Img_Lg)
	    EndIf
	  Else If (Img(1:8) .eq. 'Subject:') Then
            If (Img_Lg .ge. 10) Then
 	      Subject = Img(10:Img_Lg)
	      If (Subject(1:4) .ne. 'Re: ') Then
	        Subject = 'Re: ' // Subject
	      EndIf
            EndIf
	  ElseIf (Img(1:11) .eq. 'Newsgroups:') Then
	    If (Img_Lg .ge. 13) Then
	      Group_Name = Img(13:Img_Lg)
	      Group_Name_Lg = Img_Lg - 12
	    EndIf
	  ElseIf (Img(1:5) .eq. 'From:') Then
	    If (Img_Lg .ge. 7) Then
	      From = Img(7:Img_Lg)
	    EndIf
	  ElseIf (Img(1:11) .eq. 'Message-ID:') Then
	    If (Img_Lg .ge. 13) Then
	      MessageID = Img(13:Img_Lg)
	    EndIf
	  EndIf
	EndDo
	Goto 1

C Begin common Cmd_ArticlePost - Cmd_ArticleFollowUp

1	If ((Len(Cmd) .lt. 3) .or. (Cmd(2:3) .ne. '/x')) Then
	  Rotx = .false.
	Else
	  Rotx = .true.
	EndIf

	File_In = 'Sys$Login:News$In.News'
	File_Out = 'Sys$Login:News$Out.News'
	Call Smg_Erase

C Get group to post to

	If (Group_Name_Lg .eq. 0) Then

	I = 0
	Do While (I .eq. 0)

	  Status = SMG_Prompt
     $      (
     $	     Group_Name, 
     $       'Group (' // Group(G).Name(1:TrimLg(Group(G).Name))
     $	       // ') ',
     $       Group_Name_Lg
     $      )
	  If (.not. Status) Then
	    Call SMG_All_Print ('Post aborted.', '|')
	    Return
	  EndIf

C Make sure group is legal

	  If (Group_Name(1:Group_Name_Lg) .eq. ' ') Then
	    Group_Name = Group(G).Name
	    Group_Name_Lg = TrimLg(Group(G).Name)
	    I = G
	  Else
	    I = Group_Find (Group_Name(1:Group_Name_Lg))
	    If (I .eq. 0) Then
	      Call SMG_All_Print
     $	        (
     $	         'No such group as ' // Group_Name(1:Group_Name_Lg),
     $           '|'
     $	        )
	    EndIf
	  EndIf

	EndDo

	EndIf

C Get subject

	If (Subject .eq. ' ') Then
	  Status = SMG_Prompt (Subject, 'Subject: ', Subject_Lg)
	  If (.not. Status) Then
	    Call SMG_All_Print ('Post aborted.', '|')
	    Return
	  EndIf
	EndIf

C Get distribution 

	If (Distribution_Fld .eq. ' ') Then

	Distribution_Fld = ' '
        Status = SMG_Prompt (Img, 'Distribution: ', Img_Lg)
	X = 1
	Do While (X .le. Img_Lg)
	  Call Field (Img(1:Img_Lg), X, Fld)
	  If (Fld .ne. ' ') Then
	    I = 1
	    Do While
     $        (        
     $         (I .le. Distribution_Count) 
     $        .and.
     $         (Distribution(I) .ne. Fld)
     $       )
	      I = I + 1
	    EndDo
	    If (I .le. Distribution_Count) Then
	      If (Distribution_Fld .ne. ' ') Then
	        Distribution_Fld =
     $            Distribution_Fld(1:TrimLg(Distribution_Fld)) // ', '
	      EndIf
	      Distribution_Fld =
     $          Distribution_Fld(1:TrimLg(Distribution_Fld)) // Fld
	    Else
	      Call SMG_All_Print
     $	        (
     $           'Illegal Distribution field ' // Fld(1:TrimLg(Fld)),
     $		 '|'
     $          )
              Return
	    EndIf
	  EndIf
	EndDo

	EndIf

C Build date and time header

	Date_Time = ' '
	Call Date (Date_Time(1:9))
	Call Time (Date_Time(11:18))
	Date_Time(3:3) = ' '
	Date_Time(7:7) = ' '

C Open the edit input file

	Open 
     $    (
     $     Unit			= LU_EditIn,
     $	   File			= File_In,
     $     Status		= 'New',
     $     Form			= 'Formatted',
     $     CarriageControl	= 'List',
     $     Recl 		= 1024,
     $     IOStat		= Status
     $    )

	If (Status .ne. 0) Then
	  Call SMG_All_Print
     $      (
     $       'Error opening file ' // File_In(1:TrimLg(File_In)) //
     $	        '.  Post aborted.', '|'
     $	    )
	  Return
	EndIf

C Write the article header

	If (UserPersonalName .ne. ' ') Then
	  Write (LU_EditIn, '(A)')
     $      'From: ' //
     $      UserName(1:TrimLg(UserName)) // 
     $	    SiteId(1:TrimLg(SiteId)) //
     $	    ' (' //
     $      UserPersonalName(1:TrimLg(UserPersonalName)) //
     $      ')'
	Else
	  Write (LU_EditIn, '(A)')
     $      'From: ' //
     $      UserName(1:TrimLg(UserName)) // 
     $	    SiteId(1:TrimLg(SiteId))
	EndIf

	Write (LU_EditIn, '(A)') 'Newsgroups: ' //
     $                            Group_Name(1:Group_Name_Lg)

	Write (LU_EditIn, '(A)') 'Subject: ' // Subject(1:TrimLg(Subject))

	Write (LU_EditIn, '(A)') 'Date: ' // Date_Time

	If (Distribution_Fld .ne. ' ') Then
	  Write (LU_EditIn, '(A)') 'Distribution: ' // 
     $      Distribution_Fld(1:TrimLg(Distribution_Fld))
	EndIf

	Write (LU_EditIn, '(A)') 'Organization: ' //
     $    Organization(1:TrimLg(Organization))

	Write (LU_EditIn, '(A)') ' '

	If (FollowUp) Then
	  Write (LU_EditIn, '(A)')
     $      'In article ' // MessageID(1:TrimLg(MessageID)) // ', ' //
     $      From(1:TrimLg(From)) // ' writes...'
	  Write (LU_EditIn, '(A)') ' '
	EndIf

C If followup, copy the article to the file

	If (Followup) Then

	  Write (Img, '(A,I8)') 'body ', A
	  Status = Srv_Cmd (Img(1:13), Img, Img_Lg)
	  If (.not. Status) Then
	    Call SMG_All_Print ('Server failed', '|')
	    Stop
	  EndIf
	  If (Img(1:3) .ne. '222') Then
	    Call SMG_All_Print ('Unexpected server reply', '|')
	    Call Smg_All_Print (Img(1:Img_Lg), '|')
	    Stop
	  EndIf

	  Call Srv_CopyTxt (LU_EditIn, Mark_Character, Rotated)

	EndIf

C Copy Signature file if any

	Open
     $    (
     $     Unit			= LU_Signature,
     $	   File         	= 'SIGNATURE.MAI',
     $     DefaultFile		= UserMailDirectory,
     $     Form			= 'Formatted',
     $     CarriageControl	= 'None',
     $     Status		= 'Old',
     $     ReadOnly,
     $	   IOStat		= Status
     $    )

	If (Status .eq. 0) Then
	  Do While (Status .eq. 0)
	    Read
     $        (
     $	       Unit 		= LU_Signature,
     $         Fmt		= '(Q,A)',
     $         IOStat		= Status
     $        ) Img_Lg, Img
	    If (Status .eq. 0) Then
	      Write (LU_EditIn, '(A)') Img(1:Img_Lg)
	    EndIf
	  EndDo
	  Close (LU_Signature)
	EndIf

C Done building edit input file

	Close (LU_EditIn)

C Edit the file

	If (.not. Mail_Cmd_Mail$Edit) Then
	  Status = Edt$Edit (File_In,File_Out,,,4,,,)
	Else
	  Status = User_Edit (File_In, File_Out)
	EndIf

	Call SMG_Erase
	If (.not. Status) Then
	  Call Smg_All_Print
     $      (
     $	     ' Error editing file, post aborted.', '|'
     $      )
	  Return
	EndIf

C Open the output file

	Open 
     $    (
     $     Unit			= LU_EditOut,
     $	   File			= File_Out,
     $     Status		= 'Old',
     $     IOStat		= Status,
     $     Dispose		= 'Delete'
     $    )

	If (Status .ne. 0) Then
	  Call SMG_All_Print
     $      (
     $       'Error opening file ' // File_Out(1:TrimLg(File_Out)) //
     $	        '.  Post aborted.', '|',
     $	    )
	  Return
	EndIf

C Start a post command on the server

	Status = Srv_Cmd ('post', Img, Img_Lg)
	If (.not. Status) Then
	  Call SMG_All_Print ('Server failed', '|')
	  Stop
	EndIf

	If (Img(1:3) .eq. '340') Then

C Copy the file to the server postnews process

	  Call SMG_All_Print ('Sending article to server', '|')
	  Call SMG_All_Print (Img(1:Img_Lg), '|')

	  InHeader = .true.
	  Eof = .false.
	  Do While (.not. Eof)

	    Read 
     $        (
     $         Unit	= LU_EditOut,
     $         Fmt	= '(Q,A)',
     $         IOStat	= Status
     $        ) Img_Lg, Img

	    If ((Img_Lg .eq. 0) .or. (Img(1:Img_Lg) .eq. ' ')) Then
	      InHeader = .false.
	    EndIf

	    If ((.not. InHeader) .and. RotX) Then
	      Call Rotate (Img(1:Img_Lg))
	    EndIf

            If (Status .eq. 0) Then
	      If (Img(1:Img_Lg) .eq. '.') Then
		Img = '..'
		Img_Lg = 2
	      EndIf
	      Status = Srv_Send (Img(1:Img_Lg))
	      If (.not. Status) Then
		Call SMG_All_Print ('Server failed.', '|')
		Stop
	      EndIf
c	      Call Smg_All_Print (Img(1:Img_Lg), '|')
	    Else
	      Eof = .true.
	    EndIf
 	  EndDo

C Mark end of input with a .

	  Status = Srv_Send ('.')
	  If (.not. Status) Then
	    Call SMG_All_Print ('Server failed.', '|')
	    Stop
	  EndIf

C Retrieve final status

	  Status = Srv_Recv (Img, Img_Lg)
	  If (.not. Status) Then
	    Call SMG_All_Print ('Server failed', '|')
	    Stop
	  EndIf

	  Call SMG_All_Print (Img(1:Img_Lg), '|')

C Server not accepting postings

	Else

	  Call SMG_All_Print ('Server refusing posting requests.', '|')
	  Call SMG_All_Print (Img(1:Img_Lg), '|')

	EndIf

C Close the edit output file

	Close (LU_EditOut)

C Return

	Return

	End ! Cmd_ArticlePost


	Subroutine Cmd_ArticleSave (G, A, Cmd)

	Include 'News.Def'

C Description
C
C   Handles the S filename command.
C

C Parameter definitions

	Integer   *4	G		! Group number
	Integer   *4	A		! Article number
	Character *(*)	Cmd		! Save command line

C External routines

	Integer		Srv_Cmd
	Integer		Srv_Recv
	Integer		Lib$Create_Dir
	Integer		TrimLg
	Integer		User_Open
	External	User_Open
	Integer		User_Open_Get_What_Happened

C Local definitions

	Character *64	FileName
	Character *128  Buf
	Logical		FirstDot
	Integer   *4	Lg
	Integer   *4	Status
	Integer	  *4	X
	Logical 	SecondTry
	Character *128  Msg
	Logical 	FileOpen

C Begin Cmd_ArticleSave

C Get the file name from the command line

	X = 1
	Lg = Len(Cmd)
	Call GetField (FileName, Cmd, X, Lg)
	Call GetField (FileName, Cmd, X, Lg)

C If user specified no file name, build default from group name

	If (FileName .eq. ' ') Then
	  FileName = Group(G).Name
	  FirstDot = .true.
	  X = 1
	  Lg = TrimLg (FileName)
          Do While (X .le. Lg)
	    If (FileName(X:X) .eq. '.') Then
	      If (FirstDot) Then
	        FirstDot = .false.
	      Else
	        FileName(X:X) = '_'
	      EndIf
	    EndIf
	    X = X + 1
	  EndDo
	EndIf

C Open the file

	FileOpen = .false.
	SecondTry = .false.	

	Do While (.not. FileOpen)
	Call User_Open_Init ('STATUS_UNKNOWN',0,0,0,0,0,0,0,0)
	Open
     $    (
     $     Unit		   = LU_Save,
     $	   File	 	   = FileName,
     $     DefaultFile     = UserDirectory,
     $     Status	   = 'Unknown',
     $	   Form		   = 'Formatted',
     $     CarriageControl = 'List',
     $     Recl		   = 1024,
     $     Access	   = 'Append',
     $     UserOpen	   = User_Open,
     $     IOStat	   = Status
     $    )

	If (Status .ne. 0) Then
	  If 
     $      (
     $       (Index(FileName,':') .eq. 0)
     $      .and.
     $       (Index(FileName,'[') .eq. 0)
     $      .and.
     $       (.not. SecondTry)
     $      ) Then
	    SecondTry = .true.
	    Status = Lib$Create_Dir
     $	      (
     $         UserDirectory(1:TrimLg(UserDirectory)),	! Name
     $         ,					! Owner
     $	       'FF00'X,					! Prot enable
     $	       'FF00'X,					! Prot mask
     $	       ,					! Max versions
     $							! Rvn
     $        )
	    If (Status) Then
	      Call SMG_All_Print
     $		('Created directory ' // 
     $             UserDirectory(1:TrimLg(UserDirectory)),
     $	         '|'
     $	        )
	    Else
	      Call SMG_All_Print
     $		('Error creating directory ' // 
     $             UserDirectory(1:TrimLg(UserDirectory)),
     $	         '|'
     $	        )
	      Return
	    EndIf
          Else
	    Call SMG_All_Print
     $        (
     $         'Error opening file ' // FileName(1:TrimLg(FileName)),
     $         '|'
     $        )
	    Return
	  EndIf
	Else
	  FileOpen = .true.
	EndIf

	End Do

	If (.not. Srv_Cmd('head',Buf,Lg)) Then
	  Call SMG_All_Print ('Server failed', '|')
	  Stop
	EndIf

	If (Buf(1:3) .ne. '221') Then
	  Call SMG_All_Print ('Unexpected server response', '|')
	  Call SMG_All_Print (Buf(1:Lg), '|')
	  Stop
	EndIf

	Call Srv_CopyTxt (LU_Save, ' ', .false.)

	If (.not. Srv_Cmd('body',Buf,Lg)) Then
	  Call SMG_All_Print ('Server failed', '|')
	  Stop
	EndIf

	Write (LU_Save, '(A)') ' '

	If (Buf(1:3) .ne. '222') Then
	  Call SMG_All_Print ('Unexpected server response', '|')
	  Call SMG_All_Print (Buf(1:Lg), '|')
	  Stop
	EndIf

	Call Srv_CopyTxt (LU_Save, ' ', Rotated)

	Msg = 'Article '
	Call ItoS (A, Msg(9:Len(Msg)), Lg)
	Lg = 8 + Lg
	If (User_Open_Get_What_Happened() .eq. 1) Then
          Msg (Lg+1:Len(Msg)) = ' appended'
	  Lg = Lg + 9
	Else
	  Msg (Lg+1:Len(Msg)) = ' saved'
	  Lg = Lg + 6
	EndIf
	Msg (Lg+1:Len(Msg)) = ' to file ' // FileName
	Lg = TrimLg(Msg)

	Call SMG_All_Print (Msg(1:Lg), '|')

	Close (LU_Save)
        Return

	End ! Cmd_ArticleSave


	Logical Function Cmd_ArticleCatchUp (G, A, Cmd, U)

	Include 'News.Def'

C Description
C
C   Handles the catchup command...
C
C     Catchup [article]
C
C   Marks all articles through and including article as read.  
C   Default article is last article in the group.
C
C   Returns:
C
C     .true.  all articles read
C     .false. some articles remain

C Parameter definitions

	Integer   *4	G		! Group number
	Integer   *4	A		! Article
	Character *(*)	Cmd		! Catchup command string
	Integer   *4	U		! Unread article count, updated

C External routines

	Integer		Range_Allocate
	Integer		UnRead

C Local definitions

	Integer   *4	L, R, X

C Begin Cmd_ArticleCatchUp

C Get the last article to be caught up from the command

	X = Index (Cmd, ' ')
	L = 0
	Do While ((X .ne. 0) .and. (X .le. Len(Cmd)))
	  If ((Cmd(X:X) .ge. '0') .and. (Cmd(X:X) .le. '9')) Then
	    L = 10 * L + IChar(Cmd(X:X)) - IChar('0')
	  EndIf
	  X = X + 1
	EndDo

C If no last article, use entire group active file range

	If (L .eq. 0) Then
	  L = Group(G).Active_End
	EndIf

C Calulate return value
%%end part b
Michael Dorl (608) 262-0466
dorl@vms.macc.wisc.edu
dorl@wiscmacc.bitnet