forked from Mirrors/sngrep
More vector refactoring
This commit is contained in:
parent
b4b434a04d
commit
6f4b8d9e58
|
@ -182,8 +182,6 @@ parse_packet(u_char *mode, const struct pcap_pkthdr *header, const u_char *packe
|
|||
int transport; /* 0 UDP, 1 TCP, 2 TLS */
|
||||
// Source and Destination Ports
|
||||
u_short sport, dport;
|
||||
// Media structure for RTP packets
|
||||
//rtp_stream_t *stream;
|
||||
|
||||
// Ignore packets while capture is paused
|
||||
if (capture_is_paused())
|
||||
|
@ -337,10 +335,14 @@ parse_packet(u_char *mode, const struct pcap_pkthdr *header, const u_char *packe
|
|||
// Store this packets in output file
|
||||
dump_packet(capinfo.pd, header, packet);
|
||||
} else {
|
||||
#if 0
|
||||
// Check if this is a RTP packet from active calls
|
||||
sip_call_t *call;
|
||||
for (call = call_get_next_active(NULL); call; call = call_get_next_active(call)) {
|
||||
// Media structure for RTP packets
|
||||
rtp_stream_t *stream;
|
||||
vector_iter_t calls = sip_calls_iterator();
|
||||
vector_iterator_set_filter(&calls, call_is_active);
|
||||
|
||||
while ((call = vector_iterator_next(&calls))) {
|
||||
// Check if this call has an RTP stream for current packet data
|
||||
if ((stream = call_find_stream(call, ip_src, sport, ip_dst, dport))) {
|
||||
//! Add packet to found stream
|
||||
|
@ -350,7 +352,6 @@ parse_packet(u_char *mode, const struct pcap_pkthdr *header, const u_char *packe
|
|||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Deallocate packet duplicated payload
|
||||
|
|
32
src/filter.c
32
src/filter.c
|
@ -91,29 +91,6 @@ filter_get(int type)
|
|||
return filters[type].expr;
|
||||
}
|
||||
|
||||
void
|
||||
filter_stats(int *total, int *displayed)
|
||||
{
|
||||
// TODO
|
||||
|
||||
// sip_call_t *call = NULL;
|
||||
//
|
||||
// // Initialize stats
|
||||
// *total = 0;
|
||||
// *displayed = 0;
|
||||
//
|
||||
// while ((call = call_get_next(call))) {
|
||||
// (*total)++;
|
||||
// if (filter_check_call(call) == 0)
|
||||
// (*displayed)++;
|
||||
// }
|
||||
|
||||
vector_iter_t it = sip_calls_iterator();
|
||||
*total = vector_iterator_count(&it);
|
||||
vector_iterator_set_filter(&it, filter_check_call);
|
||||
*displayed = vector_iterator_count(&it);
|
||||
}
|
||||
|
||||
int
|
||||
filter_check_call(void *item)
|
||||
{
|
||||
|
@ -124,7 +101,7 @@ filter_check_call(void *item)
|
|||
|
||||
// Filter for this call has already be processed
|
||||
if (call->filtered != -1)
|
||||
return call->filtered;
|
||||
return (call->filtered == 0);
|
||||
|
||||
// By default, call matches all filters
|
||||
call->filtered = 0;
|
||||
|
@ -179,15 +156,16 @@ filter_check_call(void *item)
|
|||
}
|
||||
|
||||
// Return the final filter status
|
||||
return call->filtered;
|
||||
return (call->filtered == 0);
|
||||
}
|
||||
|
||||
void
|
||||
filter_reset_calls()
|
||||
{
|
||||
sip_call_t *call = NULL;
|
||||
sip_call_t *call;
|
||||
vector_iter_t calls = sip_calls_iterator();
|
||||
|
||||
// Force filter evaluation
|
||||
while ((call = call_get_next(call)))
|
||||
while ((call = vector_iterator_next(&calls)))
|
||||
call->filtered = -1;
|
||||
}
|
||||
|
|
|
@ -109,15 +109,6 @@ filter_set(int type, const char *expr);
|
|||
const char *
|
||||
filter_get(int type);
|
||||
|
||||
/**
|
||||
* @brief Get Filtered calls
|
||||
*
|
||||
* @param total Total calls processed
|
||||
* @param displayed number of calls matching filters
|
||||
*/
|
||||
void
|
||||
filter_stats(int *total, int *displayed);
|
||||
|
||||
/**
|
||||
* @brief Check if a call if filtered
|
||||
*
|
||||
|
|
98
src/group.c
98
src/group.c
|
@ -38,6 +38,7 @@ call_group_create()
|
|||
return NULL;
|
||||
}
|
||||
memset(group, 0, sizeof(sip_call_group_t));
|
||||
group->calls = vector_create(5, 2);
|
||||
return group;
|
||||
}
|
||||
|
||||
|
@ -50,54 +51,32 @@ call_group_destroy(sip_call_group_t *group)
|
|||
void
|
||||
call_group_add(sip_call_group_t *group, sip_call_t *call)
|
||||
{
|
||||
|
||||
if (!group || !call || call_group_exists(group, call))
|
||||
return;
|
||||
group->calls[group->callcnt++] = call;
|
||||
vector_append(group->calls, call);
|
||||
}
|
||||
|
||||
void
|
||||
call_group_del(sip_call_group_t *group, sip_call_t *call)
|
||||
{
|
||||
int i;
|
||||
if (!group || !call || !call_group_exists(group, call))
|
||||
return;
|
||||
for (i = 0; i < group->callcnt; i++) {
|
||||
if (call == group->calls[i]) {
|
||||
group->calls[i] = group->calls[i + 1];
|
||||
call = group->calls[i + 1];
|
||||
}
|
||||
}
|
||||
group->callcnt--;
|
||||
vector_remove(group->calls, call);
|
||||
}
|
||||
|
||||
int
|
||||
call_group_exists(sip_call_group_t *group, sip_call_t *call)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < group->callcnt; i++) {
|
||||
if (call == group->calls[i])
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return (vector_index(group->calls, call) >= 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
int
|
||||
call_group_color(sip_call_group_t *group, sip_call_t *call)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < group->callcnt; i++) {
|
||||
if (call == group->calls[i]) {
|
||||
return (i % 7) + 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return (vector_index(group->calls, call) % 7) + 1;
|
||||
}
|
||||
|
||||
sip_call_t *
|
||||
call_group_get_next(sip_call_group_t *group, sip_call_t *call)
|
||||
{
|
||||
sip_msg_t *next, *first;
|
||||
sip_call_t *c;
|
||||
int i;
|
||||
|
||||
if (!group)
|
||||
|
@ -115,15 +94,16 @@ call_group_get_next(sip_call_group_t *group, sip_call_t *call)
|
|||
next = NULL;
|
||||
|
||||
// Get the call with the next chronological message
|
||||
for (i = 0; i < group->callcnt; i++) {
|
||||
if (group->calls[i] == call)
|
||||
for (i = 0; i < vector_count(group->calls); i++) {
|
||||
if ((c = vector_item(group->calls, i)) == call)
|
||||
continue;
|
||||
|
||||
// Get first message
|
||||
first = call_get_next_msg(group->calls[i], NULL);
|
||||
first = vector_first(c->msgs);
|
||||
|
||||
// Is first message of this call older?
|
||||
if (sip_msg_is_older(first, call->msgs) && (!next || !sip_msg_is_older(first, next))) {
|
||||
if (sip_msg_is_older(first, vector_first(call->msgs))
|
||||
&& (!next || !sip_msg_is_older(first, next))) {
|
||||
next = first;
|
||||
break;
|
||||
}
|
||||
|
@ -135,25 +115,23 @@ call_group_get_next(sip_call_group_t *group, sip_call_t *call)
|
|||
int
|
||||
call_group_count(sip_call_group_t *group)
|
||||
{
|
||||
return group->callcnt;
|
||||
return vector_count(group->calls);
|
||||
}
|
||||
|
||||
int
|
||||
call_group_msg_count(sip_call_group_t *group)
|
||||
{
|
||||
sip_msg_t *msg = NULL;
|
||||
sip_call_t *call;
|
||||
vector_iter_t msgs;
|
||||
int msgcnt = 0, i;
|
||||
|
||||
for (i = 0; i < group->callcnt; i++) {
|
||||
for (i = 0; i < vector_count(group->calls); i++) {
|
||||
call = vector_item(group->calls, i);
|
||||
msgs = vector_iterator(call->msgs);
|
||||
if (group->sdp_only) {
|
||||
while ((msg = call_get_next_msg(group->calls[i], msg))) {
|
||||
if (!msg->sdp)
|
||||
continue;
|
||||
msgcnt++;
|
||||
}
|
||||
} else {
|
||||
msgcnt += call_msg_count(group->calls[i]);
|
||||
vector_iterator_set_filter(&msgs, msg_has_sdp);
|
||||
}
|
||||
msgcnt += vector_iterator_count(&msgs);
|
||||
}
|
||||
return msgcnt;
|
||||
}
|
||||
|
@ -179,24 +157,30 @@ call_group_get_next_msg(sip_call_group_t *group, sip_msg_t *msg)
|
|||
{
|
||||
sip_msg_t *next = NULL;
|
||||
sip_msg_t *cand;
|
||||
vector_iter_t msgs;
|
||||
sip_call_t *call;
|
||||
int i;
|
||||
|
||||
|
||||
// FIXME Performance hack for huge dialogs
|
||||
if (group->callcnt == 1) {
|
||||
cand = msg;
|
||||
while ((cand = call_get_next_msg(group->calls[0], cand))) {
|
||||
if (group->sdp_only && !cand->sdp)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
return cand;
|
||||
if (vector_count(group->calls) == 1) {
|
||||
call = vector_first(group->calls);
|
||||
msgs = vector_iterator(call->msgs);
|
||||
vector_iterator_set_current(&msgs, vector_index(call->msgs, msg));
|
||||
if (group->sdp_only)
|
||||
vector_iterator_set_filter(&msgs, msg_has_sdp);
|
||||
return vector_iterator_next(&msgs);
|
||||
}
|
||||
|
||||
for (i = 0; i < group->callcnt; i++) {
|
||||
for (i = 0; i < vector_count(group->calls); i++) {
|
||||
|
||||
call = vector_item(group->calls, i);
|
||||
msgs = vector_iterator(call->msgs);
|
||||
if (group->sdp_only)
|
||||
vector_iterator_set_filter(&msgs, msg_has_sdp);
|
||||
|
||||
cand = NULL;
|
||||
while ((cand = call_get_next_msg(group->calls[i], cand))) {
|
||||
if (group->sdp_only && !cand->sdp)
|
||||
continue;
|
||||
|
||||
while ((cand = vector_iterator_next(&msgs))) {
|
||||
// candidate must be between msg and next
|
||||
if (sip_msg_is_older(cand, msg) && (!next || !sip_msg_is_older(cand, next))) {
|
||||
next = cand;
|
||||
|
@ -228,10 +212,12 @@ call_group_get_next_stream(sip_call_group_t *group, rtp_stream_t *stream)
|
|||
{
|
||||
rtp_stream_t *next = NULL;
|
||||
rtp_stream_t *cand;
|
||||
sip_call_t *call;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < group->callcnt; i++) {
|
||||
for (cand = group->calls[i]->streams; cand; cand = cand->next) {
|
||||
for (i = 0; i < vector_count(group->calls); i++) {
|
||||
call = vector_item(group->calls, i);
|
||||
for (cand = call ->streams; cand; cand = cand->next) {
|
||||
if (!stream_get_count(cand))
|
||||
continue;
|
||||
|
||||
|
|
|
@ -50,9 +50,7 @@ typedef struct sip_call_group sip_call_group_t;
|
|||
*/
|
||||
struct sip_call_group {
|
||||
//! Calls array in the group
|
||||
sip_call_t *calls[1024];
|
||||
//! Calls counter
|
||||
int callcnt;
|
||||
vector_t *calls;
|
||||
//! Color of the last printed call in mode Color-by-Call
|
||||
int color;
|
||||
//! Only consider SDP messages from Calls
|
||||
|
|
|
@ -64,7 +64,7 @@ setting_t settings[SETTING_COUNT] =
|
|||
{ SETTING_CF_SCROLLSTEP, "cf.scrollstep", SETTING_FMT_NUMBER, "4", NULL },
|
||||
{ SETTING_CF_LOCALHIGHLIGHT, "cf.localhighlight", SETTING_FMT_ENUM, "on", SETTING_ENUM_ONOFF },
|
||||
{ SETTING_CF_SDP_INFO, "cf.sdpinfo", SETTING_FMT_ENUM, "off", SETTING_ENUM_SDP_INFO },
|
||||
{ SETTING_CF_MEDIA, "cf.media", SETTING_FMT_ENUM, "off", SETTING_ENUM_ONOFF },
|
||||
{ SETTING_CF_MEDIA, "cf.media", SETTING_FMT_ENUM, "on", SETTING_ENUM_ONOFF },
|
||||
{ SETTING_CF_DELTA, "cf.deltatime", SETTING_FMT_ENUM, "on", SETTING_ENUM_ONOFF },
|
||||
{ SETTING_CR_SCROLLSTEP, "cr.scrollstep", SETTING_FMT_NUMBER, "10", NULL },
|
||||
{ SETTING_FILTER_METHODS, "filter.methods", SETTING_FMT_STRING, NULL, NULL },
|
||||
|
|
208
src/sip.c
208
src/sip.c
|
@ -108,24 +108,10 @@ sip_msg_create(const char *payload)
|
|||
void
|
||||
sip_msg_destroy(sip_msg_t *msg)
|
||||
{
|
||||
sip_msg_t *prev = NULL;
|
||||
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
// If the message belongs to a call, remove it from
|
||||
// its message list
|
||||
if (msg->call) {
|
||||
if ((prev = call_get_prev_msg(msg->call, msg))) {
|
||||
prev->next = msg->next;
|
||||
} else {
|
||||
msg->call->msgs = msg->next;
|
||||
}
|
||||
if (msg->next) {
|
||||
msg->next->prev = msg->prev;
|
||||
}
|
||||
}
|
||||
|
||||
// Free message attribute list
|
||||
sip_attr_list_destroy(msg->attrs);
|
||||
|
||||
|
@ -154,13 +140,18 @@ sip_call_create(char *callid)
|
|||
memset(call, 0, sizeof(sip_call_t));
|
||||
|
||||
// Add this call to the call list
|
||||
pthread_mutex_lock(&calls.lock);
|
||||
index = vector_append(calls.list, call);
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
|
||||
// Store this call in hash table
|
||||
entry.key = strdup(callid);
|
||||
entry.data = (void *) call;
|
||||
hsearch(entry, ENTER);
|
||||
|
||||
// Create a vector to store call messages
|
||||
call->msgs = vector_create(10, 5);
|
||||
|
||||
// Initialize call filter status
|
||||
call->filtered = -1;
|
||||
|
||||
|
@ -173,6 +164,9 @@ sip_call_create(char *callid)
|
|||
void
|
||||
sip_call_destroy(sip_call_t *call)
|
||||
{
|
||||
sip_msg_t *msg;
|
||||
vector_iter_t msgs;
|
||||
|
||||
// No call to destroy
|
||||
if (!call)
|
||||
return;
|
||||
|
@ -181,8 +175,12 @@ sip_call_destroy(sip_call_t *call)
|
|||
vector_remove(calls.list, call);
|
||||
|
||||
// Remove all call messages
|
||||
while (call->msgs)
|
||||
sip_msg_destroy(call->msgs);
|
||||
msgs = vector_iterator(call->msgs);
|
||||
while ((msg = vector_iterator_next(&msgs))) {
|
||||
sip_msg_destroy(msg);
|
||||
vector_remove(call->msgs, msg);
|
||||
}
|
||||
|
||||
|
||||
// Remove all call attributes
|
||||
sip_attr_list_destroy(call->attrs);
|
||||
|
@ -342,28 +340,29 @@ sip_calls_iterator()
|
|||
return vector_iterator(calls.list);
|
||||
}
|
||||
|
||||
void
|
||||
sip_calls_stats(int *total, int *displayed)
|
||||
{
|
||||
vector_iter_t it = vector_iterator(calls.list);
|
||||
|
||||
pthread_mutex_lock(&calls.lock);
|
||||
// Total number of calls without filtering
|
||||
*total = vector_iterator_count(&it);
|
||||
// Total number of calls after filtering
|
||||
vector_iterator_set_filter(&it, filter_check_call);
|
||||
*displayed = vector_iterator_count(&it);
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
}
|
||||
|
||||
void
|
||||
call_add_message(sip_call_t *call, sip_msg_t *msg)
|
||||
{
|
||||
// Set the message owner
|
||||
msg->call = call;
|
||||
|
||||
// Put this msg at the end of the msg list
|
||||
if (!call->msgs) {
|
||||
call->msgs = msg;
|
||||
msg->prev = NULL;
|
||||
} else {
|
||||
call->last_msg->next = msg;
|
||||
msg->prev = call->last_msg;
|
||||
}
|
||||
call->last_msg = msg;
|
||||
|
||||
// Increase message count
|
||||
call->msgcnt++;
|
||||
|
||||
vector_append(call->msgs, msg);
|
||||
// Store message count
|
||||
call_set_attribute(call, SIP_ATTR_MSGCNT, "%d", call->msgcnt);
|
||||
call_set_attribute(call, SIP_ATTR_MSGCNT, "%d", vector_count(call->msgs));
|
||||
}
|
||||
|
||||
sip_call_t *
|
||||
|
@ -398,7 +397,7 @@ call_find_by_xcallid(const char *xcallid)
|
|||
int
|
||||
call_msg_count(sip_call_t *call)
|
||||
{
|
||||
return call->msgcnt;
|
||||
return vector_count(call->msgs);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -432,9 +431,9 @@ call_get_next_msg(sip_call_t *call, sip_msg_t *msg)
|
|||
sip_msg_t *ret;
|
||||
pthread_mutex_lock(&calls.lock);
|
||||
if (msg == NULL) {
|
||||
ret = call->msgs;
|
||||
ret = vector_first(call->msgs);
|
||||
} else {
|
||||
ret = msg->next;
|
||||
ret = vector_item(call->msgs, vector_index(call->msgs, msg) + 1);
|
||||
}
|
||||
|
||||
// Parse message if not parsed
|
||||
|
@ -450,13 +449,7 @@ call_get_prev_msg(sip_call_t *call, sip_msg_t *msg)
|
|||
{
|
||||
sip_msg_t *ret = NULL;
|
||||
pthread_mutex_lock(&calls.lock);
|
||||
if (msg == NULL) {
|
||||
// No message, no previous
|
||||
ret = NULL;
|
||||
} else {
|
||||
// Get previous message
|
||||
ret = msg->prev;
|
||||
}
|
||||
ret = vector_item(call->msgs, vector_index(call->msgs, msg) - 1);
|
||||
|
||||
// Parse message if not parsed
|
||||
if (ret && !ret->parsed)
|
||||
|
@ -466,66 +459,22 @@ call_get_prev_msg(sip_call_t *call, sip_msg_t *msg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
sip_call_t *
|
||||
call_get_next(sip_call_t *cur)
|
||||
int
|
||||
call_is_active(void *item)
|
||||
{
|
||||
|
||||
sip_call_t * next;
|
||||
pthread_mutex_lock(&calls.lock);
|
||||
next = vector_item(calls.list, vector_index(calls.list, cur) + 1);
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
return next;
|
||||
// TODO
|
||||
sip_call_t *call = (sip_call_t *)item;
|
||||
return call->active;
|
||||
}
|
||||
|
||||
sip_call_t *
|
||||
call_get_prev(sip_call_t *cur)
|
||||
int
|
||||
msg_has_sdp(void *item)
|
||||
{
|
||||
|
||||
sip_call_t *prev;
|
||||
pthread_mutex_lock(&calls.lock);
|
||||
prev = vector_item(calls.list, vector_index(calls.list, cur) - 1);
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
return prev;
|
||||
// TODO
|
||||
sip_msg_t *msg = (sip_msg_t *)item;
|
||||
return msg->sdp;
|
||||
}
|
||||
|
||||
sip_call_t *
|
||||
call_get_next_filtered(sip_call_t *cur)
|
||||
{
|
||||
sip_call_t *next = call_get_next(cur);
|
||||
|
||||
pthread_mutex_lock(&calls.lock);
|
||||
// Return next not filtered call
|
||||
if (next && filter_check_call(next))
|
||||
next = call_get_next_filtered(next);
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
sip_call_t *
|
||||
call_get_prev_filtered(sip_call_t *cur)
|
||||
{
|
||||
sip_call_t *prev = call_get_prev(cur);
|
||||
|
||||
pthread_mutex_lock(&calls.lock);
|
||||
// Return previous call if this one is filtered
|
||||
if (prev && filter_check_call(prev))
|
||||
prev = call_get_prev_filtered(prev);
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
return prev;
|
||||
}
|
||||
|
||||
sip_call_t *
|
||||
call_get_next_active(sip_call_t *cur)
|
||||
{
|
||||
sip_call_t *next;
|
||||
|
||||
for (next = call_get_next(cur); next; next = call_get_next(next))
|
||||
if (next && next->active)
|
||||
break;
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
void
|
||||
call_update_state(sip_call_t *call, sip_msg_t *msg)
|
||||
|
@ -533,13 +482,17 @@ call_update_state(sip_call_t *call, sip_msg_t *msg)
|
|||
const char *callstate;
|
||||
char dur[20];
|
||||
int reqresp;
|
||||
sip_msg_t *first;
|
||||
|
||||
// Sanity check
|
||||
if (!call || !call->msgs || !msg)
|
||||
return;
|
||||
|
||||
// Get the first message in the call
|
||||
first = vector_first(call->msgs);
|
||||
|
||||
// Check First message of Call has INVITE method
|
||||
if (call->msgs->reqresp != SIP_METHOD_INVITE) {
|
||||
if (first->reqresp != SIP_METHOD_INVITE) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -559,15 +512,13 @@ call_update_state(sip_call_t *call, sip_msg_t *msg)
|
|||
// Alice is not in the mood
|
||||
call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_CANCELLED);
|
||||
// Store total call duration
|
||||
call_set_attribute(call, SIP_ATTR_TOTALDUR,
|
||||
sip_calculate_duration(call->msgs, msg, dur));
|
||||
call_set_attribute(call, SIP_ATTR_TOTALDUR, sip_calculate_duration(first, msg, dur));
|
||||
call->active = 0;
|
||||
} else if (reqresp > 400) {
|
||||
// Bob is not in the mood
|
||||
call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_REJECTED);
|
||||
// Store total call duration
|
||||
call_set_attribute(call, SIP_ATTR_TOTALDUR,
|
||||
sip_calculate_duration(call->msgs, msg, dur));
|
||||
call_set_attribute(call, SIP_ATTR_TOTALDUR, sip_calculate_duration(first, msg, dur));
|
||||
call->active = 0;
|
||||
}
|
||||
} else if (!strcmp(callstate, SIP_CALLSTATE_INCALL)) {
|
||||
|
@ -585,8 +536,7 @@ call_update_state(sip_call_t *call, sip_msg_t *msg)
|
|||
call->active = 1;
|
||||
} else {
|
||||
// Store total call duration
|
||||
call_set_attribute(call, SIP_ATTR_TOTALDUR,
|
||||
sip_calculate_duration(call->msgs, msg, dur));
|
||||
call_set_attribute(call, SIP_ATTR_TOTALDUR, sip_calculate_duration(first, msg, dur));
|
||||
}
|
||||
} else {
|
||||
// This is actually a call
|
||||
|
@ -595,8 +545,6 @@ call_update_state(sip_call_t *call, sip_msg_t *msg)
|
|||
call->active = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -869,23 +817,18 @@ int
|
|||
msg_is_retrans(sip_msg_t *msg)
|
||||
{
|
||||
sip_msg_t *prev = NULL;
|
||||
vector_iter_t it;
|
||||
|
||||
// Sanity check
|
||||
if (!msg || !msg->call || !msg->payload)
|
||||
return 0;
|
||||
|
||||
// Start on previous message
|
||||
prev = msg;
|
||||
// Get previous message in call
|
||||
it = vector_iterator(msg->call->msgs);
|
||||
vector_iterator_set_current(&it, vector_index(msg->call->msgs, msg));
|
||||
prev = vector_iterator_prev(&it);
|
||||
|
||||
// Check previous messages in same call
|
||||
while ((prev = call_get_prev_msg(msg->call, prev))) {
|
||||
// Check if the payload is exactly the same
|
||||
if (!strcasecmp(msg->payload, prev->payload)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return (prev && !strcasecmp(msg->payload, prev->payload));
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -894,41 +837,6 @@ msg_is_request(sip_msg_t *msg)
|
|||
return msg->reqresp < SIP_METHOD_SENTINEL;
|
||||
}
|
||||
|
||||
sip_msg_t *
|
||||
msg_get_request(sip_msg_t *msg)
|
||||
{
|
||||
sip_msg_t *tmp = msg;
|
||||
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
if (!msg_is_request(msg))
|
||||
return NULL;
|
||||
|
||||
for (tmp = call_get_prev_msg(msg->call, tmp); tmp; tmp = call_get_prev_msg(msg->call, tmp)) {
|
||||
if (msg_is_request(tmp))
|
||||
continue;
|
||||
|
||||
if (!strcmp(tmp->src, msg->dst) && tmp->sport == msg->dport)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sip_msg_t *
|
||||
msg_get_request_sdp(sip_msg_t *msg)
|
||||
{
|
||||
sip_msg_t *tmp = msg;
|
||||
while (tmp) {
|
||||
if ((tmp = msg_get_request(tmp)) && tmp->sdp)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
char *
|
||||
msg_get_header(sip_msg_t *msg, char *out)
|
||||
{
|
||||
|
@ -1072,7 +980,7 @@ call_get_attribute(sip_call_t *call, enum sip_attr_id id)
|
|||
case SIP_ATTR_TOTALDUR:
|
||||
return sip_attr_get(call->attrs, id);
|
||||
default:
|
||||
return msg_get_attribute(call_get_next_msg(call, NULL), id);
|
||||
return msg_get_attribute(vector_first(call->msgs), id);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
108
src/sip.h
108
src/sip.h
|
@ -90,11 +90,11 @@ struct sip_msg {
|
|||
//! Message attribute list
|
||||
char *attrs[SIP_ATTR_COUNT];
|
||||
//! Source address
|
||||
char src[50];
|
||||
char src[ADDRESSLEN];
|
||||
//! Source port
|
||||
u_short sport;
|
||||
//! Destination address
|
||||
char dst[50];
|
||||
char dst[ADDRESSLEN];
|
||||
//! Destination port
|
||||
u_short dport;
|
||||
//! Temporal payload data before being parsed
|
||||
|
@ -118,10 +118,6 @@ struct sip_msg {
|
|||
u_char *pcap_packet;
|
||||
//! Message owner
|
||||
sip_call_t *call;
|
||||
|
||||
//! Messages Double linked list
|
||||
sip_msg_t *prev;
|
||||
sip_msg_t *next;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -138,12 +134,8 @@ struct sip_call {
|
|||
int filtered;
|
||||
//! For call dialogs, mark if call has not yet finished
|
||||
int active;
|
||||
//! List of messages of this call
|
||||
sip_msg_t *msgs;
|
||||
//! Pointer to the last added message
|
||||
sip_msg_t *last_msg;
|
||||
//! How many messages has this call
|
||||
int msgcnt;
|
||||
//! List of messages of this call (sip_msg_t*)
|
||||
vector_t *msgs;
|
||||
//! Message when conversation started
|
||||
sip_msg_t *cstart_msg;
|
||||
//! RTP streams for this call
|
||||
|
@ -294,6 +286,15 @@ sip_calls_count();
|
|||
vector_iter_t
|
||||
sip_calls_iterator();
|
||||
|
||||
/**
|
||||
* @brief Return stats from call list
|
||||
*
|
||||
* @param total Total calls processed
|
||||
* @param displayed number of calls matching filters
|
||||
*/
|
||||
void
|
||||
sip_calls_stats(int *total, int *displayed);
|
||||
|
||||
/**
|
||||
* @brief Append message to the call's message list
|
||||
*
|
||||
|
@ -366,79 +367,12 @@ msg_media_count(sip_msg_t *msg);
|
|||
sip_call_t *
|
||||
call_get_xcall(sip_call_t *call);
|
||||
|
||||
/**
|
||||
* @brief Finds the next msg in a call.
|
||||
*
|
||||
* If the passed msg is NULL it returns the first message
|
||||
* in the call
|
||||
*
|
||||
* @param call SIP call structure
|
||||
* @param msg Actual SIP msg from the call (can be NULL)
|
||||
* @return Next chronological message in the call
|
||||
*/
|
||||
sip_msg_t *
|
||||
call_get_next_msg(sip_call_t *call, sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Finds the prev msg in a call.
|
||||
*
|
||||
* If the passed msg is the first message in the call
|
||||
* this function will return NULL
|
||||
*
|
||||
* @param call SIP call structure
|
||||
* @param msg Actual SIP msg from the call
|
||||
* @return Previous chronological message in the call
|
||||
*/
|
||||
sip_msg_t *
|
||||
call_get_prev_msg(sip_call_t *call, sip_msg_t *msg);
|
||||
int
|
||||
call_is_active(void *item);
|
||||
|
||||
/**
|
||||
* @brief Get next call
|
||||
*
|
||||
* General getter for call list. Never access calls list
|
||||
* directly, use this instead.
|
||||
*
|
||||
* @param cur Current call. Pass NULL to get the first call.
|
||||
* @return Next call in the list or NULL if there is no next call
|
||||
*/
|
||||
sip_call_t *
|
||||
call_get_next(sip_call_t *cur);
|
||||
|
||||
/**
|
||||
* @brief Get previous call
|
||||
*
|
||||
* General getter for call list. Never access calls list
|
||||
* directly, use this instead.
|
||||
*
|
||||
* @param cur Current call
|
||||
* @return Prev call in the list or NULL if there is no previous call
|
||||
*/
|
||||
sip_call_t *
|
||||
call_get_prev(sip_call_t *cur);
|
||||
|
||||
/**
|
||||
* @brief Get next call after applying filters and ignores
|
||||
*
|
||||
* @param cur Current call. Pass NULL to get the first call.
|
||||
* @return Next call in the list or NULL if there is no next call
|
||||
*/
|
||||
sip_call_t *
|
||||
call_get_next_filtered(sip_call_t *cur);
|
||||
|
||||
/**
|
||||
* @brief Get previous call applying filters and ignores
|
||||
*
|
||||
* General getter for call list. Never access calls list
|
||||
* directly, use this instead.
|
||||
*
|
||||
* @param cur Current call
|
||||
* @return Prev call in the list or NULL if there is no previous call
|
||||
*/
|
||||
sip_call_t *
|
||||
call_get_prev_filtered(sip_call_t *cur);
|
||||
|
||||
sip_call_t *
|
||||
call_get_next_active(sip_call_t *cur);
|
||||
int
|
||||
msg_has_sdp(void *item);
|
||||
|
||||
/**
|
||||
* @brief Update Call State attribute with its last parsed message
|
||||
|
@ -520,13 +454,6 @@ msg_is_retrans(sip_msg_t *msg);
|
|||
int
|
||||
msg_is_request(sip_msg_t *msg);
|
||||
|
||||
|
||||
sip_msg_t *
|
||||
msg_get_request(sip_msg_t *msg);
|
||||
|
||||
sip_msg_t *
|
||||
msg_get_request_sdp(sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Get summary of message header data
|
||||
*
|
||||
|
@ -676,7 +603,6 @@ sip_method_from_str(const char *method);
|
|||
const char *
|
||||
sip_address_format(const char *address);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return address:port formatted depending on active settings
|
||||
*
|
||||
|
|
|
@ -145,11 +145,11 @@ call_flow_draw(PANEL *panel)
|
|||
werase(win);
|
||||
|
||||
// Set title
|
||||
if (info->group->callcnt == 1) {
|
||||
if (call_group_count(info->group) == 1) {
|
||||
sprintf(title, "Call flow for %s",
|
||||
call_get_attribute(*info->group->calls, SIP_ATTR_CALLID));
|
||||
call_get_attribute(vector_first(info->group->calls), SIP_ATTR_CALLID));
|
||||
} else {
|
||||
sprintf(title, "Call flow for %d dialogs", info->group->callcnt);
|
||||
sprintf(title, "Call flow for %d dialogs", call_group_count(info->group));
|
||||
}
|
||||
|
||||
// Print color mode in title
|
||||
|
@ -840,16 +840,12 @@ call_flow_handle_key(PANEL *panel, int key)
|
|||
case ACTION_SHOW_FLOW_EX:
|
||||
werase(panel_window(panel));
|
||||
// KEY_X , Display current call flow
|
||||
if (info->group->callcnt == 1) {
|
||||
group = call_group_create();
|
||||
call_group_add(group, info->group->calls[0]);
|
||||
call_group_add(group, call_get_xcall(info->group->calls[0]));
|
||||
call_flow_set_group(group);
|
||||
} else {
|
||||
group = call_group_create();
|
||||
call_group_add(group, info->group->calls[0]);
|
||||
call_flow_set_group(group);
|
||||
if (call_group_count(info->group) == 1) {
|
||||
call_group_add(group, call_get_xcall(vector_first(info->group->calls)));
|
||||
}
|
||||
call_group_add(group, vector_first(info->group->calls));
|
||||
call_flow_set_group(group);
|
||||
break;
|
||||
case ACTION_SHOW_RAW:
|
||||
// KEY_R, display current call in raw mode
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "ui_call_flow.h"
|
||||
#include "ui_call_raw.h"
|
||||
#include "ui_save.h"
|
||||
#include "sip.h"
|
||||
|
||||
/**
|
||||
* Ui Structure definition for Call List panel
|
||||
|
@ -111,6 +112,11 @@ call_list_create()
|
|||
info->list_win = subwin(win, height - 5, width, 4, 0);
|
||||
info->group = call_group_create();
|
||||
|
||||
// Get current call list
|
||||
info->calls = sip_calls_iterator();
|
||||
vector_iterator_set_filter(&info->calls, filter_check_call);
|
||||
info->cur_call = info->first_call = -1;
|
||||
|
||||
// Set defualt filter text if configured
|
||||
if (setting_get_value(SETTING_CL_FILTER)) {
|
||||
set_field_buffer(info->fields[FLD_LIST_FILTER], 0, setting_get_value(SETTING_CL_FILTER));
|
||||
|
@ -217,7 +223,7 @@ call_list_draw_header(PANEL *panel)
|
|||
wattroff(win, A_BOLD | A_REVERSE | COLOR_PAIR(CP_DEF_ON_CYAN));
|
||||
|
||||
// Get filter call counters
|
||||
//filter_stats(&info->callcnt, &info->dispcallcnt);
|
||||
sip_calls_stats(&info->callcnt, &info->dispcallcnt);
|
||||
|
||||
// Print calls count (also filtered)
|
||||
mvwprintw(win, 1, 35, "%*s", 35, "");
|
||||
|
@ -265,16 +271,21 @@ call_list_draw_list(PANEL *panel)
|
|||
getmaxyx(win, height, width);
|
||||
|
||||
// If no active call, use the fist one (if exists)
|
||||
if (!info->first_call && call_get_next_filtered(NULL)) {
|
||||
info->cur_call = info->first_call = call_get_next_filtered(NULL);
|
||||
if (info->first_call == -1 && vector_iterator_count(&info->calls)) {
|
||||
vector_iterator_reset(&info->calls);
|
||||
call = vector_iterator_next(&info->calls);
|
||||
info->cur_call = info->first_call = vector_index(vector_iterator_vector(&info->calls), call);
|
||||
info->cur_line = info->first_line = 1;
|
||||
}
|
||||
|
||||
// Clear call list before redrawing
|
||||
werase(win);
|
||||
|
||||
// Set the iterator position to the first call
|
||||
vector_iterator_set_current(&info->calls, info->first_call - 1 );
|
||||
|
||||
// Fill the call list
|
||||
for (call = info->first_call; call; call = call_get_next_filtered(call)) {
|
||||
while ((call = vector_iterator_next(&info->calls))) {
|
||||
// Stop if we have reached the bottom of the list
|
||||
if (cline == height)
|
||||
break;
|
||||
|
@ -288,7 +299,7 @@ call_list_draw_list(PANEL *panel)
|
|||
wattron(win, A_BOLD | COLOR_PAIR(CP_DEFAULT));
|
||||
|
||||
// Highlight active call
|
||||
if (call == info->cur_call) {
|
||||
if (call == vector_item(vector_iterator_vector(&info->calls), info->cur_call)) {
|
||||
// Reverse colors on monochrome terminals
|
||||
if (!has_colors())
|
||||
wattron(win, A_REVERSE);
|
||||
|
@ -417,6 +428,7 @@ call_list_handle_key(PANEL *panel, int key)
|
|||
ui_t *next_panel;
|
||||
sip_call_group_t *group;
|
||||
int action = -1;
|
||||
sip_call_t *call;
|
||||
|
||||
// Sanity check, this should not happen
|
||||
if (!(info = call_list_info(panel)))
|
||||
|
@ -430,29 +442,34 @@ call_list_handle_key(PANEL *panel, int key)
|
|||
WINDOW *win = info->list_win;
|
||||
getmaxyx(win, height, width);
|
||||
|
||||
// Reset iterator position to current call
|
||||
vector_iterator_set_current(&info->calls, info->cur_call);
|
||||
|
||||
// Check actions for this key
|
||||
while ((action = key_find_action(key, action)) != ERR) {
|
||||
// Check if we handle this action
|
||||
switch (action) {
|
||||
case ACTION_DOWN:
|
||||
// Check if there is a call below us
|
||||
if (!info->cur_call || !call_get_next_filtered(info->cur_call))
|
||||
if (!vector_iterator_next(&info->calls))
|
||||
break;
|
||||
info->cur_call = call_get_next_filtered(info->cur_call);
|
||||
info->cur_call = vector_iterator_current(&info->calls);
|
||||
info->cur_line++;
|
||||
// If we are out of the bottom of the displayed list
|
||||
// refresh it starting in the next call
|
||||
if (info->cur_line > height) {
|
||||
info->first_call = call_get_next_filtered(info->first_call);
|
||||
vector_iterator_set_current(&info->calls, info->first_call);
|
||||
vector_iterator_next(&info->calls);
|
||||
info->first_call = vector_iterator_current(&info->calls);
|
||||
info->first_line++;
|
||||
info->cur_line = height;
|
||||
}
|
||||
break;
|
||||
case ACTION_UP:
|
||||
// Check if there is a call above us
|
||||
if (!info->cur_call || !call_get_prev_filtered(info->cur_call))
|
||||
if (!vector_iterator_prev(&info->calls))
|
||||
break;
|
||||
info->cur_call = call_get_prev_filtered(info->cur_call);
|
||||
info->cur_call = vector_iterator_current(&info->calls);
|
||||
info->cur_line--;
|
||||
// If we are out of the top of the displayed list
|
||||
// refresh it starting in the previous (in fact current) call
|
||||
|
@ -484,48 +501,45 @@ call_list_handle_key(PANEL *panel, int key)
|
|||
break;
|
||||
case ACTION_SHOW_FLOW:
|
||||
// Check we have calls in the list
|
||||
if (!info->cur_call)
|
||||
if (info->cur_call == -1)
|
||||
break;
|
||||
next_panel = ui_create_panel(PANEL_CALL_FLOW);
|
||||
if (info->group->callcnt) {
|
||||
ui_create_panel(PANEL_CALL_FLOW);
|
||||
if (call_group_count(info->group)) {
|
||||
group = info->group;
|
||||
} else {
|
||||
if (!info->cur_call)
|
||||
break;
|
||||
group = call_group_create();
|
||||
call_group_add(group, info->cur_call);
|
||||
call = vector_item(vector_iterator_vector(&info->calls), info->cur_call);
|
||||
call_group_add(group, call);
|
||||
}
|
||||
call_flow_set_group(group);
|
||||
break;
|
||||
case ACTION_SHOW_FLOW_EX:
|
||||
// Check we have calls in the list
|
||||
if (!info->cur_call)
|
||||
if (info->cur_call == -1)
|
||||
break;
|
||||
// Display current call flow (extended)
|
||||
ui_create_panel(PANEL_CALL_FLOW);
|
||||
if (info->group->callcnt) {
|
||||
if (call_group_count(info->group)) {
|
||||
group = info->group;
|
||||
} else {
|
||||
if (!info->cur_call)
|
||||
break;
|
||||
group = call_group_create();
|
||||
call_group_add(group, info->cur_call);
|
||||
call_group_add(group, call_get_xcall(info->cur_call));
|
||||
call = vector_item(vector_iterator_vector(&info->calls), info->cur_call);
|
||||
call_group_add(group, call);
|
||||
call_group_add(group, call_get_xcall(call));
|
||||
}
|
||||
call_flow_set_group(group);
|
||||
break;
|
||||
case ACTION_SHOW_RAW:
|
||||
// Check we have calls in the list
|
||||
if (!info->cur_call)
|
||||
if (info->cur_call == -1)
|
||||
break;
|
||||
ui_create_panel(PANEL_CALL_RAW);
|
||||
if (info->group->callcnt) {
|
||||
if (call_group_count(info->group)) {
|
||||
group = info->group;
|
||||
} else {
|
||||
if (!info->cur_call)
|
||||
break;
|
||||
group = call_group_create();
|
||||
call_group_add(group, info->cur_call);
|
||||
call = vector_item(vector_iterator_vector(&info->calls), info->cur_call);
|
||||
call_group_add(group, call);
|
||||
}
|
||||
call_raw_set_group(group);
|
||||
break;
|
||||
|
@ -556,12 +570,11 @@ call_list_handle_key(PANEL *panel, int key)
|
|||
ui_create_panel(PANEL_SETTINGS);
|
||||
break;
|
||||
case ACTION_SELECT:
|
||||
if (!info->cur_call)
|
||||
break;
|
||||
if (call_group_exists(info->group, info->cur_call)) {
|
||||
call_group_del(info->group, info->cur_call);
|
||||
call = vector_item(vector_iterator_vector(&info->calls), info->cur_call);
|
||||
if (call_group_exists(info->group, call)) {
|
||||
call_group_del(info->group, call);
|
||||
} else {
|
||||
call_group_add(info->group, info->cur_call);
|
||||
call_group_add(info->group, call);
|
||||
}
|
||||
break;
|
||||
case ACTION_PREV_SCREEN:
|
||||
|
@ -825,9 +838,9 @@ call_list_clear(PANEL *panel)
|
|||
return;
|
||||
|
||||
// Initialize structures
|
||||
info->first_call = info->cur_call = NULL;
|
||||
info->first_call = info->cur_call = -1;
|
||||
info->first_line = info->cur_line = 0;
|
||||
info->group->callcnt = 0;
|
||||
vector_clear(info->group->calls);
|
||||
|
||||
// Clear Displayed lines
|
||||
werase(info->list_win);
|
||||
|
|
|
@ -73,12 +73,14 @@ struct call_list_column {
|
|||
* panel pointer.
|
||||
*/
|
||||
struct call_list_info {
|
||||
//! Displayed calls iterator
|
||||
vector_iter_t calls;
|
||||
//! First displayed call, for drawing faster
|
||||
sip_call_t *first_call;
|
||||
int first_call;
|
||||
//! First displayed call counter, for drawing scroll arrow faster
|
||||
int first_line;
|
||||
//! Selected call in the list
|
||||
sip_call_t *cur_call;
|
||||
int cur_call;
|
||||
//! Selected calls with space
|
||||
sip_call_group_t *group;
|
||||
//! Displayed column list, make it configurable in the future
|
||||
|
|
|
@ -193,7 +193,7 @@ save_draw(PANEL *panel)
|
|||
WINDOW *win = panel_window(panel);
|
||||
|
||||
// Get filter stats
|
||||
filter_stats(&total, &displayed);
|
||||
sip_calls_stats(&total, &displayed);
|
||||
|
||||
mvwprintw(win, 7, 3, "( ) all dialogs ");
|
||||
mvwprintw(win, 8, 3, "( ) selected dialogs [%d]", call_group_count(info->group));
|
||||
|
@ -359,6 +359,7 @@ save_to_file(PANEL *panel)
|
|||
pcap_dumper_t *pd = NULL;
|
||||
FILE *f = NULL;
|
||||
int i;
|
||||
vector_iter_t calls, msgs;
|
||||
|
||||
// Get panel information
|
||||
save_info_t *info = save_info(panel);
|
||||
|
@ -418,24 +419,38 @@ save_to_file(PANEL *panel)
|
|||
}
|
||||
}
|
||||
|
||||
// Get calls iterator
|
||||
calls = sip_calls_iterator();
|
||||
|
||||
switch(info->savemode) {
|
||||
case SAVE_ALL:
|
||||
// Save all packets to the file
|
||||
while ((call = call_get_next(call)))
|
||||
while ((msg = call_get_next_msg(call, msg)))
|
||||
while ((call = vector_iterator_next(&calls))) {
|
||||
msgs = vector_iterator(call->msgs);
|
||||
while ((msg = vector_iterator_next(&msgs))) {
|
||||
(info->saveformat == SAVE_PCAP) ? save_msg_pcap(pd, msg) : save_msg_txt(f, msg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SAVE_SELECTED:
|
||||
// Save selected packets to file
|
||||
while ((call = call_group_get_next(info->group, call)))
|
||||
while ((msg = call_get_next_msg(call, msg)))
|
||||
while ((call = call_group_get_next(info->group, call))) {
|
||||
msgs = vector_iterator(call->msgs);
|
||||
while ((msg = vector_iterator_next(&msgs))) {
|
||||
(info->saveformat == SAVE_PCAP) ? save_msg_pcap(pd, msg) : save_msg_txt(f, msg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SAVE_DISPLAYED:
|
||||
// Set filtering for this iterator
|
||||
vector_iterator_set_filter(&calls, filter_check_call);
|
||||
// Save selected packets to file
|
||||
while ((call = call_get_next_filtered(call)))
|
||||
while ((msg = call_get_next_msg(call, msg)))
|
||||
while ((call = vector_iterator_next(&calls))) {
|
||||
msgs = vector_iterator(call->msgs);
|
||||
while ((msg = vector_iterator_next(&msgs))) {
|
||||
(info->saveformat == SAVE_PCAP) ? save_msg_pcap(pd, msg) : save_msg_txt(f, msg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
99
src/vector.c
99
src/vector.c
|
@ -29,6 +29,7 @@
|
|||
#include "vector.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
vector_t *
|
||||
vector_create(int limit, int step)
|
||||
|
@ -61,6 +62,10 @@ vector_clear(vector_t *vector)
|
|||
int
|
||||
vector_append(vector_t *vector, void *item)
|
||||
{
|
||||
// Sanity check
|
||||
if (!item)
|
||||
return vector->count;
|
||||
|
||||
// Check if we need to increase vector size
|
||||
if (vector->count == vector->limit) {
|
||||
// Increase vector size
|
||||
|
@ -76,17 +81,28 @@ vector_append(vector_t *vector, void *item)
|
|||
void
|
||||
vector_remove(vector_t *vector, void *item)
|
||||
{
|
||||
|
||||
// Get item position
|
||||
int idx = vector_index(vector, item);
|
||||
// Decrease item counter
|
||||
vector->count--;
|
||||
// Move the rest of the elements one position up
|
||||
memcpy(vector->list + idx, vector->list + idx + 1, sizeof(void *) * (vector->count - idx));
|
||||
}
|
||||
|
||||
void *
|
||||
vector_item(vector_t *vector, int index)
|
||||
{
|
||||
if (vector->count <= index || index < 0)
|
||||
if (index >= vector->count || index < 0)
|
||||
return NULL;
|
||||
return vector->list[index];
|
||||
}
|
||||
|
||||
void *
|
||||
vector_first(vector_t *vector)
|
||||
{
|
||||
return vector_item(vector, 0);
|
||||
}
|
||||
|
||||
int
|
||||
vector_index(vector_t *vector, void *item)
|
||||
{
|
||||
|
@ -115,16 +131,29 @@ vector_iterator(vector_t *vector)
|
|||
return it;
|
||||
}
|
||||
|
||||
vector_t *
|
||||
vector_iterator_vector(vector_iter_t *it)
|
||||
{
|
||||
return it->vector;
|
||||
}
|
||||
|
||||
int
|
||||
vector_iterator_count(vector_iter_t *it)
|
||||
{
|
||||
int count = 0;
|
||||
int pos = it->current;
|
||||
|
||||
if (!it->filter)
|
||||
return vector_count(it->vector);
|
||||
vector_iterator_reset(it);
|
||||
|
||||
while(vector_iterator_next(it))
|
||||
if (!it->filter) {
|
||||
count = vector_count(it->vector);
|
||||
} else {
|
||||
while (vector_iterator_next(it)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
vector_iterator_set_current(it, pos);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -132,13 +161,65 @@ vector_iterator_count(vector_iter_t *it)
|
|||
void *
|
||||
vector_iterator_next(vector_iter_t *it)
|
||||
{
|
||||
// TODO Filter results
|
||||
it->current++;
|
||||
return vector_item(it->vector, it->current);
|
||||
void *item;
|
||||
|
||||
if (it->current >= vector_count(it->vector))
|
||||
return NULL;
|
||||
|
||||
while ((item = vector_item(it->vector, ++it->current))) {
|
||||
if (it->filter) {
|
||||
if (it->filter(item)) {
|
||||
return item;
|
||||
}
|
||||
} else {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *
|
||||
vector_iterator_prev(vector_iter_t *it)
|
||||
{
|
||||
void *item;
|
||||
|
||||
if (it->current == -1)
|
||||
return NULL;
|
||||
|
||||
while ((item = vector_item(it->vector, --it->current))) {
|
||||
if (it->filter) {
|
||||
if (it->filter(item)) {
|
||||
return item;
|
||||
}
|
||||
} else {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
vector_iterator_set_filter(vector_iter_t *it, int (*filter) (void *item))
|
||||
vector_iterator_set_filter(vector_iter_t *it, int
|
||||
(*filter)(void *item))
|
||||
{
|
||||
it->filter = filter;
|
||||
}
|
||||
|
||||
void
|
||||
vector_iterator_set_current(vector_iter_t *it, int current)
|
||||
{
|
||||
it->current = current;
|
||||
}
|
||||
|
||||
int
|
||||
vector_iterator_current(vector_iter_t *it)
|
||||
{
|
||||
return it->current;
|
||||
}
|
||||
|
||||
void
|
||||
vector_iterator_reset(vector_iter_t *it)
|
||||
{
|
||||
vector_iterator_set_current(it, -1);
|
||||
}
|
||||
|
||||
|
|
38
src/vector.h
38
src/vector.h
|
@ -106,6 +106,12 @@ vector_remove(vector_t *vector, void *item);
|
|||
void *
|
||||
vector_item(vector_t *vector, int index);
|
||||
|
||||
/**
|
||||
* @brief Return first item of the vector
|
||||
*/
|
||||
void *
|
||||
vector_first(vector_t *vector);
|
||||
|
||||
/**
|
||||
* @brief Get the index of an item
|
||||
*
|
||||
|
@ -128,6 +134,12 @@ vector_count(vector_t *vector);
|
|||
vector_iter_t
|
||||
vector_iterator(vector_t *vector);
|
||||
|
||||
/**
|
||||
* @brief Return the vector of this iterator
|
||||
*/
|
||||
vector_t *
|
||||
vector_iterator_vector(vector_iter_t *it);
|
||||
|
||||
/**
|
||||
* @brief Return the number of items of iterator
|
||||
*/
|
||||
|
@ -135,11 +147,17 @@ int
|
|||
vector_iterator_count(vector_iter_t *it);
|
||||
|
||||
/**
|
||||
* @brief Return next element of the iterator
|
||||
* @brief Return next element of iterator
|
||||
*/
|
||||
void *
|
||||
vector_iterator_next(vector_iter_t *it);
|
||||
|
||||
/**
|
||||
* @brief Return prev element of iterator
|
||||
*/
|
||||
void *
|
||||
vector_iterator_prev(vector_iter_t *it);
|
||||
|
||||
/**
|
||||
* @brief Set iterator filter funcion
|
||||
*
|
||||
|
@ -148,4 +166,22 @@ vector_iterator_next(vector_iter_t *it);
|
|||
void
|
||||
vector_iterator_set_filter(vector_iter_t *it, int (*filter) (void *item));
|
||||
|
||||
/**
|
||||
* @brief Set current iterator position
|
||||
*/
|
||||
void
|
||||
vector_iterator_set_current(vector_iter_t *it, int current);
|
||||
|
||||
/**
|
||||
* @brief Return current iterator position
|
||||
*/
|
||||
int
|
||||
vector_iterator_current(vector_iter_t *it);
|
||||
|
||||
/**
|
||||
* @brief Reset iterator position to initial
|
||||
*/
|
||||
void
|
||||
vector_iterator_reset(vector_iter_t *it);
|
||||
|
||||
#endif /* __SNGREP_VECTOR_H_ */
|
||||
|
|
Loading…
Reference in New Issue