[comp.sources.atari.st] v02i026: mailtruk -- GFA BASIC uucp software

koreth@ssyx.ucsc.edu (Steven Grimm) (03/12/89)

Submitted-by: john@logajan.mn.org (John Logajan)
Posting-number: Volume 2, Issue 26
Archive-name: mailtruk

Below are five files generically named MailTruk Release V1.0.
MailTruk is a GFA Basic (2.0) implementation of uucp/uucico.
MailTruk is intended to allow non-unix/non-C Atari ST's email
access to the Usenet community.

#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#	Run the following text with /bin/sh to create:
#	  mailtruk.doc
#	  mailtruk.lst
#	  protocol.doc
#	  readmail.lst
#	  writmail.lst
#
sed 's/^X//' << 'SHAR_EOF' > mailtruk.doc &&
X
X                      MailTruk Documentation
X                                by
X                    John Logajan, January 1989
X                         4248 Hamline Ave
X                      Arden Hills, MN  55112
X                       john@logajan.mn.org
X
X
XINTRODUCTION TO THE NETWORK
X
XWelcome to the world of uucp style data exchange.  Uucp stands for 
XUnix to Unix copy.  Unix is an operating system used by a large 
Xnumber of computers.  A large network of computers running uucp 
Xcompatible data exchange has evolved over the last several years.  
XThis network encompasses university, corporate, governmental, and 
Xindividually owned computers.  It is estimated that there are over 
X10,000 computers on the net, with approximately 400,000 users.  
XThe two primary functions of the net are private electronic mail 
Xand "broadly cast" electronic news transfer.  The Usenet News 
Xconsists of some 350 subject categories into which several 
Xthousand articles a day are posted by users.  An average day's 
Xnews is typically four million characters -- and growing.  Anyone 
Xreceiving a full newsfeed is more and more feeling the need for 
Xfaster data communications links, since such volume at 2400 baud 
Xrequires five hours if uncompressed or 2.5 hours if compressed. 
X
X
XINTRODUCTION TO THE MAILTRUK, READMAIL, AND WRITMAIL PROGRAMS
X
XMailTruk, ReadMail, and WritMail are uucp compatible 
Xcommunications programs that run on Atari ST computers.   The 
Xprograms are written in GFA Basic (2.0) and are freely distributed 
Xas a readable listings in the public domain.  Files included in 
Xthe distribution include:
XMAILTRUK.LST, READMAIL.LST, WRITMAIL.LST, MAILTRUK.DOC, 
XPROTOCOL.DOC
X
XWritMail is used to write your outgoing mail.  Writmail's main 
Xtask is to format your message so that other computers on the net 
Xrecognize what you have sent and where it is going.  Each, in 
Xturn, passes it along until it hopefully reaches your intended 
Xrecipient.
X
XMailTruk is the actual communications program.  It first dials 
Xyour neighbor site, establishes protocol agreement, and then sends 
Xthe messages, if any, that you have previously prepared with 
XWritMail.  When MailTruk has finished sending, it requests to 
Xreceive any mail that the remote site has pending for you.  After 
Xit receives all incoming mail, MailTruk terminates the connection.
X
XReadMail allows you to read your mail in a convenient manner.  The 
Xmain objection to reading you mail files directly with GEM 
Xcommands is that Unix machines use linefeed characters as end-of-
Xline indicators rather than the carriage return character used by 
XGEM.  Thus, direct reading of mail files results in a confusing 
Xpresentation.
X
XAlthough MailTruk can transfer the file types used to send the 
XNetwork News, additional file pre- and post-processing is required 
Xto read or write News articles.  ReadMail and WritMail DO NOT 
Xhandle the News format.  Uncompressed News would be a fairly 
Xstraight forward task to handle, but compressed and batched News 
Xwill require additional sophistication.  Let me know if you feel 
Xmotivated to write such a program!
X
X
XSETTING EVERYTHING UP
X
XFirst -- You need a site to call, account information for that 
Xsite, and a modem.  Since this program is being distributed over 
Xthe net, if you track back from where this program came from, 
Xyou're bound to run into somebody who knows your local net 
Xarrangement.  (I pay $25 a year to a guy who runs a "domain park" 
Xfor my access.  He, in turn, calls other bigger sites -- and so 
Xon.)
X
XSecond -- All mail going to a particular site is placed in its own 
Xdirectory.  All mail coming to your site is placed in its own 
Xdirectory.  You should create these directories before running the 
Xprograms.  I am site -logajan-, I call one site -bungia-.  So, I 
Xcreated a directory called MAIL on my C: drive where I put all my 
Xprograms, and I created two sub-directories, BUNGIA and LOGAJAN, 
Xi.e. C:\MAIL\BUNGIA\
X     C:\MAIL\LOGAJAN\
X
XThird -- All three programs are totally self-contained in that 
Xthey do not share an external common configuration file.  So you 
Xwill have to insure that each of the important variables, 
Xincluding the directory names mentioned above, in each of the 
Xprograms is correct and consistent.  The variables are grouped 
Xnear the beginning of each program.  You WILL have to customize 
Xthese variables for these programs to work!
X
XFourth -- If you have multiple sites to call, you will have to 
Xmake multiple versions of the MailTruk program (or modify it to 
Xhandle multiple cases.)  You will also want to write a program 
Xthat recognizes messages which are just passing through, and 
X"rewrites" the pertinent addresses, and places them back out in 
Xthe outbound message area.
X
XFifth -- Otherwise you are a "leaf" site (you only call one 
Xmachine) and any mail with your machine name in it is assumed to 
Xbe to you, no matter what user name or additional path is in the 
XTo: address line.
X
XSixth -- Paths; the From: and To: portion of messages; are a 
Xsomewhat mysterious subject.  Basically you have to know, at a 
Xminimum, the recipient's user-name and machine-name, and the path 
Xto the nearest smart mailer site.   Otherwise you can specify the 
Xentire path -- but some smart sites end up sending it the route 
Xthey think is best anyhow.
X
X  If I want to send to jack at atari, I enter the path as:
X     bungia!atari!jack     Note:  nearest!next!next!farthest!user
X     (my neighbor, bungia, knows the tortuous route to atari)
X
X  or bungia!umn-cs!rutgers!att.att.com!wally if I want to get to
X     wally at att and know the complete path.
X
XYou will often see @'s and %'s in paths.  Basically you just read 
Xthese in the other direction, i.e.:
X
X     john@logajan.mn.org@bungia@shamash@nic.mr.net   is an actual
X     path TO my machine from nic.mr.net.
X
XHowever, note that WritMail forces you to state the path with at 
Xleast one (!) symbol.  Your neighbor's machine is always the first 
Xname in the path, therefore you could do:
X
X     bungia!ben@franklin.electric.com
X
X
XSeventh -- Hopefully there is enough information in the listings 
Xfor you to set up your own site and get it operational.
X                           Good luck.
X
SHAR_EOF
chmod 0600 mailtruk.doc || echo "restore of mailtruk.doc fails"
sed 's/^X//' << 'SHAR_EOF' > mailtruk.lst &&
XRem  MAILTRUK V1.0 -- GFA Basic 2.0 / Atari ST implementation of uucp/uucico.
XRem                      --- PUBLIC DOMAIN ---
XRem  This program dials up computer sites running Unix or Unix clone uucp,
XRem      allowing the transfer of e-mail, news and other data files.
XRem
XRem       Totally original code by:  John Logajan, January 1989.
XRem                                  4248 Hamline Ave
XRem                                  Arden Hills, MN 55112
XRem      (john@logajan.mn.org  or  ...rutgers!bungia!logajan!john)
XRem
XRem    The next eight lines must be customized for each user/site.
XRem
XMysite$="logajan"              ! Your site machine name.  (You choose!)
XMyuser$="logajan"              ! Your user/account name for remote site.
XMypw$="youguess"               ! Your password for remote site.
XSitedir$="\mail\bungia"        ! Directory of files to send only to that site.
XSitercv$="\mail\"+Mysite$      ! Directory for all incoming files.
XSiteph$="123-4567"             ! Remote site telephone number.
XRetry!=True                    ! Should we retry dialing if busy/no answer.
XVoid Xbios(15,4,0,&H88,1,1,-1) ! RS232 configuration/baud rate. (See below.)
XRem
XRem Configure RS232 - Xbios(15,baud,flow,ctrl,rst,xst,scr).
XRem baud = 0/19200, 1/9600, 4/2400, 7/1200, 9/300.
XRem flow = 0/None. (UUCP forbids xoff/xon! ST's RTS/CTS works goofy!)
XRem ctrl = 8bits, 1stop, noparity.
XRem rst = recv enabled.
XRem xst = xmit enabled.
XRem scr = not used.
XRem
XRwinsiz%=3           ! Number of packets in receive window. (Standard=3)
XRpktsiz%=64          ! Number of bytes in a receive packet. (Standard=64)
XRem
XRem Assembler code for calculating the checksum (speedy.)  Does the check-
XRem sum calculation on a packetsize worth of data starting at Buffer.
XRem The control byte is also included in the sum and everthing is sub-
XRem tracted from AAAA hex.
XRem            Checksum=C:Chk%(L:buffer,W:packetsize,W:controlbyte)
XRem
XData "206F0004322F0008342F000A203C0000FFFF4243E358280042851A18D0453A00B345"
XData "D645B0846E02B7400441000166E40242FFFFB142303CAAAA904202800000FFFF4E75"
XRead A$
XRead B$
XA$=A$+B$
XChk$=""
XFor J%=1 To Len(A$) Step 2
X  Chk$=Chk$+Chr$(Val("&H"+Mid$(A$,J%,2)))
XNext J%
XChk%=Varptr(Chk$)
XRem
XRem Assembler code for RS232 block input (speedy.)  Puts x chars into a
XRem buffer, or times out after 12 seconds.
XRem            Remainder=C:Rcv%(L:buffer,W:byteswanted)
XRem
XData "286F0004382F000842A73F3C00204E415C8F2E002A39000004BA068500000960"
XData "3F3C00013F3C00014E4D588F4A4067143F3C00013F3C00024E4D588F18C05344"
XData "670C60DC2C39000004BA9C856DD22F073F3C00204E415C8F20044E75"
XRead A$
XRead B$
XA$=A$+B$
XRead B$
XA$=A$+B$
XRcv$=""
XFor J%=1 To Len(A$) Step 2
X  Rcv$=Rcv$+Chr$(Val("&H"+Mid$(A$,J%,2)))
XNext J%
XRcv%=Varptr(Rcv$)
XDim Rcxx%(Rpktsiz%/4+2)             ! Build an internal input buffer.
XRcvbf%=Varptr(Rcxx%(0))
XDim Wfil$(2)
XWfm=0
XWfp%=Varptr(Wfm)                    ! Build a frame buffer.
XRs232p%=Xbios(14,0)                 ! Get RS232 TOS buffer info pointer.
XRinsiz%=((Rpktsiz%+6)*Rwinsiz%+128)
XDim Rin%(Rinsiz%/4+1)               ! Make a large RS232 TOS input buffer.
XLpoke Rs232p%,Varptr(Rin%(0))
XDpoke Rs232p%+4,Rinsiz%
XDpoke Rs232p%+6,0                   ! Flag it empty.
XDpoke Rs232p%+8,0
XOpen "",#2,"AUX:"                   ! Open RS232 port as file #2.
XRem
XRem   You will probably need to customize the dialing part of the program,
XRem   depending upon the quirks of the site you are trying to call, and
XRem   your modem response codes.
XRem
XPrint "Dialing.    Push SPACE key to abort connection attempt."
XRepeat
X  @Ostr("ATDT"+Siteph$+"\0D")         !  Dial remote site.
X  @Waitfor("CONNECT",60)
X  Exit If Not Retry!
X  If Not Found!
X    Print "Busy/no answer. Dialing again."
X  Endif
XUntil Found!
XPrint "Connected."
XRetry!=False
XPause 200
XOut 1,&HD                            ! Send a couple of CR's to prime remote.
XPause 50
XOut 1,&HD
XPause 50
XOut 1,&HD
XPause 50
XOut 1,&HD
X@Waitfor("ogin:",30)
XPause 50
X@Ostr(Myuser$+"\0D")
X@Waitfor("sword:",30)
X@Ostr(Mypw$+"\0D")
X@Waitfor("Shere",30)
XPrint "Logged in."
XRem
XRem Initialization sequence.
XRem
X@Ostr("\10S"+Mysite$+"\0A")
X@Waitfor("ROK",30)
X@Waitfor("P",30)
X@Waitfor("g",5)
X@Ostr("\10Ug\0A")
XInita!=False
XInitb!=False
XInitc!=False
XFor Wf%=1 To 10                 ! INIT with window size / data segement size.
X  If Inita!=False Or Initb!=False
X    Wcc%=&H38 Or Rwinsiz%
X    @Wctlpkt(2)                      ! inita window size.
X  Endif
X  @Waitframe
X  If Found! And (Cntrol% And &HF8)=&H38
X    Inita!=True
X    Xwinsiz%=Cntrol% And 7
X    Rpktcod%=Int(Log(Rpktsiz%)/Log(2)-4.9)
X    Wcc%=&H30 Or Rpktcod%
X    @Wctlpkt(2)                      ! initb packet size.
X    @Waitframe
X  Endif
X  If Found! And (Cntrol% And &HF8)=&H30
X    Initb!=True
X    Xpktcod%=(Cntrol% And 7)+1
X    Xpktsiz%=32*2^(Xpktcod%-1)
X    Xpktsizh%=Xpktsiz%+6
X  Endif
X  Exit If Inita! And Initb!
XNext Wf%
XIf Initb!
X  Wcc%=&H28 Or Rwinsiz%
X  @Wctlpkt(2)                        ! initc window size.
X  For Wf%=1 To 3
X    @Waitframe
X    If Found! And (Cntrol% And &HF8)=&H28
X      Initc!=True
X    Endif
X    Exit If Initc!
X  Next Wf%
XEndif
XIf Inita!=False Or Initb!=False Or Initc!=False
X  Print "Failed initilization."
X  @Hangup
XEndif
XPrint "They want a sending window size = ";Xwinsiz%
XPrint "They want a sending data packet size = ";Xpktsiz%
XDim Xbuf%(2*Xpktsizh%)              ! Build an outgoing data buffer.
XXppt%=Varptr(Xbuf%(0))
XRseq%=0
XRrseq%=0
XXseq%=0
XXack%=0
XRem
XRem Since we called, we are master and send our stuff first.
XRem
XSitewrk$=Sitedir$+"\WORK"           ! Temporary work-list file.
XSitecfl$=Sitedir$+"\*.C"
XIf Exist(Sitewrk$)
X  Kill Sitewrk$                     ! Get rid of old stale one.
XEndif
XIf Exist(Sitecfl$)                  ! Do we have anything to send???
X  Dir Sitecfl$ To Sitewrk$          ! Then make a list of those files.
X  Open "I",#3,Sitewrk$
X  While Not Eof(#3)                 ! Setup to send those files, pair by pair.
X    Line Input #3,Sfil$
X    Sfil$=Sitedir$+"\"+Left$(Sfil$,Instr(Sfil$,"."))
X    Cfil$=Sfil$+"C"
X    Wfil$(1)=Sfil$+"D"
X    Wfil$(2)=Sfil$+"X"
X    If Exist(Cfil$)
X      Open "I",#4,Cfil$
X      For Wrks%=1 To 2
X        Line Input #4,Wrklin$       ! Get D. or X. worklines out of C.
X        Wrklin$=Wrklin$+Chr$(0)
X        If Exist(Wfil$(Wrks%))
X          Print "SEND:"'Wrklin$
X          Xfdone!=False
X          Xrqp%=0
X          While Not Xfdone!         ! Send the workline.
X            @Wrqtpkt
X          Wend
X          @Waitdata
X          If Peek(Rcvbf%)<>Asc("S")
X            Print "Send request failed."
X            @Hangup
X          Endif
X          If Peek(Rcvbf%+1)=Asc("Y")
X            Open "I",#1,Wfil$(Wrks%)
X            Xfl%=Lof(#1)
X            Xfp%=0
X            Xfdone!=False
X            While Not Xfdone!        ! Send D. or X. file.
X              @Wfilepkt
X            Wend
X            @Waitdata
X            If Peek(Rcvbf%)<>Asc("C") Or Peek(Rcvbf%+1)<>Asc("Y")
X              Print "Send failed."
X              @Hangup
X            Endif
X            Close #1
X          Else                       ! They won't let us do something.
X            Print "Send request refused by remote site."
X          Endif
X          Kill Wfil$(Wrks%)
X        Endif
X      Next Wrks%
X      Close #4
X      Kill Cfil$
X    Endif
X  Wend
X  Close #3
X  Kill Sitewrk$
XEndif
XRem
XRem We are done sending, now we become slave to receive.
XRem
XWrklin$="H"+Chr$(0)
XXrqp%=0
X@Wrqtpkt
X@Waitdata
XIf Peek(Rcvbf%)=Asc("H")
X  If Peek(Rcvbf%+1)=Asc("N")             ! HN means they have mail for us.
X    Do
X      Rwfr!=False
X      Wrklin$=""
X      While Not Rwfr!
X        @Waitdata                        ! Get their workline request.
X        For Wf%=0 To Rpktsiz%-1
X          Wlv%=Peek(Rcvbf%+Wf%)
X          If Wlv%=0
X            Rwfr!=True
X          Else
X            Wrklin$=Wrklin$+Chr$(Wlv%)
X          Endif
X          Exit If Rwfr!
X        Next Wf%
X      Wend
X      Rwff$=Left$(Wrklin$,1)
X      Exit If Rwff$="H"                  ! If H then they are done too.
X      Print "RCV:"'Wrklin$
X      If Rwff$="S"
X        Wlst%=Instr(5,Wrklin$," ")
X        Rwff$=Mid$(Wrklin$,Wlst%+1,1)    ! We have to shorten the file name.
X        Rfil$=Rwff$+Mid$(Wrklin$,Instr(Wlst%,Wrklin$," ")-4,4)+"."+Rwff$
X        Open "O",#1,Sitercv$+"\"+Rfil$
X        Wrklin$="SY"+Chr$(0)             ! Tell them it's okay to send.
X        Xrqp%=0
X        @Wrqtpkt
X        Rdone!=False
X        While Not Rdone!                 ! Get D. or X. file contents.
X          @Waitdata
X          If Ptyp%=&H80
X            Bput #1,Rcvbf%,Rpktsiz%
X          Else
X            Dif%=Peek(Rcvbf%)
X            Dfc%=1
X            If Dif%=>128
X              Dif%=Dif%-128+Peek(Rcvbf%+1)*128
X              Dfc%=2
X            Endif
X            Dif%=Rpktsiz%-Dif%
X            If Dif%<>0
X              Bput #1,Rcvbf%+Dfc%,Dif%
X            Else
X              Rdone!=True
X            Endif
X          Endif
X        Wend
X        Close #1
X        Wrklin$="CY"+Chr$(0)             ! Acknowledge successful copy.
X        Xrqp%=0
X        @Wrqtpkt
X      Else
X        Print "Illegal request from remote site:"
X        Print Wrklin$
X        Wrklin$=Rwff$+"N"+Chr$(0)        ! Tell them sorry, but no.
X        Xrqp%=0
X        @Wrqtpkt
X      Endif
X    Loop
X    Wrklin$="HY"+Chr$(0)
X    Xrqp%=0
X    @Wrqtpkt
X    @Waitdata
X    If Peek(Rcvbf%)<>Asc("H") Or Peek(Rcvbf%+1)<>Asc("Y")
X      Print "Failed looking to hangup."
X      @Hangup
X    Endif
X    @Fini
X  Else
X    Wrklin$="HY"+Chr$(0)
X    Xrqp%=0
X    @Wrqtpkt
X    @Fini
X  Endif
XElse
X  Print "Mode switching failed."
X  @Hangup
XEndif
XEnd
XProcedure Fini
X  Print "Done. Terminating session."
X  @Ostr("\10\09\A2\AA\08\09")
X  @Waitframe
X  If Frmcmd%<>8
X    Print "Failed waiting for CLOSE!"
X    @Hangup
X  Endif
X  @Ostr("\10OOOOOO\0A")
X  @Waitfor("OOO",5)
X  @Ostr("\10OOOOOO\0A")
X  Print "Conversation complete."
X  @Hangup
XReturn
XProcedure Ostr(O$) ! Send ASCII or HEX \XX (2 nybbles - uppercase.)
X  L%=Len(O$)
X  J%=0
X  Repeat
X    Inc J%
X    C%=Asc(Mid$(O$,J%,1))
X    If C%=&H5C
X      Inc J%
X      C%=Val("&H"+Mid$(O$,J%,2))
X      Inc J%
X    Endif
X    Out 1,C%
X  Until J%=L%
XReturn
XProcedure Waitfor(O$,Tx%) ! Look for O$ in input stream for Tx seconds.
X  Pkey!=False             ! Pressing space key aborts during dial up part.
X  Found!=False
X  Ol%=Len(O$)
X  Cp%=1
X  T%=Timer+Tx%*200
X  While Timer<T%
X    If Inp?(1)
X      C%=Inp(1) And &H7F
X      If Asc(Mid$(O$,Cp%,1))=C%
X        If Cp%=Ol%
X          Found!=True
X        Endif
X        Inc Cp%
X      Else
X        If Cp%<>1
X          Cp%=1
X          If Asc(Mid$(O$,Cp%,1))=C%
X            Inc Cp%
X          Endif
X        Endif
X      Endif
X    Endif
X    Exit If Found!
X    If Inp?(2)
X      If Inp(2)=Asc(" ")      ! Abort during login if SPACE key is pressed.
X        Pkey!=True
X      Endif
X    Endif
X    Exit If Pkey!
X  Wend
X  If ((Not Found!) And Not Retry!) Or Pkey!
X    Print "Failed waiting for: ";O$
X    @Hangup
X  Endif
XReturn
XProcedure Waitframe                 ! Wait for a six byte framing envelope.
X  Found!=False
X  Rr!=False
X  Dpkt!=False
X  Wfr%=C:Rcv%(L:Wfp%,6)
X  Repeat
X    Cntrol%=Peek(Wfp%+4)
X    Rsum1%=Peek(Wfp%+2)
X    Rsum2%=Peek(Wfp%+3)
X    Xs%=Peek(Wfp%+1) Xor Rsum1% Xor Rsum2% Xor Cntrol%
X    If Wfr%=0 And Peek(Wfp%)=&H10 And Xs%=Peek(Wfp%+5)
X      Found!=True
X      Ptyp%=Cntrol% And &HC0
X      If Ptyp%=0
X        Xack%=Cntrol% And 7
X        Frmcmd%=Cntrol% And &H38
X        If Frmcmd%=&H20
X          Rr!=True
X        Endif
X      Else
X        Dpkt!=True
X        Rrseq%=(Cntrol%/8) And 7
X        Rsum%=Rsum2%*256+Rsum1%
X      Endif
X    Else
X      If Wfr%=0
X        Bmove Wfp%+1,Wfp%,5
X        Wfr%=C:Rcv%(L:Wfp%+5,1)
X      Endif
X    Endif
X    Exit If Found!
X  Until Wfr%<>0
XReturn
XProcedure Hangup               ! Hangup.
X  Print "Hanging Up!"
X  @Ostr("\0D")
X  Pause 60
X  @Ostr("+++")
X  Pause 60
X  @Ostr("\0DATH\0D")
X  Pause 25
X  Void Xbios(30,&H10)          ! Drop DTR for 1/2 second.
X  Pause 25
X  Void Xbios(29,&HEF)          ! Raise DTR.
X  End
XReturn
XRem
XRem Writes:  One data packet, from file opened as #1, to RS232 opened as #2.
XRem Returns: Xfdone!=True after last packet sent.
XRem Initial: Xfl%=Lof(#1), Xfp%=0, Xppt%=base packet pointer,
XRem          xpktsiz%, xpktcod%, xpktsizh%.
XRem Current: Rseq%=last rcvd packet sequence number, Xseq%=last xmited.
XRem Updates: Xseq%=xmited packet sequence number, Xfp%=xmited data pointer.
XRem
XProcedure Wfilepkt
X  Xfpo%=Xfp%
X  Xfp%=Xfp%+Xpktsiz%
X  Xseq%=(Xseq%+1) And 7
X  Xph%=Xppt%+Xseq%*Xpktsizh%
X  Xpd%=Xph%+6
X  Poke Xph%,&H10
X  Poke Xph%+1,Xpktcod%
X  If Xfp%<=Xfl%
X    Bget #1,Xpd%,Xpktsiz%             ! Full Packet.
X    Xctrl%=&H80 Or Xseq%*8 Or Rseq%
X    Xsum%=C:Chk%(L:Xpd%,W:Xpktsiz%,W:Xctrl%)
X    Poke Xph%+2,Xsum%
X    Xf1%=Xsum%/256
X    Poke Xph%+3,Xf1%
X    Poke Xph%+4,Xctrl%
X    Poke Xph%+5,(Xpktcod% Xor Xsum% Xor Xf1% Xor Xctrl%)
X    @Wchkwin(0)
X  Else
X    If Xfpo%<Xfl%
X      Xbun%=Xpktsiz%-(Xfl%-Xfpo%)     ! Short Packet. (If needed.)
X      If Xbun%<128
X        Poke Xpd%,Xbun%
X        Bget #1,Xpd%+1,Xfl%-Xfpo%
X      Else
X        Poke Xpd%,Xbun% And &H7F Or &H80
X        Poke Xpd%+1,Xbun%/128
X        Bget #1,Xpd%+2,Xfl%-Xfpo%
X      Endif
X      Xctrl%=&HC0 Or Xseq%*8 Or Rseq%
X      Xsum%=C:Chk%(L:Xpd%,W:Xpktsiz%,W:Xctrl%)
X      Poke Xph%+2,Xsum%
X      Xf1%=Xsum%/256
X      Poke Xph%+3,Xf1%
X      Poke Xph%+4,Xctrl%
X      Poke Xph%+5,(Xpktcod% Xor Xsum% Xor Xf1% Xor Xctrl%)
X      @Wchkwin(0)
X    Else
X      If Xpktsiz%<128                 ! Empty Packet. (Always sent last.)
X        Poke Xpd%,Xpktsiz%
X      Else
X        Poke Xpd%,Xpktsiz% And &H7F Or &H80
X        Poke Xpd%+1,Xpktsiz%/128
X      Endif
X      Xctrl%=&HC0 Or Xseq%*8 Or Rseq%
X      Xsum%=C:Chk%(L:Xpd%,W:Xpktsiz%,W:Xctrl%)
X      Poke Xph%+2,Xsum%
X      Xf1%=Xsum%/256
X      Poke Xph%+3,Xf1%
X      Poke Xph%+4,Xctrl%
X      Poke Xph%+5,(Xpktcod% Xor Xsum% Xor Xf1% Xor Xctrl%)
X      @Wchkwin(1)
X      Xfdone!=True
X    Endif
X  Endif
XReturn
XRem
XRem This procedure sends data packets used for H,S,C type signals.
XRem It differs from the other data packets in that there are no short
XRem packets.  Instead a zero follows each command string and a zero
XRem must appear as the last byte in the packet.
XRem
XProcedure Wrqtpkt             ! Initial: Xrqp%=0, Wrklin$, Xfdone!=False.
X  Xstp%=Varptr(Wrklin$)
X  Xstl%=Len(Wrklin$)
X  Xrqpo%=Xrqp%
X  Xrqp%=Xrqp%+Xpktsiz%
X  Xseq%=(Xseq%+1) And 7
X  Xph%=Xppt%+Xseq%*Xpktsizh%
X  Xpd%=Xph%+6
X  Poke Xph%,&H10
X  Poke Xph%+1,Xpktcod%
X  Bmove Xstp%+Xrqpo%,Xpd%,Xpktsiz%
X  If Xrqp%>Xstl%
X    Poke Xpd%+Xpktsiz%-1,0
X    Xfdone!=True
X  Endif
X  Xctrl%=&H80 Or Xseq%*8 Or Rseq%
X  Xsum%=C:Chk%(L:Xpd%,W:Xpktsiz%,W:Xctrl%)
X  Poke Xph%+2,Xsum%
X  Xf1%=Xsum%/256
X  Poke Xph%+3,Xf1%
X  Poke Xph%+4,Xctrl%
X  Poke Xph%+5,(Xpktcod% Xor Xsum% Xor Xf1% Xor Xctrl%)
X  @Wchkwin(1)
XReturn
XRem
XRem This procedure sends RR's, RJ's, CLOSE, and INITA,B,C's.
XRem
XProcedure Wctlpkt(Wct%)       ! wct%=0 for RR, 1 for Rj, 2 for other.
X  If Wct%=0
X    Wcc%=&H20 Or Rseq%
X  Else
X    If Wct%=1
X      Wcc%=&H10 Or Rseq%
X    Endif
X  Endif
X  Wc1%=&HAAAA-Wcc%
X  Wc0%=Wc1% And &HFF
X  Div Wc1%,256
X  Wcx%=9 Xor Wc0% Xor Wc1% Xor Wcc%
X  Out 1,&H10
X  Out 1,&H9
X  Out 1,Wc0%
X  Out 1,Wc1%
X  Out 1,Wcc%
X  Out 1,Wcx%
XReturn
XRem
XRem This procedure waits to receive a data packet.  It RR's them as soon
XRem as it sees them.
XRem
XProcedure Waitdata
X  For Wf%=1 To 10
X    @Waitframe
X    If Dpkt!
X      Nwp%=C:Rcv%(L:Rcvbf%,Rpktsiz%)
X      Csum%=C:Chk%(L:Rcvbf%,Rpktsiz%,Cntrol%)
X      If Rsum%=Csum% And ((Rseq%+1) And 7)=Rrseq%  ! Verify data and seq.
X        Rseq%=Rrseq%
X        @Wctlpkt(0)
X      Else
X        Found!=False
X      Endif
X    Else
X      Found!=False
X    Endif
X    Exit If Found!
X    If Not Rr!                     ! Gets around a Telebit peculiarity.
X      @Wctlpkt(1)
X    Endif
X  Next Wf%
X  If Not Found!
X    Print "Failed waiting for a data frame."
X    @Hangup
X  Endif
XReturn
XRem
XRem This procedure handles the windowing of sent data packets.
XRem It sends as many packets as allowed before waiting for RR's.
XRem
XProcedure Wchkwin(Flush%)
X  If ((Xack%+Xwinsiz%+1) And 7)<>Xseq%
X    Bput #2,Xph%,Xpktsizh%
X  Else
X    For Wf%=1 To 10
X      @Waitframe
X      If Rr!
X        Bput #2,Xph%,Xpktsizh%
X      Else
X        Found!=False
X        For Jr%=1 To Xwinsiz%
X          Xjr%=(Xack%+Jr%) And 7
X          Bput #2,Xppt%+Xjr%*Xpktsizh%,Xpktsizh%
X          Exit If Xjr%=Xseq%
X        Next Jr%
X      Endif
X      Exit If Rr!
X    Next Wf%
X    If Not Found!
X      Print "Failed waiting for RR."
X      @Hangup
X    Endif
X  Endif
X  If Flush%=1
X    While Xack%<>Xseq%
X      For Wf%=1 To 10
X        @Waitframe
X        If Not Rr!
X          Found!=False
X          For Jr%=1 To Xwinsiz%
X            Xjr%=(Xack%+Jr%) And 7
X            Bput #2,Xppt%+Xjr%*Xpktsizh%,Xpktsizh%
X            Exit If Xjr%=Xseq%
X          Next Jr%
X        Endif
X        Exit If Rr!
X      Next Wf%
X      If Not Found!
X        Print "Failed waiting for flushed RR."
X        @Hangup
X      Endif
X    Wend
X  Endif
XReturn
XRem ------------------------------------------------------------------
XRem CHECKSUM ROUTINE LISTING
XRem
XRem 206F0004    start: move.l 4(sp),a0    ; data packet start address.
XRem 322F0008           move.w 8(sp),d1    ; data packet length.
XRem 322F000A           move.w 10(sp),d2   ; command byte.
XRem 203C0000FFFF       move.l #$ffff,d0
XRem 4243               clr.w d3
XRem E358        ck1:   rol.w #1,d0        ; do checksum on every
XRem 2800               move.l d0,d4       ; byte in the data packet.
XRem 4285               clr.l d5
XRem 1A18               move.b (a0)+,d5
XRem D045               add.w d5,d0
XRem 3A00               move.w d0,d5
XRem B345               eor.w d1,d5
XRem D645               add.w d5,d3
XRem B084               cmp.l d4,d0
XRem 6E02               bgt.s ovck
XRem B740               eor.w d3,d0
XRem 04410001    ovck:  sub.w #1,d1
XRem 66E4               bne.s ck1
XRem 0242FFFF           and.w #$ffff,d2
XRem B142               eor.w d0,d2       ; do checksum on command byte.
XRem 303CAAAA           move.w #$aaaa,d0
XRem 9042               sub.w d2,d0       ; subtract everything from AAAA.
XRem 02800000FFFF       and.l #$ffff,d0
XRem 4E75               rts
XRem ---------------------------------------------------------------------
XRem INPUT ROUTINE LISTING
XRem
XRem 286F0004      start:  move.l 4(sp),a4     ; Buffer address.
XRem 382F0008              move.w 8(sp),d4     ; Packet size.
XRem 42A7                  clr.l -(sp)         ; Execute in superuser mode.
XRem 3F3C0020              move.w #$20,-(sp)
XRem 4E41                  trap #1
XRem 5C8F                  addq.l #6,sp
XRem 2E00                  move.l d0,d7        ; Save SUPER stack pointer.
XRem 2A39000004BA          move.l $4ba,d5      ; Get initial time.
XRem 068500000960          add.l #2400,d5      ; Twelve second timeout.
XRem 3F3C0001      next:   move.w #1,-(sp)     ; Test for character.
XRem 3F3C0001              move.w #1,-(sp)
XRem 4E4D                  trap #13
XRem 588F                  addq.l #4,sp
XRem 4A40                  tst d0
XRem 6714                  beq.s nomore        ; No character ready.
XRem 3F3C0001              move.w #1,-(sp)     ; Else, get character.
XRem 3F3C0002              move.w #2,-(sp)
XRem 4E4D                  trap #13
XRem 588F                  addq.l #4,sp
XRem 18C0                  move.b d0,(a4)+
XRem 5344                  subq.w #1,d4
XRem 670C                  beq.s out
XRem 60DC                  bra.s next
XRem 2C39000004BA  nomore: move.l $4ba,d6      ; Check timer.
XRem 9C85                  sub.l d5,d6
XRem 6DD2                  blt.s next
XRem 2F07          out:    move.l D7,-(sp)     ; Back to USER mode.
XRem 3F3C0020              move.w #$20,-(sp)
XRem 4E41                  trap #1
XRem 5C8F                  addq.l #6,sp
XRem 2004                  move.l d4,d0        ; D0=zero for success.
XRem 4E75                  rts
XRem -------------------------------------------------------------------
X
SHAR_EOF
chmod 0600 mailtruk.lst || echo "restore of mailtruk.lst fails"
sed 's/^X//' << 'SHAR_EOF' > protocol.doc &&
X                   Packet Driver Protocol
X
X                       G. L. Chesson
X                     Bell Laboratories
X                (Shortened by John Logajan)
XGeneral
X
X                            The  technique  depends  on  the
Xnotion of a transmission window to determine upper and lower
Xbounds  for  valid  sequence  numbers.   The  transmitter is
Xallowed to retransmit packets having sequence numbers within
Xthe  window  until  the receiver indicates that packets have
Xbeen correctly received.  Positive acknowledgement from  the
Xreceiver  moves  the  window; negative acknowledgement or no
Xacknowledgement causes retransmission.   The  receiver  must
Xignore  duplicate  transmission,  detect  the various errors
Xthat may occur, and inform the transmitter when packets  are
Xcorrectly or incorrectly received.
X
XPacket Formats
X
X     The protocol is defined in terms of  message  transmis-
Xsions  of  8-bit  bytes.   Each message includes one control
Xbyte plus a data segment of zero or more information  bytes.
XThe  allowed data segment sizes range between 32 and 4096 as
Xdetermined by the formula 32(2k) where k is a 3-bit  number.
XThe  packet  sequence numbers are likewise constrained to 3-
Xbits; i.e. counting proceeds modulo-8.
X
X     The control byte is partitioned into  three  fields  as
Xdepicted below.
X
Xbit     7      6      5      4      3      2      1      0
X        t      t      x      x      x      y      y      y
X
XThe  t  bits  indicate  a  packet  type  and  determine  the
Xinterpretation  to be placed on the xxx and yyy fields.  The
Xvarious interpretations are as follows:
X
X          tt      interpretation
X
X          00      control packet
X          10      data packet
X          11      short data packet
X
XA data segment accompanies all  non-control  packets.   Each
Xtransmitter  is constrained to observe the maximum data seg-
Xment size established during initial synchronization by  the
Xreceiver  that  it  sends  to.  Type 10 packets have maximal
Xsize data segments.  Type 11, or  short,  packets have  zero
Xor more data bytes but less than the maximum.  The first one
Xor two bytes of the data  segment  of  a  short  packet  are
Xcount  bytes  that  indicate the difference between the max-
Ximum size and the number of bytes in the short segment.   If
Xthe difference is less than 127, one count byte is used.  If
Xthe difference exceeds 127, then the low-order seven bits of
Xthe  difference are put in the first data byte and the high-
Xorder bit is set as an indicator that the remaining bits  of
Xthe difference are in the second byte.
X
X     The sequence number of a non-control packet is given by
Xthe  xxx  field.   Control  packets  are not sequenced.  The
Xnewest sequence number, excluding  duplicate  transmissions,
Xaccepted  by  a  receiver is placed in the yyy field of non-
Xcontrol packets sent to the other receiver.
X
X     There are no  data  bytes  associated  with  a  control
Xpacket,  the  xxx field is interpreted as a control message,
Xand the yyy field is a value accompanying the  control  mes-
Xsage.   The  control messages are listed below in decreasing
Xpriority.  That is, if several control messages  are  to  be
Xsent, the lower-numbered ones are sent first.
X
X   xxx   name    yyy
X
X    1    CLOSE   n/a
X    2    RJ      last correctly received sequence number
X    3    ---     ---
X    4    RR      last correctly received sequence number
X    5    INITC   window size
X    6    INITB   data segment size
X    7    INITA   window size
X
X     The CLOSE message  indicates  that  the  communications
Xchannel  is  to  be  shut  down.  The RJ, or reject, message
Xindicates that the receiver has detected an  error  and  the
Xsender should retransmit after using the yyy field to update
Xthe window.                              The RR, or receiver
Xready, message indicates that the receiver has  detected  no
Xerrors;  the  yyy  field  updates  the sender's window.  The
XINITA/B/C messages are used to set window and  data  segment
Xsizes.  Segment sizes are calculated by the formula 32(2yyy)
Xand window sizes may range between 1 and 7.
X
X     Measurements of the protocol running  on  communication
Xlinks  at rates up to 9600 baud showed that a window size of
X2 is optimal given a packet  size  greater  than  32  bytes.
XThis  means that the link bandwidth can be fully utilized by
Xthe software.
X
XMessage Exchanges
X
X        Initialization
X
X     Messages are exchanged between four  cooperating  enti-
Xties:  two  senders  and two receivers.  This means that the
Xcommunication channel  is  thought  of  as  two  independent
Xhalf-duplex  data paths.  For example the window and segment
Xsizes need not be the same in each direction.
X
X     Initial synchronization is accomplished with two  3-way
Xhandshakes:  two  each  of  INITA/INITB/INITC.   Each sender
Xtransmits INITA messages repeatedly.  When an INITA  message
Xis received, INITB is sent in return.  When an INITB message
Xis received and an INITB message has  been  sent,  an  INITC
Xmessage  is  sent.   The INITA and INITB messages carry with
Xthem the packet and window size that each receiver wants  to
Xuse,  and  the  senders  are  supposed  to  comply.   When a
Xreceiver has seen all three INIT messages,  the  channel  is
Xconsidered to be open.  INIT messages are ignored elsewhere.
X
X        Data Transport
X
X     After initial  synchronization  each  receiver  sets  a
Xmodulo-8  incrementing  counter  R  to 0; each sender sets a
Xsimilar counter S to 1.  The value of R is always the number
Xof  the most recent correctly received packet.  The value of
XS is always the first sequence number in the output  window.
XLet  W  denote window size.  Note that the value of W may be
Xdifferent for each sender.
X
X     A sender may transmit packets with sequence numbers  in
Xthe  range  S  to  (S+W-1) mod-8.   At any particular time a
Xreceiver expects arriving packets to  have  numbers  in  the
Xrange  (R+1) mod-8  to  (R+W) mod-8.  Packets must arrive in
Xsequence number order are are only  acknowledged  in  order.
XThat  is, the  next  packet a receiver will acknowledge must
Xhave sequence number (R+1) mod-8.
X
X     A receiver acknowledges  receipt  of  data  packets  by
Xarranging  for  the value of its R counter to be sent across
Xthe channel where it will be used to update  an  S  counter.
XThis is done in two ways.  If data is flowing in both direc-
Xtions across a channel then each receiver's current R  value
Xis  carried in the yyy field of non-control packets.  Other-
Xwise  when  there  is  no  bidirectional  data  flow,   each
Xreceiver's R value is transmitted across the link as the yyy
Xfield of an RR control packet.
X
X     Error handling is up to the discretion of the receiver.
XIt  can ignore all errors in which case transmitter timeouts
Xmust provide for retransmission.  The receiver may also gen-
Xerate  RJ error control packets.  The yyy field of an incom-
Xing RJ message replaces the S value of the local sender  and
Xconstitutes  a  request  for retransmission to start at that
Xsequence number.
X
X        Termination
X
X     The CLOSE message is used to terminate  communications.
XSoftware on either or both ends of the communication channel
Xmay initiate termination.  In any case when one end wants to
Xterminate it sends CLOSE messages until one is received from
Xthe other end or until a programmable limit on the number of
XCLOSE  messages  is  reached.   Receipt  of  a CLOSE message
Xcauses a CLOSE message to be sent.
X
X        Framing
X
X     The term framing is used to  denote  the  technique  by
Xwhich  the  beginning  and end of a message is detected in a
Xbyte stream; error  control  denotes  the  method  by  which
Xtransmission  errors  are  detected.
X
X     A six byte framing envelope is  constructed  using  the
Xcontrol  byte C of a packet and five other bytes as depicted
Xbelow.
X          <DLE><k><c0><c1><C><x>
XThe <DLE> symbol denotes the ASCII ctrl/P character.  If the
Xenvelope  is  to  be followed by a data segment, <k> has the
Xvalue log2(size)-4; i.e. 1 < k < 8.  If k  is  9,  then  the
Xenvelope  represents  a  control  packet.  The <c0> and <c1>
Xbytes are the low-order and high-order bytes respectively of
Xa 16-bit checksum.        For control packets, this value is
X0xAAAA minus the control byte C. 
XFor data packets,  the  checksum  is calculated by a program.
X(John Logajan's 68000 version is below.)
XThe <x> byte is the exclusive-or of  <k><c0><c1><C>.   Error
Xcontrol  is  accomplished  by  checking  a  received framing
Xenvelope for compliance with the definition, and comparing a
Xchecksum function of the data segment with <c0><c1>.
X
X     This particular framing strategy assumes data  segments
Xare constant-sized: the  unused  bytes in a short packet are
Xactually transmitted.
X
X------------------------------------------------------
XLogajan's 68000 version of the checksum program,
Xas called from a GFA Basic C: call.
X
Xstart: move.l 4(sp),a0      ;data packet start address
X       move.w 8(sp),d1      ;data packet length
X       move.w 10(sp),d2     ;command byte
X       move.l #$ffff,d0
X       clr.w d3
Xck1:   rol.w #1,d0
X       move.l d0,d4
X       clr.l d5
X       move.b (a0)+,d5
X       add.w d5,d0
X       move.w d0,d5
X       eor.w d1,d5
X       add.w d5,d3
X       cmp.l d4,d0
X       bgt.s ovck
X       eor.w d3,d0
Xovck:  sub.w #1,d1
X       bne.s ck1
X       and.w #$ffff,d2
X       eor.w d0,d2
X       move.w #$aaaa,d0
X       sub.w d2,d0
X       and.l #$ffff,d0      ;Checksum in D0.    
X       rts
X-----------------------------------------------------
XExample session:
X
XNote below: S = we send, R = we receive.
XAfter the login: and password: stuff;
X
XR Shere[=sitename]
XS Soursitename
XR ROK
XR Pg[other protcols]
XS Ug
XS INITA (with our window size)
XR INITA (with their window size)
XS INITB (with our packet size)
XR INITB (with their packet size)
XS INITC (with our window size, again)
XR INITC
XS S workline with D.file name.   (If we have work, else H)
XR RR
XR SY
XS RR
XS data packets, short packet if need, followed by empty pkt.
XR RR's
XR CY
XS RR
XS S workline with X.file name.
XR RR
XR SY
XS data packets
XR RR's
XR CY
XS H    (If we are done)
XR RR
XR HN   (If they have work, else HY)
XS RR
XR S workline D.file
XS RR
XS SY
XR RR
XR data packets
XS RR's
XS CY
XR RR
XR S workline X.file
XS RR
XS SY
XR RR
XR data packets
XS RR's
XS CY
XR RR
XR H   (If they are done too.)
XS RR
XS HY
XR RR
XR HY
XR RR
XS CLOSE
XR CLOSE
XS OOOOOO
XR OOOOOO (Hangup)
X-----------------------------------------------------
X
SHAR_EOF
chmod 0600 protocol.doc || echo "restore of protocol.doc fails"
sed 's/^X//' << 'SHAR_EOF' > readmail.lst &&
XRem READMAIL V1.0 for use with MAILTRUK, by John Logajan, Jan '89.
XRem                       --- PUBLIC DOMAIN ---
XRem Checks mailbox and reads letters.  Saved files are always directed to the
XRem main mail directory specified below.  Please customize the next two lines.
XRem
XMdir$="c:\mail\"                 ! Main upper level mail directory.
XMysite$="logajan\"               ! Name of site mailbox directory.
XRem
XMwrk$=Mdir$+Mysite$+"WORK"
XMd$=Mdir$+Mysite$+"*.*"
XIf Exist(Mwrk$)
X  Kill Mwrk$
XEndif
XIf Exist(Md$)
X  Dir Md$ To Mwrk$
X  Open "I",#3,Mwrk$
X  M=0
X  Bored!=False
X  While Not Eof(#3)
X    Line Input #3,Mfil$
X    Mfix$=Mdir$+Mysite$+Mfil$
X    If Exist(Mfix$)
X      If Right$(Mfil$,2)=".X"
X        Kill Mfix$
X      Else
X        If Mfil$<>"WORK"
X          Inc M
X          @More
X          Repeat
X            Cdn!=False
X            Line Input "Next/Command";R$
X            R$=Upper$(R$)
X            If Len(R$)=0 Or Left$(R$,1)="N"
X              Cdn!=True
X            Endif
X            If Left$(R$,1)="A" Or Left$(R$,1)="S"
X              Snam$=Mid$(R$,3)
X              If Len(Snam$)>0 And Len(Snam$)<13
X                Open "I",#4,Mfix$
X                If Left$(R$,1)="A"
X                  If Exist(Mdir$+Snam$)
X                    Open "A",#1,Mdir$+Snam$
X                  Else
X                    Print "File ";Mdir$;Snam$;" doesn't exist for appending";
X                    Print " -- Creating it."
X                    R$="S"
X                    Open "O",#1,Mdir$+Snam$
X                  Endif
X                Else
X                  Open "O",#1,Mdir$+Snam$
X                Endif
X                Lc=0
X                While Not Eof(#4)
X                  Inc Lc
X                  Line Input #4,I$
X                  Print #1,I$
X                Wend
X                Close #4
X                Close #1
X                If Left$(R$,1)="A"
X                  Print "File of ";Lc;" lines appended to ";Mdir$;Snam$
X                Else
X                  Print "File of ";Lc;" lines saved in ";Mdir$;Snam$
X                Endif
X              Else
X                Print "Filename - ";Snam$;" - too long."
X              Endif
X            Endif
X            If Left$(R$,1)="D"
X              Kill Mfix$
X              Print "Message ";M;" deleted."
X            Endif
X            If Left$(R$,1)="T"
X              If Exist(Mfix$)
X                @More
X              Else
X                Print "Sorry, you have already deleted that message."
X              Endif
X            Endif
X            If Left$(R$,1)="Q"
X              Bored!=True
X            Endif
X            Exit If Bored!
X            If Left$(R$,1)="H"
X              @Hlp
X            Endif
X          Until Cdn!
X        Endif
X      Endif
X    Endif
X    Exit If Bored!
X  Wend
X  Close #3
X  Kill Mwrk$
X  If Not Bored!
X    Print
X    Print "No other mail."
X  Endif
XElse
X  Print "No mail."
XEndif
XPause 50
XEnd
XProcedure More
X  Open "I",#4,Mfix$
X  Fll%=Lof(#4)
X  Llt%=0
X  Dne!=False
X  Print Chr$(27);"EMessage - ";M
X  Llc%=23
X  Do
X    For Lc=1 To Llc%
X      Line Input #4,C$
X      Print C$
X      Llt%=Llt%+Len(C$)
X      If Eof(#4)
X        Dne!=True
X      Endif
X      Exit If Dne!
X    Next Lc
X    Exit If Dne!
X    Pc%=Int(Llt%/Fll%*100)
X    Pmt:
X    Print Chr$(27);"p--MORE--";Chr$(27)+"q(";Pc%;"%)";
X    R%=Inp(2)
X    Print Chr$(27);"l";
X    If R%=Asc("Q") Or R%=Asc("q")
X      Dne!=True
X    Endif
X    Exit If Dne!
X    If R%=&HD
X      Llc%=1
X    Else
X      Llc%=23
X    Endif
X    If R%=Asc("T") Or R%=Asc("t")
X      Close #4
X      Open "I",#4,Mfix$
X      Fll%=Lof(#4)
X      Llt%=0
X      Print Chr$(27);"EMessage - ";M
X      Llc%=23
X    Endif
X    If R%=Asc("H") Or R%=Asc("h")
X      @Hlp
X      Goto Pmt
X    Endif
X  Loop
X  Close #4
XReturn
XProcedure Hlp
X  Print
X  Print "During message:"
X  Print "   q - skips to end."
X  Print "   t - reread from the top."
X  Print "   CR - read next line."
X  Print "   SPACE - read next page."
X  Print "   h - print this help listing."
X  Print
X  Print "At command prompt:"
X  Print "   n or CR - read next message."
X  Print "   d - delete current message."
X  Print "       (Undeleted messages remain in mailbox.)"
X  Print "   t - reread current message."
X  Print "   s filename - save message to file."
X  Print "   a filename - append message to file."
X  Print "   h - print this help listing."
X  Print "   q - quit back to desktop."
X  Print
XReturn
X
SHAR_EOF
chmod 0600 readmail.lst || echo "restore of readmail.lst fails"
sed 's/^X//' << 'SHAR_EOF' > writmail.lst &&
XRem WRITMAIL V1.0 for use with MAILTRUK  --  By John Logajan, Jan '89.
XRem                     --- PUBLIC DOMAIN ---
XRem  User configuration area.  Must be customized before using.
XRem
XUser$="john"                    ! your Mail name.
XFullname$="John Logajan"        ! your full name.
XMachine$="logajan"              ! your machine name.
XDmain$=".mn.org"                ! your domain. (.uucp if unassigned)
XTimezone$="CST"                 ! your timezone.
XGmtfact=6                       ! your timezone to GMT factor.
XMdir$="c:\mail\"                ! main mail directory.
XWecall$="bungia,ziltch"         ! list of machines you can call.
XSiglines=2                      ! number of lines in signature. (Below)
XDim Sig$(Siglines)
XSig$(1)="- John Logajan @ 4248 Hamline Ave; Arden Hills, MN 55112 -"
XSig$(2)="- ...rutgers!bungia!logajan!john  or john@logajan.mn.org -"
XRem
XPrint "        WRITMAIL V1.0"
XGosub Help
XRepeat
X  Line Input "Path: ",Tpath$
X  If Len(Tpath$)=0
X    End
X  Endif
X  Path$=""
X  For J=1 To Len(Tpath$)
X    If Mid$(Tpath$,J,1)<>"\" Then
X      Path$=Path$+Mid$(Tpath$,J,1)
X    Endif
X  Next J
X  P=1
X  K=Instr(Path$,"!")
X  If K=0 Then
X    Print "Path must use at least one (!) symbol."
X    P=0
X  Else
X    Neighbor$=Left$(Path$,K-1)
X    Shortpath$=Mid$(Path$,K+1)
X    If Instr(Wecall$,Neighbor$)=0 Then
X      Print "-";Neighbor$;"- is not in our list of sites that we can call."
X      P=0
X    Else
X      If Len(Shortpath$)=0 Then
X        Print "Cannot end path with an (!) symbol."
X        P=0
X      Endif
X    Endif
X  Endif
XUntil P=1
XLine Input "Subject: ",Sub$
XIf Upper$(Sub$)="~C" Then
X  End
XEndif
XDim Mes$(20000)
XM=0
XPrint
XPrint "Enter message, (.) alone sends message."
XPrint
XDo
X  If M<0 Then
X    M=0
X  Endif
X  Inc M
X  Line Input "",Mes$(M)
X  Exit If Mes$(M)="."
X  If Upper$(Mes$(M))="~C" Then
X    End
X  Endif
X  If Upper$(Mes$(M))="~H" Then
X    Dec M
X    Gosub Help
X  Endif
X  If Upper$(Mes$(M))="~D" Then
X    M=M-2
X    If M<=0 Then
X      M=0
X      Print "No message."
X    Else
X      Print
X      For P=1 To M
X        Print Mes$(P)
X      Next P
X    Endif
X  Endif
X  If Upper$(Mes$(M))="~V" Then
X    Dec M
X    If M>0 Then
X      Print
X      For P=1 To M
X        Print Mes$(P)
X      Next P
X    Else
X      Print "No message."
X    Endif
X  Endif
X  If Upper$(Left$(Mes$(M),3))="~R " Then
X    Rdfile$=Mid$(Mes$(M),4)
X    If Exist(Rdfile$) Then
X      Open "I",#1,Rdfile$
X      Lc=0
X      While Not Eof(#1)
X        Line Input #1,Mes$(M)
X        Inc M
X        Inc Lc
X      Wend
X      Close #1
X      Print "File of ";Lc;" lines read into message buffer."
X    Else
X      Dec M
X      Print "No such file!"
X    Endif
X  Endif
X  If Upper$(Mes$(M))="~S"
X    M=M-1
X    For J=1 To Siglines
X      M=M+1
X      Mes$(M)=Sig$(J)
X      Print Mes$(M)
X    Next J
X  Endif
XLoop
XIf M=1 Then
X  Print "No message to send -- Not sending."
X  Pause 50
X  End
XEndif
XSeq=10000+(Timer/100 And &H1FFF)
XSeqf$="A"+Str$(Seq And &H1FFF Or &H1000)
XDdir$=Mdir$+Neighbor$+"\"+Seqf$+".D"
XXdir$=Mdir$+Neighbor$+"\"+Seqf$+".X"
XCdir$=Mdir$+Neighbor$+"\"+Seqf$+".C"
XOpen "O",#1,Ddir$
XGosub Getdate
XYears=Year-1900
XPrint #1,"From"'Machine$;"!";User$'Dayweek$'Month$'Day'Time$'Year;Chr$(10);
XPrint #1,"Return-Path: <";Machine$;"!";User$;">";Chr$(10);
XPrint #1,"Received: by"'Machine$;Dmain$'"(MailTruk1.0)";Chr$(10);
XPrint #1,"        id AA";Seq;";"'Dayweek$;","'Day'Month$'Years'Time$'Timezone$;
XPrint #1,Chr$(10);
XPrint #1,"Date:"'Dayweek$;","'Day'Month$'Years'Time$'Timezone$;Chr$(10);
XPrint #1,"From:"'Machine$;Dmain$;"!";User$'"(";Fullname$;")";Chr$(10);
XPrint #1,"Message-Id: <";(((Years*100+Month)*100+Day)*100+Hgmt)*100+Minute;".";
XPrint #1,"AA";Seq;"@";Machine$;Dmain$;">";Chr$(10);
XPrint #1,"To:"'Path$;Chr$(10);
XIf Len(Sub$)>1 Then
X  Print #1,"Subject:"'Sub$;Chr$(10);
XEndif
XPrint #1,Chr$(10);
XFor P=1 To M-1
X  Print #1,Mes$(P);Chr$(10);
XNext P
XClose #1
XOpen "O",#2,Xdir$
XPrint #2,"U"'User$'Machine$;Chr$(10);
XPrint #2,"F"'"D.";Neighbor$;Seqf$;Chr$(10);
XPrint #2,"I"'"D.";Neighbor$;Seqf$;Chr$(10);
XPrint #2,"C rmail"'Shortpath$;Chr$(10);
XClose #2
XOpen "O",#3,Cdir$
XDest$="D."+Neighbor$+Seqf$
XBest$="D."+Machine$+Seqf$
XXest$="X."+Machine$+Seqf$
XPrint #3,"S"'Dest$'Dest$'User$'"-"'Dest$'"0666"
XPrint #3,"S"'Best$'Xest$'User$'"-"'Best$'"0666"
XClose #3
XPrint "Mail sent to outbound file area, awaiting UUCP."
XPause 50
XEnd
XProcedure Getdate            ! returns Month,Day,Year,Dayweek,Dayweek$,Month$
X  Local K,L                  ! Hour,Minute,Second,Ampm$,Hour12,Hgmt
X  Month=Val(Mid$(Date$,1,2))
X  Day=Val(Mid$(Date$,4,2))
X  Year=Val(Mid$(Date$,7,4))
X  Hour=Val(Mid$(Time$,1,2))
X  Minute=Val(Mid$(Time$,4,2))
X  Second=Val(Mid$(Time$,7,2))
X  If Hour>=12 Then
X    Ampm$="PM"
X    Hour12=Hour-12
X  Else
X    Ampm$="AM"
X    Hour12=Hour
X  Endif
X  If Hour12=0 Then
X    Hour12=12
X  Endif
X  Month$=Mid$("JanFebMarAprMayJunJulAugSepOctNovDec",Month*3-2,3)
X  Hgmt=Hour+Gmtfact
X  If Hgmt>=24 Then
X    Hgmt=Hgmt-24
X  Endif
X  K=Int(0.6+1/Month)
X  L=Year-K
X  Dayweek=Int(13*(Month+12*K+1)/5)+Int(5*L/4)-Int(L/100)+Int(L/400)+Day-1
X  Dayweek=Dayweek-(7*Int(Dayweek/7))+1
X  Dayweek$=Mid$("SunMonTueWedThuFriSat",Dayweek*3-2,3)
XReturn
XProcedure Help
X  Print
X  Print ". alone on line sends message."
X  Print "~r filename --  reads in a file."
X  Print "~d deletes previous line, and reprints message so far."
X  Print "~c cancels message."
X  Print "~h prints this help message."
X  Print "~v reprints message so far."
X  Print "~s adds predefined signature lines to message."
X  Print "Paths are of the form:  neighborsite!nextsite!...!sitex!recipient"
X  Print "Subject: is optional.  CR to skip it."
X  Print
XReturn
X
SHAR_EOF
chmod 0600 writmail.lst || echo "restore of writmail.lst fails"
exit 0