#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);
LinphoneFriend *lf, const char *url);
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_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf);
static void print_prompt(LinphoneCore *opm);
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;
+
+
void linphonec_call_identify(LinphoneCall* call){
static long callid=1;
return call;
}
}
- linphonec_out("Sorry, no call with id %i exists at this time.",id);
+ linphonec_out("Sorry, no call with id %i exists at this time.\n",id);
return NULL;
}
static void
linphonec_display_refer (LinphoneCore * lc, const char *refer_to)
{
- linphonec_out("Receiving out of call refer to %s", refer_to);
+ linphonec_out("Receiving out of call refer to %s\n", refer_to);
}
/*
}
+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");
+ }
+}
+
+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.\n", id, from);
+ 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.\n", from,id);
+ 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 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", from,id);
+ 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;
}
*/
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?)
}
}
}else{
#ifdef HAVE_READLINE
- return readline(prompt);
+ char* ret=readline(prompt);
+ return ret;
#endif
}
}
#endif
linphonec_vtable.call_state_changed=linphonec_call_state_changed;
linphonec_vtable.notify_presence_recv = linphonec_notify_presence_received;
- linphonec_vtable.new_unknown_subscriber = linphonec_new_unknown_subscriber;
+ 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;
linphonec_vtable.dtmf_received=linphonec_dtmf_received;
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)
{
+ // 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 */
{
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");
snprintf(message, 255, "Can't open %s for writing: %s\n",
to, strerror(errno));
fprintf(stderr, "%s", message);
+ fclose(in);
return 0;
}
{
if ( ! fwrite(buf, 1, n, out) )
{
+ fclose(in);
+ fclose(out);
return 0;
}
}