diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index ee75f3f2a..f1336a491 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -77,9 +77,9 @@ void sal_process_authentication(SalOp *op, belle_sip_response_t *response) { } if (belle_sip_provider_add_authorization(op->base.root->prov,request,response,&auth_list)) { if (is_within_dialog) { - sal_op_resend_request(op,request); - } else { sal_op_send_request(op,request); + } else { + sal_op_resend_request(op,request); } }else { ms_message("No auth info found for [%s]",sal_op_get_from(op)); @@ -115,7 +115,7 @@ static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *e op->callbacks.process_io_error(op,event); } } else { - ms_error("process_io_error not implemented yet for non transaction"); + ms_error("sal process_io_error not implemented yet for non transaction"); } } static void process_request_event(void *sal, const belle_sip_request_event_t *event) { @@ -126,17 +126,10 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev belle_sip_header_address_t* address; belle_sip_header_from_t* from_header; belle_sip_header_to_t* to; - belle_sip_header_content_type_t* content_type; belle_sip_response_t* resp; - belle_sip_header_call_id_t* call_id = belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t); - belle_sip_header_cseq_t* cseq = belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); - SalMessage salmsg; - char message_id[256]={0}; from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); - char* from; - if (dialog) { op=(SalOp*)belle_sip_dialog_get_application_data(dialog); } else if (strcmp("INVITE",belle_sip_request_get_method(req))==0) { @@ -148,34 +141,13 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev op->dir=SalOpDirIncoming; sal_op_presence_fill_cbs(op); } else if (strcmp("MESSAGE",belle_sip_request_get_method(req))==0) { - content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); - if (content_type - && strcmp("text",belle_sip_header_content_type_get_type(content_type))==0 - && strcmp("plain",belle_sip_header_content_type_get_subtype(content_type))==0) { - address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) - ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); - from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address)); - snprintf(message_id,sizeof(message_id)-1,"%s%i" - ,belle_sip_header_call_id_get_call_id(call_id) - ,belle_sip_header_cseq_get_seq_number(cseq)); - salmsg.from=from; - salmsg.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); - salmsg.url=NULL; /*FIXME not implemented yet*/ - salmsg.message_id=message_id; - op=sal_op_new((Sal*)sal); - ((Sal*)sal)->callbacks.text_received(op,&salmsg); - sal_op_release(op); - belle_sip_object_unref(address); - belle_sip_free(from); - return; - } else { - ms_error("Unsupported MESSAGE with content type [%s/%s]",belle_sip_header_content_type_get_type(content_type) - ,belle_sip_header_content_type_get_subtype(content_type)); - return; - } + op=sal_op_new((Sal*)sal); + op->dir=SalOpDirIncoming; + sal_op_message_fill_cbs(op); + } else { ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req)); - resp=belle_sip_response_create_from_request(req,500); + resp=belle_sip_response_create_from_request(req,501); belle_sip_provider_send_response(((Sal*)sal)->prov,resp); return; @@ -217,136 +189,139 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev static void process_response_event(void *user_ctx, const belle_sip_response_event_t *event){ belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); - if (!client_transaction) { - ms_error("Unexpected stateless response, trashing"); - return; - } - SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); belle_sip_response_t* response = belle_sip_response_event_get_response(event); - belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); - belle_sip_header_contact_t* original_contact; - belle_sip_header_address_t* contact_address=NULL; - belle_sip_header_via_t* via_header; - belle_sip_uri_t* contact_uri; - unsigned int contact_port; - const char* received; - int rport; - bool_t contact_updated=FALSE; - char* new_contact; - belle_sip_request_t* old_request=NULL;; - belle_sip_response_t* old_response=NULL;; int response_code = belle_sip_response_get_status_code(response); - - if (op->state == SalOpStateTerminated) { - belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code); + if (!client_transaction) { + ms_warning("Discarding state less response [%i]",response_code); return; - } - if (!op->base.remote_ua) { - sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response)); - } - - if (op->callbacks.process_response_event) { - /*Fix contact if needed*/ - via_header= (belle_sip_header_via_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_VIA); - received = belle_sip_header_via_get_received(via_header); - rport = belle_sip_header_via_get_rport(via_header); - if (!sal_op_get_contact(op)) { - /*check if contqct set in reauest*/ - - if ((original_contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t))) { - /*no contact set yet, try to see if sip tack has an updated one*/ - contact_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(original_contact))); - sal_op_set_contact_address(op,(const SalAddress *)contact_address); - belle_sip_object_unref(contact_address); - } else { - - /*hmm update contact from via, maybe useless, some op may not need any contact at all*/ - contact_address=belle_sip_header_address_new(); - contact_uri=belle_sip_uri_create(NULL,belle_sip_header_via_get_host(via_header)); - belle_sip_header_address_set_uri(contact_address,contact_uri); - - if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { - belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); - } - if (belle_sip_header_via_get_listening_port(via_header) - != belle_sip_listening_point_get_well_known_port(belle_sip_header_via_get_transport(via_header))) { - belle_sip_uri_set_port(contact_uri,belle_sip_header_via_get_listening_port(via_header) ); - } - contact_updated=TRUE; - } - } - - if (received!=NULL || rport>0) { - if (sal_op_get_contact(op)){ - contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op))); - } - contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address)); - if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) { - /*need to update host*/ - belle_sip_uri_set_host(contact_uri,received); - contact_updated=TRUE; - } - contact_port = belle_sip_uri_get_port(contact_uri); - if (rport>0 && rport!=contact_port && (contact_port+rport)!=5060) { - /*need to update port*/ - belle_sip_uri_set_port(contact_uri,rport); - contact_updated=TRUE; - } - - /*try to fix transport if needed (very unlikely)*/ - if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { - if (!belle_sip_uri_get_transport_param(contact_uri) - ||strcasecmp(belle_sip_uri_get_transport_param(contact_uri),belle_sip_header_via_get_transport(via_header))!=0) { - belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); - contact_updated=TRUE; - } - } else { - if (belle_sip_uri_get_transport_param(contact_uri)) { - contact_updated=TRUE; - belle_sip_uri_set_transport_param(contact_uri,NULL); - } - } - if (contact_updated) { - new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); - ms_message("Updating contact from [%s] to [%s] for [%p]",sal_op_get_contact(op),new_contact,op); - sal_op_set_contact(op,new_contact); - belle_sip_free(new_contact); - } - if (contact_address)belle_sip_object_unref(contact_address); - } - /*update request/response - * maybe only the transaction should be kept*/ - old_request=op->request; - op->request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); - belle_sip_object_ref(op->request); - if (old_request) belle_sip_object_unref(old_request); - - old_response=op->response; - op->response=response; /*kept for use at authorization time*/ - belle_sip_object_ref(op->response); - if (old_response) belle_sip_object_unref(old_response); - - /*handle authozation*/ - switch (response_code) { - case 200: { - sal_remove_pending_auth(op->base.root,op);/*just in case*/ - break; - } - case 401: - case 407:{ - if (op->state == SalOpStateTerminating) { - belle_sip_message("Op is in state terminating, nothing else to do"); - return; - } else { - sal_process_authentication(op,response); - return; - } - } - } - op->callbacks.process_response_event(op,event); - } else { - ms_error("Unhandled event response [%p]",event); + SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_header_contact_t* original_contact; + belle_sip_header_address_t* contact_address=NULL; + belle_sip_header_via_t* via_header; + belle_sip_uri_t* contact_uri; + unsigned int contact_port; + const char* received; + int rport; + bool_t contact_updated=FALSE; + char* new_contact; + belle_sip_request_t* old_request=NULL;; + belle_sip_response_t* old_response=NULL;; + + + if (op->state == SalOpStateTerminated) { + belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code); + return; + } + if (!op->base.remote_ua) { + sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response)); + } + + if (op->callbacks.process_response_event) { + /*Fix contact if needed*/ + via_header= (belle_sip_header_via_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_VIA); + received = belle_sip_header_via_get_received(via_header); + rport = belle_sip_header_via_get_rport(via_header); + if (!sal_op_get_contact(op)) { + /*check if contqct set in reauest*/ + + if ((original_contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t))) { + /*no contact set yet, try to see if sip tack has an updated one*/ + contact_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(original_contact))); + sal_op_set_contact_address(op,(const SalAddress *)contact_address); + belle_sip_object_unref(contact_address); + } else { + + /*hmm update contact from via, maybe useless, some op may not need any contact at all*/ + contact_address=belle_sip_header_address_new(); + contact_uri=belle_sip_uri_create(NULL,belle_sip_header_via_get_host(via_header)); + belle_sip_header_address_set_uri(contact_address,contact_uri); + + if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { + belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); + } + if (belle_sip_header_via_get_listening_port(via_header) + != belle_sip_listening_point_get_well_known_port(belle_sip_header_via_get_transport(via_header))) { + belle_sip_uri_set_port(contact_uri,belle_sip_header_via_get_listening_port(via_header) ); + } + contact_updated=TRUE; + } + } + + if (received!=NULL || rport>0) { + if (sal_op_get_contact(op)){ + contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op))); + } + contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address)); + if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) { + /*need to update host*/ + belle_sip_uri_set_host(contact_uri,received); + contact_updated=TRUE; + } + contact_port = belle_sip_uri_get_port(contact_uri); + if (rport>0 && rport!=contact_port && (contact_port+rport)!=5060) { + /*need to update port*/ + belle_sip_uri_set_port(contact_uri,rport); + contact_updated=TRUE; + } + + /*try to fix transport if needed (very unlikely)*/ + if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { + if (!belle_sip_uri_get_transport_param(contact_uri) + ||strcasecmp(belle_sip_uri_get_transport_param(contact_uri),belle_sip_header_via_get_transport(via_header))!=0) { + belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); + contact_updated=TRUE; + } + } else { + if (belle_sip_uri_get_transport_param(contact_uri)) { + contact_updated=TRUE; + belle_sip_uri_set_transport_param(contact_uri,NULL); + } + } + if (contact_updated) { + new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); + ms_message("Updating contact from [%s] to [%s] for [%p]",sal_op_get_contact(op),new_contact,op); + sal_op_set_contact(op,new_contact); + belle_sip_free(new_contact); + } + if (contact_address)belle_sip_object_unref(contact_address); + } + /*update request/response + * maybe only the transaction should be kept*/ + old_request=op->request; + op->request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_object_ref(op->request); + if (old_request) belle_sip_object_unref(old_request); + + old_response=op->response; + op->response=response; /*kept for use at authorization time*/ + belle_sip_object_ref(op->response); + if (old_response) belle_sip_object_unref(old_response); + + /*handle authozation*/ + switch (response_code) { + case 200: { + sal_remove_pending_auth(op->base.root,op);/*just in case*/ + break; + } + case 401: + case 407:{ + if (op->state == SalOpStateTerminating) { + belle_sip_message("Op is in state terminating, nothing else to do"); + return; + } else { + sal_process_authentication(op,response); + return; + } + } + } + + op->callbacks.process_response_event(op,event); + + } else { + ms_error("Unhandled event response [%p]",event); + } } } diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 46692786b..2f7262c6f 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -60,8 +60,8 @@ struct SalOp{ belle_sip_refresher_t* registration_refresher; bool_t sdp_offering; belle_sip_dialog_t* dialog; - belle_sip_header_address_t *replaces; - belle_sip_header_address_t *referred_by; + belle_sip_header_replaces_t *replaces; + belle_sip_header_t *referred_by; bool_t auto_answer_asked; SalMediaDescription *result; belle_sdp_session_description_t *sdp_answer; @@ -90,5 +90,7 @@ bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,S void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) ; /*presence*/ void sal_op_presence_fill_cbs(SalOp*op); +/*messaging*/ +void sal_op_message_fill_cbs(SalOp*op); #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 984881592..2c6401d81 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -266,7 +266,6 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t op->pending_server_trans=server_transaction; belle_sdp_session_description_t* sdp; belle_sip_request_t* req = belle_sip_request_event_get_request(event); - belle_sip_header_t* replace_header; belle_sip_dialog_state_t dialog_state; belle_sip_response_t* resp; belle_sip_header_t* call_info; @@ -279,8 +278,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t switch(dialog_state) { case BELLE_SIP_DIALOG_NULL: { - if (!op->replaces && (replace_header=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"replaces"))) { - op->replaces=belle_sip_header_address_parse(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(replace_header))); + if (!op->replaces && (op->replaces=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_replaces_t))) { belle_sip_object_ref(op->replaces); } else if(op->replaces) { ms_warning("replace header already set"); @@ -550,9 +548,15 @@ SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ } return h->result; } -int sal_call_refer(SalOp *h, const char *refer_to){ - ms_fatal("sal_call_refer not implemented yet"); - return -1; +int sal_call_refer(SalOp *op, const char *refer_to){ + belle_sip_header_refer_to_t* refer_to_header=belle_sip_header_refer_to_create(belle_sip_header_address_parse(refer_to)); + belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"REFER"):NULL; /*cannot create request if dialog not set yet*/ + if (!req) { + ms_error("Cannot refer to [%s] for op [%p]",refer_to,op); + return -1; + } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(refer_to_header)); + return sal_op_send_request(op,req); } int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ ms_fatal("sal_call_refer_with_replaces not implemented yet"); @@ -660,4 +664,49 @@ void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){ void sal_use_dates(Sal *ctx, bool_t enabled){ ms_warning("sal_use_dates not implemented yet"); } - +/* +static void process_refer(SalOp *op, belle_sip_request_event_t *event){ + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_header_refer_to_t *refer_to= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_refer_to_t);; + belle_sip_uri_t* refer_to_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)); + ms_message("Receiving REFER request on op [%p]",op); + if (refer_to){ + char *tmp; + if (refer_to_uri){ + if (op ){ + osip_uri_header_t *uh=NULL; + osip_header_t *referred_by=NULL; + osip_uri_header_get_byname(&from->url->url_headers,(char*)"Replaces",&uh); + if (belle_sip_uri_get_header(refer_to_uri,"Replaces")) + if (uh!=NULL && uh->gvalue && uh->gvalue[0]!='\0'){ + ms_message("Found replaces in Refer-To"); + if (op->replaces){ + ms_free(op->replaces); + } + op->replaces=ms_strdup(uh->gvalue); + } + osip_message_header_get_byname(ev->request,"Referred-By",0,&referred_by); + if (referred_by && referred_by->hvalue && referred_by->hvalue[0]!='\0'){ + if (op->referred_by) + ms_free(op->referred_by); + op->referred_by=ms_strdup(referred_by->hvalue); + } + } + osip_uri_header_freelist(&from->url->url_headers); + osip_from_to_str(from,&tmp); + sal->callbacks.refer_received(sal,op,tmp); + osip_free(tmp); + osip_from_free(from); + } + eXosip_lock(); + eXosip_call_build_answer(ev->tid,202,&ans); + if (ans) + eXosip_call_send_answer(ev->tid,202,ans); + eXosip_unlock(); + } + else + { + ms_warning("cannot do anything with the refer without destination\n"); + } +} +*/ diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 2fcbeb0bb..46492f63a 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -18,21 +18,103 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "sal_impl.h" -static void message_response_event(void *op_base, const belle_sip_response_event_t *event){ - /*nop for futur use*/ +static void process_error( SalOp* op) { + if (op->dir == SalOpDirOutgoing) { + op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); + } else { + ms_warning("unexpected io error for incoming message on op [%p]",op); + } + op->state=SalOpStateTerminated; + } +static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ + SalOp* op = (SalOp*)user_ctx; + process_error(op); +} +static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { + SalOp* op=(SalOp*)user_ctx; + process_error(op); +} +static void process_response_event(void *op_base, const belle_sip_response_event_t *event){ + SalOp* op = (SalOp*)op_base; + int code = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); + SalTextDeliveryStatus status; + if (code>=100 && code <200) + status=SalTextDeliveryInProgress; + else if (code>=200 && code <300) + status=SalTextDeliveryDone; + else + status=SalTextDeliveryFailed; + + op->base.root->callbacks.text_delivery_update(op,status); + +} +static bool_t is_plain_text(belle_sip_header_content_type_t* content_type) { + return strcmp("text",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("plain",belle_sip_header_content_type_get_subtype(content_type))==0; +} +static bool_t is_external_body(belle_sip_header_content_type_t* content_type) { + return strcmp("message",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("external-body",belle_sip_header_content_type_get_subtype(content_type))==0; +} + +static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { + SalOp* op = (SalOp*)op_base; + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req); + belle_sip_header_address_t* address; + belle_sip_header_from_t* from_header; + belle_sip_header_content_type_t* content_type; + belle_sip_response_t* resp; + belle_sip_header_call_id_t* call_id = belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t); + belle_sip_header_cseq_t* cseq = belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); + SalMessage salmsg; + char message_id[256]={0}; + int response_code=501; + char* from; + bool_t plain_text=FALSE; + bool_t external_body=FALSE; + + from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); + content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); + if (content_type && ((plain_text=is_plain_text(content_type)) + || (external_body=is_external_body(content_type)))) { + + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); + from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address)); + snprintf(message_id,sizeof(message_id)-1,"%s%i" + ,belle_sip_header_call_id_get_call_id(call_id) + ,belle_sip_header_cseq_get_seq_number(cseq)); + salmsg.from=from; + salmsg.text=plain_text?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL; + salmsg.url=external_body?belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL"):NULL; + salmsg.message_id=message_id; + op->base.root->callbacks.text_received(op,&salmsg); + belle_sip_object_unref(address); + belle_sip_free(from); + response_code=200; + } else { + ms_error("Unsupported MESSAGE with content type [%s/%s]",belle_sip_header_content_type_get_type(content_type) + ,belle_sip_header_content_type_get_subtype(content_type)); + response_code=501; /*not implemented sound appropriate*/ + } + resp = belle_sip_response_create_from_request(req,response_code); + belle_sip_server_transaction_send_response(server_transaction,resp); + sal_op_release(op); +} int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){ belle_sip_request_t* req; char content_type_raw[256]; - size_t content_length = strlen(msg); - if (!op->callbacks.process_response_event) - op->callbacks.process_response_event=message_response_event; + size_t content_length = msg?strlen(msg):0; + sal_op_message_fill_cbs(op); if (from) sal_op_set_from(op,from); if (to) sal_op_set_to(op,to); + op->dir=SalOpDirOutgoing; req=sal_op_build_request(op,"MESSAGE"); snprintf(content_type_raw,sizeof(content_type_raw),BELLE_SIP_CONTENT_TYPE ": %s",content_type); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_parse(content_type_raw))); @@ -44,3 +126,10 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) { return sal_message_send(op,from,to,"text/plain",msg); } + +void sal_op_message_fill_cbs(SalOp*op) { + op->callbacks.process_io_error=process_io_error; + op->callbacks.process_response_event=process_response_event; + op->callbacks.process_timeout=process_timeout; + op->callbacks.process_request_event=process_request_event; +} diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 31e457486..23f586088 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -965,11 +965,13 @@ static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){ ,chatStatusSal2Linphone(status) ,chat_msg->cb_ud); } - linphone_chat_message_destroy(chat_msg); - - if (!ms_list_find_custom((MSList*)calls, (MSCompareFunc) op_equals, op)) { - /*op was only create for messaging purpose, destroying*/ - sal_op_release(op); + if (status != SalTextDeliveryInProgress) { /*don't release op if progress*/ + linphone_chat_message_destroy(chat_msg); + + if (!ms_list_find_custom((MSList*)calls, (MSCompareFunc) op_equals, op)) { + /*op was only create for messaging purpose, destroying*/ + sal_op_release(op); + } } } diff --git a/tester/call_tester.c b/tester/call_tester.c index 3dd9cb0ca..3ca6ebe71 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -432,6 +432,67 @@ static void call_early_media() { linphone_core_manager_destroy(pauline); } +static void simple_call_transfer() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); +/* stats initial_marie_stat; + stats initial_pauline_stat; + stats initial_laure_stat;*/ + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new("./tester/laure_rc"); + char* laure_identity=linphone_address_as_string(laure->identity); + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,laure->lc); + + LinphoneCall* marie_call_pauline; + LinphoneCall* pauline_called_by_marie; +/* LinphoneCall* marie_call_laure;*/ + + CU_ASSERT_TRUE(call(marie,pauline)); + marie_call_pauline=linphone_core_get_current_call(marie->lc); + pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); + + + linphone_core_transfer_call(pauline->lc,pauline_called_by_marie,laure_identity); + +/* + initial_marie_stat=marie->stat; + initial_pauline_stat=pauline->stat; + initial_laure_stat=laure->stat; + + marie_call_laure=linphone_core_get_current_call(marie->lc); + + + linphone_core_transfer_call() + CU_ASSERT_TRUE(wait_for(marie->lc,laure->lc,&marie->stat.number_of_LinphoneCallUpdating,initial_marie_stat.number_of_LinphoneCallUpdating+1)); + + + + linphone_core_add_to_conference(marie->lc,marie_call_pauline); + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallResuming,initial_marie_stat.number_of_LinphoneCallResuming+1,2000)); + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,initial_pauline_stat.number_of_LinphoneCallStreamsRunning+1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,initial_marie_stat.number_of_LinphoneCallStreamsRunning+2,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,initial_laure_stat.number_of_LinphoneCallStreamsRunning+1,2000)); + + CU_ASSERT_TRUE(linphone_core_is_in_conference(marie->lc)); + CU_ASSERT_EQUAL(linphone_core_get_conference_size(marie->lc),3) + + linphone_core_terminate_conference(marie->lc); + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,2000)); + + +*/ + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); + ms_list_free(lcs); +} + int call_test_suite () { CU_pSuite pSuite = CU_add_suite("Call", init, uninit); if (NULL == CU_add_test(pSuite, "call_early_declined", call_early_declined)) { @@ -467,6 +528,10 @@ int call_test_suite () { if (NULL == CU_add_test(pSuite, "simple_conference", simple_conference)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "simple_call_transfer", simple_call_transfer)) { + return CU_get_error(); + } + return 0; } diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index a20d72581..7a1c8f133 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -114,9 +114,11 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,in bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { MSList* lcs=NULL; - lcs=ms_list_append(lcs,lc_1); + if (lc_1) + lcs=ms_list_append(lcs,lc_1); bool_t result; - lcs=ms_list_append(lcs,lc_2); + if (lc_2) + lcs=ms_list_append(lcs,lc_2); result=wait_for_list(lcs,counter,value,2000); ms_list_free(lcs); return result; @@ -153,6 +155,7 @@ LinphoneCoreManager* linphone_core_manager_new(const char* rc_file) { mgr->v_table.registration_state_changed=registration_state_changed; mgr->v_table.call_state_changed=call_state_changed; mgr->v_table.text_received=text_message_received; + mgr->v_table.message_received=message_received; mgr->v_table.new_subscription_request=new_subscribtion_request; mgr->v_table.notify_presence_recv=notify_presence_received; mgr->lc=configure_lc_from(&mgr->v_table,rc_file,1); diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index cc662c2f0..85cc719dd 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -57,6 +57,13 @@ typedef struct _stats { int number_of_LinphoneCallReleased; int number_of_LinphoneMessageReceived; + int number_of_LinphoneMessageReceivedLegacy; + int number_of_LinphoneMessageExtBodyReceived; + int number_of_LinphoneMessageInProgress; + int number_of_LinphoneMessageDelivered; + int number_of_LinphoneMessageNotDelivered; + + int number_of_NewSubscriptionRequest; int number_of_NotifyReceived; @@ -80,9 +87,12 @@ void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *c void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg); void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf); void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message); +void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* message); + void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url); void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); + LinphoneCore* create_lc_with_auth(unsigned int with_auth) ; LinphoneAddress * create_linphone_address(const char * domain); LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* file,int proxy_count); diff --git a/tester/message_tester.c b/tester/message_tester.c index a48e0dbe1..424a12b32 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -22,13 +22,40 @@ #include "liblinphone_tester.h" void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message) { - char* from=linphone_address_as_string(from_address); - ms_message("Message from [%s] is [%s]",from,message); + stats* counters = (stats*)linphone_core_get_user_data(lc); + counters->number_of_LinphoneMessageReceivedLegacy++; +} +void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* message) { + char* from=linphone_address_as_string(linphone_chat_message_get_from(message)); + ms_message("Message from [%s] is [%s] , external URL [%s]",from + ,linphone_chat_message_get_text(message) + ,linphone_chat_message_get_external_body_url(message)); ms_free(from); stats* counters = (stats*)linphone_core_get_user_data(lc); counters->number_of_LinphoneMessageReceived++; + if (linphone_chat_message_get_external_body_url(message)) + counters->number_of_LinphoneMessageExtBodyReceived++; } +void linphone_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { + LinphoneCore* lc=(LinphoneCore*)ud; + stats* counters = (stats*)linphone_core_get_user_data(lc); + ms_message("Message [%s] [%s]",linphone_chat_message_get_text(msg),linphone_chat_message_state_to_string(state)); + switch (state) { + case LinphoneChatMessageStateDelivered: + counters->number_of_LinphoneMessageDelivered++; + break; + case LinphoneChatMessageStateNotDelivered: + counters->number_of_LinphoneMessageNotDelivered++; + break; + case LinphoneChatMessageStateInProgress: + counters->number_of_LinphoneMessageInProgress++; + break; + default: + ms_error("Unexpected state [%s] for message [%p]",linphone_chat_message_state_to_string(state),msg); + } + +} static void text_message() { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); @@ -37,7 +64,56 @@ static void text_message() { LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageReceivedLegacy,1); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void text_message_with_ack() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + linphone_chat_room_send_message2(chat_room,message,linphone_chat_message_state_change,pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void text_message_with_external_body() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + linphone_chat_message_set_external_body_url(message,"http://www.linphone.org"); + linphone_chat_room_send_message2(chat_room,message,linphone_chat_message_state_change,pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void text_message_with_send_error() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + char* to = linphone_address_as_string(pauline->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(marie->lc,to); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + /*simultate a network error*/ + sal_set_send_error(marie->lc->sal, -1); + linphone_chat_room_send_message2(chat_room,message,linphone_chat_message_state_change,marie->lc); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageNotDelivered,1)); + /*CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageInProgress,1);*/ + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageReceived,0); + + sal_set_send_error(marie->lc->sal, 0); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } @@ -47,5 +123,15 @@ int message_test_suite () { if (NULL == CU_add_test(pSuite, "text_message", text_message)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "text_message_with_ack", text_message_with_ack)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "text_message_with_send_error", text_message_with_send_error)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "text_message_with_external_body", text_message_with_external_body)) { + return CU_get_error(); + } + return 0; }