1 /**************************************************************************
2  **
3  ** sngrep - SIP Messages flow viewer
4  **
5  ** Copyright (C) 2013-2018 Ivan Alonso (Kaian)
6  ** Copyright (C) 2013-2018 Irontec SL. All rights reserved.
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 as published by
10  ** the Free Software Foundation, either version 3 of the License, or
11  ** (at your option) any later version.
12  **
13  ** This program is distributed in the hope that it will be useful,
14  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  ** GNU General Public License for more details.
17  **
18  ** You should have received a copy of the GNU General Public License
19  ** along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  **
21  ****************************************************************************/
22 /**
23  * @file group.c
24  * @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
25  *
26  * @brief Source code of functions defined in keybinding.h
27  *
28  */
29 
30 #include "config.h"
31 #include <ctype.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include "setting.h"
35 #include "keybinding.h"
36 #include "curses/ui_manager.h"
37 
38 //! sngrep keybindings
39 key_binding_t bindings[ACTION_SENTINEL] = {
40    { ACTION_PRINTABLE,      "",             { }, 0 },
41    { ACTION_UP,             "up",           { KEY_UP, 'k' }, 2 },
42    { ACTION_DOWN,           "down",         { KEY_DOWN, 'j' }, 2 },
43    { ACTION_LEFT,           "left",         { KEY_LEFT, 'h' }, 2 },
44    { ACTION_RIGHT,          "right",        { KEY_RIGHT, 'l'}, 2 },
45    { ACTION_DELETE,         "delete",       { KEY_DC }, 1 },
46    { ACTION_BACKSPACE,      "backspace",    { KEY_BACKSPACE, KEY_BACKSPACE2, KEY_BACKSPACE3 }, 3 },
47    { ACTION_NPAGE,          "npage",        { KEY_NPAGE, KEY_CTRL('F') }, 2 },
48    { ACTION_PPAGE,          "ppage",        { KEY_PPAGE, KEY_CTRL('B') }, 2 },
49    { ACTION_HNPAGE,         "hnpage",       { KEY_CTRL('D') }, 1 },
50    { ACTION_HPPAGE,         "hppage",       { KEY_CTRL('U') }, 2 },
51    { ACTION_BEGIN,          "begin",        { KEY_HOME, KEY_CTRL('A') }, 2 },
52    { ACTION_END,            "end",          { KEY_END, KEY_CTRL('E') }, 2 },
53    { ACTION_PREV_FIELD,     "pfield",       { KEY_UP }, 1 },
54    { ACTION_NEXT_FIELD,     "nfield",       { KEY_DOWN, KEY_TAB }, 2 },
55    { ACTION_RESIZE_SCREEN,  "",             { KEY_RESIZE }, 1 },
56    { ACTION_CLEAR,          "clear",        { KEY_CTRL('U'), KEY_CTRL('W')}, 2 },
57    { ACTION_CLEAR_CALLS,    "clearcalls",   { KEY_F(5), KEY_CTRL('L')}, 2 },
58    { ACTION_CLEAR_CALLS_SOFT, "clearcallssoft", {KEY_F(9)}, 2 },
59    { ACTION_TOGGLE_SYNTAX,  "togglesyntax", { KEY_F(8), 'C' }, 2 },
60    { ACTION_CYCLE_COLOR,    "colormode",    { 'c' }, 1 },
61    { ACTION_COMPRESS,       "compress",     { 's' }, 1 },
62    { ACTION_SHOW_ALIAS,     "togglealias",  { 'a' }, 1 },
63    { ACTION_TOGGLE_PAUSE,   "pause",        { 'p' }, 1 },
64    { ACTION_PREV_SCREEN,    "prevscreen",   { KEY_ESC, 'q', 'Q' }, 3 },
65    { ACTION_SHOW_HELP,      "help",         { KEY_F(1), 'h', 'H', '?' }, 4 },
66    { ACTION_SHOW_RAW,       "raw",          { KEY_F(6), 'R', 'r' }, 3 },
67    { ACTION_SHOW_FLOW,      "flow",         { KEY_INTRO }, 1 },
68    { ACTION_SHOW_FLOW_EX,   "flowex",       { KEY_F(4), 'x' }, 2 },
69    { ACTION_SHOW_FILTERS,   "filters",      { KEY_F(7), 'f', 'F' }, 3 },
70    { ACTION_SHOW_COLUMNS,   "columns",      { KEY_F(10), 't', 'T' }, 3 },
71    { ACTION_SHOW_SETTINGS,  "settings",     { KEY_F(8), 'o', 'O' }, 3 },
72    { ACTION_SHOW_STATS,     "stats",        { 'i' }, 1 },
73    { ACTION_COLUMN_MOVE_UP, "columnup",     { '-' }, 1 },
74    { ACTION_COLUMN_MOVE_DOWN, "columndown", { '+' }, 1 },
75    { ACTION_SDP_INFO,       "sdpinfo",      { KEY_F(2), 'd' }, 2 },
76    { ACTION_DISP_FILTER,    "search",       { KEY_F(3), '/', KEY_TAB }, 3 },
77    { ACTION_SAVE,           "save",         { KEY_F(2), 's', 'S'}, 3 },
78    { ACTION_SELECT,         "select",       { KEY_SPACE }, 1 },
79    { ACTION_CONFIRM,        "confirm",      { KEY_INTRO }, 1 },
80    { ACTION_TOGGLE_MEDIA,   "togglemedia",  { KEY_F(3), 'm' }, 2 },
81    { ACTION_ONLY_MEDIA,     "onlymedia",    { 'M' }, 1 },
82    { ACTION_TOGGLE_RAW,     "rawpreview",   { 't' }, 1 },
83    { ACTION_INCREASE_RAW,   "morerawpreview", { '9' }, 1 },
84    { ACTION_DECREASE_RAW,   "lessrawpreview", { '0' }, 1 },
85    { ACTION_RESET_RAW,      "resetrawpreview", { 'T' }, 1 },
86    { ACTION_ONLY_SDP,       "onlysdp",      { 'D' }, 1 },
87    { ACTION_AUTOSCROLL,     "autoscroll",   { 'A' }, 1 },
88    { ACTION_TOGGLE_HINT,    "hintalt",      { 'K' }, 1 },
89    { ACTION_SORT_PREV,      "sortprev",     { '<' }, 1 },
90    { ACTION_SORT_NEXT,      "sortnext",     { '>' }, 1 },
91    { ACTION_SORT_SWAP,      "sortswap",     { 'z' }, 1 },
92    { ACTION_TOGGLE_TIME,    "toggletime",   { 'w' }, 1 },
93 };
94 
95 void
key_bindings_dump()96 key_bindings_dump()
97 {
98     int i, j;
99     for (i = 1; i < ACTION_SENTINEL; i++) {
100         for (j = 0; j < bindings[i].bindcnt; j++) {
101             printf("ActionID: %d\t ActionName: %-21s Key: %d (%s)\n",
102                    bindings[i].id,
103                    bindings[i].name,
104                    bindings[i].keys[j],
105                    key_to_str(bindings[i].keys[j]));
106         }
107     }
108 }
109 
110 key_binding_t *
key_binding_data(int action)111 key_binding_data(int action)
112 {
113     int i;
114     for (i = 1; i < ACTION_SENTINEL; i++) {
115         if (bindings[i].id == action)
116             return &bindings[i];
117     }
118 
119     return NULL;
120 }
121 
122 void
key_bind_action(int action,int key)123 key_bind_action(int action, int key)
124 {
125     key_binding_t *bind;
126 
127     if (!(bind = key_binding_data(action)))
128         return;
129 
130     if (bind->bindcnt == MAX_BINDINGS)
131         return;
132 
133     bind->keys[bind->bindcnt++] = key;
134 }
135 
136 void
key_unbind_action(int action,int key)137 key_unbind_action(int action, int key)
138 {
139     key_binding_t tmp, *bind;
140     int i;
141 
142     // Action is not valid
143     if (!(bind = key_binding_data(action)))
144         return;
145 
146     // Copy binding to temporal struct
147     memcpy(&tmp, bind, sizeof(key_binding_t));
148 
149     // Reset bindings for this action
150     memset(&bind->keys, 0, sizeof(int) * MAX_BINDINGS);
151 
152     // Add all bindings but the unbinded
153     for (i=0; i < tmp.bindcnt; i++) {
154         if (tmp.keys[i] != key) {
155             key_bind_action(action, tmp.keys[i]);
156         }
157     }
158 }
159 
160 int
key_find_action(int key,int start)161 key_find_action(int key, int start)
162 {
163     int i, j;
164     for (i = start + 1; i < ACTION_SENTINEL; i++) {
165 
166         if (i == ACTION_PRINTABLE && key_is_printable(key))
167             return ACTION_PRINTABLE;
168 
169         for (j = 0; j < bindings[i].bindcnt; j++)
170             if (bindings[i].keys[j] == key)
171                 return bindings[i].id;
172     }
173     return -1;
174 }
175 
176 int
key_action_id(const char * action)177 key_action_id(const char *action)
178 {
179     int i;
180     for (i = 1; i < ACTION_SENTINEL; i++) {
181         if (!strcasecmp(action, bindings[i].name))
182             return bindings[i].id;
183 
184     }
185     return -1;
186 }
187 
188 int
key_is_printable(int key)189 key_is_printable(int key)
190 {
191     return key == ' ' || (key > 33 && key < 126) || (key > 160 && key < 255);
192 }
193 
194 const char *
key_to_str(int key)195 key_to_str(int key)
196 {
197     //! Check function keys and Special keys
198     switch(key) {
199         case KEY_F(1):
200             return "F1";
201         case KEY_F(2):
202             return "F2";
203         case KEY_F(3):
204             return "F3";
205         case KEY_F(4):
206             return "F4";
207         case KEY_F(5):
208             return "F5";
209         case KEY_F(6):
210             return "F6";
211         case KEY_F(7):
212             return "F7";
213         case KEY_F(8):
214             return "F8";
215         case KEY_F(9):
216             return "F9";
217         case KEY_F(10):
218             return "F10";
219         case KEY_ESC:
220             return "Esc";
221         case KEY_INTRO:
222             return "Enter";
223         case ' ':
224             return "Space";
225         default:
226             if (key_is_printable(key))
227                 return keyname(key);
228     }
229 
230     return "";
231 }
232 
233 int
key_from_str(const char * key)234 key_from_str(const char *key)
235 {
236     if (!key)
237         return 0;
238 
239     // Single character string
240     if (strlen(key) == 1)
241         return *key;
242 
243     // Function keys
244     if (*key == 'F')
245         return KEY_F(atoi(key+1));
246 
247     // Control Secuences
248     if (*key == '^')
249         return KEY_CTRL(toupper(*(key+1)));
250     if (!strncasecmp(key, "Ctrl-", 5))
251         return KEY_CTRL(toupper(*(key+5)));
252 
253     // Special Name characters
254     if (!strcasecmp(key, "Esc"))
255         return KEY_ESC;
256     if (!strcasecmp(key, "Space"))
257         return ' ';
258     if (!strcasecmp(key, "Enter"))
259         return KEY_INTRO;
260 
261     return 0;
262 }
263 
264 const char *
key_action_key_str(int action)265 key_action_key_str(int action)
266 {
267     key_binding_t *bind;
268 
269     if (!(bind = key_binding_data(action)))
270         return NULL;
271 
272     if (setting_enabled(SETTING_ALTKEY_HINT) && bind->bindcnt > 1) {
273         // First alt keybinding
274         return key_to_str(bind->keys[1]);
275     } else {
276         // Default keybinding
277         return key_to_str(bind->keys[0]);
278     }
279 }
280 
281 int
key_action_key(int action)282 key_action_key(int action)
283 {
284     key_binding_t *bind;
285 
286     if (!(bind = key_binding_data(action)))
287         return -1;
288 
289     if (setting_enabled(SETTING_ALTKEY_HINT) && bind->bindcnt > 1) {
290         // First alt keybinding
291         return bind->keys[1];
292     } else {
293         // Default keybinding
294         return bind->keys[0];
295     }
296 
297     return -1;
298 }
299