diff --git a/linphone/console/commands.c b/linphone/console/commands.c index 6d763f468..486202d03 100644 --- a/linphone/console/commands.c +++ b/linphone/console/commands.c @@ -1428,11 +1428,13 @@ static int lpc_cmd_status(LinphoneCore *lc, char *args) else if (strstr(args,"hook")) { gstate_t call_state=linphone_core_get_state(lc,GSTATE_GROUP_CALL); +/* if (!cfg || !linphone_proxy_config_is_registered(cfg)){ linphonec_out("unregistered\n"); return 1; } - switch(call_state){ + */ + switch(call_state){ case GSTATE_CALL_OUT_INVITE: linphonec_out("hook=dialing\n"); break; diff --git a/linphone/console/linphonec.c b/linphone/console/linphonec.c index c50e00376..1036052af 100644 --- a/linphone/console/linphonec.c +++ b/linphone/console/linphonec.c @@ -164,6 +164,13 @@ LinphoneCoreVTable linphonec_vtable = { .dtmf_received=linphonec_dtmf_received }; + +/* zsd: called from exevents, only interesting to gui */ +void linphone_call_started_remotely(const char * url) +{ +} + + /*************************************************************************** * * Linphone core callbacks diff --git a/linphone/console/sipomatic.c b/linphone/console/sipomatic.c index 3a96699a5..537815f59 100644 --- a/linphone/console/sipomatic.c +++ b/linphone/console/sipomatic.c @@ -22,6 +22,11 @@ call. #include +/* zsd: called from exevents, only interesting to gui */ +void linphone_call_started_remotely(const char * url) +{ +} + int run_cond=1; Sipomatic sipomatic; diff --git a/linphone/coreapi/exevents.c b/linphone/coreapi/exevents.c index c9d3ace8d..c48c02a4e 100644 --- a/linphone/coreapi/exevents.c +++ b/linphone/coreapi/exevents.c @@ -25,6 +25,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include + +/* zsd: only want to do something here if the GUI is active */ +void linphone_call_started_remotely(const char * URL); + static int linphone_answer_sdp(LinphoneCore *lc, eXosip_event_t *ev, sdp_message_t *sdp); static bool_t linphone_call_matches_event(LinphoneCall *call, eXosip_event_t *ev){ @@ -333,19 +337,28 @@ int linphone_inc_new_call(LinphoneCore *lc, eXosip_event_t *ev) barmesg=ortp_strdup_printf("%s %s",tmp,_("is contacting you.")); lc->vtable.show(lc); lc->vtable.display_status(lc,barmesg); - lc->vtable.inv_recv(lc,tmp); - ms_free(barmesg); - osip_free(tmp); - - linphone_call_set_state(lc->call,LCStateRinging); - eXosip_lock(); - eXosip_call_send_answer(ev->tid,180,NULL); - eXosip_unlock(); + /* play the ring */ + /* + * zsd moved this statement and the next four from the bottom of + * this block so that the gui inv_recv function could automatically + * answer. + * With this below, the ringing didn't start until after the + * auto-answer, which caused the ring to time out and terminate the + * call. + */ if (lc->sound_conf.ring_sndcard!=NULL){ ms_message("Starting local ring..."); lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard); } + linphone_call_set_state(lc->call,LCStateRinging); + eXosip_lock(); + eXosip_call_send_answer(ev->tid,180,NULL); + eXosip_unlock(); + + lc->vtable.inv_recv(lc,tmp); + ms_free(barmesg); + osip_free(tmp); }else{ ms_error("Error during sdp negociation. "); eXosip_lock(); @@ -1016,7 +1029,64 @@ static void linphone_other_request(LinphoneCore *lc, eXosip_event_t *ev){ ms_message("Receiving WAKEUP request !"); if (lc->vtable.show) lc->vtable.show(lc); - }else { + } + /* zsd addition: allow a "remote" call request */ + /* + * The current implementation of the feature is a horrible kludge: + * rather than extracting the URL from the body, get it from the SIP + * method... it is all the chars after "CALL". + */ + else if (strncmp(ev->request->sip_method, "CALL", 4) == 0 + && comes_from_local_if(ev->request)) + { + char * sip_method = ev->request->sip_method; + + eXosip_message_send_answer(ev->tid, 200, NULL); + ms_message("Received CALL request."); + + /* + fprintf(stderr, "Received CALL request!\n"); + fprintf(stderr, "addr to call is |%s|\n", &ev->request->sip_method[4]); + fprintf(stderr, "addr to call is |%s|\n", &sip_method[4]); + */ + /* + * The following two lines of code should probably be wrapped into + * something and then put in a new slot in the vtable. + */ + linphone_core_invite(lc, &sip_method[4]); + linphone_call_started_remotely(&sip_method[4]); + +#if 0 + fprintf(stderr, "textinfo is |%s|\n", ev->textinfo); + fprintf(stderr, "request content_length is |%s|\n", + ev->request->content_length->value); + /* + * The following code (in the braces) was snarfled off the web, as + * an example of how to get at the body content. + * It didn't work for me. + */ + { + int pos = 0; + while (!osip_list_eol (&ev->request->bodies, pos)) + { + osip_body_t * oldbody; + + oldbody = (osip_body_t *)osip_list_get(&ev->request->bodies, + pos); + pos++; + + /* !!!! -> body is here: "oldbody->body" */ + fprintf(stderr, "oldbody->length = %d\n", oldbody->length); + fprintf(stderr, "oldbody->body = %s\n", oldbody->body); + } + } + fprintf(stderr, "request is |%s|\n", ev->request->message); +#endif + + if (lc->vtable.show) + lc->vtable.show(lc); + } + else { char *tmp=NULL; size_t msglen=0; osip_message_to_str(ev->request,&tmp,&msglen); diff --git a/linphone/coreapi/linphonecore.h b/linphone/coreapi/linphonecore.h index ee7ac5c39..878417335 100644 --- a/linphone/coreapi/linphonecore.h +++ b/linphone/coreapi/linphonecore.h @@ -788,7 +788,13 @@ struct _LpConfig *linphone_core_get_config(LinphoneCore *lc); /* attempts to wake up another linphone engine already running. The "show" callback is called for the other linphone, causing gui to show up. The method returns 0 if an already running linphone was found*/ +/* zsd: old code was int linphone_core_wake_up_possible_already_running_instance(const char *config_file); + * new code: If the second arg is non-null, pass the call addr to the + * already-running instance. + */ +int linphone_core_wake_up_possible_already_running_instance( + const char * config_file, const char * call_addr); /*set a callback for some blocking operations, it takes you informed of the progress of the operation*/ void linphone_core_set_waiting_callback(LinphoneCore *lc, LinphoneWaitingCallback cb, void *user_context); diff --git a/linphone/coreapi/misc.c b/linphone/coreapi/misc.c index 22ed27852..f506a7592 100644 --- a/linphone/coreapi/misc.c +++ b/linphone/coreapi/misc.c @@ -679,7 +679,10 @@ static int extract_sip_port(const char *config){ return ret; } -int linphone_core_wake_up_possible_already_running_instance(const char *config_file){ +/* zsd added "addr_to_call" to this function. */ +int linphone_core_wake_up_possible_already_running_instance( + const char * config_file, const char * addr_to_call) +{ int port=extract_sip_port(config_file); const char *wakeup="WAKEUP sip:127.0.0.1 SIP/2.0\r\n" "Via: SIP/2.0/UDP 127.0.0.1:%i;rport;branch=z9hG4bK%u\r\n" @@ -688,6 +691,19 @@ int linphone_core_wake_up_possible_already_running_instance(const char *config_f "CSeq: 1 WAKEUP\r\n" "Call-ID: %u@onsantape\r\n" "Content-length: 0\r\n\r\n"; + /* + * zsd: is this the worst kludge ever? + * Q: How do you extract the body of the message at the other end?? + * (Use "...Content-length: %d\r\n\r\n%s\r\n", strlen(a_to_c)+2, a_to_c + * to put stuff in the body, assuming content length includes the \r\n.) + */ + const char * call = "CALL%s sip:127.0.0.1 SIP/2.0\r\n" + "Via: SIP/2.0/UDP 127.0.0.1:%i;rport;branch=z9hG4bK%u\r\n" + "From: ;tag=%u\r\n" + "To: \r\n" + "CSeq: 1 CALL\r\n" + "Call-ID: %u@onsantape\r\n" "Content-length: 0\r\n\r\n"; + /*make sure ortp is initialized (it initializes win32 socket api)*/ ortp_init(); if (port>0){ @@ -701,7 +717,15 @@ int linphone_core_wake_up_possible_already_running_instance(const char *config_f if (sock<0) sock=create_socket(++locport); if (sock>=0){ char req[512]; - snprintf(req,sizeof(req),wakeup,locport,random(),random(),random()); + /* zsd */ + if (addr_to_call != NULL) + snprintf(req, sizeof(req), call, addr_to_call, locport, + random(), random(), random()); + else + snprintf(req, sizeof(req), wakeup, locport, + random(), random(), random()); +//fprintf(stderr, "linphone_core_wake_up_... MAY send\n|%s|\n", req); /* zsd */ +//original line of code: snprintf(req,sizeof(req),wakeup,locport,random(),random(),random()); if (connect(sock,(struct sockaddr*)&ss,sslen)<0){ fprintf(stderr,"connect failed: %s\n",getSocketError()); }else if (send(sock,req,strlen(req),0)>0){ @@ -710,8 +734,11 @@ int linphone_core_wake_up_possible_already_running_instance(const char *config_f for(i=0;i<10;++i){ if (recv(sock,req,sizeof(req),0)>0){ close_socket(sock); +//fprintf(stderr, "GOT A RESPONSE to the wake-up message\n"); /* zsd */ return 0; }else if (getSocketErrorCode()!=EWOULDBLOCK){ + /* zsd */ +// fprintf(stderr, "l_c_w_u_p_a_r_i: WOULDN'T BLOCK!\n"); break; } #ifdef WIN32 @@ -720,10 +747,21 @@ int linphone_core_wake_up_possible_already_running_instance(const char *config_f usleep(100000); #endif } - }else ms_message("sendto() of WAKEUP request failed, nobody to wakeup."); + }else + { + /* zsd fprintf() */ + // fprintf(stderr, "sendto() of WAKEUP request failed\n"); + ms_message("sendto() of WAKEUP request failed, nobody to wakeup."); + } + } +// else /* zsd */ +// fprintf(stderr, "l_c_w_u_p_a_r_i: unable to create socket\n"); close_socket(sock); } } + /* zsd */ +// else +// fprintf(stderr, "l_c_w_u_p_a_r_i: port <= 0 !!!!!!!\n"); return -1; } diff --git a/linphone/gtk-glade/main.c b/linphone/gtk-glade/main.c index e65157d9f..4e420511e 100644 --- a/linphone/gtk-glade/main.c +++ b/linphone/gtk-glade/main.c @@ -70,14 +70,31 @@ static LinphoneCoreVTable vtable={ }; static gboolean verbose=0; -static GOptionEntry linphone_options[2]={ +static gboolean auto_answer = 0; /* zsd */ +static gchar * addr_to_call = NULL; /* zsd: FIXME: is this correct??? */ +static GOptionEntry linphone_options[]={ /* zsd deleted array size 2 */ { .long_name="verbose", .short_name= '\0', .arg=G_OPTION_ARG_NONE, .arg_data= (gpointer)&verbose, .description="log to stdout some debug information while running." - } + }, + { /* zsd addition */ + .long_name = "call", + .short_name = 'c', + .arg = G_OPTION_ARG_STRING, + .arg_data = &addr_to_call, /* zsd: FIXME: is this correct??? */ + .description = "address to call right now" + }, + { /* zsd addition */ + .long_name = "auto-answer", + .short_name = 'a', + .arg = G_OPTION_ARG_NONE, + .arg_data = (gpointer) & auto_answer, + .description = "if set, automatically answer incoming calls" + }, + {0} }; #define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone" @@ -505,6 +522,9 @@ void linphone_gtk_terminate_call(GtkWidget *button){ void linphone_gtk_decline_call(GtkWidget *button){ linphone_core_terminate_call(linphone_gtk_get_core(),NULL); + /* zsd note: there was a big here in 3.0.0 which caused an abort if + * someone clicked "decline"... the following line of code looks + * like a fix for that. */ gtk_widget_destroy(gtk_widget_get_toplevel(button)); } @@ -556,6 +576,23 @@ static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from){ GtkWidget *w=linphone_gtk_create_window("incoming_call"); GtkWidget *label; gchar *msg; + + if (auto_answer) // zsd addition + { + /* + * Let the phone ring a bit before the auto-answer so that the + * local user knows something is happening. + */ +//fflush(stdout);fprintf(stderr, "******************** sleep(2)\n"); + sleep(2); +//fflush(stdout);fprintf(stderr, "******************** calling linphone_core_accept_call()\n"); + linphone_core_accept_call(linphone_gtk_get_core(), NULL); +//fflush(stdout);fprintf(stderr, "******************** calling linphone_gtk_call_started()\n"); + linphone_gtk_call_started(linphone_gtk_get_main_window()); + + return; + } + gtk_window_set_transient_for(GTK_WINDOW(w),GTK_WINDOW(linphone_gtk_get_main_window())); gtk_window_set_position(GTK_WINDOW(w),GTK_WIN_POS_CENTER_ON_PARENT); @@ -968,22 +1005,64 @@ void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){ linphone_gtk_log_push(lev,fmt,args); } + + + +/* zsd added this */ +void linphone_call_started_remotely(const char * url) +{ + GtkEntry * uri_bar = + GTK_ENTRY(linphone_gtk_get_widget + (linphone_gtk_get_main_window(), "uribar")); + + gtk_entry_set_text(uri_bar, url); + linphone_gtk_call_started(linphone_gtk_get_main_window()); +} + + int main(int argc, char *argv[]){ #ifdef ENABLE_NLS void *p; #endif const char *config_file; const char *lang; + int i; // zsd g_thread_init(NULL); gdk_threads_init(); config_file=linphone_gtk_get_config_file(); - if (linphone_core_wake_up_possible_already_running_instance(config_file)==0){ + + /* + * zsd addition: + * Did the user ask for an-already running instance to make a call? + * Look thru the args the old-fashioned way. + */ + for (i = 1; i < argc; i++) + { + if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "-call") == 0) + { + if (i + 1 < argc) + addr_to_call = argv[i + 1]; + i = argc + 1; + } + } + // fprintf(stderr, "addr_to_call is |%s|\n", addr_to_call); + +// zsd replaced this line +// if (linphone_core_wake_up_possible_already_running_instance(config_file)==0){ + if (linphone_core_wake_up_possible_already_running_instance( + config_file, addr_to_call) == 0) + { +// and zsd added this if stmt and the braces + if (addr_to_call == NULL) + { g_warning("Another running instance of linphone has been detected. It has been woken-up."); g_warning("This instance is going to exit now."); - return 0; + } + return 0; } + #ifdef WIN32 /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */ if ((lang=getenv("LANG"))!=NULL){ @@ -1016,13 +1095,22 @@ int main(int argc, char *argv[]){ #ifdef WIN32 gtk_rc_add_default_file("./gtkrc"); #endif + // fprintf(stderr, "about to call gdk_threads_enter()\n"); //zsd gdk_threads_enter(); + // fprintf(stderr, "AFTER call gdk_threads_enter()\n"); + // fprintf(stderr, "b4 !gtk_init_with_args() addr_to_call is |%s|\n", + // addr_to_call); /* zsd */ if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"), linphone_options,NULL,NULL)){ + fprintf(stderr, "IN !gtk_init_with_args() if clause\n"); /* zsd */ gdk_threads_leave(); return -1; } + /* zsd: we don't get here if the args were not OK */ + // fprintf(stderr, "AFTER !gtk_init_with_args() addr_to_call is |%s|\n", + // addr_to_call); /* zsd */ + add_pixmap_directory("pixmaps"); add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone"); @@ -1039,6 +1127,30 @@ int main(int argc, char *argv[]){ linphone_gtk_init_status_icon(); linphone_gtk_show_main_window(); linphone_gtk_check_for_new_version(); + + /* zsd additions for calling a URL given as an argument */ + /* + * Comment from linphone 3.0.0: + * With this here, the video window never shows up, altho the + * main window does. Why is that? + if (addr_to_call != NULL) + { + linphone_core_invite(linphone_gtk_get_core(), addr_to_call); + linphone_call_started_remotely(addr_to_call); + } + */ + /* Horrible, horrible kludge since the above doesn't work: */ + if (addr_to_call != NULL) + { + char buf[512]; + + snprintf(buf, sizeof(buf), + "(sleep 2; %s -c %s)&", argv[0], addr_to_call); + if (system(buf)) + linphone_gtk_display_warning(linphone_gtk_get_core(), + "Unable to perform remote call!"); + } + gtk_main(); gdk_threads_leave(); linphone_gtk_destroy_log_window(); @@ -1047,5 +1159,3 @@ int main(int argc, char *argv[]){ gtk_status_icon_set_visible(icon,FALSE); return 0; } - -