static void presence_refresher_listener(belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase){ SalOp* op = (SalOp*)user_pointer; switch(status_code){ case 481: { ms_message("The server or remote ua lost the SUBSCRIBE dialog context. Let's restart a new one."); belle_sip_refresher_stop(op->refresher); if (op->dialog) { /*delete previous dialog if any*/ belle_sip_dialog_set_application_data(op->dialog,NULL); belle_sip_object_unref(op->dialog); op->dialog=NULL; } if (sal_op_get_contact_address(op)) { /*contact is also probably not good*/ SalAddress* contact=sal_address_clone(sal_op_get_contact_address(op)); sal_address_set_port(contact,-1); sal_address_set_domain(contact,NULL); sal_op_set_contact_address(op,contact); sal_address_destroy(contact); } sal_subscribe_presence(op,NULL,NULL,-1); break; } } }
belle_sip_header_contact_t* sal_op_create_contact(SalOp *op){ belle_sip_header_contact_t* contact_header; belle_sip_uri_t* contact_uri; if (sal_op_get_contact_address(op)) { contact_header = belle_sip_header_contact_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_contact_address(op))); } else { contact_header= belle_sip_header_contact_new(); } if (!(contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_header)))) { /*no uri, just creating a new one*/ contact_uri=belle_sip_uri_new(); belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact_header),contact_uri); } belle_sip_uri_set_user_password(contact_uri,NULL); belle_sip_uri_set_secure(contact_uri,sal_op_is_secure(op)); if (op->privacy!=SalPrivacyNone){ belle_sip_uri_set_user(contact_uri,NULL); } belle_sip_header_contact_set_automatic(contact_header,op->base.root->auto_contacts); if (op->base.root->uuid){ if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance")==0){ char *instance_id=belle_sip_strdup_printf("\"<urn:uuid:%s>\"",op->base.root->uuid); belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance",instance_id); belle_sip_free(instance_id); } } return contact_header; }
int sal_call_notify_ringing(SalOp *op, bool_t early_media){ int status_code =early_media?183:180; belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)); belle_sip_response_t* ringing_response = sal_op_create_response_from_request(op,req,status_code); belle_sip_header_t *require; const char *tags=NULL; if (early_media){ handle_offer_answer_response(op,ringing_response); } require=belle_sip_message_get_header((belle_sip_message_t*)req,"Require"); if (require) tags=belle_sip_header_get_unparsed_value(require); /* if client requires 100rel, then add necessary stuff*/ if (tags && strstr(tags,"100rel")!=0) { belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_header_create("Require","100rel")); belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_header_create("RSeq","1")); } #ifndef SAL_OP_CALL_FORCE_CONTACT_IN_RINGING if (tags && strstr(tags,"100rel")!=0) #endif { belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(op); belle_sip_header_contact_t* contact_header; if (contact && (contact_header=belle_sip_header_contact_create(contact))) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(ringing_response),BELLE_SIP_HEADER(contact_header)); } } belle_sip_server_transaction_send_response(op->pending_server_trans,ringing_response); return 0; }
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 = msg?strlen(msg):0; time_t curtime=time(NULL); if (op->dialog){ /*for SIP MESSAGE that are sent in call's dialog*/ req=belle_sip_dialog_create_queued_request(op->dialog,"MESSAGE"); }else{ 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"); if (sal_op_get_contact_address(op)){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); } } 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))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),msg,content_length); return sal_op_send_request(op,req); }
int sal_publish(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBody *body){ belle_sip_request_t *req=NULL; if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) { if (from) sal_op_set_from(op,from); if (to) sal_op_set_to(op,to); sal_op_publish_fill_cbs(op); req=sal_op_build_request(op,"PUBLISH"); if (sal_op_get_contact_address(op)){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); } belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname)); sal_op_add_body(op,BELLE_SIP_MESSAGE(req),body); return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener); } else { /*update status*/ const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); /*update body*/ sal_op_add_body(op,BELLE_SIP_MESSAGE(last_publish),expires!=0 ? body : NULL); return belle_sip_refresher_refresh(op->refresher,expires==-1 ? BELLE_SIP_REFRESHER_REUSE_EXPIRES : expires); } }
static void presence_refresher_listener(belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase){ SalOp* op = (SalOp*)user_pointer; if (status_code >= 300) { ms_message("The SUBSCRIBE dialog no longer works. Let's restart a new one."); belle_sip_refresher_stop(op->refresher); if (op->dialog) { /*delete previous dialog if any*/ set_or_update_dialog(op, NULL); } if (sal_op_get_contact_address(op)) { /*contact is also probably not good*/ SalAddress* contact=sal_address_clone(sal_op_get_contact_address(op)); sal_address_set_port(contact,-1); sal_address_set_domain(contact,NULL); sal_op_set_contact_address(op,contact); sal_address_destroy(contact); } /*send a new SUBSCRIBE, that will attempt to establish a new dialog*/ sal_subscribe_presence(op,NULL,NULL,-1); } }
/*presence publish */ int sal_publish_presence(SalOp *op, const char *from, const char *to, int expires, SalPresenceModel *presence){ belle_sip_request_t *req=NULL; if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) { if (from) sal_op_set_from(op,from); if (to) sal_op_set_to(op,to); op->type=SalOpPublish; req=sal_op_build_request(op,"PUBLISH"); if (sal_op_get_contact_address(op)){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); } belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","presence")); sal_add_presence_info(op,BELLE_SIP_MESSAGE(req),presence); return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener); } else { /*update presence status*/ const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); sal_add_presence_info(op,BELLE_SIP_MESSAGE(last_publish),expires!=0 ? presence : NULL); return belle_sip_refresher_refresh(op->refresher,expires); } }
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); belle_sip_response_t* response = belle_sip_response_event_get_response(event); int response_code = belle_sip_response_get_status_code(response); if (!client_transaction) { ms_warning("Discarding stateless response [%i]",response_code); return; } else { 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; 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->base.call_id) { op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(response), belle_sip_header_call_id_t)))); } sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); if (op->callbacks.process_response_event) { if (op->base.root->nat_helper_enabled) { /*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 ((original_contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t))) { /*update contact with sent values in any cases*/ 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); } if (sal_op_get_contact(op)){ if (received!=NULL || rport>0) { 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) { char* old_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(sal_op_get_contact_address(op))); new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); ms_message("Updating contact from [%s] to [%s] for [%p]",old_contact,new_contact,op); sal_op_set_contact_address(op,(const SalAddress *)contact_address); belle_sip_free(new_contact); belle_sip_free(old_contact); } if (contact_address)belle_sip_object_unref(contact_address); } } } /*handle authorization*/ switch (response_code) { case 200: { break; } case 401: case 407:{ /*belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*//*remove op from trans*/ if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) { /*only bye are completed*/ belle_sip_message("Op is in state terminating, nothing else to do "); } else { if (op->pending_auth_transaction){ belle_sip_object_unref(op->pending_auth_transaction); op->pending_auth_transaction=NULL; } op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction); sal_process_authentication(op); return; } } } op->callbacks.process_response_event(op,event); } else { ms_error("Unhandled event response [%p]",event); } } }
int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri){ belle_sip_request_t* req; char content_type_raw[256]; size_t content_length = msg?strlen(msg):0; time_t curtime = time(NULL); uint8_t *multipartEncryptedMessage = NULL; int retval; if (op->dialog){ /*for SIP MESSAGE that are sent in call's dialog*/ req = belle_sip_dialog_create_queued_request(op->dialog,"MESSAGE"); }else{ 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"); if (req == NULL ){ return -1; } if (sal_op_get_contact_address(op)){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req), BELLE_SIP_HEADER(sal_op_create_contact(op))); } } /* shall we try to encrypt the message?*/ if ((strcmp(content_type, "xml/cipher") == 0) || ((strcmp(content_type, "application/cipher.vnd.gsma.rcs-ft-http+xml") == 0))) { /* access the zrtp cache to get keys needed to cipher the message */ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); FILE *CACHEFD = fopen(lc->zrtp_secrets_cache, "rb+"); if (CACHEFD == NULL) { ms_warning("Unable to access ZRTP ZID cache to encrypt message"); /*probably not a good idea to do this:*/ sal_error_info_set(&op->error_info, SalReasonNotAcceptable, 488, "Unable to encrypt IM", NULL); op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); return -1; } else { size_t cacheSize; char *cacheString; xmlDocPtr cacheXml; int retval; cacheString=ms_load_file_content(CACHEFD, &cacheSize); if (!cacheString){ ms_warning("Unable to load content of ZRTP ZID cache to encrypt message"); return -1; } cacheString[cacheSize] = '\0'; cacheSize += 1; fclose(CACHEFD); cacheXml = xmlParseDoc((xmlChar*)cacheString); ms_free(cacheString); retval = lime_createMultipartMessage(cacheXml, (uint8_t *)msg, (uint8_t *)peer_uri, &multipartEncryptedMessage); if (retval != 0) { ms_warning("Unable to encrypt message for %s : %s - op [%p]", peer_uri, lime_error_code_to_string(retval), op); xmlFreeDoc(cacheXml); free(multipartEncryptedMessage); /*probably not a good idea to do this:*/ sal_error_info_set(&op->error_info, SalReasonNotAcceptable, 488, "Unable to encrypt IM", NULL); op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); return -1; } else { /* dump updated cache to a string */ xmlChar *xmlStringOutput; int xmlStringLength; xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); /* write it to the cache file */ CACHEFD = fopen(lc->zrtp_secrets_cache, "wb+"); if (fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD)<=0){ ms_warning("Unable to write zid cache"); } xmlFree(xmlStringOutput); fclose(CACHEFD); content_length = strlen((const char *)multipartEncryptedMessage); } xmlFreeDoc(cacheXml); } } 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))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),(multipartEncryptedMessage==NULL)?msg:(const char *)multipartEncryptedMessage,content_length); retval = sal_op_send_request(op,req); free(multipartEncryptedMessage); return retval; }