#endif /*_WIN32_WCE*/
#include <limits.h>
#include <ctype.h>
+#include <stdlib.h>
#include <linphonecore.h>
#define PACKAGE_DIR ""
#endif
+#ifdef HAVE_X11_XLIB_H
+#include <X11/Xlib.h>
+#endif
+
/***************************************************************************
*
* Types
#endif /*_WIN32_WCE*/
static int linphonec_parse_cmdline(int argc, char **argv);
static int linphonec_init(int argc, char **argv);
-static int linphonec_main_loop (LinphoneCore * opm, char * sipAddr);
+static int linphonec_main_loop (LinphoneCore * opm);
static int linphonec_idle_call (void);
#ifdef HAVE_READLINE
static int linphonec_initialize_readline(void);
#endif
/* These are callback for linphone core */
-static void linphonec_call_received(LinphoneCore *lc, const char *from);
static void linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm,
const char *username);
+static void linphonec_display_refer (LinphoneCore * lc, const char *refer_to);
static void linphonec_display_something (LinphoneCore * lc, const char *something);
static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url);
static void linphonec_display_warning (LinphoneCore * lc, const char *something);
-static void stub () {}
-static void linphonec_notify_received(LinphoneCore *lc,LinphoneFriend *fid);
+static void linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event);
+
+static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid);
static void linphonec_new_unknown_subscriber(LinphoneCore *lc,
LinphoneFriend *lf, const char *url);
-static void linphonec_bye_received(LinphoneCore *lc, const char *from);
+
static void linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr,
- const char *from, const char *msg);
+ const LinphoneAddress *from, const char *msg);
static void linphonec_display_status (LinphoneCore * lc, const char *something);
-static void linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate);
-static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf);
+static void linphonec_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf);
static void print_prompt(LinphoneCore *opm);
+void linphonec_out(const char *fmt,...);
/***************************************************************************
*
* Global variables
static int trace_level = 0;
static char *logfile_name = NULL;
static char configfile_name[PATH_MAX];
-static char *sipAddr = NULL; /* for autocall */
+static char zrtpsecrets[PATH_MAX];
+static const char *factory_configfile_name=NULL;
+static char *sip_addr_to_call = NULL; /* for autocall */
+static int window_id = 0; /* 0=standalone window, or window id for embedding video */
#if !defined(_WIN32_WCE)
static ortp_pipe_t client_sock=ORTP_PIPE_INVALID;
#endif /*_WIN32_WCE*/
static ortp_pipe_t server_sock;
#endif /*_WIN32_WCE*/
+bool_t linphonec_camera_enabled=TRUE;
-LinphoneCoreVTable linphonec_vtable
-#if !defined (_MSC_VER)
-= {
- .show =(ShowInterfaceCb) stub,
- .inv_recv = linphonec_call_received,
- .bye_recv = linphonec_bye_received,
- .notify_recv = linphonec_notify_received,
- .new_unknown_subscriber = linphonec_new_unknown_subscriber,
- .auth_info_requested = linphonec_prompt_for_auth,
- .display_status = linphonec_display_status,
- .display_message=linphonec_display_something,
-#ifdef VINCENT_MAURY_RSVP
- /* the yes/no dialog box */
- .display_yes_no= (DisplayMessageCb) stub,
-#endif
- .display_warning=linphonec_display_warning,
- .display_url=linphonec_display_url,
- .display_question=(DisplayQuestionCb)stub,
- .text_received=linphonec_text_received,
- .general_state=linphonec_general_state,
- .dtmf_received=linphonec_dtmf_received
-}
-#endif /*_WIN32_WCE*/
-;
+void linphonec_call_identify(LinphoneCall* call){
+ static long callid=1;
+ linphone_call_set_user_pointer (call,(void*)callid);
+ callid++;
+}
+
+LinphoneCall *linphonec_get_call(long id){
+ const MSList *elem=linphone_core_get_calls(linphonec);
+ for (;elem!=NULL;elem=elem->next){
+ LinphoneCall *call=(LinphoneCall*)elem->data;
+ if (linphone_call_get_user_pointer (call)==(void*)id){
+ return call;
+ }
+ }
+ linphonec_out("Sorry, no call with id %i exists at this time.\n",id);
+ return NULL;
+}
/***************************************************************************
*
*
***************************************************************************/
+/*
+ * Linphone core callback
+ */
+static void
+linphonec_display_refer (LinphoneCore * lc, const char *refer_to)
+{
+ linphonec_out("Receiving out of call refer to %s\n", refer_to);
+}
+
/*
* Linphone core callback
*/
fprintf (stdout, "%s : %s\n", something, url);
}
-
-/*
- * Linphone core callback
- */
-static void
-linphonec_call_received(LinphoneCore *lc, const char *from)
-{
- linphonec_set_caller(from);
- if ( auto_answer) {
- answer_call=TRUE;
- }
-}
-
/*
* Linphone core callback
*/
* Linphone core callback
*/
static void
-linphonec_notify_received(LinphoneCore *lc,LinphoneFriend *fid)
+linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event)
+{
+ if(!strcmp(event,"refer"))
+ {
+ linphonec_out("The distand endpoint %s of call %li has been transfered, you can safely close the call.\n",
+ from,(long)linphone_call_get_user_pointer (call));
+ }
+}
+
+
+/*
+ * Linphone core callback
+ */
+static void
+linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid)
{
char *tmp=linphone_address_as_string(linphone_friend_get_address(fid));
printf("Friend %s is %s\n", tmp, linphone_online_status_to_string(linphone_friend_get_status(fid)));
}
-/*
- * Linphone core callback
- */
-static void
-linphonec_bye_received(LinphoneCore *lc, const char *from)
-{
- // Should change prompt back to original maybe
+static void linphonec_call_updated(LinphoneCall *call){
+ const LinphoneCallParams *cp=linphone_call_get_current_params(call);
+ if (!linphone_call_camera_enabled (call) && linphone_call_params_video_enabled (cp)){
+ linphonec_out("Far end requests to share video.\nType 'camera on' if you agree.\n");
+ }
+}
- // printing this is unneeded as we'd get a "Communication ended"
- // message trough display_status callback anyway
- //printf("Bye received from %s\n", from);
+static void linphonec_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t encrypted, const char *auth_token) {
+ long id=(long)linphone_call_get_user_pointer (call);
+ if (!encrypted) {
+ linphonec_out("Call %i is not fully encrypted and auth token is %s.\n", id,
+ (auth_token != NULL) ? auth_token : "absent");
+ } else {
+ linphonec_out("Call %i is fully encrypted and auth token is %s.\n", id,
+ (auth_token != NULL) ? auth_token : "absent");
+ }
+}
+
+static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState st, const char *msg){
+ char *from=linphone_call_get_remote_address_as_string(call);
+ long id=(long)linphone_call_get_user_pointer (call);
+ switch(st){
+ case LinphoneCallEnd:
+ linphonec_out("Call %i with %s ended (%s).\n", id, from, linphone_reason_to_string(linphone_call_get_reason(call)));
+ break;
+ case LinphoneCallResuming:
+ linphonec_out("Resuming call %i with %s.\n", id, from);
+ break;
+ case LinphoneCallStreamsRunning:
+ linphonec_out("Media streams established with %s for call %i (%s).\n", from,id,( linphone_call_params_video_enabled( linphone_call_get_current_params(call)) ? "video":"audio"));
+ break;
+ case LinphoneCallPausing:
+ linphonec_out("Pausing call %i with %s.\n", id, from);
+ break;
+ case LinphoneCallPaused:
+ linphonec_out("Call %i with %s is now paused.\n", id, from);
+ break;
+ case LinphoneCallPausedByRemote:
+ linphonec_out("Call %i has been paused by %s.\n",id,from);
+ break;
+ case LinphoneCallIncomingReceived:
+ linphonec_call_identify(call);
+ linphone_call_enable_camera (call,linphonec_camera_enabled);
+ id=(long)linphone_call_get_user_pointer (call);
+ linphonec_set_caller(from);
+ if ( auto_answer) {
+ answer_call=TRUE;
+ }
+ linphonec_out("Receiving new incoming call from %s, assigned id %i\n", from,id);
+ break;
+ case LinphoneCallOutgoingInit:
+ linphonec_call_identify(call);
+ id=(long)linphone_call_get_user_pointer (call);
+ linphonec_out("Establishing call id to %s, assigned id %i\n", from,id);
+ break;
+ case LinphoneCallUpdatedByRemote:
+ linphonec_call_updated(call);
+ break;
+ case LinphoneCallOutgoingProgress:
+ linphonec_out("Call %i to %s in progress.\n", id, from);
+ break;
+ case LinphoneCallOutgoingRinging:
+ linphonec_out("Call %i to %s ringing.\n", id, from);
+ break;
+ case LinphoneCallConnected:
+ linphonec_out("Call %i with %s connected.\n", id, from);
+ break;
+ case LinphoneCallOutgoingEarlyMedia:
+ linphonec_out("Call %i with %s early media.\n", id, from);
+ break;
+ case LinphoneCallError:
+ linphonec_out("Call %i with %s error.\n", id, from);
+ break;
+ default:
+ break;
+ }
+ ms_free(from);
}
/*
*/
static void
linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr,
- const char *from, const char *msg)
+ const LinphoneAddress *from, const char *msg)
{
- printf("%s: %s\n", from, msg);
+ linphonec_out("Message received from %s: %s\n", linphone_address_as_string(from), msg);
// TODO: provide mechanism for answering.. ('say' command?)
}
-static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf){
- fprintf(stdout,"Receiving tone %c\n",dtmf);
+static void linphonec_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf){
+ char *from=linphone_call_get_remote_address_as_string(call);
+ fprintf(stdout,"Receiving tone %c from %s\n",dtmf,from);
fflush(stdout);
-}
-
-static void
-linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate)
-{
- if (show_general_state) {
- switch(gstate->new_state) {
- case GSTATE_POWER_OFF:
- printf("GSTATE_POWER_OFF");
- break;
- case GSTATE_POWER_STARTUP:
- printf("GSTATE_POWER_STARTUP");
- break;
- case GSTATE_POWER_ON:
- printf("GSTATE_POWER_ON");
- break;
- case GSTATE_POWER_SHUTDOWN:
- printf("GSTATE_POWER_SHUTDOWN");
- break;
- case GSTATE_REG_NONE:
- printf("GSTATE_REG_NONE");
- break;
- case GSTATE_REG_OK:
- printf("GSTATE_REG_OK");
- break;
- case GSTATE_REG_FAILED:
- printf("GSTATE_REG_FAILED");
- break;
- case GSTATE_CALL_IDLE:
- printf("GSTATE_CALL_IDLE");
- break;
- case GSTATE_CALL_OUT_INVITE:
- printf("GSTATE_CALL_OUT_INVITE");
- break;
- case GSTATE_CALL_OUT_CONNECTED:
- printf("GSTATE_CALL_OUT_CONNECTED");
- break;
- case GSTATE_CALL_IN_INVITE:
- printf("GSTATE_CALL_IN_INVITE");
- break;
- case GSTATE_CALL_IN_CONNECTED:
- printf("GSTATE_CALL_IN_CONNECTED");
- break;
- case GSTATE_CALL_END:
- printf("GSTATE_CALL_END");
- break;
- case GSTATE_CALL_ERROR:
- printf("GSTATE_CALL_ERROR");
- break;
- default:
- printf("GSTATE_UNKNOWN_%d",gstate->new_state);
- }
- if (gstate->message) printf(" %s", gstate->message);
- printf("\n");
- }
+ ms_free(from);
}
static char received_prompt[PROMPT_MAX_LEN];
linphonec_idle_call();
#ifdef WIN32
Sleep(20);
+ /* Following is to get the video window going as it
+ should. Maybe should we only have this on when the option -V
+ or -D is on? */
+ MSG msg;
+
+ if (PeekMessage(&msg, NULL, 0, 0,1)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
#else
usleep(20000);
#endif
}
}else{
#ifdef HAVE_READLINE
- return readline(prompt);
+ char* ret=readline(prompt);
+ return ret;
#endif
}
}
return auto_answer;
}
+LinphoneCoreVTable linphonec_vtable={0};
+
/***************************************************************************/
/*
* Main
int _tmain(int argc, _TCHAR* wargv[]) {
char **argv=convert_args_to_ascii(argc,wargv);
trace_level=6;
- linphonec_vtable.show =(ShowInterfaceCb) stub;
- linphonec_vtable.inv_recv = linphonec_call_received;
- linphonec_vtable.bye_recv = linphonec_bye_received;
- linphonec_vtable.notify_recv = linphonec_notify_received;
- linphonec_vtable.new_unknown_subscriber = linphonec_new_unknown_subscriber;
+
+#else
+int
+main (int argc, char *argv[]) {
+#endif
+ linphonec_vtable.call_state_changed=linphonec_call_state_changed;
+ linphonec_vtable.notify_presence_recv = linphonec_notify_presence_received;
+ linphonec_vtable.new_subscription_request = linphonec_new_unknown_subscriber;
linphonec_vtable.auth_info_requested = linphonec_prompt_for_auth;
linphonec_vtable.display_status = linphonec_display_status;
linphonec_vtable.display_message=linphonec_display_something;
-#ifdef VINCENT_MAURY_RSVP
- /* the yes/no dialog box */
- linphonec_vtable.display_yes_no= (DisplayMessageCb) stub;
-#endif
linphonec_vtable.display_warning=linphonec_display_warning;
linphonec_vtable.display_url=linphonec_display_url;
- linphonec_vtable.display_question=(DisplayQuestionCb)stub;
linphonec_vtable.text_received=linphonec_text_received;
- linphonec_vtable.general_state=linphonec_general_state;
linphonec_vtable.dtmf_received=linphonec_dtmf_received;
-
-#else
-int
-main (int argc, char *argv[]) {
-#endif
-
-
+ linphonec_vtable.refer_received=linphonec_display_refer;
+ linphonec_vtable.notify_recv=linphonec_notify_received;
+ linphonec_vtable.call_encryption_changed=linphonec_call_encryption_changed;
+
if (! linphonec_init(argc, argv) ) exit(EXIT_FAILURE);
- linphonec_main_loop (linphonec, sipAddr);
+ linphonec_main_loop (linphonec);
linphonec_finish(EXIT_SUCCESS);
#ifndef _WIN32
snprintf(configfile_name, PATH_MAX, "%s/.linphonerc",
getenv("HOME"));
+ snprintf(zrtpsecrets, PATH_MAX, "%s/.linphone-zidcache",
+ getenv("HOME"));
#elif defined(_WIN32_WCE)
strncpy(configfile_name,PACKAGE_DIR "\\linphonerc",PATH_MAX);
mylogfile=fopen(PACKAGE_DIR "\\" "linphonec.log","w");
#else
snprintf(configfile_name, PATH_MAX, "%s/Linphone/linphonerc",
getenv("APPDATA"));
+ snprintf(zrtpsecrets, PATH_MAX, "%s/Linphone/linphone-zidcache",
+ getenv("APPDATA"));
#endif
/* Handle configuration filename changes */
switch (handle_configfile_migration())
/*
* Initialize linphone core
*/
- linphonec=linphone_core_new (&linphonec_vtable, configfile_name, NULL,
- NULL);
+ linphonec=linphone_core_new (&linphonec_vtable, configfile_name, factory_configfile_name, NULL);
+ linphone_core_set_zrtp_secrets_file(linphonec,zrtpsecrets);
linphone_core_enable_video(linphonec,vcap_enabled,display_enabled);
+ if (display_enabled && window_id != 0)
+ {
+ printf ("Setting window_id: 0x%x\n", window_id);
+ linphone_core_set_native_video_window_id(linphonec,window_id);
+ }
+
linphone_core_enable_video_preview(linphonec,preview_enabled);
if (!(vcap_enabled || display_enabled)) printf("Warning: video is disabled in linphonec, use -V or -C or -D to enable.\n");
#ifdef HAVE_READLINE
void
linphonec_finish(int exit_status)
{
- printf("Terminating...\n");
+ // Do not allow concurrent destroying to prevent glibc errors
+ static bool_t terminating=FALSE;
+ if (terminating) return;
+ terminating=TRUE;
+ linphonec_out("Terminating...\n");
/* Terminate any pending call */
- linphonec_parse_command_line(linphonec, "terminate");
- linphonec_command_finished();
+ linphone_core_terminate_all_calls(linphonec);
#ifdef HAVE_READLINE
linphonec_finish_readline();
#endif
{
fclose (mylogfile);
}
-
+ printf("\n");
exit(exit_status);
}
int
linphonec_prompt_for_auth_final(LinphoneCore *lc)
{
+ static int reentrancy=0;
char *input, *iptr;
char auth_prompt[256];
#ifdef HAVE_READLINE
rl_hook_func_t *old_event_hook;
#endif
+
+ if (reentrancy!=0) return 0;
+
+ reentrancy++;
+
LinphoneAuthInfo *pending_auth=auth_stack.elem[auth_stack.nitems-1];
snprintf(auth_prompt, 256, "Password for %s on %s: ",
void
print_usage (int exit_status)
{
- fprintf (stdout, "\n\
-usage: linphonec [-c file] [-s sipaddr] [-a] [-V] [-d level ] [-l logfile]\n\
- linphonec -v\n\
-\n\
- -c file specify path of configuration file.\n\
- -d level be verbose. 0 is no output. 6 is all output\n\
- -l logfile specify the log file for your SIP phone\n\
- -s sipaddress specify the sip call to do at startup\n\
- -a enable auto answering for incoming calls\n\
- -V enable video features globally (disabled by default)\n\
- -C enable video capture only (disabled by default)\n\
- -D enable video display only (disabled by default)\n\
- -S show general state messages (disabled by default)\n\
- -v or --version display version and exits.\n");
+ fprintf (stdout, "\n"
+"usage: linphonec [-c file] [-s sipaddr] [-a] [-V] [-d level ] [-l logfile]\n"
+ "linphonec -v\n"
+"\n"
+" -b file specify path of readonly factory configuration file.\n"
+" -c file specify path of configuration file.\n"
+" -d level be verbose. 0 is no output. 6 is all output\n"
+" -l logfile specify the log file for your SIP phone\n"
+" -s sipaddress specify the sip call to do at startup\n"
+" -a enable auto answering for incoming calls\n"
+" -V enable video features globally (disabled by default)\n"
+" -C enable video capture only (disabled by default)\n"
+" -D enable video display only (disabled by default)\n"
+" -S show general state messages (disabled by default)\n"
+" --wid windowid force embedding of video window into provided windowid (disabled by default)\n"
+" -v or --version display version and exits.\n");
exit(exit_status);
}
+#ifdef VIDEO_ENABLED
+
+#ifdef HAVE_X11_XLIB_H
+static void x11_apply_video_params(VideoParams *params, Window window){
+ XWindowChanges wc;
+ unsigned int flags=0;
+ static Display *display = NULL;
+ const char *dname=getenv("DISPLAY");
+
+ if (display==NULL && dname!=NULL){
+ XInitThreads();
+ display=XOpenDisplay(dname);
+ }
+
+ if (display==NULL){
+ ms_error("Could not open display %s",dname);
+ return;
+ }
+ memset(&wc,0,sizeof(wc));
+ wc.x=params->x;
+ wc.y=params->y;
+ wc.width=params->w;
+ wc.height=params->h;
+ if (params->x!=-1 ){
+ flags|=CWX|CWY;
+ }
+ if (params->w!=-1){
+ flags|=CWWidth|CWHeight;
+ }
+ /*printf("XConfigureWindow x=%i,y=%i,w=%i,h=%i\n",
+ wc.x, wc.y ,wc.width, wc.height);*/
+ XConfigureWindow(display,window,flags,&wc);
+ if (params->show)
+ XMapWindow(display,window);
+ else
+ XUnmapWindow(display,window);
+ XSync(display,FALSE);
+}
+#endif
+
+
+static void lpc_apply_video_params(){
+ static unsigned long old_wid=0,old_pwid=0;
+ unsigned long wid=linphone_core_get_native_video_window_id (linphonec);
+ unsigned long pwid=linphone_core_get_native_preview_window_id (linphonec);
+
+ if (wid!=0 && (lpc_video_params.refresh || old_wid!=wid)){
+ lpc_video_params.refresh=FALSE;
+#ifdef HAVE_X11_XLIB_H
+ if (lpc_video_params.wid==0){ // do not manage window if embedded
+ x11_apply_video_params(&lpc_video_params,wid);
+ } else {
+ linphone_core_show_video(linphonec, lpc_video_params.show);
+ }
+#endif
+ }
+ old_wid=wid;
+ if (pwid!=0 && (lpc_preview_params.refresh || old_pwid!=pwid)){
+ lpc_preview_params.refresh=FALSE;
+#ifdef HAVE_X11_XLIB_H
+ /*printf("wid=%lu pwid=%lu\n",wid,pwid);*/
+ if (lpc_preview_params.wid==0){ // do not manage window if embedded
+ printf("Refreshing\n");
+ x11_apply_video_params(&lpc_preview_params,pwid);
+ }
+#endif
+ }
+ old_pwid=pwid;
+}
+
+#endif
+
/*
*
linphone_core_accept_call(opm,NULL);
answer_call=FALSE;
}
+ /* auto call handling */
+ if (sip_addr_to_call != NULL )
+ {
+ char buf[512];
+ snprintf (buf, sizeof(buf),"call %s", sip_addr_to_call);
+ sip_addr_to_call=NULL;
+ linphonec_parse_command_line(linphonec, buf);
+ }
if ( auth_stack.nitems )
{
#endif
}
+#ifdef VIDEO_ENABLED
+ lpc_apply_video_params();
+#endif
+
return 0;
}
}
static int
-linphonec_main_loop (LinphoneCore * opm, char * sipAddr)
+linphonec_main_loop (LinphoneCore * opm)
{
- char buf[LINE_MAX_LEN]; /* auto call handling */
char *input;
print_prompt(opm);
- /* auto call handling */
- if (sipAddr != NULL )
- {
- snprintf (buf, sizeof(buf),"call %s", sipAddr);
- linphonec_parse_command_line(linphonec, buf);
- }
-
while (linphonec_running && (input=linphonec_readline(prompt)))
{
char *iptr; /* input and input pointer */
#endif /*_WIN32_WCE*/
snprintf(configfile_name, PATH_MAX, "%s", argv[arg_num]);
}
+ else if (strncmp ("-b", argv[arg_num], 2) == 0)
+ {
+ if ( ++arg_num >= argc ) print_usage(EXIT_FAILURE);
+#if !defined(_WIN32_WCE)
+ if (access(argv[arg_num],F_OK)!=0 )
+ {
+ fprintf (stderr,
+ "Cannot open config file %s.\n",
+ argv[arg_num]);
+ exit(EXIT_FAILURE);
+ }
+#endif /*_WIN32_WCE*/
+ factory_configfile_name = argv[arg_num];
+ }
else if (strncmp ("-s", argv[arg_num], 2) == 0)
{
arg_num++;
if (arg_num < argc)
- sipAddr = argv[arg_num];
+ sip_addr_to_call = argv[arg_num];
}
else if (strncmp ("-a", argv[arg_num], 2) == 0)
{
{
unix_socket=1;
}
+ else if (strncmp ("--wid", argv[arg_num], 5) == 0)
+ {
+ arg_num++;
+ if (arg_num < argc) {
+ char *tmp;
+ window_id = strtol( argv[arg_num], &tmp, 0 );
+ lpc_video_params.wid = window_id;
+ }
+ }
else if (old_arg_num == arg_num)
{
fprintf (stderr, "ERROR: bad arguments\n");