KERMIT.MOD 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
  1. (* Release 3.10 *)
  2. (*-------------------------------------------------------------------------*
  3. * *
  4. * KERMIT.MOD - COMMS Toolkit KERMIT file protocol *
  5. * *
  6. * COPYRIGHT (C) 1988..1992 Clarion Software Corporation. *
  7. * All Rights Reserved *
  8. * *
  9. *--------------------------------------------------------------------------*)
  10. IMPLEMENTATION MODULE Kermit;
  11. IMPORT ComSetup,Filenames,FIO,FTSupport,Lib,RS232,SPRINTF,Str;
  12. CONST
  13. TooMany = "Too many retries";
  14. UserAbort = "User Abort";
  15. FileOpened = "File Opened";
  16. FileClosed = "File Closed";
  17. EndSession = "Session Ends";
  18. XParams = "Exchanging Params";
  19. OK = 0;
  20. SOH = 1;
  21. CHKLNTH = 1;
  22. YES = ORD("Y");
  23. NO = ORD("N");
  24. MAXTRIES = 5;
  25. MAXPACK = 512; (* My maximum extended-length packet size *)
  26. MAXWINDO = 6; (* My window size *)
  27. (* Kermit Packet Types *)
  28. DATA = 100H+ORD('D');
  29. ACK = 100H+ORD('Y');
  30. NAK = 100H+ORD('N');
  31. SENDINIT = 100H+ORD('S');
  32. ENDSESS = 100H+ORD('B');
  33. FILEHDR = 100H+ORD('F');
  34. EOFILE = 100H+ORD('Z');
  35. ERROR = 100H+ORD('E');
  36. QRSRVD = 100H+ORD('Q');
  37. TIMEOUT = 100H+ORD('T');
  38. ATTR = 100H+ORD('A');
  39. (* flags = Bit Numbers for Capability mask *)
  40. XLPKTS = 1; (* True if extended length packets are supported *)
  41. WINDOWS = 2; (* True if sliding windows are supported *)
  42. ATTPKTS = 3; (* True if attribute packets are supported *)
  43. TYPE
  44. DefaultRec = RECORD
  45. MaxL : CARDINAL; (* The max length packet to send *)
  46. Time : CARDINAL; (* The timeout while waiting for a pkt *)
  47. NPad : CARDINAL; (* The number of pad characters to send *)
  48. PadC : CARDINAL; (* The pad character to use *)
  49. Eoln : CARDINAL; (* The end of line character to use *)
  50. QCtl : CARDINAL; (* The char to use as Ctrl-Quote *)
  51. QBin : CARDINAL; (* The char used for 8th bit quoting *)
  52. Chkt : CARDINAL; (* The frame check type to use *)
  53. Rept : CARDINAL; (* The char used for repeat encoding *)
  54. Capa : BITSET; (* Remote's capability mask *)
  55. WSiz : CARDINAL; (* Window Size *)
  56. XLen : CARDINAL; (* Extended Packet Length *)
  57. END;
  58. Buffer = ARRAY[0..MAXPACK-1] OF CHAR;
  59. TableEntry = RECORD
  60. PacketNo : CARDINAL; (* seq no of this packet *)
  61. Acked : BOOLEAN; (* true if this entry is ok *)
  62. Sent : CARDINAL; (* number of times this pkt sent *)
  63. Data : Buffer; (* the actual packet contents *)
  64. Lenth : CARDINAL; (* Bytes of data in this pkt *)
  65. FilePos : LONGCARD; (* the new file pointer *)
  66. END;
  67. VAR
  68. Tries : CARDINAL; (* Number of attempts to send/receive *)
  69. SeqNo : CARDINAL; (* The sequence number I use/expect next *)
  70. WindowSize : CARDINAL; (* The current window size *)
  71. SizeToSend : CARDINAL; (* Maximum size packet I can send *)
  72. Default : DefaultRec; (* Settings for various protocol options *)
  73. f : FIO.File; (* The file being sent/received *)
  74. (*...............................................*)
  75. PROCEDURE InitVars;
  76. BEGIN
  77. FTSupport.Errors:=0;
  78. FTSupport.LastMessage:='';
  79. FTSupport.XferMode := 'CHK';
  80. FTSupport.Transferred:=0;
  81. FTSupport.Aborted := FALSE;
  82. FTSupport.SizeInBytes:=0;
  83. WindowSize := MAXWINDO;
  84. END InitVars;
  85. (*...............................................*)
  86. PROCEDURE Min(a,b:CARDINAL):CARDINAL;
  87. BEGIN
  88. IF a<b THEN
  89. RETURN(a);
  90. ELSE
  91. RETURN(b);
  92. END;
  93. END Min;
  94. (*...............................................*)
  95. PROCEDURE Max(a,b:CARDINAL):CARDINAL;
  96. BEGIN
  97. IF a>b THEN
  98. RETURN(a);
  99. ELSE
  100. RETURN(b);
  101. END;
  102. END Max;
  103. (*...............................................*)
  104. PROCEDURE ToChar(x:CARDINAL):CARDINAL;
  105. BEGIN
  106. RETURN x+20H;
  107. END ToChar;
  108. (*...............................................*)
  109. PROCEDURE UnChar(x:CARDINAL):CARDINAL;
  110. BEGIN
  111. RETURN x-20H;
  112. END UnChar;
  113. (*...............................................*)
  114. PROCEDURE Ctrl(x:CARDINAL):CARDINAL;
  115. BEGIN
  116. RETURN CARDINAL(BITSET(x) / BITSET(40H));
  117. END Ctrl;
  118. (*...............................................*)
  119. PROCEDURE Receive(TLimit:CARDINAL):CARDINAL;
  120. VAR
  121. c : CHAR;
  122. BEGIN
  123. LOOP
  124. IF RS232.SerialRead(c,TLimit*10) THEN
  125. IF (ORD(c)=SOH) OR (c>=' ') THEN
  126. RETURN ORD(c);
  127. END;
  128. ELSE
  129. RETURN TIMEOUT;
  130. END;
  131. END;
  132. END Receive;
  133. (*...............................................*)
  134. PROCEDURE Msg(s:ARRAY OF CHAR);
  135. VAR
  136. Lnth : CARDINAL;
  137. BEGIN
  138. Lnth := Str.Length(s);
  139. Lib.Move(ADR(s),ADR(FTSupport.LastMessage),Lnth);
  140. FTSupport.LastMessage[Lnth] := 0C;
  141. FTSupport.UpdateStatus;
  142. END Msg;
  143. (*...............................................*)
  144. PROCEDURE Error(s:ARRAY OF CHAR);
  145. BEGIN
  146. INC(FTSupport.Errors);
  147. Msg(s);
  148. END Error;
  149. (*...............................................*)
  150. PROCEDURE SendPacket(tipe,SeqNo,DataLnth:CARDINAL);
  151. VAR
  152. i,p,CheckSum : CARDINAL;
  153. Buff : ARRAY[0..MAXPACK+15] OF CHAR;
  154. Extended : BOOLEAN;
  155. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  156. PROCEDURE sPutChar(c:CARDINAL);
  157. BEGIN
  158. Buff[p] := CHR(c);
  159. CheckSum := (CheckSum+c) MOD 100H;
  160. INC(p);
  161. END sPutChar;
  162. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  163. BEGIN (* SendPacket *)
  164. i:=0;
  165. p:=1;
  166. CheckSum:=0;
  167. WITH Default DO
  168. Extended := (XLPKTS IN Capa) AND (DataLnth>MaxL-(2+CHKLNTH));
  169. END;
  170. Buff[0]:=CHR(SOH);
  171. IF Extended THEN
  172. sPutChar(ToChar(0))
  173. ELSE
  174. sPutChar(ToChar(DataLnth+2+CHKLNTH))
  175. END;
  176. sPutChar(ToChar(SeqNo));
  177. sPutChar(tipe-100H);
  178. IF Extended THEN
  179. sPutChar(ToChar((DataLnth+CHKLNTH) DIV 95));
  180. sPutChar(ToChar((DataLnth+CHKLNTH) MOD 95));
  181. sPutChar(ToChar((CheckSum+(CheckSum>>6)) MOD 64));
  182. END;
  183. WHILE i<DataLnth DO sPutChar(ORD(FTSupport.FBuff[i]));
  184. INC(i)
  185. END;
  186. Buff[p] := CHR(ToChar((CheckSum+(CheckSum>>6)) MOD 64));
  187. Buff[p+1] := CHR(Default.Eoln);
  188. RS232.SerialWrite(Buff,p+2);
  189. END SendPacket;
  190. (*...............................................*)
  191. (* Read a packet and return the packet type. *)
  192. PROCEDURE ReadPacket(VAR SeqNo,Lnth:CARDINAL; SkipSOH:BOOLEAN):CARDINAL;
  193. CONST
  194. BadChecksum = "Bad Checksum";
  195. TYPE
  196. RdStates = (Mark,Len,Seq,Type,LenX1,LenX2,HChk,Data,Check,Err);
  197. VAR
  198. Extended : BOOLEAN;
  199. Timeout,rslt,
  200. PacketType,Cnt,
  201. HCheck,CheckSum : CARDINAL;
  202. RdState : RdStates;
  203. BEGIN
  204. RdState:=Mark;
  205. Timeout:=Default.Time;
  206. Timeout := Max(Timeout,10);
  207. LOOP
  208. IF SkipSOH THEN
  209. rslt:=SOH;
  210. ELSE
  211. rslt:=Receive(Timeout);
  212. END;
  213. IF rslt = TIMEOUT THEN
  214. Error("Timeout");
  215. RETURN TIMEOUT;
  216. ELSIF rslt = SOH THEN
  217. SkipSOH:=FALSE;
  218. RdState:=Len;
  219. CheckSum:=0;
  220. Cnt:=0;
  221. Extended:=FALSE;
  222. ELSE
  223. IF RdState # Check THEN
  224. CheckSum := CARDINAL(BITSET(CheckSum+rslt)*BITSET(0FFH));
  225. END;
  226. CASE RdState OF
  227. Mark : (* do nothing, as SOH should have been trapped above *)|
  228. Len : Lnth:=UnChar(rslt);
  229. Extended:=(Lnth=0);
  230. IF NOT Extended THEN
  231. DEC(Lnth,2+CHKLNTH);
  232. END;
  233. RdState:=Seq; |
  234. Seq : SeqNo:=UnChar(rslt);
  235. RdState:=Type; |
  236. Type : PacketType := 100H+rslt;
  237. IF Extended THEN
  238. RdState := LenX1
  239. ELSIF Lnth>0 THEN
  240. RdState:=Data
  241. ELSE
  242. RdState:=Check
  243. END; |
  244. LenX1 : Lnth:=UnChar(rslt);
  245. RdState:=LenX2; |
  246. LenX2 : Lnth := (Lnth*95+UnChar(rslt)) - CHKLNTH;
  247. HCheck:=CheckSum;
  248. RdState := HChk; |
  249. HChk : IF rslt=ToChar((HCheck+(HCheck>>6)) MOD 64) THEN
  250. IF Lnth>0 THEN
  251. RdState:=Data;
  252. ELSE
  253. RdState:=Check;
  254. END;
  255. ELSE
  256. Error(BadChecksum);
  257. RETURN TIMEOUT;
  258. END; |
  259. Data : FTSupport.FBuff[Cnt] := CHR(rslt);
  260. INC(Cnt);
  261. IF Cnt=Lnth THEN
  262. RdState:=Check;
  263. END; |
  264. Check : IF rslt=ToChar((CheckSum+(CheckSum>>6)) MOD 64) THEN
  265. IF PacketType=ERROR THEN
  266. Msg("Error Packet received");
  267. END;
  268. RETURN PacketType;
  269. ELSE
  270. Error(BadChecksum); RETURN TIMEOUT;
  271. END; |
  272. Err : (* purge modem buffer *);
  273. END;
  274. END;
  275. END;
  276. END ReadPacket;
  277. (*...............................................*)
  278. PROCEDURE NxtPktNo(SeqNo:CARDINAL):CARDINAL;
  279. BEGIN
  280. RETURN CARDINAL(BITSET(SeqNo+1) * BITSET(3FH));
  281. END NxtPktNo;
  282. (*...............................................*)
  283. PROCEDURE SendInitParms(tipe:CARDINAL);
  284. VAR
  285. MyCapas : BITSET;
  286. BEGIN
  287. (* This line says that I can use attribute and extended length packets *)
  288. MyCapas := {WINDOWS,XLPKTS,ATTPKTS};
  289. WITH Default DO
  290. WindowSize := Min(MAXWINDO,WSiz);
  291. FTSupport.FBuff[ 0] := CHR(ToChar(MaxL));
  292. FTSupport.FBuff[ 1] := CHR(ToChar(Time));
  293. FTSupport.FBuff[ 2] := CHR(ToChar(0));
  294. FTSupport.FBuff[ 3] := CHR(Ctrl(0));
  295. FTSupport.FBuff[ 4] := CHR(ToChar(Eoln));
  296. FTSupport.FBuff[ 5] := CHR(QCtl);
  297. FTSupport.FBuff[ 6] := 'Y';
  298. FTSupport.FBuff[ 7] := '1';
  299. FTSupport.FBuff[ 8] := CHR(Rept);
  300. FTSupport.FBuff[ 9] := CHR(ToChar(CARDINAL(MyCapas)));
  301. FTSupport.FBuff[10] := CHR(ToChar(WindowSize)); (* Window Size *)
  302. FTSupport.FBuff[11] := CHR(ToChar(MAXPACK DIV 95)); (* pkt lnth - High bits *)
  303. FTSupport.FBuff[12] := CHR(ToChar(MAXPACK MOD 95)); (* pkt lnth - Low bits *)
  304. END;
  305. SendPacket(tipe,SeqNo,13);
  306. END SendInitParms;
  307. (*...............................................*)
  308. PROCEDURE GetInitParams():CARDINAL;
  309. TYPE
  310. InitStates = (maxl,time,npad,padc,eol,qctl,qbin,chkt,rept,capas,capas2,windo,maxlx1,maxlx2,done);
  311. VAR
  312. rslt,p,c,Seq,Lnth : CARDINAL;
  313. temp : BITSET;
  314. State : InitStates;
  315. BEGIN
  316. IF Tries=MAXTRIES THEN
  317. Error(TooMany);
  318. RETURN(ERROR);
  319. END;
  320. INC(Tries);
  321. rslt := ReadPacket(Seq,Lnth,FALSE);
  322. IF (rslt # SENDINIT) AND (rslt # ACK) THEN
  323. RETURN(rslt);
  324. END;
  325. (* Set defaults *)
  326. WITH Default DO
  327. Capa:={};
  328. p:=0;
  329. State:=maxl;
  330. LOOP
  331. IF p<Lnth THEN
  332. c:=ORD(FTSupport.FBuff[p]);
  333. INC(p)
  334. ELSE
  335. c:=0;
  336. END;
  337. CASE State OF
  338. maxl : MaxL:=UnChar(c);
  339. State:=time; |
  340. time : Time:=UnChar(c);
  341. State:=npad; |
  342. npad : NPad:=UnChar(c);
  343. IF NPad=0 THEN
  344. INC(p);
  345. State:=eol;
  346. ELSE
  347. State:=padc;
  348. END; |
  349. padc : PadC:=Ctrl(c);
  350. State:=eol; |
  351. eol : Eoln:=UnChar(c);
  352. State:=qctl; |
  353. qctl : QCtl:=c;
  354. State:=qbin; |
  355. (* optional features *)
  356. qbin : IF (c=YES) OR (c=NO) THEN
  357. QBin:=0;
  358. ELSE
  359. QBin:=c;
  360. END;
  361. State:=chkt; |
  362. chkt : (* Ignore frame check type for the moment *)
  363. State := rept; |
  364. rept : IF c=32 THEN
  365. Rept:=0;
  366. ELSE
  367. Rept:=c;
  368. END;
  369. State:=capas; |
  370. capas : IF c<32 THEN
  371. Capa:={};
  372. ELSE
  373. Capa:=BITSET(UnChar(c));
  374. END;
  375. IF 0 IN Capa THEN
  376. State:=capas2;
  377. ELSE
  378. State:=windo;
  379. END; |
  380. capas2 : IF c<32 THEN
  381. temp:={};
  382. ELSE
  383. temp:=BITSET(UnChar(c));
  384. END;
  385. IF NOT (0 IN Capa) THEN
  386. State:=windo;
  387. END; |
  388. windo : IF c<32 THEN
  389. WSiz:=0;
  390. ELSE
  391. WSiz:=UnChar(c);
  392. END;
  393. State:=maxlx1; |
  394. maxlx1 : IF c<32 THEN
  395. XLen:=0;
  396. ELSE
  397. XLen:=UnChar(c);
  398. END;
  399. State:=maxlx2; |
  400. maxlx2 : IF c>31 THEN
  401. XLen := XLen+(UnChar(c)<<6);
  402. END;
  403. State:=done; |
  404. done : EXIT; |
  405. END;
  406. END;
  407. END;
  408. RETURN rslt;
  409. END GetInitParams;
  410. (*...............................................*)
  411. PROCEDURE WriteData(Lnth:CARDINAL;VAR FBuff,Buff:ARRAY OF CHAR;WriteIt:BOOLEAN):CARDINAL;
  412. (* Get data from an incoming packet into a file. *)
  413. VAR
  414. i,rep,c,BuffPtr : CARDINAL;
  415. SetBit8 : BOOLEAN;
  416. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  417. PROCEDURE wPutChar(c:CARDINAL);
  418. BEGIN
  419. IF WriteIt AND (BuffPtr=MAXPACK) THEN
  420. INC(FTSupport.Transferred,MAXPACK);
  421. FIO.WrBin(f,Buff,MAXPACK);
  422. BuffPtr := 0;
  423. END;
  424. Buff[BuffPtr] := CHR(c);
  425. INC(BuffPtr);
  426. END wPutChar;
  427. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  428. PROCEDURE Low(In:CARDINAL):CARDINAL;
  429. BEGIN
  430. RETURN CARDINAL(BITSET(In) - BITSET{7});
  431. END Low;
  432. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  433. BEGIN (* WriteData *)
  434. BuffPtr:=0;
  435. i:=0;
  436. WITH Default DO
  437. WHILE i<Lnth DO
  438. rep := 1;
  439. c:=ORD(FBuff[i]);
  440. INC(i); (* Get character *)
  441. IF c=Rept THEN
  442. rep := UnChar(ORD(FBuff[i]));
  443. c := ORD(FBuff[i+1]);
  444. INC(i,2);
  445. END;
  446. SetBit8:=FALSE;
  447. IF c=QBin THEN
  448. SetBit8 := TRUE;
  449. c:=ORD(FBuff[i]);
  450. INC(i);
  451. END;
  452. IF c=QCtl THEN (* Control quote? *)
  453. c:=ORD(FBuff[i]);
  454. INC(i); (* Get the quoted character *)
  455. IF (Low(c) # QCtl) & (Low(c) # QBin) & (Low(c) # Rept) THEN
  456. c:=Ctrl(c);
  457. END;
  458. END;
  459. IF SetBit8 THEN
  460. c := CARDINAL(BITSET(c)+{7});
  461. END;
  462. WHILE rep>0 DO
  463. wPutChar(c);
  464. DEC(rep); (* Put the char in the file *)
  465. END;
  466. END;
  467. END;
  468. IF (WriteIt) AND (BuffPtr>0) THEN
  469. FIO.WrBin(f,Buff,BuffPtr);
  470. INC(FTSupport.Transferred,LONGCARD(BuffPtr));
  471. END;
  472. IF WriteIt THEN
  473. FTSupport.UpdateStatus
  474. END;
  475. RETURN BuffPtr;
  476. END WriteData;
  477. (*...............................................*)
  478. PROCEDURE GetFileHeader():CARDINAL;
  479. VAR
  480. rslt,Seq,Lnth : CARDINAL;
  481. BEGIN
  482. LOOP
  483. IF Tries=MAXTRIES THEN
  484. Error(TooMany);
  485. RETURN(ERROR);
  486. END;
  487. INC(Tries);
  488. rslt := ReadPacket(Seq,Lnth,FALSE);
  489. CASE rslt OF
  490. FILEHDR : Lnth := WriteData(Lnth,FTSupport.FBuff,FTSupport.FileSpec,FALSE);
  491. FTSupport.FileSpec[Lnth] := 0C;
  492. FTSupport.CompleteFilename;
  493. FTSupport.NewFilename;
  494. f := FIO.Create(FTSupport.FileSpec);
  495. IF FIO.IOresult() # 0 THEN
  496. Error("File Create Error"); RETURN ERROR
  497. END;
  498. Msg(FileOpened); RETURN rslt; |
  499. TIMEOUT : SendPacket(NAK,NxtPktNo(SeqNo),0); |
  500. ERROR,
  501. SENDINIT,
  502. EOFILE,
  503. ENDSESS : RETURN rslt; |
  504. ELSE
  505. RETURN ERROR;
  506. END;
  507. END;
  508. END GetFileHeader;
  509. (*...............................................*)
  510. PROCEDURE GetFileAttributes(Lnth:CARDINAL);
  511. VAR
  512. attr : CHAR;
  513. p,rslt,len : CARDINAL;
  514. BEGIN
  515. (* Run along attribute data looking for "Size in Bytes" attribute. *)
  516. (* This is the only attribute we can actually use. *)
  517. p:=0;
  518. WHILE p<Lnth DO
  519. attr:=FTSupport.FBuff[p];
  520. INC(p);
  521. len:=UnChar(ORD(FTSupport.FBuff[p]));
  522. INC(p);
  523. IF attr='1' THEN (* found Size in bytes *)
  524. FTSupport.SizeInBytes := 0;
  525. WHILE len>0 DO
  526. FTSupport.SizeInBytes := FTSupport.SizeInBytes*10+LONGCARD(ORD(FTSupport.FBuff[p])-48);
  527. INC(p);
  528. DEC(len);
  529. END;
  530. FTSupport.UpdateStatus;
  531. ELSE
  532. INC(p,len);
  533. END;
  534. END;
  535. END GetFileAttributes;
  536. (*...............................................*)
  537. PROCEDURE GetFileData():CARDINAL;
  538. VAR
  539. i,p,rslt,Seq,Lnth,
  540. first,last : CARDINAL;
  541. RcvTable : ARRAY[0..MAXWINDO-1] OF TableEntry;
  542. WriteBuff : Buffer;
  543. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  544. PROCEDURE NAKit(Seq:CARDINAL);
  545. BEGIN
  546. SendPacket(NAK,Seq,0);
  547. END NAKit;
  548. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  549. PROCEDURE InitReceiveTable(FirstSeqNo:CARDINAL);
  550. VAR
  551. i : CARDINAL;
  552. BEGIN
  553. first:=0;
  554. last:=WindowSize-1;
  555. FOR i:=0 TO WindowSize-1 DO
  556. WITH RcvTable[i] DO
  557. PacketNo := CARDINAL(BITSET(FirstSeqNo+i+1)*BITSET(3FH));
  558. Acked := FALSE;
  559. Lenth := 0;
  560. END;
  561. END;
  562. END InitReceiveTable;
  563. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  564. PROCEDURE Duplicate(Seq:CARDINAL; VAR Index:CARDINAL):BOOLEAN;
  565. VAR
  566. i : CARDINAL;
  567. BEGIN
  568. FOR i:=0 TO WindowSize-1 DO
  569. IF Seq=RcvTable[i].PacketNo THEN
  570. Index:=i;
  571. RETURN(TRUE)
  572. END;
  573. END;
  574. RETURN FALSE;
  575. END Duplicate;
  576. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  577. PROCEDURE MostWanted():CARDINAL;
  578. VAR
  579. i,p : CARDINAL;
  580. BEGIN
  581. p:=first;
  582. FOR i:=0 TO WindowSize-1 DO
  583. IF NOT RcvTable[p].Acked THEN
  584. RETURN(p);
  585. END;
  586. p := (p+1) MOD WindowSize;
  587. END;
  588. RETURN NxtPktNo(RcvTable[last].PacketNo);
  589. END MostWanted;
  590. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  591. PROCEDURE RotateTable():CARDINAL;
  592. VAR
  593. i,NextPkt :CARDINAL;
  594. BEGIN
  595. NextPkt := NxtPktNo(RcvTable[last].PacketNo);
  596. (* Ok, now rotate the window. Not physically, just adjust the *)
  597. (* first and last pointers. *)
  598. last:=first;
  599. first:=(first+1) MOD WindowSize;
  600. WITH RcvTable[last] DO (* write old contents then clear entry *)
  601. IF NOT Acked THEN
  602. RETURN(ERROR);
  603. END;
  604. IF Lenth>0 THEN
  605. i:=WriteData(Lenth,Data,WriteBuff,TRUE);
  606. END;
  607. Acked:=FALSE;
  608. PacketNo:=NextPkt;
  609. Lenth:=0;
  610. END;
  611. RETURN OK;
  612. END RotateTable;
  613. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  614. PROCEDURE StoreData(Index,Lnth:CARDINAL);
  615. BEGIN
  616. WITH RcvTable[Index] DO
  617. IF Acked THEN
  618. Msg("Duplicate Packet");
  619. END;
  620. Acked:=TRUE;
  621. Lenth:=Lnth;
  622. Lib.Move(ADR(FTSupport.FBuff),ADR(Data),Lenth);
  623. END;
  624. END StoreData;
  625. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  626. BEGIN (* GetFileData *)
  627. InitReceiveTable(SeqNo); (* initialise receive table *)
  628. LOOP
  629. IF FTSupport.AbortRequested() THEN
  630. Msg(UserAbort);
  631. RETURN ERROR;
  632. END;
  633. IF Tries=MAXTRIES THEN
  634. Msg(TooMany);
  635. RETURN(ERROR);
  636. END;
  637. INC(Tries);
  638. rslt := ReadPacket(Seq,Lnth,FALSE);
  639. CASE rslt OF
  640. DATA : Tries := 0;
  641. IF Duplicate(Seq,i) THEN
  642. SendPacket(ACK,Seq,0);
  643. StoreData(i,Lnth);
  644. ELSE (* new packet *)
  645. i:=0;
  646. SendPacket(ACK,Seq,0);
  647. REPEAT
  648. INC(i);
  649. IF RotateTable()=ERROR THEN
  650. Error("Out of Sequence!");
  651. RETURN ERROR;
  652. END;
  653. UNTIL Seq=RcvTable[last].PacketNo;
  654. StoreData(last,Lnth);
  655. IF i>1 THEN (* NAK any packets skipped *)
  656. p:=first;
  657. FOR i:=0 TO WindowSize-1 DO
  658. WITH RcvTable[p] DO
  659. IF NOT Acked THEN
  660. Error("NAK: Packets Skipped");
  661. NAKit(PacketNo);
  662. END;
  663. END;
  664. p := (p+1) MOD WindowSize;
  665. END;
  666. END;
  667. END; |
  668. ATTR : Tries := 0;
  669. SendPacket(ACK,Seq,0);
  670. GetFileAttributes(Lnth);
  671. InitReceiveTable(Seq); |
  672. TIMEOUT : Error("NAK: Timeout");
  673. NAKit(MostWanted()); |
  674. ERROR : RETURN rslt; |
  675. FILEHDR : RETURN rslt; |
  676. EOFILE : p:=first;
  677. FOR i:=0 TO WindowSize-1 DO
  678. WITH RcvTable[p] DO
  679. IF Acked AND (Lenth>0) THEN
  680. Lnth := WriteData(Lenth,Data,WriteBuff,TRUE);
  681. END;
  682. END;
  683. p := (p+1) MOD WindowSize;
  684. END;
  685. RETURN EOFILE; |
  686. ELSE
  687. RETURN ERROR;
  688. END;
  689. SeqNo := Seq;
  690. END;
  691. END GetFileData;
  692. (*...............................................*)
  693. PROCEDURE RxStateMachine():CARDINAL;
  694. TYPE
  695. RxStates = (rSendInit,rFHeader,rFData);
  696. VAR
  697. rslt : CARDINAL;
  698. RxState : RxStates;
  699. BEGIN
  700. RxState := rSendInit;
  701. SeqNo := 0; (* Start Sequence Number *)
  702. Default.Time := 15; (* default timeout for Send-Init packet *)
  703. Default.Eoln := 13;
  704. Tries := 0;
  705. LOOP
  706. CASE RxState OF
  707. rSendInit : rslt := GetInitParams();
  708. IF rslt=ERROR THEN
  709. RETURN ERROR
  710. ELSIF rslt=SENDINIT THEN
  711. SendInitParms(ACK);
  712. Tries := 0;
  713. RxState:=rFHeader;
  714. ELSE (* timeout *)
  715. SendPacket(NAK,SeqNo,0);
  716. END; |
  717. rFHeader : InitVars;
  718. rslt := GetFileHeader();
  719. IF rslt=ERROR THEN
  720. RETURN ERROR
  721. ELSIF rslt=SENDINIT THEN
  722. SendInitParms(ACK);
  723. ELSIF rslt=EOFILE THEN
  724. SendPacket(ACK,SeqNo,0);
  725. ELSIF rslt=ENDSESS THEN
  726. SeqNo := NxtPktNo(SeqNo);
  727. SendPacket(ACK,SeqNo,0);
  728. Msg(EndSession);
  729. RETURN OK;
  730. ELSIF rslt=FILEHDR THEN
  731. SeqNo := NxtPktNo(SeqNo);
  732. SendPacket(ACK,SeqNo,0);
  733. Tries := 0;
  734. RxState := rFData;
  735. END; |
  736. rFData : rslt := GetFileData();
  737. IF rslt=ERROR THEN
  738. RETURN ERROR
  739. ELSIF rslt=FILEHDR THEN
  740. SendPacket(ACK,SeqNo,0);
  741. ELSIF rslt=EOFILE THEN
  742. SeqNo := NxtPktNo(SeqNo);
  743. SendPacket(ACK,SeqNo,0);
  744. Msg(FileClosed);
  745. FIO.Close(f);
  746. Tries := 0;
  747. RxState := rFHeader;
  748. END; |
  749. END;
  750. END;
  751. END RxStateMachine;
  752. (*...............................................*)
  753. PROCEDURE KermitReceive():CARDINAL;
  754. VAR
  755. rslt:CARDINAL;
  756. BEGIN
  757. InitVars;
  758. FTSupport.OpenStatusWindow('SuperKermit Download');
  759. rslt := RxStateMachine();
  760. IF rslt=ERROR THEN
  761. SendPacket(ERROR,SeqNo,0);
  762. END;
  763. FIO.Close(f);
  764. FTSupport.CloseStatusWindow;
  765. RETURN rslt;
  766. END KermitReceive;
  767. (*...............................................*)
  768. PROCEDURE GetPath(Wild:ARRAY OF CHAR; VAR Path:ARRAY OF CHAR):BOOLEAN;
  769. VAR
  770. Drive,Ext : ARRAY[0..4] OF CHAR;
  771. Name : ARRAY[0..12] OF CHAR;
  772. BEGIN
  773. IF NOT Filenames.ParseFilename(Wild,Drive,Path,Name,Ext) THEN
  774. RETURN(FALSE);
  775. END;
  776. Name := '';
  777. Ext:='';
  778. Filenames.MakeFilename(Drive,Path,Name,Ext,Path);
  779. RETURN TRUE;
  780. END GetPath;
  781. (*...............................................*)
  782. PROCEDURE SendMyParams():CARDINAL;
  783. VAR
  784. rslt : CARDINAL;
  785. BEGIN
  786. Msg(XParams);
  787. WITH Default DO
  788. WITH ComSetup.Setup.Kermit DO
  789. MaxL:=90;
  790. Time:=15;
  791. NPad:=NumPadChars;
  792. PadC:=ORD(PadChar);
  793. Eoln:=ORD(EolChar);
  794. QCtl:=ORD(CtlQuote);
  795. QBin:=ORD(EightBitQuote);
  796. Chkt:=1;
  797. Rept:=ORD(ReptPrefix);
  798. Capa:={WINDOWS,XLPKTS,ATTPKTS};
  799. WSiz:=MAXWINDO;
  800. XLen:=MAXPACK;
  801. END;
  802. END;
  803. Tries:=0;
  804. LOOP
  805. SendInitParms(SENDINIT);
  806. rslt := GetInitParams();
  807. CASE rslt OF
  808. ACK : (* this is what I want*)
  809. WITH Default DO
  810. IF WINDOWS IN Capa THEN
  811. WindowSize := Max(1,Min(WSiz,MAXWINDO));
  812. ELSE
  813. WindowSize := 1;
  814. END;
  815. IF (QBin=YES) OR (QBin=NO) THEN
  816. QBin:=0;
  817. END;
  818. IF XLPKTS IN Capa THEN
  819. SizeToSend := Min(MAXPACK,XLen-CHKLNTH)
  820. ELSE
  821. SizeToSend := MaxL-(CHKLNTH+2)
  822. END;
  823. END;
  824. SeqNo := NxtPktNo(SeqNo);
  825. RS232.FlushInBuf;
  826. RETURN ACK; |
  827. TIMEOUT : (* loop again *) |
  828. ELSE
  829. RETURN ERROR;
  830. END;
  831. END;
  832. END SendMyParams;
  833. (*...............................................*)
  834. PROCEDURE SendMessage(tipe,DataLnth:CARDINAL):CARDINAL;
  835. VAR
  836. rslt,Seq,Lnth : CARDINAL;
  837. BEGIN
  838. Tries := 0;
  839. LOOP
  840. SendPacket(tipe,SeqNo,DataLnth);
  841. rslt := ReadPacket(Seq,Lnth,FALSE);
  842. IF (rslt=ERROR) OR (rslt=ACK) THEN
  843. SeqNo := NxtPktNo(SeqNo);
  844. RETURN(rslt);
  845. END;
  846. END;
  847. END SendMessage;
  848. (*...............................................*)
  849. PROCEDURE SendFileHeader(VAR Path:ARRAY OF CHAR):CARDINAL;
  850. (* send file header and lnth attribute *)
  851. VAR
  852. rslt,Lnth : CARDINAL;
  853. BEGIN
  854. Lnth:=Str.Length(FTSupport.FileSpec);
  855. Str.Copy(FTSupport.FBuff,FTSupport.FileSpec);
  856. rslt := SendMessage(FILEHDR,Lnth);
  857. IF rslt # ACK THEN
  858. RETURN(rslt);
  859. END;
  860. IF Path[0] # 0C THEN
  861. Str.Concat(FTSupport.FileSpec,Path,FTSupport.FileSpec);
  862. END;
  863. f := FIO.Open(FTSupport.FileSpec);
  864. IF FIO.IOresult() # 0 THEN
  865. RETURN(ERROR);
  866. END;
  867. IF NOT (ATTPKTS IN Default.Capa) THEN
  868. RETURN(ACK);
  869. END;
  870. FTSupport.SizeInBytes := FIO.Size(f);
  871. SPRINTF.SPrintF1("1$%u",FTSupport.SizeInBytes,FTSupport.FBuff);
  872. Lnth := Str.Length(FTSupport.FBuff);
  873. FTSupport.FBuff[1] := CHR(ToChar(Lnth-2));
  874. FTSupport.NewFilename;
  875. Msg(FileOpened);
  876. RETURN SendMessage(ATTR,Lnth);
  877. END SendFileHeader;
  878. (*...............................................*)
  879. PROCEDURE SendFileData():CARDINAL;
  880. TYPE
  881. SetOfChar = SET OF CHAR;
  882. VAR
  883. rslt,rptr,
  884. bytesread,
  885. NextToSend,first,
  886. last,pbstack : CARDINAL;
  887. Stack : ARRAY[0..1] OF CARDINAL;
  888. CtrlChars : SetOfChar;
  889. RxPos : LONGCARD;
  890. SndTable : ARRAY[0..MAXWINDO-1] OF TableEntry;
  891. ReadBuff : Buffer;
  892. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  893. PROCEDURE PushBack(c:CARDINAL);
  894. BEGIN
  895. Stack[pbstack]:=c;
  896. INC(pbstack);
  897. END PushBack;
  898. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  899. PROCEDURE GetChar(VAR c:CARDINAL):CARDINAL;
  900. BEGIN
  901. IF pbstack>0 THEN
  902. DEC(pbstack);
  903. c:=Stack[pbstack];
  904. ELSE
  905. WHILE rptr=bytesread DO
  906. IF bytesread<MAXPACK THEN
  907. c:=0FFFFH;
  908. RETURN(c);
  909. END;
  910. bytesread := FIO.RdBin(f,ReadBuff,MAXPACK);
  911. INC(RxPos,LONGCARD(bytesread));
  912. rptr := 0;
  913. END;
  914. c := ORD(ReadBuff[rptr]);
  915. INC(rptr);
  916. END;
  917. RETURN c;
  918. END GetChar;
  919. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  920. PROCEDURE FillBuffer(Index:CARDINAL);
  921. VAR
  922. wptr,c,c2,nextc,
  923. rep,SafetyMargin: CARDINAL;
  924. BEGIN
  925. WITH SndTable[Index] DO
  926. wptr:=0;
  927. SafetyMargin:=SizeToSend-5;
  928. IF Default.QBin=0 THEN
  929. INC(SafetyMargin);
  930. END;
  931. WHILE (wptr<=SafetyMargin) AND (GetChar(c) # 0FFFFH) DO
  932. rep:=1;
  933. IF Default.Rept>0 THEN (* are we allowed repeated chars? *)
  934. (* count repeated chars *)
  935. WHILE (rep<94) AND (GetChar(nextc)=c) DO
  936. INC(rep);
  937. END;
  938. IF rep<94 THEN
  939. PushBack(nextc);
  940. END;
  941. IF rep>1 THEN
  942. IF rep=2 THEN (* not worth compressing *)
  943. PushBack(c);
  944. ELSE
  945. Data[wptr]:=CHR(Default.Rept);
  946. INC(wptr);
  947. Data[wptr]:=CHR(ToChar(rep));
  948. INC(wptr);
  949. END;
  950. END;
  951. END;
  952. c2 := CARDINAL(BITSET(c)*BITSET(127));
  953. IF (Default.QBin>0) AND (c>127) THEN
  954. c:=c2;
  955. Data[wptr]:=CHR(Default.QBin);
  956. INC(wptr);
  957. END;
  958. IF CHR(c) IN CtrlChars THEN
  959. Data[wptr]:=CHR(Default.QCtl);
  960. INC(wptr);
  961. IF (c2<32) OR (c2=127) THEN
  962. c:=Ctrl(c);
  963. END;
  964. END;
  965. Data[wptr]:=CHR(c);
  966. INC(wptr);
  967. END;
  968. Lenth := wptr;
  969. FilePos := RxPos;
  970. END;
  971. END FillBuffer;
  972. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  973. PROCEDURE InitSndTable;
  974. VAR
  975. i : CARDINAL;
  976. BEGIN
  977. CtrlChars := SetOfChar{0C..CHR(31),CHR(127),CHR(128)..CHR(159),CHR(255)};
  978. INCL(CtrlChars,CHR(Default.Rept));
  979. INCL(CtrlChars,CHR(Default.QBin));
  980. INCL(CtrlChars,CHR(Default.QCtl));
  981. pbstack:=0;
  982. rptr:=0FFFFH;
  983. bytesread:=rptr;
  984. first:=0;
  985. last:=WindowSize-1;
  986. RxPos := 0;
  987. FOR i:=0 TO WindowSize-1 DO
  988. WITH SndTable[i] DO
  989. PacketNo:=(SeqNo+i) MOD 64;
  990. Acked:=FALSE;
  991. Sent := 0;
  992. END;
  993. FillBuffer(i);
  994. END;
  995. END InitSndTable;
  996. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  997. PROCEDURE SendIt(Index:CARDINAL):CARDINAL;
  998. BEGIN
  999. WITH SndTable[Index] DO
  1000. IF Lenth=0 THEN
  1001. RETURN(OK);
  1002. END;
  1003. IF Sent=MAXTRIES THEN
  1004. RETURN(ERROR);
  1005. END;
  1006. INC(Sent);
  1007. Lib.Move(ADR(Data),ADR(FTSupport.FBuff),Lenth);
  1008. SendPacket(DATA,PacketNo,Lenth);
  1009. END;
  1010. RETURN OK;
  1011. END SendIt;
  1012. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  1013. PROCEDURE WindowClosed():BOOLEAN;
  1014. (* Try and find the next packet to send by searching for the next *)
  1015. (* packet which has not yet been sent and which has length>0. If *)
  1016. (* one is found then the window has not yet closed, otherwise it *)
  1017. (* is closed. *)
  1018. VAR
  1019. i,p : CARDINAL;
  1020. BEGIN
  1021. p:=NextToSend;
  1022. FOR i:=0 TO WindowSize-1 DO
  1023. WITH SndTable[p] DO
  1024. IF (Sent=0) AND (Lenth>0) THEN
  1025. NextToSend:=p;
  1026. RETURN(FALSE);
  1027. END;
  1028. END;
  1029. p := (p+1) MOD WindowSize;
  1030. END;
  1031. RETURN TRUE;
  1032. END WindowClosed;
  1033. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  1034. PROCEDURE Done():BOOLEAN;
  1035. VAR
  1036. i : CARDINAL;
  1037. BEGIN
  1038. FOR i:=0 TO WindowSize-1 DO
  1039. IF SndTable[i].Lenth>0 THEN
  1040. RETURN(FALSE);
  1041. END;
  1042. END;
  1043. RETURN TRUE;
  1044. END Done;
  1045. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  1046. PROCEDURE TestReply():CARDINAL;
  1047. VAR
  1048. next,rslt,Seq,
  1049. Lnth,i,ptr : CARDINAL;
  1050. GotSOH : BOOLEAN;
  1051. c : CHAR;
  1052. BEGIN
  1053. LOOP
  1054. IF FTSupport.AbortRequested() THEN
  1055. Msg(UserAbort);
  1056. RETURN(ERROR);
  1057. END;
  1058. IF Done() THEN
  1059. RETURN(OK);
  1060. END;
  1061. Tries:=0;
  1062. GotSOH:=FALSE;
  1063. IF WindowClosed() THEN
  1064. (* force a wait for a reply *)
  1065. rslt := ReadPacket(Seq,Lnth,FALSE);
  1066. ELSE
  1067. (* Flush input buffer, looking out for a reply *)
  1068. IF RS232.SerialRead(c,0) THEN
  1069. REPEAT
  1070. UNTIL (ORD(c)=SOH) OR (NOT RS232.SerialRead(c,0));
  1071. GotSOH := (ORD(c)=SOH);
  1072. END;
  1073. IF GotSOH THEN
  1074. rslt := ReadPacket(Seq,Lnth,TRUE);
  1075. ELSE
  1076. RETURN OK;
  1077. END
  1078. END;
  1079. CASE rslt OF
  1080. ACK : ptr:=first;
  1081. FOR i:=0 TO WindowSize-1 DO
  1082. WITH SndTable[ptr] DO
  1083. IF PacketNo=Seq THEN
  1084. Acked:=TRUE;
  1085. END;
  1086. END;
  1087. ptr := (ptr+1) MOD WindowSize;
  1088. END;
  1089. (* Rotate the table *)
  1090. WHILE SndTable[first].Acked DO
  1091. FTSupport.Transferred := SndTable[first].FilePos;
  1092. FTSupport.UpdateStatus;
  1093. next := NxtPktNo(SndTable[last].PacketNo);
  1094. last:=first;
  1095. first:=(first+1) MOD WindowSize;
  1096. WITH SndTable[last] DO
  1097. PacketNo:=next;
  1098. Acked:=FALSE;
  1099. Sent:=0;
  1100. END;
  1101. FillBuffer(last);
  1102. END;
  1103. IF WindowSize=1 THEN
  1104. RETURN(OK);
  1105. END; |
  1106. NAK : ptr:=first;
  1107. FOR i:=0 TO WindowSize-1 DO
  1108. WITH SndTable[ptr] DO
  1109. IF PacketNo=Seq THEN
  1110. IF SendIt(ptr)=ERROR THEN
  1111. RETURN(ERROR);
  1112. END;
  1113. END;
  1114. END;
  1115. ptr := (ptr+1) MOD WindowSize;
  1116. END; |
  1117. TIMEOUT : (* resend the oldest UnAcked packet *)
  1118. IF SendIt(first)=ERROR THEN
  1119. RETURN(ERROR);
  1120. END; |
  1121. ELSE
  1122. RETURN ERROR;
  1123. END;
  1124. END;
  1125. END TestReply;
  1126. (*. . . . . . . . . . . . . . . . . . . . . . . .*)
  1127. BEGIN (* SendFileData *)
  1128. InitSndTable;
  1129. NextToSend:=0;
  1130. rslt:=OK;
  1131. LOOP
  1132. IF Done() THEN
  1133. EXIT;
  1134. END;
  1135. rslt := SendIt(NextToSend);
  1136. IF rslt=ERROR THEN
  1137. EXIT;
  1138. END;
  1139. NextToSend := (NextToSend+1) MOD WindowSize;
  1140. rslt := TestReply();
  1141. IF rslt=ERROR THEN
  1142. EXIT;
  1143. END;
  1144. END;
  1145. SeqNo := SndTable[first].PacketNo;
  1146. IF rslt # ERROR THEN
  1147. rslt:=OK;
  1148. END;
  1149. RETURN rslt;
  1150. END SendFileData;
  1151. (*...............................................*)
  1152. PROCEDURE TxStateMachine(VAR Wild:ARRAY OF CHAR):CARDINAL;
  1153. TYPE
  1154. TxStates = (TxInit,TxSendInit,TxSendHdr,TxSendData,TxSendEOF,TxEndSess);
  1155. VAR
  1156. State : TxStates;
  1157. GotFile : BOOLEAN;
  1158. rslt : CARDINAL;
  1159. Path : ARRAY[0..80] OF CHAR;
  1160. Dir : FIO.DirEntry;
  1161. BEGIN
  1162. State := TxInit;
  1163. SeqNo := 0;
  1164. LOOP
  1165. IF FTSupport.AbortRequested() THEN RETURN(ERROR) END;
  1166. CASE State OF
  1167. TxInit : IF NOT GetPath(Wild,Path) THEN
  1168. RETURN(ERROR);
  1169. END;
  1170. GotFile := FIO.ReadFirstEntry(Wild,FIO.FileAttr{},Dir);
  1171. IF NOT GotFile THEN
  1172. Error("No Matching Files");
  1173. RETURN ERROR;
  1174. END;
  1175. Str.Copy(FTSupport.FileSpec,Dir.Name);
  1176. State:=TxSendInit; |
  1177. TxSendInit : IF SendMyParams() # ACK THEN
  1178. RETURN(ERROR);
  1179. END;
  1180. State:=TxSendHdr; |
  1181. TxSendHdr : FTSupport.Transferred:=0;
  1182. IF SendFileHeader(Path) # ACK THEN
  1183. RETURN(ERROR);
  1184. END;
  1185. State := TxSendData; |
  1186. TxSendData : IF SendFileData()=ERROR THEN
  1187. RETURN(ERROR);
  1188. END;
  1189. State := TxSendEOF; |
  1190. TxSendEOF : IF SendMessage(EOFILE,0) # ACK THEN
  1191. RETURN(ERROR);
  1192. END;
  1193. FIO.Close(f);
  1194. Msg(FileClosed);
  1195. GotFile := FIO.ReadNextEntry(Dir);
  1196. IF GotFile THEN
  1197. State:=TxSendHdr;
  1198. ELSE
  1199. State:=TxEndSess;
  1200. END;
  1201. Str.Copy(FTSupport.FileSpec,Dir.Name); |
  1202. TxEndSess : IF SendMessage(ENDSESS,0) # ACK THEN
  1203. RETURN(ERROR);
  1204. END;
  1205. Msg(EndSession);
  1206. RETURN OK; |
  1207. END;
  1208. END;
  1209. END TxStateMachine;
  1210. (*...............................................*)
  1211. PROCEDURE KermitSend(wild:ARRAY OF CHAR):CARDINAL;
  1212. VAR
  1213. rslt : CARDINAL;
  1214. BEGIN
  1215. InitVars;
  1216. FTSupport.OpenStatusWindow('SuperKermit Upload');
  1217. rslt := TxStateMachine(wild);
  1218. IF rslt=ERROR THEN
  1219. SendPacket(ERROR,SeqNo,0);
  1220. END;
  1221. FIO.Close(f);
  1222. FTSupport.CloseStatusWindow;
  1223. RETURN rslt;
  1224. END KermitSend;
  1225. (*...............................................*)
  1226. END Kermit.
  1227.