con.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  1. #include <u.h>
  2. #include <libc.h>
  3. #include "rustream.h"
  4. #include "ruttyio.h"
  5. #include "rusignal.h"
  6. #include "rufilio.h"
  7. int debug; /* true if debugging */
  8. int ctl = -1; /* control fd (for break's) */
  9. int raw; /* true if raw is on */
  10. int consctl = -1; /* control fd for cons */
  11. int ttypid; /* pid's if the 2 processes (used to kill them) */
  12. int msgfd = -1; /* mesgld file descriptor (for signals to be written to) */
  13. int outfd = 1; /* local output file descriptor */
  14. int cooked; /* non-zero forces cooked mode */
  15. int returns; /* non-zero forces carriage returns not to be filtered out */
  16. int crtonl; /* non-zero forces carriage returns to be converted to nls coming from net */
  17. int strip; /* strip off parity bits */
  18. char firsterr[2*ERRMAX];
  19. char transerr[2*ERRMAX];
  20. int limited;
  21. char *remuser;
  22. int verbose;
  23. int baud;
  24. int notkbd;
  25. int nltocr; /* translate kbd nl to cr and vice versa */
  26. typedef struct Msg Msg;
  27. #define MAXMSG (2*8192)
  28. int dodial(char*, char*, char*);
  29. void fromkbd(int);
  30. void fromnet(int);
  31. long iread(int, void*, int);
  32. long iwrite(int, void*, int);
  33. int menu(int);
  34. void msgfromkbd(int);
  35. void msgfromnet(int);
  36. int msgwrite(int, void*, int);
  37. void notifyf(void*, char*);
  38. void pass(int, int, int);
  39. void rawoff(void);
  40. void rawon(void);
  41. int readupto(int, char*, int);
  42. int sendctl(int, int);
  43. int sendctl1(int, int, int);
  44. void stdcon(int);
  45. char* system(int, char*);
  46. void dosystem(int, char*);
  47. int wasintr(void);
  48. void punt(char*);
  49. char* syserr(void);
  50. void seterr(char*);
  51. /* protocols */
  52. void device(char*, char*);
  53. void rlogin(char*, char*);
  54. void simple(char*, char*);
  55. void
  56. usage(void)
  57. {
  58. punt("usage: con [-drCvsn] [-l [user]] [-c cmd] net!host[!service]");
  59. }
  60. void
  61. main(int argc, char *argv[])
  62. {
  63. char *dest;
  64. char *cmd = 0;
  65. returns = 1;
  66. ARGBEGIN{
  67. case 'b':
  68. baud = atoi(ARGF());
  69. break;
  70. case 'd':
  71. debug = 1;
  72. break;
  73. case 'l':
  74. limited = 1;
  75. if(argv[1] != nil && argv[1][0] != '-')
  76. remuser = ARGF();
  77. break;
  78. case 'n':
  79. notkbd = 1;
  80. break;
  81. case 'r':
  82. returns = 0;
  83. break;
  84. case 'R':
  85. nltocr = 1;
  86. break;
  87. case 'T':
  88. crtonl = 1;
  89. break;
  90. case 'C':
  91. cooked = 1;
  92. break;
  93. case 'c':
  94. cmd = ARGF();
  95. break;
  96. case 'v':
  97. verbose = 1;
  98. break;
  99. case 's':
  100. strip = 1;
  101. break;
  102. default:
  103. usage();
  104. }ARGEND
  105. if(argc != 1){
  106. if(remuser == 0)
  107. usage();
  108. dest = remuser;
  109. remuser = 0;
  110. } else
  111. dest = argv[0];
  112. if(*dest == '/' && strchr(dest, '!') == 0)
  113. device(dest, cmd);
  114. else if(limited){
  115. simple(dest, cmd); /* doesn't return if dialout succeeds */
  116. rlogin(dest, cmd); /* doesn't return if dialout succeeds */
  117. } else {
  118. rlogin(dest, cmd); /* doesn't return if dialout succeeds */
  119. simple(dest, cmd); /* doesn't return if dialout succeeds */
  120. }
  121. punt(firsterr);
  122. }
  123. /*
  124. * just dial and use as a byte stream with remote echo
  125. */
  126. void
  127. simple(char *dest, char *cmd)
  128. {
  129. int net;
  130. net = dodial(dest, 0, 0);
  131. if(net < 0)
  132. return;
  133. if(cmd)
  134. dosystem(net, cmd);
  135. if(!cooked)
  136. rawon();
  137. stdcon(net);
  138. exits(0);
  139. }
  140. /*
  141. * dial, do UCB authentication, use as a byte stream with local echo
  142. *
  143. * return if dial failed
  144. */
  145. void
  146. rlogin(char *dest, char *cmd)
  147. {
  148. int net;
  149. char buf[128];
  150. char *p;
  151. char *localuser;
  152. /* only useful on TCP */
  153. if(strchr(dest, '!')
  154. && (strncmp(dest, "tcp!", 4)!=0 && strncmp(dest, "net!", 4)!=0))
  155. return;
  156. net = dodial(dest, "tcp", "login");
  157. if(net < 0)
  158. return;
  159. /*
  160. * do UCB rlogin authentication
  161. */
  162. localuser = getuser();
  163. if(remuser == 0){
  164. if(limited)
  165. remuser = ":";
  166. else
  167. remuser = localuser;
  168. }
  169. p = getenv("TERM");
  170. if(p == 0)
  171. p = "p9";
  172. if(write(net, "", 1)<0
  173. || write(net, localuser, strlen(localuser)+1)<0
  174. || write(net, remuser, strlen(remuser)+1)<0
  175. || write(net, p, strlen(p)+1)<0){
  176. close(net);
  177. punt("BSD authentication failed");
  178. }
  179. if(read(net, buf, 1) != 1)
  180. punt("BSD authentication failed1");
  181. if(buf[0] != 0){
  182. fprint(2, "con: remote error: ");
  183. while(read(net, buf, 1) == 1){
  184. write(2, buf, 1);
  185. if(buf[0] == '\n')
  186. break;
  187. }
  188. exits("read");
  189. }
  190. if(cmd)
  191. dosystem(net, cmd);
  192. if(!cooked)
  193. rawon();
  194. nltocr = 1;
  195. stdcon(net);
  196. exits(0);
  197. }
  198. /*
  199. * just open a device and use it as a connection
  200. */
  201. void
  202. device(char *dest, char *cmd)
  203. {
  204. int net;
  205. char cname[128];
  206. net = open(dest, ORDWR);
  207. if(net < 0) {
  208. fprint(2, "con: cannot open %s: %r\n", dest);
  209. exits("open");
  210. }
  211. snprint(cname, sizeof cname, "%sctl", dest);
  212. ctl = open(cname, ORDWR);
  213. if (baud > 0) {
  214. if(ctl >= 0)
  215. fprint(ctl, "b%d", baud);
  216. else
  217. fprint(2, "con: cannot open %s: %r\n", cname);
  218. }
  219. if(cmd)
  220. dosystem(net, cmd);
  221. if(!cooked)
  222. rawon();
  223. stdcon(net);
  224. exits(0);
  225. }
  226. /*
  227. * ignore interrupts
  228. */
  229. void
  230. notifyf(void *a, char *msg)
  231. {
  232. USED(a);
  233. if(strstr(msg, "yankee"))
  234. noted(NDFLT);
  235. if(strstr(msg, "closed pipe")
  236. || strcmp(msg, "interrupt") == 0
  237. || strcmp(msg, "hangup") == 0)
  238. noted(NCONT);
  239. noted(NDFLT);
  240. }
  241. /*
  242. * turn keyboard raw mode on
  243. */
  244. void
  245. rawon(void)
  246. {
  247. if(debug)
  248. fprint(2, "rawon\n");
  249. if(raw)
  250. return;
  251. if(consctl < 0)
  252. consctl = open("/dev/consctl", OWRITE);
  253. if(consctl < 0){
  254. // fprint(2, "can't open consctl\n");
  255. return;
  256. }
  257. write(consctl, "rawon", 5);
  258. raw = 1;
  259. }
  260. /*
  261. * turn keyboard raw mode off
  262. */
  263. void
  264. rawoff(void)
  265. {
  266. if(debug)
  267. fprint(2, "rawoff\n");
  268. if(raw == 0)
  269. return;
  270. if(consctl < 0)
  271. consctl = open("/dev/consctl", OWRITE);
  272. if(consctl < 0){
  273. // fprint(2, "can't open consctl\n");
  274. return;
  275. }
  276. write(consctl, "rawoff", 6);
  277. raw = 0;
  278. }
  279. /*
  280. * control menu
  281. */
  282. #define STDHELP "\t(b)reak, (q)uit, (i)nterrupt, toggle printing (r)eturns, (.)continue, (!cmd)\n"
  283. int
  284. menu(int net)
  285. {
  286. char buf[MAXMSG];
  287. long n;
  288. int done;
  289. int wasraw = raw;
  290. if(wasraw)
  291. rawoff();
  292. fprint(2, ">>> ");
  293. for(done = 0; !done; ){
  294. n = read(0, buf, sizeof(buf)-1);
  295. if(n <= 0)
  296. return -1;
  297. buf[n] = 0;
  298. switch(buf[0]){
  299. case '!':
  300. print(buf);
  301. system(net, buf+1);
  302. print("!\n");
  303. done = 1;
  304. break;
  305. case '.':
  306. done = 1;
  307. break;
  308. case 'q':
  309. return -1;
  310. break;
  311. case 'i':
  312. buf[0] = 0x1c;
  313. if(msgfd <= 0)
  314. write(net, buf, 1);
  315. else
  316. sendctl1(msgfd, M_SIGNAL, SIGQUIT);
  317. done = 1;
  318. break;
  319. case 'b':
  320. if(msgfd >= 0)
  321. sendctl(msgfd, M_BREAK);
  322. else if(ctl >= 0)
  323. write(ctl, "k", 1);
  324. done = 1;
  325. break;
  326. case 'r':
  327. returns = 1-returns;
  328. done = 1;
  329. break;
  330. default:
  331. fprint(2, STDHELP);
  332. break;
  333. }
  334. if(!done)
  335. fprint(2, ">>> ");
  336. }
  337. if(wasraw)
  338. rawon();
  339. else
  340. rawoff();
  341. return 0;
  342. }
  343. /*
  344. * the real work. two processes pass bytes back and forth between the
  345. * terminal and the network.
  346. */
  347. void
  348. stdcon(int net)
  349. {
  350. int netpid;
  351. ttypid = getpid();
  352. switch(netpid = rfork(RFMEM|RFPROC)){
  353. case -1:
  354. perror("con");
  355. exits("fork");
  356. case 0:
  357. notify(notifyf);
  358. fromnet(net);
  359. postnote(PNPROC, ttypid, "die yankee dog");
  360. exits(0);
  361. default:
  362. notify(notifyf);
  363. fromkbd(net);
  364. if(notkbd)
  365. for(;;)sleep(0);
  366. postnote(PNPROC, netpid, "die yankee dog");
  367. exits(0);
  368. }
  369. }
  370. /*
  371. * Read the keyboard and write it to the network. '^\' gets us into
  372. * the menu.
  373. */
  374. void
  375. fromkbd(int net)
  376. {
  377. long n;
  378. char buf[MAXMSG];
  379. char *p, *ep;
  380. int eofs;
  381. eofs = 0;
  382. for(;;){
  383. n = read(0, buf, sizeof(buf));
  384. if(n < 0){
  385. if(wasintr()){
  386. if(!raw){
  387. buf[0] = 0x7f;
  388. n = 1;
  389. } else
  390. continue;
  391. } else
  392. return;
  393. }
  394. if(n == 0){
  395. if(++eofs > 32)
  396. return;
  397. } else
  398. eofs = 0;
  399. if(n && memchr(buf, 0x1c, n)){
  400. if(menu(net) < 0)
  401. return;
  402. }else{
  403. if(!raw && n==0){
  404. buf[0] = 0x4;
  405. n = 1;
  406. }
  407. if(nltocr){
  408. ep = buf+n;
  409. for(p = buf; p < ep; p++)
  410. switch(*p){
  411. case '\r':
  412. *p = '\n';
  413. break;
  414. case '\n':
  415. *p = '\r';
  416. break;
  417. }
  418. }
  419. if(iwrite(net, buf, n) != n)
  420. return;
  421. }
  422. }
  423. }
  424. /*
  425. * Read from the network and write to the screen.
  426. * Filter out spurious carriage returns.
  427. */
  428. void
  429. fromnet(int net)
  430. {
  431. long n;
  432. char buf[MAXMSG];
  433. char *cp, *ep;
  434. for(;;){
  435. n = iread(net, buf, sizeof(buf));
  436. if(n < 0)
  437. return;
  438. if(n == 0)
  439. continue;
  440. if (strip)
  441. for (cp=buf; cp<buf+n; cp++)
  442. *cp &= 0177;
  443. if(crtonl) {
  444. /* convert cr's to nl's */
  445. for (cp = buf; cp < buf + n; cp++)
  446. if (*cp == '\r')
  447. *cp = '\n';
  448. }
  449. else if(!returns){
  450. /* convert cr's to null's */
  451. cp = buf;
  452. ep = buf + n;
  453. while(cp < ep && (cp = memchr(cp, '\r', ep-cp))){
  454. memmove(cp, cp+1, ep-cp-1);
  455. ep--;
  456. n--;
  457. }
  458. }
  459. if(n > 0 && iwrite(outfd, buf, n) != n){
  460. if(outfd == 1)
  461. return;
  462. outfd = 1;
  463. if(iwrite(1, buf, n) != n)
  464. return;
  465. }
  466. }
  467. }
  468. /*
  469. * dial and return a data connection
  470. */
  471. int
  472. dodial(char *dest, char *net, char *service)
  473. {
  474. char name[128];
  475. char devdir[128];
  476. int data;
  477. devdir[0] = 0;
  478. strcpy(name, netmkaddr(dest, net, service));
  479. data = dial(name, 0, devdir, &ctl);
  480. if(data < 0){
  481. seterr(name);
  482. return -1;
  483. }
  484. fprint(2, "connected to %s on %s\n", name, devdir);
  485. return data;
  486. }
  487. void
  488. dosystem(int fd, char *cmd)
  489. {
  490. char *p;
  491. p = system(fd, cmd);
  492. if(p){
  493. print("con: %s terminated with %s\n", cmd, p);
  494. exits(p);
  495. }
  496. }
  497. /*
  498. * run a command with the network connection as standard IO
  499. */
  500. char *
  501. system(int fd, char *cmd)
  502. {
  503. int pid;
  504. int p;
  505. static Waitmsg msg;
  506. int pfd[2];
  507. int n;
  508. char buf[4096];
  509. if(pipe(pfd) < 0){
  510. perror("pipe");
  511. return "pipe failed";
  512. }
  513. outfd = pfd[1];
  514. close(consctl);
  515. consctl = -1;
  516. switch(pid = fork()){
  517. case -1:
  518. perror("con");
  519. return "fork failed";
  520. case 0:
  521. close(pfd[1]);
  522. dup(pfd[0], 0);
  523. dup(fd, 1);
  524. close(ctl);
  525. close(fd);
  526. close(pfd[0]);
  527. if(*cmd)
  528. execl("/bin/rc", "rc", "-c", cmd, 0);
  529. else
  530. execl("/bin/rc", "rc", 0);
  531. perror("con");
  532. exits("exec");
  533. break;
  534. default:
  535. close(pfd[0]);
  536. while((n = read(pfd[1], buf, sizeof(buf))) > 0){
  537. if(msgfd >= 0){
  538. if(msgwrite(fd, buf, n) != n)
  539. break;
  540. } else {
  541. if(write(fd, buf, n) != n)
  542. break;
  543. }
  544. }
  545. p = waitpid();
  546. outfd = 1;
  547. close(pfd[1]);
  548. if(p < 0 || p != pid)
  549. return "lost child";
  550. break;
  551. }
  552. return msg.msg;
  553. }
  554. int
  555. wasintr(void)
  556. {
  557. return strcmp(syserr(), "interrupted") == 0;
  558. }
  559. void
  560. punt(char *msg)
  561. {
  562. if(*msg == 0)
  563. msg = transerr;
  564. fprint(2, "con: %s\n", msg);
  565. exits(msg);
  566. }
  567. char*
  568. syserr(void)
  569. {
  570. static char err[ERRMAX];
  571. errstr(err, sizeof err);
  572. return err;
  573. }
  574. void
  575. seterr(char *addr)
  576. {
  577. char *se = syserr();
  578. if(verbose)
  579. fprint(2, "'%s' calling %s\n", se, addr);
  580. if(firsterr[0] && (strstr(se, "translate") ||
  581. strstr(se, "file does not exist") ||
  582. strstr(se, "unknown address") ||
  583. strstr(se, "directory entry not found")))
  584. return;
  585. strcpy(firsterr, se);
  586. }
  587. long
  588. iread(int f, void *a, int n)
  589. {
  590. long m;
  591. for(;;){
  592. m = read(f, a, n);
  593. if(m >= 0 || !wasintr())
  594. break;
  595. }
  596. return m;
  597. }
  598. long
  599. iwrite(int f, void *a, int n)
  600. {
  601. long m;
  602. m = write(f, a, n);
  603. if(m < 0 && wasintr())
  604. return n;
  605. return m;
  606. }
  607. /*
  608. * The rest is to support the V10 mesgld protocol.
  609. */
  610. /*
  611. * network orderings
  612. */
  613. #define get2byte(p) ((p)[0] + ((p)[1]<<8))
  614. #define get4byte(p) ((p)[0] + ((p)[1]<<8) + ((p)[2]<<16) + ((p)[3]<<24))
  615. #define put2byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8)
  616. #define put4byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8, (p)[2]=(i)>>16, (p)[3]=(i)>>24)
  617. /*
  618. * tty parameters
  619. */
  620. int sgflags = ECHO;
  621. /*
  622. * a mesgld message
  623. */
  624. struct Msg {
  625. struct mesg h;
  626. char b[MAXMSG];
  627. };
  628. /*
  629. * send an empty mesgld message
  630. */
  631. int
  632. sendctl(int net, int type)
  633. {
  634. Msg m;
  635. m.h.type = type;
  636. m.h.magic = MSGMAGIC;
  637. put2byte(m.h.size, 0);
  638. if(iwrite(net, &m, sizeof(struct mesg)) != sizeof(struct mesg))
  639. return -1;
  640. return 0;
  641. }
  642. /*
  643. * send a one byte mesgld message
  644. */
  645. int
  646. sendctl1(int net, int type, int parm)
  647. {
  648. Msg m;
  649. m.h.type = type;
  650. m.h.magic = MSGMAGIC;
  651. m.b[0] = parm;
  652. put2byte(m.h.size, 1);
  653. if(iwrite(net, &m, sizeof(struct mesg)+1) != sizeof(struct mesg)+1)
  654. return -1;
  655. return 0;
  656. }
  657. /*
  658. * read n bytes. return -1 if it fails, 0 otherwise.
  659. */
  660. int
  661. readupto(int from, char *a, int len)
  662. {
  663. int n;
  664. while(len > 0){
  665. n = iread(from, a, len);
  666. if(n < 0)
  667. return -1;
  668. a += n;
  669. len -= n;
  670. }
  671. return 0;
  672. }
  673. /*
  674. * Decode a mesgld message from the network
  675. */
  676. void
  677. msgfromnet(int net)
  678. {
  679. ulong com;
  680. struct stioctl *io;
  681. struct sgttyb *sg;
  682. struct ttydevb *td;
  683. struct tchars *tc;
  684. int len;
  685. Msg m;
  686. for(;;){
  687. /* get a complete mesgld message */
  688. if(readupto(net, (char*)&m.h, sizeof(struct mesg)) < 0)
  689. break;
  690. if(m.h.magic != MSGMAGIC){
  691. fprint(2, "con: bad message magic 0x%ux\n", m.h.magic);
  692. break;
  693. }
  694. len = get2byte(m.h.size);
  695. if(len > sizeof(m.b)){
  696. len = sizeof(m.b);
  697. fprint(2, "con: mesgld message too long\n");
  698. }
  699. if(len && readupto(net, m.b, len) < 0)
  700. break;
  701. /* decode */
  702. switch(m.h.type){
  703. case M_HANGUP:
  704. if(debug)
  705. fprint(2, "M_HANGUP\n");
  706. return;
  707. case M_DATA:
  708. if(debug)
  709. fprint(2, "M_DATA %d bytes\n", len);
  710. if(iwrite(outfd, m.b, len) != len){
  711. if(outfd == 1)
  712. return;
  713. outfd = 1;
  714. if(iwrite(outfd, m.b, len) != len)
  715. return;
  716. }
  717. continue;
  718. case M_IOCTL:
  719. break;
  720. default:
  721. /* ignore */
  722. if(debug)
  723. fprint(2, "con: unknown message\n");
  724. continue;
  725. }
  726. /*
  727. * answer an ioctl
  728. */
  729. io = (struct stioctl *)m.b;
  730. com = get4byte(io->com);
  731. if(debug)
  732. fprint(2, "M_IOCTL %lud\n", com);
  733. switch(com){
  734. case FIOLOOKLD:
  735. put4byte(io->data, tty_ld);
  736. len = 0;
  737. break;
  738. case TIOCGETP:
  739. sg = (struct sgttyb *)io->data;
  740. sg->sg_ispeed = sg->sg_ospeed = B9600;
  741. sg->sg_erase = 0010; /* back space */
  742. sg->sg_kill = 0025; /* CNTL U */
  743. put2byte(sg->sg_flags, sgflags);
  744. len = sizeof(struct sgttyb);
  745. break;
  746. case TIOCSETN:
  747. case TIOCSETP:
  748. sg = (struct sgttyb *)io->data;
  749. sgflags = get2byte(sg->sg_flags);
  750. if((sgflags&(RAW|CBREAK)) || !(sgflags&ECHO))
  751. rawon();
  752. else
  753. rawoff();
  754. len = 0;
  755. break;
  756. case TIOCGETC:
  757. tc = (struct tchars *)io->data;
  758. tc->t_intrc = 0177;
  759. tc->t_quitc = 0034;
  760. tc->t_startc = 0;
  761. tc->t_stopc = 0;
  762. tc->t_eofc = 0004;
  763. tc->t_brkc = 0;
  764. len = sizeof(struct tchars);
  765. break;
  766. case TIOCSETC:
  767. len = 0;
  768. break;
  769. case TIOCGDEV:
  770. td = (struct ttydevb *)io->data;
  771. td->ispeed = td->ospeed = B9600;
  772. put2byte(td->flags, 0);
  773. len = sizeof(struct ttydevb);
  774. break;
  775. case TIOCSDEV:
  776. len = 0;
  777. break;
  778. default:
  779. /*
  780. * unimplemented
  781. */
  782. m.b[len] = 0;
  783. if(sendctl(net, M_IOCNAK) < 0)
  784. return;
  785. continue;
  786. }
  787. /*
  788. * acknowledge
  789. */
  790. m.h.type = M_IOCACK;
  791. m.h.magic = MSGMAGIC;
  792. len += 4;
  793. put2byte(m.h.size, len);
  794. len += sizeof(struct mesg);
  795. if(iwrite(net, &m, len) != len)
  796. return;
  797. }
  798. }
  799. /*
  800. * Read the keyboard, convert to mesgld messages, and write it to the network.
  801. * '^\' gets us into the menu.
  802. */
  803. void
  804. msgfromkbd(int net)
  805. {
  806. long n;
  807. char buf[MAXMSG];
  808. for(;;){
  809. n = iread(0, buf, sizeof(buf));
  810. if(n < 0)
  811. return;
  812. if(n && memchr(buf, 0034, n)){
  813. if(menu(net) < 0)
  814. return;
  815. } else {
  816. if(msgwrite(net, buf, n) != n)
  817. return;
  818. }
  819. }
  820. }
  821. int
  822. msgwrite(int fd, void *buf, int len)
  823. {
  824. Msg m;
  825. int n;
  826. n = len;
  827. memmove(m.b, buf, n);
  828. put2byte(m.h.size, n);
  829. m.h.magic = MSGMAGIC;
  830. m.h.type = M_DATA;
  831. n += sizeof(struct mesg);
  832. if(iwrite(fd, &m, n) != n)
  833. return -1;
  834. put2byte(m.h.size, 0);
  835. m.h.magic = MSGMAGIC;
  836. m.h.type = M_DELIM;
  837. n = sizeof(struct mesg);
  838. if(iwrite(fd, &m, n) != n)
  839. return -1;
  840. return len;
  841. }