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