Commit bc2bdc61 authored by Victor Seva's avatar Victor Seva

New upstream version 1.4.6

parent ec6b2bcc
......@@ -2,6 +2,7 @@
.*project
.settings
.vscode
.idea
# Build files
src/sngrep
......
2018-10-31 Ivan Alonso <kaian@irontec.com>
* sngrep 1.4.6 released
* capture: fixed pcap reading from stdin
* capture: make SIP regexp more tolerant to invalid uris
* capture: SIP dialogs can now start with INFO, REFER and UPDATE
* call list: Added methods and key bindings for soft clear of call list
* call flow: improved performance while displaying a dialog with lots of messages
* call flow: arrows are now sorted by time while displaying multiple dialogs
* ui: fixed multiples buffer overflows crashes
* ui: improve compatibility with newest ncurses version
2018-01-19 Ivan Alonso <kaian@irontec.com>
* sngrep 1.4.5 released
......
......@@ -100,3 +100,7 @@
##-----------------------------------------------------------------------------
## Uncomment to display dialogs that does not start with a request method
# set sip.noincomplete off
##-----------------------------------------------------------------------------
## Uncomment to define custom b_leg correlation header
# set sip.xcid X-Call-ID|X-CID
AC_PREREQ([2.59])
AC_INIT([sngrep], [1.4.5], [kaian@irontec.com], [sngrep], [http://www.irontec.com/])
AC_INIT([sngrep], [1.4.6], [kaian@irontec.com], [sngrep], [http://www.irontec.com/])
AM_INIT_AUTOMAKE([1.9])
AC_CONFIG_HEADERS([src/config.h])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
......
......@@ -3,7 +3,7 @@
.\" Copyright (c) 2013-2018 Ivan Alonso <kaian@irontec.com>
.\" Copyright (c) 2013-2018 Irontec S.L.
.TH SNGREP 8 "September 2017" "sngrep 1.4.5"
.TH SNGREP 8 "October 2018" "sngrep 1.4.6"
.SH NAME
......
sngrep (1.4.6) experimental; urgency=low
* sngrep 1.4.6 released
-- Ivan Alonso <kaian@irontec.com> Wed, 31 Oct 2018 17:19:27 +0100
sngrep (1.4.5) experimental; urgency=low
* sngrep 1.4.5 released
......
......@@ -2,7 +2,7 @@
Summary: SIP Messages flow viewer
Name: sngrep
Version: 1.4.5
Version: 1.4.6
Release: 0%{?dist}
License: GPLv3
Group: Applications/Engineering
......@@ -59,6 +59,8 @@ make %{?_smp_mflags}
%{__rm} -rf %{buildroot}
%changelog
* Wed Oct 31 2018 Ivan Alonso <kaian@irontec.com> - 1.4.6
- Version 1.4.6
* Fri Dec 22 2017 Ivan Alonso <kaian@irontec.com> - 1.4.5
- Version 1.4.5
* Sun Sep 17 2017 Ivan Alonso <kaian@irontec.com> - 1.4.4
......
......@@ -178,7 +178,6 @@ capture_offline(const char *infile, const char *outfile)
// Check if file is standard input
if (strlen(infile) == 1 && *infile == '-') {
infile = "/dev/stdin";
fstdin = freopen("/dev/tty", "r", stdin);
}
// Set capture input file
......@@ -190,6 +189,14 @@ capture_offline(const char *infile, const char *outfile)
return 1;
}
// Reopen tty for ncurses after pcap have used stdin
if (!strncmp(infile, "/dev/stdin", 10)) {
if (!(stdin = freopen("/dev/tty", "r", stdin))) {
fprintf(stderr, "Failed to reopen tty while using stdin for capture.");
return 1;
}
}
// Get datalink to parse packets correctly
capinfo->link = pcap_datalink(capinfo->handle);
......@@ -808,7 +815,12 @@ capture_close()
//Close PCAP file
if (capinfo->handle) {
if (capinfo->running) {
/* We must cancel the thread here instead of joining because, according to pcap_breakloop man page,
* you can only break pcap_loop from within the same thread.
* @see: https://www.tcpdump.org/manpages/pcap_breakloop.3pcap.html
*/
pcap_breakloop(capinfo->handle);
pthread_cancel(capinfo->capture_t);
pthread_join(capinfo->capture_t, NULL);
}
}
......@@ -917,7 +929,7 @@ capture_paused()
const char *
capture_status_desc()
{
int online = 0, offline = 0;
int online = 0, offline = 0, loading = 0;
capture_info_t *capinfo;
......@@ -925,6 +937,9 @@ capture_status_desc()
while ((capinfo = vector_iterator_next(&it))) {
if (capinfo->infile) {
offline++;
if (capinfo->running) {
loading++;
}
} else {
online++;
}
......@@ -945,6 +960,14 @@ capture_status_desc()
} else {
return "Mixed (Paused)";
}
} else if (loading > 0) {
if (online > 0 && offline == 0) {
return "Online (Loading)";
} else if (online == 0 && offline > 0) {
return "Offline (Loading)";
} else {
return "Mixed (Loading)";
}
} else {
if (online > 0 && offline == 0) {
return "Online";
......@@ -1048,12 +1071,6 @@ capture_packet_time_sorter(vector_t *vector, void *item)
// TODO Implement multiframe packets
curts = packet_time(item);
prevts = packet_time(vector_last(vector));
// Check if the item is already sorted
if (timeval_is_older(curts, prevts)) {
return;
}
for (i = count - 2 ; i >= 0; i--) {
// Get previous packet
......
......@@ -94,7 +94,7 @@ P_hash(const char *digest, unsigned char *dest, int dlen, unsigned char *secret,
// Calculate enough data to fill destination
while (pending > 0) {
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if MODSSL_USE_OPENSSL_PRE_1_1_API
HMAC_CTX hm;
HMAC_Init(&hm, secret, sslen, md);
HMAC_Update(&hm, tmpseed, tmpslen);
......@@ -495,7 +495,7 @@ tls_process_record(struct SSLConnection *conn, const uint8_t *payload,
break;
case change_cipher_spec:
// From now on, this connection will be encrypted using MasterSecret
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if MODSSL_USE_OPENSSL_PRE_1_1_API
if (conn->client_cipher_ctx->cipher && conn->server_cipher_ctx->cipher)
conn->encrypted = 1;
#else
......@@ -588,7 +588,7 @@ tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment,
// Decrypt PreMasterKey
clientkeyex = (struct ClientKeyExchange *) body;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if MODSSL_USE_OPENSSL_PRE_1_1_API
RSA_private_decrypt(UINT16_INT(clientkeyex->length),
(const unsigned char *) &clientkeyex->exchange_keys,
(unsigned char *) &conn->pre_master_secret,
......
......@@ -65,6 +65,15 @@
#define OLD_OPENSSL_VERSION 1
#endif
/* LibreSSL declares OPENSSL_VERSION_NUMBER == 2.0 but does not include most
* changes from OpenSSL >= 1.1 (new functions, macros, deprecations, ...)
*/
#if defined(LIBRESSL_VERSION_NUMBER)
#define MODSSL_USE_OPENSSL_PRE_1_1_API (1)
#else
#define MODSSL_USE_OPENSSL_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L)
#endif
//! Three bytes unsigned integer
typedef struct uint16 {
unsigned char x[2];
......
......@@ -311,11 +311,21 @@ call_flow_draw_columns(ui_t *ui)
if (setting_enabled(SETTING_CF_SPLITCALLID) || !column->addr.port) {
snprintf(coltext, MAX_SETTING_LEN, "%s", column->alias);
} else if (setting_enabled(SETTING_DISPLAY_ALIAS)) {
snprintf(coltext, MAX_SETTING_LEN, "%.*s:%u",
MAX_SETTING_LEN - 7, column->alias, column->addr.port);
if (strlen(column->addr.ip) > 15) {
snprintf(coltext, MAX_SETTING_LEN, "..%.*s:%u",
MAX_SETTING_LEN - 7, column->alias + strlen(column->alias) - 13, column->addr.port);
} else {
snprintf(coltext, MAX_SETTING_LEN, "%.*s:%u",
MAX_SETTING_LEN - 7, column->alias, column->addr.port);
}
} else {
snprintf(coltext, MAX_SETTING_LEN, "%.*s:%u",
MAX_SETTING_LEN - 7, column->addr.ip, column->addr.port);
if (strlen(column->addr.ip) > 15) {
snprintf(coltext, MAX_SETTING_LEN, "..%.*s:%u",
MAX_SETTING_LEN - 7, column->addr.ip + strlen(column->addr.ip) - 13, column->addr.port);
} else {
snprintf(coltext, MAX_SETTING_LEN, "%.*s:%u",
MAX_SETTING_LEN - 7, column->addr.ip, column->addr.port);
}
}
mvwprintw(ui->win, 2, 10 + 30 * column->colpos + (22 - strlen(coltext)) / 2, "%s", coltext);
......@@ -415,18 +425,19 @@ call_flow_draw_message(ui_t *ui, call_flow_arrow_t *arrow, int cline)
WINDOW *flow_win;
sdp_media_t *media;
const char *callid;
char msg_method[128];
char msg_method[SIP_ATTR_MAXLEN];
char msg_time[80];
address_t src;
address_t dst;
char method[80];
char delta[15] = { };
char delta[15] = {};
int flowh, floww;
char mediastr[40];
sip_msg_t *msg = arrow->item;
vector_iter_t medias;
int color = 0;
int msglen;
int aline = cline + 1;
// Get panel information
info = call_flow_info(ui);
......@@ -491,13 +502,17 @@ call_flow_draw_message(ui_t *ui, call_flow_arrow_t *arrow, int cline)
arrow->dcolumn = call_flow_column_get(ui, callid, dst);
// Determine start and end position of the arrow line
int arrow_dir, startpos, endpos;
if (arrow->scolumn->colpos < arrow->dcolumn->colpos) {
arrow_dir = CF_ARROW_RIGHT;
int startpos, endpos;
if (arrow->scolumn == arrow->dcolumn) {
arrow->dir = CF_ARROW_SPIRAL;
startpos = 19 + 30 * arrow->dcolumn->colpos;
endpos = 20 + 30 * arrow->scolumn->colpos;
} else if (arrow->scolumn->colpos < arrow->dcolumn->colpos) {
arrow->dir = CF_ARROW_RIGHT;
startpos = 20 + 30 * arrow->scolumn->colpos;
endpos = 20 + 30 * arrow->dcolumn->colpos;
} else {
arrow_dir = CF_ARROW_LEFT;
arrow->dir = CF_ARROW_LEFT;
startpos = 20 + 30 * arrow->dcolumn->colpos;
endpos = 20 + 30 * arrow->scolumn->colpos;
}
......@@ -529,16 +544,23 @@ call_flow_draw_message(ui_t *ui, call_flow_arrow_t *arrow, int cline)
color = msg->cseq % 7 + 1;
}
// Print arrow in the same line than message
if (setting_has_value(SETTING_CF_SDP_INFO, "compressed")) {
aline = cline;
}
// Turn on the message color
wattron(flow_win, COLOR_PAIR(color));
// Clear the line
mvwprintw(flow_win, cline, startpos + 2, "%*s", distance, "");
// Draw method
mvwprintw(flow_win, cline, startpos + distance / 2 - msglen / 2 + 2, "%.26s", method);
if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed"))
cline++;
// Draw method
if (arrow->dir == CF_ARROW_SPIRAL) {
mvwprintw(flow_win, cline, startpos + 5, "%.26s", method);
} else {
mvwprintw(flow_win, cline, startpos + distance / 2 - msglen / 2 + 2, "%.26s", method);
}
// Draw media information
if (msg_has_sdp(msg) && setting_has_value(SETTING_CF_SDP_INFO, "full")) {
......@@ -548,28 +570,48 @@ call_flow_draw_message(ui_t *ui, call_flow_arrow_t *arrow, int cline)
media->type,
media->address.port,
media_get_prefered_format(media));
mvwprintw(flow_win, cline++, startpos + distance / 2 - strlen(mediastr) / 2 + 2, mediastr);
if (arrow->dir == CF_ARROW_SPIRAL) {
mvwprintw(flow_win, cline + 1, startpos + 5, mediastr);
} else {
mvwprintw(flow_win, cline + 1, startpos + distance / 2 - strlen(mediastr) / 2 + 2, mediastr);
}
cline++;
aline++;
}
}
if (arrow == call_flow_arrow_selected(ui)) {
mvwhline(flow_win, cline, startpos + 2, '=', distance);
} else {
mvwhline(flow_win, cline, startpos + 2, ACS_HLINE, distance);
if (arrow->dir != CF_ARROW_SPIRAL) {
if (arrow == call_flow_arrow_selected(ui)) {
mvwhline(flow_win, aline, startpos + 2, '=', distance);
} else {
mvwhline(flow_win, aline, startpos + 2, ACS_HLINE, distance);
}
}
// Write the arrow at the end of the message (two arros if this is a retrans)
if (arrow_dir == CF_ARROW_RIGHT) {
mvwaddch(flow_win, cline, endpos - 2, '>');
// Write the arrow at the end of the message (two arrows if this is a retrans)
if (arrow->dir == CF_ARROW_SPIRAL) {
mvwaddch(flow_win, aline, startpos + 2, '<');
if (msg->retrans) {
mvwaddch(flow_win, cline, endpos - 3, '>');
mvwaddch(flow_win, cline, endpos - 4, '>');
mvwaddch(flow_win, aline, startpos + 3, '<');
mvwaddch(flow_win, aline, startpos + 4, '<');
}
// If multiple lines are available, print a spiral icon
if (aline != cline) {
mvwaddch(flow_win, aline, startpos + 3, ACS_LRCORNER);
mvwaddch(flow_win, aline - 1, startpos + 3, ACS_URCORNER);
mvwaddch(flow_win, aline - 1, startpos + 2, ACS_HLINE);
}
} else if (arrow->dir == CF_ARROW_RIGHT) {
mvwaddch(flow_win, aline, endpos - 2, '>');
if (msg->retrans) {
mvwaddch(flow_win, aline, endpos - 3, '>');
mvwaddch(flow_win, aline, endpos - 4, '>');
}
} else {
mvwaddch(flow_win, cline, startpos + 2, '<');
mvwaddch(flow_win, aline, startpos + 2, '<');
if (msg->retrans) {
mvwaddch(flow_win, cline, startpos + 3, '<');
mvwaddch(flow_win, cline, startpos + 4, '<');
mvwaddch(flow_win, aline, startpos + 3, '<');
mvwaddch(flow_win, aline, startpos + 4, '<');
}
}
......@@ -724,13 +766,13 @@ call_flow_draw_rtp_stream(ui_t *ui, call_flow_arrow_t *arrow, int cline)
}
// Determine start and end position of the arrow line
int arrow_dir, startpos, endpos;
int startpos, endpos;
if (arrow->scolumn->colpos < arrow->dcolumn->colpos) {
arrow_dir = CF_ARROW_RIGHT;
arrow->dir= CF_ARROW_RIGHT;
startpos = 20 + 30 * arrow->scolumn->colpos;
endpos = 20 + 30 * arrow->dcolumn->colpos;
} else {
arrow_dir = CF_ARROW_LEFT;
arrow->dir = CF_ARROW_LEFT;
startpos = 20 + 30 * arrow->dcolumn->colpos;
endpos = 20 + 30 * arrow->scolumn->colpos;
}
......@@ -752,9 +794,9 @@ call_flow_draw_rtp_stream(ui_t *ui, call_flow_arrow_t *arrow, int cline)
// Fix arrow direction based on ports
if (stream->src.port < stream->dst.port) {
arrow_dir = CF_ARROW_RIGHT;
arrow->dir = CF_ARROW_RIGHT;
} else {
arrow_dir = CF_ARROW_LEFT;
arrow->dir = CF_ARROW_LEFT;
}
}
......@@ -790,7 +832,7 @@ call_flow_draw_rtp_stream(ui_t *ui, call_flow_arrow_t *arrow, int cline)
mvwhline(win, cline, startpos + 2, ACS_HLINE, distance);
// Write the arrow at the end of the message (two arrows if this is a retrans)
if (arrow_dir == CF_ARROW_RIGHT) {
if (arrow->dir == CF_ARROW_RIGHT) {
if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) {
mvwprintw(win, cline, startpos - 4, "%d", stream->src.port);
mvwprintw(win, cline, endpos, "%d", stream->dst.port);
......@@ -926,6 +968,8 @@ call_flow_draw_raw(ui_t *ui, sip_msg_t *msg)
{
call_flow_info_t *info;
WINDOW *raw_win;
vector_iter_t arrows;
call_flow_arrow_t *arrow;
int raw_width, raw_height;
int min_raw_width, fixed_raw_width;
......@@ -939,6 +983,17 @@ call_flow_draw_raw(ui_t *ui, sip_msg_t *msg)
// Calculate the raw data width (width - used columns for flow - vertical lines)
raw_width = ui->width - (30 * vector_count(info->columns)) - 2;
// If last column has spirals, add an extra column with
arrows = vector_iterator(info->arrows);
while ((arrow = vector_iterator_next(&arrows))) {
if (arrow->dir == CF_ARROW_SPIRAL
&& arrow->scolumn == vector_last(info->columns)) {
raw_width -= 15;
break;
}
}
// We can define a mininum size for rawminwidth
if (raw_width < min_raw_width) {
raw_width = min_raw_width;
......@@ -1201,6 +1256,7 @@ call_flow_handle_key(ui_t *ui, int key)
call_raw_set_msg(call_flow_arrow_message(vector_item(info->darrows, info->cur_arrow)));
break;
case ACTION_CLEAR_CALLS:
case ACTION_CLEAR_CALLS_SOFT:
// Propagate the key to the previous panel
return KEY_PROPAGATED;
......@@ -1499,12 +1555,6 @@ call_flow_arrow_sorter(vector_t *vector, void *item)
return;
curts = call_flow_arrow_time(item);
prevts = call_flow_arrow_time(vector_item(vector, vector_count(vector) - 2));
// Check if the item is already sorted
if (timeval_is_older(curts, prevts)) {
return;
}
for (i = count - 2 ; i >= 0; i--) {
// Get previous arrow
......
......@@ -82,6 +82,7 @@ enum call_flow_arrow_type {
enum call_flow_arrow_dir {
CF_ARROW_RIGHT = 0,
CF_ARROW_LEFT,
CF_ARROW_SPIRAL
};
/**
......@@ -100,6 +101,8 @@ struct call_flow_arrow {
int height;
//! Line of flow window this line starts
int line;
//! Arrow direction
enum call_flow_arrow_dir dir;
//! Source column for this arrow
call_flow_column_t *scolumn;
//! Destination column for this arrow
......
......@@ -330,10 +330,11 @@ call_list_draw_footer(ui_t *ui)
key_action_key_str(ACTION_CLEAR_CALLS), "Clear",
key_action_key_str(ACTION_SHOW_FILTERS), "Filter",
key_action_key_str(ACTION_SHOW_SETTINGS), "Settings",
key_action_key_str(ACTION_CLEAR_CALLS_SOFT), "Clear with Filter",
key_action_key_str(ACTION_SHOW_COLUMNS), "Columns"
};
ui_draw_bindings(ui, keybindings, 22);
ui_draw_bindings(ui, keybindings, 23);
}
void
......@@ -672,6 +673,12 @@ call_list_handle_key(ui_t *ui, int key)
// Clear List
call_list_clear(ui);
break;
case ACTION_CLEAR_CALLS_SOFT:
// Remove stored calls, keeping the currently displayed calls
sip_calls_clear_soft();
// Clear List
call_list_clear(ui);
break;
case ACTION_AUTOSCROLL:
info->autoscroll = (info->autoscroll) ? 0 : 1;
break;
......@@ -740,7 +747,7 @@ int
call_list_handle_form_key(ui_t *ui, int key)
{
int field_idx;
char dfilter[COLS];
char *dfilter;
int action = -1;
// Get panel information
......@@ -810,13 +817,16 @@ call_list_handle_form_key(ui_t *ui, int key)
form_driver(info->form, REQ_VALIDATION);
// Store dfilter input
// We trim spaces with sscanf because and empty field is stored as space characters
memset(dfilter, 0, sizeof(dfilter));
strcpy(dfilter, field_buffer(info->fields[FLD_LIST_FILTER], 0));
int field_len = strlen(field_buffer(info->fields[FLD_LIST_FILTER], 0));
dfilter = malloc(field_len + 1);
memset(dfilter, 0, field_len + 1);
strncpy(dfilter, field_buffer(info->fields[FLD_LIST_FILTER], 0), field_len);
// Trim any trailing spaces
strtrim(dfilter);
// Set display filter
filter_set(FILTER_CALL_LIST, strlen(dfilter) ? dfilter : NULL);
free(dfilter);
// Return if this panel has handled or not the key
return (action == ERR) ? KEY_NOT_HANDLED : KEY_HANDLED;
......
......@@ -266,6 +266,7 @@ call_raw_handle_key(ui_t *ui, int key)
}
break;
case ACTION_CLEAR_CALLS:
case ACTION_CLEAR_CALLS_SOFT:
// Propagate the key to the previous panel
return KEY_PROPAGATED;
default:
......
......@@ -19,6 +19,7 @@
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
/**
* @file ui_column_select.c
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
......@@ -470,20 +471,31 @@ column_select_move_item(ui_t *ui, ITEM *item, int pos)
// Swap position with destination
int item_pos = item_index(item);
info->items[item_pos] = info->items[pos];
info->items[item_pos]->index = item_pos;
info->items[pos] = item;
info->items[pos]->index = pos;
set_menu_items(info->menu, info->items);
}
void
column_select_toggle_item(ui_t *ui, ITEM *item)
{
// Get panel information
column_select_info_t *info = column_select_info(ui);
int pos = item_index(item);
// Change item name
if (!strncmp(item_name(item), "[ ]", 3)) {
item->name.str = "[*]";
info->items[pos] = new_item("[*]", item_description(item));
} else {
item->name.str = "[ ]";
info->items[pos] = new_item("[ ]", item_description(item));
}
// Restore menu item
set_item_userptr(info->items[pos], item_userptr(item));
set_menu_items(info->menu, info->items);
// Destroy old item
free_item(item);
}
void
......@@ -504,4 +516,8 @@ column_select_update_menu(ui_t *ui)
// Move until the current position is set
set_top_row(info->menu, top_idx);
set_current_item(info->menu, current);
// Force menu redraw
menu_driver(info->menu, REQ_UP_ITEM);
menu_driver(info->menu, REQ_DOWN_ITEM);
}
......@@ -55,7 +55,7 @@ filter_create(ui_t *ui)
const char *method, *payload;
// Cerate a new indow for the panel and form
ui_panel_create(ui, 16, 50);
ui_panel_create(ui, 17, 50);
// Initialize Filter panel specific data
info = sng_malloc(sizeof(filter_info_t));
......@@ -73,9 +73,12 @@ filter_create(ui_t *ui)
info->fields[FLD_FILTER_INVITE] = new_field(1, 1, 10, 15, 0, 0);
info->fields[FLD_FILTER_SUBSCRIBE] = new_field(1, 1, 11, 15, 0, 0);
info->fields[FLD_FILTER_NOTIFY] = new_field(1, 1, 12, 15, 0, 0);
info->fields[FLD_FILTER_INFO] = new_field(1, 1, 13, 15, 0, 0);
info->fields[FLD_FILTER_OPTIONS] = new_field(1, 1, 9, 37, 0, 0);
info->fields[FLD_FILTER_PUBLISH] = new_field(1, 1, 10, 37, 0, 0);
info->fields[FLD_FILTER_MESSAGE] = new_field(1, 1, 11, 37, 0, 0);
info->fields[FLD_FILTER_REFER] = new_field(1, 1, 12, 37, 0, 0);
info->fields[FLD_FILTER_UPDATE] = new_field(1, 1, 13, 37, 0, 0);
info->fields[FLD_FILTER_FILTER] = new_field(1, 10, ui->height - 2, 11, 0, 0);
info->fields[FLD_FILTER_CANCEL] = new_field(1, 10, ui->height - 2, 30, 0, 0);
info->fields[FLD_FILTER_COUNT] = NULL;
......@@ -90,9 +93,12 @@ filter_create(ui_t *ui)
field_opts_off(info->fields[FLD_FILTER_INVITE], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_SUBSCRIBE], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_NOTIFY], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_INFO], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_OPTIONS], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_PUBLISH], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_MESSAGE], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_REFER], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_UPDATE], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_FILTER], O_EDIT);
field_opts_off(info->fields[FLD_FILTER_CANCEL], O_EDIT);
......@@ -118,9 +124,12 @@ filter_create(ui_t *ui)
mvwprintw(ui->win, 10, 3, "INVITE [ ]");
mvwprintw(ui->win, 11, 3, "SUBSCRIBE [ ]");
mvwprintw(ui->win, 12, 3, "NOTIFY [ ]");
mvwprintw(ui->win, 13, 3, "INFO [ ]");
mvwprintw(ui->win, 9, 25, "OPTIONS [ ]");
mvwprintw(ui->win, 10, 25, "PUBLISH [ ]");
mvwprintw(ui->win, 11, 25, "MESSAGE [ ]");
mvwprintw(ui->win, 12, 25, "REFER [ ]");
mvwprintw(ui->win, 13, 25, "UPDATE [ ]");
// Get Method filter
if (!(method = filter_get(FILTER_METHOD)))
......@@ -144,12 +153,18 @@ filter_create(ui_t *ui)
strcasestr(method,sip_method_str(SIP_METHOD_SUBSCRIBE)) ? "*" : "");
set_field_buffer(info->fields[FLD_FILTER_NOTIFY], 0,
strcasestr(method, sip_method_str(SIP_METHOD_NOTIFY)) ? "*" : "");
set_field_buffer(info->fields[FLD_FILTER_INFO], 0,
strcasestr(method, sip_method_str(SIP_METHOD_INFO)) ? "*" : "");
set_field_buffer(info->fields[FLD_FILTER_OPTIONS], 0,
strcasestr(method, sip_method_str(SIP_METHOD_OPTIONS)) ? "*" : "");
set_field_buffer(info->fields[FLD_FILTER_PUBLISH], 0,
strcasestr(method, sip_method_str(SIP_METHOD_PUBLISH)) ? "*" : "");
strcasestr(method, sip_method_str(SIP_METHOD_PUBLISH)) ? "*" : "");
set_field_buffer(info->fields[FLD_FILTER_MESSAGE], 0,
strcasestr(method, sip_method_str(SIP_METHOD_MESSAGE)) ? "*" : "");
strcasestr(method, sip_method_str(SIP_METHOD_MESSAGE)) ? "*" : "");
set_field_buffer(info->fields[FLD_FILTER_REFER], 0,
strcasestr(method, sip_method_str(SIP_METHOD_REFER)) ? "*" : "");
set_field_buffer(info->fields[FLD_FILTER_UPDATE], 0,
strcasestr(method, sip_method_str(SIP_METHOD_UPDATE)) ? "*" : "");
set_field_buffer(info->fields[FLD_FILTER_FILTER], 0, "[ Filter ]");
set_field_buffer(info->fields[FLD_FILTER_CANCEL], 0, "[ Cancel ]");
......@@ -254,9 +269,12 @@ filter_handle_key(ui_t *ui, int key)
case FLD_FILTER_INVITE:
case FLD_FILTER_SUBSCRIBE:
case FLD_FILTER_NOTIFY:
case FLD_FILTER_INFO:
case FLD_FILTER_OPTIONS:
case FLD_FILTER_PUBLISH:
case FLD_FILTER_MESSAGE:
case FLD_FILTER_REFER:
case FLD_FILTER_UPDATE:
if (field_value[0] == '*') {
form_driver(info->form, REQ_DEL_CHAR);
} else {
......@@ -353,6 +371,9 @@ filter_save_options(ui_t *ui)
case FLD_FILTER_OPTIONS:
case FLD_FILTER_PUBLISH:
case FLD_FILTER_MESSAGE:
case FLD_FILTER_INFO:
case FLD_FILTER_REFER:
case FLD_FILTER_UPDATE:
if (!strcmp(field_value, "*")) {
if (strlen(method_expr)) {
sprintf(method_expr + strlen(method_expr), ",%s", filter_field_method(field_id));
......@@ -402,6 +423,15 @@ filter_field_method(int field_id)
case FLD_FILTER_MESSAGE:
method = SIP_METHOD_MESSAGE;
break;
case FLD_FILTER_INFO:
method = SIP_METHOD_INFO;
break;
case FLD_FILTER_REFER:
method = SIP_METHOD_REFER;
break;
case FLD_FILTER_UPDATE:
method = SIP_METHOD_UPDATE;
break;
}
return sip_method_str(method);
......
......@@ -53,9 +53,12 @@ enum filter_field_list {
FLD_FILTER_INVITE,
FLD_FILTER_SUBSCRIBE,
FLD_FILTER_NOTIFY,
FLD_FILTER_INFO,
FLD_FILTER_OPTIONS,
FLD_FILTER_PUBLISH,
FLD_FILTER_MESSAGE,
FLD_FILTER_REFER,
FLD_FILTER_UPDATE,
FLD_FILTER_FILTER,
FLD_FILTER_CANCEL,
//! Never remove this field id @see filter_info
......
......@@ -349,6 +349,7 @@ draw_message_pos(WINDOW *win, sip_msg_t *msg, int starting)
int height, width, line, column, i;
const char *cur_line, *payload, *method = NULL;
int syntax = setting_enabled(SETTING_SYNTAX);
const char *nonascii = setting_get_value(SETTING_CR_NON_ASCII);
// Default text format
int attrs = A_NORMAL | COLOR_PAIR(CP_DEFAULT);
......@@ -451,7 +452,11 @@ draw_message_pos(WINDOW *win, sip_msg_t *msg, int starting)
}
// Put next character in position
mvwaddch(win, line, column++, payload[i]);
if (isascii(payload[i])) {
mvwaddch(win, line, column++, payload[i]);
} else {
mvwaddch(win, line, column++, *nonascii);
}
// Stop if we've reached the bottom of the window
if (line == height)
......
......@@ -224,23 +224,30 @@ sip_msg_t *
call_group_get_next_msg(sip_call_group_t *group, sip_msg_t *msg)
{
sip_msg_t *next;
vector_t *messages = vector_create(1,10);
vector_set_sorter(messages, call_group_msg_sorter);
vector_iter_t callsit = vector_iterator(group->calls);