capt_get_packet(): check for key press only every 20ms
[iptraf-ng.git] / src / landesc.c
blobd51c09418bed504fa881a3a5c3074dcf6b1df6d7
1 /* For terms of usage/redistribution/modification see the LICENSE file */
2 /* For authors and contributors see the AUTHORS file */
4 /***
6 landesc.c - LAN host description management module
7 Currently includes support for Ethernet, PLIP,
8 and FDDI
10 ***/
12 #include "iptraf-ng-compat.h"
14 #include "tui/input.h"
15 #include "tui/listbox.h"
16 #include "tui/msgboxes.h"
17 #include "tui/menurt.h"
19 #include "landesc.h"
20 #include "deskman.h"
21 #include "attrs.h"
22 #include "dirs.h"
24 static int check_mac_addr(const char *mac)
26 if (strlen(mac) != 17)
27 return 0;
29 char a[3], b[3], c[3], d[3], e[3], f[3];
31 int success = sscanf(mac, "%02s:%02s:%02s:%02s:%02s:%02s",
32 a, b, c, d, e, f);
34 if (success != 6)
35 return 0;
37 char mac_hex[13];
39 sprintf(mac_hex, "%s%s%s%s%s%s", a, b, c, d, e, f);
41 for (int ii = 0; ii < 12; ++ii)
42 if (!isxdigit(mac_hex[ii]))
43 return 0;
45 return 1;
48 /* parse and insert unique eth description.
49 * caller is responsible for freeing whole list
51 static void parse_eth_desc(FILE * fp, struct eth_desc *hd)
53 char *l = NULL;
54 size_t len = 0;
55 ssize_t read;
57 while ((read = getline(&l, &len, fp)) != -1) {
58 if (l[0] == '\n' || l[0] == '#')
59 continue;
61 char *line = l;
63 if (strchr(line, '\n'))
64 strchr(line, '\n')[0] = '\0';
65 char mac[18] = { 0 };
66 strncpy(mac, line, 17);
68 if (!check_mac_addr(mac)) {
69 tui_error(ANYKEY_MSG, "Not a mac '%s' address, skipped",
70 mac);
71 continue;
74 /* skip mac address */
75 line += 17;
77 /* mandatory space between mac and ip */
78 if (!isspace(*line)) {
79 tui_error(ANYKEY_MSG,
80 "Missing mandatory space between"
81 "mac and host/ip address, skipped");
82 continue;
85 line = skip_whitespace(line);
87 if (!*line) {
88 tui_error(ANYKEY_MSG, "Missing description, skipped");
89 continue;
92 struct eth_desc *new = xmalloc(sizeof(struct eth_desc));
94 memcpy(new->hd_mac, mac, sizeof(mac));
95 new->hd_desc = xstrdup(line);
97 struct eth_desc *desc = NULL;
99 list_for_each_entry(desc, &hd->hd_list, hd_list)
100 if ((strcmp(desc->hd_mac, mac) == 0)
101 || (strcmp(desc->hd_desc, line) == 0))
102 goto dupe;
104 list_add_tail(&new->hd_list, &hd->hd_list);
105 dupe:;
108 free(l);
111 struct eth_desc *load_eth_desc(unsigned link_type)
113 /* why is usefull to have it two files with same content?
114 * There is two options how to merge it.
115 * 1) separate by comments
116 * $ cat ETHFILE
117 * # ethernet host description
118 * MAC ip/hostname
120 * # fddi host description
121 * MAC ip/hostname
122 * 2) put it into groups
123 * [ethernet]
124 * MAC ip/hostname
126 * [fddi]
127 * MAC ip/hostname
129 char *filename = NULL;
130 FILE *fp = NULL;
132 if (link_type == ARPHRD_ETHER)
133 filename = ETHFILE;
134 else if (link_type == ARPHRD_FDDI)
135 filename = FDDIFILE;
137 struct eth_desc *hd = xmallocz(sizeof(struct eth_desc));
139 INIT_LIST_HEAD(&hd->hd_list);
141 fp = fopen(filename, "r");
142 if (fp) {
143 parse_eth_desc(fp, hd);
144 fclose(fp);
147 /* merge with /etc/ethers */
148 fp = fopen("/etc/ethers", "r");
149 if (fp) {
150 parse_eth_desc(fp, hd);
151 fclose(fp);
154 return hd;
157 static void save_eth_desc(struct eth_desc *hd, unsigned linktype)
159 FILE *fd = NULL;
161 if (linktype == ARPHRD_ETHER)
162 fd = fopen(ETHFILE, "w");
163 else if (linktype == ARPHRD_FDDI)
164 fd = fopen(FDDIFILE, "w");
166 if (!fd) {
167 tui_error(ANYKEY_MSG, "Unable to save host description file");
168 return;
171 fprintf(fd, "# see man ethers for syntax\n\n");
172 struct eth_desc *desc = NULL;
174 list_for_each_entry(desc, &hd->hd_list, hd_list)
175 fprintf(fd, "%s %s\n", desc->hd_mac, desc->hd_desc);
177 fclose(fd);
181 void free_eth_desc(struct eth_desc *hd)
183 struct eth_desc *entry = NULL;
184 struct list_head *l, *n;
186 list_for_each_safe(l, n, &hd->hd_list) {
187 entry = list_entry(l, struct eth_desc, hd_list);
189 free(entry->hd_desc);
190 list_del(l);
191 free(entry);
195 static struct eth_desc *select_eth_desc(const struct eth_desc *hd)
198 struct scroll_list slist;
199 char descline[80];
201 if (list_empty(&hd->hd_list)) {
202 tui_error(ANYKEY_MSG, "No descriptions");
203 return NULL;
206 tx_init_listbox(&slist, COLS, 20, 0, (LINES - 20) / 2, STDATTR, BOXATTR,
207 BARSTDATTR, HIGHATTR);
209 tx_set_listbox_title(&slist, "Address", 1);
210 tx_set_listbox_title(&slist, "Description", 19);
212 struct eth_desc *entry = NULL;
214 list_for_each_entry(entry, &hd->hd_list, hd_list) {
215 snprintf(descline, 80, "%-18s%s", entry->hd_mac,
216 entry->hd_desc);
217 tx_add_list_entry(&slist, (char *) entry, descline);
220 tx_show_listbox(&slist);
222 int aborted = 0;
224 tx_operate_listbox(&slist, &aborted);
226 if (!aborted)
227 entry = (struct eth_desc *) slist.textptr->nodeptr;
228 else
229 entry = NULL;
231 tx_close_listbox(&slist);
232 tx_destroy_list(&slist);
234 update_panels();
235 doupdate();
237 return entry;
240 static int dialog_eth_desc(struct FIELDLIST *fields, const char *initaddr,
241 const char *initdesc)
243 /* TODO: move to tui */
244 WINDOW *win = newwin(8, 70, 8, (COLS - 70) / 2);
245 PANEL *panel = new_panel(win);
247 wattrset(win, DLGBOXATTR);
248 tx_colorwin(win);
249 tx_box(win, ACS_VLINE, ACS_HLINE);
250 wmove(win, 6, 2 * COLS / 80);
251 tabkeyhelp(win);
252 wmove(win, 6, 20 * COLS / 80);
253 stdkeyhelp(win);
255 wattrset(win, DLGTEXTATTR);
256 mvwprintw(win, 2, 2 * COLS / 80, "MAC Address:");
257 mvwprintw(win, 4, 2 * COLS / 80, "Description:");
259 tx_initfields(fields, 3, 52, 10, (COLS - 52) / 2 + 6 * COLS / 80,
260 DLGTEXTATTR, FIELDATTR);
261 tx_addfield(fields, 17, 0, 0, initaddr);
262 tx_addfield(fields, 50, 2, 0, initdesc);
264 int aborted = 0;
266 tx_fillfields(fields, &aborted);
268 del_panel(panel);
269 delwin(win);
271 return aborted;
274 static void add_eth_desc(struct eth_desc *list)
276 struct FIELDLIST fields;
278 int aborted = dialog_eth_desc(&fields, "", "");
280 if (!aborted) {
281 struct eth_desc *new = xmalloc(sizeof(struct eth_desc));
283 memcpy(new->hd_mac, fields.list->buf, sizeof(new->hd_mac));
284 new->hd_desc = xstrdup(fields.list->nextfield->buf);
286 list_add_tail(&new->hd_list, &list->hd_list);
289 tx_destroyfields(&fields);
290 update_panels();
291 doupdate();
294 static void edit_eth_desc(struct eth_desc *list)
296 struct eth_desc *hd = select_eth_desc(list);
298 if (!hd)
299 return;
301 struct FIELDLIST fields;
302 int aborted = dialog_eth_desc(&fields, hd->hd_mac, hd->hd_desc);
304 if (!aborted) {
305 free(hd->hd_desc);
306 memcpy(hd->hd_mac, fields.list->buf, sizeof(hd->hd_mac));
307 hd->hd_desc = xstrdup(fields.list->nextfield->buf);
310 tx_destroyfields(&fields);
313 static void del_eth_desc(struct eth_desc *list)
315 struct eth_desc *hd = select_eth_desc(list);
317 if (hd) {
318 free(hd->hd_desc);
319 list_del(&hd->hd_list);
320 free(hd);
324 void manage_eth_desc(unsigned linktype)
326 struct MENU menu;
327 int row = 1;
328 int aborted = 0;
330 tx_initmenu(&menu, 7, 31, (LINES - 6) / 2, (COLS - 31) / 2, BOXATTR,
331 STDATTR, HIGHATTR, BARSTDATTR, BARHIGHATTR, DESCATTR);
332 tx_additem(&menu, " ^A^dd description...",
333 "Adds a description for a MAC address");
334 tx_additem(&menu, " ^E^dit description...",
335 "Modifies an existing MAC address description");
336 tx_additem(&menu, " ^D^elete description...",
337 "Deletes an existing MAC address description");
338 tx_additem(&menu, NULL, NULL);
339 tx_additem(&menu, " E^x^it menu", "Returns to the main menu");
341 struct eth_desc *list =
342 load_eth_desc(linktype /*, WITHOUTETCETHERS */ );
344 do {
345 tx_showmenu(&menu);
346 tx_operatemenu(&menu, &row, &aborted);
348 switch (row) {
349 case 1:
350 add_eth_desc(list);
351 break;
352 case 2:
353 edit_eth_desc(list);
354 break;
355 case 3:
356 del_eth_desc(list);
357 break;
359 } while (row != 5);
361 tx_destroymenu(&menu);
362 update_panels();
363 doupdate();
364 save_eth_desc(list, linktype);