Implemented a filter UI for Call list

This commit is contained in:
Kaian 2014-03-18 12:05:11 +01:00
parent 6cab1f10f6
commit d798d9ab4b
18 changed files with 666 additions and 47 deletions

View File

@ -1,2 +1,2 @@
sysconfdir = @sysconfdir@
sysconfdir=@sysconfdir@
sysconf_DATA=sngreprc

56
configure vendored
View File

@ -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

View File

@ -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], [], [

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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");
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);

318
src/ui_filter.c Normal file
View File

@ -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;
}
}
}

128
src/ui_filter.h Normal file
View File

@ -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

View File

@ -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);

View File

@ -124,6 +124,8 @@ enum panel_types
DETAILS_PANEL,
//! Raw SIP messages ui screen
RAW_PANEL,
//! Filters panel
FILTER_PANEL,
};
/**