fgui.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "dat.h"
  10. #include <draw.h>
  11. #include <mouse.h>
  12. #include <keyboard.h>
  13. #include <control.h>
  14. int ctldeletequits = 1;
  15. typedef struct RequestType RequestType;
  16. typedef struct Request Request;
  17. typedef struct Memory Memory;
  18. struct RequestType
  19. {
  20. char *file; /* file to read requests from */
  21. void (*f)(Request*); /* request handler */
  22. void (*r)(Controlset*); /* resize handler */
  23. int fd; /* fd = open(file, ORDWR) */
  24. Channel *rc; /* channel requests are multiplexed to */
  25. Controlset *cs;
  26. };
  27. struct Request
  28. {
  29. RequestType *rt;
  30. Attr *a;
  31. Attr *tag;
  32. };
  33. struct Memory
  34. {
  35. Memory *next;
  36. Attr *a;
  37. Attr *val;
  38. };
  39. Memory *mem;
  40. static void readreq(void*);
  41. static void hide(void);
  42. static void unhide(void);
  43. static void openkmr(void);
  44. static void closekmr(void);
  45. static Memory* searchmem(Attr*);
  46. static void addmem(Attr*, Attr*);
  47. static void confirm(Request*);
  48. static void resizeconfirm(Controlset*);
  49. static void needkey(Request*);
  50. static void resizeneedkey(Controlset*);
  51. Control *b_remember;
  52. Control *b_accept;
  53. Control *b_refuse;
  54. RequestType rt[] =
  55. {
  56. { "/mnt/factotum/confirm", confirm, resizeconfirm, },
  57. { "/mnt/factotum/needkey", needkey, resizeneedkey, },
  58. { 0 },
  59. };
  60. enum
  61. {
  62. ButtonDim= 15,
  63. };
  64. void
  65. threadmain(int argc, char *argv[])
  66. {
  67. Request r;
  68. Channel *rc;
  69. RequestType *p;
  70. Font *invis;
  71. ARGBEGIN{
  72. }ARGEND;
  73. if(newwindow("-hide") < 0)
  74. sysfatal("newwindow: %r");
  75. fmtinstall('A', _attrfmt);
  76. /* create the proc's that read */
  77. rc = chancreate(sizeof(Request), 0);
  78. for(p = rt; p->file != 0; p++){
  79. p->fd = -1;
  80. p->rc = rc;
  81. proccreate(readreq, p, 16*1024);
  82. }
  83. /* gui initialization */
  84. if(initdraw(0, 0, "auth/fgui") < 0)
  85. sysfatal("initdraw failed: %r");
  86. initcontrols();
  87. hide();
  88. /* get an invisible font for passwords */
  89. invis = openfont(display, "/lib/font/bit/lucm/passwd.9.font");
  90. if (invis == nil)
  91. sysfatal("fgui: %s: %r", "/lib/font/bit/lucm/passwd.9.font");
  92. namectlfont(invis, "invisible");
  93. /* serialize all requests */
  94. for(;;){
  95. if(recv(rc, &r) < 0)
  96. break;
  97. (*r.rt->f)(&r);
  98. _freeattr(r.a);
  99. _freeattr(r.tag);
  100. }
  101. threadexitsall(nil);
  102. }
  103. /*
  104. * read requests and pass them to the main loop
  105. */
  106. enum
  107. {
  108. Requestlen=4096,
  109. };
  110. static void
  111. readreq(void *a)
  112. {
  113. RequestType *rt = a;
  114. char *buf, *p;
  115. int n;
  116. Request r;
  117. Attr **l;
  118. rt->fd = open(rt->file, ORDWR);
  119. if(rt->fd < 0)
  120. sysfatal("opening %s: %r", rt->file);
  121. rt->cs = nil;
  122. buf = malloc(Requestlen);
  123. if(buf == nil)
  124. sysfatal("allocating read buffer: %r");
  125. r.rt = rt;
  126. for(;;){
  127. n = read(rt->fd, buf, Requestlen-1);
  128. if(n < 0)
  129. break;
  130. buf[n] = 0;
  131. /* skip verb, parse attributes, and remove tag */
  132. p = strchr(buf, ' ');
  133. if(p != nil)
  134. p++;
  135. else
  136. p = buf;
  137. r.a = _parseattr(p);
  138. /* separate out the tag */
  139. r.tag = nil;
  140. for(l = &r.a; *l != nil; l = &(*l)->next)
  141. if(strcmp((*l)->name, "tag") == 0){
  142. r.tag = *l;
  143. *l = r.tag->next;
  144. r.tag->next = nil;
  145. break;
  146. }
  147. /* if no tag, forget it */
  148. if(r.tag == nil){
  149. _freeattr(r.a);
  150. continue;
  151. }
  152. send(rt->rc, &r);
  153. }
  154. }
  155. #ifdef asdf
  156. static void
  157. readreq(void *a)
  158. {
  159. RequestType *rt = a;
  160. char *buf, *p;
  161. int n;
  162. Request r;
  163. rt->fd = -1;
  164. rt->cs = nil;
  165. buf = malloc(Requestlen);
  166. if(buf == nil)
  167. sysfatal("allocating read buffer: %r");
  168. r.rt = rt;
  169. for(;;){
  170. strcpy(buf, "adfasdf=afdasdf asdfasdf=asdfasdf");
  171. r.a = _parseattr(buf);
  172. send(rt->rc, &r);
  173. sleep(5000);
  174. }
  175. }
  176. #endif //asdf
  177. /*
  178. * open/close the keyboard, mouse and resize channels
  179. */
  180. static Channel *kbdc;
  181. static Channel *mousec;
  182. static Channel *resizec;
  183. static Keyboardctl *kctl;
  184. static Mousectl *mctl;
  185. static void
  186. openkmr(void)
  187. {
  188. /* get channels for subsequent newcontrolset calls */
  189. kctl = initkeyboard(nil);
  190. if(kctl == nil)
  191. sysfatal("can't initialize keyboard: %r");
  192. kbdc = kctl->c;
  193. mctl = initmouse(nil, screen);
  194. if(mctl == nil)
  195. sysfatal("can't initialize mouse: %r");
  196. mousec = mctl->c;
  197. resizec = mctl->resizec;
  198. }
  199. static void
  200. closekmr(void)
  201. {
  202. Mouse m;
  203. while(nbrecv(kbdc, &m) > 0)
  204. ;
  205. closekeyboard(kctl);
  206. while(nbrecv(mousec, &m) > 0)
  207. ;
  208. closemouse(mctl);
  209. }
  210. /*
  211. * called when the window is resized
  212. */
  213. void
  214. resizecontrolset(Controlset *cs)
  215. {
  216. RequestType *p;
  217. for(p = rt; p->file != 0; p++){
  218. if(p->cs == cs){
  219. (*p->r)(cs);
  220. break;
  221. }
  222. }
  223. }
  224. /*
  225. * hide window when not in use
  226. */
  227. static void
  228. unhide(void)
  229. {
  230. int wctl;
  231. wctl = open("/dev/wctl", OWRITE);
  232. if(wctl < 0)
  233. return;
  234. fprint(wctl, "unhide");
  235. close(wctl);
  236. }
  237. static void
  238. hide(void)
  239. {
  240. int wctl;
  241. int tries;
  242. wctl = open("/dev/wctl", OWRITE);
  243. if(wctl < 0)
  244. return;
  245. for(tries = 0; tries < 10; tries++){
  246. if(fprint(wctl, "hide") >= 0)
  247. break;
  248. sleep(100);
  249. }
  250. close(wctl);
  251. }
  252. /*
  253. * set up the controls for the confirmation window
  254. */
  255. static Channel*
  256. setupconfirm(Request *r)
  257. {
  258. Controlset *cs;
  259. Channel *c;
  260. Attr *a;
  261. /* create a new control set for the confirmation */
  262. openkmr();
  263. cs = newcontrolset(screen, kbdc, mousec, resizec);
  264. createtext(cs, "msg");
  265. chanprint(cs->ctl, "msg image paleyellow");
  266. chanprint(cs->ctl, "msg border 1");
  267. chanprint(cs->ctl, "msg add 'The following key is being used:'");
  268. for(a = r->a; a != nil; a = a->next)
  269. chanprint(cs->ctl, "msg add ' %s = %s'", a->name,
  270. a->val);
  271. namectlimage(display->white, "i_white");
  272. namectlimage(display->black, "i_black");
  273. b_remember = createbutton(cs, "b_remember");
  274. chanprint(cs->ctl, "b_remember border 1");
  275. chanprint(cs->ctl, "b_remember mask i_white");
  276. chanprint(cs->ctl, "b_remember image i_white");
  277. chanprint(cs->ctl, "b_remember light i_black");
  278. createtext(cs, "t_remember");
  279. chanprint(cs->ctl, "t_remember image white");
  280. chanprint(cs->ctl, "t_remember bordercolor white");
  281. chanprint(cs->ctl, "t_remember add 'Remember this answer for future confirmations'");
  282. b_accept = createtextbutton(cs, "b_accept");
  283. chanprint(cs->ctl, "b_accept border 1");
  284. chanprint(cs->ctl, "b_accept align center");
  285. chanprint(cs->ctl, "b_accept text Accept");
  286. chanprint(cs->ctl, "b_accept image i_white");
  287. chanprint(cs->ctl, "b_accept light i_black");
  288. b_refuse = createtextbutton(cs, "b_refuse");
  289. chanprint(cs->ctl, "b_refuse border 1");
  290. chanprint(cs->ctl, "b_refuse align center");
  291. chanprint(cs->ctl, "b_refuse text Refuse");
  292. chanprint(cs->ctl, "b_refuse image i_white");
  293. chanprint(cs->ctl, "b_refuse light i_black");
  294. c = chancreate(sizeof(char*), 0);
  295. controlwire(b_remember, "event", c);
  296. controlwire(b_accept, "event", c);
  297. controlwire(b_refuse, "event", c);
  298. /* make the controls interactive */
  299. activate(b_remember);
  300. activate(b_accept);
  301. activate(b_refuse);
  302. r->rt->cs = cs;
  303. unhide();
  304. resizecontrolset(cs);
  305. return c;
  306. }
  307. /*
  308. * resize the controls for the confirmation window
  309. */
  310. static void
  311. resizeconfirm(Controlset *cs)
  312. {
  313. Rectangle r, mr, nr, ntr, ar, rr;
  314. int fontwidth;
  315. fontwidth = font->height;
  316. /* get usable window rectangle */
  317. if(getwindow(display, Refnone) < 0)
  318. ctlerror("resize failed: %r");
  319. r = insetrect(screen->r, 10);
  320. /* message box fills everything not needed for buttons */
  321. mr = r;
  322. mr.max.y = mr.min.y + font->height*((Dy(mr)-3*ButtonDim-font->height-4)/font->height);
  323. /* remember button */
  324. nr.min = Pt(mr.min.x, mr.max.y+ButtonDim);
  325. nr.max = Pt(mr.max.x, r.max.y);
  326. if(Dx(nr) > ButtonDim)
  327. nr.max.x = nr.min.x+ButtonDim;
  328. if(Dy(nr) > ButtonDim)
  329. nr.max.y = nr.min.y+ButtonDim;
  330. ntr.min = Pt(nr.max.x+ButtonDim, nr.min.y);
  331. ntr.max = Pt(r.max.x, nr.min.y+font->height);
  332. /* accept/refuse buttons */
  333. ar.min = Pt(r.min.x+Dx(r)/2-ButtonDim-6*fontwidth, nr.max.y+ButtonDim);
  334. ar.max = Pt(ar.min.x+6*fontwidth, ar.min.y+font->height+4);
  335. rr.min = Pt(r.min.x+Dx(r)/2+ButtonDim, nr.max.y+ButtonDim);
  336. rr.max = Pt(rr.min.x+6*fontwidth, rr.min.y+font->height+4);
  337. /* make the controls visible */
  338. chanprint(cs->ctl, "msg rect %R\nmsg show", mr);
  339. chanprint(cs->ctl, "b_remember rect %R\nb_remember show", nr);
  340. chanprint(cs->ctl, "t_remember rect %R\nt_remember show", ntr);
  341. chanprint(cs->ctl, "b_accept rect %R\nb_accept show", ar);
  342. chanprint(cs->ctl, "b_refuse rect %R\nb_refuse show", rr);
  343. }
  344. /*
  345. * free the controls for the confirmation window
  346. */
  347. static void
  348. teardownconfirm(Request *r)
  349. {
  350. Controlset *cs;
  351. cs = r->rt->cs;
  352. r->rt->cs = nil;
  353. hide();
  354. closecontrolset(cs);
  355. closekmr();
  356. }
  357. /*
  358. * get user confirmation of a key
  359. */
  360. static void
  361. confirm(Request *r)
  362. {
  363. Channel *c;
  364. char *s;
  365. int n;
  366. char *args[3];
  367. int remember;
  368. Attr *val;
  369. Memory *m;
  370. /* if it's something that the user wanted us not to ask again about */
  371. m = searchmem(r->a);
  372. if(m != nil){
  373. fprint(r->rt->fd, "%A %A", r->tag, m->val);
  374. return;
  375. }
  376. /* set up the controls */
  377. c = setupconfirm(r);
  378. /* wait for user to reply */
  379. remember = 0;
  380. for(;;){
  381. s = recvp(c);
  382. n = tokenize(s, args, nelem(args));
  383. if(n==3 && strcmp(args[1], "value")==0){
  384. if(strcmp(args[0], "b_remember:") == 0){
  385. remember = atoi(args[2]);
  386. }
  387. if(strcmp(args[0], "b_accept:") == 0){
  388. val = _mkattr(AttrNameval, "answer", "yes", nil);
  389. free(s);
  390. break;
  391. }
  392. if(strcmp(args[0], "b_refuse:") == 0){
  393. val = _mkattr(AttrNameval, "answer", "no", nil);
  394. free(s);
  395. break;
  396. }
  397. }
  398. free(s);
  399. }
  400. teardownconfirm(r);
  401. fprint(r->rt->fd, "%A %A", r->tag, val);
  402. if(remember)
  403. addmem(_copyattr(r->a), val);
  404. else
  405. _freeattr(val);
  406. }
  407. /*
  408. * confirmations that are remembered
  409. */
  410. static int
  411. match(Attr *a, Attr *b)
  412. {
  413. Attr *x;
  414. for(; a != nil; a = a->next){
  415. x = _findattr(b, a->name);
  416. if(x == nil || strcmp(a->val, x->val) != 0)
  417. return 0;
  418. }
  419. return 1;
  420. }
  421. static Memory*
  422. searchmem(Attr *a)
  423. {
  424. Memory *m;
  425. for(m = mem; m != nil; m = m->next){
  426. if(match(a, m->a))
  427. break;
  428. }
  429. return m;
  430. }
  431. static void
  432. addmem(Attr *a, Attr *val)
  433. {
  434. Memory *m;
  435. m = malloc(sizeof *m);
  436. if(m == nil)
  437. return;
  438. m->a = a;
  439. m->val = val;
  440. m->next = mem;
  441. mem = m;
  442. }
  443. /* controls for needkey */
  444. Control *msg;
  445. Control *b_done;
  446. enum {
  447. Pprivate= 1<<0,
  448. Pneed= 1<<1,
  449. };
  450. typedef struct Entry Entry;
  451. struct Entry {
  452. Control *name;
  453. Control *val;
  454. Control *eq;
  455. Attr *a;
  456. };
  457. static Entry *entry;
  458. static int entries;
  459. /*
  460. * set up the controls for the confirmation window
  461. */
  462. static Channel*
  463. setupneedkey(Request *r)
  464. {
  465. Controlset *cs;
  466. Channel *c;
  467. Attr *a;
  468. Attr **l;
  469. char cn[10];
  470. int i;
  471. /* create a new control set for the confirmation */
  472. openkmr();
  473. cs = newcontrolset(screen, kbdc, mousec, resizec);
  474. /* count attributes and allocate entry controls */
  475. entries = 0;
  476. for(l = &r->a; *l; l = &(*l)->next)
  477. entries++;
  478. if(entries == 0){
  479. closecontrolset(cs);
  480. closekmr();
  481. return nil;
  482. }
  483. *l = a = mallocz(sizeof *a, 1);
  484. a->type = AttrQuery;
  485. entries++;
  486. l = &(*l)->next;
  487. *l = a = mallocz(sizeof *a, 1);
  488. a->type = AttrQuery;
  489. entries++;
  490. entry = malloc(entries*sizeof(Entry));
  491. if(entry == nil){
  492. closecontrolset(cs);
  493. closekmr();
  494. return nil;
  495. }
  496. namectlimage(display->white, "i_white");
  497. namectlimage(display->black, "i_black");
  498. /* create controls */
  499. msg = createtext(cs, "msg");
  500. chanprint(cs->ctl, "msg image white");
  501. chanprint(cs->ctl, "msg bordercolor white");
  502. chanprint(cs->ctl, "msg add 'You need the following key. Fill in the blanks'");
  503. chanprint(cs->ctl, "msg add 'and click on the DONE button.'");
  504. for(i = 0, a = r->a; a != nil; i++, a = a->next){
  505. entry[i].a = a;
  506. snprint(cn, sizeof cn, "name_%d", i);
  507. if(entry[i].a->name == nil){
  508. entry[i].name = createentry(cs, cn);
  509. chanprint(cs->ctl, "%s image yellow", cn);
  510. chanprint(cs->ctl, "%s border 1", cn);
  511. } else {
  512. entry[i].name = createtext(cs, cn);
  513. chanprint(cs->ctl, "%s image white", cn);
  514. chanprint(cs->ctl, "%s bordercolor white", cn);
  515. chanprint(cs->ctl, "%s add '%s'", cn, a->name);
  516. }
  517. snprint(cn, sizeof cn, "val_%d", i);
  518. if(a->type == AttrQuery){
  519. entry[i].val = createentry(cs, cn);
  520. chanprint(cs->ctl, "%s image yellow", cn);
  521. chanprint(cs->ctl, "%s border 1", cn);
  522. if(a->name != nil){
  523. if(strcmp(a->name, "user") == 0)
  524. chanprint(cs->ctl, "%s value %q", cn, getuser());
  525. if(*a->name == '!')
  526. chanprint(cs->ctl, "%s font invisible", cn);
  527. }
  528. } else {
  529. entry[i].val = createtext(cs, cn);
  530. chanprint(cs->ctl, "%s image white", cn);
  531. chanprint(cs->ctl, "%s add %q", cn, a->val);
  532. }
  533. snprint(cn, sizeof cn, "eq_%d", i);
  534. entry[i].eq = createtext(cs, cn);
  535. chanprint(cs->ctl, "%s image white", cn);
  536. chanprint(cs->ctl, "%s add ' = '", cn);
  537. }
  538. b_done = createtextbutton(cs, "b_done");
  539. chanprint(cs->ctl, "b_done border 1");
  540. chanprint(cs->ctl, "b_done align center");
  541. chanprint(cs->ctl, "b_done text DONE");
  542. chanprint(cs->ctl, "b_done image green");
  543. chanprint(cs->ctl, "b_done light green");
  544. /* wire controls for input */
  545. c = chancreate(sizeof(char*), 0);
  546. controlwire(b_done, "event", c);
  547. for(i = 0; i < entries; i++)
  548. if(entry[i].a->type == AttrQuery)
  549. controlwire(entry[i].val, "event", c);
  550. /* make the controls interactive */
  551. activate(msg);
  552. activate(b_done);
  553. for(i = 0; i < entries; i++){
  554. if(entry[i].a->type != AttrQuery)
  555. continue;
  556. if(entry[i].a->name == nil)
  557. activate(entry[i].name);
  558. activate(entry[i].val);
  559. }
  560. /* change the display */
  561. r->rt->cs = cs;
  562. unhide();
  563. resizecontrolset(cs);
  564. return c;
  565. }
  566. /*
  567. * resize the controls for the confirmation window
  568. */
  569. static void
  570. resizeneedkey(Controlset *cs)
  571. {
  572. Rectangle r, mr;
  573. int mid, i, n, lasty;
  574. /* get usable window rectangle */
  575. if(getwindow(display, Refnone) < 0)
  576. ctlerror("resize failed: %r");
  577. r = insetrect(screen->r, 10);
  578. /* find largest name */
  579. mid = 0;
  580. for(i = 0; i < entries; i++){
  581. if(entry[i].a->name == nil)
  582. continue;
  583. n = strlen(entry[i].a->name);
  584. if(n > mid)
  585. mid = n;
  586. }
  587. mid = (mid+2) * font->height;
  588. /* top line is the message */
  589. mr = r;
  590. mr.max.y = mr.min.y + 2*font->height + 2;
  591. chanprint(cs->ctl, "msg rect %R\nmsg show", mr);
  592. /* one line per attribute */
  593. mr.min.x += 2*font->height;
  594. lasty = mr.max.y;
  595. for(i = 0; i < entries; i++){
  596. r.min.x = mr.min.x;
  597. r.min.y = lasty+2;
  598. r.max.x = r.min.x + mid - 3*stringwidth(font, "=");
  599. r.max.y = r.min.y + font->height;
  600. chanprint(cs->ctl, "name_%d rect %R\nname_%d show", i, r, i);
  601. r.min.x = r.max.x;
  602. r.max.x = r.min.x + 3*stringwidth(font, "=");
  603. chanprint(cs->ctl, "eq_%d rect %R\neq_%d show", i, r, i);
  604. r.min.x = r.max.x;
  605. r.max.x = mr.max.x;
  606. if(Dx(r) > 32*font->height)
  607. r.max.x = r.min.x + 32*font->height;
  608. chanprint(cs->ctl, "val_%d rect %R\nval_%d show", i, r, i);
  609. lasty = r.max.y;
  610. }
  611. /* done button */
  612. mr.min.x -= 2*font->height;
  613. r.min.x = mr.min.x + mid - 3*font->height;
  614. r.min.y = lasty+10;
  615. r.max.x = r.min.x + 6*font->height;
  616. r.max.y = r.min.y + font->height + 2;
  617. chanprint(cs->ctl, "b_done rect %R\nb_done show", r);
  618. }
  619. /*
  620. * free the controls for the confirmation window
  621. */
  622. static void
  623. teardownneedkey(Request *r)
  624. {
  625. Controlset *cs;
  626. cs = r->rt->cs;
  627. r->rt->cs = nil;
  628. hide();
  629. closecontrolset(cs);
  630. closekmr();
  631. if(entry != nil)
  632. free(entry);
  633. entry = nil;
  634. }
  635. static void
  636. needkey(Request *r)
  637. {
  638. Channel *c;
  639. char *nam, *val;
  640. int i, n;
  641. int fd;
  642. char *args[3];
  643. /* set up the controls */
  644. c = setupneedkey(r);
  645. if(c == nil)
  646. goto out;
  647. /* wait for user to reply */
  648. for(;;){
  649. val = recvp(c);
  650. n = tokenize(val, args, nelem(args));
  651. if(n==3 && strcmp(args[1], "value")==0){ /* user hit 'enter' */
  652. free(val);
  653. break;
  654. }
  655. free(val);
  656. }
  657. /* get entry values */
  658. for(i = 0; i < entries; i++){
  659. if(entry[i].a->type != AttrQuery)
  660. continue;
  661. chanprint(r->rt->cs->ctl, "val_%d data", i);
  662. val = recvp(entry[i].val->data);
  663. if(entry[i].a->name == nil){
  664. chanprint(r->rt->cs->ctl, "name_%d data", i);
  665. nam = recvp(entry[i].name->data);
  666. if(nam == nil || *nam == 0){
  667. free(val);
  668. continue;
  669. }
  670. entry[i].a->val = estrdup(val);
  671. free(val);
  672. entry[i].a->name = estrdup(nam);
  673. free(nam);
  674. } else {
  675. if(val != nil){
  676. entry[i].a->val = estrdup(val);
  677. free(val);
  678. }
  679. }
  680. entry[i].a->type = AttrNameval;
  681. }
  682. /* enter the new key !!!!need to do something in case of error!!!! */
  683. fd = open("/mnt/factotum/ctl", OWRITE);
  684. fprint(fd, "key %A", r->a);
  685. close(fd);
  686. teardownneedkey(r);
  687. out:
  688. fprint(r->rt->fd, "%A", r->tag);
  689. }