xref: /plan9/sys/src/cmd/auth/factotum/fgui.c (revision 9ef7517a50e613e265e62b53dd1110fd021da569)
19a747e4fSDavid du Colombier #include "dat.h"
29a747e4fSDavid du Colombier #include <draw.h>
39a747e4fSDavid du Colombier #include <mouse.h>
49a747e4fSDavid du Colombier #include <keyboard.h>
59a747e4fSDavid du Colombier #include <control.h>
69a747e4fSDavid du Colombier 
79a747e4fSDavid du Colombier int ctldeletequits = 1;
89a747e4fSDavid du Colombier 
99a747e4fSDavid du Colombier typedef struct RequestType RequestType;
109a747e4fSDavid du Colombier typedef struct Request Request;
119a747e4fSDavid du Colombier typedef struct Memory Memory;
129a747e4fSDavid du Colombier 
139a747e4fSDavid du Colombier struct RequestType
149a747e4fSDavid du Colombier {
159a747e4fSDavid du Colombier 	char		*file;			/* file to read requests from */
169a747e4fSDavid du Colombier 	void		(*f)(Request*);		/* request handler */
179a747e4fSDavid du Colombier 	void		(*r)(Controlset*);	/* resize handler */
189a747e4fSDavid du Colombier 	int		fd;			/* fd = open(file, ORDWR) */
199a747e4fSDavid du Colombier 	Channel		*rc;			/* channel requests are multiplexed to */
209a747e4fSDavid du Colombier 	Controlset	*cs;
219a747e4fSDavid du Colombier };
229a747e4fSDavid du Colombier 
239a747e4fSDavid du Colombier struct Request
249a747e4fSDavid du Colombier {
259a747e4fSDavid du Colombier 	RequestType	*rt;
269a747e4fSDavid du Colombier 	Attr		*a;
279a747e4fSDavid du Colombier 	Attr		*tag;
289a747e4fSDavid du Colombier };
299a747e4fSDavid du Colombier 
309a747e4fSDavid du Colombier struct Memory
319a747e4fSDavid du Colombier {
329a747e4fSDavid du Colombier 	Memory	*next;
339a747e4fSDavid du Colombier 	Attr	*a;
349a747e4fSDavid du Colombier 	Attr	*val;
359a747e4fSDavid du Colombier };
369a747e4fSDavid du Colombier Memory *mem;
379a747e4fSDavid du Colombier 
389a747e4fSDavid du Colombier static void	readreq(void*);
399a747e4fSDavid du Colombier static void	hide(void);
409a747e4fSDavid du Colombier static void	unhide(void);
419a747e4fSDavid du Colombier static void	openkmr(void);
429a747e4fSDavid du Colombier static void	closekmr(void);
439a747e4fSDavid du Colombier static Memory*	searchmem(Attr*);
449a747e4fSDavid du Colombier static void	addmem(Attr*, Attr*);
459a747e4fSDavid du Colombier 
469a747e4fSDavid du Colombier static void	confirm(Request*);
479a747e4fSDavid du Colombier static void	resizeconfirm(Controlset*);
489a747e4fSDavid du Colombier static void	needkey(Request*);
499a747e4fSDavid du Colombier static void	resizeneedkey(Controlset*);
509a747e4fSDavid du Colombier 
519a747e4fSDavid du Colombier Control *b_remember;
529a747e4fSDavid du Colombier Control *b_accept;
539a747e4fSDavid du Colombier Control *b_refuse;
549a747e4fSDavid du Colombier 
559a747e4fSDavid du Colombier RequestType rt[] =
569a747e4fSDavid du Colombier {
579a747e4fSDavid du Colombier 	{ "/mnt/factotum/confirm",	confirm,	resizeconfirm, },
589a747e4fSDavid du Colombier 	{ "/mnt/factotum/needkey",	needkey,	resizeneedkey, },
599a747e4fSDavid du Colombier 	{ 0 },
609a747e4fSDavid du Colombier };
619a747e4fSDavid du Colombier 
629a747e4fSDavid du Colombier enum
639a747e4fSDavid du Colombier {
649a747e4fSDavid du Colombier 	ButtonDim=	15,
659a747e4fSDavid du Colombier };
669a747e4fSDavid du Colombier 
679a747e4fSDavid du Colombier void
threadmain(int argc,char * argv[])689a747e4fSDavid du Colombier threadmain(int argc, char *argv[])
699a747e4fSDavid du Colombier {
709a747e4fSDavid du Colombier 	Request r;
719a747e4fSDavid du Colombier 	Channel *rc;
729a747e4fSDavid du Colombier 	RequestType *p;
739a747e4fSDavid du Colombier 	Font *invis;
749a747e4fSDavid du Colombier 
759a747e4fSDavid du Colombier 	ARGBEGIN{
769a747e4fSDavid du Colombier 	}ARGEND;
779a747e4fSDavid du Colombier 
785e91980fSDavid du Colombier 	if(newwindow("-hide") < 0)
795e91980fSDavid du Colombier 		sysfatal("newwindow: %r");
80d9306527SDavid du Colombier 
819a747e4fSDavid du Colombier 	fmtinstall('A', _attrfmt);
829a747e4fSDavid du Colombier 
839a747e4fSDavid du Colombier 	/* create the proc's that read */
849a747e4fSDavid du Colombier 	rc = chancreate(sizeof(Request), 0);
859a747e4fSDavid du Colombier 	for(p = rt;  p->file != 0; p++){
869a747e4fSDavid du Colombier 		p->fd = -1;
879a747e4fSDavid du Colombier 		p->rc = rc;
889a747e4fSDavid du Colombier 		proccreate(readreq, p, 16*1024);
899a747e4fSDavid du Colombier 	}
909a747e4fSDavid du Colombier 
919a747e4fSDavid du Colombier 	/* gui initialization */
92*9ef7517aSDavid du Colombier 	if(initdraw(0, 0, "auth/fgui") < 0)
93*9ef7517aSDavid du Colombier 		sysfatal("initdraw failed: %r");
949a747e4fSDavid du Colombier 	initcontrols();
959a747e4fSDavid du Colombier 	hide();
969a747e4fSDavid du Colombier 
979a747e4fSDavid du Colombier 	/* get an invisible font for passwords */
989a747e4fSDavid du Colombier 	invis = openfont(display, "/lib/font/bit/lucm/passwd.9.font");
999a747e4fSDavid du Colombier 	if (invis == nil)
1009a747e4fSDavid du Colombier 		sysfatal("fgui: %s: %r", "/lib/font/bit/lucm/passwd.9.font");
1019a747e4fSDavid du Colombier 	namectlfont(invis, "invisible");
1029a747e4fSDavid du Colombier 
1039a747e4fSDavid du Colombier 	/* serialize all requests */
1049a747e4fSDavid du Colombier 	for(;;){
1059a747e4fSDavid du Colombier 		if(recv(rc, &r) < 0)
1069a747e4fSDavid du Colombier 			break;
1079a747e4fSDavid du Colombier 		(*r.rt->f)(&r);
1089a747e4fSDavid du Colombier 		_freeattr(r.a);
1099a747e4fSDavid du Colombier 		_freeattr(r.tag);
1109a747e4fSDavid du Colombier 	}
1119a747e4fSDavid du Colombier 
1129a747e4fSDavid du Colombier 	threadexitsall(nil);
1139a747e4fSDavid du Colombier }
1149a747e4fSDavid du Colombier 
1159a747e4fSDavid du Colombier /*
1169a747e4fSDavid du Colombier  *  read requests and pass them to the main loop
1179a747e4fSDavid du Colombier  */
1189a747e4fSDavid du Colombier enum
1199a747e4fSDavid du Colombier {
1209a747e4fSDavid du Colombier 	Requestlen=4096,
1219a747e4fSDavid du Colombier };
1229a747e4fSDavid du Colombier static void
readreq(void * a)1239a747e4fSDavid du Colombier readreq(void *a)
1249a747e4fSDavid du Colombier {
1259a747e4fSDavid du Colombier 	RequestType *rt = a;
1269a747e4fSDavid du Colombier 	char *buf, *p;
1279a747e4fSDavid du Colombier 	int n;
1289a747e4fSDavid du Colombier 	Request r;
1299a747e4fSDavid du Colombier 	Attr **l;
1309a747e4fSDavid du Colombier 
1319a747e4fSDavid du Colombier 	rt->fd = open(rt->file, ORDWR);
1329a747e4fSDavid du Colombier 	if(rt->fd < 0)
1339a747e4fSDavid du Colombier 		sysfatal("opening %s: %r", rt->file);
1349a747e4fSDavid du Colombier 	rt->cs = nil;
1359a747e4fSDavid du Colombier 
1369a747e4fSDavid du Colombier 	buf = malloc(Requestlen);
1379a747e4fSDavid du Colombier 	if(buf == nil)
1389a747e4fSDavid du Colombier 		sysfatal("allocating read buffer: %r");
1399a747e4fSDavid du Colombier 	r.rt = rt;
1409a747e4fSDavid du Colombier 
1419a747e4fSDavid du Colombier 	for(;;){
1429a747e4fSDavid du Colombier 		n = read(rt->fd, buf, Requestlen-1);
1439a747e4fSDavid du Colombier 		if(n < 0)
1449a747e4fSDavid du Colombier 			break;
1459a747e4fSDavid du Colombier 		buf[n] = 0;
1469a747e4fSDavid du Colombier 
1479a747e4fSDavid du Colombier 		/* skip verb, parse attributes, and remove tag */
1489a747e4fSDavid du Colombier 		p = strchr(buf, ' ');
1499a747e4fSDavid du Colombier 		if(p != nil)
1509a747e4fSDavid du Colombier 			p++;
1519a747e4fSDavid du Colombier 		else
1529a747e4fSDavid du Colombier 			p = buf;
1539a747e4fSDavid du Colombier 		r.a = _parseattr(p);
1549a747e4fSDavid du Colombier 
1559a747e4fSDavid du Colombier 		/* separate out the tag */
1569a747e4fSDavid du Colombier 		r.tag = nil;
1579a747e4fSDavid du Colombier 		for(l = &r.a; *l != nil; l = &(*l)->next)
1582ebbfa15SDavid du Colombier 			if(strcmp((*l)->name, "tag") == 0){
1599a747e4fSDavid du Colombier 				r.tag = *l;
1609a747e4fSDavid du Colombier 				*l = r.tag->next;
1619a747e4fSDavid du Colombier 				r.tag->next = nil;
1629a747e4fSDavid du Colombier 				break;
1639a747e4fSDavid du Colombier 			}
1649a747e4fSDavid du Colombier 
1659a747e4fSDavid du Colombier 		/* if no tag, forget it */
1669a747e4fSDavid du Colombier 		if(r.tag == nil){
1679a747e4fSDavid du Colombier 			_freeattr(r.a);
1689a747e4fSDavid du Colombier 			continue;
1699a747e4fSDavid du Colombier 		}
1709a747e4fSDavid du Colombier 
1719a747e4fSDavid du Colombier 		send(rt->rc, &r);
1729a747e4fSDavid du Colombier 	}
1739a747e4fSDavid du Colombier }
1749a747e4fSDavid du Colombier #ifdef asdf
1759a747e4fSDavid du Colombier static void
readreq(void * a)1769a747e4fSDavid du Colombier readreq(void *a)
1779a747e4fSDavid du Colombier {
1789a747e4fSDavid du Colombier 	RequestType *rt = a;
1799a747e4fSDavid du Colombier 	char *buf, *p;
1809a747e4fSDavid du Colombier 	int n;
1819a747e4fSDavid du Colombier 	Request r;
1829a747e4fSDavid du Colombier 
1839a747e4fSDavid du Colombier 	rt->fd = -1;
1849a747e4fSDavid du Colombier 	rt->cs = nil;
1859a747e4fSDavid du Colombier 
1869a747e4fSDavid du Colombier 	buf = malloc(Requestlen);
1879a747e4fSDavid du Colombier 	if(buf == nil)
1889a747e4fSDavid du Colombier 		sysfatal("allocating read buffer: %r");
1899a747e4fSDavid du Colombier 	r.rt = rt;
1909a747e4fSDavid du Colombier 
1919a747e4fSDavid du Colombier 	for(;;){
1929a747e4fSDavid du Colombier 		strcpy(buf, "adfasdf=afdasdf asdfasdf=asdfasdf");
1939a747e4fSDavid du Colombier 		r.a = _parseattr(buf);
1949a747e4fSDavid du Colombier 		send(rt->rc, &r);
1959a747e4fSDavid du Colombier 		sleep(5000);
1969a747e4fSDavid du Colombier 	}
1979a747e4fSDavid du Colombier }
1989a747e4fSDavid du Colombier #endif asdf
1999a747e4fSDavid du Colombier 
2009a747e4fSDavid du Colombier /*
2019a747e4fSDavid du Colombier  *  open/close the keyboard, mouse and resize channels
2029a747e4fSDavid du Colombier  */
2039a747e4fSDavid du Colombier static Channel *kbdc;
2049a747e4fSDavid du Colombier static Channel *mousec;
2059a747e4fSDavid du Colombier static Channel *resizec;
2069a747e4fSDavid du Colombier static Keyboardctl *kctl;
2079a747e4fSDavid du Colombier static Mousectl *mctl;
2089a747e4fSDavid du Colombier 
2099a747e4fSDavid du Colombier static void
openkmr(void)2109a747e4fSDavid du Colombier openkmr(void)
2119a747e4fSDavid du Colombier {
2129a747e4fSDavid du Colombier 	/* get channels for subsequent newcontrolset calls  */
2139a747e4fSDavid du Colombier 	kctl = initkeyboard(nil);
2149a747e4fSDavid du Colombier 	if(kctl == nil)
2159a747e4fSDavid du Colombier 		sysfatal("can't initialize keyboard: %r");
2169a747e4fSDavid du Colombier 	kbdc = kctl->c;
2179a747e4fSDavid du Colombier 	mctl = initmouse(nil, screen);
2189a747e4fSDavid du Colombier 	if(mctl == nil)
2199a747e4fSDavid du Colombier 		sysfatal("can't initialize mouse: %r");
2209a747e4fSDavid du Colombier 	mousec = mctl->c;
2219a747e4fSDavid du Colombier 	resizec = mctl->resizec;
2229a747e4fSDavid du Colombier }
2239a747e4fSDavid du Colombier static void
closekmr(void)2249a747e4fSDavid du Colombier closekmr(void)
2259a747e4fSDavid du Colombier {
2269a747e4fSDavid du Colombier 	Mouse m;
2279a747e4fSDavid du Colombier 
2289a747e4fSDavid du Colombier 	while(nbrecv(kbdc, &m) > 0)
2299a747e4fSDavid du Colombier 		;
2309a747e4fSDavid du Colombier 	closekeyboard(kctl);
2319a747e4fSDavid du Colombier 	while(nbrecv(mousec, &m) > 0)
2329a747e4fSDavid du Colombier 		;
2339a747e4fSDavid du Colombier 	closemouse(mctl);
2349a747e4fSDavid du Colombier }
2359a747e4fSDavid du Colombier 
2369a747e4fSDavid du Colombier 
2379a747e4fSDavid du Colombier /*
2389a747e4fSDavid du Colombier  *  called when the window is resized
2399a747e4fSDavid du Colombier  */
2409a747e4fSDavid du Colombier void
resizecontrolset(Controlset * cs)2419a747e4fSDavid du Colombier resizecontrolset(Controlset *cs)
2429a747e4fSDavid du Colombier {
2439a747e4fSDavid du Colombier 	RequestType *p;
2449a747e4fSDavid du Colombier 
2459a747e4fSDavid du Colombier 	for(p = rt;  p->file != 0; p++){
2469a747e4fSDavid du Colombier 		if(p->cs == cs){
2479a747e4fSDavid du Colombier 			(*p->r)(cs);
2489a747e4fSDavid du Colombier 			break;
2499a747e4fSDavid du Colombier 		}
2509a747e4fSDavid du Colombier 	}
2519a747e4fSDavid du Colombier }
2529a747e4fSDavid du Colombier 
2539a747e4fSDavid du Colombier /*
2549a747e4fSDavid du Colombier  *  hide window when not in use
2559a747e4fSDavid du Colombier  */
2569a747e4fSDavid du Colombier static void
unhide(void)2579a747e4fSDavid du Colombier unhide(void)
2589a747e4fSDavid du Colombier {
2599a747e4fSDavid du Colombier 	int wctl;
2609a747e4fSDavid du Colombier 
2619a747e4fSDavid du Colombier 	wctl = open("/dev/wctl", OWRITE);
2629a747e4fSDavid du Colombier 	if(wctl < 0)
2639a747e4fSDavid du Colombier 		return;
2649a747e4fSDavid du Colombier 	fprint(wctl, "unhide");
2659a747e4fSDavid du Colombier 	close(wctl);
2669a747e4fSDavid du Colombier }
2679a747e4fSDavid du Colombier static void
hide(void)2689a747e4fSDavid du Colombier hide(void)
2699a747e4fSDavid du Colombier {
2709a747e4fSDavid du Colombier 	int wctl;
2719a747e4fSDavid du Colombier 	int tries;
2729a747e4fSDavid du Colombier 
2739a747e4fSDavid du Colombier 	wctl = open("/dev/wctl", OWRITE);
2749a747e4fSDavid du Colombier 	if(wctl < 0)
2759a747e4fSDavid du Colombier 		return;
2769a747e4fSDavid du Colombier 	for(tries = 0; tries < 10; tries++){
2779a747e4fSDavid du Colombier 		if(fprint(wctl, "hide") >= 0)
2789a747e4fSDavid du Colombier 			break;
2799a747e4fSDavid du Colombier 		sleep(100);
2809a747e4fSDavid du Colombier 	}
2819a747e4fSDavid du Colombier 	close(wctl);
2829a747e4fSDavid du Colombier }
2839a747e4fSDavid du Colombier 
2849a747e4fSDavid du Colombier /*
2859a747e4fSDavid du Colombier  *  set up the controls for the confirmation window
2869a747e4fSDavid du Colombier  */
2879a747e4fSDavid du Colombier static Channel*
setupconfirm(Request * r)2889a747e4fSDavid du Colombier setupconfirm(Request *r)
2899a747e4fSDavid du Colombier {
2909a747e4fSDavid du Colombier 	Controlset *cs;
2919a747e4fSDavid du Colombier 	Channel *c;
2929a747e4fSDavid du Colombier 	Attr *a;
2939a747e4fSDavid du Colombier 
2949a747e4fSDavid du Colombier 	/* create a new control set for the confirmation */
2959a747e4fSDavid du Colombier 	openkmr();
2969a747e4fSDavid du Colombier 	cs = newcontrolset(screen, kbdc, mousec, resizec);
2979a747e4fSDavid du Colombier 
2989a747e4fSDavid du Colombier 	createtext(cs, "msg");
2999a747e4fSDavid du Colombier 	chanprint(cs->ctl, "msg image paleyellow");
3009a747e4fSDavid du Colombier 	chanprint(cs->ctl, "msg border 1");
3019a747e4fSDavid du Colombier 	chanprint(cs->ctl, "msg add 'The following key is being used:'");
3029a747e4fSDavid du Colombier 	for(a = r->a; a != nil; a = a->next)
3032ebbfa15SDavid du Colombier 		chanprint(cs->ctl, "msg add '    %s = %s'", a->name,
3042ebbfa15SDavid du Colombier 				a->val);
3059a747e4fSDavid du Colombier 
3069a747e4fSDavid du Colombier 	namectlimage(display->white, "i_white");
3079a747e4fSDavid du Colombier 	namectlimage(display->black, "i_black");
3089a747e4fSDavid du Colombier 
3099a747e4fSDavid du Colombier 	b_remember = createbutton(cs, "b_remember");
3109a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_remember border 1");
3119a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_remember mask i_white");
3129a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_remember image i_white");
3139a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_remember light i_black");
3149a747e4fSDavid du Colombier 
3159a747e4fSDavid du Colombier 	createtext(cs, "t_remember");
3169a747e4fSDavid du Colombier 	chanprint(cs->ctl, "t_remember image white");
3179a747e4fSDavid du Colombier 	chanprint(cs->ctl, "t_remember bordercolor white");
3189a747e4fSDavid du Colombier 	chanprint(cs->ctl, "t_remember add 'Remember this answer for future confirmations'");
3199a747e4fSDavid du Colombier 
3209a747e4fSDavid du Colombier 	b_accept = createtextbutton(cs, "b_accept");
3219a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_accept border 1");
3229a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_accept align center");
3239a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_accept text Accept");
3249a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_accept image i_white");
3259a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_accept light i_black");
3269a747e4fSDavid du Colombier 
3279a747e4fSDavid du Colombier 	b_refuse = createtextbutton(cs, "b_refuse");
3289a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_refuse border 1");
3299a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_refuse align center");
3309a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_refuse text Refuse");
3319a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_refuse image i_white");
3329a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_refuse light i_black");
3339a747e4fSDavid du Colombier 
3349a747e4fSDavid du Colombier 	c = chancreate(sizeof(char*), 0);
3359a747e4fSDavid du Colombier 	controlwire(b_remember, "event", c);
3369a747e4fSDavid du Colombier 	controlwire(b_accept, "event", c);
3379a747e4fSDavid du Colombier 	controlwire(b_refuse, "event", c);
3389a747e4fSDavid du Colombier 
3399a747e4fSDavid du Colombier 	/* make the controls interactive */
3409a747e4fSDavid du Colombier 	activate(b_remember);
3419a747e4fSDavid du Colombier 	activate(b_accept);
3429a747e4fSDavid du Colombier 	activate(b_refuse);
3439a747e4fSDavid du Colombier 	r->rt->cs = cs;
3449a747e4fSDavid du Colombier 	unhide();
3459a747e4fSDavid du Colombier 	resizecontrolset(cs);
3469a747e4fSDavid du Colombier 
3479a747e4fSDavid du Colombier 	return c;
3489a747e4fSDavid du Colombier }
3499a747e4fSDavid du Colombier 
3509a747e4fSDavid du Colombier /*
3519a747e4fSDavid du Colombier  *  resize the controls for the confirmation window
3529a747e4fSDavid du Colombier  */
3539a747e4fSDavid du Colombier static void
resizeconfirm(Controlset * cs)3549a747e4fSDavid du Colombier resizeconfirm(Controlset *cs)
3559a747e4fSDavid du Colombier {
3569a747e4fSDavid du Colombier 	Rectangle r, mr, nr, ntr, ar, rr;
3579a747e4fSDavid du Colombier 	int fontwidth;
3589a747e4fSDavid du Colombier 
3599a747e4fSDavid du Colombier 	fontwidth = font->height;
3609a747e4fSDavid du Colombier 
3619a747e4fSDavid du Colombier 	/* get usable window rectangle */
3629a747e4fSDavid du Colombier 	if(getwindow(display, Refnone) < 0)
3639a747e4fSDavid du Colombier 		ctlerror("resize failed: %r");
3649a747e4fSDavid du Colombier 	r = insetrect(screen->r, 10);
3659a747e4fSDavid du Colombier 
3669a747e4fSDavid du Colombier 	/* message box fills everything not needed for buttons */
3679a747e4fSDavid du Colombier 	mr = r;
3689a747e4fSDavid du Colombier 	mr.max.y = mr.min.y + font->height*((Dy(mr)-3*ButtonDim-font->height-4)/font->height);
3699a747e4fSDavid du Colombier 
3709a747e4fSDavid du Colombier 	/* remember button */
3719a747e4fSDavid du Colombier 	nr.min = Pt(mr.min.x, mr.max.y+ButtonDim);
3729a747e4fSDavid du Colombier 	nr.max = Pt(mr.max.x, r.max.y);
3739a747e4fSDavid du Colombier 	if(Dx(nr) > ButtonDim)
3749a747e4fSDavid du Colombier 		nr.max.x = nr.min.x+ButtonDim;
3759a747e4fSDavid du Colombier 	if(Dy(nr) > ButtonDim)
3769a747e4fSDavid du Colombier 		nr.max.y = nr.min.y+ButtonDim;
3779a747e4fSDavid du Colombier 	ntr.min = Pt(nr.max.x+ButtonDim, nr.min.y);
3789a747e4fSDavid du Colombier 	ntr.max = Pt(r.max.x, nr.min.y+font->height);
3799a747e4fSDavid du Colombier 
3809a747e4fSDavid du Colombier 	/* accept/refuse buttons */
3819a747e4fSDavid du Colombier 	ar.min = Pt(r.min.x+Dx(r)/2-ButtonDim-6*fontwidth, nr.max.y+ButtonDim);
3829a747e4fSDavid du Colombier 	ar.max = Pt(ar.min.x+6*fontwidth, ar.min.y+font->height+4);
3839a747e4fSDavid du Colombier 	rr.min = Pt(r.min.x+Dx(r)/2+ButtonDim, nr.max.y+ButtonDim);
3849a747e4fSDavid du Colombier 	rr.max = Pt(rr.min.x+6*fontwidth, rr.min.y+font->height+4);
3859a747e4fSDavid du Colombier 
3869a747e4fSDavid du Colombier 	/* make the controls visible */
3879a747e4fSDavid du Colombier 	chanprint(cs->ctl, "msg rect %R\nmsg show", mr);
3889a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_remember rect %R\nb_remember show", nr);
3899a747e4fSDavid du Colombier 	chanprint(cs->ctl, "t_remember rect %R\nt_remember show", ntr);
3909a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_accept rect %R\nb_accept show", ar);
3919a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_refuse rect %R\nb_refuse show", rr);
3929a747e4fSDavid du Colombier }
3939a747e4fSDavid du Colombier 
3949a747e4fSDavid du Colombier /*
3959a747e4fSDavid du Colombier  *  free the controls for the confirmation window
3969a747e4fSDavid du Colombier  */
3979a747e4fSDavid du Colombier static void
teardownconfirm(Request * r)3989a747e4fSDavid du Colombier teardownconfirm(Request *r)
3999a747e4fSDavid du Colombier {
4009a747e4fSDavid du Colombier 	Controlset *cs;
4019a747e4fSDavid du Colombier 
4029a747e4fSDavid du Colombier 	cs = r->rt->cs;
4039a747e4fSDavid du Colombier 	r->rt->cs = nil;
4049a747e4fSDavid du Colombier 	hide();
4059a747e4fSDavid du Colombier 	closecontrolset(cs);
4069a747e4fSDavid du Colombier 	closekmr();
4079a747e4fSDavid du Colombier }
4089a747e4fSDavid du Colombier 
4099a747e4fSDavid du Colombier /*
4109a747e4fSDavid du Colombier  *  get user confirmation of a key
4119a747e4fSDavid du Colombier  */
4129a747e4fSDavid du Colombier static void
confirm(Request * r)4139a747e4fSDavid du Colombier confirm(Request *r)
4149a747e4fSDavid du Colombier {
4159a747e4fSDavid du Colombier 	Channel *c;
4169a747e4fSDavid du Colombier 	char *s;
4179a747e4fSDavid du Colombier 	int n;
4189a747e4fSDavid du Colombier 	char *args[3];
4199a747e4fSDavid du Colombier 	int remember;
4209a747e4fSDavid du Colombier 	Attr *val;
4219a747e4fSDavid du Colombier 	Memory *m;
4229a747e4fSDavid du Colombier 
4239a747e4fSDavid du Colombier 	/* if it's something that the user wanted us not to ask again about */
4249a747e4fSDavid du Colombier 	m = searchmem(r->a);
4259a747e4fSDavid du Colombier 	if(m != nil){
4269a747e4fSDavid du Colombier 		fprint(r->rt->fd, "%A %A", r->tag, m->val);
4279a747e4fSDavid du Colombier 		return;
4289a747e4fSDavid du Colombier 	}
4299a747e4fSDavid du Colombier 
4309a747e4fSDavid du Colombier 	/* set up the controls */
4319a747e4fSDavid du Colombier 	c = setupconfirm(r);
4329a747e4fSDavid du Colombier 
4339a747e4fSDavid du Colombier 	/* wait for user to reply */
4349a747e4fSDavid du Colombier 	remember = 0;
4359a747e4fSDavid du Colombier 	for(;;){
4369a747e4fSDavid du Colombier 		s = recvp(c);
4379a747e4fSDavid du Colombier 		n = tokenize(s, args, nelem(args));
4389a747e4fSDavid du Colombier 		if(n==3 && strcmp(args[1], "value")==0){
4399a747e4fSDavid du Colombier 			if(strcmp(args[0], "b_remember:") == 0){
4409a747e4fSDavid du Colombier 				remember = atoi(args[2]);
4419a747e4fSDavid du Colombier 			}
4429a747e4fSDavid du Colombier 			if(strcmp(args[0], "b_accept:") == 0){
4439a747e4fSDavid du Colombier 				val = _mkattr(AttrNameval, "answer", "yes", nil);
4449a747e4fSDavid du Colombier 				free(s);
4459a747e4fSDavid du Colombier 				break;
4469a747e4fSDavid du Colombier 			}
4479a747e4fSDavid du Colombier 			if(strcmp(args[0], "b_refuse:") == 0){
4489a747e4fSDavid du Colombier 				val = _mkattr(AttrNameval, "answer", "no", nil);
4499a747e4fSDavid du Colombier 				free(s);
4509a747e4fSDavid du Colombier 				break;
4519a747e4fSDavid du Colombier 			}
4529a747e4fSDavid du Colombier 		}
4539a747e4fSDavid du Colombier 		free(s);
4549a747e4fSDavid du Colombier 	}
4559a747e4fSDavid du Colombier 	teardownconfirm(r);
4569a747e4fSDavid du Colombier 	fprint(r->rt->fd, "%A %A", r->tag, val);
4579a747e4fSDavid du Colombier 	if(remember)
4589a747e4fSDavid du Colombier 		addmem(_copyattr(r->a), val);
4599a747e4fSDavid du Colombier 	else
4609a747e4fSDavid du Colombier 		_freeattr(val);
4619a747e4fSDavid du Colombier }
4629a747e4fSDavid du Colombier 
4639a747e4fSDavid du Colombier /*
4649a747e4fSDavid du Colombier  *  confirmations that are remembered
4659a747e4fSDavid du Colombier  */
4669a747e4fSDavid du Colombier static int
match(Attr * a,Attr * b)4679a747e4fSDavid du Colombier match(Attr *a, Attr *b)
4689a747e4fSDavid du Colombier {
4699a747e4fSDavid du Colombier 	Attr *x;
4709a747e4fSDavid du Colombier 
4719a747e4fSDavid du Colombier 	for(; a != nil; a = a->next){
4722ebbfa15SDavid du Colombier 		x = _findattr(b, a->name);
4732ebbfa15SDavid du Colombier 		if(x == nil || strcmp(a->val, x->val) != 0)
4749a747e4fSDavid du Colombier 			return 0;
4759a747e4fSDavid du Colombier 	}
4769a747e4fSDavid du Colombier 	return 1;
4779a747e4fSDavid du Colombier }
4789a747e4fSDavid du Colombier static Memory*
searchmem(Attr * a)4799a747e4fSDavid du Colombier searchmem(Attr *a)
4809a747e4fSDavid du Colombier {
4819a747e4fSDavid du Colombier 	Memory *m;
4829a747e4fSDavid du Colombier 
4839a747e4fSDavid du Colombier 	for(m = mem; m != nil; m = m->next){
4849a747e4fSDavid du Colombier 		if(match(a, m->a))
4859a747e4fSDavid du Colombier 			break;
4869a747e4fSDavid du Colombier 	}
4879a747e4fSDavid du Colombier 	return m;
4889a747e4fSDavid du Colombier }
4899a747e4fSDavid du Colombier static void
addmem(Attr * a,Attr * val)4909a747e4fSDavid du Colombier addmem(Attr *a, Attr *val)
4919a747e4fSDavid du Colombier {
4929a747e4fSDavid du Colombier 	Memory *m;
4939a747e4fSDavid du Colombier 
4949a747e4fSDavid du Colombier 	m = malloc(sizeof *m);
4959a747e4fSDavid du Colombier 	if(m == nil)
4969a747e4fSDavid du Colombier 		return;
4979a747e4fSDavid du Colombier 	m->a = a;
4989a747e4fSDavid du Colombier 	m->val = val;
4999a747e4fSDavid du Colombier 	m->next = mem;
5009a747e4fSDavid du Colombier 	mem = m;
5019a747e4fSDavid du Colombier }
5029a747e4fSDavid du Colombier 
5039a747e4fSDavid du Colombier /* controls for needkey */
5049a747e4fSDavid du Colombier Control *msg;
5059a747e4fSDavid du Colombier Control *b_done;
5069a747e4fSDavid du Colombier enum {
5079a747e4fSDavid du Colombier 	Pprivate=	1<<0,
5089a747e4fSDavid du Colombier 	Pneed=		1<<1,
5099a747e4fSDavid du Colombier };
5109a747e4fSDavid du Colombier typedef struct Entry Entry;
5119a747e4fSDavid du Colombier struct Entry {
5129a747e4fSDavid du Colombier 	Control *name;
5139a747e4fSDavid du Colombier 	Control *val;
5149a747e4fSDavid du Colombier 	Control *eq;
5159a747e4fSDavid du Colombier 	Attr *a;
5169a747e4fSDavid du Colombier };
5179a747e4fSDavid du Colombier static Entry *entry;
5189a747e4fSDavid du Colombier static int entries;
5199a747e4fSDavid du Colombier 
5209a747e4fSDavid du Colombier /*
5219a747e4fSDavid du Colombier  *  set up the controls for the confirmation window
5229a747e4fSDavid du Colombier  */
5239a747e4fSDavid du Colombier static Channel*
setupneedkey(Request * r)5249a747e4fSDavid du Colombier setupneedkey(Request *r)
5259a747e4fSDavid du Colombier {
5269a747e4fSDavid du Colombier 	Controlset *cs;
5279a747e4fSDavid du Colombier 	Channel *c;
5289a747e4fSDavid du Colombier 	Attr *a;
5299a747e4fSDavid du Colombier 	Attr **l;
5309a747e4fSDavid du Colombier 	char cn[10];
5319a747e4fSDavid du Colombier 	int i;
5329a747e4fSDavid du Colombier 
5339a747e4fSDavid du Colombier 	/* create a new control set for the confirmation */
5349a747e4fSDavid du Colombier 	openkmr();
5359a747e4fSDavid du Colombier 	cs = newcontrolset(screen, kbdc, mousec, resizec);
5369a747e4fSDavid du Colombier 
5379a747e4fSDavid du Colombier 	/* count attributes and allocate entry controls */
5389a747e4fSDavid du Colombier 	entries = 0;
5399a747e4fSDavid du Colombier 	for(l = &r->a; *l; l = &(*l)->next)
5409a747e4fSDavid du Colombier 		entries++;
5419a747e4fSDavid du Colombier 	if(entries == 0){
5429a747e4fSDavid du Colombier 		closecontrolset(cs);
5439a747e4fSDavid du Colombier 		closekmr();
5449a747e4fSDavid du Colombier 		return nil;
5459a747e4fSDavid du Colombier 	}
5469a747e4fSDavid du Colombier 	*l = a = mallocz(sizeof *a, 1);
5479a747e4fSDavid du Colombier 	a->type = AttrQuery;
5489a747e4fSDavid du Colombier 	entries++;
5499a747e4fSDavid du Colombier 	l = &(*l)->next;
5509a747e4fSDavid du Colombier 	*l = a = mallocz(sizeof *a, 1);
5519a747e4fSDavid du Colombier 	a->type = AttrQuery;
5529a747e4fSDavid du Colombier 	entries++;
5539a747e4fSDavid du Colombier 	entry = malloc(entries*sizeof(Entry));
5549a747e4fSDavid du Colombier 	if(entry == nil){
5559a747e4fSDavid du Colombier 		closecontrolset(cs);
5569a747e4fSDavid du Colombier 		closekmr();
5579a747e4fSDavid du Colombier 		return nil;
5589a747e4fSDavid du Colombier 	}
5599a747e4fSDavid du Colombier 
5609a747e4fSDavid du Colombier 	namectlimage(display->white, "i_white");
5619a747e4fSDavid du Colombier 	namectlimage(display->black, "i_black");
5629a747e4fSDavid du Colombier 
5639a747e4fSDavid du Colombier 	/* create controls */
5649a747e4fSDavid du Colombier 	msg = createtext(cs, "msg");
5659a747e4fSDavid du Colombier 	chanprint(cs->ctl, "msg image white");
5669a747e4fSDavid du Colombier 	chanprint(cs->ctl, "msg bordercolor white");
5679a747e4fSDavid du Colombier 	chanprint(cs->ctl, "msg add 'You need the following key.  Fill in the blanks'");
5689a747e4fSDavid du Colombier 	chanprint(cs->ctl, "msg add 'and click on the DONE button.'");
5699a747e4fSDavid du Colombier 
5709a747e4fSDavid du Colombier 	for(i = 0, a = r->a; a != nil; i++, a = a->next){
5719a747e4fSDavid du Colombier 		entry[i].a = a;
5729a747e4fSDavid du Colombier 		snprint(cn, sizeof cn, "name_%d", i);
5739a747e4fSDavid du Colombier 		if(entry[i].a->name == nil){
5749a747e4fSDavid du Colombier 			entry[i].name = createentry(cs, cn);
5759a747e4fSDavid du Colombier 			chanprint(cs->ctl, "%s image yellow", cn);
5769a747e4fSDavid du Colombier 			chanprint(cs->ctl, "%s border 1", cn);
5779a747e4fSDavid du Colombier 		} else {
5789a747e4fSDavid du Colombier 			entry[i].name = createtext(cs, cn);
5799a747e4fSDavid du Colombier 			chanprint(cs->ctl, "%s image white", cn);
5809a747e4fSDavid du Colombier 			chanprint(cs->ctl, "%s bordercolor white", cn);
5812ebbfa15SDavid du Colombier 			chanprint(cs->ctl, "%s add '%s'", cn, a->name);
5829a747e4fSDavid du Colombier 		}
5839a747e4fSDavid du Colombier 
5849a747e4fSDavid du Colombier 		snprint(cn, sizeof cn, "val_%d", i);
5859a747e4fSDavid du Colombier 		if(a->type == AttrQuery){
5869a747e4fSDavid du Colombier 			entry[i].val = createentry(cs, cn);
5879a747e4fSDavid du Colombier 			chanprint(cs->ctl, "%s image yellow", cn);
5889a747e4fSDavid du Colombier 			chanprint(cs->ctl, "%s border 1", cn);
5899a747e4fSDavid du Colombier 			if(a->name != nil){
5902ebbfa15SDavid du Colombier 				if(strcmp(a->name, "user") == 0)
5919a747e4fSDavid du Colombier 					chanprint(cs->ctl, "%s value %q", cn, getuser());
5922ebbfa15SDavid du Colombier 				if(*a->name == '!')
5939a747e4fSDavid du Colombier 					chanprint(cs->ctl, "%s font invisible", cn);
5949a747e4fSDavid du Colombier 			}
5959a747e4fSDavid du Colombier 		} else {
5969a747e4fSDavid du Colombier 			entry[i].val = createtext(cs, cn);
5979a747e4fSDavid du Colombier 			chanprint(cs->ctl, "%s image white", cn);
5982ebbfa15SDavid du Colombier 			chanprint(cs->ctl, "%s add %q", cn, a->val);
5999a747e4fSDavid du Colombier 		}
6009a747e4fSDavid du Colombier 
6019a747e4fSDavid du Colombier 		snprint(cn, sizeof cn, "eq_%d", i);
6029a747e4fSDavid du Colombier 		entry[i].eq = createtext(cs, cn);
6039a747e4fSDavid du Colombier 		chanprint(cs->ctl, "%s image white", cn);
6049a747e4fSDavid du Colombier 		chanprint(cs->ctl, "%s add ' = '", cn);
6059a747e4fSDavid du Colombier 	}
6069a747e4fSDavid du Colombier 
6079a747e4fSDavid du Colombier 	b_done = createtextbutton(cs, "b_done");
6089a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_done border 1");
6099a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_done align center");
6109a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_done text DONE");
611d9306527SDavid du Colombier 	chanprint(cs->ctl, "b_done image green");
612d9306527SDavid du Colombier 	chanprint(cs->ctl, "b_done light green");
6139a747e4fSDavid du Colombier 
6149a747e4fSDavid du Colombier 	/* wire controls for input */
6159a747e4fSDavid du Colombier 	c = chancreate(sizeof(char*), 0);
6169a747e4fSDavid du Colombier 	controlwire(b_done, "event", c);
6179a747e4fSDavid du Colombier 	for(i = 0; i < entries; i++)
6189a747e4fSDavid du Colombier 		if(entry[i].a->type == AttrQuery)
6199a747e4fSDavid du Colombier 			controlwire(entry[i].val, "event", c);
6209a747e4fSDavid du Colombier 
6219a747e4fSDavid du Colombier 	/* make the controls interactive */
6229a747e4fSDavid du Colombier 	activate(msg);
6239a747e4fSDavid du Colombier 	activate(b_done);
6249a747e4fSDavid du Colombier 	for(i = 0; i < entries; i++){
6259a747e4fSDavid du Colombier 		if(entry[i].a->type != AttrQuery)
6269a747e4fSDavid du Colombier 			continue;
6279a747e4fSDavid du Colombier 		if(entry[i].a->name == nil)
6289a747e4fSDavid du Colombier 			activate(entry[i].name);
6299a747e4fSDavid du Colombier 		activate(entry[i].val);
6309a747e4fSDavid du Colombier 	}
6319a747e4fSDavid du Colombier 
6329a747e4fSDavid du Colombier 	/* change the display */
6339a747e4fSDavid du Colombier 	r->rt->cs = cs;
6349a747e4fSDavid du Colombier 	unhide();
6359a747e4fSDavid du Colombier 	resizecontrolset(cs);
6369a747e4fSDavid du Colombier 
6379a747e4fSDavid du Colombier 	return c;
6389a747e4fSDavid du Colombier }
6399a747e4fSDavid du Colombier 
6409a747e4fSDavid du Colombier /*
6419a747e4fSDavid du Colombier  *  resize the controls for the confirmation window
6429a747e4fSDavid du Colombier  */
6439a747e4fSDavid du Colombier static void
resizeneedkey(Controlset * cs)6449a747e4fSDavid du Colombier resizeneedkey(Controlset *cs)
6459a747e4fSDavid du Colombier {
6469a747e4fSDavid du Colombier 	Rectangle r, mr;
6479a747e4fSDavid du Colombier 	int mid, i, n, lasty;
6489a747e4fSDavid du Colombier 
6499a747e4fSDavid du Colombier 	/* get usable window rectangle */
6509a747e4fSDavid du Colombier 	if(getwindow(display, Refnone) < 0)
6519a747e4fSDavid du Colombier 		ctlerror("resize failed: %r");
6529a747e4fSDavid du Colombier 	r = insetrect(screen->r, 10);
6539a747e4fSDavid du Colombier 
6549a747e4fSDavid du Colombier 	/* find largest name */
6559a747e4fSDavid du Colombier 	mid = 0;
6569a747e4fSDavid du Colombier 	for(i = 0; i < entries; i++){
6579a747e4fSDavid du Colombier 		if(entry[i].a->name == nil)
6589a747e4fSDavid du Colombier 			continue;
6592ebbfa15SDavid du Colombier 		n = strlen(entry[i].a->name);
6609a747e4fSDavid du Colombier 		if(n > mid)
6619a747e4fSDavid du Colombier 			mid = n;
6629a747e4fSDavid du Colombier 	}
6639a747e4fSDavid du Colombier 	mid = (mid+2) * font->height;
6649a747e4fSDavid du Colombier 
6659a747e4fSDavid du Colombier 	/* top line is the message */
6669a747e4fSDavid du Colombier 	mr = r;
6679a747e4fSDavid du Colombier 	mr.max.y = mr.min.y + 2*font->height + 2;
6689a747e4fSDavid du Colombier 	chanprint(cs->ctl, "msg rect %R\nmsg show", mr);
6699a747e4fSDavid du Colombier 
6709a747e4fSDavid du Colombier 	/* one line per attribute */
6719a747e4fSDavid du Colombier 	mr.min.x += 2*font->height;
6729a747e4fSDavid du Colombier 	lasty = mr.max.y;
6739a747e4fSDavid du Colombier 	for(i = 0; i < entries; i++){
6749a747e4fSDavid du Colombier 		r.min.x = mr.min.x;
6759a747e4fSDavid du Colombier 		r.min.y = lasty+2;
6769a747e4fSDavid du Colombier 		r.max.x = r.min.x + mid - 3*stringwidth(font, "=");
6779a747e4fSDavid du Colombier 		r.max.y = r.min.y + font->height;
6789a747e4fSDavid du Colombier 		chanprint(cs->ctl, "name_%d rect %R\nname_%d show", i, r, i);
6799a747e4fSDavid du Colombier 
6809a747e4fSDavid du Colombier 		r.min.x = r.max.x;
6819a747e4fSDavid du Colombier 		r.max.x = r.min.x + 3*stringwidth(font, "=");
6829a747e4fSDavid du Colombier 		chanprint(cs->ctl, "eq_%d rect %R\neq_%d show", i, r, i);
6839a747e4fSDavid du Colombier 
6849a747e4fSDavid du Colombier 		r.min.x = r.max.x;
6859a747e4fSDavid du Colombier 		r.max.x = mr.max.x;
6869a747e4fSDavid du Colombier 		if(Dx(r) > 32*font->height)
6879a747e4fSDavid du Colombier 			r.max.x = r.min.x + 32*font->height;
6889a747e4fSDavid du Colombier 		chanprint(cs->ctl, "val_%d rect %R\nval_%d show", i, r, i);
6899a747e4fSDavid du Colombier 		lasty = r.max.y;
6909a747e4fSDavid du Colombier 	}
6919a747e4fSDavid du Colombier 
6929a747e4fSDavid du Colombier 	/* done button */
6939a747e4fSDavid du Colombier 	mr.min.x -= 2*font->height;
6949a747e4fSDavid du Colombier 	r.min.x = mr.min.x + mid - 3*font->height;
6959a747e4fSDavid du Colombier 	r.min.y = lasty+10;
6969a747e4fSDavid du Colombier 	r.max.x = r.min.x + 6*font->height;
6979a747e4fSDavid du Colombier 	r.max.y = r.min.y + font->height + 2;
6989a747e4fSDavid du Colombier 	chanprint(cs->ctl, "b_done rect %R\nb_done show", r);
6999a747e4fSDavid du Colombier }
7009a747e4fSDavid du Colombier 
7019a747e4fSDavid du Colombier /*
7029a747e4fSDavid du Colombier  *  free the controls for the confirmation window
7039a747e4fSDavid du Colombier  */
7049a747e4fSDavid du Colombier static void
teardownneedkey(Request * r)7059a747e4fSDavid du Colombier teardownneedkey(Request *r)
7069a747e4fSDavid du Colombier {
7079a747e4fSDavid du Colombier 	Controlset *cs;
7089a747e4fSDavid du Colombier 
7099a747e4fSDavid du Colombier 	cs = r->rt->cs;
7109a747e4fSDavid du Colombier 	r->rt->cs = nil;
7119a747e4fSDavid du Colombier 	hide();
7129a747e4fSDavid du Colombier 	closecontrolset(cs);
7139a747e4fSDavid du Colombier 	closekmr();
7149a747e4fSDavid du Colombier 
7159a747e4fSDavid du Colombier 	if(entry != nil)
7169a747e4fSDavid du Colombier 		free(entry);
7179a747e4fSDavid du Colombier 	entry = nil;
7189a747e4fSDavid du Colombier }
7199a747e4fSDavid du Colombier 
7209a747e4fSDavid du Colombier static void
needkey(Request * r)7219a747e4fSDavid du Colombier needkey(Request *r)
7229a747e4fSDavid du Colombier {
7239a747e4fSDavid du Colombier 	Channel *c;
7249a747e4fSDavid du Colombier 	char *nam, *val;
7259a747e4fSDavid du Colombier 	int i, n;
7269a747e4fSDavid du Colombier 	int fd;
7279a747e4fSDavid du Colombier 	char *args[3];
7289a747e4fSDavid du Colombier 
7299a747e4fSDavid du Colombier 	/* set up the controls */
7309a747e4fSDavid du Colombier 	c = setupneedkey(r);
7319a747e4fSDavid du Colombier 	if(c == nil)
7329a747e4fSDavid du Colombier 		goto out;
7339a747e4fSDavid du Colombier 
7349a747e4fSDavid du Colombier 	/* wait for user to reply */
7359a747e4fSDavid du Colombier 	for(;;){
7369a747e4fSDavid du Colombier 		val = recvp(c);
7379a747e4fSDavid du Colombier 		n = tokenize(val, args, nelem(args));
738d9306527SDavid du Colombier 		if(n==3 && strcmp(args[1], "value")==0){	/* user hit 'enter' */
7399a747e4fSDavid du Colombier 			free(val);
7409a747e4fSDavid du Colombier 			break;
7419a747e4fSDavid du Colombier 		}
7429a747e4fSDavid du Colombier 		free(val);
7439a747e4fSDavid du Colombier 	}
7449a747e4fSDavid du Colombier 
7459a747e4fSDavid du Colombier 	/* get entry values */
7469a747e4fSDavid du Colombier 	for(i = 0; i < entries; i++){
7479a747e4fSDavid du Colombier 		if(entry[i].a->type != AttrQuery)
7489a747e4fSDavid du Colombier 			continue;
7499a747e4fSDavid du Colombier 
7509a747e4fSDavid du Colombier 		chanprint(r->rt->cs->ctl, "val_%d data", i);
7519a747e4fSDavid du Colombier 		val = recvp(entry[i].val->data);
7529a747e4fSDavid du Colombier 		if(entry[i].a->name == nil){
7539a747e4fSDavid du Colombier 			chanprint(r->rt->cs->ctl, "name_%d data", i);
7549a747e4fSDavid du Colombier 			nam = recvp(entry[i].name->data);
7559a747e4fSDavid du Colombier 			if(nam == nil || *nam == 0){
7569a747e4fSDavid du Colombier 				free(val);
7579a747e4fSDavid du Colombier 				continue;
7589a747e4fSDavid du Colombier 			}
7592ebbfa15SDavid du Colombier 			entry[i].a->val = estrdup(val);
7609a747e4fSDavid du Colombier 			free(val);
7612ebbfa15SDavid du Colombier 			entry[i].a->name = estrdup(nam);
7629a747e4fSDavid du Colombier 			free(nam);
7639a747e4fSDavid du Colombier 		} else {
7649a747e4fSDavid du Colombier 			if(val != nil){
7652ebbfa15SDavid du Colombier 				entry[i].a->val = estrdup(val);
7669a747e4fSDavid du Colombier 				free(val);
7679a747e4fSDavid du Colombier 			}
7689a747e4fSDavid du Colombier 		}
7699a747e4fSDavid du Colombier 		entry[i].a->type = AttrNameval;
7709a747e4fSDavid du Colombier 	}
7719a747e4fSDavid du Colombier 
7729a747e4fSDavid du Colombier 	/* enter the new key !!!!need to do something in case of error!!!! */
7739a747e4fSDavid du Colombier 	fd = open("/mnt/factotum/ctl", OWRITE);
7749a747e4fSDavid du Colombier 	fprint(fd, "key %A", r->a);
7759a747e4fSDavid du Colombier 	close(fd);
7769a747e4fSDavid du Colombier 
7779a747e4fSDavid du Colombier 	teardownneedkey(r);
7789a747e4fSDavid du Colombier out:
7799a747e4fSDavid du Colombier 	fprint(r->rt->fd, "%A", r->tag);
7809a747e4fSDavid du Colombier }
781