const char * call_get_attribute(sip_call_t *call, enum sip_attr_id id, char *value) { sip_msg_t *first, *last; if (!call) return NULL; switch (id) { case SIP_ATTR_CALLINDEX: sprintf(value, "%d", call->index); break; case SIP_ATTR_CALLID: sprintf(value, "%s", call->callid); break; case SIP_ATTR_XCALLID: sprintf(value, "%s", call->xcallid); break; case SIP_ATTR_MSGCNT: sprintf(value, "%d", vector_count(call->msgs)); break; case SIP_ATTR_CALLSTATE: sprintf(value, "%s", call_state_to_str(call->state)); break; case SIP_ATTR_TRANSPORT: first = vector_first(call->msgs); sprintf(value, "%s", sip_transport_str(first->packet->type)); break; case SIP_ATTR_CONVDUR: timeval_to_duration(msg_get_time(call->cstart_msg), msg_get_time(call->cend_msg), value); break; case SIP_ATTR_TOTALDUR: first = vector_first(call->msgs); last = vector_last(call->msgs); timeval_to_duration(msg_get_time(first), msg_get_time(last), value); break; default: return msg_get_attribute(vector_first(call->msgs), id, value); break; } return strlen(value) ? value : NULL; }
void call_update_state(sip_call_t *call, sip_msg_t *msg) { const char *callstate; char dur[20]; int reqresp; sip_msg_t *first; if (!call_is_invite(call)) return; // Get the first message in the call first = vector_first(call->msgs); // Get current message Method / Response Code reqresp = msg->reqresp; // If this message is actually a call, get its current state if ((callstate = call_get_attribute(call, SIP_ATTR_CALLSTATE))) { if (!strcmp(callstate, SIP_CALLSTATE_CALLSETUP)) { if (reqresp == 200) { // Alice and Bob are talking call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_INCALL); // Store the timestap where call has started call->active = 1; call->cstart_msg = msg; } else if (reqresp == SIP_METHOD_CANCEL) { // 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, timeval_to_duration(msg_get_time(first), msg_get_time(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, timeval_to_duration(msg_get_time(first), msg_get_time(msg), dur)); call->active = 0; } } else if (!strcmp(callstate, SIP_CALLSTATE_INCALL)) { if (reqresp == SIP_METHOD_BYE) { // Thanks for all the fish! call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_COMPLETED); // Store Conversation duration call_set_attribute(call, SIP_ATTR_CONVDUR, timeval_to_duration(msg_get_time(call->cstart_msg), msg_get_time(msg), dur)); call->active = 0; } } else if (reqresp == SIP_METHOD_INVITE && strcmp(callstate, SIP_CALLSTATE_INCALL)) { // Call is being setup (after proper authentication) call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_CALLSETUP); call->active = 1; } else { // Store total call duration call_set_attribute(call, SIP_ATTR_TOTALDUR, timeval_to_duration(msg_get_time(first), msg_get_time(msg), dur)); } } else { // This is actually a call if (reqresp == SIP_METHOD_INVITE) { call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_CALLSETUP); call->active = 1; } } }