Functional Call-Flow extended

Code style GNUK applied
Some documentation and cleanups
This commit is contained in:
Kaian 2013-06-24 14:39:19 +02:00
parent cb51d66196
commit cfe9e7823b
17 changed files with 931 additions and 547 deletions

View File

@ -45,7 +45,8 @@
** (let's say -T), sngrep will fail at parsing any header :(
**
****************************************************************************/
int run_ngrep(void *pargv)
int
run_ngrep(void *pargv)
{
char **argv = (char**) pargv;
int argc = 1;
@ -73,7 +74,7 @@ int run_ngrep(void *pargv)
struct sip_msg *msg;
if ((msg = sip_parse_message(msg_header, strdup((const char*) msg_payload)))) {
// Update the ui
refresh_call_ui(msg->call->callid);
ui_new_msg_refresh(msg);
}
// Initialize structures

View File

@ -38,6 +38,7 @@
** (let's say -T), sngrep will fail at parsing any header :(
**
****************************************************************************/
int run_ngrep(void *pargs);
int
run_ngrep(void *pargs);
#endif

View File

@ -33,7 +33,8 @@
* Print all available options (which are none actually)
*
*/
void usage(const char* progname)
void
usage(const char* progname)
{
fprintf(stdout, "[%s] Copyright (C) 2013 Irontec S.L.\n\n", progname);
fprintf(stdout, "Usage:\n");
@ -53,7 +54,8 @@ void usage(const char* progname)
* without any type of validation.
*
*/
int main(int argc, char* argv[])
int
main(int argc, char* argv[])
{
int ret;
@ -79,7 +81,6 @@ int main(int argc, char* argv[])
} else {
// Show online mode in ui
config.online = 1;
// Assume online mode, launch ngrep in a thread
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

View File

@ -1,4 +1,3 @@
/**************************************************************************
**
** sngrep - Ncurses ngrep interface for SIP
@ -35,47 +34,61 @@
* @return 0 if load has been successfull, 1 otherwise
*
*/
int load_pcap_file(const char* file) {
int
load_pcap_file(const char* file)
{
// Temporary packet buffers
struct pcap_pkthdr header; // The header that pcap gives us
const u_char *packet; // The actual packet
pcap_t *handle; // PCAP file handler
char errbuf[PCAP_ERRBUF_SIZE]; // Error text (in case of file open error)
int linktype; // Packages Datalink
int size_link; // Datalink Header size
struct ether_header *eptr; // Ethernet header data
u_short ether_type; // Ethernet header type
struct nread_ip *ip; // IP header data
int size_ip; // IP header size
struct nread_udp *udp; // UDP header data
char msg_header[256]; // XXX Fake header (Like the one from ngrep)
u_char *msg_payload; // Packet payload data
int size_payload; // Packet payload size
// The header that pcap gives us
struct pcap_pkthdr header;
// The actual packet
const u_char *packet;
// PCAP file handler
pcap_t *handle;
// Error text (in case of file open error)
char errbuf[PCAP_ERRBUF_SIZE];
// Packages Datalink
int linktype;
// Datalink Header size
int size_link;
// Ethernet header data
struct ether_header *eptr;
// Ethernet header type
u_short ether_type;
// IP header data
struct nread_ip *ip;
// IP header size
int size_ip;
// UDP header data
struct nread_udp *udp;
// XXX Fake header (Like the one from ngrep)
char msg_header[256];
// Packet payload data
u_char *msg_payload;
// Packet payload size
int size_payload;
struct timeval tvBegin, tvEnd;
int packagecnt = 0;
int packagecnt = 0;
gettimeofday(&tvBegin, NULL); // Grab starting time
// Open PCAP file
if ((handle = pcap_open_offline(file, errbuf)) == NULL) {
fprintf(stderr,"Couldn't open pcap file %s: %s\n", file, errbuf);
fprintf(stderr, "Couldn't open pcap file %s: %s\n", file, errbuf);
return 1;
}
// Get datalink to parse packages correctly
linktype = pcap_datalink(handle);
// Loop through packages
while ((packet = pcap_next(handle,&header))) {
packagecnt++;
while ((packet = pcap_next(handle, &header))) {
packagecnt++;
// Get link header size from datalink type
if (linktype == DLT_EN10MB ) {
if (linktype == DLT_EN10MB) {
eptr = (struct ether_header *) packet;
if ((ether_type = ntohs(eptr->ether_type)) != ETHERTYPE_IP )
continue;
if ((ether_type = ntohs(eptr->ether_type)) != ETHERTYPE_IP) continue;
size_link = SIZE_ETHERNET;
} else if (linktype == DLT_LINUX_SLL) {
size_link = SLL_HDR_LEN;
size_link = SLL_HDR_LEN;
} else {
// Something we are not prepared to parse :(
fprintf(stderr, "Error handing linktype %d\n", linktype);
@ -83,23 +96,22 @@ int load_pcap_file(const char* file) {
}
// Get IP header
ip = (struct nread_ip*)(packet + size_link);
size_ip = IP_HL(ip)*4;
ip = (struct nread_ip*) (packet + size_link);
size_ip = IP_HL(ip) * 4;
// Only interested in UDP packets
if (ip->ip_p != IPPROTO_UDP )
continue;
if (ip->ip_p != IPPROTO_UDP) continue;
// Get UDP header
udp = (struct nread_udp*)(packet + size_link + size_ip);
udp = (struct nread_udp*) (packet + size_link + size_ip);
// Get package payload
msg_payload = (u_char *)(packet + size_link + size_ip + SIZE_UDP);
msg_payload = (u_char *) (packet + size_link + size_ip + SIZE_UDP);
size_payload = htons(udp->udp_hlen) - SIZE_UDP;
msg_payload[size_payload] = '\0';
// XXX Process timestamp
struct timeval ut_tv = header.ts;
time_t t = (time_t)ut_tv.tv_sec;
time_t t = (time_t) ut_tv.tv_sec;
// XXX Get current time
char timestr[200];
@ -107,18 +119,19 @@ int load_pcap_file(const char* file) {
strftime(timestr, sizeof(timestr), "%Y/%m/%d %T", time);
// XXX Build a header string
sprintf(msg_header, "U %s.%06ld %s:%u -> %s:%u",
timestr, ut_tv.tv_usec,
inet_ntoa(ip->ip_src), htons(udp->udp_sport),
inet_ntoa(ip->ip_dst), htons(udp->udp_dport));
sprintf(msg_header, "U %s.%06ld", timestr, ut_tv.tv_usec);
sprintf(msg_header, "%s %s:%u", msg_header, inet_ntoa(ip->ip_src), htons(udp->udp_sport));
sprintf(msg_header, "%s -> %s:%u", msg_header, inet_ntoa(ip->ip_dst), htons(udp->udp_dport));
// Parse this header and payload
sip_parse_message(msg_header, (const char*)msg_payload);
sip_parse_message(msg_header, (const char*) msg_payload);
}
// Close PCAP file
pcap_close(handle);
gettimeofday(&tvEnd, NULL); // Grab ending time
long int diff = ((tvEnd.tv_usec + 1000000 * tvEnd.tv_sec) - (tvBegin.tv_usec + 1000000 * tvBegin.tv_sec)) / 1000;
long int diff = ((tvEnd.tv_usec + 1000000 * tvEnd.tv_sec) - (tvBegin.tv_usec + 1000000
* tvBegin.tv_sec)) / 1000;
printf("%d packages readed in %ld ms.\n", packagecnt, diff);
return 0;
}

View File

@ -40,19 +40,32 @@
/* IP data structure */
struct nread_ip
{
u_int8_t ip_vhl; /* header length, version */
u_int8_t ip_tos; /* type of service */
u_int16_t ip_len; /* total length */
u_int16_t ip_id; /* identification */
u_int16_t ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_int8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */
u_int16_t ip_sum; /* checksum */
struct in_addr ip_src, ip_dst; /* source and dest address */
//! header length, version
u_int8_t ip_vhl;
//! type of service
u_int8_t ip_tos;
//! total length
u_int16_t ip_len;
//! identification
u_int16_t ip_id;
//! fragment offset field
u_int16_t ip_off;
//! reserved fragment flag
#define IP_RF 0x8000
//! dont fragment flag
#define IP_DF 0x4000
//! more fragments flag
#define IP_MF 0x2000
//! mask for fragmenting bits
#define IP_OFFMASK 0x1fff
//! time to live
u_int8_t ip_ttl;
//! protocol
u_int8_t ip_p;
//! checksum
u_int16_t ip_sum;
//! source and dest addresses
struct in_addr ip_src, ip_dst;
};
#define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)
@ -61,10 +74,14 @@ struct nread_ip
/* UDP data structure */
struct nread_udp
{
u_short udp_sport; /* source port */
u_short udp_dport; /* destination port */
u_short udp_hlen; /* Udp header length*/
u_short udp_chksum; /* Udp Checksum */
//! source port
u_short udp_sport;
//! destination port
u_short udp_dport;
//! UDP header length
u_short udp_hlen;
//! UDP Checksum
u_short udp_chksum;
};
/**
@ -78,6 +95,7 @@ struct nread_udp
* @return 0 if load has been successfull, 1 otherwise
*
*/
int load_pcap_file(const char* file);
extern int
load_pcap_file(const char* file);
#endif

View File

@ -54,7 +54,8 @@ pthread_mutex_t calls_lock;
* @returns the message structure @sip_msg
*
*/
struct sip_msg *sip_parse_message(const char *header, const char *payload)
sip_msg_t *
sip_parse_message(const char *header, const char *payload)
{
char *callid;
struct sip_call *call;
@ -74,7 +75,7 @@ struct sip_msg *sip_parse_message(const char *header, const char *payload)
// Deallocate parsed callid
free(callid);
// Return the parsed structure
// Return the parsed structure
return call_add_message(call, header, payload);
}
@ -85,7 +86,8 @@ struct sip_msg *sip_parse_message(const char *header, const char *payload)
* @returns callid parsed from Call-ID header
* @note the returned pointer MUST be deallocated after use
*/
char *get_callid(const char* payload)
char *
get_callid(const char* payload)
{
char buffer[512];
char *pch, *callid = NULL;
@ -116,7 +118,8 @@ char *get_callid(const char* payload)
* @param callid Call-ID Header value
* @returns pointer to the sip_call created
*/
struct sip_call *call_new(const char *callid)
struct sip_call *
call_new(const char *callid)
{
// XXX LOCKING
struct sip_call *call = malloc(sizeof(struct sip_call));
@ -129,7 +132,8 @@ struct sip_call *call_new(const char *callid)
if (!calls) {
calls = call;
} else {
for (cur = calls; cur; prev = cur, cur = cur->next);
for (cur = calls; cur; prev = cur, cur = cur->next)
;
prev->next = call;
call->prev = prev;
}
@ -144,7 +148,8 @@ struct sip_call *call_new(const char *callid)
* @param header ngrep header generated by -qpt arguments
* @param payload SIP message payload
*/
struct sip_msg *call_add_message(struct sip_call *call, const char *header, const char *payload)
struct sip_msg *
call_add_message(struct sip_call *call, const char *header, const char *payload)
{
struct sip_msg *msg;
@ -164,8 +169,8 @@ struct sip_msg *call_add_message(struct sip_call *call, const char *header, cons
;
prev->next = msg;
}
return msg;
return msg;
}
/**
@ -176,10 +181,13 @@ struct sip_msg *call_add_message(struct sip_call *call, const char *header, cons
* @param header ngrep header generated by -qpt arguments
* @returns 0 on success, 1 on malformed header
*/
int msg_parse_header(struct sip_msg *msg, const char *header)
int
msg_parse_header(struct sip_msg *msg, const char *header)
{
struct tm when = { 0 };
struct tm when = {
0 };
char time[20];
if (sscanf(header, "U %d/%d/%d %d:%d:%d.%d %s -> %s", &when.tm_year, &when.tm_mon,
&when.tm_mday, &when.tm_hour, &when.tm_min, &when.tm_sec, (int*) &msg->ts.tv_usec,
msg->ip_from, msg->ip_to)) {
@ -209,7 +217,8 @@ int msg_parse_header(struct sip_msg *msg, const char *header)
* @param payload SIP message payload
* @returns 0 in all cases
*/
int msg_parse_payload(struct sip_msg *msg, const char *payload)
int
msg_parse_payload(struct sip_msg *msg, const char *payload)
{
char *body = strdup(payload);
char * pch;
@ -256,7 +265,8 @@ int msg_parse_payload(struct sip_msg *msg, const char *payload)
* @param xcallid X-Call-ID or X-CID Header value
* @returns pointer to the sip_call structure found or NULL
*/
struct sip_call *call_find_by_callid(const char *callid)
struct sip_call *
call_find_by_callid(const char *callid)
{
struct sip_call *cur = calls;
// XXX LOCKING
@ -274,7 +284,8 @@ struct sip_call *call_find_by_callid(const char *callid)
* @param callid Call-ID Header value
* @returns pointer to the sip_call structure found or NULL
*/
struct sip_call *call_find_by_xcallid(const char *xcallid)
struct sip_call *
call_find_by_xcallid(const char *xcallid)
{
struct sip_call *cur = calls;
// XXX LOCKING
@ -291,7 +302,8 @@ struct sip_call *call_find_by_xcallid(const char *xcallid)
*
* @returns how many calls are linked in the list
*/
int get_n_calls()
int
get_n_calls()
{
int callcnt = 0;
struct sip_call *call = calls;
@ -307,7 +319,8 @@ int get_n_calls()
*
* @returns how many messages are in the call
*/
int get_n_msgs(const struct sip_call *call)
int
get_n_msgs(const struct sip_call *call)
{
int msgcnt = 0;
struct sip_msg *msg = call->messages;
@ -328,7 +341,8 @@ int get_n_msgs(const struct sip_call *call)
* @param call SIP call structure
* @returns The other call structure or NULL if none found
*/
struct sip_call *get_ex_call(const struct sip_call *call)
struct sip_call *
get_ex_call(const struct sip_call *call)
{
if (strlen(call->xcallid)) {
return call_find_by_callid(call->xcallid);
@ -347,7 +361,8 @@ struct sip_call *get_ex_call(const struct sip_call *call)
*
* XXX This function must be recoded if message linked list is not sorted
*/
struct sip_msg *get_next_msg(const struct sip_call *call, const struct sip_msg *msg)
struct sip_msg *
get_next_msg(const struct sip_call *call, const struct sip_msg *msg)
{
if (msg == NULL) {
return call->messages;
@ -366,7 +381,8 @@ struct sip_msg *get_next_msg(const struct sip_call *call, const struct sip_msg *
*
* XXX This function must be recoded if message linked list is not sorted
*/
struct sip_msg *get_next_msg_ex(const struct sip_call *call, const struct sip_msg *msg)
struct sip_msg *
get_next_msg_ex(const struct sip_call *call, const struct sip_msg *msg)
{
struct sip_msg *msg1 = NULL, *msg2 = NULL;
@ -407,17 +423,17 @@ struct sip_msg *get_next_msg_ex(const struct sip_call *call, const struct sip_ms
}
}
sip_msg_t *parse_msg(sip_msg_t *msg){
sip_msg_t *
parse_msg(sip_msg_t *msg)
{
// Nothing to parse
if (!msg)
return NULL;
if (!msg) return NULL;
// Message already parsed
if (msg->parsed)
return msg;
if (msg->parsed) return msg;
// Parse message header
// Parse message header
if (msg_parse_header(msg, msg->headerptr) != 0) {
return NULL;
}

View File

@ -41,24 +41,36 @@ typedef struct sip_msg sip_msg_t;
*/
struct sip_msg
{
char date[9]; // FIXME for capturing at midnight?
char time[18]; // FIXME this can be calculated
char ip_from[22]; // Address including port
char ip_to[22]; // Address including port
//! FIXME for capturing at midnight?
char date[9];
//! FIXME this can be calculated
char time[18];
//! From Address including port
char ip_from[22];
//! To Address including port
char ip_to[22];
char sip_from[256];
char sip_to[256];
char type[40];
int cseq;
time_t timet; // FIXME not required
//! FIXME not required
time_t timet;
struct timeval ts;
//! Temporal header data before being parsed
char *headerptr;
//! Temporal payload data before being parsed
char *payloadptr;
const char *payload[80]; // FIXME Payload in one struct
int plines; // FIXME not required
int parsed; // Flag to mark if payload data has been parsed
//! FIXME Payload in one struct
const char *payload[80];
//!! FIXME not required
int plines;
//! Flag to mark if payload data has been parsed
int parsed;
struct sip_call *call; /* Message owner */
struct sip_msg *next; /* Messages linked list */
//! Message owner
struct sip_call *call;
//! Messages linked list
struct sip_msg *next;
};
/**
@ -94,7 +106,8 @@ struct sip_call
* @returns the message structure @sip_msg or NULL if parsed failed
*
*/
struct sip_msg *sip_parse_message(const char *header, const char *payload);
extern sip_msg_t *
sip_parse_message(const char *header, const char *payload);
/**
* Parses Call-ID header of a SIP message payload
@ -103,7 +116,8 @@ struct sip_msg *sip_parse_message(const char *header, const char *payload);
* @returns callid parsed from Call-ID header
* @note the returned pointer MUST be deallocated after use
*/
char *get_callid(const char* payload);
extern char *
get_callid(const char* payload);
/**
* Create a new call with the given callid (Minimum required data)
@ -111,7 +125,8 @@ char *get_callid(const char* payload);
* @param callid Call-ID Header value
* @returns pointer to the sip_call created
*/
struct sip_call *call_new(const char *callid);
extern sip_call_t *
call_new(const char *callid);
/**
* Parse the ngrep header and payload and add the result message
@ -122,7 +137,8 @@ struct sip_call *call_new(const char *callid);
* @param payload SIP message payload
* @retursn the message structure or NULL if parsed failed
*/
struct sip_msg *call_add_message(struct sip_call *call, const char *header, const char *payload);
extern sip_msg_t *
call_add_message(sip_call_t *call, const char *header, const char *payload);
/**
* Parse ngrep header line to get timestamps and ip addresses
@ -132,7 +148,8 @@ struct sip_msg *call_add_message(struct sip_call *call, const char *header, cons
* @param header ngrep header generated by -qpt arguments
* @returns 0 on success, 1 on malformed header
*/
int msg_parse_header(struct sip_msg *msg, const char *header);
extern int
msg_parse_header(sip_msg_t *msg, const char *header);
/**
* Parse SIP Message payload to fill sip_msg structe
@ -141,7 +158,8 @@ int msg_parse_header(struct sip_msg *msg, const char *header);
* @param payload SIP message payload
* @returns 0 in all cases
*/
int msg_parse_payload(struct sip_msg *msg, const char *payload);
extern int
msg_parse_payload(sip_msg_t *msg, const char *payload);
/**
* Find a call structure in calls linked list given an xcallid
@ -149,7 +167,8 @@ int msg_parse_payload(struct sip_msg *msg, const char *payload);
* @param xcallid X-Call-ID or X-CID Header value
* @returns pointer to the sip_call structure found or NULL
*/
struct sip_call *call_find_by_xcallid(const char *xcallid);
extern sip_call_t *
call_find_by_xcallid(const char *xcallid);
/**
* Find a call structure in calls linked list given an callid
@ -157,21 +176,24 @@ struct sip_call *call_find_by_xcallid(const char *xcallid);
* @param callid Call-ID Header value
* @returns pointer to the sip_call structure found or NULL
*/
struct sip_call *call_find_by_callid(const char *callid);
extern sip_call_t *
call_find_by_callid(const char *callid);
/**
* Getter for calls linked list size
*
* @returns how many calls are linked in the list
*/
int get_n_calls();
extern int
get_n_calls();
/**
* Getter for call messages linked list size
*
* @returns how many messages are in the call
*/
int get_n_msgs(const struct sip_call *call);
extern int
get_n_msgs(const sip_call_t *call);
/**
* Finds the other leg of this call.
@ -183,7 +205,8 @@ int get_n_msgs(const struct sip_call *call);
* @param call SIP call structure
* @returns The other call structure or NULL if none found
*/
struct sip_call *get_ex_call(const struct sip_call *call);
extern sip_call_t *
get_ex_call(const sip_call_t *call);
/**
* Finds the next msg in a call. If the passed msg is
@ -192,7 +215,8 @@ struct sip_call *get_ex_call(const struct sip_call *call);
* @param msg Actual SIP msg from the call (can be NULL)
* @returns Next chronological message in the call
*/
struct sip_msg *get_next_msg(const struct sip_call *call, const struct sip_msg *msg);
extern sip_msg_t *
get_next_msg(const sip_call_t *call, const sip_msg_t *msg);
/**
* Finds the next msg in call and it's extended. If the passed msg is
@ -203,8 +227,10 @@ struct sip_msg *get_next_msg(const struct sip_call *call, const struct sip_msg *
* @returns Next chronological message in the conversation
*
*/
struct sip_msg *get_next_msg_ex(const struct sip_call *call, const struct sip_msg *msg);
extern sip_msg_t *
get_next_msg_ex(const sip_call_t *call, const sip_msg_t *msg);
sip_msg_t *parse_msg(sip_msg_t *msg);
extern sip_msg_t *
parse_msg(sip_msg_t *msg);
#endif

View File

@ -23,6 +23,7 @@
#include <string.h>
#include "ui_manager.h"
#include "ui_call_flow.h"
#include "ui_call_flow_ex.h"
#include "ui_call_raw.h"
/**
@ -30,7 +31,8 @@
* This data stores the actual status of the panel. It's stored in the
* PANEL user pointer.
*/
PANEL *call_flow_create()
PANEL *
call_flow_create()
{
PANEL *panel;
WINDOW *win;
@ -53,15 +55,15 @@ PANEL *call_flow_create()
info->linescnt = height - 10;
// Window borders
wattron(win,COLOR_PAIR(DETAIL_BORDER_COLOR));
wattron(win, COLOR_PAIR(DETAIL_BORDER_COLOR));
title_foot_box(win);
mvwaddch(win, 2, 61, ACS_TTEE);
mvwvline(win, 3, 61, ACS_VLINE, height - 6);
mvwaddch(win, 4, 0, ACS_LTEE);
mvwhline(win, 4, 1, ACS_HLINE, 61);
mvwaddch(win, 4, 61, ACS_RTEE);
mvwaddch(win, height-3, 61, ACS_BTEE);
wattroff(win,COLOR_PAIR(DETAIL_BORDER_COLOR));
mvwaddch(win, height - 3, 61, ACS_BTEE);
wattroff(win, COLOR_PAIR(DETAIL_BORDER_COLOR));
// Callflow box title
mvwprintw(win, 3, 30, "Call Flow");
@ -70,23 +72,38 @@ PANEL *call_flow_create()
mvwaddch(win, 6, 20, ACS_TTEE);
mvwaddch(win, 6, 50, ACS_TTEE);
mvwprintw(win, height - 2, 2, "Q/Esc: Quit");
mvwprintw(win, height - 2, 16, "F1: Show help");
mvwprintw(win, height - 2, 32, "X: Show Extendend");
mvwprintw(win, height - 2, 2, "Q/Esc: Quit");
mvwprintw(win, height - 2, 16, "F1: Help");
mvwprintw(win, height - 2, 27, "X: Call-Flow Extended");
return panel;
}
void call_flow_destroy(PANEL *panel)
int
call_flow_redraw_required(PANEL *panel, sip_msg_t *msg)
{
// Get panel information
call_flow_info_t *info;
// Check we have panel info
if (!(info = (call_flow_info_t*) panel_userptr(panel))) return -1;
// If this message belongs to first call
if (msg->call == info->call) return 0;
return -1;
}
void
call_flow_destroy(PANEL *panel)
{
call_flow_info_t *info;
// Hide the panel
hide_panel(panel);
// Free the panel information
if ((info = (call_flow_info_t*)panel_userptr(panel)))
free(info);
if ((info = (call_flow_info_t*) panel_userptr(panel))) free(info);
// Delete panel window
delwin(panel_window(panel));
@ -94,7 +111,8 @@ void call_flow_destroy(PANEL *panel)
del_panel(panel);
}
int call_flow_draw(PANEL *panel)
int
call_flow_draw(PANEL *panel)
{
int i, height, width, cline, msgcnt, startpos = 7;
sip_msg_t *msg;
@ -135,7 +153,7 @@ int call_flow_draw(PANEL *panel)
//}
// Check if there are still 2 spaces for this message in the list
if (cline >= info->linescnt + startpos ) {
if (cline >= info->linescnt + startpos) {
// Draw 2 arrow to show there are more messages
mvwaddch(win, info->linescnt + startpos - 1, 20, ACS_DARROW);
mvwaddch(win, info->linescnt + startpos - 1, 50, ACS_DARROW);
@ -145,7 +163,7 @@ int call_flow_draw(PANEL *panel)
// Print timestamp
mvwprintw(win, cline, 2, "%s", msg->time);
if (msg == info->cur_msg) wattron(win,A_REVERSE);
if (msg == info->cur_msg) wattron(win, A_REVERSE);
// Determine the message direction
if (!strcmp(msg->ip_from, from)) {
@ -171,7 +189,7 @@ int call_flow_draw(PANEL *panel)
// One message fills 2 lines
cline += 2;
}
}
// Clean the message area
for (cline = 3, i = 0; i < info->linescnt + 4; i++)
@ -179,13 +197,14 @@ int call_flow_draw(PANEL *panel)
// Print the message payload in the right side of the screen
for (cline = 3, i = 0; i < info->cur_msg->plines && i < info->linescnt + 4; i++)
mvwprintw(win, cline++, 62, "%.*s", width - 63, info->cur_msg->payload[i]);
mvwprintw(win, cline++, 62, "%.*s", width - 63, info->cur_msg->payload[i]);
return 0;
}
int call_flow_handle_key(PANEL *panel, int key)
int
call_flow_handle_key(PANEL *panel, int key)
{
int i, rnpag_steps = 4;
call_flow_info_t *info = (call_flow_info_t*) panel_userptr(panel);
@ -198,8 +217,7 @@ int call_flow_handle_key(PANEL *panel, int key)
switch (key) {
case KEY_DOWN:
// Check if there is a call below us
if (!(next = get_next_msg(info->call, info->cur_msg)))
break;
if (!(next = get_next_msg(info->call, info->cur_msg))) break;
info->cur_msg = next;
info->cur_line += 2;
// If we are out of the bottom of the displayed list
@ -212,35 +230,40 @@ int call_flow_handle_key(PANEL *panel, int key)
case KEY_UP:
// FIXME We start searching from the fist one
// FIXME This wont work well with a lot of msg
while ((prev = get_next_msg(info->call, prev))){
if (prev->next == info->cur_msg)
break;
}
while ((prev = get_next_msg(info->call, prev))) {
if (prev->next == info->cur_msg) break;
}
// We're at the first message already
if (!prev) break;
info->cur_msg = prev;
info->cur_line -= 2;
if ( info->cur_line <= 0 ){
if (info->cur_line <= 0) {
info->first_msg = info->cur_msg;
info->cur_line = 1;
info->cur_line = 1;
}
break;
case KEY_NPAGE:
// Next page => N key down strokes
for (i=0; i < rnpag_steps; i++)
for (i = 0; i < rnpag_steps; i++)
call_flow_handle_key(panel, KEY_DOWN);
break;
case KEY_PPAGE:
// Prev page => N key up strokes
for (i=0; i < rnpag_steps; i++)
for (i = 0; i < rnpag_steps; i++)
call_flow_handle_key(panel, KEY_UP);
break;
case 10:
case 'x':
if (!info->call) return -1;
if (!get_ex_call(info->call)) return -1;
// KEY_ENTER , Display current call flow
next_panel = ui_create(ui_find_by_type(DETAILS_EX_PANEL));
call_flow_ex_set_call(info->call);
ui_set_replace(ui_find_by_panel(panel), next_panel);
break;
case 'r':
case 'R':
// KEY_R, display current call in raw mode
next_panel = ui_create(RAW_PANEL);
next_panel = ui_create(ui_find_by_type(RAW_PANEL));
call_raw_set_call(info->call);
wait_for_input(next_panel);
default:
@ -250,28 +273,26 @@ int call_flow_handle_key(PANEL *panel, int key)
return 0;
}
int call_flow_help(PANEL *panel)
int
call_flow_help(PANEL *panel)
{
return 0;
}
int call_flow_set_call(sip_call_t *call) {
int
call_flow_set_call(sip_call_t *call)
{
ui_t *flow_panel;
PANEL *panel;
call_flow_info_t *info;
if (!call)
return -1;
if (!call) return -1;
if (!(flow_panel = ui_find_by_type(DETAILS_PANEL)))
return -1;
if (!(panel = flow_panel->panel))
return -1;
if (!(flow_panel = ui_find_by_type(DETAILS_PANEL))) return -1;
if (!(info = (call_flow_info_t*) panel_userptr(panel)))
return -1;
if (!(panel = flow_panel->panel)) return -1;
if (!(info = (call_flow_info_t*) panel_userptr(panel))) return -1;
info->call = call;
info->cur_msg = info->first_msg = call->messages;

View File

@ -32,7 +32,8 @@ typedef struct call_flow_info call_flow_info_t;
* This data stores the actual status of the panel. It's stored in the
* PANEL user pointer.
*/
struct call_flow_info {
struct call_flow_info
{
sip_call_t *call;
sip_msg_t *first_msg;
sip_msg_t *cur_msg;
@ -40,11 +41,19 @@ struct call_flow_info {
int cur_line;
};
extern PANEL *call_flow_create();
extern void call_flow_destroy(PANEL *panel);
extern int call_flow_draw(PANEL *panel);
extern int call_flow_handle_key(PANEL *panel, int key);
extern int call_flow_help(PANEL *panel);
extern int call_flow_set_call(sip_call_t *call);
extern PANEL *
call_flow_create();
extern void
call_flow_destroy(PANEL *panel);
extern int
call_flow_redraw_required(PANEL *panel, sip_msg_t *msg);
extern int
call_flow_draw(PANEL *panel);
extern int
call_flow_handle_key(PANEL *panel, int key);
extern int
call_flow_help(PANEL *panel);
extern int
call_flow_set_call(sip_call_t *call);
#endif

View File

@ -19,35 +19,130 @@
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "ui_manager.h"
#include "ui_call_flow.h"
#include "ui_call_flow_ex.h"
#include "ui_call_raw.h"
struct sip_call *active_call;
PANEL *call_flow_ex_create()
/**
* @brief Call flow status information
* This data stores the actual status of the panel. It's stored in the
* PANEL user pointer.
*/
PANEL *
call_flow_ex_create()
{
PANEL *panel = new_panel(newwin(LINES, COLS, 0, 0));
return panel;
PANEL *panel;
WINDOW *win;
int height, width;
call_flow_ex_info_t *info;
// Create a new panel to fill all the screen
panel = new_panel(newwin(LINES, COLS, 0, 0));
// Initialize Call List specific data
info = malloc(sizeof(call_flow_ex_info_t));
memset(info, 0, sizeof(call_flow_ex_info_t));
// Store it into panel userptr
set_panel_userptr(panel, (void*) info);
// Let's draw the fixed elements of the screen
win = panel_window(panel);
getmaxyx(win, height, width);
// Calculate available printable area
info->linescnt = height - 10;
// Window borders
wattron(win, COLOR_PAIR(DETAIL_BORDER_COLOR));
title_foot_box(win);
mvwaddch(win, 2, 91, ACS_TTEE);
mvwvline(win, 3, 91, ACS_VLINE, height - 6);
mvwaddch(win, 4, 0, ACS_LTEE);
mvwhline(win, 4, 1, ACS_HLINE, 91);
mvwaddch(win, 4, 91, ACS_RTEE);
mvwaddch(win, height - 3, 91, ACS_BTEE);
wattroff(win, COLOR_PAIR(DETAIL_BORDER_COLOR));
// Callflow box title
mvwprintw(win, 3, 40, "Call Flow Extended");
mvwhline(win, 6, 11, ACS_HLINE, 20);
mvwhline(win, 6, 40, ACS_HLINE, 20);
mvwhline(win, 6, 70, ACS_HLINE, 20);
mvwaddch(win, 6, 20, ACS_TTEE);
mvwaddch(win, 6, 50, ACS_TTEE);
mvwaddch(win, 6, 80, ACS_TTEE);
// Make the vertical lines for messages (2 lines per message + extra space)
mvwvline(win, 7, 20, ACS_VLINE, info->linescnt);
mvwvline(win, 7, 50, ACS_VLINE, info->linescnt);
mvwvline(win, 7, 80, ACS_VLINE, info->linescnt);
mvwprintw(win, height - 2, 2, "Q/Esc: Quit");
mvwprintw(win, height - 2, 16, "F1: Help");
mvwprintw(win, height - 2, 27, "X: Call-Flow");
return panel;
}
int call_flow_ex_draw(PANEL *panel)
int
call_flow_ex_redraw_required(PANEL *panel, sip_msg_t *msg)
{
int w, h, fw, fh, rw, rh, ph;
int msgcnt = 0;
int padpos, highlight;
// Get panel information
call_flow_ex_info_t *info;
// This panel only makes sense with a selected call
if (!active_call) return 1;
// Check we have panel info
if (!(info = (call_flow_ex_info_t*) panel_userptr(panel))) return -1;
// If this message belongs to first call
if (msg->call == info->call)
return 0;
// If this message belongs to second call
if (msg->call == info->call2)
return 0;
return -1;
}
void
call_flow_ex_destroy(PANEL *panel)
{
call_flow_ex_info_t *info;
// Hide the panel
hide_panel(panel);
// Free the panel information
if ((info = (call_flow_ex_info_t*) panel_userptr(panel))) free(info);
// Delete panel window
delwin(panel_window(panel));
// Delete panel
del_panel(panel);
}
int
call_flow_ex_draw(PANEL *panel)
{
int i, height, width, cline, msgcnt, startpos = 7;
sip_msg_t *msg;
sip_call_t *call, *call2;
// Get panel information
call_flow_ex_info_t *info = (call_flow_ex_info_t*) panel_userptr(panel);
call = info->call;
call2 = info->call2;
// This panel only makes sense with a selected call with extended xcallid
if (!call || !call2) return 1;
// Get window of main panel
WINDOW *win = panel_window(panel);
msgcnt = get_n_msgs(call) + get_n_msgs(call2);
// Get other call data
struct sip_call *call = active_call;
struct sip_call *call2 = get_ex_call(call);
if (!call2) return 1;
// Get data from first message
const char *from, *to, *via;
const char *callid1, *callid2;
@ -67,154 +162,172 @@ int call_flow_ex_draw(PANEL *panel)
}
// Get window size
getmaxyx(win, h, w);
// Get flow size
fw = 95;
fh = h - 3 - 3;
// Get the raw size
rw = w - fw - 2;
rh = h - 3 - 3;
// Window borders
wattron(win,COLOR_PAIR(DETAIL_BORDER_COLOR));
title_foot_box(win);
mvwaddch(win, 2, fw, ACS_TTEE);
mvwvline(win, 3, fw, ACS_VLINE, fh);
mvwaddch(win, 4, 0, ACS_LTEE);
mvwhline(win, 4, 1, ACS_HLINE, fw);
mvwaddch(win, 4, fw, ACS_RTEE);
mvwaddch(win, 3+fh, fw, ACS_BTEE);
wattroff(win,COLOR_PAIR(DETAIL_BORDER_COLOR));
getmaxyx(win, height, width);
// Window title
mvwprintw(win, 1, (w - 45) / 2, "Call Details for %s", call->callid);
// Callflow box title
mvwprintw(win, 3, 40, "Call Flow Extended");
mvwprintw(win, 1, (width - 45) / 2, "Call Details for %s -> %s", call->callid, call2->callid);
// Hosts and lines in callflow
mvwprintw(win, 5, 13, "%-22s", from);
mvwprintw(win, 5, 42, "%-22s", via);
mvwprintw(win, 5, 72, "%-22s", to);
mvwhline(win, 6, 11, ACS_HLINE, 20);
mvwhline(win, 6, 40, ACS_HLINE, 20);
mvwhline(win, 6, 70, ACS_HLINE, 20);
mvwaddch(win, 6, 20, ACS_TTEE);
mvwaddch(win, 6, 50, ACS_TTEE);
mvwaddch(win, 6, 80, ACS_TTEE);
mvwprintw(win, h - 2, 2,
"Q: Quit C: Toggle color F: Show raw messages X: Show Call-Flow");
mvwprintw(win, 5, 7, "%22s", from);
mvwprintw(win, 5, 37, "%22s", via);
mvwprintw(win, 5, 67, "%22s", to);
int msgcntex = get_n_msgs(call) + get_n_msgs(call2);
// Make the pad long enough to contain all messages and some extra space
WINDOW *flow_pad = newpad(fh + msgcntex * 2, fw);
mvwvline(flow_pad, 0, 20, ACS_VLINE, fh+msgcntex*2);
mvwvline(flow_pad, 0, 50, ACS_VLINE, fh+msgcntex*2);
mvwvline(flow_pad, 0, 80, ACS_VLINE, fh+msgcntex*2);
// Make a pad for sip message
WINDOW *raw_pad = newpad(rh, rw);
struct sip_msg *msg = NULL;
int cline = 0;
while ((msg = get_next_msg_ex(call, msg))) {
msgcnt++;
// Set raw content for selected text
if (msgcnt == highlight) {
int raw_line = 0, pcount = 0;
for (raw_line = 0; raw_line < msg->plines; raw_line++, pcount++) {
mvwprintw(raw_pad, pcount, 0, "%.*s", rw, msg->payload[raw_line]);
}
for (cline = startpos, msg = info->first_msg; msg; msg = get_next_msg_ex(info->call, msg)) {
// Check if there are still 2 spaces for this message in the list
if (cline >= info->linescnt + startpos) {
// Draw 2 arrow to show there are more messages
mvwaddch(win, info->linescnt + startpos - 1, 20, ACS_DARROW);
mvwaddch(win, info->linescnt + startpos - 1, 50, ACS_DARROW);
break;
}
// Print timestamp
mvwprintw(flow_pad, cline, 2, "%s", msg->time);
mvwprintw(win, cline, 2, "%s", msg->time);
if (msgcnt == highlight) wattron(flow_pad,A_REVERSE);
if (msg == info->cur_msg) wattron(win, A_REVERSE);
// Draw message type or status and line
int msglen = strlen(msg->type);
if (msglen > 24) msglen = 24;
// Determine the message direction
if (!strcmp(msg->call->callid, callid1) && !strcmp(msg->ip_from, from)) {
wattron(flow_pad,COLOR_PAIR(OUTGOING_COLOR));
mvwprintw(flow_pad, cline, 22, "%26s", "");
mvwprintw(flow_pad, cline++, 22 + (24 - msglen) / 2, "%.24s", msg->type);
mvwhline(flow_pad, cline, 22, ACS_HLINE, 26);
mvwaddch(flow_pad, cline++, 47, ACS_RARROW);
wattron(win, COLOR_PAIR(OUTGOING_COLOR));
mvwprintw(win, cline, 22, "%26s", "");
mvwprintw(win, cline, 22 + (24 - msglen) / 2, "%.24s", msg->type);
mvwhline(win, cline + 1, 22, ACS_HLINE, 26);
mvwaddch(win, cline + 1, 47, ACS_RARROW);
} else if (!strcmp(msg->call->callid, callid1) && !strcmp(msg->ip_to, from)) {
wattron(flow_pad,COLOR_PAIR(INCOMING_COLOR));
mvwprintw(flow_pad, cline, 22, "%26s", "");
mvwprintw(flow_pad, cline++, 22 + (24 - msglen) / 2, "%.24s", msg->type);
mvwhline(flow_pad, cline, 22, ACS_HLINE, 26);
mvwaddch(flow_pad, cline++, 22, ACS_LARROW);
wattron(win, COLOR_PAIR(INCOMING_COLOR));
mvwprintw(win, cline, 22, "%26s", "");
mvwprintw(win, cline, 22 + (24 - msglen) / 2, "%.24s", msg->type);
mvwhline(win, cline + 1, 22, ACS_HLINE, 26);
mvwaddch(win, cline + 1, 22, ACS_LARROW);
} else if (!strcmp(msg->call->callid, callid2) && !strcmp(msg->ip_from, via)) {
wattron(flow_pad,COLOR_PAIR(OUTGOING_COLOR));
mvwprintw(flow_pad, cline, 52, "%26s", "");
mvwprintw(flow_pad, cline++, 54 + (24 - msglen) / 2, "%.24s", msg->type);
mvwhline(flow_pad, cline, 52, ACS_HLINE, 26);
mvwaddch(flow_pad, cline++, 77, ACS_RARROW);
wattron(win, COLOR_PAIR(OUTGOING_COLOR));
mvwprintw(win, cline, 52, "%26s", "");
mvwprintw(win, cline, 54 + (24 - msglen) / 2, "%.24s", msg->type);
mvwhline(win, cline + 1, 52, ACS_HLINE, 26);
mvwaddch(win, cline + 1, 77, ACS_RARROW);
} else {
wattron(flow_pad,COLOR_PAIR(INCOMING_COLOR));
mvwprintw(flow_pad, cline, 52, "%26s", "");
mvwprintw(flow_pad, cline++, 54 + (24 - msglen) / 2, "%.24s", msg->type);
mvwhline(flow_pad, cline, 52, ACS_HLINE, 26);
mvwaddch(flow_pad, cline++, 52, ACS_LARROW);
wattron(win, COLOR_PAIR(INCOMING_COLOR));
mvwprintw(win, cline, 52, "%26s", "");
mvwprintw(win, cline, 54 + (24 - msglen) / 2, "%.24s", msg->type);
mvwhline(win, cline + 1, 52, ACS_HLINE, 26);
mvwaddch(win, cline + 1, 52, ACS_LARROW);
}
wattroff(flow_pad,COLOR_PAIR(OUTGOING_COLOR));
wattroff(flow_pad,COLOR_PAIR(INCOMING_COLOR));
wattroff(flow_pad, A_REVERSE);
// Turn off colors
wattroff(win, COLOR_PAIR(OUTGOING_COLOR));
wattroff(win, COLOR_PAIR(INCOMING_COLOR));
wattroff(win, A_REVERSE);
// One message fills 2 lines
cline += 2;
}
/* Calculate the space the pad will be covering in the screen */
ph = fh - 3 /* CF header */- 2 /* Addresses */;
/* Make it even */
ph -= ph % 2;
// Clean the message area
for (cline = 3, i = 0; i < info->linescnt + 4; i++)
mvwprintw(win, cline++, 92, "%*s", width - 93, "");
/* Calculate the highlight position */
// The highlight position is below the last displayed position?
if (highlight * 2 > ph + padpos) {
// Scrolling down
padpos += 2;
// The highlight position is above the first displayed position?
} else if (highlight * 2 <= padpos) {
// Scroll up
padpos -= 2;
}
/* Draw some fancy arrow to indicate scrolling */
if (padpos > 0) {
mvwaddch(flow_pad, padpos, 20, ACS_UARROW);
mvwaddch(flow_pad, padpos, 50, ACS_UARROW);
mvwaddch(flow_pad, padpos, 80, ACS_UARROW);
}
if (msgcntex * 2 > ph + padpos) {
mvwaddch(flow_pad, ph+padpos-1, 20, ACS_DARROW);
mvwaddch(flow_pad, ph+padpos-1, 50, ACS_DARROW);
mvwaddch(flow_pad, ph+padpos-1, 80, ACS_DARROW);
}
// Copy the callflow into the screen
copywin(flow_pad, win, padpos, 1, 3 + 2 + 2, 1, 6 + ph, fw - 1, false);
delwin(flow_pad);
// Copy the rawmessage into the screen
copywin(raw_pad, win, 0, 0, 3, fw + 1, rh, fw + rw, false);
delwin(raw_pad);
// Print the message payload in the right side of the screen
for (cline = 3, i = 0; i < info->cur_msg->plines && i < info->linescnt + 4; i++)
mvwprintw(win, cline++, 92, "%.*s", width - 93, info->cur_msg->payload[i]);
return 0;
}
int call_flow_ex_handle_key(PANEL *panel, char key)
int
call_flow_ex_handle_key(PANEL *panel, int key)
{
return 0;
int i, rnpag_steps = 4;
call_flow_ex_info_t *info = (call_flow_ex_info_t*) panel_userptr(panel);
sip_msg_t *next = NULL, *prev = NULL;
ui_t *next_panel;
// Sanity check, this should not happen
if (!info) return -1;
switch (key) {
case KEY_DOWN:
// Check if there is a call below us
if (!(next = get_next_msg_ex(info->call, info->cur_msg))) break;
info->cur_msg = next;
info->cur_line += 2;
// If we are out of the bottom of the displayed list
// refresh it starting in the next call
if (info->cur_line > info->linescnt) {
info->first_msg = get_next_msg_ex(info->call, info->first_msg);
info->cur_line = info->linescnt;
}
break;
case KEY_UP:
// FIXME We start searching from the fist one
// FIXME This wont work well with a lot of msg
while ((next = get_next_msg_ex(info->call, next))) {
if (next == info->cur_msg) break;
prev = next;
}
// We're at the first message already
if (!prev) break;
info->cur_msg = prev;
info->cur_line -= 2;
if (info->cur_line <= 0) {
info->first_msg = info->cur_msg;
info->cur_line = 1;
}
break;
case KEY_NPAGE:
// Next page => N key down strokes
for (i = 0; i < rnpag_steps; i++)
call_flow_ex_handle_key(panel, KEY_DOWN);
break;
case KEY_PPAGE:
// Prev page => N key up strokes
for (i = 0; i < rnpag_steps; i++)
call_flow_ex_handle_key(panel, KEY_UP);
break;
case 'x':
if (!info->call) return -1;
// KEY_ENTER , Display current call flow
next_panel = ui_create(ui_find_by_type(DETAILS_PANEL));
call_flow_set_call(info->call);
ui_set_replace(ui_find_by_panel(panel), next_panel);
break;
case 'r':
case 'R':
// KEY_R, display current call in raw mode
next_panel = ui_create(ui_find_by_type(RAW_PANEL));
call_raw_set_call(info->call);
wait_for_input(next_panel);
default:
return -1;
}
return 0;
}
int call_flow_ex_help(PANEL *panel)
int
call_flow_ex_help(PANEL *panel)
{
return 0;
return 0;
}
int
call_flow_ex_set_call(sip_call_t *call)
{
PANEL *panel;
call_flow_ex_info_t *info;
if (!call) return -1;
if (!(panel = ui_get_panel(ui_find_by_type(DETAILS_EX_PANEL)))) return -1;
if (!(info = (call_flow_ex_info_t*) panel_userptr(panel))) return -1;
info->call = call;
info->call2 = get_ex_call(call);
info->cur_msg = info->first_msg = get_next_msg_ex(call, NULL);
info->cur_line = 1;
return 0;
}

View File

@ -19,13 +19,42 @@
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#ifndef __UI_CALL_flow_ex_EX_H
#define __UI_CALL_flow_ex_EX_H
#ifndef __UI_CALL_flow_ex_H
#define __UI_CALL_flow_ex_H
#include "sip.h"
#include "ui_manager.h"
extern PANEL *call_flow_ex_create();
extern int call_flow_ex_draw(PANEL *panel);
extern int call_flow_ex_handle_key(PANEL *panel, char key);
extern int call_flow_ex_help(PANEL *panel);
//! Sorter declaration of struct call_flow_ex_info
typedef struct call_flow_ex_info call_flow_ex_info_t;
/**
* @brief Call flow status information
* This data stores the actual status of the panel. It's stored in the
* PANEL user pointer.
*/
struct call_flow_ex_info
{
sip_call_t *call;
sip_call_t *call2;
sip_msg_t *first_msg;
sip_msg_t *cur_msg;
int linescnt;
int cur_line;
};
extern PANEL *
call_flow_ex_create();
extern void
call_flow_ex_destroy(PANEL *panel);
extern int
call_flow_ex_redraw_required(PANEL *panel, sip_msg_t *msg);
extern int
call_flow_ex_draw(PANEL *panel);
extern int
call_flow_ex_handle_key(PANEL *panel, int key);
extern int
call_flow_ex_help(PANEL *panel);
extern int
call_flow_ex_set_call(sip_call_t *call);
#endif

View File

@ -24,18 +24,20 @@
#include <string.h>
#include "ui_call_list.h"
#include "ui_call_flow.h"
#include "ui_call_flow_ex.h"
#include "ui_call_raw.h"
#include "sip.h"
// FIXME create a getter function for this at sip.c
extern struct sip_call *calls;
PANEL *call_list_create()
PANEL *
call_list_create()
{
PANEL *panel;
WINDOW *win;
int height, width, i, colpos;
call_list_info_t *info;
call_list_info_t *info;
// Create a new panel that fill all the screen
panel = new_panel(newwin(LINES, COLS, 0, 0));
@ -46,12 +48,12 @@ PANEL *call_list_create()
set_panel_userptr(panel, (void*) info);
// Set default columns. One day this will be configurable
call_list_add_column( panel, 0, "From SIP", 40);
call_list_add_column( panel, 1, "To SIP", 40);
call_list_add_column( panel, 2, "Msg", 5);
call_list_add_column( panel, 3, "From", 22);
call_list_add_column( panel, 4, "To", 22);
call_list_add_column( panel, 5, "Starting", 15);
call_list_add_column(panel, 0, "From SIP", 40);
call_list_add_column(panel, 1, "To SIP", 40);
call_list_add_column(panel, 2, "Msg", 5);
call_list_add_column(panel, 3, "From", 22);
call_list_add_column(panel, 4, "To", 22);
call_list_add_column(panel, 5, "Starting", 15);
// Let's draw the fixed elements of the screen
win = panel_window(panel);
@ -59,7 +61,7 @@ PANEL *call_list_create()
// Calculate available printable area
info->linescnt = height - 11;
// Draw a box arround the window
title_foot_box(win);
@ -72,12 +74,12 @@ PANEL *call_list_create()
mvwaddch(win, 7, 0, ACS_LTEE);
mvwhline(win, 7, 1, ACS_HLINE, width - 2);
mvwaddch(win, 7, width - 1, ACS_RTEE);
mvwprintw(win, height - 2, 2, "Q/Esc: Quit");
mvwprintw(win, height - 2, 16, "F1: Show help");
mvwprintw(win, height - 2, 32, "Enter: Show Call-flow");
mvwprintw(win, height - 2, 2, "Q/Esc: Quit");
mvwprintw(win, height - 2, 16, "F1: Help");
mvwprintw(win, height - 2, 27, "X: Call-Flow Extended");
// Draw columns titles
for (colpos = 5, i = 0; i < info->columncnt; i++){
for (colpos = 5, i = 0; i < info->columncnt; i++) {
// Check if the column will fit in the remaining space of the screen
if (colpos + info->columns[i].width >= width) break;
mvwprintw(win, 6, colpos, info->columns[i].title);
@ -87,7 +89,14 @@ PANEL *call_list_create()
return panel;
}
int call_list_draw(PANEL *panel)
int
call_list_redraw_required(PANEL *panel, sip_msg_t *msg)
{
return 0;
}
int
call_list_draw(PANEL *panel)
{
int height, width, i, colpos, collen, startline = 8;
struct sip_call *call;
@ -98,8 +107,7 @@ int call_list_draw(PANEL *panel)
if (!info) return -1;
// Get available calls counter (we'll use it here a couple of times)
if (!(callcnt = get_n_calls()))
return -1;
if (!(callcnt = get_n_calls())) return 0;
// If no active call, use the fist one (if exists)
if (!info->first_call && calls) {
@ -115,36 +123,46 @@ int call_list_draw(PANEL *panel)
int cline = startline;
for (call = info->first_call; call; call = call->next) {
// Stop if we have reached the bottom of the list
if (cline >= info->linescnt + startline)
break;
if (cline >= info->linescnt + startline) break;
// We only print calls with messages (In fact, all call should have msgs)
if (!get_n_msgs(call))
continue;
if (!get_n_msgs(call)) continue;
// Highlight active call
if (call == info->cur_call) {
wattron(win,COLOR_PAIR(HIGHLIGHT_COLOR));
}
mvwprintw(win, cline, 4, "%*s", width - 6 , "");
wattron(win, COLOR_PAIR(HIGHLIGHT_COLOR));
}
mvwprintw(win, cline, 4, "%*s", width - 6, "");
// Print requested columns
for (colpos = 5, i=0; i < info->columncnt; i++){
for (colpos = 5, i = 0; i < info->columncnt; i++) {
collen = info->columns[i].width;
// Check if the column will fit in the remaining space of the screen
if (colpos + collen >= width) break;
// Display each column with it's data
switch (info->columns[i].id) {
case 0: mvwprintw(win, cline, colpos, "%.*s", collen, call->messages->sip_from); break;
case 1: mvwprintw(win, cline, colpos, "%.*s", collen, call->messages->sip_to); break;
case 2: mvwprintw(win, cline, colpos, "%d", get_n_msgs(call)); break;
case 3: mvwprintw(win, cline, colpos, "%.*s", collen, call->messages->ip_from); break;
case 4: mvwprintw(win, cline, colpos, "%.*s", collen, call->messages->ip_to); break;
case 5: mvwprintw(win, cline, colpos, "%.*s", collen, call->messages->type); break;
case 0:
mvwprintw(win, cline, colpos, "%.*s", collen, call->messages->sip_from);
break;
case 1:
mvwprintw(win, cline, colpos, "%.*s", collen, call->messages->sip_to);
break;
case 2:
mvwprintw(win, cline, colpos, "%d", get_n_msgs(call));
break;
case 3:
mvwprintw(win, cline, colpos, "%.*s", collen, call->messages->ip_from);
break;
case 4:
mvwprintw(win, cline, colpos, "%.*s", collen, call->messages->ip_to);
break;
case 5:
mvwprintw(win, cline, colpos, "%.*s", collen, call->messages->type);
break;
}
colpos += collen;
}
}
wattroff(win, COLOR_PAIR(HIGHLIGHT_COLOR));
cline++;
}
@ -153,22 +171,21 @@ int call_list_draw(PANEL *panel)
mvwprintw(win, startline, 2, " ");
mvwprintw(win, startline + info->linescnt - 2, 2, " ");
mvwprintw(win, startline + info->linescnt - 1, 2, " ");
// Update the scroll information
if (info->first_line > 1 )
mvwaddch(win, startline, 2, ACS_UARROW);
if (info->first_line > 1) mvwaddch(win, startline, 2, ACS_UARROW);
if (callcnt > info->first_line + info->linescnt) {
mvwaddch(win, startline + info->linescnt - 1, 2, ACS_DARROW);
}
// Set the current line % if we have more calls that available lines
if (callcnt > info->linescnt )
mvwprintw(win, startline + info->linescnt - 2, 1, "%2d%%",
(info->first_line + info->cur_line) * 100 / callcnt);
if (callcnt > info->linescnt) mvwprintw(win, startline + info->linescnt - 2, 1, "%2d%%",
(info->first_line + info->cur_line) * 100 / callcnt);
return 0;
}
int call_list_handle_key(PANEL *panel, int key)
int
call_list_handle_key(PANEL *panel, int key)
{
int i, rnpag_steps = 10;
call_list_info_t *info = (call_list_info_t*) panel_userptr(panel);
@ -180,8 +197,7 @@ int call_list_handle_key(PANEL *panel, int key)
switch (key) {
case KEY_DOWN:
// Check if there is a call below us
if (!info->cur_call || !info->cur_call->next)
break;
if (!info->cur_call || !info->cur_call->next) break;
info->cur_call = info->cur_call->next;
info->cur_line++;
// If we are out of the bottom of the displayed list
@ -194,13 +210,12 @@ int call_list_handle_key(PANEL *panel, int key)
break;
case KEY_UP:
// Check if there is a call above us
if (!info->cur_call || !info->cur_call->prev)
break;
if (!info->cur_call || !info->cur_call->prev) break;
info->cur_call = info->cur_call->prev;
info->cur_line--;
// If we are out of the top of the displayed list
// refresh it starting in the previous (in fact current) call
if (info->cur_line <= 0 ){
if (info->cur_line <= 0) {
info->first_call = info->cur_call;
info->first_line--;
info->cur_line = 1;
@ -208,30 +223,37 @@ int call_list_handle_key(PANEL *panel, int key)
break;
case KEY_NPAGE:
// Next page => N key down strokes
for (i=0; i < rnpag_steps; i++)
call_list_handle_key(panel, KEY_DOWN);
for (i = 0; i < rnpag_steps; i++)
call_list_handle_key(panel, KEY_DOWN);
break;
case KEY_PPAGE:
// Prev page => N key up strokes
for (i=0; i < rnpag_steps; i++)
call_list_handle_key(panel, KEY_UP);
for (i = 0; i < rnpag_steps; i++)
call_list_handle_key(panel, KEY_UP);
break;
case 10:
if (!info->cur_call) return -1;
// KEY_ENTER , Display current call flow
next_panel = ui_create(DETAILS_PANEL);
next_panel = ui_create(ui_find_by_type(DETAILS_PANEL));
call_flow_set_call(info->cur_call);
wait_for_input(next_panel);
break;
case 'x':
if (!info->cur_call) return -1;
// KEY_ENTER , Display current call flow
next_panel = ui_create(ui_find_by_type(DETAILS_EX_PANEL));
call_flow_ex_set_call(info->cur_call);
wait_for_input(next_panel);
break;
case 'r':
case 'R':
if (!info->cur_call) return -1;
// KEY_R, display current call in raw mode
next_panel = ui_create(RAW_PANEL);
next_panel = ui_create(ui_find_by_type(RAW_PANEL));
call_raw_set_call(info->cur_call);
wait_for_input(next_panel);
break;
default:
return -1;
}
@ -239,7 +261,8 @@ int call_list_handle_key(PANEL *panel, int key)
return 0;
}
int call_list_help(PANEL * ppanel)
int
call_list_help(PANEL * ppanel)
{
int cline = 1;
int width, height;
@ -255,14 +278,14 @@ int call_list_help(PANEL * ppanel)
mvwprintw(win, cline++, 15, "Help - Dialogs Window ");
mvwaddch(win, cline, 0, ACS_LTEE);
mvwhline(win, cline, 1, ACS_HLINE, width - 2);
mvwaddch(win, cline++, width-1, ACS_RTEE);
wattron(win,COLOR_PAIR(HELP_COLOR));
mvwaddch(win, cline++, width - 1, ACS_RTEE);
wattron(win, COLOR_PAIR(HELP_COLOR));
mvwprintw(win, cline, 3, "F1/h:");
mvwprintw(win, cline + 1, 3, "ESC/q:");
mvwprintw(win, cline + 2, 3, "Up:");
mvwprintw(win, cline + 3, 3, "Down:");
mvwprintw(win, cline + 4, 3, "Enter:");
wattroff(win,COLOR_PAIR(HELP_COLOR));
wattroff(win, COLOR_PAIR(HELP_COLOR));
mvwprintw(win, cline, 15, "Show this screen :)");
mvwprintw(win, cline + 1, 15, "Exit sngrep");
mvwprintw(win, cline + 2, 15, "Select Previous dialog");
@ -271,22 +294,23 @@ int call_list_help(PANEL * ppanel)
return 0;
}
void call_list_destroy(PANEL *panel)
void
call_list_destroy(PANEL *panel)
{
call_list_info_t *info;
call_list_info_t *info;
// Hide the panel
hide_panel(panel);
// Hide the panel
hide_panel(panel);
// Free its status data
if ((info = (call_list_info_t*) panel_userptr(panel)))
free(info);
// Free its status data
if ((info = (call_list_info_t*) panel_userptr(panel))) free(info);
// Finally free the panel memory
del_panel(panel);
// Finally free the panel memory
del_panel(panel);
}
int call_list_add_column (PANEL *panel, int id, char *title, int width)
int
call_list_add_column(PANEL *panel, int id, char *title, int width)
{
call_list_info_t *info = (call_list_info_t*) panel_userptr(panel);
if (!info) return -1;

View File

@ -22,6 +22,7 @@
#ifndef __UI_CALL_LIST_H
#define __UI_CALL_LIST_H
#include "ui_manager.h"
#include "sip.h"
//! Sorter declaration of call_list_column struct
typedef struct call_list_column call_list_column_t;
@ -34,10 +35,11 @@ typedef struct call_list_info call_list_info_t;
* in which order a configurable option.
* This structure is one step towards configurable stuff
*/
struct call_list_column {
int id;
char *title;
int width;
struct call_list_column
{
int id;
char *title;
int width;
};
/**
@ -45,9 +47,10 @@ struct call_list_column {
* This data stores the actual status of the panel. It's stored in the
* panel pointer.
*/
struct call_list_info {
struct call_list_info
{
//! First displayed call, for drawing faster
sip_call_t *first_call;
sip_call_t *first_call;
//! First displayed call counter, for drawing scroll arrow faster
int first_line;
//! Selected call in the list
@ -60,12 +63,20 @@ struct call_list_info {
int linescnt;
//! Stores the current selected line
int cur_line;
};
};
extern PANEL *call_list_create();
extern int call_list_draw(PANEL *panel);
extern int call_list_handle_key(PANEL *panel, int key);
extern int call_list_help(PANEL *panel);
extern void call_list_destroy(PANEL *panel);
extern int call_list_add_column (PANEL *panel, int id, char *title, int width);
extern PANEL *
call_list_create();
extern int
call_list_redraw_required(PANEL *panel, sip_msg_t *msg);
extern int
call_list_draw(PANEL *panel);
extern int
call_list_handle_key(PANEL *panel, int key);
extern int
call_list_help(PANEL *panel);
extern void
call_list_destroy(PANEL *panel);
extern int
call_list_add_column(PANEL *panel, int id, char *title, int width);
#endif

View File

@ -24,7 +24,8 @@
#include "ui_manager.h"
#include "ui_call_raw.h"
PANEL *call_raw_create()
PANEL *
call_raw_create()
{
PANEL *panel;
WINDOW *win;
@ -46,11 +47,16 @@ PANEL *call_raw_create()
// Calculate available printable area
info->linescnt = height;
return panel;
}
int
call_raw_redraw_required(PANEL *panel, sip_msg_t *msg)
{
return 0;
}
int call_raw_draw(PANEL *panel)
int
call_raw_draw(PANEL *panel)
{
struct sip_msg *msg = NULL;
int pline = 0, raw_line;
@ -64,29 +70,29 @@ int call_raw_draw(PANEL *panel)
wclear(win);
/*
FIXME This part could be coded decently.
A better aproach is creating a pad window and copy the visible area
into the panel window, taking into account the scroll position.
This is dirty but easier to manage by now
*/
memset(all_lines, 0, 1024);
FIXME This part could be coded decently.
A better aproach is creating a pad window and copy the visible area
into the panel window, taking into account the scroll position.
This is dirty but easier to manage by now
*/
while ((msg = get_next_msg(info->call, msg))) {
for (raw_line = 0; raw_line < msg->plines; raw_line++) {
all_lines[all_linescnt++] = msg->payload[raw_line];
}
all_linescnt+=2;
all_lines[all_linescnt++] = NULL;
all_lines[all_linescnt++] = NULL;
}
info->all_lines = all_linescnt;
for (raw_line = info->scrollpos; raw_line - info->scrollpos < info->linescnt; raw_line++){
if (all_lines[raw_line])
mvwprintw(win, pline, 0, "%s", all_lines[raw_line]);
for (raw_line = info->scrollpos; raw_line - info->scrollpos < info->linescnt; raw_line++) {
if (all_lines[raw_line]) mvwprintw(win, pline, 0, "%s", all_lines[raw_line]);
pline++;
}
return 0;
}
int call_raw_handle_key(PANEL *panel, int key)
int
call_raw_handle_key(PANEL *panel, int key)
{
int i, rnpag_steps = 10;
call_raw_info_t *info = (call_raw_info_t*) panel_userptr(panel);
@ -98,23 +104,19 @@ int call_raw_handle_key(PANEL *panel, int key)
switch (key) {
case KEY_DOWN:
info->scrollpos++;
if (info->scrollpos + info->linescnt >= info->all_lines)
info->scrollpos--;
if (info->scrollpos + info->linescnt < info->all_lines) info->scrollpos++;
break;
case KEY_UP:
info->scrollpos--;
if (info->scrollpos <= 0)
info->scrollpos = 0;
if (info->scrollpos > 0) info->scrollpos--;
break;
case KEY_NPAGE:
// Next page => N key down strokes
for (i=0; i < rnpag_steps; i++)
for (i = 0; i < rnpag_steps; i++)
call_raw_handle_key(panel, KEY_DOWN);
break;
case KEY_PPAGE:
// Prev page => N key up strokes
for (i=0; i < rnpag_steps; i++)
for (i = 0; i < rnpag_steps; i++)
call_raw_handle_key(panel, KEY_UP);
break;
default:
@ -123,27 +125,26 @@ int call_raw_handle_key(PANEL *panel, int key)
return 0;
}
int call_raw_help(PANEL * ppanel)
int
call_raw_help(PANEL * ppanel)
{
return 0;
}
int call_raw_set_call(sip_call_t *call) {
int
call_raw_set_call(sip_call_t *call)
{
ui_t *raw_panel;
PANEL *panel;
call_raw_info_t *info;
if (!call)
return -1;
if (!call) return -1;
if (!(raw_panel = ui_find_by_type(RAW_PANEL)))
return -1;
if (!(raw_panel = ui_find_by_type(RAW_PANEL))) return -1;
if (!(panel = raw_panel->panel))
return -1;
if (!(panel = raw_panel->panel)) return -1;
if (!(info = (call_raw_info_t*) panel_userptr(panel)))
return -1;
if (!(info = (call_raw_info_t*) panel_userptr(panel))) return -1;
info->call = call;
info->scrollpos = 0;

View File

@ -32,17 +32,25 @@ typedef struct call_raw_info call_raw_info_t;
* This data stores the actual status of the panel. It's stored in the
* PANEL user pointer.
*/
struct call_raw_info {
struct call_raw_info
{
sip_call_t *call;
int scrollpos;
int linescnt;
int all_lines;
};
extern PANEL *call_raw_create();
extern int call_raw_draw(PANEL *panel);
extern int call_raw_handle_key(PANEL *panel, int key);
extern int call_raw_help(PANEL *panel);
extern int call_raw_set_call(sip_call_t *call);
extern PANEL *
call_raw_create();
int
call_raw_redraw_required(PANEL *panel, sip_msg_t *msg);
extern int
call_raw_draw(PANEL *panel);
extern int
call_raw_handle_key(PANEL *panel, int key);
extern int
call_raw_help(PANEL *panel);
extern int
call_raw_set_call(sip_call_t *call);
#endif

View File

@ -23,7 +23,8 @@
* XXX I think this should be in the applicaton configuration structure
* avaliable everywhere in the program
*/
static struct ui_status {
static struct ui_status
{
int color;
} status;
@ -36,40 +37,40 @@ static struct ui_status {
* themselfs into the panel pool dynamically.
*/
static ui_t panel_pool[] = {
{
.type = MAIN_PANEL,
.panel = NULL,
.create = call_list_create,
.draw = call_list_draw,
.handle_key = call_list_handle_key,
.help = call_list_help,
.destroy = call_list_destroy,
},
{
.type = DETAILS_PANEL,
.panel = NULL,
.create = call_flow_create,
.draw = call_flow_draw,
.handle_key = call_flow_handle_key,
.help = call_flow_help,
.destroy = call_flow_destroy,
},
{
.type = DETAILS_PANEL_EX,
.panel = NULL,
.create = call_flow_ex_create,
.draw = call_flow_ex_draw,
//.handle_key = call_flow_ex_handle_key,
.help = call_flow_ex_help
},
{
.type = RAW_PANEL,
.panel = NULL,
.create = call_raw_create,
.draw = call_raw_draw,
.handle_key = call_raw_handle_key,
.help = call_raw_help
}};
{
.type = MAIN_PANEL,
.panel = NULL,
.create = call_list_create,
.redraw_required = call_list_redraw_required,
.draw = call_list_draw,
.handle_key = call_list_handle_key,
.help = call_list_help,
.destroy = call_list_destroy, },
{
.type = DETAILS_PANEL,
.panel = NULL,
.create = call_flow_create,
.redraw_required = call_flow_redraw_required,
.draw = call_flow_draw,
.handle_key = call_flow_handle_key,
.help = call_flow_help,
.destroy = call_flow_destroy, },
{
.type = DETAILS_EX_PANEL,
.panel = NULL,
.create = call_flow_ex_create,
.redraw_required = call_flow_ex_redraw_required,
.draw = call_flow_ex_draw,
.handle_key = call_flow_ex_handle_key,
.help = call_flow_ex_help },
{
.type = RAW_PANEL,
.panel = NULL,
.create = call_raw_create,
.redraw_required = call_raw_redraw_required,
.draw = call_raw_draw,
.handle_key = call_raw_handle_key,
.help = call_raw_help } };
/**
* Initialize ncurses mode and create a main window
@ -81,19 +82,23 @@ int
init_interface(const struct ui_config uicfg)
{
// Initialize curses
initscr();
if (!initscr()) {
fprintf(stderr, "Unable to initialize ncurses mode.\n");
return -1;
}
cbreak();
// Dont write user input on screen
noecho();
noecho();
// Hide the cursor
curs_set(0);
curs_set(0);
// Only delay ESC Sequences 25 ms (we dont want Escape sequences)
ESCDELAY = 25;
ESCDELAY = 25;
start_color();
toggle_color((status.color = 1));
// Start showing call list
wait_for_input(ui_create(MAIN_PANEL));
wait_for_input(ui_create(ui_find_by_type(MAIN_PANEL)));
// End ncurses mode
endwin();
@ -101,97 +106,105 @@ init_interface(const struct ui_config uicfg)
}
ui_t *
ui_create(int type)
ui_create(ui_t *ui)
{
ui_t* ui;
// Find the ui structure for this panel type
if (!(ui = ui_find_by_type(type)))
return NULL;
// If already has a panel, just return it
if (ui_get_panel(ui))
return ui;
else if (ui->create)
if (ui_get_panel(ui)) return ui;
// Otherwise, request the ui to create the panel
if (ui->create) {
ui->panel = ui->create();
}
// And return it
return ui;
}
void
ui_destroy(ui_t *ui)
ui_destroy(ui_t *ui)
{
PANEL *panel;
// If thre is no ui panel, we're done
if (!(panel = ui_get_panel(ui)))
return;
if (!(panel = ui_get_panel(ui))) return;
// If panel has a destructor function use it
if (ui->destroy)
ui->destroy(panel);
if (ui->destroy) ui->destroy(panel);
// Initialize panel pointer
ui->panel = NULL;
ui->panel = NULL;
}
PANEL *
ui_get_panel(ui_t *ui)
{
// Return panel pointer of ui struct
return (ui)?ui->panel:NULL;
return (ui) ? ui->panel : NULL;
}
void
int
ui_redraw_required(ui_t *ui, sip_msg_t *msg)
{
//! Sanity check, this should not happen
if (!ui) return -1;
// Request the panel to draw on the scren
if (ui->redraw_required) {
return ui->redraw_required(ui_get_panel(ui), msg);
}
// If no redraw capabilities, never redraw
return -1;
}
int
ui_draw_panel(ui_t *ui)
{
//! Sanity check, this should not happen
if (!ui) return;
if (!ui) return -1;
// Create the panel if it does not exist
if (!(ui_create(ui->type))) return;
if (!(ui_create(ui))) return -1;
// Make this panel the topmost panel
top_panel(ui_get_panel(ui));
// Request the panel to draw on the scren
if (ui->draw)
ui->draw(ui_get_panel(ui));
// Update panel stack
update_panels();
doupdate();
if (ui->draw) {
if (ui->draw(ui_get_panel(ui)) == 0) {
// Update panel stack
update_panels();
doupdate();
return 0;
}
}
return -1;
}
void
void
ui_help(ui_t *ui)
{
// If current ui has help function
if (ui->help)
ui->help(ui_get_panel(ui));
if (ui->help) ui->help(ui_get_panel(ui));
// Update the stacking order
update_panels();
doupdate();
update_panels();
doupdate();
// Press any key to continue
wgetch(panel_window(ui_get_panel(ui)));
}
void
int
ui_handle_key(ui_t *ui, int key)
{
if (ui->handle_key)
ui->handle_key(ui_get_panel(ui), key);
if (ui->handle_key) return ui->handle_key(ui_get_panel(ui), key);
return -1;
}
ui_t *
ui_find_by_panel(PANEL *panel)
{
int i;
int panelcnt = sizeof(panel_pool)/sizeof(ui_t);
for (i=0; i <panelcnt; i++){
if (panel_pool[i].panel == panel)
return &panel_pool[i];
int panelcnt = sizeof(panel_pool) / sizeof(ui_t);
for (i = 0; i < panelcnt; i++) {
if (panel_pool[i].panel == panel) return &panel_pool[i];
}
return NULL;
}
@ -200,25 +213,42 @@ ui_t *
ui_find_by_type(int type)
{
int i;
int panelcnt = sizeof(panel_pool)/sizeof(ui_t);
for (i=0; i <panelcnt; i++){
if (panel_pool[i].type == type)
return &panel_pool[i];
int panelcnt = sizeof(panel_pool) / sizeof(ui_t);
for (i = 0; i < panelcnt; i++) {
if (panel_pool[i].type == type) return &panel_pool[i];
}
return NULL;
}
void
int
wait_for_input(ui_t *ui)
{
// Get window of main panel
//ui_draw_panel(ui);
WINDOW *win = panel_window(ui_get_panel(ui));
keypad(win, TRUE);
ui_t *replace;
WINDOW *win;
for (;;) {
ui_draw_panel(ui);
// Keep getting keys until panel is destroyed
while (ui_get_panel(ui)) {
// If ui requested replacement
if (ui->replace) {
replace = ui->replace;
ui->replace = NULL;
ui_destroy(ui);
ui = replace;
}
if (ui_draw_panel(ui) != 0) return -1;
// Enable key input on current panel
win = panel_window(ui_get_panel(ui));
keypad(win, TRUE);
// Get pressed key
int c = wgetch(win);
// Check if current panel has custom bindings for that key
if (ui_handle_key(ui, c) == 0) continue;
// Otherwise, use standard keybindings
switch (c) {
case 'C':
case 'c':
@ -229,18 +259,21 @@ wait_for_input(ui_t *ui)
case 'H':
case 'h':
case 265: /* KEY_F1 */
ui_help(ui); break;
ui_help(ui);
break;
case 'Q':
case 'q':
case 27: /* KEY_ESC */
ui_destroy(ui); return;
default:
ui_handle_key(ui, c); break;
ui_destroy(ui);
return 0;
break;
}
}
return -1;
}
void
void
toggle_color(int on)
{
if (on) {
@ -259,19 +292,22 @@ toggle_color(int on)
}
}
void
refresh_call_ui(const char *callid)
void
ui_new_msg_refresh(sip_msg_t *msg)
{
PANEL *panel;
// Get the topmost panel
if ((panel = panel_below(NULL))) {
// Get ui information for that panel
ui_draw_panel(ui_find_by_panel(panel));
if (ui_redraw_required(ui_find_by_panel(panel), msg) == 0) {
// If ui needs to be update, redraw it
ui_draw_panel(ui_find_by_panel(panel));
}
}
}
void
void
title_foot_box(WINDOW *win)
{
int height, width;
@ -281,9 +317,17 @@ title_foot_box(WINDOW *win)
box(win, 0, 0);
mvwaddch(win, 2, 0, ACS_LTEE);
mvwhline(win, 2, 1, ACS_HLINE, width - 2);
mvwaddch(win, 2, width-1, ACS_RTEE);
mvwaddch(win, height-3, 0, ACS_LTEE);
mvwhline(win, height-3, 1, ACS_HLINE, width - 2);
mvwaddch(win, height-3, width-1, ACS_RTEE);
mvwaddch(win, 2, width - 1, ACS_RTEE);
mvwaddch(win, height - 3, 0, ACS_LTEE);
mvwhline(win, height - 3, 1, ACS_HLINE, width - 2);
mvwaddch(win, height - 3, width - 1, ACS_RTEE);
}
int
ui_set_replace(ui_t *original, ui_t *replace)
{
if (!original || !replace) return -1;
original->replace = replace;
return 0;
}

View File

@ -36,23 +36,30 @@ typedef struct ui ui_t;
struct ui
{
//! Panel Type @see panel_types enum
int type;
int type;
//! The actual ncurses panel pointer
PANEL *panel;
//! Constructor for this panel
PANEL *(*create)();
PANEL *
(*create)();
//! Destroy current panel
void (*destroy)(PANEL *);
void
(*destroy)(PANEL *);
//! Request the panel to redraw its data
int (*draw)(PANEL*);
int
(*draw)(PANEL*);
//! Check if the panel request redraw with given msg
int (*redraw_required)(PANEL *, sip_msg_t *);
int
(*redraw_required)(PANEL *, sip_msg_t *);
//! Handle a custom keybind on this panel
int (*handle_key)(PANEL*, int key);
int
(*handle_key)(PANEL*, int key);
//! Show help window for this panel (if any)
int (*help)(PANEL *);
}
;
int
(*help)(PANEL *);
//! Replace current UI with the following in the next update
ui_t *replace;
};
/**
* Enum for available color pairs
@ -77,7 +84,7 @@ enum panel_types
MAIN_PANEL = 0,
MHELP_PANEL,
DETAILS_PANEL,
DETAILS_PANEL_EX,
DETAILS_EX_PANEL,
RAW_PANEL,
};
@ -100,17 +107,20 @@ struct ui_config
* @param ui_config UI configuration structure
* @returns 0 on ncurses initialization success, 1 otherwise
*/
int init_interface(const struct ui_config);
extern int
init_interface(const struct ui_config);
/**
* @brief Create a panel structure
*/
ui_t *ui_create(int type);
extern ui_t *
ui_create(ui_t *ui);
/**
* @brief Destroy a panel structure
*/
void ui_destroy(ui_t *ui);
extern void
ui_destroy(ui_t *ui);
/**
* @brief Get panel pointer from an ui element
@ -122,10 +132,34 @@ void ui_destroy(ui_t *ui);
* @param ui UI structure
* @return ncurses panel pointer of given UI
*/
PANEL *ui_get_panel(ui_t *ui);
extern PANEL *
ui_get_panel(ui_t *ui);
/**
* @brief Check if the given msg makes the UI redraw
*
* This function is ivoked every time a new package is readed
* in online mode. Check if the ui needs to be redrawn with the
* message to avioid not needed work.
*
* @param ui UI structure
* @param msg las readed message
* @return 0 in case of redraw required, -1 otherwise
*/
extern int
ui_redraw_required(ui_t *ui, sip_msg_t *msg);
void ui_draw_panel(ui_t *ui);
/**
* @brief Redrawn current ui
*
* This function acts as wrapper to custom ui draw functions
* with some checks
*
* @param ui UI structure
* @return 0 if ui has been drawn, -1 otherwise
*/
extern int
ui_draw_panel(ui_t *ui);
/**
* @brief Show help screen from current UI (if any)
@ -136,7 +170,8 @@ void ui_draw_panel(ui_t *ui);
*
* @param ui UI structure
*/
void ui_help(ui_t *ui);
extern void
ui_help(ui_t *ui);
/**
* @brief Handle key inputs on given UI
@ -148,22 +183,26 @@ void ui_help(ui_t *ui);
* @param ui UI structure
* @param key keycode sequence of the pressed keys and mods
*/
void ui_handle_key(ui_t *ui, int key);
extern int
ui_handle_key(ui_t *ui, int key);
/**
* @brief Find a ui from its pannel pointer
*/
ui_t *ui_find_by_panel(PANEL *panel);
extern ui_t *
ui_find_by_panel(PANEL *panel);
/**
* @brief Find a ui form its panel id
*/
ui_t *ui_find_by_type(int type);
extern ui_t *
ui_find_by_type(int type);
/**
* @brief Toggle color mode on and off
* @param on Pass 0 to turn all black&white
*/
void toggle_color(int on);
extern void
toggle_color(int on);
/**
* @brief Wait for user input.
@ -172,9 +211,8 @@ void toggle_color(int on);
*
* @param panel the topmost panel ui structure
*/
void wait_for_input(ui_t *ui);
extern int
wait_for_input(ui_t *ui);
/**
* Draw a box around passed windows with two bars (top and bottom)
@ -182,7 +220,8 @@ void wait_for_input(ui_t *ui);
*
* @param win Window to draw borders on
*/
void title_foot_box(WINDOW *win);
extern void
title_foot_box(WINDOW *win);
/**
* This function is invocked asynchronously from the
@ -192,7 +231,16 @@ void title_foot_box(WINDOW *win);
*
* @param callid Call-ID from the last received message
*/
void refresh_call_ui(const char *callid);
extern void
ui_new_msg_refresh(sip_msg_t *msg);
/**
* @brief Replace one UI with another
*
* This function can be handy when we want to destroy one UI element
* and replace it for another.
*/
extern int
ui_set_replace(ui_t *, ui_t*);
#endif // __SNGREP_UI_MANAGER_H