home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / epson / filink.sh < prev    next >
Encoding:
Internet Message Format  |  1994-09-02  |  11.8 KB

  1. From: Frank D. Cringle <fdc@cliwe.ping.de>
  2. Date: Tue, 30 Aug 94 09:40:15 +0200
  3. Message-Id: <9408300740.AA08233@cliwe.ping.de>
  4. To: jeff@vela.acs.oakland.edu
  5. Subject: Submission for CP/M archives
  6.  
  7. Here is a unix equivalent to the epslink.azm program in the epson area of the
  8. archives.  It may be useful for folks who want to transfer files between unix
  9. machines and epson PX-8's without needing to install xmodem or kermit or
  10. whatever on their PX-8.  Other than that I reverse-engineered it from
  11. filink.com on my PX-8, its all my own work and I hereby donate it to the
  12. public domain.
  13.  
  14. I am submitting this as a shell archive, because it is aimed at unix users.
  15. Feel free to convert it if you want to conform to some other convention.
  16.  
  17. Submitted-by: fdc@cliwe.ping.de
  18. Archive-name: filink-0.01/part01
  19.  
  20. ---- Cut Here and feed the following to sh ----
  21. #!/bin/sh
  22. # This is filink-0.01, a shell archive (produced by shar 3.49)
  23. # To extract the files from this archive, save it to a file, remove
  24. # everything above the "!/bin/sh" line above, and type "sh file_name".
  25. #
  26. # made 08/30/1994 07:37 UTC by fdc@cliwe.ping.de
  27. # Source directory /tmp/filink-0.01
  28. #
  29. # existing files will NOT be overwritten unless -c is specified
  30. #
  31. # This shar contains:
  32. # length  mode       name
  33. # ------ ---------- ------------------------------------------
  34. #   1892 -rw-rw-r-- README
  35. #    112 -rw-rw-r-- Makefile
  36. #   7054 -rw-rw-r-- filink.c
  37. #
  38. # ============= README ==============
  39. if test -f 'README' -a X"$1" != X"-c"; then
  40.     echo 'x - skipping README (File already exists)'
  41. else
  42. echo 'x - extracting README (Text)'
  43. sed 's/^X//' << 'SHAR_EOF' > 'README' &&
  44. Transfer files between a unix machine and an Epson PX-8 (Geneva)
  45. ================================================================
  46. X
  47. filink.c implements the file transfer protocol which is built into
  48. the Epson PX-8 (a portable CP/M machine of early '80s vintage).
  49. X
  50. It is designed to be called as a file-transfer subprocess by some
  51. other program that is talking to the PX-8.  This might be cu or tip
  52. or, best of all, pcomm.
  53. X
  54. The user interface of filink is, well, spartan.  If filink is executed
  55. without parameters it expects to receive one or more files from the
  56. PX-8.  If you give it some command-line arguments (which may have been
  57. wildcard-expanded by a shell), it will interpret them as filenames and
  58. try to send them to the PX-8.
  59. X
  60. Using filing from tip:
  61. ~Cfilink            # receive files
  62. ~Cfilink list of files        # send files
  63. X
  64. Using filink from cu (only works with gnu (Taylor) cu):
  65. ~+filink            # receive files
  66. ~+filink list of files        # send files
  67. X
  68. Using filink from pcomm:
  69. First install filink as an external protocol -
  70. type ctrl-A S 6, then enter filink for upload and download as shown:
  71. X                                    UPLOAD
  72. X        Name         Command line                     Requires file list?
  73. X     1) zmodem       zmtx                                      Y
  74. X     2) kermit       kermit -ivs                               Y
  75. X     3) filink       filink                                    Y
  76. X                                   DOWNLOAD
  77. X        Name         Command line                     Requires file list?
  78. X     4) zmodem       zmrx -o                                   N
  79. X     5) kermit       kermit -ivr                               Y
  80. X     6) filink       filink                                    N
  81. You can now transfer files by typing ctrl-A <up-arrow> to upload to
  82. the PX-8 or ctrl-A <down-arrow> to download files to the unix machine.
  83. X
  84. X
  85. Frank Cringle
  86. fdc@cliwe.ping.de
  87. SHAR_EOF
  88. chmod 0664 README ||
  89. echo 'restore of README failed'
  90. Wc_c="`wc -c < 'README'`"
  91. test 1892 -eq "$Wc_c" ||
  92.     echo 'README: original size 1892, current size' "$Wc_c"
  93. fi
  94. # ============= Makefile ==============
  95. if test -f 'Makefile' -a X"$1" != X"-c"; then
  96.     echo 'x - skipping Makefile (File already exists)'
  97. else
  98. echo 'x - extracting Makefile (Text)'
  99. sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
  100. CC            =    gcc
  101. CFLAGS        =    -O2 -g -Wall
  102. X
  103. filink:        filink.o
  104. X
  105. install:    filink
  106. X        mv filink /usr/local/bin
  107. SHAR_EOF
  108. chmod 0664 Makefile ||
  109. echo 'restore of Makefile failed'
  110. Wc_c="`wc -c < 'Makefile'`"
  111. test 112 -eq "$Wc_c" ||
  112.     echo 'Makefile: original size 112, current size' "$Wc_c"
  113. fi
  114. # ============= filink.c ==============
  115. if test -f 'filink.c' -a X"$1" != X"-c"; then
  116.     echo 'x - skipping filink.c (File already exists)'
  117. else
  118. echo 'x - extracting filink.c (Text)'
  119. sed 's/^X//' << 'SHAR_EOF' > 'filink.c' &&
  120. /* filink.c - transfer files between unix and an Epson PX-8 */
  121. X
  122. /* This program is in the public domain.  If it doesn't work or causes */
  123. /* you grief in any way, blame the public, not me! */
  124. /* Frank Cringle, August 1994 */
  125. X
  126. /* The best way to compile this is with gcc on a sysv-like machine. */
  127. /* If that is not what you have available, try to get as close as */
  128. /* possible - use the sys5 universe or /usr/5bin/cc or whatever. */
  129. X
  130. /* Version 0.01 */
  131. X
  132. #include <stdio.h>
  133. #include <stdlib.h>
  134. #include <unistd.h>
  135. #include <termios.h>
  136. #include <string.h>
  137. #include <ctype.h>
  138. X
  139. struct termios  cookedtio, rawtio;
  140. X
  141. #define GOTTIO    1
  142. #define ISATTY    2
  143. #define ISRAW    4
  144. int             ttyflags;
  145. X
  146. /* put the tty back to normal mode */
  147. static void
  148. ttycooked(void)
  149. {
  150. X    tcflush(0, TCIOFLUSH);
  151. X    if (ttyflags & ISRAW) {
  152. X        tcsetattr(fileno(stdin), TCSAFLUSH, &cookedtio);
  153. X        putc('\n', stdout);
  154. X        ttyflags &= ~ISRAW;
  155. X    }
  156. }
  157. X
  158. /* set up the tty (stdin/stdout) to transfer all 8-bit characters */
  159. static void
  160. ttyraw(void)
  161. {
  162. X    if (!(ttyflags & GOTTIO) && isatty(fileno(stdin))) {
  163. X        ttyflags = ISATTY|GOTTIO;
  164. X        tcflush(0, TCIOFLUSH);
  165. X        if (tcgetattr(fileno(stdin), &cookedtio) != 0) {
  166. X            perror("tcgetattr");
  167. X            exit(1);
  168. X        }
  169. X        rawtio = cookedtio;
  170. X        rawtio.c_iflag = 0;
  171. X        rawtio.c_oflag &= ~(OPOST | OLCUC | ONLCR | OCRNL | ONOCR | ONLRET);
  172. X        rawtio.c_lflag = 0;
  173. X        memset(rawtio.c_cc, 0, NCCS);
  174. X        rawtio.c_cc[VMIN] = 0; /* read returns as soon as data */
  175. X                       /* is available */
  176. X        rawtio.c_cc[VTIME] = 1;    /* or after 1 tenth of a */
  177. X                    /* second at the latest*/
  178. X    }
  179. X    if ((ttyflags & (ISATTY | ISRAW)) == ISATTY) {
  180. X        tcsetattr(fileno(stdin), TCSAFLUSH, &rawtio);
  181. X        ttyflags |= ISRAW;
  182. X    }
  183. X
  184. X    /* reset to normal before exit. If your C library does not */
  185. X    /* have atexit(), you should install ttycooked as a handler */
  186. X    /* for SIGINT, SIGHUP, etc. */
  187. X    atexit(ttycooked);
  188. }
  189. X
  190. /* print timeout message and quit */
  191. static void
  192. noanswer(int state, int who)
  193. {
  194. X    fprintf(stderr, "%s not responding in state %d\r\n",
  195. X        who == 'R' ? "Receiver" : "Sender", state);
  196. X    exit(1);
  197. }
  198. X
  199. /* send a character with error checking */
  200. static void
  201. send(char c)
  202. {
  203. X    if (write(1, &c, 1) != 1) {
  204. X        perror("stdout");
  205. X        exit(1);
  206. X    }
  207. }
  208. X
  209. /* get a character
  210. X   (give up and return -1 after trys*0.1 secs if trys is positive) */
  211. static int
  212. get(int trys)
  213. {
  214. X    char            c;
  215. X
  216. X    do {
  217. X        if (trys <= 0)
  218. X            trys = -1;
  219. X        switch (read(0, &c, 1)) {
  220. X        case 1: return c & 0xff;
  221. X        case 0: break;
  222. X        default:
  223. X            perror("stdin");
  224. X            exit(1);
  225. X        }
  226. X    } while (--trys);
  227. X    return -1;
  228. }
  229. X
  230. /* send named file */
  231. static void
  232. sendfile(char *name)
  233. {
  234. X    FILE           *f;
  235. X    char            buf[128];
  236. X    int             bufc = 0;
  237. X    char            fn[12];
  238. X    char           *p = name;
  239. X    int             csum = 0, i, state = 1;
  240. X
  241. X    if ((f = fopen(name, "r")) == NULL) {
  242. X        perror(name);
  243. X        return;
  244. X    }
  245. X    /* strip path */
  246. X    if ((p = strrchr(name, '/')) != NULL)
  247. X        p++;
  248. X    else
  249. X        p = name;
  250. X    /* convert name to upper case (max 8 chars) */
  251. X    for (i = 0; i < 8 && *p && *p != '.'; i++) {
  252. X        fn[i] = toupper(*p);
  253. X        p++;
  254. X    }
  255. X    while (i < 8)
  256. X        fn[i++] = ' ';
  257. X    /* skip to extension (if there is one) */
  258. X    while (*p && *p != '.')
  259. X        p++;
  260. X    if (*p == '.')
  261. X        p++;
  262. X    /* copy and convert extension */
  263. X    for (i = 8; i < 11 && *p; i++) {
  264. X        fn[i] = toupper(*p);
  265. X        p++;
  266. X    }
  267. X    while (i < 11)
  268. X        fn[i++] = ' ';
  269. X    fn[11] = 0;
  270. X    p = fn;
  271. X
  272. X    while (1)
  273. X        switch (state) {
  274. X        case 1: send('R');
  275. X            switch (get(50)) {
  276. X            case 'S':
  277. X                state = 2;
  278. X                break;
  279. X            case -1:
  280. X                fputs("Receiver not ready\r\n", stderr);
  281. X            }
  282. X            break;
  283. X        case 2: send('G');
  284. X            state = 3;
  285. X            break;
  286. X        case 3: send(4);
  287. X            switch (get(20)) {
  288. X            case 8: state = 4;
  289. X                break;
  290. X            case -1:
  291. X                noanswer(state, 'R');
  292. X            }
  293. X            break;
  294. X        case 4: if (*p == 0)
  295. X                state = 5;
  296. X            else {
  297. X                send(*p);
  298. X                if ((i = get(20)) == *p)
  299. X                    p++;
  300. X                else if (i == -1)
  301. X                    noanswer(state, 'R');
  302. X                else
  303. X                    state = 3;
  304. X            }
  305. X            break;
  306. X        case 5: send(5);
  307. X            switch (get(20)) {
  308. X            case 9: state = 6;
  309. X                break;
  310. X            case -1:
  311. X                noanswer(state, 'R');
  312. X            default:
  313. X                state = 3;
  314. X            }
  315. X            break;
  316. X        case 6: if (bufc == 0 && feof(f)) {
  317. X                send(3);
  318. X                state = 9;
  319. X            }
  320. X            else {
  321. X                send(2);
  322. X                switch (get(20)) {
  323. X                case -1:
  324. X                    noanswer(state, 'R');
  325. X                case 'P':
  326. X                    state = 7;
  327. X                }
  328. X            }
  329. X            break;
  330. X        case 7: if (bufc == 0) {
  331. X                memset(buf, 0x1a, 128);
  332. X                fread(buf, 128, 1, f);
  333. X                bufc = 128;
  334. X                csum = 0;
  335. X            }
  336. X            csum ^= buf[128 - bufc];
  337. X            send(buf[128 - bufc--]);
  338. X            state = bufc ? 7 : 8;
  339. X            break;
  340. X        case 8: send(csum);
  341. X            switch (get(20)) {
  342. X            case 'B':
  343. X                state = 6;
  344. X                bufc = 128;
  345. X                break;
  346. X            case 'G':
  347. X                state = 6;
  348. X                bufc = 0;
  349. X                break;
  350. X            case -1:
  351. X                noanswer(state, 'R');
  352. X            default:
  353. X                state = 8;
  354. X                break;
  355. X            }
  356. X            break;
  357. X        case 9: send(19);
  358. X            return;
  359. X        }
  360. }
  361. X
  362. /* receive however many files the other guy wants to send */
  363. static void
  364. receivefile(void)
  365. {
  366. X    FILE           *f = NULL;
  367. X    char            buf[128], name[13], *p = NULL;
  368. X    int             bufc = 0;
  369. X    int             c, csum = 0, i = 0, state = 1;
  370. X
  371. X    while (1)
  372. X        switch (state) {
  373. X        case 1: switch (get(50)) {
  374. X            case 'R':
  375. X                send('S');
  376. X                state = 2;
  377. X                break;
  378. X            case -1:
  379. X                fputs("Sender not ready\r\n", stderr);
  380. X            }
  381. X            break;
  382. X        case 2: switch (get(20)) {
  383. X            case 'G':
  384. X                state = 3;
  385. X                break;
  386. X            case -1:
  387. X                noanswer(state, 'S');
  388. X            }
  389. X            break;
  390. X        case 3: switch (get(20)) {
  391. X            case 4: send(8);
  392. X                p = name;
  393. X                i = 0;
  394. X                state = 4;
  395. X                break;
  396. X            case 19:
  397. X                exit(0);
  398. X            case -1:
  399. X                noanswer(state, 'S');
  400. X            default:
  401. X                send('X');
  402. X            }
  403. X            break;
  404. X        case 4: if ((c = get(20)) == -1)
  405. X                noanswer(state, 'S');
  406. X            /* pick up filename and convert it to */
  407. X            /* lower case */
  408. X            if (c < ' ' || i >= 11) {
  409. X                send('X');
  410. X                state = 3;
  411. X            }
  412. X            else {
  413. X                if (++i == 8)
  414. X                    *p++ = '.';
  415. X                if (c != ' ')
  416. X                    *p++ = tolower(c & 0x7f);
  417. X                send(c);
  418. X            }
  419. X            if (i == 11) {
  420. X                *p = 0;
  421. X                if (p > name && p[-1] == '.')
  422. X                    p[-1] = 0;
  423. X                state = 5;
  424. X            }
  425. X            break;
  426. X        case 5: switch (get(20)) {
  427. X            case 5: if ((f = fopen(name, "w")) == NULL) {
  428. X                    perror(name);
  429. X                    send('X');
  430. X                    state = 3;
  431. X                    /* protocol weakness: there is */
  432. X                    /* no way to say "this ain't */
  433. X                    /* never gonna work" */
  434. X                }
  435. X                else {
  436. X                    send(9);
  437. X                    state = 6;
  438. X                }
  439. X                break;
  440. X            case -1:
  441. X                noanswer(state, 'S');
  442. X            default:
  443. X                send('X');
  444. X                state = 3;
  445. X            }
  446. X            break;
  447. X        case 6: switch (get(20)) {
  448. X            case 2: send('P');
  449. X                p = buf;
  450. X                bufc = 0;
  451. X                csum = 0;
  452. X                state = 7;
  453. X                break;
  454. X            case 3: fclose(f);
  455. X                state = 3;
  456. X                break;
  457. X            case -1:
  458. X                noanswer(state, 'S');
  459. X            default:
  460. X                send('N');
  461. X            }
  462. X            break;
  463. X        case 7: if ((c = get(20)) == -1)
  464. X                noanswer(state, 'S');
  465. X            *p++ = c;
  466. X            csum ^= c;
  467. X            if (++bufc == 128)
  468. X                state = 8;
  469. X            break;
  470. X        case 8: if ((c = get(20)) == -1)
  471. X                noanswer(state, 'S');
  472. X            if (c != csum)
  473. X                send('B');
  474. X            else {
  475. X                if (fwrite(buf, 128, 1, f) == 0) {
  476. X                    perror(name);
  477. X                    exit(1);
  478. X                }
  479. X                send('G');
  480. X            }
  481. X            state = 6;
  482. X            break;
  483. X        }
  484. X    return;
  485. }
  486. X
  487. int
  488. main(int argc, char **argv)
  489. {
  490. X    int             i;
  491. X
  492. X    ttyraw();
  493. X    if (argc == 1)
  494. X        receivefile();
  495. X    else
  496. X        for (i = 1; i < argc; i++)
  497. X            sendfile(argv[i]);
  498. X    ttycooked();
  499. X    exit(0);
  500. }
  501. SHAR_EOF
  502. chmod 0664 filink.c ||
  503. echo 'restore of filink.c failed'
  504. Wc_c="`wc -c < 'filink.c'`"
  505. test 7054 -eq "$Wc_c" ||
  506.     echo 'filink.c: original size 7054, current size' "$Wc_c"
  507. fi
  508. exit 0
  509.  
  510. Frank Cringle            | fdc@cliwe.ping.de
  511. Phone +49 2304 45565        |
  512.  
  513.