From: logajan@ns.UUCP (John Logajan x3118) Newsgroups: comp.sys.atari.st Subject: GFA Basic (2.0) version of dial-out uucp. Message-ID: <1081@ns.UUCP> Date: 19 Jan 89 19:50:47 GMT Organization: Network Systems Corp. Mpls MN Lines: 1513 I am posting this here because I have had a few requests for it ASAP. 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. The five files included below, between *****'s are, in order: MAILTRUK.DOC, MAILTRUK.LST, WRITMAIL.LST, READMAIL.LST, and PROTOCOL.DOC. Thanks -- John Logajan. ************************************************************************ MailTruk Documentation by John Logajan, January 1989 4248 Hamline Ave Arden Hills, MN 55112 john@logajan.mn.org INTRODUCTION TO THE NETWORK Welcome to the world of uucp style data exchange. Uucp stands for Unix to Unix copy. Unix is an operating system used by a large number of computers. A large network of computers running uucp compatible data exchange has evolved over the last several years. This network encompasses university, corporate, governmental, and individually owned computers. It is estimated that there are over 10,000 computers on the net, with approximately 400,000 users. The two primary functions of the net are private electronic mail and "broadly cast" electronic news transfer. The Usenet News consists of some 350 subject categories into which several thousand articles a day are posted by users. An average day's news is typically four million characters -- and growing. Anyone receiving a full newsfeed is more and more feeling the need for faster data communications links, since such volume at 2400 baud requires five hours if uncompressed or 2.5 hours if compressed. INTRODUCTION TO THE MAILTRUK, READMAIL, AND WRITMAIL PROGRAMS MailTruk, ReadMail, and WritMail are uucp compatible communications programs that run on Atari ST computers. The programs are written in GFA Basic (2.0) and are freely distributed as a readable listings in the public domain. Files included in the distribution include: MAILTRUK.LST, READMAIL.LST, WRITMAIL.LST, MAILTRUK.DOC, PROTOCOL.DOC WritMail is used to write your outgoing mail. Writmail's main task is to format your message so that other computers on the net recognize what you have sent and where it is going. Each, in turn, passes it along until it hopefully reaches your intended recipient. MailTruk is the actual communications program. It first dials your neighbor site, establishes protocol agreement, and then sends the messages, if any, that you have previously prepared with WritMail. When MailTruk has finished sending, it requests to receive any mail that the remote site has pending for you. After it receives all incoming mail, MailTruk terminates the connection. ReadMail allows you to read your mail in a convenient manner. The main objection to reading you mail files directly with GEM commands is that Unix machines use linefeed characters as end-of- line indicators rather than the carriage return character used by GEM. Thus, direct reading of mail files results in a confusing presentation. Although MailTruk can transfer the file types used to send the Network News, additional file pre- and post-processing is required to read or write News articles. ReadMail and WritMail DO NOT handle the News format. Uncompressed News would be a fairly straight forward task to handle, but compressed and batched News will require additional sophistication. Let me know if you feel motivated to write such a program! SETTING EVERYTHING UP First -- You need a site to call, account information for that site, and a modem. Since this program is being distributed over the net, if you track back from where this program came from, you're bound to run into somebody who knows your local net arrangement. (I pay $25 a year to a guy who runs a "domain park" for my access. He, in turn, calls other bigger sites -- and so on.) Second -- All mail going to a particular site is placed in its own directory. All mail coming to your site is placed in its own directory. You should create these directories before running the programs. I am site -logajan-, I call one site -bungia-. So, I created a directory called MAIL on my C: drive where I put all my programs, and I created two sub-directories, BUNGIA and LOGAJAN, i.e. C:\MAIL\BUNGIA\ C:\MAIL\LOGAJAN\ Third -- All three programs are totally self-contained in that they do not share an external common configuration file. So you will have to insure that each of the important variables, including the directory names mentioned above, in each of the programs is correct and consistent. The variables are grouped near the beginning of each program. You WILL have to customize these variables for these programs to work! Fourth -- If you have multiple sites to call, you will have to make multiple versions of the MailTruk program (or modify it to handle multiple cases.) You will also want to write a program that recognizes messages which are just passing through, and "rewrites" the pertinent addresses, and places them back out in the outbound message area. Fifth -- Otherwise you are a "leaf" site (you only call one machine) and any mail with your machine name in it is assumed to be to you, no matter what user name or additional path is in the To: address line. Sixth -- Paths; the From: and To: portion of messages; are a somewhat mysterious subject. Basically you have to know, at a minimum, the recipient's user-name and machine-name, and the path to the nearest smart mailer site. Otherwise you can specify the entire path -- but some smart sites end up sending it the route they think is best anyhow. If I want to send to jack at atari, I enter the path as: bungia!atari!jack Note: nearest!next!next!farthest!user (my neighbor, bungia, knows the tortuous route to atari) or bungia!umn-cs!rutgers!att.att.com!wally if I want to get to wally at att and know the complete path. You will often see @'s and %'s in paths. Basically you just read these in the other direction, i.e.: john@logajan.mn.org@bungia@shamash@nic.mr.net is an actual path TO my machine from nic.mr.net. However, note that WritMail forces you to state the path with at least one (!) symbol. Your neighbor's machine is always the first name in the path, therefore you could do: bungia!ben@franklin.electric.com Seventh -- Hopefully there is enough information in the listings for you to set up your own site and get it operational. Good luck. ********************************************************************** Rem MAILTRUK V1.0 -- GFA Basic 2.0 / Atari ST implementation of uucp/uucico. Rem --- PUBLIC DOMAIN --- Rem This program dials up computer sites running Unix or Unix clone uucp, Rem allowing the transfer of e-mail, news and other data files. Rem Rem Totally original code by: John Logajan, January 1989. Rem 4248 Hamline Ave Rem Arden Hills, MN 55112 Rem (john@logajan.mn.org or ...rutgers!bungia!logajan!john) Rem Rem The next eight lines must be customized for each user/site. Rem Mysite$="logajan" ! Your site machine name. (You choose!) Myuser$="logajan" ! Your user/account name for remote site. Mypw$="youguess" ! Your password for remote site. Sitedir$="\mail\bungia" ! Directory of files to send only to that site. Sitercv$="\mail\"+Mysite$ ! Directory for all incoming files. Siteph$="123-4567" ! Remote site telephone number. Retry!=True ! Should we retry dialing if busy/no answer. Void Xbios(15,4,0,&H88,1,1,-1) ! RS232 configuration/baud rate. (See below.) Rem Rem Configure RS232 - Xbios(15,baud,flow,ctrl,rst,xst,scr). Rem baud = 0/19200, 1/9600, 4/2400, 7/1200, 9/300. Rem flow = 0/None. (UUCP forbids xoff/xon! ST's RTS/CTS works goofy!) Rem ctrl = 8bits, 1stop, noparity. Rem rst = recv enabled. Rem xst = xmit enabled. Rem scr = not used. Rem Rwinsiz%=3 ! Number of packets in receive window. (Standard=3) Rpktsiz%=64 ! Number of bytes in a receive packet. (Standard=64) Rem Rem Assembler code for calculating the checksum (speedy.) Does the check- Rem sum calculation on a packetsize worth of data starting at Buffer. Rem The control byte is also included in the sum and everthing is sub- Rem tracted from AAAA hex. Rem Checksum=C:Chk%(L:buffer,W:packetsize,W:controlbyte) Rem Data "206F0004322F0008342F000A203C0000FFFF4243E358280042851A18D0453A00B345" Data "D645B0846E02B7400441000166E40242FFFFB142303CAAAA904202800000FFFF4E75" Read A$ Read B$ A$=A$+B$ Chk$="" For J%=1 To Len(A$) Step 2 Chk$=Chk$+Chr$(Val("&H"+Mid$(A$,J%,2))) Next J% Chk%=Varptr(Chk$) Rem Rem Assembler code for RS232 block input (speedy.) Puts x chars into a Rem buffer, or times out after 12 seconds. Rem Remainder=C:Rcv%(L:buffer,W:byteswanted) Rem Data "286F0004382F000842A73F3C00204E415C8F2E002A39000004BA068500000960" Data "3F3C00013F3C00014E4D588F4A4067143F3C00013F3C00024E4D588F18C05344" Data "670C60DC2C39000004BA9C856DD22F073F3C00204E415C8F20044E75" Read A$ Read B$ A$=A$+B$ Read B$ A$=A$+B$ Rcv$="" For J%=1 To Len(A$) Step 2 Rcv$=Rcv$+Chr$(Val("&H"+Mid$(A$,J%,2))) Next J% Rcv%=Varptr(Rcv$) Dim Rcxx%(Rpktsiz%/4+2) ! Build an internal input buffer. Rcvbf%=Varptr(Rcxx%(0)) Dim Wfil$(2) Wfm=0 Wfp%=Varptr(Wfm) ! Build a frame buffer. Rs232p%=Xbios(14,0) ! Get RS232 TOS buffer info pointer. Rinsiz%=((Rpktsiz%+6)*Rwinsiz%+128) Dim Rin%(Rinsiz%/4+1) ! Make a large RS232 TOS input buffer. Lpoke Rs232p%,Varptr(Rin%(0)) Dpoke Rs232p%+4,Rinsiz% Dpoke Rs232p%+6,0 ! Flag it empty. Dpoke Rs232p%+8,0 Open "",#2,"AUX:" ! Open RS232 port as file #2. Rem Rem You will probably need to customize the dialing part of the program, Rem depending upon the quirks of the site you are trying to call, and Rem your modem response codes. Rem Print "Dialing. Push SPACE key to abort connection attempt." Repeat @Ostr("ATDT"+Siteph$+"\0D") ! Dial remote site. @Waitfor("CONNECT",60) Exit If Not Retry! If Not Found! Print "Busy/no answer. Dialing again." Endif Until Found! Print "Connected." Retry!=False Pause 200 Out 1,&HD ! Send a couple of CR's to prime remote. Pause 50 Out 1,&HD Pause 50 Out 1,&HD Pause 50 Out 1,&HD @Waitfor("ogin:",30) Pause 50 @Ostr(Myuser$+"\0D") @Waitfor("sword:",30) @Ostr(Mypw$+"\0D") @Waitfor("Shere",30) Print "Logged in." Rem Rem Initialization sequence. Rem @Ostr("\10S"+Mysite$+"\0A") @Waitfor("ROK",30) @Waitfor("P",30) @Waitfor("g",5) @Ostr("\10Ug\0A") Inita!=False Initb!=False Initc!=False For Wf%=1 To 10 ! INIT with window size / data segement size. If Inita!=False Or Initb!=False Wcc%=&H38 Or Rwinsiz% @Wctlpkt(2) ! inita window size. Endif @Waitframe If Found! And (Cntrol% And &HF8)=&H38 Inita!=True Xwinsiz%=Cntrol% And 7 Rpktcod%=Int(Log(Rpktsiz%)/Log(2)-4.9) Wcc%=&H30 Or Rpktcod% @Wctlpkt(2) ! initb packet size. @Waitframe Endif If Found! And (Cntrol% And &HF8)=&H30 Initb!=True Xpktcod%=(Cntrol% And 7)+1 Xpktsiz%=32*2^(Xpktcod%-1) Xpktsizh%=Xpktsiz%+6 Endif Exit If Inita! And Initb! Next Wf% If Initb! Wcc%=&H28 Or Rwinsiz% @Wctlpkt(2) ! initc window size. For Wf%=1 To 3 @Waitframe If Found! And (Cntrol% And &HF8)=&H28 Initc!=True Endif Exit If Initc! Next Wf% Endif If Inita!=False Or Initb!=False Or Initc!=False Print "Failed initilization." @Hangup Endif Print "They want a sending window size = ";Xwinsiz% Print "They want a sending data packet size = ";Xpktsiz% Dim Xbuf%(2*Xpktsizh%) ! Build an outgoing data buffer. Xppt%=Varptr(Xbuf%(0)) Rseq%=0 Rrseq%=0 Xseq%=0 Xack%=0 Rem Rem Since we called, we are master and send our stuff first. Rem Sitewrk$=Sitedir$+"\WORK" ! Temporary work-list file. Sitecfl$=Sitedir$+"\*.C" If Exist(Sitewrk$) Kill Sitewrk$ ! Get rid of old stale one. Endif If Exist(Sitecfl$) ! Do we have anything to send??? Dir Sitecfl$ To Sitewrk$ ! Then make a list of those files. Open "I",#3,Sitewrk$ While Not Eof(#3) ! Setup to send those files, pair by pair. Line Input #3,Sfil$ Sfil$=Sitedir$+"\"+Left$(Sfil$,Instr(Sfil$,".")) Cfil$=Sfil$+"C" Wfil$(1)=Sfil$+"D" Wfil$(2)=Sfil$+"X" If Exist(Cfil$) Open "I",#4,Cfil$ For Wrks%=1 To 2 Line Input #4,Wrklin$ ! Get D. or X. worklines out of C. Wrklin$=Wrklin$+Chr$(0) If Exist(Wfil$(Wrks%)) Print "SEND:"'Wrklin$ Xfdone!=False Xrqp%=0 While Not Xfdone! ! Send the workline. @Wrqtpkt Wend @Waitdata If Peek(Rcvbf%)<>Asc("S") Print "Send request failed." @Hangup Endif If Peek(Rcvbf%+1)=Asc("Y") Open "I",#1,Wfil$(Wrks%) Xfl%=Lof(#1) Xfp%=0 Xfdone!=False While Not Xfdone! ! Send D. or X. file. @Wfilepkt Wend @Waitdata If Peek(Rcvbf%)<>Asc("C") Or Peek(Rcvbf%+1)<>Asc("Y") Print "Send failed." @Hangup Endif Close #1 Else ! They won't let us do something. Print "Send request refused by remote site." Endif Kill Wfil$(Wrks%) Endif Next Wrks% Close #4 Kill Cfil$ Endif Wend Close #3 Kill Sitewrk$ Endif Rem Rem We are done sending, now we become slave to receive. Rem Wrklin$="H"+Chr$(0) Xrqp%=0 @Wrqtpkt @Waitdata If Peek(Rcvbf%)=Asc("H") If Peek(Rcvbf%+1)=Asc("N") ! HN means they have mail for us. Do Rwfr!=False Wrklin$="" While Not Rwfr! @Waitdata ! Get their workline request. For Wf%=0 To Rpktsiz%-1 Wlv%=Peek(Rcvbf%+Wf%) If Wlv%=0 Rwfr!=True Else Wrklin$=Wrklin$+Chr$(Wlv%) Endif Exit If Rwfr! Next Wf% Wend Rwff$=Left$(Wrklin$,1) Exit If Rwff$="H" ! If H then they are done too. Print "RCV:"'Wrklin$ If Rwff$="S" Wlst%=Instr(5,Wrklin$," ") Rwff$=Mid$(Wrklin$,Wlst%+1,1) ! We have to shorten the file name. Rfil$=Rwff$+Mid$(Wrklin$,Instr(Wlst%,Wrklin$," ")-4,4)+"."+Rwff$ Open "O",#1,Sitercv$+"\"+Rfil$ Wrklin$="SY"+Chr$(0) ! Tell them it's okay to send. Xrqp%=0 @Wrqtpkt Rdone!=False While Not Rdone! ! Get D. or X. file contents. @Waitdata If Ptyp%=&H80 Bput #1,Rcvbf%,Rpktsiz% Else Dif%=Peek(Rcvbf%) Dfc%=1 If Dif%=>128 Dif%=Dif%-128+Peek(Rcvbf%+1)*128 Dfc%=2 Endif Dif%=Rpktsiz%-Dif% If Dif%<>0 Bput #1,Rcvbf%+Dfc%,Dif% Else Rdone!=True Endif Endif Wend Close #1 Wrklin$="CY"+Chr$(0) ! Acknowledge successful copy. Xrqp%=0 @Wrqtpkt Else Print "Illegal request from remote site:" Print Wrklin$ Wrklin$=Rwff$+"N"+Chr$(0) ! Tell them sorry, but no. Xrqp%=0 @Wrqtpkt Endif Loop Wrklin$="HY"+Chr$(0) Xrqp%=0 @Wrqtpkt @Waitdata If Peek(Rcvbf%)<>Asc("H") Or Peek(Rcvbf%+1)<>Asc("Y") Print "Failed looking to hangup." @Hangup Endif @Fini Else Wrklin$="HY"+Chr$(0) Xrqp%=0 @Wrqtpkt @Fini Endif Else Print "Mode switching failed." @Hangup Endif End Procedure Fini Print "Done. Terminating session." @Ostr("\10\09\A2\AA\08\09") @Waitframe If Frmcmd%<>8 Print "Failed waiting for CLOSE!" @Hangup Endif @Ostr("\10OOOOOO\0A") @Waitfor("OOO",5) @Ostr("\10OOOOOO\0A") Print "Conversation complete." @Hangup Return Procedure Ostr(O$) ! Send ASCII or HEX \XX (2 nybbles - uppercase.) L%=Len(O$) J%=0 Repeat Inc J% C%=Asc(Mid$(O$,J%,1)) If C%=&H5C Inc J% C%=Val("&H"+Mid$(O$,J%,2)) Inc J% Endif Out 1,C% Until J%=L% Return Procedure Waitfor(O$,Tx%) ! Look for O$ in input stream for Tx seconds. Pkey!=False ! Pressing space key aborts during dial up part. Found!=False Ol%=Len(O$) Cp%=1 T%=Timer+Tx%*200 While Timer1 Cp%=1 If Asc(Mid$(O$,Cp%,1))=C% Inc Cp% Endif Endif Endif Endif Exit If Found! If Inp?(2) If Inp(2)=Asc(" ") ! Abort during login if SPACE key is pressed. Pkey!=True Endif Endif Exit If Pkey! Wend If ((Not Found!) And Not Retry!) Or Pkey! Print "Failed waiting for: ";O$ @Hangup Endif Return Procedure Waitframe ! Wait for a six byte framing envelope. Found!=False Rr!=False Dpkt!=False Wfr%=C:Rcv%(L:Wfp%,6) Repeat Cntrol%=Peek(Wfp%+4) Rsum1%=Peek(Wfp%+2) Rsum2%=Peek(Wfp%+3) Xs%=Peek(Wfp%+1) Xor Rsum1% Xor Rsum2% Xor Cntrol% If Wfr%=0 And Peek(Wfp%)=&H10 And Xs%=Peek(Wfp%+5) Found!=True Ptyp%=Cntrol% And &HC0 If Ptyp%=0 Xack%=Cntrol% And 7 Frmcmd%=Cntrol% And &H38 If Frmcmd%=&H20 Rr!=True Endif Else Dpkt!=True Rrseq%=(Cntrol%/8) And 7 Rsum%=Rsum2%*256+Rsum1% Endif Else If Wfr%=0 Bmove Wfp%+1,Wfp%,5 Wfr%=C:Rcv%(L:Wfp%+5,1) Endif Endif Exit If Found! Until Wfr%<>0 Return Procedure Hangup ! Hangup. Print "Hanging Up!" @Ostr("\0D") Pause 60 @Ostr("+++") Pause 60 @Ostr("\0DATH\0D") Pause 25 Void Xbios(30,&H10) ! Drop DTR for 1/2 second. Pause 25 Void Xbios(29,&HEF) ! Raise DTR. End Return Rem Rem Writes: One data packet, from file opened as #1, to RS232 opened as #2. Rem Returns: Xfdone!=True after last packet sent. Rem Initial: Xfl%=Lof(#1), Xfp%=0, Xppt%=base packet pointer, Rem xpktsiz%, xpktcod%, xpktsizh%. Rem Current: Rseq%=last rcvd packet sequence number, Xseq%=last xmited. Rem Updates: Xseq%=xmited packet sequence number, Xfp%=xmited data pointer. Rem Procedure Wfilepkt Xfpo%=Xfp% Xfp%=Xfp%+Xpktsiz% Xseq%=(Xseq%+1) And 7 Xph%=Xppt%+Xseq%*Xpktsizh% Xpd%=Xph%+6 Poke Xph%,&H10 Poke Xph%+1,Xpktcod% If Xfp%<=Xfl% Bget #1,Xpd%,Xpktsiz% ! Full Packet. Xctrl%=&H80 Or Xseq%*8 Or Rseq% Xsum%=C:Chk%(L:Xpd%,W:Xpktsiz%,W:Xctrl%) Poke Xph%+2,Xsum% Xf1%=Xsum%/256 Poke Xph%+3,Xf1% Poke Xph%+4,Xctrl% Poke Xph%+5,(Xpktcod% Xor Xsum% Xor Xf1% Xor Xctrl%) @Wchkwin(0) Else If Xfpo%Xstl% Poke Xpd%+Xpktsiz%-1,0 Xfdone!=True Endif Xctrl%=&H80 Or Xseq%*8 Or Rseq% Xsum%=C:Chk%(L:Xpd%,W:Xpktsiz%,W:Xctrl%) Poke Xph%+2,Xsum% Xf1%=Xsum%/256 Poke Xph%+3,Xf1% Poke Xph%+4,Xctrl% Poke Xph%+5,(Xpktcod% Xor Xsum% Xor Xf1% Xor Xctrl%) @Wchkwin(1) Return Rem Rem This procedure sends RR's, RJ's, CLOSE, and INITA,B,C's. Rem Procedure Wctlpkt(Wct%) ! wct%=0 for RR, 1 for Rj, 2 for other. If Wct%=0 Wcc%=&H20 Or Rseq% Else If Wct%=1 Wcc%=&H10 Or Rseq% Endif Endif Wc1%=&HAAAA-Wcc% Wc0%=Wc1% And &HFF Div Wc1%,256 Wcx%=9 Xor Wc0% Xor Wc1% Xor Wcc% Out 1,&H10 Out 1,&H9 Out 1,Wc0% Out 1,Wc1% Out 1,Wcc% Out 1,Wcx% Return Rem Rem This procedure waits to receive a data packet. It RR's them as soon Rem as it sees them. Rem Procedure Waitdata For Wf%=1 To 10 @Waitframe If Dpkt! Nwp%=C:Rcv%(L:Rcvbf%,Rpktsiz%) Csum%=C:Chk%(L:Rcvbf%,Rpktsiz%,Cntrol%) If Rsum%=Csum% And ((Rseq%+1) And 7)=Rrseq% ! Verify data and seq. Rseq%=Rrseq% @Wctlpkt(0) Else Found!=False Endif Else Found!=False Endif Exit If Found! If Not Rr! ! Gets around a Telebit peculiarity. @Wctlpkt(1) Endif Next Wf% If Not Found! Print "Failed waiting for a data frame." @Hangup Endif Return Rem Rem This procedure handles the windowing of sent data packets. Rem It sends as many packets as allowed before waiting for RR's. Rem Procedure Wchkwin(Flush%) If ((Xack%+Xwinsiz%+1) And 7)<>Xseq% Bput #2,Xph%,Xpktsizh% Else For Wf%=1 To 10 @Waitframe If Rr! Bput #2,Xph%,Xpktsizh% Else Found!=False For Jr%=1 To Xwinsiz% Xjr%=(Xack%+Jr%) And 7 Bput #2,Xppt%+Xjr%*Xpktsizh%,Xpktsizh% Exit If Xjr%=Xseq% Next Jr% Endif Exit If Rr! Next Wf% If Not Found! Print "Failed waiting for RR." @Hangup Endif Endif If Flush%=1 While Xack%<>Xseq% For Wf%=1 To 10 @Waitframe If Not Rr! Found!=False For Jr%=1 To Xwinsiz% Xjr%=(Xack%+Jr%) And 7 Bput #2,Xppt%+Xjr%*Xpktsizh%,Xpktsizh% Exit If Xjr%=Xseq% Next Jr% Endif Exit If Rr! Next Wf% If Not Found! Print "Failed waiting for flushed RR." @Hangup Endif Wend Endif Return Rem ------------------------------------------------------------------ Rem CHECKSUM ROUTINE LISTING Rem Rem 206F0004 start: move.l 4(sp),a0 ; data packet start address. Rem 322F0008 move.w 8(sp),d1 ; data packet length. Rem 322F000A move.w 10(sp),d2 ; command byte. Rem 203C0000FFFF move.l #$ffff,d0 Rem 4243 clr.w d3 Rem E358 ck1: rol.w #1,d0 ; do checksum on every Rem 2800 move.l d0,d4 ; byte in the data packet. Rem 4285 clr.l d5 Rem 1A18 move.b (a0)+,d5 Rem D045 add.w d5,d0 Rem 3A00 move.w d0,d5 Rem B345 eor.w d1,d5 Rem D645 add.w d5,d3 Rem B084 cmp.l d4,d0 Rem 6E02 bgt.s ovck Rem B740 eor.w d3,d0 Rem 04410001 ovck: sub.w #1,d1 Rem 66E4 bne.s ck1 Rem 0242FFFF and.w #$ffff,d2 Rem B142 eor.w d0,d2 ; do checksum on command byte. Rem 303CAAAA move.w #$aaaa,d0 Rem 9042 sub.w d2,d0 ; subtract everything from AAAA. Rem 02800000FFFF and.l #$ffff,d0 Rem 4E75 rts Rem --------------------------------------------------------------------- Rem INPUT ROUTINE LISTING Rem Rem 286F0004 start: move.l 4(sp),a4 ; Buffer address. Rem 382F0008 move.w 8(sp),d4 ; Packet size. Rem 42A7 clr.l -(sp) ; Execute in superuser mode. Rem 3F3C0020 move.w #$20,-(sp) Rem 4E41 trap #1 Rem 5C8F addq.l #6,sp Rem 2E00 move.l d0,d7 ; Save SUPER stack pointer. Rem 2A39000004BA move.l $4ba,d5 ; Get initial time. Rem 068500000960 add.l #2400,d5 ; Twelve second timeout. Rem 3F3C0001 next: move.w #1,-(sp) ; Test for character. Rem 3F3C0001 move.w #1,-(sp) Rem 4E4D trap #13 Rem 588F addq.l #4,sp Rem 4A40 tst d0 Rem 6714 beq.s nomore ; No character ready. Rem 3F3C0001 move.w #1,-(sp) ; Else, get character. Rem 3F3C0002 move.w #2,-(sp) Rem 4E4D trap #13 Rem 588F addq.l #4,sp Rem 18C0 move.b d0,(a4)+ Rem 5344 subq.w #1,d4 Rem 670C beq.s out Rem 60DC bra.s next Rem 2C39000004BA nomore: move.l $4ba,d6 ; Check timer. Rem 9C85 sub.l d5,d6 Rem 6DD2 blt.s next Rem 2F07 out: move.l D7,-(sp) ; Back to USER mode. Rem 3F3C0020 move.w #$20,-(sp) Rem 4E41 trap #1 Rem 5C8F addq.l #6,sp Rem 2004 move.l d4,d0 ; D0=zero for success. Rem 4E75 rts Rem ------------------------------------------------------------------- *********************************************************************** Rem WRITMAIL V1.0 for use with MAILTRUK -- By John Logajan, Jan '89. Rem --- PUBLIC DOMAIN --- Rem User configuration area. Must be customized before using. Rem User$="john" ! your Mail name. Fullname$="John Logajan" ! your full name. Machine$="logajan" ! your machine name. Dmain$=".mn.org" ! your domain. (.uucp if unassigned) Timezone$="CST" ! your timezone. Gmtfact=6 ! your timezone to GMT factor. Mdir$="c:\mail\" ! main mail directory. Wecall$="bungia,ziltch" ! list of machines you can call. Siglines=2 ! number of lines in signature. (Below) Dim Sig$(Siglines) Sig$(1)="- John Logajan @ 4248 Hamline Ave; Arden Hills, MN 55112 -" Sig$(2)="- ...rutgers!bungia!logajan!john or john@logajan.mn.org -" Rem Print " WRITMAIL V1.0" Gosub Help Repeat Line Input "Path: ",Tpath$ If Len(Tpath$)=0 End Endif Path$="" For J=1 To Len(Tpath$) If Mid$(Tpath$,J,1)<>"\" Then Path$=Path$+Mid$(Tpath$,J,1) Endif Next J P=1 K=Instr(Path$,"!") If K=0 Then Print "Path must use at least one (!) symbol." P=0 Else Neighbor$=Left$(Path$,K-1) Shortpath$=Mid$(Path$,K+1) If Instr(Wecall$,Neighbor$)=0 Then Print "-";Neighbor$;"- is not in our list of sites that we can call." P=0 Else If Len(Shortpath$)=0 Then Print "Cannot end path with an (!) symbol." P=0 Endif Endif Endif Until P=1 Line Input "Subject: ",Sub$ If Upper$(Sub$)="~C" Then End Endif Dim Mes$(20000) M=0 Print Print "Enter message, (.) alone sends message." Print Do If M<0 Then M=0 Endif Inc M Line Input "",Mes$(M) Exit If Mes$(M)="." If Upper$(Mes$(M))="~C" Then End Endif If Upper$(Mes$(M))="~H" Then Dec M Gosub Help Endif If Upper$(Mes$(M))="~D" Then M=M-2 If M<=0 Then M=0 Print "No message." Else Print For P=1 To M Print Mes$(P) Next P Endif Endif If Upper$(Mes$(M))="~V" Then Dec M If M>0 Then Print For P=1 To M Print Mes$(P) Next P Else Print "No message." Endif Endif If Upper$(Left$(Mes$(M),3))="~R " Then Rdfile$=Mid$(Mes$(M),4) If Exist(Rdfile$) Then Open "I",#1,Rdfile$ Lc=0 While Not Eof(#1) Line Input #1,Mes$(M) Inc M Inc Lc Wend Close #1 Print "File of ";Lc;" lines read into message buffer." Else Dec M Print "No such file!" Endif Endif If Upper$(Mes$(M))="~S" M=M-1 For J=1 To Siglines M=M+1 Mes$(M)=Sig$(J) Print Mes$(M) Next J Endif Loop If M=1 Then Print "No message to send -- Not sending." Pause 50 End Endif Seq=10000+(Timer/100 And &H1FFF) Seqf$="A"+Str$(Seq And &H1FFF Or &H1000) Ddir$=Mdir$+Neighbor$+"\"+Seqf$+".D" Xdir$=Mdir$+Neighbor$+"\"+Seqf$+".X" Cdir$=Mdir$+Neighbor$+"\"+Seqf$+".C" Open "O",#1,Ddir$ Gosub Getdate Years=Year-1900 Print #1,"From"'Machine$;"!";User$'Dayweek$'Month$'Day'Time$'Year;Chr$(10); Print #1,"Return-Path: <";Machine$;"!";User$;">";Chr$(10); Print #1,"Received: by"'Machine$;Dmain$'"(MailTruk1.0)";Chr$(10); Print #1," id AA";Seq;";"'Dayweek$;","'Day'Month$'Years'Time$'Timezone$; Print #1,Chr$(10); Print #1,"Date:"'Dayweek$;","'Day'Month$'Years'Time$'Timezone$;Chr$(10); Print #1,"From:"'Machine$;Dmain$;"!";User$'"(";Fullname$;")";Chr$(10); Print #1,"Message-Id: <";(((Years*100+Month)*100+Day)*100+Hgmt)*100+Minute;"."; Print #1,"AA";Seq;"@";Machine$;Dmain$;">";Chr$(10); Print #1,"To:"'Path$;Chr$(10); If Len(Sub$)>1 Then Print #1,"Subject:"'Sub$;Chr$(10); Endif Print #1,Chr$(10); For P=1 To M-1 Print #1,Mes$(P);Chr$(10); Next P Close #1 Open "O",#2,Xdir$ Print #2,"U"'User$'Machine$;Chr$(10); Print #2,"F"'"D.";Neighbor$;Seqf$;Chr$(10); Print #2,"I"'"D.";Neighbor$;Seqf$;Chr$(10); Print #2,"C rmail"'Shortpath$;Chr$(10); Close #2 Open "O",#3,Cdir$ Dest$="D."+Neighbor$+Seqf$ Best$="D."+Machine$+Seqf$ Xest$="X."+Machine$+Seqf$ Print #3,"S"'Dest$'Dest$'User$'"-"'Dest$'"0666" Print #3,"S"'Best$'Xest$'User$'"-"'Best$'"0666" Close #3 Print "Mail sent to outbound file area, awaiting UUCP." Pause 50 End Procedure Getdate ! returns Month,Day,Year,Dayweek,Dayweek$,Month$ Local K,L ! Hour,Minute,Second,Ampm$,Hour12,Hgmt Month=Val(Mid$(Date$,1,2)) Day=Val(Mid$(Date$,4,2)) Year=Val(Mid$(Date$,7,4)) Hour=Val(Mid$(Time$,1,2)) Minute=Val(Mid$(Time$,4,2)) Second=Val(Mid$(Time$,7,2)) If Hour>=12 Then Ampm$="PM" Hour12=Hour-12 Else Ampm$="AM" Hour12=Hour Endif If Hour12=0 Then Hour12=12 Endif Month$=Mid$("JanFebMarAprMayJunJulAugSepOctNovDec",Month*3-2,3) Hgmt=Hour+Gmtfact If Hgmt>=24 Then Hgmt=Hgmt-24 Endif K=Int(0.6+1/Month) L=Year-K Dayweek=Int(13*(Month+12*K+1)/5)+Int(5*L/4)-Int(L/100)+Int(L/400)+Day-1 Dayweek=Dayweek-(7*Int(Dayweek/7))+1 Dayweek$=Mid$("SunMonTueWedThuFriSat",Dayweek*3-2,3) Return Procedure Help Print Print ". alone on line sends message." Print "~r filename -- reads in a file." Print "~d deletes previous line, and reprints message so far." Print "~c cancels message." Print "~h prints this help message." Print "~v reprints message so far." Print "~s adds predefined signature lines to message." Print "Paths are of the form: neighborsite!nextsite!...!sitex!recipient" Print "Subject: is optional. CR to skip it." Print Return ************************************************************************* Rem READMAIL V1.0 for use with MAILTRUK, by John Logajan, Jan '89. Rem --- PUBLIC DOMAIN --- Rem Checks mailbox and reads letters. Saved files are always directed to the Rem main mail directory specified below. Please customize the next two lines. Rem Mdir$="c:\mail\" ! Main upper level mail directory. Mysite$="logajan\" ! Name of site mailbox directory. Rem Mwrk$=Mdir$+Mysite$+"WORK" Md$=Mdir$+Mysite$+"*.*" If Exist(Mwrk$) Kill Mwrk$ Endif If Exist(Md$) Dir Md$ To Mwrk$ Open "I",#3,Mwrk$ M=0 Bored!=False While Not Eof(#3) Line Input #3,Mfil$ Mfix$=Mdir$+Mysite$+Mfil$ If Exist(Mfix$) If Right$(Mfil$,2)=".X" Kill Mfix$ Else If Mfil$<>"WORK" Inc M @More Repeat Cdn!=False Line Input "Next/Command";R$ R$=Upper$(R$) If Len(R$)=0 Or Left$(R$,1)="N" Cdn!=True Endif If Left$(R$,1)="A" Or Left$(R$,1)="S" Snam$=Mid$(R$,3) If Len(Snam$)>0 And Len(Snam$)<13 Open "I",#4,Mfix$ If Left$(R$,1)="A" If Exist(Mdir$+Snam$) Open "A",#1,Mdir$+Snam$ Else Print "File ";Mdir$;Snam$;" doesn't exist for appending"; Print " -- Creating it." R$="S" Open "O",#1,Mdir$+Snam$ Endif Else Open "O",#1,Mdir$+Snam$ Endif Lc=0 While Not Eof(#4) Inc Lc Line Input #4,I$ Print #1,I$ Wend Close #4 Close #1 If Left$(R$,1)="A" Print "File of ";Lc;" lines appended to ";Mdir$;Snam$ Else Print "File of ";Lc;" lines saved in ";Mdir$;Snam$ Endif Else Print "Filename - ";Snam$;" - too long." Endif Endif If Left$(R$,1)="D" Kill Mfix$ Print "Message ";M;" deleted." Endif If Left$(R$,1)="T" If Exist(Mfix$) @More Else Print "Sorry, you have already deleted that message." Endif Endif If Left$(R$,1)="Q" Bored!=True Endif Exit If Bored! If Left$(R$,1)="H" @Hlp Endif Until Cdn! Endif Endif Endif Exit If Bored! Wend Close #3 Kill Mwrk$ If Not Bored! Print Print "No other mail." Endif Else Print "No mail." Endif Pause 50 End Procedure More Open "I",#4,Mfix$ Fll%=Lof(#4) Llt%=0 Dne!=False Print Chr$(27);"EMessage - ";M Llc%=23 Do For Lc=1 To Llc% Line Input #4,C$ Print C$ Llt%=Llt%+Len(C$) If Eof(#4) Dne!=True Endif Exit If Dne! Next Lc Exit If Dne! Pc%=Int(Llt%/Fll%*100) Pmt: Print Chr$(27);"p--MORE--";Chr$(27)+"q(";Pc%;"%)"; R%=Inp(2) Print Chr$(27);"l"; If R%=Asc("Q") Or R%=Asc("q") Dne!=True Endif Exit If Dne! If R%=&HD Llc%=1 Else Llc%=23 Endif If R%=Asc("T") Or R%=Asc("t") Close #4 Open "I",#4,Mfix$ Fll%=Lof(#4) Llt%=0 Print Chr$(27);"EMessage - ";M Llc%=23 Endif If R%=Asc("H") Or R%=Asc("h") @Hlp Goto Pmt Endif Loop Close #4 Return Procedure Hlp Print Print "During message:" Print " q - skips to end." Print " t - reread from the top." Print " CR - read next line." Print " SPACE - read next page." Print " h - print this help listing." Print Print "At command prompt:" Print " n or CR - read next message." Print " d - delete current message." Print " (Undeleted messages remain in mailbox.)" Print " t - reread current message." Print " s filename - save message to file." Print " a filename - append message to file." Print " h - print this help listing." Print " q - quit back to desktop." Print Return ************************************************************************ Packet Driver Protocol G. L. Chesson Bell Laboratories (Shortened by John Logajan) General The technique depends on the notion of a transmission window to determine upper and lower bounds for valid sequence numbers. The transmitter is allowed to retransmit packets having sequence numbers within the window until the receiver indicates that packets have been correctly received. Positive acknowledgement from the receiver moves the window; negative acknowledgement or no acknowledgement causes retransmission. The receiver must ignore duplicate transmission, detect the various errors that may occur, and inform the transmitter when packets are correctly or incorrectly received. Packet Formats The protocol is defined in terms of message transmis- sions of 8-bit bytes. Each message includes one control byte plus a data segment of zero or more information bytes. The allowed data segment sizes range between 32 and 4096 as determined by the formula 32(2k) where k is a 3-bit number. The packet sequence numbers are likewise constrained to 3- bits; i.e. counting proceeds modulo-8. The control byte is partitioned into three fields as depicted below. bit 7 6 5 4 3 2 1 0 t t x x x y y y The t bits indicate a packet type and determine the interpretation to be placed on the xxx and yyy fields. The various interpretations are as follows: tt interpretation 00 control packet 10 data packet 11 short data packet A data segment accompanies all non-control packets. Each transmitter is constrained to observe the maximum data seg- ment size established during initial synchronization by the receiver that it sends to. Type 10 packets have maximal size data segments. Type 11, or short, packets have zero or more data bytes but less than the maximum. The first one or two bytes of the data segment of a short packet are count bytes that indicate the difference between the max- imum size and the number of bytes in the short segment. If the difference is less than 127, one count byte is used. If the difference exceeds 127, then the low-order seven bits of the difference are put in the first data byte and the high- order bit is set as an indicator that the remaining bits of the difference are in the second byte. The sequence number of a non-control packet is given by the xxx field. Control packets are not sequenced. The newest sequence number, excluding duplicate transmissions, accepted by a receiver is placed in the yyy field of non- control packets sent to the other receiver. There are no data bytes associated with a control packet, the xxx field is interpreted as a control message, and the yyy field is a value accompanying the control mes- sage. The control messages are listed below in decreasing priority. That is, if several control messages are to be sent, the lower-numbered ones are sent first. xxx name yyy 1 CLOSE n/a 2 RJ last correctly received sequence number 3 --- --- 4 RR last correctly received sequence number 5 INITC window size 6 INITB data segment size 7 INITA window size The CLOSE message indicates that the communications channel is to be shut down. The RJ, or reject, message indicates that the receiver has detected an error and the sender should retransmit after using the yyy field to update the window. The RR, or receiver ready, message indicates that the receiver has detected no errors; the yyy field updates the sender's window. The INITA/B/C messages are used to set window and data segment sizes. Segment sizes are calculated by the formula 32(2yyy) and window sizes may range between 1 and 7. Measurements of the protocol running on communication links at rates up to 9600 baud showed that a window size of 2 is optimal given a packet size greater than 32 bytes. This means that the link bandwidth can be fully utilized by the software. Message Exchanges Initialization Messages are exchanged between four cooperating enti- ties: two senders and two receivers. This means that the communication channel is thought of as two independent half-duplex data paths. For example the window and segment sizes need not be the same in each direction. Initial synchronization is accomplished with two 3-way handshakes: two each of INITA/INITB/INITC. Each sender transmits INITA messages repeatedly. When an INITA message is received, INITB is sent in return. When an INITB message is received and an INITB message has been sent, an INITC message is sent. The INITA and INITB messages carry with them the packet and window size that each receiver wants to use, and the senders are supposed to comply. When a receiver has seen all three INIT messages, the channel is considered to be open. INIT messages are ignored elsewhere. Data Transport After initial synchronization each receiver sets a modulo-8 incrementing counter R to 0; each sender sets a similar counter S to 1. The value of R is always the number of the most recent correctly received packet. The value of S is always the first sequence number in the output window. Let W denote window size. Note that the value of W may be different for each sender. A sender may transmit packets with sequence numbers in the range S to (S+W-1) mod-8. At any particular time a receiver expects arriving packets to have numbers in the range (R+1) mod-8 to (R+W) mod-8. Packets must arrive in sequence number order are are only acknowledged in order. That is, the next packet a receiver will acknowledge must have sequence number (R+1) mod-8. A receiver acknowledges receipt of data packets by arranging for the value of its R counter to be sent across the channel where it will be used to update an S counter. This is done in two ways. If data is flowing in both direc- tions across a channel then each receiver's current R value is carried in the yyy field of non-control packets. Other- wise when there is no bidirectional data flow, each receiver's R value is transmitted across the link as the yyy field of an RR control packet. Error handling is up to the discretion of the receiver. It can ignore all errors in which case transmitter timeouts must provide for retransmission. The receiver may also gen- erate RJ error control packets. The yyy field of an incom- ing RJ message replaces the S value of the local sender and constitutes a request for retransmission to start at that sequence number. Termination The CLOSE message is used to terminate communications. Software on either or both ends of the communication channel may initiate termination. In any case when one end wants to terminate it sends CLOSE messages until one is received from the other end or until a programmable limit on the number of CLOSE messages is reached. Receipt of a CLOSE message causes a CLOSE message to be sent. Framing The term framing is used to denote the technique by which the beginning and end of a message is detected in a byte stream; error control denotes the method by which transmission errors are detected. A six byte framing envelope is constructed using the control byte C of a packet and five other bytes as depicted below. The symbol denotes the ASCII ctrl/P character. If the envelope is to be followed by a data segment, has the value log2(size)-4; i.e. 1 < k < 8. If k is 9, then the envelope represents a control packet. The and bytes are the low-order and high-order bytes respectively of a 16-bit checksum. For control packets, this value is 0xAAAA minus the control byte C. For data packets, the checksum is calculated by a program. (John Logajan's 68000 version is below.) The byte is the exclusive-or of . Error control is accomplished by checking a received framing envelope for compliance with the definition, and comparing a checksum function of the data segment with . This particular framing strategy assumes data segments are constant-sized: the unused bytes in a short packet are actually transmitted. ------------------------------------------------------ Logajan's 68000 version of the checksum program, as called from a GFA Basic C: call. start: move.l 4(sp),a0 ;data packet start address move.w 8(sp),d1 ;data packet length move.w 10(sp),d2 ;command byte move.l #$ffff,d0 clr.w d3 ck1: rol.w #1,d0 move.l d0,d4 clr.l d5 move.b (a0)+,d5 add.w d5,d0 move.w d0,d5 eor.w d1,d5 add.w d5,d3 cmp.l d4,d0 bgt.s ovck eor.w d3,d0 ovck: sub.w #1,d1 bne.s ck1 and.w #$ffff,d2 eor.w d0,d2 move.w #$aaaa,d0 sub.w d2,d0 and.l #$ffff,d0 ;Checksum in D0. rts ----------------------------------------------------- Example session: Note below: S = we send, R = we receive. After the login: and password: stuff; R Shere[=sitename] S Soursitename R ROK R Pg[other protcols] S Ug S INITA (with our window size) R INITA (with their window size) S INITB (with our packet size) R INITB (with their packet size) S INITC (with our window size, again) R INITC S S workline with D.file name. (If we have work, else H) R RR R SY S RR S data packets, short packet if need, followed by empty pkt. R RR's R CY S RR S S workline with X.file name. R RR R SY S data packets R RR's R CY S H (If we are done) R RR R HN (If they have work, else HY) S RR R S workline D.file S RR S SY R RR R data packets S RR's S CY R RR R S workline X.file S RR S SY R RR R data packets S RR's S CY R RR R H (If they are done too.) S RR S HY R RR R HY R RR S CLOSE R CLOSE S OOOOOO R OOOOOO (Hangup) ----------------------------------------------------- *********************************************************************** -- - John M. Logajan @ Network Systems; 7600 Boone Ave; Brooklyn Park, MN 55428 - - ...rutgers!umn-cs!ns!logajan / logajan@ns.network.com / john@logajan.mn.org -