/* eXosip - This is the eXtended osip library. Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org eXosip is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. eXosip is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef ENABLE_MPATROL #include #endif #include "eXosip2.h" extern eXosip_t eXosip; static int eXosip_create_transaction (eXosip_call_t * jc, eXosip_dialog_t * jd, osip_message_t * request); static int eXosip_create_cancel_transaction (eXosip_call_t * jc, eXosip_dialog_t * jd, osip_message_t * request); static int _eXosip_call_reuse_contact(osip_message_t *invite, osip_message_t *msg); static int eXosip_create_transaction (eXosip_call_t * jc, eXosip_dialog_t * jd, osip_message_t * request) { osip_event_t *sipevent; osip_transaction_t *tr; int i; i = _eXosip_transaction_init (&tr, NICT, eXosip.j_osip, request); if (i != 0) { /* TODO: release the j_call.. */ osip_message_free (request); return -1; } if (jd != NULL) osip_list_add (jd->d_out_trs, tr, 0); sipevent = osip_new_outgoing_sipmessage (request); sipevent->transactionid = tr->transactionid; osip_transaction_set_your_instance (tr, __eXosip_new_jinfo (jc, jd, NULL, NULL)); osip_transaction_add_event (tr, sipevent); __eXosip_wakeup (); return 0; } static int eXosip_create_cancel_transaction (eXosip_call_t * jc, eXosip_dialog_t * jd, osip_message_t * request) { osip_event_t *sipevent; osip_transaction_t *tr; int i; i = _eXosip_transaction_init (&tr, NICT, eXosip.j_osip, request); if (i != 0) { /* TODO: release the j_call.. */ osip_message_free (request); return -2; } osip_list_add (eXosip.j_transactions, tr, 0); sipevent = osip_new_outgoing_sipmessage (request); sipevent->transactionid = tr->transactionid; osip_transaction_add_event (tr, sipevent); __eXosip_wakeup (); return 0; } static int _eXosip_call_reuse_contact(osip_message_t *invite, osip_message_t *msg) { osip_contact_t *co_invite=NULL; osip_contact_t *co_msg=NULL; int i; i = osip_message_get_contact(invite, 0, &co_invite); if (i<0 || co_invite==NULL || co_invite->url==NULL) { return -1; } i = osip_message_get_contact(msg, 0, &co_msg); if (i>=0 && co_msg!=NULL) { osip_list_remove(&msg->contacts, 0); osip_contact_free(co_msg); } co_msg=NULL; i = osip_contact_clone(co_invite, &co_msg); if (i>=0 && co_msg!=NULL) { osip_list_add(&msg->contacts, co_msg, 0); return 0; } return -1; } int _eXosip_call_transaction_find (int tid, eXosip_call_t ** jc, eXosip_dialog_t ** jd, osip_transaction_t ** tr) { for (*jc = eXosip.j_calls; *jc != NULL; *jc = (*jc)->next) { if ((*jc)->c_inc_tr != NULL && (*jc)->c_inc_tr->transactionid == tid) { *tr = (*jc)->c_inc_tr; *jd = (*jc)->c_dialogs; return 0; } if ((*jc)->c_out_tr != NULL && (*jc)->c_out_tr->transactionid == tid) { *tr = (*jc)->c_out_tr; *jd = (*jc)->c_dialogs; return 0; } for (*jd = (*jc)->c_dialogs; *jd != NULL; *jd = (*jd)->next) { osip_transaction_t *transaction; int pos = 0; while (!osip_list_eol ((*jd)->d_inc_trs, pos)) { transaction = (osip_transaction_t *) osip_list_get ((*jd)->d_inc_trs, pos); if (transaction != NULL && transaction->transactionid == tid) { *tr = transaction; return 0; } pos++; } pos = 0; while (!osip_list_eol ((*jd)->d_out_trs, pos)) { transaction = (osip_transaction_t *) osip_list_get ((*jd)->d_out_trs, pos); if (transaction != NULL && transaction->transactionid == tid) { *tr = transaction; return 0; } pos++; } } } *jd = NULL; *jc = NULL; return -1; } int eXosip_call_set_reference (int id, void *reference) { eXosip_dialog_t *jd = NULL; eXosip_call_t *jc = NULL; if (id > 0) { eXosip_call_dialog_find (id, &jc, &jd); if (jc == NULL) { eXosip_call_find (id, &jc); } } if (jc == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No call here?\n")); return -1; } jc->external_reference = reference; return 0; } /* this method can't be called unless the previous INVITE transaction is over. */ int eXosip_call_build_initial_invite (osip_message_t ** invite, const char *to, const char *from, const char *route, const char *subject) { int i; osip_uri_param_t *uri_param = NULL; osip_to_t *_to = NULL; char transport[10]; *invite = NULL; if (to != NULL && *to == '\0') return -1; if (route != NULL && *route == '\0') route = NULL; if (subject != NULL && *subject == '\0') subject = NULL; i = osip_to_init (&_to); if (i != 0) return -1; i = osip_to_parse (_to, to); if (i != 0) { osip_to_free (_to); return -1; } osip_uri_uparam_get_byname (_to->url, "transport", &uri_param); if (uri_param != NULL && uri_param->gvalue != NULL) snprintf(transport, sizeof(transport), "%s", uri_param->gvalue); else if (eXosip.net_interfaces[0].net_socket > 0) snprintf(transport, sizeof(transport), "%s", "UDP"); else snprintf(transport, sizeof(transport), "%s", "TCP"); i = generating_request_out_of_dialog (invite, "INVITE", to, transport, from, route); osip_to_free (_to); if (i != 0) return -1; _eXosip_dialog_add_contact(*invite, NULL); if (subject != NULL) osip_message_set_subject (*invite, subject); /* after this delay, we should send a CANCEL */ osip_message_set_expires (*invite, "120"); return 0; } int eXosip_call_send_initial_invite (osip_message_t * invite) { eXosip_call_t *jc; osip_transaction_t *transaction; osip_event_t *sipevent; int i; eXosip_call_init (&jc); i = _eXosip_transaction_init (&transaction, ICT, eXosip.j_osip, invite); if (i != 0) { eXosip_call_free (jc); osip_message_free (invite); return -1; } jc->c_out_tr = transaction; sipevent = osip_new_outgoing_sipmessage (invite); sipevent->transactionid = transaction->transactionid; osip_transaction_set_your_instance (transaction, __eXosip_new_jinfo (jc, NULL, NULL, NULL)); osip_transaction_add_event (transaction, sipevent); jc->external_reference = NULL; ADD_ELEMENT (eXosip.j_calls, jc); eXosip_update (); /* fixed? */ __eXosip_wakeup (); return jc->c_id; } int eXosip_call_build_ack (int did, osip_message_t ** _ack) { eXosip_dialog_t *jd = NULL; eXosip_call_t *jc = NULL; osip_transaction_t *tr = NULL; osip_message_t *ack; char *transport; int i; *_ack = NULL; if (did > 0) { eXosip_call_dialog_find (did, &jc, &jd); } if (jc == NULL || jd == NULL || jd->d_dialog == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No call here?\n")); return -1; } tr = eXosip_find_last_invite (jc, jd); if (tr == NULL || tr->orig_request == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No transaction for call?\n")); return -1; } if (0 != osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: ACK are only sent for invite transactions\n")); return -1; } transport = NULL; transport = _eXosip_transport_protocol (tr->orig_request); if (transport == NULL) i = _eXosip_build_request_within_dialog (&ack, "ACK", jd->d_dialog, "UDP"); else i = _eXosip_build_request_within_dialog (&ack, "ACK", jd->d_dialog, transport); if (i != 0) { return -1; } _eXosip_call_reuse_contact(tr->orig_request, ack); /* Fix CSeq Number when request has been exchanged during INVITE transactions */ if (tr->orig_request->cseq != NULL && tr->orig_request->cseq->number != NULL) { if (ack != NULL && ack->cseq != NULL && ack->cseq->number != NULL) { osip_free (ack->cseq->number); ack->cseq->number = osip_strdup (tr->orig_request->cseq->number); } } /* copy all credentials from INVITE! */ { int pos = 0; int i; osip_proxy_authorization_t *pa = NULL; i = osip_message_get_proxy_authorization (tr->orig_request, pos, &pa); while (i == 0 && pa != NULL) { osip_proxy_authorization_t *pa2; i = osip_proxy_authorization_clone (pa, &pa2); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "Error in credential from INVITE\n")); break; } osip_list_add (&ack->proxy_authorizations, pa2, -1); pa = NULL; pos++; i = osip_message_get_proxy_authorization (tr->orig_request, pos, &pa); } } *_ack = ack; return 0; } int eXosip_call_send_ack (int did, osip_message_t * ack) { eXosip_dialog_t *jd = NULL; eXosip_call_t *jc = NULL; osip_route_t *route; char *host; int port; if (did > 0) { eXosip_call_dialog_find (did, &jc, &jd); } if (jc == NULL || jd == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No call here?\n")); if (ack != NULL) osip_message_free (ack); return -1; } if (ack == NULL) { int i; i = eXosip_call_build_ack (did, &ack); if (i != 0) { return -1; } } osip_message_get_route (ack, 0, &route); if (route != NULL) { osip_uri_param_t *lr_param = NULL; osip_uri_uparam_get_byname (route->url, "lr", &lr_param); if (lr_param == NULL) route = NULL; } if (route != NULL) { port = 5060; if (route->url->port != NULL) port = osip_atoi (route->url->port); host = route->url->host; } else { port = 5060; if (ack->req_uri->port != NULL) port = osip_atoi (ack->req_uri->port); host = ack->req_uri->host; } cb_snd_message (NULL, ack, host, port, -1); if (jd->d_ack != NULL) osip_message_free (jd->d_ack); jd->d_ack = ack; return 0; } int eXosip_call_build_request (int jid, const char *method, osip_message_t ** request) { eXosip_dialog_t *jd = NULL; eXosip_call_t *jc = NULL; osip_transaction_t *transaction; char *transport; int i; *request = NULL; if (method == NULL || method[0] == '\0') return -1; if (jid > 0) { eXosip_call_dialog_find (jid, &jc, &jd); } if (jd == NULL || jd->d_dialog == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No call here?\n")); return -1; } transaction = NULL; if (0 == osip_strcasecmp (method, "INVITE")) { transaction = eXosip_find_last_invite (jc, jd); } else /* OPTIONS, UPDATE, INFO, REFER, ?... */ { transaction = eXosip_find_last_transaction (jc, jd, method); } if (transaction != NULL) { if (0 != osip_strcasecmp (method, "INVITE")) { if (transaction->state != NICT_TERMINATED && transaction->state != NIST_TERMINATED && transaction->state != NICT_COMPLETED && transaction->state != NIST_COMPLETED) return -1; } else { if (transaction->state != ICT_TERMINATED && transaction->state != IST_TERMINATED && transaction->state != IST_CONFIRMED && transaction->state != ICT_COMPLETED) return -1; } } transport = NULL; transaction = eXosip_find_last_invite (jc, jd); if (transaction != NULL && transaction->orig_request != NULL) transport = _eXosip_transport_protocol (transaction->orig_request); transaction = NULL; if (transport == NULL) i = _eXosip_build_request_within_dialog (request, method, jd->d_dialog, "UDP"); else i = _eXosip_build_request_within_dialog (request, method, jd->d_dialog, transport); if (i != 0) return -2; if (jc->response_auth != NULL) eXosip_add_authentication_information (*request, jc->response_auth); return 0; } int eXosip_call_send_request (int jid, osip_message_t * request) { eXosip_dialog_t *jd = NULL; eXosip_call_t *jc = NULL; osip_transaction_t *transaction; osip_event_t *sipevent; int i; if (request == NULL) return -1; if (request->sip_method == NULL) { osip_message_free (request); return -1; } if (jid > 0) { eXosip_call_dialog_find (jid, &jc, &jd); } if (jd == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No call here?\n")); osip_message_free (request); return -1; } transaction = NULL; if (0 == osip_strcasecmp (request->sip_method, "INVITE")) { transaction = eXosip_find_last_invite (jc, jd); } else /* OPTIONS, UPDATE, INFO, REFER, ?... */ { transaction = eXosip_find_last_transaction (jc, jd, request->sip_method); } if (transaction != NULL) { if (0 != osip_strcasecmp (request->sip_method, "INVITE")) { if (transaction->state != NICT_TERMINATED && transaction->state != NIST_TERMINATED && transaction->state != NICT_COMPLETED && transaction->state != NIST_COMPLETED) { osip_message_free (request); return -1; } } else { if (transaction->state != ICT_TERMINATED && transaction->state != IST_TERMINATED && transaction->state != IST_CONFIRMED && transaction->state != ICT_COMPLETED) { osip_message_free (request); return -1; } } } transaction = NULL; if (0 != osip_strcasecmp (request->sip_method, "INVITE")) { i = _eXosip_transaction_init (&transaction, NICT, eXosip.j_osip, request); } else { i = _eXosip_transaction_init (&transaction, ICT, eXosip.j_osip, request); } if (i != 0) { osip_message_free (request); return -2; } osip_list_add (jd->d_out_trs, transaction, 0); sipevent = osip_new_outgoing_sipmessage (request); sipevent->transactionid = transaction->transactionid; osip_transaction_set_your_instance (transaction, __eXosip_new_jinfo (jc, jd, NULL, NULL)); osip_transaction_add_event (transaction, sipevent); __eXosip_wakeup (); return 0; } int eXosip_call_build_refer (int did, const char *refer_to, osip_message_t ** request) { int i; *request = NULL; i = eXosip_call_build_request (did, "REFER", request); if (i != 0) return -1; if (refer_to == NULL || refer_to[0] == '\0') return 0; osip_message_set_header (*request, "Refer-to", refer_to); return 0; } int eXosip_call_build_options (int did, osip_message_t ** request) { int i; *request = NULL; i = eXosip_call_build_request (did, "OPTIONS", request); if (i != 0) return -1; return 0; } int eXosip_call_build_info (int did, osip_message_t ** request) { int i; *request = NULL; i = eXosip_call_build_request (did, "INFO", request); if (i != 0) return -1; return 0; } int eXosip_call_build_update (int did, osip_message_t ** request) { int i; *request = NULL; i = eXosip_call_build_request (did, "UPDATE", request); if (i != 0) return -1; return 0; } int eXosip_call_build_notify (int did, int subscription_status, osip_message_t ** request) { char subscription_state[50]; char *tmp; int i; *request = NULL; i = eXosip_call_build_request (did, "NOTIFY", request); if (i != 0) return -1; if (subscription_status == EXOSIP_SUBCRSTATE_PENDING) osip_strncpy (subscription_state, "pending;expires=", 16); else if (subscription_status == EXOSIP_SUBCRSTATE_ACTIVE) osip_strncpy (subscription_state, "active;expires=", 15); else if (subscription_status == EXOSIP_SUBCRSTATE_TERMINATED) { int reason = NORESOURCE; if (reason == DEACTIVATED) osip_strncpy (subscription_state, "terminated;reason=deactivated", 29); else if (reason == PROBATION) osip_strncpy (subscription_state, "terminated;reason=probation", 27); else if (reason == REJECTED) osip_strncpy (subscription_state, "terminated;reason=rejected", 26); else if (reason == TIMEOUT) osip_strncpy (subscription_state, "terminated;reason=timeout", 25); else if (reason == GIVEUP) osip_strncpy (subscription_state, "terminated;reason=giveup", 24); else if (reason == NORESOURCE) osip_strncpy (subscription_state, "terminated;reason=noresource", 29); } tmp = subscription_state + strlen (subscription_state); if (subscription_status != EXOSIP_SUBCRSTATE_TERMINATED) sprintf (tmp, "%i", 180); osip_message_set_header (*request, "Subscription-State", subscription_state); return 0; } int eXosip_call_build_answer (int tid, int status, osip_message_t ** answer) { int i = -1; eXosip_dialog_t *jd = NULL; eXosip_call_t *jc = NULL; osip_transaction_t *tr = NULL; *answer = NULL; if (tid > 0) { _eXosip_call_transaction_find (tid, &jc, &jd, &tr); } if (tr == NULL || jd == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No call here?\n")); return -1; } if (0 == osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) { if (status > 100 && status < 200) { i = _eXosip_answer_invite_1xx (jc, jd, status, answer); } else if (status > 199 && status < 300) { i = _eXosip_answer_invite_2xx (jc, jd, status, answer); } else if (status > 300 && status <= 699) { i = _eXosip_answer_invite_3456xx (jc, jd, status, answer); } else { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: wrong status code (101d_dialog, status, tr->orig_request); } else { i = _eXosip_build_response_default (answer, NULL, status, tr->orig_request); } if (status > 100 && status < 300) i = complete_answer_that_establish_a_dialog (*answer, tr->orig_request); } if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "ERROR: Could not create response for %s\n", tr->orig_request->sip_method)); return -1; } return 0; } int eXosip_call_send_answer (int tid, int status, osip_message_t * answer) { int i = -1; eXosip_dialog_t *jd = NULL; eXosip_call_t *jc = NULL; osip_transaction_t *tr = NULL; osip_event_t *evt_answer; if (tid > 0) { _eXosip_call_transaction_find (tid, &jc, &jd, &tr); } if (jd == NULL || tr == NULL || tr->orig_request == NULL || tr->orig_request->sip_method == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No call here or no transaction for call\n")); osip_message_free (answer); return -1; } if (answer == NULL) { if (0 == osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) { if (status >= 100 && status <= 199) { } else if (status >= 300 && status <= 699) { } else { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: Wrong parameter?\n")); osip_message_free (answer); return -1; } } } /* is the transaction already answered? */ if (tr->state == IST_COMPLETED || tr->state == IST_CONFIRMED || tr->state == IST_TERMINATED || tr->state == NIST_COMPLETED || tr->state == NIST_TERMINATED) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: transaction already answered\n")); osip_message_free (answer); return -1; } if (answer == NULL) { if (0 == osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) { if (status < 200) i = _eXosip_default_answer_invite_1xx (jc, jd, status); else i = _eXosip_default_answer_invite_3456xx (jc, jd, status); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: cannot send response!\n")); return -1; } } else { /* TODO */ OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: a response must be given!\n")); return -1; } return 0; } else { i = 0; } if (0 == osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) { if (MSG_IS_STATUS_1XX (answer)) { if (jd == NULL) { i = eXosip_dialog_init_as_uas (&jd, tr->orig_request, answer); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: cannot create dialog!\n")); i = 0; } else { ADD_ELEMENT (jc->c_dialogs, jd); } } } else if (MSG_IS_STATUS_2XX (answer)) { if (jd == NULL) { i = eXosip_dialog_init_as_uas (&jd, tr->orig_request, answer); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: cannot create dialog!\n")); osip_message_free (answer); return -1; } ADD_ELEMENT (jc->c_dialogs, jd); } else i = 0; eXosip_dialog_set_200ok (jd, answer); /* wait for a ACK */ osip_dialog_set_state (jd->d_dialog, DIALOG_CONFIRMED); } else if (answer->status_code >= 300 && answer->status_code <= 699) { i = 0; } else { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: wrong status code (101transactionid = tr->transactionid; osip_transaction_add_event (tr, evt_answer); eXosip_update (); __eXosip_wakeup (); return 0; } int eXosip_call_terminate (int cid, int did) { int i; osip_transaction_t *tr; osip_message_t *request = NULL; eXosip_dialog_t *jd = NULL; eXosip_call_t *jc = NULL; char *transport = NULL; if (did > 0) { eXosip_call_dialog_find (did, &jc, &jd); if (jd == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No call here?\n")); return -1; } } else { eXosip_call_find (cid, &jc); } if (jc == NULL) { return -1; } tr = eXosip_find_last_out_invite (jc, jd); if (tr != NULL && tr->last_response != NULL && MSG_IS_STATUS_1XX (tr->last_response)) { i = generating_cancel (&request, tr->orig_request); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: cannot terminate this call!\n")); return -2; } i = eXosip_create_cancel_transaction (jc, jd, request); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: cannot initiate SIP transaction!\n")); return i; } if (jd != NULL) { osip_dialog_free (jd->d_dialog); jd->d_dialog = NULL; eXosip_update (); /* AMD 30/09/05 */ } return 0; } if (jd == NULL || jd->d_dialog == NULL) { /* Check if some dialog exists */ if (jd != NULL && jd->d_dialog != NULL) { transport = NULL; if (tr != NULL && tr->orig_request != NULL) transport = _eXosip_transport_protocol (tr->orig_request); if (transport == NULL) i = generating_bye (&request, jd->d_dialog, "UDP"); else i = generating_bye (&request, jd->d_dialog, transport); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: cannot terminate this call!\n")); return -2; } if (jc->response_auth != NULL) eXosip_add_authentication_information (request, jc->response_auth); i = eXosip_create_transaction (jc, jd, request); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: cannot initiate SIP transaction!\n")); return -2; } osip_dialog_free (jd->d_dialog); jd->d_dialog = NULL; eXosip_update (); /* AMD 30/09/05 */ return 0; } OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No established dialog!\n")); return -1; } if (tr == NULL) { /*this may not be enough if it's a re-INVITE! */ tr = eXosip_find_last_inc_invite (jc, jd); if (tr != NULL && tr->last_response != NULL && MSG_IS_STATUS_1XX (tr->last_response)) { /* answer with 603 */ i = eXosip_call_send_answer (tr->transactionid, 603, NULL); return i; } } transport = NULL; if (tr != NULL && tr->orig_request != NULL) transport = _eXosip_transport_protocol (tr->orig_request); if (transport == NULL) i = generating_bye (&request, jd->d_dialog, "UDP"); else i = generating_bye (&request, jd->d_dialog, transport); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: cannot terminate this call!\n")); return -2; } if (jc->response_auth != NULL) eXosip_add_authentication_information (request, jc->response_auth); i = eXosip_create_transaction (jc, jd, request); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: cannot initiate SIP transaction!\n")); return -2; } osip_dialog_free (jd->d_dialog); jd->d_dialog = NULL; eXosip_update (); /* AMD 30/09/05 */ return 0; } int eXosip_call_build_prack (int tid, osip_message_t ** prack) { eXosip_dialog_t *jd = NULL; eXosip_call_t *jc = NULL; osip_transaction_t *tr = NULL; osip_header_t *rseq; char *transport; int i; *prack = NULL; if (tid > 0) { _eXosip_call_transaction_find (tid, &jc, &jd, &tr); } if (jc == NULL || jd == NULL || jd->d_dialog == NULL || tr == NULL || tr->orig_request == NULL || tr->orig_request->sip_method == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No call here or no transaction for call\n")); return -1; } if (0 != osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) return -1; /* PRACK are only send in the PROCEEDING state */ if (tr->state != ICT_PROCEEDING) return -1; if (tr->orig_request->cseq == NULL || tr->orig_request->cseq->number == NULL || tr->orig_request->cseq->method == NULL) return -1; transport = NULL; if (tr != NULL && tr->orig_request != NULL) transport = _eXosip_transport_protocol (tr->orig_request); if (transport == NULL) i = _eXosip_build_request_within_dialog (prack, "PRACK", jd->d_dialog, "UDP"); else i = _eXosip_build_request_within_dialog (prack, "PRACK", jd->d_dialog, transport); if (i != 0) return -2; osip_message_header_get_byname (tr->last_response, "RSeq", 0, &rseq); if (rseq != NULL && rseq->hvalue != NULL) { char tmp[128]; memset (tmp, '\0', sizeof (tmp)); snprintf (tmp, 127, "%s %s %s", rseq->hvalue, tr->orig_request->cseq->number, tr->orig_request->cseq->method); osip_message_set_header (*prack, "RAck", tmp); } return 0; } int eXosip_call_send_prack (int tid, osip_message_t * prack) { eXosip_dialog_t *jd = NULL; eXosip_call_t *jc = NULL; osip_transaction_t *tr = NULL; osip_event_t *sipevent; int i; if (prack == NULL) return -1; if (tid > 0) { _eXosip_call_transaction_find (tid, &jc, &jd, &tr); } if (jc == NULL || jd == NULL || jd->d_dialog == NULL || tr == NULL || tr->orig_request == NULL || tr->orig_request->sip_method == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No call here or no transaction for call\n")); osip_message_free (prack); return -1; } if (0 != osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) { osip_message_free (prack); return -1; } /* PRACK are only send in the PROCEEDING state */ if (tr->state != ICT_PROCEEDING) { osip_message_free (prack); return -1; } tr = NULL; i = _eXosip_transaction_init (&tr, NICT, eXosip.j_osip, prack); if (i != 0) { osip_message_free (prack); return -2; } osip_list_add (jd->d_out_trs, tr, 0); sipevent = osip_new_outgoing_sipmessage (prack); sipevent->transactionid = tr->transactionid; osip_transaction_set_your_instance (tr, __eXosip_new_jinfo (jc, jd, NULL, NULL)); osip_transaction_add_event (tr, sipevent); __eXosip_wakeup (); return 0; } int _eXosip_call_redirect_request (eXosip_call_t * jc, eXosip_dialog_t * jd, osip_transaction_t * out_tr) { osip_transaction_t *tr = NULL; osip_message_t *msg = NULL; osip_event_t *sipevent; int cseq; osip_via_t *via; osip_contact_t *co; int pos; int i; int protocol = IPPROTO_UDP; if (jc == NULL) return -1; if (jd != NULL) { if (jd->d_out_trs == NULL) return -1; } if (out_tr == NULL || out_tr->orig_request == NULL || out_tr->last_response == NULL) return -1; osip_message_clone (out_tr->orig_request, &msg); if (msg == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: could not clone msg for authentication\n")); return -1; } via = (osip_via_t *) osip_list_get (&msg->vias, 0); if (via == NULL || msg->cseq == NULL || msg->cseq->number == NULL) { osip_message_free (msg); OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: missing via or cseq header\n")); return -1; } co = NULL; pos = 0; while (!osip_list_eol (&out_tr->last_response->contacts, pos)) { co = (osip_contact_t *) osip_list_get (&out_tr->last_response->contacts, pos); if (co != NULL && co->url != NULL) { /* check tranport? Only allow UDP, right now */ osip_uri_param_t *u_param; int pos2; u_param = NULL; pos2 = 0; while (!osip_list_eol (&co->url->url_params, pos2)) { u_param = (osip_uri_param_t *) osip_list_get (&co->url->url_params, pos2); if (u_param == NULL || u_param->gname == NULL || u_param->gvalue == NULL) { u_param = NULL; /* skip */ } else if (0 == osip_strcasecmp (u_param->gvalue, "transport")) { if (0 == osip_strcasecmp (u_param->gvalue, "udp")) { #if 0 /* remove the UDP parameter */ osip_list_remove (co->url->url_params, pos2); osip_uri_param_free (u_param); #endif u_param = NULL; protocol = IPPROTO_UDP; break; /* ok */ } else if (0 == osip_strcasecmp (u_param->gvalue, "tcp")) { #if 0 osip_list_remove (co->url->url_params, pos2); osip_uri_param_free (u_param); #endif protocol = IPPROTO_TCP; u_param = NULL; } break; } pos2++; } if (u_param == NULL || u_param->gname == NULL || u_param->gvalue == NULL) { break; /* default is udp! */ } } pos++; co = NULL; } if (co == NULL || co->url == NULL) { osip_message_free (msg); OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: contact header\n")); return -1; } /* TODO: remove extra parameter from new request-uri check usual parameter like "transport" */ /* replace request-uri with NEW contact address */ osip_uri_free (msg->req_uri); msg->req_uri = NULL; osip_uri_clone (co->url, &msg->req_uri); /* increment cseq */ cseq = atoi (msg->cseq->number); osip_free (msg->cseq->number); msg->cseq->number = strdup_printf ("%i", cseq + 1); if (jd != NULL && jd->d_dialog != NULL) { jd->d_dialog->local_cseq++; } i = eXosip_update_top_via(msg); if (i!=0) { osip_message_free (msg); OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: unsupported protocol\n")); return -1; } eXosip_add_authentication_information (msg, out_tr->last_response); osip_message_force_update (msg); if (0 != osip_strcasecmp (msg->sip_method, "INVITE")) { i = _eXosip_transaction_init (&tr, NICT, eXosip.j_osip, msg); } else { i = _eXosip_transaction_init (&tr, ICT, eXosip.j_osip, msg); } if (i != 0) { osip_message_free (msg); return -1; } if (out_tr == jc->c_out_tr) { /* replace with the new tr */ osip_list_add (eXosip.j_transactions, jc->c_out_tr, 0); jc->c_out_tr = tr; /* fix dialog issue */ if (jd != NULL) { REMOVE_ELEMENT (jc->c_dialogs, jd); eXosip_dialog_free (jd); jd = NULL; } } else { /* add the new tr for the current dialog */ osip_list_add (jd->d_out_trs, tr, 0); } sipevent = osip_new_outgoing_sipmessage (msg); osip_transaction_set_your_instance (tr, __eXosip_new_jinfo (jc, jd, NULL, NULL)); osip_transaction_add_event (tr, sipevent); eXosip_update (); /* fixed? */ __eXosip_wakeup (); return 0; } int _eXosip_call_send_request_with_credential (eXosip_call_t * jc, eXosip_dialog_t * jd, osip_transaction_t * out_tr) { osip_transaction_t *tr = NULL; osip_message_t *msg = NULL; osip_event_t *sipevent; int cseq; osip_via_t *via; int i; int pos; if (jc == NULL) return -1; if (jd != NULL) { if (jd->d_out_trs == NULL) return -1; } if (out_tr == NULL || out_tr->orig_request == NULL || out_tr->last_response == NULL) return -1; osip_message_clone (out_tr->orig_request, &msg); if (msg == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: could not clone msg for authentication\n")); return -1; } /* remove all previous authentication headers */ pos = 0; while (!osip_list_eol (&msg->authorizations, pos)) { osip_authorization_t *auth; auth = (osip_authorization_t *) osip_list_get (&msg->authorizations, pos); osip_list_remove (&msg->authorizations, pos); osip_authorization_free (auth); pos++; } pos = 0; while (!osip_list_eol (&msg->proxy_authorizations, pos)) { osip_proxy_authorization_t *auth; auth = (osip_proxy_authorization_t *) osip_list_get (&msg-> proxy_authorizations, pos); osip_list_remove (&msg->proxy_authorizations, pos); osip_authorization_free (auth); pos++; } via = (osip_via_t *) osip_list_get (&msg->vias, 0); if (via == NULL || msg->cseq == NULL || msg->cseq->number == NULL) { osip_message_free (msg); OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: missing via or cseq header\n")); return -1; } /* increment cseq */ cseq = atoi (msg->cseq->number); osip_free (msg->cseq->number); msg->cseq->number = strdup_printf ("%i", cseq + 1); if (jd != NULL && jd->d_dialog != NULL) { jd->d_dialog->local_cseq++; } i = eXosip_update_top_via(msg); if (i!=0) { osip_message_free (msg); OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: unsupported protocol\n")); return -1; } eXosip_add_authentication_information (msg, out_tr->last_response); osip_message_force_update (msg); if (0 != osip_strcasecmp (msg->sip_method, "INVITE")) { i = _eXosip_transaction_init (&tr, NICT, eXosip.j_osip, msg); } else { i = _eXosip_transaction_init (&tr, ICT, eXosip.j_osip, msg); } if (i != 0) { osip_message_free (msg); return -1; } if (out_tr == jc->c_out_tr) { /* replace with the new tr */ osip_list_add (eXosip.j_transactions, jc->c_out_tr, 0); jc->c_out_tr = tr; /* fix dialog issue */ if (jd != NULL) { REMOVE_ELEMENT (jc->c_dialogs, jd); eXosip_dialog_free (jd); jd = NULL; } } else { /* add the new tr for the current dialog */ osip_list_add (jd->d_out_trs, tr, 0); } sipevent = osip_new_outgoing_sipmessage (msg); osip_transaction_set_your_instance (tr, __eXosip_new_jinfo (jc, jd, NULL, NULL)); osip_transaction_add_event (tr, sipevent); eXosip_update (); /* fixed? */ __eXosip_wakeup (); return 0; } int eXosip_call_get_referto(int did, char *refer_to, size_t refer_to_len) { eXosip_dialog_t *jd = NULL; eXosip_call_t *jc = NULL; osip_transaction_t *tr = NULL; osip_uri_t *referto_uri; char atmp[256]; char *referto_tmp=NULL; int i; eXosip_call_dialog_find (did, &jc, &jd); if (jc == NULL || jd == NULL || jd->d_dialog == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No call here?\n")); return -1; } tr = eXosip_find_last_invite (jc, jd); if (tr == NULL || tr->orig_request == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No transaction for call?\n")); return -1; } i = osip_uri_clone(jd->d_dialog->remote_uri->url, &referto_uri); if (i!=0) return -1; if (jd->d_dialog->type == CALLER) { snprintf(atmp, sizeof(atmp), "%s;to-tag=%s;from-tag=%s", jd->d_dialog->call_id, jd->d_dialog->remote_tag, jd->d_dialog->local_tag); } else { snprintf(atmp, sizeof(atmp), "%s;to-tag=%s;from-tag=%s", jd->d_dialog->call_id, jd->d_dialog->local_tag, jd->d_dialog->remote_tag); } osip_uri_uheader_add(referto_uri, osip_strdup("Replaces"), osip_strdup(atmp)); i = osip_uri_to_str(referto_uri, &referto_tmp); if (i!=0) { osip_uri_free(referto_uri); return -1; } snprintf(refer_to, refer_to_len, "%s", referto_tmp); osip_uri_free(referto_uri); return 0; }