]> git.decadent.org.uk Git - ap-utils.git/blob - lib/input.c
Imported Upstream version 1.5~pre1
[ap-utils.git] / lib / input.c
1 /*
2  *      scr.c from Access Point SNMP Utils for Linux
3  *      program input & screen related functions
4  *
5  * Copyright (c) 2002 Roman Festchook <roma at polesye dot net>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License Version 2 from
9  * June 1991 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/time.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <menu.h>
28 #include <errno.h>
29 #include "ap-utils.h"
30
31 extern WINDOW *main_sub, *win_for_help;
32
33 #define GEN_IV_MSG _("Invalid value. Press any key to continue.")
34 #define OOR_IV_MSG _("Value must be in range %u - %u. Press any key to continue.")
35
36 #define MAC_LEN 12
37 #define MAC_BYTES 6
38
39 void
40 get_mac(char *mac, int row, int col)
41 {
42     char message[MAC_LEN+1], mess[MAC_LEN/MAC_BYTES+1];
43     int i;
44
45     get_value(message, row, col, MAC_LEN+1, HEX_STRING, 0, 0, NULL);
46     if (strlen(message) < 12) i = 255;
47
48     for (i = 0; i < MAC_BYTES; i++) {
49         mess[0] = message[2 * i];
50         mess[1] = message[2 * i + 1];
51         mess[2] = '\0';
52         mac[i] = strtol(mess, NULL, 16);
53     }
54 }
55
56 #define IP_LEN 15
57
58 void
59 get_ip(struct in_addr *ip, int row, int col, char *helpmsg)
60 {
61     char message[IP_LEN+1], *cp;
62     int dotc;
63
64 get_ip_again:
65     get_value(message, row, col, IP_LEN+1, ANY_STRING, 0, 0, NULL);
66     for (cp = message, dotc = 0; *cp && (cp = index(cp, '.')); cp++, dotc++);
67     if (dotc < 3 || !(inet_aton(message, ip))) {
68         if (helpmsg) {
69             print_helperr(GEN_IV_MSG);
70             getch();
71             print_help(helpmsg);
72         }
73         goto get_ip_again;
74     }
75 }
76
77 void
78 get_mask(struct in_addr *ip, int row, int col, char *helpmsg)
79 {
80     int i, bit, hmask, trans_count = 0;
81
82 get_mask_again:
83     get_ip(ip, row, col, helpmsg);
84     hmask = ntohl(ip->s_addr);
85     bit = hmask & 0x00000001;
86     for (i = 1; i < 32; i++)
87         if (((hmask >> i) & 0x00000001) != bit) {
88             bit ^= 0x00000001;
89             trans_count++;
90         }
91
92     if (trans_count > 1) {
93         print_helperr(GEN_IV_MSG);
94         getch();
95         print_help(helpmsg);
96         goto get_mask_again;
97     }
98 }
99
100 /*
101  * This is the main input function for all cases when user needs to enter
102  * a visible string. It also performs syntax correctness checks
103  * as well as bounds checks if required.
104  *
105  * value ....... this should keep the value, entered by the user,
106  *               in ascii string notation
107  * row
108  * col ......... the begin coordinates, relative to the current window,
109  *               at which the string entered by the user will appear
110  * len ......... maximum length of the entered string, including the
111  *               tailing '\0' character. Negative value along with
112  *               vt=ANY_STRING means that zero-length string is allowed.
113  * vt .......... desired input value type (types INT_STRING, HEX_STRING,
114  *               ANY_STRING)
115  * minv, maxv .. min/max bounds in case of integer value input. Each can be
116  *               of value 0-0xFFFFFFFF. If both are 0, it means no value bounds
117  *               checking will be performed. Used only with vt=INT_STRING.
118  * helpmsg ..... pointer to string that will be printed after OOR_IV_MSG
119  *               message if the entered integer value is out of range.
120  *               If NULL, then no 'invalid value' and subsequent status line
121  *               message will be printed, and whole input process will be
122  *               repeated. Used only with vt=INT_STRING.
123  */
124 void
125 get_value(char *value, int row, int col, int len,
126           char vt, unsigned int minv, unsigned int maxv, char *helpmsg)
127 {
128     unsigned int i;
129     unsigned char c, acs;
130     char iv_msg[128], zerolen_perm = 0;
131
132     if (vt == ANY_STRING && len < 0) {
133         zerolen_perm = 1;
134         len = -len;
135     }
136
137     echo();
138     wattrset(main_sub, COLOR_PAIR(2));
139 get_value_again:
140     wmove(main_sub, row, col);
141     for (i = 0; i < (unsigned int)len - 1; i++)
142         waddch(main_sub, ' ');
143     curs_set(1);
144     wmove(main_sub, row, col);
145     wrefresh(main_sub);
146
147     i = 0;
148     while (1) {
149         c = getchar();
150         acs = 0;
151         switch (vt) {
152             case INT_STRING:
153                 if (c >= '0' && c <= '9') acs = 1;
154                 break;
155             case HEX_STRING:
156                 if ((c >= '0' && c <= '9') ||
157                     (c >= 'a' && c <= 'f') ||
158                     (c >= 'A' && c <= 'F')) acs = 1;
159                 break;
160             case ANY_STRING:
161                 acs = 1;
162         }
163         if (c == 0x7F) {
164             /* DELETE KEY */
165             if (i > 0) {
166                 value[i--] = 0;
167                 wmove(main_sub, row, col + i);
168                 waddch(main_sub, ' ');
169                 /* put backspace to move cursor back */
170                 wechochar(main_sub, 0x08);
171             }
172             continue;
173         } else if (c == 0x0D) {
174             /* ENTER KEY */
175             if (i > 0 || zerolen_perm)
176                 break;
177             continue;
178         } else if (c == 0x1B) {
179             /* ESCAPE KEY */
180             continue;
181         } else if (acs && (i < (unsigned int)len - 1)) {
182             value[i++] = c;
183             wechochar(main_sub, c);
184         }
185     }
186     value[i] = 0;
187
188     noecho();
189     if (vt == INT_STRING && (minv | maxv)) {
190         errno = 0;
191         i = strtoul(value, (char **)NULL, 10);
192         if (i < minv || i > maxv || errno == ERANGE) {
193             if (helpmsg) {
194                 snprintf(iv_msg, sizeof(iv_msg) - 1, OOR_IV_MSG, minv, maxv);
195                 print_helperr(iv_msg);
196                 getch();
197                 print_help(helpmsg);
198             }
199             goto get_value_again;
200         }
201     }
202
203     curs_set(0);
204     wattrset(main_sub, A_BOLD);
205     wmove(main_sub, row, col);
206     for (i = 0; i < (unsigned int)len - 1; i++)
207         waddch(main_sub, ' ');
208     mvwaddstr(main_sub, row, col, value);
209     wattrset(main_sub, A_NORMAL);
210     wrefresh(main_sub);
211 }
212
213 /*
214  * Note: indeed we should use get_value() for this action, but for the moment,
215  * we'll settle with this one.
216  */
217
218 void
219 get_pass(char *value, int row, int col, int len)
220 {
221     int i, j = 0;
222
223     wattrset(main_sub, COLOR_PAIR(2));
224     wmove(main_sub, row, col);
225     for (i = 0; i < len - 1; i++)
226         waddch(main_sub, ' ');
227     curs_set(1);
228
229     while (1) {
230         value[j] = mvwgetch(main_sub, row, col + j);
231         if (value[j] == 0x0A) /* NEWLINE */
232             break;
233         if (value[j] == 0x1B) /* ESCAPE */
234             continue;
235         if (value[j] != 0x7F) { /* BACKSPACE */
236             if (j < len - 1)
237                 mvwaddch(main_sub, row, col + j++, '*');
238         } else {
239             if (j)
240                 mvwaddch(main_sub, row, col + --j, ' ');
241         }
242     };
243     value[j] = '\0';
244
245     curs_set(0);
246     wattrset(main_sub, A_BOLD);
247     wmove(main_sub, row, col);
248     for (i = 0; i < len - 1; i++)
249         waddch(main_sub, ' ');
250     wmove(main_sub, row, col);
251     for (i = 0; i < j; i++)
252         waddch(main_sub, '*');
253     wattrset(main_sub, A_NORMAL);
254     wrefresh(main_sub);
255 }
256
257 int
258 yes_no(int brow, int bcol)
259 {
260     char *names[2] = { YES, NO };
261
262     return menu_choose(brow, bcol, names, 2) + 1;
263 }
264
265 int
266 on_off(int brow, int bcol)
267 {
268     char *names[2] = { ON, OFF };
269
270     return menu_choose(brow, bcol, names, 2) + 1;
271 }
272
273 int menu_choose(int brow, int bcol, char **names, unsigned int num)
274 {
275     unsigned short int c;
276     ITEM **menu_item = calloc(num, sizeof(ITEM)), **ip = menu_item;
277     MENU *menu1;
278     unsigned int ncol = 2, i, nrow;
279     WINDOW *choose_menu, *sub_choose_menu;
280     extern WINDOW *main_sub;
281
282     for (i = 0; i < num; i++) {
283         *ip++ = new_item(names[i], "");
284         if (ncol < strlen(names[i]) + 3)
285             ncol = strlen(names[i]) + 3;
286     }
287     *ip = (ITEM *) 0;
288
289
290     nrow = num + 2;
291     if (brow + 2 + nrow <= (unsigned int) LINES - 2)
292         choose_menu = newwin(nrow, ncol, brow + 2, bcol + MCOLS);
293     else
294         choose_menu = newwin(nrow, ncol, brow - nrow + 3, bcol + MCOLS);
295     sub_choose_menu = derwin(choose_menu, nrow - 2, ncol - 2, 1, 1);
296     attrset(COLOR_PAIR(1));
297
298     mvwaddch(choose_menu, 0, 0, ACS_ULCORNER);
299     mvwaddch(choose_menu, 0, ncol - 1, ACS_URCORNER);
300     mvwaddch(choose_menu, nrow - 1, 0, ACS_LLCORNER);
301     mvwaddch(choose_menu, nrow - 1, ncol - 1, ACS_LRCORNER);
302     for (i = 1; i < ncol - 1; i++) {
303         mvwaddch(choose_menu, 0, i, ACS_HLINE);
304         mvwaddch(choose_menu, nrow - 1, i, ACS_HLINE);
305     }
306     for (i = 1; i < nrow - 1; i++) {
307         mvwaddch(choose_menu, i, 0, ACS_VLINE);
308         mvwaddch(choose_menu, i, ncol - 1, ACS_VLINE);
309     }
310     wrefresh(choose_menu);
311
312
313     menu1 = new_menu(menu_item);
314     set_menu_win(menu1, choose_menu);
315     set_menu_sub(menu1, sub_choose_menu);
316
317     set_menu_opts(menu1, O_ONEVALUE);
318
319     curs_set(0);
320     post_menu(menu1);
321     wrefresh(sub_choose_menu);
322
323     while (1) {
324         switch (getch()) {
325         case KEY_DOWN:
326         case 'j':
327         case 'J':
328             menu_driver(menu1, REQ_NEXT_ITEM);
329             wrefresh(sub_choose_menu);
330             break;
331         case KEY_RIGHT:
332         case 'l':
333         case 'L':
334             menu_driver(menu1, REQ_LAST_ITEM);
335             wrefresh(sub_choose_menu);
336             break;
337         case KEY_LEFT:
338         case 'h':
339         case 'H':
340             menu_driver(menu1, REQ_FIRST_ITEM);
341             wrefresh(sub_choose_menu);
342             break;
343         case KEY_UP:
344         case 'k':
345         case 'K':
346             menu_driver(menu1, REQ_PREV_ITEM);
347             wrefresh(sub_choose_menu);
348             break;
349         case 10:
350             i = item_index(current_item(menu1));
351             unpost_menu(menu1);
352             free_menu(menu1);
353             for (c = 0; c < nrow - 2; c++)
354                 free_item(menu_item[c]);
355             delwin(sub_choose_menu);
356             delwin(choose_menu);
357             redrawwin(main_sub);
358             free(menu_item);
359             return i;
360
361         }
362     }
363 }
364
365 /*
366  * Reads key by either getch() (WAIT_FOREVER mode) or select()
367  * (WAIT_TIMEOUT mode). Returns -1 upon error, 0 for timeout, or
368  * pressed key code.
369  */
370 int wait_key()
371 {
372     int i = 0;
373     fd_set rds;
374     struct timeval timeout;
375     extern int wait_mode;
376
377     timeout.tv_sec = 1;
378     timeout.tv_usec = 0;
379     FD_ZERO(&rds);
380     FD_SET(0, &rds);
381
382     if (wait_mode == WAIT_TIMEOUT) {
383         /*
384          * wait up to timeout until anything is avail. for reading
385          * on stdin
386          */
387         i = select(1, &rds, NULL, NULL, &timeout);
388
389         /* not timed out => anything avail. for reading in rds */
390         if (i > 0)
391             i = getc(stdin);
392
393         /* error occured */
394         if (i == -1) {
395             print_helperr(SELECT);
396             getch();
397         }
398
399         /* also happens: i = 0 => timeout => release */
400
401     } else { /* wait_mode = WAIT_FOREVER */
402         i = getch();
403     }
404
405     return i;
406 }
407
408 int help_ysn()
409 {
410     char c;
411
412     print_help (_("Y - Yes; Any other key - No (it's safer to answer No)"));
413     c = getch();
414     clear_main(0);
415     if (c == 'y' || c == 'Y')
416         return 0;
417
418     return 1;
419 }
420