forked from Mirrors/sngrep
Functional Call-Flow extended
Code style GNUK applied Some documentation and cleanups
This commit is contained in:
parent
cb51d66196
commit
cfe9e7823b
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
91
src/pcap.c
91
src/pcap.c
|
@ -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;
|
||||
}
|
||||
|
|
54
src/pcap.h
54
src/pcap.h
|
@ -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
|
||||
|
|
64
src/sip.c
64
src/sip.c
|
@ -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;
|
||||
}
|
||||
|
|
74
src/sip.h
74
src/sip.h
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
250
src/ui_manager.c
250
src/ui_manager.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue