]> git.decadent.org.uk Git - ap-utils.git/blob - lib/input.c
b966f12558d5c303a803101723e544ad83510cdb
[ap-utils.git] / lib / input.c
1 /*
2  *      input.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  * Copyright (c) 2005 Jan Rafaj <jr-aputils at cedric dot unob dot cz>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License Version 2 from
10  * June 1991 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  */
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <menu.h>
27 #include <errno.h>
28 #include "ap-utils.h"
29
30 extern WINDOW *main_sub, *win_for_help;
31
32 #define GEN_IV_MSG _("Invalid value. Press any key to continue.")
33 #define OOR_IV_MSG _("Value must be in range %u - %u. Press any key to continue.")
34
35 #define MAC_LEN 12
36 #define MAC_BYTES 6
37
38 void
39 get_mac(char *mac, int row, int col)
40 {
41     char message[MAC_LEN+1], mess[MAC_LEN/MAC_BYTES+1];
42     int i;
43
44     message[0] = '\0';
45     while (strlen(message) != 12)
46         get_value(message, row, col, MAC_LEN+1, HEX_STRING, 0, 0, NULL);
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;
81
82 get_mask_again:
83     trans_count = 0;
84     get_ip(ip, row, col, helpmsg);
85     hmask = ntohl(ip->s_addr);
86     bit = hmask & 0x00000001;
87     for (i = 1; i < 32; i++)
88         if (((hmask >> i) & 0x00000001) != bit) {
89             bit ^= 0x00000001;
90             trans_count++;
91         }
92
93     if (trans_count > 1) {
94         print_helperr(GEN_IV_MSG);
95         getch();
96         print_help(helpmsg);
97         goto get_mask_again;
98     }
99 }
100
101 /*
102  * This is the main input function for all cases when user needs to enter
103  * a visible string. It also performs syntax correctness checks
104  * as well as bounds checks if required.
105  *
106  * value ....... this should keep the value, entered by the user,
107  *               in ascii string notation
108  * row
109  * col ......... the begin coordinates, relative to the current window,
110  *               at which the string entered by the user will appear
111  * len ......... maximum length of the entered string, including the
112  *               tailing '\0' character. Negative value along with
113  *               vt=ANY_STRING means that zero-length string is allowed.
114  * vt .......... desired input value type (types INT_STRING, HEX_STRING,
115  *               ANY_STRING)
116  * minv, maxv .. min/max bounds in case of integer value input. Each can be
117  *               of value 0-0xFFFFFFFF. If both are 0, it means no value bounds
118  *               checking will be performed. Used only with vt=INT_STRING.
119  * helpmsg ..... pointer to string that will be printed after OOR_IV_MSG
120  *               message if the entered integer value is out of range.
121  *               If NULL, then no 'invalid value' and subsequent status line
122  *               message will be printed, and whole input process will be
123  *               repeated. Used only with vt=INT_STRING.
124  */
125 void
126 get_value(char *value, int row, int col, int len,
127           char vt, unsigned int minv, unsigned int maxv, char *helpmsg)
128 {
129     int c, i, x, y;
130     unsigned char acs;
131     char iv_msg[128], zerolen_perm = 0;
132     enum { INSERT, OVERWRITE } mode;
133     WINDOW *gv_win;
134
135     if (vt == ANY_STRING && len < 0) {
136         zerolen_perm = 1;
137         len = -len;
138     }
139
140     gv_win = derwin(main_sub, 1, len - 1, row, col);
141     wbkgdset(gv_win, A_REVERSE);
142
143 get_value_again:
144     mode = INSERT;
145     curs_set(1);
146     werase(gv_win);
147     wrefresh(gv_win);
148
149     i = 0; /* means 'character count' here */
150     while (1) {
151         c = getch();
152         acs = 0;
153         switch (vt) {
154             case INT_STRING:
155                 if (c >= '0' && c <= '9') acs = 1;
156                 break;
157             case HEX_STRING:
158                 if ((c >= '0' && c <= '9') ||
159                     (c >= 'a' && c <= 'f') ||
160                     (c >= 'A' && c <= 'F')) acs = 1;
161                 break;
162             case ANY_STRING:
163                 acs = 1;
164         }
165         /* rather do not ask, how this works... */
166         getyx(gv_win, y, x);
167         switch (c) {
168             case KEY_BACKSPACE:
169                 /* lefthandside DELETE */
170                 if (x > 0) {
171                     /*
172                      * do not step cursor back only if window is filled AND
173                      * cursor is totally on RHS
174                      */
175                     if ((i < len - 1) || (x < len - 2))
176                         x--;
177                     mvwdelch(gv_win, 0, x);
178                     wrefresh(gv_win);
179                     i--;
180                 }
181                 break;
182             case KEY_DC:
183                 /* righthandside DELETE */
184                 if (i > 0) {
185                     if (x == i)
186                         x--;
187                     mvwdelch(gv_win, 0, x);
188                     wrefresh(gv_win);
189                     i--;
190                 }
191                 break;
192             case KEY_LEFT:
193                 if (x > 0) {
194                     wmove(gv_win, 0, --x);
195                     wrefresh(gv_win);
196                 }
197                 break;
198             case KEY_RIGHT:
199                 if (x < i) {
200                     wmove(gv_win, 0, ++x);
201                     wrefresh(gv_win);
202                 }
203                 break;
204             case KEY_HOME:
205                 wmove(gv_win, 0, 0);
206                 wrefresh(gv_win);
207                 break;
208             case KEY_END:
209                 wmove(gv_win, 0, (i == len - 1 ? i - 1 : i));
210                 wrefresh(gv_win);
211                 break;
212             case KEY_IC:
213                 mode = (mode == INSERT ? OVERWRITE : INSERT);
214                 curs_set(mode == INSERT ? 1 : 2);
215                 break;
216             case 0x0A:
217                 /* ENTER KEY */
218                 if (i > 0 || zerolen_perm)
219                     goto away;
220
221                 break;
222             default:
223                 if (acs && (c < 0x100)) {
224                     if (mode == INSERT) {
225                         if (i < len - 1) {
226                             winsch(gv_win, c);
227                             i++;
228                             wmove(gv_win, 0, ++x);
229                             wrefresh(gv_win);
230                         }
231                     } else {
232                         if (i <= len - 1) {
233 //                          wechochar(gv_win, c);
234                             waddch(gv_win, c);
235                             if (x == i)
236                                 i++;
237                             wmove(gv_win, 0, ++x);
238                             wrefresh(gv_win);
239                         }
240                     }
241                 }
242         }
243     }
244
245 away:
246     wmove(gv_win, 0, 0);
247     winnstr(gv_win, value, i);
248     value[i] = 0;
249     curs_set(0);
250
251     if (vt == INT_STRING) {
252         i = strtoul(value, (char **)NULL, 10);
253         sprintf(value, "%i", i); /* eat leading zeros */
254         if (minv | maxv) {
255             errno = 0;
256             if ((unsigned)i < minv || (unsigned)i > maxv || errno == ERANGE) {
257                 if (helpmsg) {
258                     snprintf(iv_msg, sizeof(iv_msg) -1, OOR_IV_MSG, minv, maxv);
259                     print_helperr(iv_msg);
260                     getch();
261                     print_help(helpmsg);
262                 }
263                 goto get_value_again;
264             }
265         }
266     }
267
268     wbkgdset(gv_win, A_BOLD);
269     werase(gv_win);
270     waddstr(gv_win, value);
271     wrefresh(gv_win);
272 //    mvwprintw(main_sub, 18, 1, "length: %i", i);
273 //    wrefresh(main_sub);
274     delwin(gv_win);
275 }
276
277 /*
278  * Note: indeed we should use get_value() for this action, but for the moment,
279  * we'll settle with this one.
280  */
281
282 void
283 get_pass(char *value, int row, int col, int len)
284 {
285     int i, j = 0;
286
287     wattrset(main_sub, COLOR_PAIR(12));
288     wmove(main_sub, row, col);
289     for (i = 0; i < len - 1; i++)
290         waddch(main_sub, ' ');
291     curs_set(1);
292
293     while (1) {
294         value[j] = mvwgetch(main_sub, row, col + j);
295         if (value[j] == 0x0A) /* NEWLINE */
296             break;
297         if (value[j] == 0x1B) /* ESCAPE */
298             continue;
299         if (value[j] != 0x7F) { /* BACKSPACE */
300             if (j < len - 1)
301                 mvwaddch(main_sub, row, col + j++, '*');
302         } else {
303             if (j)
304                 mvwaddch(main_sub, row, col + --j, ' ');
305         }
306     };
307     value[j] = '\0';
308
309     curs_set(0);
310     wattrset(main_sub, A_BOLD);
311     wmove(main_sub, row, col);
312     for (i = 0; i < len - 1; i++)
313         waddch(main_sub, ' ');
314     wmove(main_sub, row, col);
315     for (i = 0; i < j; i++)
316         waddch(main_sub, '*');
317     wattrset(main_sub, A_NORMAL);
318     wrefresh(main_sub);
319 }
320
321 int
322 yes_no(int brow, int bcol)
323 {
324     char *names[2] = { YES, NO };
325
326     return menu_choose(brow, bcol, names, 2) + 1;
327 }
328
329 int
330 on_off(int brow, int bcol)
331 {
332     char *names[2] = { ON, OFF };
333
334     return menu_choose(brow, bcol, names, 2) + 1;
335 }
336
337 int menu_choose(int brow, int bcol, char **names, unsigned int num)
338 {
339     unsigned short int c;
340     ITEM **menu_item = calloc(num, sizeof(ITEM)), **ip = menu_item;
341     MENU *menu1;
342     unsigned int ncol = 2, i, nrow;
343     WINDOW *choose_menu, *sub_choose_menu;
344     extern WINDOW *main_sub;
345
346     for (i = 0; i < num; i++) {
347         *ip++ = new_item(names[i], "");
348         if (ncol < strlen(names[i]) + 3)
349             ncol = strlen(names[i]) + 3;
350     }
351     *ip = (ITEM *) 0;
352
353
354     nrow = num + 2;
355     if (brow + 2 + nrow <= (unsigned int) LINES - 2)
356         choose_menu = newwin(nrow, ncol, brow + 2, bcol + MCOLS);
357     else
358         choose_menu = newwin(nrow, ncol, brow - nrow + 3, bcol + MCOLS);
359     sub_choose_menu = derwin(choose_menu, nrow - 2, ncol - 2, 1, 1);
360     attrset(COLOR_PAIR(11));
361
362     mvwaddch(choose_menu, 0, 0, ACS_ULCORNER);
363     mvwaddch(choose_menu, 0, ncol - 1, ACS_URCORNER);
364     mvwaddch(choose_menu, nrow - 1, 0, ACS_LLCORNER);
365     mvwaddch(choose_menu, nrow - 1, ncol - 1, ACS_LRCORNER);
366     for (i = 1; i < ncol - 1; i++) {
367         mvwaddch(choose_menu, 0, i, ACS_HLINE);
368         mvwaddch(choose_menu, nrow - 1, i, ACS_HLINE);
369     }
370     for (i = 1; i < nrow - 1; i++) {
371         mvwaddch(choose_menu, i, 0, ACS_VLINE);
372         mvwaddch(choose_menu, i, ncol - 1, ACS_VLINE);
373     }
374     wrefresh(choose_menu);
375
376
377     menu1 = new_menu(menu_item);
378     set_menu_win(menu1, choose_menu);
379     set_menu_sub(menu1, sub_choose_menu);
380
381     set_menu_opts(menu1, O_ONEVALUE);
382
383     curs_set(0);
384     post_menu(menu1);
385     wrefresh(sub_choose_menu);
386
387     while (1) {
388         switch (getch()) {
389         case KEY_DOWN:
390         case 'j':
391         case 'J':
392             menu_driver(menu1, REQ_NEXT_ITEM);
393             wrefresh(sub_choose_menu);
394             break;
395         case KEY_RIGHT:
396         case 'l':
397         case 'L':
398             menu_driver(menu1, REQ_LAST_ITEM);
399             wrefresh(sub_choose_menu);
400             break;
401         case KEY_LEFT:
402         case 'h':
403         case 'H':
404             menu_driver(menu1, REQ_FIRST_ITEM);
405             wrefresh(sub_choose_menu);
406             break;
407         case KEY_UP:
408         case 'k':
409         case 'K':
410             menu_driver(menu1, REQ_PREV_ITEM);
411             wrefresh(sub_choose_menu);
412             break;
413         case 10:
414             i = item_index(current_item(menu1));
415             unpost_menu(menu1);
416             free_menu(menu1);
417             for (c = 0; c < nrow - 2; c++)
418                 free_item(menu_item[c]);
419             delwin(sub_choose_menu);
420             delwin(choose_menu);
421             redrawwin(main_sub);
422             free(menu_item);
423             return i;
424
425         }
426     }
427 }
428
429 /*
430  * Reads key by either no-delay getch() (WAIT_FOREVER mode) or using
431  * getch() with tval tenths of second timeout (WAIT_TIMEOUT mode).
432  * Returns 0 for timeout, or pressed key code.
433  */
434 int wait_key(int tval)
435 {
436     int i;
437     extern int wait_mode;
438
439     if (wait_mode == WAIT_TIMEOUT)
440         timeout(tval * 100);
441
442     i = getch();
443
444     if (wait_mode == WAIT_TIMEOUT) {
445         timeout(-1);
446 //      nocbreak();
447 //      cbreak();
448     }
449
450     if (i == ERR)
451         i = 0;
452
453     return i;
454 }
455
456 int help_ysn()
457 {
458     char c;
459
460     print_help (_("Y - Yes; Any other key - No (it's safer to answer No)"));
461     c = getch();
462     clear_main(0);
463     if (c == 'y' || c == 'Y')
464         return 0;
465
466     return 1;
467 }
468