/* Copyright 2015 Kuklin István
This file is part of OpenSIPphone.
OpenSIPphone 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, version 2 of the License.
OpenSIPphone 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 OpenSIPphone. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include /* superset of previous */
#include
#include "gtk_ui.h"
#include "gtk_uconf.h"
#include "main.h"
#include "sip.h"
#include "gtk_debug.h"
#include "sound.h"
#include "rtp.h"
char vm_number[100];
void osp_call_number(GtkTreeViewColumn *null, gpointer data) {
char *number = (char *)(data);
osp_print(number, GTK_TEXT_VIEW(debug_view));
gtk_entry_set_text(GTK_ENTRY(dial_entry), number);
osp_make_call();
}
int init_osp_eXosip() {
strcpy(vm_number, "");
if(eXosip_init_done == 1)eXosip_quit(ctx);
eXosip_init_done = 1;
TRACE_INITIALIZE (6, NULL);
ctx = eXosip_malloc();
if (ctx == NULL) {
printf("sip.c: ctx is null, dying\n");
return -1;
}
j = eXosip_init(ctx);
if(j != 0) {
printf("sip.c: failed to initialize eXoSIP context, dying");
return -1;
}
printf("eXoSIP main initializing is done\n");
int val=1;
j = eXosip_set_option (ctx, EXOSIP_OPT_SET_TLS_VERIFY_CERTIFICATE, (void*)&val);
eXosip_tls_ctx_t tls_info;
switch (user_settings.transport){
case 0:
j = eXosip_listen_addr(ctx, IPPROTO_UDP, NULL, 5060, AF_INET, 0);
break;
case 1:
j = eXosip_listen_addr(ctx, IPPROTO_TCP, NULL, 5060, AF_INET, 0);
break;
case 2:
j = eXosip_listen_addr (ctx, IPPROTO_TCP, NULL, 5061, AF_INET, 1); //FAIL
if(j != 0 ) {
printf("eXoSIP: cannot listen, returning\n");
return -1;
}
memset(&tls_info, 0, sizeof(eXosip_tls_ctx_t));
snprintf(tls_info.root_ca_cert, sizeof(tls_info.root_ca_cert), "/etc/ssl/certs/ca-certificates.crt");
j = 0;
j = eXosip_set_option (ctx, EXOSIP_OPT_SET_TLS_CERTIFICATES_INFO, (void*)&tls_info);
if(j < 0) printf("ERROR INITIALIZING TLS TRANSPORT!\n");
else printf("TLS TRANSPORT INITIALIZED\nCA file: %s\n", tls_info.root_ca_cert);
break;
default:
j = eXosip_listen_addr(ctx, IPPROTO_UDP, NULL, 0, AF_INET, 0);
}
eXosip_set_user_agent (ctx, selfname);
val=17000;
eXosip_set_option (ctx, EXOSIP_OPT_UDP_KEEP_ALIVE, (void*)&val);
val=2;
eXosip_set_option (ctx, EXOSIP_OPT_DNS_CAPABILITIES, (void*)&val);
val=1;
eXosip_set_option (ctx, EXOSIP_OPT_USE_RPORT, (void*)&val);
val=26;
eXosip_set_option (ctx, EXOSIP_OPT_SET_DSCP, (void*)&val);
eXosip_set_option (ctx, EXOSIP_OPT_SET_IPV4_FOR_GATEWAY, (void *)gtk_entry_get_text(GTK_ENTRY(domain_entry)));
val=0;
eXosip_set_option (ctx, EXOSIP_OPT_DNS_CAPABILITIES, &val);
reg = NULL;
char reg_uri[300];
char prov_uri[200];
strcpy(prov_uri, "sip:");
strcat(prov_uri, (char *)gtk_entry_get_text(GTK_ENTRY(domain_entry)));
strcpy(reg_uri, "sip:");
strcat(reg_uri, (char *)gtk_entry_get_text(GTK_ENTRY(username_entry)));
strcat(reg_uri, "@");
strcat(reg_uri, (char *)gtk_entry_get_text(GTK_ENTRY(domain_entry)));
printf("Registration URI: %s\nProvider URI: %s\n", reg_uri, prov_uri);
eXosip_lock(ctx);
rid = eXosip_register_build_initial_register (ctx, reg_uri, prov_uri, NULL, 1800, ®);
if(rid < 0) {
printf("Returned -1 as asked.\n");
eXosip_unlock (ctx);
return -1;
}
osip_message_set_supported (reg, "100rel");
osip_message_set_supported (reg, "path");
j = eXosip_register_send_register (ctx, rid, reg);
eXosip_add_authentication_info (ctx, (char *)gtk_entry_get_text(GTK_ENTRY(username_entry)), (char *)gtk_entry_get_text(GTK_ENTRY(username_entry)), (char *)gtk_entry_get_text(GTK_ENTRY(password_entry)), NULL, NULL);
eXosip_unlock (ctx);
pthread_cancel(event_pth);
pthread_create(&event_pth, NULL, osp_event_listen, NULL);
return 0;
}
void *osp_event_listen() {
//Listening for events...
//eXosip_event_t *evt;
int first_time_reg_failure = 1;
for (;;)
{
evt = eXosip_event_wait (ctx, 0, 50);
eXosip_lock(ctx);
eXosip_automatic_action (ctx);
eXosip_unlock(ctx);
if (evt == NULL) continue;
if(evt->type == EXOSIP_REGISTRATION_SUCCESS ) {
osp_print("Registered successfully.\n", GTK_TEXT_VIEW(user_message_view));
gdk_threads_add_idle((GSourceFunc)(on_sip_registration_done), GINT_TO_POINTER(1));
}
if(evt->type == EXOSIP_REGISTRATION_FAILURE ) {
if(first_time_reg_failure == 1 && user_settings.transport == 2) first_time_reg_failure = 0;
else osp_print("Failed to register.\n", GTK_TEXT_VIEW(user_message_view));
gdk_threads_add_idle((GSourceFunc)(on_sip_registration_done), GINT_TO_POINTER(0));
}
if(evt->type == EXOSIP_CALL_RINGING) {
on_the_phone = TRUE;
did = evt->did;
cid = evt->cid;
tid = evt->tid;
gdk_threads_add_idle(after_trying, NULL);
osp_print("Ringing...\n", GTK_TEXT_VIEW(user_message_view));
}
if(evt->type == EXOSIP_CALL_ANSWERED) {
on_the_phone = TRUE;
did = evt->did;
cid = evt->cid;
tid = evt->tid;
pthread_cancel(rst);
gdk_threads_add_idle(on_call_answered, NULL);
{
osip_message_t *ack;
j = eXosip_call_build_ack(ctx, did, &ack);
if(j == 0) {
osp_print("Sending ACK\n", GTK_TEXT_VIEW(debug_view));
eXosip_call_send_ack(ctx, did, ack);
}
}
osp_on_call_established();
}
if(evt->type == EXOSIP_CALL_GLOBALFAILURE || evt->type == EXOSIP_CALL_REQUESTFAILURE || evt->type == EXOSIP_CALL_SERVERFAILURE || evt->type == EXOSIP_CALL_GLOBALFAILURE){
char text_buffer[300];
osp_print("MAIN: SOME KIND OF FAILURE EVENT CAUGHT\n", GTK_TEXT_VIEW(debug_view));
if(evt->response->status_code != 401) {
sprintf(text_buffer, "SIP %d %s\n", evt->response->status_code, evt->response->reason_phrase);
if(evt->response->status_code = 404) reset_dial_interface();
osp_print(text_buffer, GTK_TEXT_VIEW(user_message_view));
}
}
if(evt->type == EXOSIP_CALL_CLOSED || evt->type == EXOSIP_CALL_REQUESTFAILURE || evt->type == EXOSIP_CALL_CANCELLED) {
if(did == evt->did) reset_dial_interface();
gdk_threads_add_idle(close_notification, incoming_call_notification);
pthread_cancel(rst);
pthread_cancel(osp_rtp_play_thread);
};
if(evt->type == EXOSIP_CALL_CLOSED) {
gdk_threads_add_idle(dial_entry_empty, NULL);
osp_print("Call ended\n", GTK_TEXT_VIEW(user_message_view));
}
if(evt->type == EXOSIP_CALL_INVITE) {
if(on_the_phone == FALSE) {
did = evt->did;
cid = evt->cid;
tid = evt->tid;
eXosip_lock (ctx);
eXosip_call_send_answer (ctx, evt->tid, 180, NULL);
eXosip_unlock (ctx);
char dest[4096];
osip_uri_t *uri = osip_from_get_url(evt->request->from);
sprintf(dest, "address@hidden", osip_uri_get_username(uri), osip_uri_get_host(uri));
gdk_threads_add_idle(on_incoming_call, dest);
osp_print("MAIN: INVITE EVENT CAUGHT\n", GTK_TEXT_VIEW(debug_view));
struct osp_play_audio_file_options_t options;
strcpy(options.path, gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(ringtone_chooser)));
if(0 != pthread_create(&rst, NULL, (void * (*)(void *))(osp_play_audio_file), (&options))) {
osp_print("Error creating sound thread!\n", GTK_TEXT_VIEW(debug_view));
};
//osp_play_audio_file("/usr/share/sounds/ubuntu/stereo/desktop-login.ogg");
} else {
eXosip_lock (ctx);
eXosip_call_terminate (ctx, evt->cid, evt->did);
eXosip_unlock (ctx);
};
}
if(evt->type == EXOSIP_MESSAGE_NEW || evt->type == EXOSIP_MESSAGE_PROCEEDING ) {
osp_print("MAIN: MESSAGE EVENT CAUGHT\n", GTK_TEXT_VIEW(debug_view));
char text_buffer[300];
sprintf(text_buffer, "Request method is: %s\n", evt->request->sip_method);
//MWI
if(strcmp("NOTIFY", evt->request->sip_method) == 0) {
//char *req_uri_str = osip_url_to_str(evt->request->req_uri);
{
osip_body_t *body = osip_list_get(&(evt->request->bodies), 0);
char *dest=NULL;
size_t length=0;
osip_body_to_str(body, &dest, &length);
osp_print(dest, GTK_TEXT_VIEW(debug_view));
if(strstr(dest, "Messages-Waiting: yes") != NULL) {
osp_print("New voicemail.\n", GTK_TEXT_VIEW(debug_view));
gdk_threads_add_idle(mwi_notify, GINT_TO_POINTER(TRUE));
} else if(strstr(dest, "Messages-Waiting: no") != NULL) {
osp_print("No voicemail.\n", GTK_TEXT_VIEW(debug_view));
gdk_threads_add_idle(mwi_notify, GINT_TO_POINTER(FALSE));
}
char *dig_vm_number = dig_vm_number = strstr(dest, "sip:");
if(dig_vm_number == NULL) osp_print("No voicemail account.\n", GTK_TEXT_VIEW(debug_view));
sscanf(dig_vm_number, "%s\n", vm_number);
{
char output_buffer[1024];
sprintf(output_buffer, "Voicemail number is: %s\n", vm_number);
osp_print(output_buffer, GTK_TEXT_VIEW(debug_view));
}
}
}
osp_print(text_buffer, GTK_TEXT_VIEW(debug_view));
if(strcmp(evt->request->sip_method, "OPTIONS") == 0) {
eXosip_lock (ctx);
j = 0;
j = eXosip_options_build_answer(ctx, evt->tid, 200, &msg);
if(j < 0) osp_print("There was a problem building the options answer.\n", GTK_TEXT_VIEW(debug_view));
j = eXosip_options_send_answer(ctx, evt->tid, 200, msg);
if(j < 0) osp_print("There was a problem sending the options answer.\n", GTK_TEXT_VIEW(debug_view));
eXosip_unlock (ctx);
}
if((strcmp(evt->request->sip_method, "BYE") == 0 || strcmp(evt->request->sip_method, "CANCEL") == 0)) {
on_the_phone = FALSE;
gdk_threads_add_idle(enable_dial_interface, GINT_TO_POINTER(1));
}
}
eXosip_event_free(evt);
}
return NULL;
}
void osp_sip_quit() {
eXosip_lock (ctx);
j = eXosip_register_build_register (ctx, rid, 0, ®);
if (j < 0)
{
eXosip_unlock (ctx);
return;
}
eXosip_register_send_register (ctx, rid, reg);
eXosip_unlock (ctx);
}
void osp_sdp_build (osip_message_t *invite) {
char tmp[4096];
char tmp2[300];
char localip[128];
char port_str[6];
sprintf(port_str, "49170");
eXosip_guess_localip (ctx, AF_INET, localip, 128);
sprintf(tmp, "v=0\r\no=%s 0 0 IN IP4 %s\r\ns=conversation\r\nc=IN IP4 %s\r\n", gtk_entry_get_text (GTK_ENTRY (username_entry)), localip, localip);
if(user_settings.srtp_enabled == TRUE) sprintf(tmp + strlen(tmp), "t=0 0\r\nm=audio %s RTP/SAVP 0 8 101\r\n", port_str);
else sprintf(tmp + strlen(tmp), "t=0 0\r\nm=audio %s RTP/AVP 0 8 101\r\n", port_str);
sprintf(tmp + strlen(tmp), "a=sendrecv\r\n");
//Codecs here...
sprintf(tmp + strlen(tmp), "a=rtpmap:0 PCMU/8000\r\n");
//sprintf(tmp + strlen(tmp), "a=rtpmap:8 PCMA/8000\r\n");
//SRTP key
if(user_settings.srtp_enabled == TRUE) sprintf(tmp+strlen(tmp), "a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj\r\n");
osip_message_set_body (invite, tmp, strlen (tmp));
osip_message_set_content_type (invite, "application/sdp");
}
void osp_make_call() {
osip_message_t *invite;
char from[300];
char to[300];
strcpy(from, "sip:");
osp_print(from, GTK_TEXT_VIEW(debug_view));
strcat(from, gtk_entry_get_text (GTK_ENTRY (username_entry) ) );
strcat(from, "@");
strcat(from, gtk_entry_get_text (GTK_ENTRY (domain_entry) ) );
strcpy(to, "");
if(strstr(gtk_entry_get_text(GTK_ENTRY(dial_entry)), "sip:") == NULL) strcat(to, "sip:");
strcat(to, gtk_entry_get_text (GTK_ENTRY (dial_entry) ) );
if(strstr(gtk_entry_get_text(GTK_ENTRY(dial_entry)), "@") == NULL) {
strcat(to, "@");
strcat(to, gtk_entry_get_text (GTK_ENTRY (domain_entry) ) );
}
gtk_entry_set_text(GTK_ENTRY(dial_entry), to);
j = eXosip_call_build_initial_invite (ctx, &invite, (char *)(to), (char *)(from), NULL, NULL);
if(user_settings.transport == 2) {
osip_uri_param_add(&(invite->req_uri->url_params), osip_strdup("transport"), osip_strdup("TLS"));
};
{
char output_buffer[DEBUG_MESSAGE_DATA_LENGTH];
char *uri_buffer;
osip_uri_to_str(osip_message_get_uri(invite), &uri_buffer);
sprintf(output_buffer, "Connecting to:\n%s\n", uri_buffer);
osp_print(output_buffer, GTK_TEXT_VIEW(user_message_view));
}
osip_message_set_supported(invite, "100rel");
osp_sdp_build(invite);
eXosip_lock (ctx);
cid = eXosip_call_send_initial_invite (ctx, invite);
eXosip_unlock(ctx);
on_the_phone = TRUE;
}
void osp_reject_call() {
pthread_cancel(rst);
eXosip_lock (ctx);
eXosip_call_terminate (ctx, cid, did);
eXosip_unlock (ctx);
notify_notification_close(incoming_call_notification, NULL);
gdk_threads_add_idle(dial_entry_empty, NULL);
osp_print("Ending call\n", GTK_TEXT_VIEW(user_message_view));
on_the_phone = FALSE;
pthread_cancel(osp_rtp_play_thread);
}
void osp_answer_call() {
pthread_cancel(rst);
on_the_phone = TRUE;
msg = NULL;
eXosip_lock (ctx);
j = eXosip_call_build_answer (ctx, tid, 200, &msg);
if (j != 0)
{
eXosip_call_send_answer (ctx, tid, 400, NULL);
}
else
{
osp_sdp_build(msg);
if (j != 0)
{
osip_message_free (msg);
eXosip_call_send_answer (ctx, tid, 415, NULL);
}
else
eXosip_call_send_answer (ctx, tid, 200, msg);
}
eXosip_unlock (ctx);
osp_on_call_established();
}
void osp_on_call_established() {
osp_print("Call established\n", GTK_TEXT_VIEW(user_message_view));
notify_notification_close(incoming_call_notification, NULL);
sdp_message_t * sdp_remote = NULL;
sdp_remote = eXosip_get_remote_sdp(ctx, did);
if(sdp_remote == NULL) {
osp_print("Failed to get remote SDP!\n", GTK_TEXT_VIEW(debug_view));
return;
}
char *tempbuf = malloc(sizeof(*tempbuf)*512);
char *sdpmsg = malloc(sizeof(*tempbuf)*512);
char *needle = "m=audio ";
sdp_message_to_str(sdp_remote, &sdpmsg);
sprintf(tempbuf, "SDP: Remote body is:\n%s\n", sdpmsg);
char *needle_pos = strstr(sdpmsg, needle);
if(needle_pos != NULL) {
int audio_port;
osp_print(tempbuf, GTK_TEXT_VIEW(debug_view));
sscanf(needle_pos, "m=audio %d RTP", &audio_port);
sprintf(tempbuf, "RTP audio port number is: %d\n", audio_port);
osp_print(tempbuf, GTK_TEXT_VIEW(debug_view));
pthread_create(&osp_rtp_play_thread, NULL, osp_rtp_play, &audio_port);
} else {
osp_print("Audio port number not found!\n", GTK_TEXT_VIEW(debug_view));
}
free(tempbuf);
tempbuf = NULL;
}