]> git.neil.brown.name Git - edlib.git/blob - lib-askpass.c
TODO: clean out done items.
[edlib.git] / lib-askpass.c
1 /*
2  * Copyright Neil Brown ©2023 <neil@brown.name>
3  * May be distributed under terms of GPLv2 - see file:COPYING
4  *
5  * askpass - ask for a password.
6  * This doesn't yet have any focus on protecting the password
7  * from being swapped out.
8  *
9  * We place a popup in mid-display with a message and
10  * "HEAVY BALLOT X" for each character typed.
11  */
12
13 #include <unistd.h>
14 #include <memory.h>
15
16 #define PANE_DATA_TYPE struct apinfo
17 #include "core.h"
18
19 struct apinfo {
20         char *msg safe;
21         struct buf b;
22         struct command *c;
23 };
24 #include "core-pane.h"
25
26 static struct map *askpass_map;
27 DEF_LOOKUP_CMD(askpass_handle, askpass_map);
28
29 DEF_CMD(askpass_refresh_view)
30 {
31         struct buf b;
32         struct apinfo *ai = ci->home->data;
33         int shift = 0;
34         int i;
35
36         buf_init(&b);
37         buf_concat(&b, ai->msg);
38         for (i = 0; i < utf8_strlen(buf_final(&ai->b)); i++)
39                 buf_append(&b, 0x2718); /* HEAVY BALLOT X */
40         call("render-line:set", ci->focus, b.len, NULL, buf_final(&b));
41         for (i = 0; i < 10; i++) {
42                 int cw;
43                 attr_set_int(&ci->focus->attrs, "render-wrap", shift);
44                 call("render-line:measure", ci->focus, b.len);
45                 cw = pane_attr_get_int(ci->focus, "curs_width", 1);
46                 if (ci->home->parent->cx < ci->home->parent->w - cw)
47                         break;
48                 shift += 8 * cw;
49         }
50         free(buf_final(&b));
51         return 1;
52 }
53
54 DEF_CMD(askpass_key)
55 {
56         const char *k = ksuffix(ci, "K-");
57         struct apinfo *ai = ci->home->data;
58
59         buf_concat(&ai->b, k);
60         pane_damaged(ci->home, DAMAGED_VIEW);
61         return 1;
62 }
63
64 DEF_CMD(askpass_bs)
65 {
66         struct apinfo *ai = ci->home->data;
67
68         if (ai->b.len > 0)
69                 ai->b.len = utf8_round_len(ai->b.b, ai->b.len-1);
70         pane_damaged(ci->home, DAMAGED_VIEW);
71         return 1;
72 }
73
74 DEF_CMD(askpass_ignore)
75 {
76         return 1;
77 }
78
79 DEF_CMD(askpass_done)
80 {
81         struct apinfo *ai = ci->home->data;
82
83         comm_call(ai->c, "cb", ci->focus, ai->b.len, NULL,
84                   buf_final(&ai->b));
85         memset(ai->b.b, 0, ai->b.size);
86         call("popup:close", ci->focus);
87         return 1;
88 }
89
90 DEF_CMD(askpass_abort)
91 {
92         struct apinfo *ai = ci->home->data;
93
94         memset(ai->b.b, 0, ai->b.size);
95         comm_call(ai->c, "cb", ci->focus, -1);
96         call("popup:close", ci->focus);
97         return 1;
98 }
99
100 DEF_CMD(askpass_attach)
101 {
102         struct pane *p, *p2;
103
104         if (!ci->str || !ci->comm2)
105                 return Enoarg;
106         p = call_ret(pane, "PopupTile", ci->focus, 0, NULL, "D2");
107         if (!p)
108                 return Efail;
109         p2  = call_ret(pane, "attach-view", p);
110         if (!p2)
111                 goto fail;
112         p = p2;
113
114         p2 = call_ret(pane, "attach-renderline", p);
115         if (!p2)
116                 goto fail;
117         p = p2;
118
119         p2 = pane_register(p, 0, &askpass_handle.c);
120         if (!p2)
121                 goto fail;
122         p = p2;
123
124         attr_set_str(&p->attrs, "pane-title", "Ask Password");
125
126         p->data->msg = strdup(ci->str);
127         p->data->c = command_get(ci->comm2);
128         buf_init(&p->data->b);
129         pane_damaged(p, DAMAGED_VIEW);
130         return 1;
131
132 fail:
133         if (ci->focus->focus)
134                 pane_close(ci->focus->focus);
135         return Efail;
136 }
137
138 DEF_CMD_CLOSED(askpass_close)
139 {
140         struct apinfo *ai = ci->home->data;
141
142         free(ai->msg);
143         ai->msg = safe_cast NULL;
144         free(buf_final(&ai->b));
145         ai->b.b = safe_cast NULL;
146         command_put(ai->c);
147         ai->c = NULL;
148         return 1;
149 }
150
151 void edlib_init(struct pane *ed safe)
152 {
153         call_comm("global-set-command", ed, &askpass_attach,
154                   0, NULL, "AskPass");
155
156         askpass_map = key_alloc();
157         key_add(askpass_map, "Close", &askpass_close);
158         key_add_prefix(askpass_map, "K-", &askpass_key);
159         key_add_prefix(askpass_map, "K:", &askpass_ignore);
160         key_add_prefix(askpass_map, "M:", &askpass_ignore);
161         key_add(askpass_map, "K:Enter", &askpass_done);
162         key_add(askpass_map, "K:Backspace", &askpass_bs);
163         key_add(askpass_map, "K:ESC", &askpass_abort);
164         key_add(askpass_map, "K:C-C", &askpass_abort);
165         key_add(askpass_map, "K:C-G", &askpass_abort);
166         key_add_prefix(askpass_map, "Refresh:view", &askpass_refresh_view);
167 }