forked from Mirrors/sngrep
Implemented a filter UI for Call list
This commit is contained in:
parent
6cab1f10f6
commit
d798d9ab4b
|
@ -1,2 +1,2 @@
|
|||
sysconfdir = @sysconfdir@
|
||||
sysconfdir=@sysconfdir@
|
||||
sysconf_DATA=sngreprc
|
||||
|
|
|
@ -4133,8 +4133,8 @@ fi
|
|||
|
||||
|
||||
if test "$enable_debug" = "yes" ; then
|
||||
CFLAGS="$CFLAGS -g -O0 -Wall -Werror -Wno-uninitialized"
|
||||
CXXFLAGS="$CXXFLAGS -g -O0 -Wall -Werror -Wno-uninitialized"
|
||||
CFLAGS="$CFLAGS -g -O0 -Wall -Werror -Wno-unused-but-set-variable"
|
||||
CXXFLAGS="$CXXFLAGS $CFLAGS"
|
||||
fi
|
||||
|
||||
# Minimum checks for a C program :)
|
||||
|
@ -5411,7 +5411,57 @@ _ACEOF
|
|||
|
||||
else
|
||||
|
||||
as_fn_error $? " You need to have libpanel installed to compile sngrep." "$LINENO" 5
|
||||
as_fn_error $? " You need to have ncurses panel library installed to compile sngrep." "$LINENO" 5
|
||||
|
||||
fi
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for new_form in -lform" >&5
|
||||
$as_echo_n "checking for new_form in -lform... " >&6; }
|
||||
if ${ac_cv_lib_form_new_form+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lform $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char new_form ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return new_form ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_form_new_form=yes
|
||||
else
|
||||
ac_cv_lib_form_new_form=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_form_new_form" >&5
|
||||
$as_echo "$ac_cv_lib_form_new_form" >&6; }
|
||||
if test "x$ac_cv_lib_form_new_form" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_LIBFORM 1
|
||||
_ACEOF
|
||||
|
||||
LIBS="-lform $LIBS"
|
||||
|
||||
else
|
||||
|
||||
as_fn_error $? " You need to have ncurses forms library installed to compile sngrep." "$LINENO" 5
|
||||
|
||||
fi
|
||||
|
||||
|
|
10
configure.ac
10
configure.ac
|
@ -14,8 +14,8 @@ AC_ARG_ENABLE(debug,
|
|||
enable_debug=$enableval, enable_debug=no)
|
||||
|
||||
if test "$enable_debug" = "yes" ; then
|
||||
CFLAGS="$CFLAGS -g -O0 -Wall -Werror -Wno-uninitialized"
|
||||
CXXFLAGS="$CXXFLAGS -g -O0 -Wall -Werror -Wno-uninitialized"
|
||||
CFLAGS="$CFLAGS -g -O0 -Wall -Werror -Wno-unused-but-set-variable"
|
||||
CXXFLAGS="$CXXFLAGS $CFLAGS"
|
||||
fi
|
||||
|
||||
# Minimum checks for a C program :)
|
||||
|
@ -54,7 +54,11 @@ AC_CHECK_LIB([ncurses], [initscr], [], [
|
|||
])
|
||||
|
||||
AC_CHECK_LIB([panel], [new_panel], [], [
|
||||
AC_MSG_ERROR([ You need to have libpanel installed to compile sngrep.])
|
||||
AC_MSG_ERROR([ You need to have ncurses panel library installed to compile sngrep.])
|
||||
])
|
||||
|
||||
AC_CHECK_LIB([form], [new_form], [], [
|
||||
AC_MSG_ERROR([ You need to have ncurses forms library installed to compile sngrep.])
|
||||
])
|
||||
|
||||
AC_CHECK_LIB([pthread], [pthread_create], [], [
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
bin_PROGRAMS=sngrep
|
||||
sngrep_SOURCES=exec.c spcap.c sip.c main.c option.c group.c ui_manager.c ui_call_list.c ui_call_flow.c ui_call_raw.c
|
||||
sngrep_SOURCES=exec.c spcap.c sip.c main.c option.c group.c ui_manager.c ui_call_list.c ui_call_flow.c ui_call_raw.c ui_filter.c
|
||||
|
|
|
@ -64,7 +64,8 @@ PROGRAMS = $(bin_PROGRAMS)
|
|||
am_sngrep_OBJECTS = exec.$(OBJEXT) spcap.$(OBJEXT) sip.$(OBJEXT) \
|
||||
main.$(OBJEXT) option.$(OBJEXT) group.$(OBJEXT) \
|
||||
ui_manager.$(OBJEXT) ui_call_list.$(OBJEXT) \
|
||||
ui_call_flow.$(OBJEXT) ui_call_raw.$(OBJEXT)
|
||||
ui_call_flow.$(OBJEXT) ui_call_raw.$(OBJEXT) \
|
||||
ui_filter.$(OBJEXT)
|
||||
sngrep_OBJECTS = $(am_sngrep_OBJECTS)
|
||||
sngrep_LDADD = $(LDADD)
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@
|
||||
|
@ -191,7 +192,7 @@ target_alias = @target_alias@
|
|||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
sngrep_SOURCES = exec.c spcap.c sip.c main.c option.c group.c ui_manager.c ui_call_list.c ui_call_flow.c ui_call_raw.c
|
||||
sngrep_SOURCES = exec.c spcap.c sip.c main.c option.c group.c ui_manager.c ui_call_list.c ui_call_flow.c ui_call_raw.c ui_filter.c
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
|
@ -285,6 +286,7 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui_call_flow.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui_call_list.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui_call_raw.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui_filter.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui_manager.Po@am__quote@
|
||||
|
||||
.c.o:
|
||||
|
|
|
@ -72,7 +72,7 @@ int
|
|||
main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
int ret;
|
||||
int ret = 0;
|
||||
//! ngrep thread attributes
|
||||
pthread_attr_t attr;
|
||||
//! ngrep running thread
|
||||
|
|
18
src/option.c
18
src/option.c
|
@ -75,6 +75,20 @@ init_options()
|
|||
// Allow dialogs to be incomplete
|
||||
set_option_value("sip.ignoreincomlete", "0");
|
||||
|
||||
// Toggle capture
|
||||
set_option_value("sip.capture", "on");
|
||||
|
||||
// Set default filter options
|
||||
set_option_value("filter.enable", "off");
|
||||
set_option_value("filter.REGISTER", "on");
|
||||
set_option_value("filter.INVITE", "on");
|
||||
set_option_value("filter.INVITE (SDP)", "on");
|
||||
set_option_value("filter.SUBSCRIBE", "on");
|
||||
set_option_value("filter.NOTIFY", "on");
|
||||
set_option_value("filter.OPTIONS", "on");
|
||||
set_option_value("filter.PUBLISH", "on");
|
||||
set_option_value("filter.MESSAGE", "on");
|
||||
|
||||
// Read options from configuration files
|
||||
read_options("/etc/sngreprc");
|
||||
read_options("/usr/local/etc/sngreprc");
|
||||
|
@ -150,12 +164,12 @@ set_option_value(const char *opt, const char *value)
|
|||
if (!get_option_value(opt)) {
|
||||
options[optscnt].type = SETTING;
|
||||
options[optscnt].opt = opt;
|
||||
options[optscnt].value = value;
|
||||
options[optscnt].value = strdup(value);
|
||||
optscnt++;
|
||||
} else {
|
||||
for (i = 0; i < optscnt; i++) {
|
||||
if (!strcasecmp(opt, options[i].opt)) {
|
||||
options[i].value = value;
|
||||
options[i].value = strdup(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
39
src/sip.c
39
src/sip.c
|
@ -176,6 +176,11 @@ sip_load_message(const char *header, const char *payload)
|
|||
sip_call_t *call;
|
||||
char *callid;
|
||||
|
||||
// Skip messages if capture is disabled
|
||||
if (!is_option_enabled("sip.capture")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get the Call-ID of this message
|
||||
if (!(callid = sip_get_callid(payload))) {
|
||||
return NULL;
|
||||
|
@ -235,11 +240,45 @@ int
|
|||
sip_check_call_ignore(sip_call_t *call)
|
||||
{
|
||||
int i;
|
||||
char filter_option[80];
|
||||
const char *filter;
|
||||
// Check if an ignore option exists
|
||||
for (i = 0; i < sizeof(attrs) / sizeof(*attrs); i++) {
|
||||
if (is_ignored_value(attrs[i].name, call_get_attribute(call, attrs[i].id))) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Check enabled filters
|
||||
if (is_option_enabled("filter.enable")) {
|
||||
if ((filter = get_option_value("filter.sipfrom")) && strlen(filter)) {
|
||||
if(strstr(call_get_attribute(call, SIP_ATTR_SIPFROM), filter) == NULL) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if ((filter = get_option_value("filter.sipto")) && strlen(filter)) {
|
||||
if(strstr(call_get_attribute(call, SIP_ATTR_SIPTO), filter) == NULL) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if ((filter = get_option_value("filter.src")) && strlen(filter)) {
|
||||
if(strncasecmp(filter, call_get_attribute(call, SIP_ATTR_SRC), strlen(filter))) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if ((filter = get_option_value("filter.dst")) && strlen(filter)) {
|
||||
if (strncasecmp(filter, call_get_attribute(call, SIP_ATTR_DST), strlen(filter))) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a filter option exists
|
||||
memset(filter_option, 0, sizeof(filter_option));
|
||||
sprintf(filter_option, "filter.%s", call_get_attribute(call, SIP_ATTR_STARTING));
|
||||
if (!is_option_enabled(filter_option)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -435,7 +435,7 @@ call_flow_handle_key(PANEL *panel, int key)
|
|||
wait_for_input(next_panel);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
return key;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -132,7 +132,7 @@ call_flow_draw_raw(PANEL *panel, sip_msg_t *msg);
|
|||
*
|
||||
* @param panel Ncurses panel pointer
|
||||
* @param key Pressed keycode
|
||||
* @return 0 if the function can handle the key, -1 otherwise
|
||||
* @return 0 if the function can handle the key, key otherwise
|
||||
*/
|
||||
extern int
|
||||
call_flow_handle_key(PANEL *panel, int key);
|
||||
|
|
|
@ -94,10 +94,9 @@ call_list_create()
|
|||
mvwaddch(win, 7, width - 1, ACS_RTEE);
|
||||
mvwprintw(win, height - 2, 2, "Q/Esc: Quit");
|
||||
mvwprintw(win, height - 2, 16, "F1: Help");
|
||||
mvwprintw(win, height - 2, 27, "x: Call-Flow Extended");
|
||||
mvwprintw(win, height - 2, 52, "r: Call Raw");
|
||||
mvwprintw(win, height - 2, 67, "c: Colours");
|
||||
mvwprintw(win, height - 2, 80, "Space: Select dialog");
|
||||
mvwprintw(win, height - 2, 27, "Enter/x: Call-Flow");
|
||||
mvwprintw(win, height - 2, 48, "p: pause capture");
|
||||
mvwprintw(win, height - 2, 67, "Space: Select dialog");
|
||||
|
||||
// Draw columns titles
|
||||
for (colpos = 6, i = 0; i < info->columncnt; i++) {
|
||||
|
@ -147,6 +146,13 @@ call_list_draw(PANEL *panel)
|
|||
call_list_info_t *info = (call_list_info_t*) panel_userptr(panel);
|
||||
if (!info) return -1;
|
||||
|
||||
// Get window of call list panel
|
||||
WINDOW *win = panel_window(panel);
|
||||
getmaxyx(win, height, width);
|
||||
|
||||
// Print in the header if we're actually capturing
|
||||
mvwprintw(win, 3, 23, "%s", is_option_enabled("sip.capture")?" ":"(Paused)");
|
||||
|
||||
// Get available calls counter (we'll use it here a couple of times)
|
||||
if (!(callcnt = sip_calls_count())) return 0;
|
||||
|
||||
|
@ -156,10 +162,6 @@ call_list_draw(PANEL *panel)
|
|||
info->cur_line = info->first_line = 1;
|
||||
}
|
||||
|
||||
// Get window of call list panel
|
||||
WINDOW *win = panel_window(panel);
|
||||
getmaxyx(win, height, width);
|
||||
|
||||
// Fill the call list
|
||||
int cline = startline;
|
||||
for (call = info->first_call; call; call = call_get_next(call)) {
|
||||
|
@ -303,7 +305,7 @@ call_list_handle_key(PANEL *panel, int key)
|
|||
break;
|
||||
case 'r':
|
||||
case 'R':
|
||||
// KEY_X , Display current call flow (extended)
|
||||
// KEY_R , Display current call flow (extended)
|
||||
next_panel = ui_create(ui_find_by_type(RAW_PANEL));
|
||||
if (info->group->callcnt) {
|
||||
group = info->group;
|
||||
|
@ -315,6 +317,13 @@ call_list_handle_key(PANEL *panel, int key)
|
|||
call_raw_set_group(group);
|
||||
wait_for_input(next_panel);
|
||||
break;
|
||||
case 'f':
|
||||
case 'F':
|
||||
// KEY_F, Display filter panel
|
||||
next_panel = ui_create(ui_find_by_type(FILTER_PANEL));
|
||||
wait_for_input(next_panel);
|
||||
call_list_filter_update(panel);
|
||||
break;
|
||||
case ' ':
|
||||
if (!info->cur_call) return -1;
|
||||
if (call_group_exists(info->group, info->cur_call)) {
|
||||
|
@ -331,7 +340,7 @@ call_list_handle_key(PANEL *panel, int key)
|
|||
}
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
return key;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -344,7 +353,7 @@ call_list_help(PANEL *panel)
|
|||
PANEL *help_panel;
|
||||
|
||||
// Create a new panel and show centered
|
||||
help_win = newwin(20, 65, (LINES - 20) / 2, (COLS - 65) / 2);
|
||||
help_win = newwin(21, 65, (LINES - 21) / 2, (COLS - 65) / 2);
|
||||
help_panel = new_panel(help_win);
|
||||
|
||||
// Set the window title
|
||||
|
@ -355,16 +364,16 @@ call_list_help(PANEL *panel)
|
|||
box(help_win, 0, 0);
|
||||
mvwhline(help_win, 2, 1, ACS_HLINE, 63);
|
||||
mvwhline(help_win, 7, 1, ACS_HLINE, 63);
|
||||
mvwhline(help_win, 17, 1, ACS_HLINE, 63);
|
||||
mvwhline(help_win, 18, 1, ACS_HLINE, 63);
|
||||
mvwaddch(help_win, 2, 0, ACS_LTEE);
|
||||
mvwaddch(help_win, 7, 0, ACS_LTEE);
|
||||
mvwaddch(help_win, 17, 0, ACS_LTEE);
|
||||
mvwaddch(help_win, 18, 0, ACS_LTEE);
|
||||
mvwaddch(help_win, 2, 64, ACS_RTEE);
|
||||
mvwaddch(help_win, 7, 64, ACS_RTEE);
|
||||
mvwaddch(help_win, 17, 64, ACS_RTEE);
|
||||
mvwaddch(help_win, 18, 64, ACS_RTEE);
|
||||
|
||||
// Set the window footer (nice blue?)
|
||||
mvwprintw(help_win, 18, 20, "Press any key to continue");
|
||||
mvwprintw(help_win, 19, 20, "Press any key to continue");
|
||||
|
||||
// Some brief explanation abotu what window shows
|
||||
wattron(help_win, COLOR_PAIR(HELP_COLOR));
|
||||
|
@ -383,6 +392,7 @@ call_list_help(PANEL *panel)
|
|||
mvwprintw(help_win, 14, 2, "Enter Show selected call-flow.");
|
||||
mvwprintw(help_win, 15, 2, "x Show selected call-flow (Extended) if available.");
|
||||
mvwprintw(help_win, 16, 2, "r Show selected call messages in raw mode.");
|
||||
mvwprintw(help_win, 17, 2, "p Pause. Stop capturing packages");
|
||||
|
||||
// Press any key to close
|
||||
wgetch(help_win);
|
||||
|
@ -448,9 +458,9 @@ call_list_exit_confirm(PANEL *panel)
|
|||
exit = (exit)?0:1;
|
||||
break;
|
||||
case 10:
|
||||
// If we return 1, we let ui_manager to handle this
|
||||
// If we return ESC, we let ui_manager to handle this
|
||||
// key and exit sngrep gracefully
|
||||
return exit;
|
||||
return (exit)?27:0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -471,3 +481,33 @@ call_list_add_column(PANEL *panel, enum sip_attr_id id, const char* attr, const
|
|||
info->columncnt++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
call_list_filter_update(PANEL *panel)
|
||||
{
|
||||
|
||||
WINDOW *win = panel_window(panel);
|
||||
int height, width, i, startline = 8;
|
||||
|
||||
// Get panel info
|
||||
call_list_info_t *info = (call_list_info_t*) panel_userptr(panel);
|
||||
if (!info) return;
|
||||
|
||||
// Initialize structures
|
||||
info->first_call = info->cur_call = NULL;
|
||||
info->first_line = info->cur_line = 0;
|
||||
info->group->callcnt = 0;
|
||||
|
||||
// Get Window dimensions
|
||||
getmaxyx(win, height, width);
|
||||
|
||||
// Clear Displayed lines
|
||||
for (i=0; i < info->linescnt; i++) {
|
||||
mvwprintw(win, startline++, 5, "%*s", width - 6, "");
|
||||
}
|
||||
|
||||
// Print filter info
|
||||
mvwprintw(win, 4, 2, "%*s", width - 4, "");
|
||||
if (is_option_enabled("filter.enable"))
|
||||
mvwprintw(win, 4, 2, "%s", "Display filter: TODO");
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ call_list_draw(PANEL *panel);
|
|||
*
|
||||
* @param panel Ncurses panel pointer
|
||||
* @param key Pressed keycode
|
||||
* @return 0 if the function can handle the key, -1 otherwise
|
||||
* @return 0 if the function can handle the key, key otherwise
|
||||
*/
|
||||
extern int
|
||||
call_list_handle_key(PANEL *panel, int key);
|
||||
|
@ -162,13 +162,12 @@ call_list_help(PANEL *panel);
|
|||
* The default button can be configured using option
|
||||
* cl.defexitbutton (default 1, that means yes)
|
||||
*
|
||||
* @param panel Ncurses panel pointer
|
||||
* @return 0 if user selects yes, 1 otherwise
|
||||
* @param panel Call list panel pointer
|
||||
* @return 27 if user confirmed exit, 0 otherwise
|
||||
*/
|
||||
extern int
|
||||
call_list_exit_confirm(PANEL *panel);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add a column the Call List
|
||||
*
|
||||
|
@ -185,4 +184,16 @@ call_list_exit_confirm(PANEL *panel);
|
|||
extern int
|
||||
call_list_add_column(PANEL *panel, enum sip_attr_id id, const char* attr, const char *title, int width);
|
||||
|
||||
/**
|
||||
* @brief Update list information after a filter has been set
|
||||
*
|
||||
* This function is called after showing the filter dialog (@see ui_filter.h)
|
||||
* and resets the displayed information to force a new call list
|
||||
* load.
|
||||
*
|
||||
* @param panel Call list panel pointer
|
||||
*/
|
||||
extern void
|
||||
call_list_filter_update(PANEL *panel);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -160,7 +160,7 @@ call_raw_handle_key(PANEL *panel, int key)
|
|||
call_raw_handle_key(panel, KEY_UP);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
return key;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ call_raw_print_msg(PANEL *panel, sip_msg_t *msg);
|
|||
*
|
||||
* @param panel Ncurses panel pointer
|
||||
* @param key Pressed keycode
|
||||
* @return 0 if the function can handle the key, -1 otherwise
|
||||
* @return 0 if the function can handle the key, key otherwise
|
||||
*/
|
||||
extern int
|
||||
call_raw_handle_key(PANEL *panel, int key);
|
||||
|
|
|
@ -0,0 +1,318 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** sngrep - SIP callflow viewer using ngrep
|
||||
**
|
||||
** Copyright (C) 2014 Ivan Alonso (Kaian)
|
||||
** Copyright (C) 2014 Irontec SL. All rights reserved.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
****************************************************************************/
|
||||
/**
|
||||
* @file ui_call_raw.c
|
||||
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
|
||||
*
|
||||
* @brief Source of functions defined in ui_call_raw.h
|
||||
*
|
||||
* @todo Code help screen. Please.
|
||||
* @todo Replace the panel refresh. Wclear sucks on high latency conections.
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <form.h>
|
||||
#include "ui_filter.h"
|
||||
#include "option.h"
|
||||
|
||||
PANEL *
|
||||
filter_create()
|
||||
{
|
||||
PANEL *panel;
|
||||
WINDOW *win;
|
||||
int height, width;
|
||||
filter_info_t *info;
|
||||
|
||||
// Calculate window dimensions
|
||||
height = 17;
|
||||
width = 50;
|
||||
|
||||
// Cerate a new indow for the panel and form
|
||||
win = newwin(height, width, (LINES - height) / 2, (COLS - width) / 2);
|
||||
|
||||
// Create a new panel
|
||||
panel = new_panel(win);
|
||||
|
||||
// Initialize Filter panel specific data
|
||||
info = malloc(sizeof(filter_info_t));
|
||||
memset(info, 0, sizeof(filter_info_t));
|
||||
|
||||
// Store it into panel userptr
|
||||
set_panel_userptr(panel, (void*) info);
|
||||
|
||||
// Initialize the fields
|
||||
info->fields[FIELD_ENABLE] = new_field(1, 1, 3, 19, 0, 0);
|
||||
info->fields[FIELD_SIPFROM] = new_field(1, 28, 5, 18, 0, 0);
|
||||
info->fields[FIELD_SIPTO] = new_field(1, 28, 6, 18, 0, 0);
|
||||
info->fields[FIELD_SRC] = new_field(1, 18, 7, 18, 0, 0);
|
||||
info->fields[FIELD_DST] = new_field(1, 18, 8, 18, 0, 0);
|
||||
info->fields[FIELD_REGISTER] = new_field(1, 1, 10, 15, 0, 0);
|
||||
info->fields[FIELD_INVITE] = new_field(1, 1, 11, 15, 0, 0);
|
||||
info->fields[FIELD_SUBSCRIBE] = new_field(1, 1, 12, 15, 0, 0);
|
||||
info->fields[FIELD_NOTIFY] = new_field(1, 1, 13, 15, 0, 0);
|
||||
info->fields[FIELD_OPTIONS] = new_field(1, 1, 10, 37, 0, 0);
|
||||
info->fields[FIELD_PUBLISH] = new_field(1, 1, 11, 37, 0, 0);
|
||||
info->fields[FIELD_MESSAGE] = new_field(1, 1, 12, 37, 0, 0);
|
||||
info->fields[FIELD_FILTER] = new_field(1, 10, height - 2, 11, 0, 0);
|
||||
info->fields[FIELD_CANCEL] = new_field(1, 10, height - 2, 30, 0, 0);
|
||||
info->fields[FIELD_COUNT] = NULL;
|
||||
|
||||
// Set fields options
|
||||
field_opts_off(info->fields[FIELD_ENABLE], O_AUTOSKIP);
|
||||
field_opts_off(info->fields[FIELD_SIPFROM], O_AUTOSKIP);
|
||||
field_opts_off(info->fields[FIELD_SIPTO], O_AUTOSKIP);
|
||||
field_opts_off(info->fields[FIELD_SRC], O_AUTOSKIP);
|
||||
field_opts_off(info->fields[FIELD_DST], O_AUTOSKIP);
|
||||
field_opts_off(info->fields[FIELD_REGISTER], O_AUTOSKIP);
|
||||
field_opts_off(info->fields[FIELD_INVITE], O_AUTOSKIP);
|
||||
field_opts_off(info->fields[FIELD_SUBSCRIBE], O_AUTOSKIP);
|
||||
field_opts_off(info->fields[FIELD_NOTIFY], O_AUTOSKIP);
|
||||
field_opts_off(info->fields[FIELD_OPTIONS], O_AUTOSKIP);
|
||||
field_opts_off(info->fields[FIELD_PUBLISH], O_AUTOSKIP);
|
||||
field_opts_off(info->fields[FIELD_MESSAGE], O_AUTOSKIP);
|
||||
field_opts_off(info->fields[FIELD_FILTER], O_EDIT);
|
||||
field_opts_off(info->fields[FIELD_CANCEL], O_EDIT);
|
||||
|
||||
// Change background of input fields
|
||||
set_field_back(info->fields[FIELD_SIPFROM], A_UNDERLINE);
|
||||
set_field_back(info->fields[FIELD_SIPTO], A_UNDERLINE);
|
||||
set_field_back(info->fields[FIELD_SRC], A_UNDERLINE);
|
||||
set_field_back(info->fields[FIELD_DST], A_UNDERLINE);
|
||||
|
||||
// Create the form and post it
|
||||
info->form = new_form(info->fields);
|
||||
set_form_sub(info->form, win);
|
||||
post_form(info->form);
|
||||
|
||||
// Fields labels
|
||||
mvwprintw(win, 3, 3, "Enable filters [ ]");
|
||||
mvwprintw(win, 5, 3, "SIP From:");
|
||||
mvwprintw(win, 6, 3, "SIP To:");
|
||||
mvwprintw(win, 7, 3, "Source:");
|
||||
mvwprintw(win, 8, 3, "Destiny:");
|
||||
mvwprintw(win, 10, 3, "REGISTER [ ]");
|
||||
mvwprintw(win, 11, 3, "INVITE [ ]");
|
||||
mvwprintw(win, 12, 3, "SUBSCRIBE [ ]");
|
||||
mvwprintw(win, 13, 3, "NOTIFY [ ]");
|
||||
mvwprintw(win, 10, 25, "OPTIONS [ ]");
|
||||
mvwprintw(win, 11, 25, "PUBLISH [ ]");
|
||||
mvwprintw(win, 12, 25, "MESSAGE [ ]");
|
||||
|
||||
// Set Default field values
|
||||
set_field_buffer(info->fields[FIELD_ENABLE], 0, "*");
|
||||
set_field_buffer(info->fields[FIELD_SIPFROM], 0, get_option_value("filter.sipfrom"));
|
||||
set_field_buffer(info->fields[FIELD_SIPTO], 0, get_option_value("filter.sipto"));
|
||||
set_field_buffer(info->fields[FIELD_SRC], 0, get_option_value("filter.src"));
|
||||
set_field_buffer(info->fields[FIELD_DST], 0, get_option_value("filter.dst"));
|
||||
set_field_buffer(info->fields[FIELD_REGISTER], 0, is_option_enabled("filter.REGISTER")?"*":"");
|
||||
set_field_buffer(info->fields[FIELD_INVITE], 0, is_option_enabled("filter.INVITE")?"*":"");
|
||||
set_field_buffer(info->fields[FIELD_SUBSCRIBE], 0, is_option_enabled("filter.SUBSCRIBE")?"*":"");
|
||||
set_field_buffer(info->fields[FIELD_NOTIFY], 0, is_option_enabled("filter.NOTIFY")?"*":"");
|
||||
set_field_buffer(info->fields[FIELD_OPTIONS], 0, is_option_enabled("filter.OPTIONS")?"*":"");
|
||||
set_field_buffer(info->fields[FIELD_PUBLISH], 0, is_option_enabled("filter.PUBLISH")?"*":"");
|
||||
set_field_buffer(info->fields[FIELD_MESSAGE], 0, is_option_enabled("filter.MESSAGE")?"*":"");
|
||||
set_field_buffer(info->fields[FIELD_FILTER], 0, "[ Filter ]");
|
||||
set_field_buffer(info->fields[FIELD_CANCEL], 0, "[ Cancel ]");
|
||||
|
||||
// Set the window title and boxes
|
||||
mvwprintw(win, 1, 18, "Filter options");
|
||||
wattron(win, COLOR_PAIR(DETAIL_BORDER_COLOR));
|
||||
title_foot_box(panel_window(panel));
|
||||
mvwhline(win, 4, 1, ACS_HLINE, 49);
|
||||
mvwaddch(win, 4, 0, ACS_LTEE);
|
||||
mvwaddch(win, 4, 49, ACS_RTEE);
|
||||
mvwhline(win, 9, 1, ACS_HLINE, 49);
|
||||
mvwaddch(win, 9, 0, ACS_LTEE);
|
||||
mvwaddch(win, 9, 49, ACS_RTEE);
|
||||
wattroff(win, COLOR_PAIR(DETAIL_BORDER_COLOR));
|
||||
|
||||
// Set default cursor position
|
||||
set_current_field(info->form, info->fields[FIELD_SIPFROM]);
|
||||
wmove(win, 5, 18);
|
||||
curs_set(1);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
void
|
||||
filter_destroy(PANEL *panel)
|
||||
{
|
||||
// Disable cursor position
|
||||
curs_set(0);
|
||||
}
|
||||
|
||||
int
|
||||
filter_handle_key(PANEL *panel, int key)
|
||||
{
|
||||
int field_idx;
|
||||
char field_value[30];
|
||||
|
||||
// Get panel information
|
||||
filter_info_t *info = (filter_info_t*) panel_userptr(panel);
|
||||
|
||||
// Get current field id
|
||||
field_idx = field_index(current_field(info->form));
|
||||
|
||||
// Get current field value.
|
||||
// We trim spaces with sscanf because and empty field is stored as
|
||||
// space characters
|
||||
memset(field_value, 0, sizeof(field_value));
|
||||
sscanf(field_buffer(current_field(info->form), 0), "%[^ ]", field_value);
|
||||
|
||||
switch(key) {
|
||||
case 9 /*KEY_TAB*/:
|
||||
case KEY_DOWN:
|
||||
form_driver(info->form, REQ_NEXT_FIELD);
|
||||
form_driver(info->form, REQ_END_LINE);
|
||||
break;
|
||||
case KEY_UP:
|
||||
form_driver(info->form, REQ_PREV_FIELD);
|
||||
form_driver(info->form, REQ_END_LINE);
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
form_driver(info->form, REQ_RIGHT_CHAR);
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
form_driver(info->form, REQ_LEFT_CHAR);
|
||||
break;
|
||||
case KEY_HOME:
|
||||
form_driver(info->form, REQ_BEG_LINE);
|
||||
break;
|
||||
case KEY_END:
|
||||
form_driver(info->form, REQ_END_LINE);
|
||||
break;
|
||||
case KEY_DC:
|
||||
form_driver(info->form, REQ_DEL_CHAR);
|
||||
break;
|
||||
case 27 /*KEY_ESC*/:
|
||||
return key;
|
||||
break;
|
||||
case KEY_BACKSPACE:
|
||||
if (strlen(field_value) > 0)
|
||||
form_driver(info->form, REQ_DEL_PREV);
|
||||
break;
|
||||
case ' ':
|
||||
switch(field_idx) {
|
||||
case FIELD_ENABLE:
|
||||
case FIELD_REGISTER:
|
||||
case FIELD_INVITE:
|
||||
case FIELD_SUBSCRIBE:
|
||||
case FIELD_NOTIFY:
|
||||
case FIELD_OPTIONS:
|
||||
case FIELD_PUBLISH:
|
||||
case FIELD_MESSAGE:
|
||||
if (field_value[0] == '*') {
|
||||
form_driver(info->form, REQ_DEL_CHAR);
|
||||
} else {
|
||||
form_driver(info->form, '*');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
form_driver(info->form, REQ_NEXT_FIELD);
|
||||
form_driver(info->form, REQ_END_LINE);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 10: /* KEY_ENTER */
|
||||
if (field_idx != FIELD_CANCEL)
|
||||
filter_save_options(panel);
|
||||
return 27;
|
||||
default:
|
||||
// If this is a normal character on input field, print it
|
||||
switch(field_idx) {
|
||||
case FIELD_SIPFROM:
|
||||
case FIELD_SIPTO:
|
||||
case FIELD_SRC:
|
||||
case FIELD_DST:
|
||||
form_driver(info->form, key);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Validate all input data
|
||||
form_driver(info->form, REQ_VALIDATION);
|
||||
|
||||
// Change background and cursor of "button fields"
|
||||
set_field_back(info->fields[FIELD_FILTER], A_NORMAL);
|
||||
set_field_back(info->fields[FIELD_CANCEL], A_NORMAL);
|
||||
curs_set(1);
|
||||
|
||||
// Change current field background
|
||||
field_idx = field_index(current_field(info->form));
|
||||
if (field_idx == FIELD_FILTER || field_idx == FIELD_CANCEL) {
|
||||
set_field_back(info->fields[field_idx], A_REVERSE);
|
||||
curs_set(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
filter_save_options(PANEL *panel)
|
||||
{
|
||||
char field_value[30];
|
||||
int i;
|
||||
|
||||
// Get panel information
|
||||
filter_info_t *info = (filter_info_t*) panel_userptr(panel);
|
||||
|
||||
for (i = 0; i < FIELD_COUNT; i++) {
|
||||
// Get current field value.
|
||||
// We trim spaces with sscanf because and empty field is stored as
|
||||
// space characters
|
||||
memset(field_value, 0, sizeof(field_value));
|
||||
sscanf(field_buffer(info->fields[i], 0), "%[^ ]", field_value);
|
||||
|
||||
switch(i) {
|
||||
case FIELD_ENABLE:
|
||||
set_option_value("filter.enable", strlen(field_value)?"on":"off"); break;
|
||||
case FIELD_SIPFROM:
|
||||
set_option_value("filter.sipfrom", field_value); break;
|
||||
case FIELD_SIPTO:
|
||||
set_option_value("filter.sipto", field_value); break;
|
||||
case FIELD_SRC:
|
||||
set_option_value("filter.src", field_value); break;
|
||||
case FIELD_DST:
|
||||
set_option_value("filter.dst", field_value); break;
|
||||
case FIELD_REGISTER:
|
||||
set_option_value("filter.REGISTER", strlen(field_value)?"on":"off"); break;
|
||||
case FIELD_INVITE:
|
||||
set_option_value("filter.INVITE", strlen(field_value)?"on":"off");
|
||||
set_option_value("filter.INVITE (SDP)", strlen(field_value)?"on":"off"); break;
|
||||
case FIELD_SUBSCRIBE:
|
||||
set_option_value("filter.SUBSCRIBE", strlen(field_value)?"on":"off"); break;
|
||||
case FIELD_NOTIFY:
|
||||
set_option_value("filter.NOTIFY", strlen(field_value)?"on":"off"); break;
|
||||
case FIELD_OPTIONS:
|
||||
set_option_value("filter.OPTIONS", strlen(field_value)?"on":"off"); break;
|
||||
case FIELD_PUBLISH:
|
||||
set_option_value("filter.PUBLISH", strlen(field_value)?"on":"off"); break;
|
||||
case FIELD_MESSAGE:
|
||||
set_option_value("filter.MESSAGE", strlen(field_value)?"on":"off"); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** sngrep - SIP callflow viewer using ngrep
|
||||
**
|
||||
** Copyright (C) 2014 Ivan Alonso (Kaian)
|
||||
** Copyright (C) 2014 Irontec SL. All rights reserved.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
****************************************************************************/
|
||||
/**
|
||||
* @file ui_filter.h
|
||||
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
|
||||
*
|
||||
* @brief Functions to manage ui window for filtering options
|
||||
*
|
||||
* This file contains the functions and structures to manage the filter
|
||||
* dialog, that can be used to filter the lines in call list window.
|
||||
*/
|
||||
|
||||
#ifndef __UI_FILTER_H
|
||||
#define __UI_FILTER_H
|
||||
#include <form.h>
|
||||
#include "ui_manager.h"
|
||||
|
||||
/**
|
||||
* @brief Enum of available dialog fields
|
||||
*
|
||||
* Dialog form has a field array. Following enum represents the
|
||||
* order this fields are stored in panel info structure.
|
||||
*
|
||||
*/
|
||||
enum field_list {
|
||||
FIELD_ENABLE = 0,
|
||||
FIELD_SIPFROM,
|
||||
FIELD_SIPTO,
|
||||
FIELD_SRC,
|
||||
FIELD_DST,
|
||||
FIELD_REGISTER,
|
||||
FIELD_INVITE,
|
||||
FIELD_SUBSCRIBE,
|
||||
FIELD_NOTIFY,
|
||||
FIELD_OPTIONS,
|
||||
FIELD_PUBLISH,
|
||||
FIELD_MESSAGE,
|
||||
FIELD_FILTER,
|
||||
FIELD_CANCEL,
|
||||
//! Never remove this field id @see filte_info
|
||||
FIELD_COUNT,
|
||||
};
|
||||
|
||||
//! Sorter declaration of struct filter_info
|
||||
typedef struct filter_info filter_info_t;
|
||||
|
||||
/**
|
||||
* @brief Filter panel private information
|
||||
*
|
||||
* This structure contains the durable data of filter panel.
|
||||
*/
|
||||
struct filter_info
|
||||
{
|
||||
//! Form that contains the filter fields
|
||||
FORM *form;
|
||||
//! An array of fields
|
||||
FIELD *fields[FIELD_COUNT];
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates a new filter panel
|
||||
*
|
||||
* This function allocates all required memory for
|
||||
* displaying the filter panel. It also draws all the
|
||||
* static information of the panel that will never be
|
||||
* redrawn.
|
||||
*
|
||||
* @return a panel pointer
|
||||
*/
|
||||
extern PANEL *
|
||||
filter_create();
|
||||
|
||||
/**
|
||||
* @brief Destroy filter panel
|
||||
*
|
||||
* This function do the final cleanups for this panel
|
||||
*/
|
||||
extern void
|
||||
filter_destroy();
|
||||
|
||||
/**
|
||||
* @brief Manage pressed keys for filter panel
|
||||
*
|
||||
* This function is called by UI manager every time a
|
||||
* key is pressed. This allow the filter panel to manage
|
||||
* its own keys.
|
||||
* If this function return 0, the key will not be handled
|
||||
* by ui manager. Otherwise the return will be considered
|
||||
* a key code.
|
||||
*
|
||||
* @param panel Filter panel pointer
|
||||
* @param key key code
|
||||
* @return 0 if the key is handled, keycode otherwise
|
||||
*/
|
||||
extern int
|
||||
filter_handle_key(PANEL *panel, int key);
|
||||
|
||||
/**
|
||||
* @brief Save form data to options
|
||||
*
|
||||
* This function will update the options values
|
||||
* of filter fields with its new value.
|
||||
*
|
||||
* @param panel Filter panel pointer
|
||||
*/
|
||||
extern void
|
||||
filter_save_options(PANEL *panel);
|
||||
|
||||
#endif
|
|
@ -31,6 +31,7 @@
|
|||
#include "ui_call_list.h"
|
||||
#include "ui_call_flow.h"
|
||||
#include "ui_call_raw.h"
|
||||
#include "ui_filter.h"
|
||||
|
||||
/**
|
||||
* @brief Warranty thread-safe ui refresh
|
||||
|
@ -74,7 +75,13 @@ static ui_t panel_pool[] = {
|
|||
.create = call_raw_create,
|
||||
.redraw_required = call_raw_redraw_required,
|
||||
.draw = call_raw_draw,
|
||||
.handle_key = call_raw_handle_key, } };
|
||||
.handle_key = call_raw_handle_key, },
|
||||
{
|
||||
.type = FILTER_PANEL,
|
||||
.panel = NULL,
|
||||
.create = filter_create,
|
||||
.handle_key = filter_handle_key,
|
||||
.destroy = filter_destroy}, };
|
||||
|
||||
int
|
||||
init_interface()
|
||||
|
@ -142,7 +149,7 @@ ui_get_panel(ui_t *ui)
|
|||
int
|
||||
ui_redraw_required(ui_t *ui, sip_msg_t *msg)
|
||||
{
|
||||
int ret = -1;
|
||||
int ret = 0;
|
||||
//! Sanity check, this should not happen
|
||||
if (!ui) return -1;
|
||||
pthread_mutex_lock(&ui->lock);
|
||||
|
@ -171,16 +178,16 @@ ui_draw_panel(ui_t *ui)
|
|||
|
||||
// Request the panel to draw on the scren
|
||||
if (ui->draw) {
|
||||
if (ui->draw(ui_get_panel(ui)) == 0) {
|
||||
// Update panel stack
|
||||
update_panels();
|
||||
doupdate();
|
||||
if (ui->draw(ui_get_panel(ui)) != 0) {
|
||||
pthread_mutex_unlock(&ui->lock);
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// Update panel stack
|
||||
update_panels();
|
||||
doupdate();
|
||||
pthread_mutex_unlock(&ui->lock);
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -253,7 +260,7 @@ wait_for_input(ui_t *ui)
|
|||
int c = wgetch(win);
|
||||
|
||||
// Check if current panel has custom bindings for that key
|
||||
if (ui_handle_key(ui, c) == 0) continue;
|
||||
if ((c = ui_handle_key(ui, c)) == 0) continue;
|
||||
|
||||
// Otherwise, use standard keybindings
|
||||
switch (c) {
|
||||
|
@ -265,6 +272,10 @@ wait_for_input(ui_t *ui)
|
|||
case 'C':
|
||||
set_option_value("color.callid", is_option_enabled("color.callid") ? "off" : "on");
|
||||
break;
|
||||
case 'p':
|
||||
// Toggle capture option
|
||||
toggle_option("sip.capture");
|
||||
break;
|
||||
case 'h':
|
||||
case 265: /* KEY_F1 */
|
||||
ui_help(ui);
|
||||
|
|
|
@ -124,6 +124,8 @@ enum panel_types
|
|||
DETAILS_PANEL,
|
||||
//! Raw SIP messages ui screen
|
||||
RAW_PANEL,
|
||||
//! Filters panel
|
||||
FILTER_PANEL,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue