]> sjero.net Git - linphone/blob - console/commands.c
Merge branch 'master' of git.sv.gnu.org:/srv/git/linphone
[linphone] / console / commands.c
1 /****************************************************************************
2  *
3  *  $Id: commands.c,v 1.39 2008/07/03 15:08:34 smorlat Exp $
4  *
5  *  Copyright (C) 2006-2009  Sandro Santilli <strk@keybit.net>
6  *  Copyright (C) 2004  Simon MORLAT <simon.morlat@linphone.org>
7  *
8 ****************************************************************************
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  *
24  ****************************************************************************/
25
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #ifndef _WIN32_WCE
30 #include <errno.h>
31 #include <unistd.h>
32 #endif /*_WIN32_WCE*/
33 #include <limits.h>
34 #include <ctype.h>
35 #include <linphonecore.h>
36 #include "linphonec.h"
37 #include "lpconfig.h"
38
39 #ifndef WIN32
40 #include <sys/wait.h>
41 #endif
42
43 #define AUDIO 0
44 #define VIDEO 1
45
46 /***************************************************************************
47  *
48  *  Forward declarations 
49  *
50  ***************************************************************************/
51
52 extern char *lpc_strip_blanks(char *input);
53
54 /* Command handlers */
55 static int lpc_cmd_help(LinphoneCore *, char *);
56 static int lpc_cmd_proxy(LinphoneCore *, char *);
57 static int lpc_cmd_call(LinphoneCore *, char *);
58 static int lpc_cmd_calls(LinphoneCore *, char *);
59 static int lpc_cmd_chat(LinphoneCore *, char *);
60 static int lpc_cmd_answer(LinphoneCore *, char *);
61 static int lpc_cmd_autoanswer(LinphoneCore *, char *);
62 static int lpc_cmd_terminate(LinphoneCore *, char *);
63 static int lpc_cmd_redirect(LinphoneCore *, char *);
64 static int lpc_cmd_call_logs(LinphoneCore *, char *);
65 static int lpc_cmd_ipv6(LinphoneCore *, char *);
66 static int lpc_cmd_transfer(LinphoneCore *, char *);
67 static int lpc_cmd_quit(LinphoneCore *, char *);
68 static int lpc_cmd_nat(LinphoneCore *, char *);
69 static int lpc_cmd_stun(LinphoneCore *, char *);
70 static int lpc_cmd_firewall(LinphoneCore *, char *);
71 static int lpc_cmd_friend(LinphoneCore *, char*);
72 static int lpc_cmd_soundcard(LinphoneCore *, char *);
73 static int lpc_cmd_webcam(LinphoneCore *, char *);
74 static int lpc_cmd_staticpic(LinphoneCore *, char *);
75 static int lpc_cmd_play(LinphoneCore *, char *);
76 static int lpc_cmd_record(LinphoneCore *, char *);
77 static int lpc_cmd_register(LinphoneCore *, char *);
78 static int lpc_cmd_unregister(LinphoneCore *, char *);
79 static int lpc_cmd_duration(LinphoneCore *lc, char *args);
80 static int lpc_cmd_status(LinphoneCore *lc, char *args);
81 static int lpc_cmd_ports(LinphoneCore *lc, char *args);
82 static int lpc_cmd_param(LinphoneCore *lc, char *args);
83 static int lpc_cmd_speak(LinphoneCore *lc, char *args);
84 static int lpc_cmd_acodec(LinphoneCore *lc, char *args);
85 static int lpc_cmd_vcodec(LinphoneCore *lc, char *args);
86 static int lpc_cmd_codec(int type, LinphoneCore *lc, char *args);
87 static int lpc_cmd_echocancellation(LinphoneCore *lc, char *args);
88 static int lpc_cmd_echolimiter(LinphoneCore *lc, char *args);
89 static int lpc_cmd_pause(LinphoneCore *lc, char *args);
90 static int lpc_cmd_resume(LinphoneCore *lc, char *args);
91 static int lpc_cmd_mute_mic(LinphoneCore *lc, char *args);
92 static int lpc_cmd_unmute_mic(LinphoneCore *lc, char *args);
93 static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args);
94 #ifdef VIDEO_ENABLED
95 static int lpc_cmd_camera(LinphoneCore *lc, char *args);
96 static int lpc_cmd_video_window(LinphoneCore *lc, char *args);
97 static int lpc_cmd_preview_window(LinphoneCore *lc, char *args);
98 static int lpc_cmd_snapshot(LinphoneCore *lc, char *args);
99 static int lpc_cmd_vfureq(LinphoneCore *lc, char *arg);
100 #endif
101 static int lpc_cmd_states(LinphoneCore *lc, char *args);
102 static int lpc_cmd_identify(LinphoneCore *lc, char *args);
103 static int lpc_cmd_ringback(LinphoneCore *lc, char *args);
104
105 /* Command handler helpers */
106 static void linphonec_proxy_add(LinphoneCore *lc);
107 static void linphonec_proxy_display(LinphoneProxyConfig *lc);
108 static void linphonec_proxy_list(LinphoneCore *lc);
109 static void linphonec_proxy_remove(LinphoneCore *lc, int index);
110 static  int linphonec_proxy_use(LinphoneCore *lc, int index);
111 static void linphonec_proxy_show(LinphoneCore *lc,int index);
112 static void linphonec_friend_display(LinphoneFriend *fr);
113 static int linphonec_friend_list(LinphoneCore *lc, char *arg);
114 static void linphonec_display_command_help(LPC_COMMAND *cmd);
115 static int linphonec_friend_call(LinphoneCore *lc, unsigned int num);
116 #ifndef WIN32
117 static int linphonec_friend_add(LinphoneCore *lc, const char *name, const char *addr);
118 #endif
119 static int linphonec_friend_delete(LinphoneCore *lc, int num);
120 static int linphonec_friend_delete(LinphoneCore *lc, int num);
121 static void linphonec_codec_list(int type, LinphoneCore *lc);
122 static void linphonec_codec_enable(int type, LinphoneCore *lc, int index);
123 static void linphonec_codec_disable(int type, LinphoneCore *lc, int index);
124
125
126
127 /* Command table management */
128 static LPC_COMMAND *lpc_find_command(const char *name);
129
130 void linphonec_out(const char *fmt,...);
131
132 VideoParams lpc_video_params={-1,-1,-1,-1,0,TRUE};
133 VideoParams lpc_preview_params={-1,-1,-1,-1,0,TRUE};
134
135 /***************************************************************************
136  *
137  *  Global variables
138  *
139  ***************************************************************************/
140
141 /*
142  * Commands table.
143  */
144 static LPC_COMMAND commands[] = {
145         { "help", lpc_cmd_help, "Print commands help.",
146                 "'help <command>'\t: displays specific help for command.\n"
147                 "'help advanced'\t: shows advanced commands.\n"
148         },
149         { "call", lpc_cmd_call, "Call a SIP uri or number",
150 #ifdef VIDEO_ENABLED
151                 "'call <sip-url or number>  [options]' \t: initiate a call to the specified destination.\n"
152                 "Options can be:\n"
153                 "--audio-only : initiate the call without video.\n"
154                 "--early-media : sends audio and video stream immediately when remote proposes early media.\n"
155 #else
156                 "'call <sip-url or number>' \t: initiate a call to the specified destination.\n"
157 #endif
158                 },
159         { "calls", lpc_cmd_calls, "Show all the current calls with their id and status.",
160                 NULL
161                 },
162         { "chat", lpc_cmd_chat, "Chat with a SIP uri",
163                 "'chat <sip-url> \"message\"' "
164                 ": send a chat message \"message\" to the specified destination."
165                 },
166         { "terminate", lpc_cmd_terminate, "Terminate a call",
167                 "'terminate' : Terminate the current call\n"
168                 "'terminate <call id>' : Terminate the call with supplied id\n"
169                 "'terminate <all>' : Terminate all the current calls\n"
170                 },
171         { "answer", lpc_cmd_answer, "Answer a call",
172                 "'answer' : Answer the current incoming call\n"
173                 "'answer <call id>' : Answer the call with given id\n"
174         },
175         { "pause", lpc_cmd_pause, "pause a call",
176                 "'pause' : pause the current call\n"},
177         { "resume", lpc_cmd_resume, "resume a call",
178                 "'resume' : resume the unique call\n"
179                 "'resume <call id>' : hold off the call with given id\n"},
180         { "transfer", lpc_cmd_transfer,
181                 "Transfer a call to a specified destination.",
182                 "'transfer <sip-uri>' : transfers the current active call to the destination sip-uri\n"
183                 "'transfer <call id> <sip-uri>': transfers the call with 'id' to the destination sip-uri\n"
184                 "'transfer <call id1> --to-call <call id2>': transfers the call with 'id1' to the destination of call 'id2' (attended transfer)\n"
185         },
186         { "mute", lpc_cmd_mute_mic, 
187           "Mute microphone and suspend voice transmission."},
188 #ifdef VIDEO_ENABLED
189         { "camera", lpc_cmd_camera, "Send camera output for current call.",
190                 "'camera on'\t: allow sending of local camera video to remote end.\n"
191                 "'camera off'\t: disable sending of local camera's video to remote end.\n"},
192 #endif
193         { "unmute", lpc_cmd_unmute_mic, 
194                   "Unmute microphone and resume voice transmission."},
195         { "duration", lpc_cmd_duration, "Print duration in seconds of the last call.", NULL },
196         
197         { "autoanswer", lpc_cmd_autoanswer, "Show/set auto-answer mode",
198                 "'autoanswer'       \t: show current autoanswer mode\n"
199                 "'autoanswer enable'\t: enable autoanswer mode\n"
200                 "'autoanswer disable'\t: disable autoanswer modeĀ \n"},
201         { "proxy", lpc_cmd_proxy, "Manage proxies",
202                 "'proxy list' : list all proxy setups.\n"
203                 "'proxy add' : add a new proxy setup.\n"
204                 "'proxy remove <index>' : remove proxy setup with number index.\n"
205                 "'proxy use <index>' : use proxy with number index as default proxy.\n"
206                 "'proxy unuse' : don't use a default proxy.\n"
207                 "'proxy show <index>' : show configuration and status of the proxy numbered by index.\n"
208                 "'proxy show default' : show configuration and status of the default proxy.\n"
209         },
210         { "soundcard", lpc_cmd_soundcard, "Manage soundcards",
211                 "'soundcard list' : list all sound devices.\n"
212                 "'soundcard show' : show current sound devices configuration.\n"
213                 "'soundcard use <index>' : select a sound device.\n"
214                 "'soundcard use files' : use .wav files instead of soundcard\n"
215         },
216         { "webcam", lpc_cmd_webcam, "Manage webcams",
217                 "'webcam list' : list all known devices.\n"
218                 "'webcam use <index>' : select a video device.\n"
219         },
220         { "ipv6", lpc_cmd_ipv6, "Use IPV6",
221                 "'ipv6 status' : show ipv6 usage status.\n"
222                 "'ipv6 enable' : enable the use of the ipv6 network.\n"
223                 "'ipv6 disable' : do not use ipv6 network."
224         },
225         { "nat", lpc_cmd_nat, "Set nat address",
226                 "'nat'        : show nat settings.\n"
227                 "'nat <addr>' : set nat address.\n"
228         },
229         { "stun", lpc_cmd_stun, "Set stun server address",
230                 "'stun'        : show stun settings.\n"
231                 "'stun <addr>' : set stun server address.\n"
232         },
233         { "firewall", lpc_cmd_firewall, "Set firewall policy",
234                 "'firewall'        : show current firewall policy.\n"
235                 "'firewall none'   : use direct connection.\n"
236                 "'firewall nat'    : use nat address given with the 'nat' command.\n"
237                 "'firewall stun'   : use stun server given with the 'stun' command.\n"
238         },
239         { "call-logs", lpc_cmd_call_logs, "Calls history", NULL },
240         { "friend", lpc_cmd_friend, "Manage friends",
241                 "'friend list [<pattern>]'    : list friends.\n"
242                 "'friend call <index>'        : call a friend.\n"
243                 "'friend add <name> <addr>'   : add friend, <name> must be quoted to include\n"
244             "                               spaces, <addr> has \"sip:\" added if it isn't\n"
245             "                               there.  Don't use '<' '>' around <addr>.\n"
246                 "'friend delete <index>'      : remove friend, 'all' removes all\n"
247         },
248         { "play", lpc_cmd_play, "play a wav file",
249                 "This command has two roles:\n"
250                 "Plays a file instead of capturing from soundcard - only available in file mode (see 'help soundcard')\n"
251                 "Specifies a wav file to be played to play music to far end when putting it on hold (pause)\n"
252                 "'play <wav file>'    : play a wav file."
253         },
254         { "record", lpc_cmd_record, "record to a wav file",
255                 "This feature is available only in file mode (see 'help soundcard')\n"
256                 "'record <wav file>'    : record into wav file."
257         },
258         { "quit", lpc_cmd_quit, "Exit linphonec", NULL },
259         { (char *)NULL, (lpc_cmd_handler)NULL, (char *)NULL, (char *)NULL }
260 };
261
262
263 static LPC_COMMAND advanced_commands[] = {
264          { "codec", lpc_cmd_acodec, "Audio codec configuration",
265             "'codec list' : list audio codecs\n"
266             "'codec enable <index>' : enable available audio codec\n"
267             "'codec disable <index>' : disable audio codec" },
268     { "vcodec", lpc_cmd_vcodec, "Video codec configuration",
269             "'vcodec list' : list video codecs\n"
270             "'vcodec enable <index>' : enable available video codec\n"
271             "'vcodec disable <index>' : disable video codec" },
272         { "ec", lpc_cmd_echocancellation, "Echo cancellation",
273             "'ec on [<delay>] [<tail>] [<framesize>]' : turn EC on with given delay, tail length and framesize\n"
274             "'ec off' : turn echo cancellation (EC) off\n"
275             "'ec show' : show EC status" },
276         { "el", lpc_cmd_echolimiter, "Echo limiter",
277             "'el on turns on echo limiter (automatic half duplex, for cases where echo canceller cannot work)\n"
278             "'el off' : turn echo limiter off\n"
279             "'el show' : show echo limiter status" },
280         { "nortp-on-audio-mute", lpc_cmd_rtp_no_xmit_on_audio_mute,
281                   "Set the rtp_no_xmit_on_audio_mute configuration parameter",
282                   "   If set to 1 then rtp transmission will be muted when\n"
283                   "   audio is muted , otherwise rtp is always sent."}, 
284 #ifdef VIDEO_ENABLED
285         { "vwindow", lpc_cmd_video_window, "Control video display window",
286                 "'vwindow show': shows video window\n"
287                 "'vwindow hide': hides video window\n"
288                 "'vwindow pos <x> <y>': Moves video window to x,y pixel coordinates\n"
289                 "'vwindow size <width> <height>': Resizes video window\n"
290                 "'vwindow id <window id>': embeds video display into supplied window id."
291         },
292         { "pwindow", lpc_cmd_preview_window, "Control local camera video display (preview window)",
293                 "'pwindow show': shows the local camera video display\n"
294                 "'pwindow hide': hides the local camera video display\n"
295                 "'pwindow pos <x> <y>': Moves preview window to x,y pixel coordinates\n"
296                 "'pwindow size <width> <height>': Resizes preview window\n"
297                 "'pwindow id <window id>': embeds preview display into supplied window id.\n"
298                 "'pwindow integrated': integrate preview display within the video window of current call.\n"
299                 "'pwindow standalone': use standalone window for preview display."
300         },
301         { "snapshot", lpc_cmd_snapshot, "Take a snapshot of currently received video stream",
302                 "'snapshot <file path>': take a snapshot and records it in jpeg format into the supplied path\n"
303         },
304         { "vfureq", lpc_cmd_vfureq, "Request the other side to send VFU for the current call"},
305 #endif
306         { "states", lpc_cmd_states, "Show internal states of liblinphone, registrations and calls, according to linphonecore.h definitions",
307                 "'states global': shows global state of liblinphone \n"
308                 "'states calls': shows state of calls\n"
309                 "'states proxies': shows state of proxy configurations"
310         },
311         { "register", lpc_cmd_register, "Register in one line to a proxy" , "register <sip identity> <sip proxy> <password>"},
312         { "unregister", lpc_cmd_unregister, "Unregister from default proxy", NULL       },
313         { "status", lpc_cmd_status, "Print various status information", 
314                         "'status register'  \t: print status concerning registration\n"
315                         "'status autoanswer'\t: tell whether autoanswer mode is enabled\n"
316                         "'status hook'      \t: print hook status\n" },
317         { "ports", lpc_cmd_ports, "Network ports configuration", 
318                         "'ports'  \t: prints current used ports.\n"
319                         "'ports sip <port number>'\t: Sets the sip port.\n" },
320         { "param", lpc_cmd_param, "parameter set or read as normally given in .linphonerc",
321                         "'param <section> <parameter> [<value>]'  \t: reads [sets] given parameter.\n"
322                         "NOTES: - changes may become effective after (re)establishing a sip connection.\n"
323                         "       - upon exit, .linphonerc will reflect the updated state.\n" },
324         { "speak", lpc_cmd_speak, "Speak a sentence using espeak TTS engine",
325                         "This feature is available only in file mode. (see 'help soundcard')\n"
326                         "'speak <voice name> <sentence>'        : speak a text using the specified espeak voice.\n"
327                         "Example for english voice: 'speak default Hello my friend !'"
328         },
329         { "staticpic", lpc_cmd_staticpic, "Manage static pictures when nowebcam",
330                 "'staticpic set' : Set path to picture that should be used.\n"
331                 "'staticpic fps' : Get/set frames per seconds for picture emission.\n"
332         },
333         { "identify", lpc_cmd_identify, "Returns the user-agent string of far end",
334                 "'identify' \t: returns remote user-agent string for current call.\n"
335                 "'identify <id>' \t: returns remote user-agent string for call with supplied id.\n"
336         },
337         { "ringback", lpc_cmd_ringback, "Specifies a ringback tone to be played to remote end during incoming calls",
338                 "'ringback <path of mono .wav file>'\t: Specifies a ringback tone to be played to remote end during incoming calls\n"
339                 "'ringback disable'\t: Disable playing of ringback tone to callers\n"
340         },
341         { "redirect", lpc_cmd_redirect, "Redirect an incoming call",
342                 "'redirect <redirect-uri>'\t: Redirect all pending incoming calls to the <redirect-uri>\n"
343         },
344         {       NULL,NULL,NULL,NULL}
345 };
346
347
348
349 /***************************************************************************
350  *
351  *  Public interface 
352  *
353  ***************************************************************************/
354
355 /*
356  * Main command dispatcher.
357  * WARNING: modifies second argument!
358  *
359  * Always return 1 currently.
360  */
361 int
362 linphonec_parse_command_line(LinphoneCore *lc, char *cl)
363 {
364         char *ptr=cl;
365         char *args=NULL;
366         LPC_COMMAND *cmd;
367
368         /* Isolate first word and args */
369         while(*ptr && !isspace(*ptr)) ++ptr;
370         if (*ptr)
371         {
372                 *ptr='\0';
373                 /* set args to first nonblank */
374                 args=ptr+1;
375                 while(*args && isspace(*args)) ++args;
376         }
377
378         /* Handle DTMF */
379         if ( isdigit(*cl) || *cl == '#' || *cl == '*' )
380         {
381                 while ( isdigit(*cl) || *cl == '#' || *cl == '*' )
382                 {
383                         linphone_core_send_dtmf(lc, *cl);
384                         linphone_core_play_dtmf (lc,*cl,100);
385                         ms_sleep(1); // be nice
386                         ++cl;
387                 }
388
389                 // discard spurious trailing chars
390                 return 1;
391         }
392
393         /* Handle other kind of commands */
394         cmd=lpc_find_command(cl);
395         if ( !cmd )
396         {
397                 linphonec_out("'%s': Cannot understand this.\n", cl);
398                 return 1;
399         }
400
401         if ( ! cmd->func(lc, args) )
402         {
403                 linphonec_out("Syntax error.\n");
404                 linphonec_display_command_help(cmd);
405         }
406
407         return 1;
408 }
409
410 /*
411  * Generator function for command completion.
412  * STATE let us know whether to start from scratch;
413  * without any state (STATE==0), then we start at the
414  * top of the list.
415  */
416 char *
417 linphonec_command_generator(const char *text, int state)
418 {
419         static int index, len, adv;
420         char *name;
421
422         if ( ! state )
423         {
424                 index=0;
425                 adv=0;
426                 len=strlen(text);
427         }
428         /*
429          * Return the next name which partially matches
430          * from the commands list
431          */
432         if (adv==0){
433                 while ((name=commands[index].name))
434                 {
435                         ++index; /* so next call get next command */
436
437                         if (strncmp(name, text, len) == 0)
438                         {
439                                 return ortp_strdup(name);
440                         }
441                 }
442                 adv=1;
443                 index=0;
444         }
445         if (adv==1){
446                 while ((name=advanced_commands[index].name))
447                 {
448                         ++index; /* so next call get next command */
449
450                         if (strncmp(name, text, len) == 0)
451                         {
452                                 return ortp_strdup(name);
453                         }
454                 }
455         }
456         return NULL;
457 }
458
459
460 /***************************************************************************
461  *
462  *  Command handlers 
463  *
464  ***************************************************************************/
465
466 static int
467 lpc_cmd_help(LinphoneCore *lc, char *arg)
468 {
469         int i=0;
470         LPC_COMMAND *cmd;
471
472         if (!arg || !*arg)
473         {
474                 linphonec_out("Commands are:\n");
475                 linphonec_out("---------------------------\n");
476
477                 while (commands[i].help)
478                 {
479                         linphonec_out("%10.10s\t%s\n", commands[i].name,
480                                 commands[i].help);
481                         i++;
482                 }
483                 
484                 linphonec_out("---------------------------\n");
485                 linphonec_out("Type 'help <command>' for more details or\n");
486                 linphonec_out("     'help advanced' to list additional commands.\n");
487
488                 return 1;
489         }
490
491         if (strcmp(arg,"advanced")==0){
492                 linphonec_out("Advanced commands are:\n");
493                 linphonec_out("---------------------------\n");
494                 i=0;
495                 while (advanced_commands[i].help)
496                 {
497                         linphonec_out("%10.10s\t%s\n", advanced_commands[i].name,
498                                 advanced_commands[i].help);
499                         i++;
500                 }
501                 
502                 linphonec_out("---------------------------\n");
503                 linphonec_out("Type 'help <command>' for more details.\n");
504
505                 return 1;
506         }
507         
508         cmd=lpc_find_command(arg);
509         if ( !cmd )
510         {
511                 linphonec_out("No such command.\n");
512                 return 1;
513         }
514
515         linphonec_display_command_help(cmd);
516         return 1;
517
518 }
519
520 static char callee_name[256]={0};
521 static char caller_name[256]={0};
522
523 static const char *get_call_status(LinphoneCall *call){
524         switch(linphone_call_get_state(call)){
525                 case LinphoneCallPaused:
526                         if (linphone_call_get_refer_to (call)!=NULL){
527                                 return "Paused (transfered)";
528                         }else{
529                                 return "Paused";
530                         }
531                 break;
532                 case LinphoneCallPausedByRemote:
533                         return "Paused by remote";
534                 break;
535                 case LinphoneCallIncomingReceived:
536                         return "Pending";
537                 break;
538                 case LinphoneCallOutgoingInit:
539                 case LinphoneCallOutgoingProgress:
540                         return "Dialing out";
541                 break;
542                 case LinphoneCallOutgoingEarlyMedia:
543                 case LinphoneCallOutgoingRinging:
544                         return "Remote ringing";
545                 break;
546                 default:
547                         if (linphone_call_has_transfer_pending(call)){
548                                 return "Running (transfer pending)";
549                         }else
550                                 return "Running";
551         }
552         return "";
553 }
554
555 static int
556 lpc_cmd_call(LinphoneCore *lc, char *args)
557 {
558         if ( ! args || ! *args )
559         {
560                 return 0;
561         }
562         {
563                 LinphoneCall *call;
564                 LinphoneCallParams *cp=linphone_core_create_default_call_parameters (lc);
565                 char *opt1,*opt2;
566                 if ( linphone_core_in_call(lc) )
567                 {
568                         linphonec_out("Terminate or hold on the current call first.\n");
569                         return 1;
570                 }
571                 opt1=strstr(args,"--audio-only");
572                 opt2=strstr(args,"--early-media");
573                 if (opt1){
574                         opt1[0]='\0';
575                         linphone_call_params_enable_video (cp,FALSE);
576                 }
577                 if (opt2){
578                         opt2[0]='\0';
579                         linphone_call_params_enable_early_media_sending(cp,TRUE);
580                 }
581                 if ( NULL == (call=linphone_core_invite_with_params(lc, args,cp)) )
582                 {
583                         linphonec_out("Error from linphone_core_invite.\n");
584                 }
585                 else
586                 {
587                         snprintf(callee_name,sizeof(callee_name),"%s",args);
588                 }
589                 linphone_call_params_destroy(cp);
590         }
591         return 1;
592 }
593
594 static int 
595 lpc_cmd_calls(LinphoneCore *lc, char *args){
596         const MSList *calls = linphone_core_get_calls(lc);
597         if(calls)
598         {
599                 const MSList *p_calls = calls;
600                 linphonec_out("ID\t\tDestination\t\t\t\tStatus\n---------------------------------------------------------------------\n");
601                 while(p_calls != NULL)                  
602                 {
603                         LinphoneCall *call=(LinphoneCall*)p_calls->data;
604                         char *tmp=linphone_call_get_remote_address_as_string(call);
605                         linphonec_out("%li\t%s\t\t\t%s\r\n",
606                                                   (long)linphone_call_get_user_pointer (call),
607                                         tmp,
608                                         get_call_status(call));
609                         p_calls = p_calls->next;
610                         ms_free(tmp);
611                 }
612         }else
613         {
614                 linphonec_out("No active call.\n");
615         }
616         return 1;
617 }
618
619
620 static int
621 lpc_cmd_chat(LinphoneCore *lc, char *args)
622 {
623         char *arg1 = args;
624         char *arg2 = NULL;
625         char *ptr = args;
626
627         if (!args) return 0;
628
629         /* Isolate first and second arg */
630         while(*ptr && !isspace(*ptr)) ++ptr;
631         if ( *ptr )
632         {
633                 *ptr='\0';
634                 arg2=ptr+1;
635                 while(*arg2 && isspace(*arg2)) ++arg2;
636         }
637         else
638         {
639                 /* missing one parameter */
640                 return 0;
641         }
642         LinphoneChatRoom *cr = linphone_core_create_chat_room(lc,arg1);
643         linphone_chat_room_send_message(cr,arg2);
644         linphone_chat_room_destroy(cr);
645
646         return 1;
647 }
648
649 const char *linphonec_get_callee(){
650         return callee_name;
651 }
652
653 const char *linphonec_get_caller(){
654         return caller_name;
655 }
656
657 void linphonec_set_caller(const char *caller){
658         snprintf(caller_name,sizeof(caller_name)-1,"%s",caller);
659 }
660
661 static int
662 lpc_cmd_transfer(LinphoneCore *lc, char *args)
663 {
664         if (args){
665                 LinphoneCall *call;
666                 LinphoneCall *call2;
667                 const char *refer_to=NULL;
668                 char arg1[256]={0};
669                 char arg2[266]={0};
670                 long id2=0;
671                 int n=sscanf(args,"%s %s %li",arg1,arg2,&id2);
672                 if (n==1 || isalpha(*arg1)){
673                         call=linphone_core_get_current_call(lc);
674                         if (call==NULL && ms_list_size(linphone_core_get_calls(lc))==1){
675                                 call=(LinphoneCall*)linphone_core_get_calls(lc)->data;
676                         }
677                         refer_to=args;
678                         if (call==NULL){
679                                 linphonec_out("No active call, please specify a call id among the ones listed by 'calls' command.\n");
680                                 return 0;
681                         }
682                         linphone_core_transfer_call(lc, call, refer_to);
683                 }else if (n==2){
684                         long id=atoi(arg1);
685                         refer_to=args+strlen(arg1)+1;
686                         call=linphonec_get_call(id);
687                         if (call==NULL) return 0;
688                         linphone_core_transfer_call(lc, call, refer_to);
689                 }else if (n==3){
690                         long id=atoi(arg1);
691                         call=linphonec_get_call(id);
692                         call2=linphonec_get_call(id2);
693                         if (call==NULL || call2==NULL) return 0;
694                         if (strcmp(arg2,"--to-call")!=0){
695                                 return 0;
696                         }
697                         linphonec_out("Performing attended transfer of call %i to call %i",id,id2);
698                         linphone_core_transfer_call_to_another (lc,call,call2);
699                 }else return 0;
700         }else{
701                 linphonec_out("Transfer command requires at least one argument\n");
702                 return 0;
703         }
704         return 1;
705 }
706
707 static int
708 lpc_cmd_terminate(LinphoneCore *lc, char *args)
709 {
710         if (linphone_core_get_calls(lc)==NULL){
711                 linphonec_out("No active calls\n");
712                 return 1;
713         }
714         if (!args)
715         {
716                 if ( -1 == linphone_core_terminate_call(lc, NULL) ){
717                         linphonec_out("Could not stop the active call.\n");
718                 }
719                 return 1;
720         }
721         
722         if(strcmp(args,"all")==0){
723                 linphonec_out("We are going to stop all the calls.\n");
724                 linphone_core_terminate_all_calls(lc);
725                 return 1;
726         }else{
727                 /*the argument is a linphonec call id */
728                 long id=atoi(args);
729                 LinphoneCall *call=linphonec_get_call(id);
730                 if (call){
731                         if (linphone_core_terminate_call(lc,call)==-1){
732                                 linphonec_out("Could not stop the call with id %li\n",id);
733                         }
734                 }else return 0;
735                 return 1;
736         }
737         return 0;
738         
739 }
740
741 static int
742 lpc_cmd_redirect(LinphoneCore *lc, char *args){
743         const MSList *elem;
744         int didit=0;
745         if (!args) return 0;
746         if ((elem=linphone_core_get_calls(lc))==NULL){
747                 linphonec_out("No active calls.\n");
748                 return 1;
749         }
750         while(elem!=NULL){
751                 LinphoneCall *call=(LinphoneCall*)elem->data;
752                 if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
753                         linphone_core_redirect_call(lc,call,args);
754                         didit=1;
755                         /*as the redirection closes the call, we need to re-check the call list that is invalidated.*/
756                         elem=linphone_core_get_calls(lc);
757                 }else elem=elem->next;
758         }
759         if (didit==0){
760                 linphonec_out("There is no pending incoming call to redirect.");
761         }
762         return 1;
763 }
764
765 static int
766 lpc_cmd_answer(LinphoneCore *lc, char *args){
767         if (!args)
768         {
769                 int nb=ms_list_size(linphone_core_get_calls(lc));
770                 if (nb==1){
771                         //if just one call is present answer the only one in passing NULL to the linphone_core_accept_call ...
772                         if ( -1 == linphone_core_accept_call(lc, NULL) )
773                         {
774                                 linphonec_out("Fail to accept incoming call\n");
775                         }
776                 }else if (nb==0){
777                         linphonec_out("There are no calls to answer.\n");
778                 }else{
779                         linphonec_out("Multiple calls in progress, please specify call id.\n");
780                         return 0;
781                 }
782                 return 1;
783         }else{
784                 long id;
785                 if (sscanf(args,"%li",&id)==1){
786                         LinphoneCall *call=linphonec_get_call (id);
787                         if (linphone_core_accept_call (lc,call)==-1){
788                                 linphonec_out("Fail to accept call %i\n",id);
789                         }
790                 }else return 0;
791                 return 1;
792         }
793         return 0;
794 }
795
796 static int
797 lpc_cmd_autoanswer(LinphoneCore *lc, char *args)
798 {
799         if ( ! args )
800         {
801                 if ( linphonec_get_autoanswer() ) {
802                         linphonec_out("Auto answer is enabled. Use 'autoanswer disable' to disable.\n");
803                 } else {
804                         linphonec_out("Auto answer is disabled. Use 'autoanswer enable' to enable.\n");
805                 }
806                 return 1;
807         }
808
809         if (strstr(args,"enable")){
810                 linphonec_set_autoanswer(TRUE);
811                 linphonec_out("Auto answer enabled.\n");
812         }else if (strstr(args,"disable")){
813                 linphonec_set_autoanswer(FALSE);
814                 linphonec_out("Auto answer disabled.\n");
815         }else return 0;
816         return 1;
817 }
818
819 static int
820 lpc_cmd_quit(LinphoneCore *lc, char *args)
821 {
822         linphonec_main_loop_exit();
823         return 1;
824 }
825
826 static int
827 lpc_cmd_nat(LinphoneCore *lc, char *args)
828 {
829         bool_t use;
830         const char *nat;
831
832         if ( args ) args=lpc_strip_blanks(args);
833
834         if ( args && *args )
835         {
836                 linphone_core_set_nat_address(lc, args);
837                 /* linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_NAT_ADDRESS); */
838         }
839
840         nat = linphone_core_get_nat_address(lc);
841         use = linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress;
842         linphonec_out("Nat address: %s%s\n", nat ? nat : "unspecified" , use ? "" : " (disabled - use 'firewall nat' to enable)");
843
844         return 1;
845 }
846
847 static int
848 lpc_cmd_stun(LinphoneCore *lc, char *args)
849 {
850         bool_t use;
851         const char *stun;
852
853         if ( args ) args=lpc_strip_blanks(args);
854
855         if ( args && *args )
856         {
857                 linphone_core_set_stun_server(lc, args);
858                 /* linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_STUN); */
859         }
860
861         stun = linphone_core_get_stun_server(lc);
862         use = linphone_core_get_firewall_policy(lc)==LinphonePolicyUseStun;
863         linphonec_out("Stun server: %s%s\n", stun ? stun : "unspecified" , use? "" : " (disabled - use 'firewall stun' to enable)");
864
865         return 1;
866 }
867
868 static int
869 lpc_cmd_firewall(LinphoneCore *lc, char *args)
870 {
871         const char* setting=NULL;
872
873         if ( args ) args=lpc_strip_blanks(args);
874
875         if ( args && *args )
876         {
877                 if (strcmp(args,"none")==0)
878                 {
879                         linphone_core_set_firewall_policy(lc,LinphonePolicyNoFirewall);
880                 }
881                 else if (strcmp(args,"stun")==0)
882                 {
883                         setting = linphone_core_get_stun_server(lc);
884                         if ( ! setting )
885                         {
886                                 linphonec_out("No stun server address is defined, use 'stun <address>' first\n");
887                                 return 1;
888                         }
889                         linphone_core_set_firewall_policy(lc,LinphonePolicyUseStun);
890                 }
891                 else if (strcmp(args,"nat")==0)
892                 {
893                         setting = linphone_core_get_nat_address(lc);
894                         if ( ! setting )
895                         {
896                                 linphonec_out("No nat address is defined, use 'nat <address>' first");
897                                 return 1;
898                         }
899                         linphone_core_set_firewall_policy(lc,LinphonePolicyUseNatAddress);
900                 }
901         }
902
903         switch(linphone_core_get_firewall_policy(lc))
904         {
905                 case LinphonePolicyNoFirewall:
906                         linphonec_out("No firewall\n");
907                         break;
908                 case LinphonePolicyUseStun:
909                         linphonec_out("Using stun server %s to discover firewall address\n", setting ? setting : linphone_core_get_stun_server(lc));
910                         break;
911                 case LinphonePolicyUseNatAddress:
912                         linphonec_out("Using supplied nat address %s.\n", setting ? setting : linphone_core_get_nat_address(lc));
913                         break;
914         }
915         return 1;
916 }
917
918 #ifndef WIN32
919 /* Helper function for processing freind names */
920 static int
921 lpc_friend_name(char **args, char **name)
922 {
923         /* Use space as a terminator unless quoted */
924         if (('"' == **args) || ('\'' == **args)){
925                 char *end;
926                 char delim = **args;
927                 (*args)++;
928                 end = (*args);
929                 while ((delim != *end) && ('\0' != *end)) end++;
930                 if ('\0' == *end) {
931                         fprintf(stderr, "Mismatched quotes\n");
932                         return 0;
933                 }
934                 *name = *args;
935                 *end = '\0';
936                 *args = ++end;
937         } else {
938                 *name = strsep(args, " ");
939                 
940                 if (NULL == *args) { /* Means there was no separator */
941                         fprintf(stderr, "Either name or address is missing\n");
942                         return 0;
943                 }
944                 if (NULL == *name) return 0;
945         }
946         return 1;
947 }
948 #endif
949
950 static int
951 lpc_cmd_friend(LinphoneCore *lc, char *args)
952 {
953         int friend_num;
954
955         if ( args ) args=lpc_strip_blanks(args);
956
957         if ( ! args || ! *args ) return 0;
958
959         if ( !strncmp(args, "list", 4) )
960         {
961                 return linphonec_friend_list(lc, args+4);
962                 return 1;
963         }
964         else if ( !strncmp(args, "call", 4) )
965         {
966                 args+=4;
967                 if ( ! *args ) return 0;
968                 friend_num = strtol(args, NULL, 10);
969 #ifndef _WIN32_WCE              
970                 if ( errno == ERANGE ) {
971                         linphonec_out("Invalid friend number\n");
972                         return 0;
973                 }
974 #endif /*_WIN32_WCE*/
975                 linphonec_friend_call(lc, friend_num);
976                 return 1;
977         }
978         else if ( !strncmp(args, "delete", 6) )
979         {
980                 args+=6;
981                 if ( ! *args ) return 0;
982                 while (*args == ' ') args++;
983                 if ( ! *args ) return 0;
984                 if (!strncmp(args, "all", 3))
985                 {
986                         friend_num = -1;
987                 } 
988                 else
989                 {
990                         friend_num = strtol(args, NULL, 10);
991 #ifndef _WIN32_WCE              
992                         if ( errno == ERANGE ) {
993                                 linphonec_out("Invalid friend number\n");
994                                 return 0;
995                         }
996 #endif /*_WIN32_WCE*/
997                 }
998                 linphonec_friend_delete(lc, friend_num);
999                 return 1;
1000         }
1001         else if ( !strncmp(args, "add", 3) )
1002         {
1003 #ifndef WIN32
1004                 char  *name;
1005                 char  addr[80];
1006                 char *addr_p = addr;
1007                 char *addr_orig;
1008
1009                 args+=3;
1010                 if ( ! *args ) return 0;
1011                 while (*args == ' ') args++;
1012                 if ( ! *args ) return 0;
1013
1014                 if (!lpc_friend_name(&args,  &name)) return 0;
1015
1016                 while (*args == ' ') args++;
1017                 if ( ! *args ) return 0;
1018                 if (isdigit(*args)) {
1019                         strcpy (addr, "sip:");
1020                         addr_p = addr + strlen("sip:");
1021                 }
1022                 addr_orig = strsep(&args, " ");
1023                 if (1 >= strlen(addr_orig)) {
1024                         fprintf(stderr, "A single-digit address is not valid\n");
1025                         return 0;
1026                 }
1027                 strcpy(addr_p, addr_orig);
1028                 linphonec_friend_add(lc, name, addr);
1029 #else
1030                 LinphoneFriend *new_friend;
1031                 new_friend = linphone_friend_new_with_addr(args);
1032                 linphone_core_add_friend(lc, new_friend);
1033 #endif
1034                 return 1;
1035         }
1036         return 0;
1037 }
1038
1039 static int lpc_cmd_play(LinphoneCore *lc, char *args){
1040         if ( args ) args=lpc_strip_blanks(args);
1041         if ( ! args || ! *args ) return 0;
1042         linphone_core_set_play_file(lc,args);
1043         return 1;
1044 }
1045
1046 static int lpc_cmd_record(LinphoneCore *lc, char *args){
1047         if ( args ) args=lpc_strip_blanks(args);
1048         if ( ! args || ! *args ) return 0;
1049         linphone_core_set_record_file(lc,args);
1050         return 1;
1051 }
1052
1053 /*
1054  * Modified input
1055  */
1056 static int
1057 lpc_cmd_proxy(LinphoneCore *lc, char *args)
1058 {
1059         char *arg1 = args;
1060         char *arg2 = NULL;
1061         char *ptr = args;
1062         int proxynum;
1063
1064         if ( ! arg1 ) return 0;
1065
1066         /* Isolate first and second arg */
1067         while(*ptr && !isspace(*ptr)) ++ptr;
1068         if ( *ptr )
1069         {
1070                 *ptr='\0';
1071                 arg2=ptr+1;
1072                 while(*arg2 && isspace(*arg2)) ++arg2;
1073         }
1074
1075         if (strcmp(arg1,"add")==0)
1076         {
1077 #ifdef HAVE_READLINE
1078                 rl_inhibit_completion=1;
1079 #endif
1080                 linphonec_proxy_add(lc);
1081 #ifdef HAVE_READLINE
1082                 rl_inhibit_completion=0;
1083 #endif
1084         }
1085         else if (strcmp(arg1,"list")==0)
1086         {
1087                 linphonec_proxy_list(lc);
1088         }
1089         else if (strcmp(arg1,"remove")==0)
1090         {
1091                 linphonec_proxy_remove(lc,atoi(arg2));
1092         }
1093         else if (strcmp(arg1,"use")==0)
1094         {
1095                 if ( arg2 && *arg2 )
1096                 {
1097                         proxynum=atoi(arg2);
1098                         if ( linphonec_proxy_use(lc, proxynum) )
1099                                 linphonec_out("Default proxy set to %d.\n", proxynum);
1100                 }
1101                 else
1102                 {
1103                         proxynum=linphone_core_get_default_proxy(lc, NULL);
1104                         if ( proxynum == -1 ) linphonec_out("No default proxy.\n");
1105                         else linphonec_out("Current default proxy is %d.\n", proxynum);
1106                 }
1107         }else if (strcmp(arg1, "unuse")==0){
1108                 linphone_core_set_default_proxy(lc, NULL);
1109                 linphonec_out("Use no proxy.\n");
1110         }
1111
1112         else if (strcmp(arg1, "show")==0)
1113         {
1114                 if (arg2 && *arg2)
1115                 {
1116                         if (strstr(arg2,"default"))
1117                         {
1118                 proxynum=linphone_core_get_default_proxy(lc, NULL);
1119                 if ( proxynum < 0 ) {
1120                         linphonec_out("No default proxy defined\n");
1121                         return 1;
1122                 }
1123                 linphonec_proxy_show(lc,proxynum);
1124                         }
1125                         else
1126                         {
1127                 linphonec_proxy_show(lc, atoi(arg2));
1128                         }
1129                 }
1130                 else return 0; /* syntax error */
1131         }
1132
1133         else
1134         {
1135                 return 0; /* syntax error */
1136         }
1137
1138         return 1;
1139 }
1140
1141 static int
1142 lpc_cmd_call_logs(LinphoneCore *lc, char *args)
1143 {
1144         const MSList *elem=linphone_core_get_call_logs(lc);
1145         for (;elem!=NULL;elem=ms_list_next(elem))
1146         {
1147                 LinphoneCallLog *cl=(LinphoneCallLog*)elem->data;
1148                 char *str=linphone_call_log_to_str(cl);
1149                 linphonec_out("%s\n",str);
1150                 ms_free(str);
1151         }
1152         return 1;
1153 }
1154
1155 static int
1156 lpc_cmd_ipv6(LinphoneCore *lc, char *arg1)
1157 {
1158         if ( ! arg1 )
1159         {
1160                 return 0; /* syntax error */
1161         }
1162
1163         if (strcmp(arg1,"status")==0)
1164         {
1165                 linphonec_out("ipv6 use enabled: %s\n",linphone_core_ipv6_enabled(lc) ? "true":"false");
1166         }
1167         else if (strcmp(arg1,"enable")==0)
1168         {
1169                 linphone_core_enable_ipv6(lc,TRUE);
1170                 linphonec_out("ipv6 use enabled.\n");
1171         }
1172         else if (strcmp(arg1,"disable")==0)
1173         {
1174                 linphone_core_enable_ipv6(lc,FALSE);
1175                 linphonec_out("ipv6 use disabled.\n");
1176         }
1177         else
1178         {
1179                 return 0; /* syntax error */
1180         }
1181         return 1;
1182 }
1183
1184 static int devname_to_index(LinphoneCore *lc, const char *devname){
1185         const char **p;
1186         int i;
1187         for(i=0,p=linphone_core_get_sound_devices(lc);*p!=NULL;++p,++i){
1188                 if (strcmp(devname,*p)==0) return i;
1189         }
1190         return -1;
1191 }
1192
1193 static const char *index_to_devname(LinphoneCore *lc, int index){
1194         const char **p;
1195         int i;
1196         for(i=0,p=linphone_core_get_sound_devices(lc);*p!=NULL;++p,++i){
1197                 if (i==index) return *p;
1198         }
1199         return NULL;
1200 }
1201
1202 static int lpc_cmd_soundcard(LinphoneCore *lc, char *args)
1203 {
1204         int i, index;
1205         const char **dev;
1206         char *arg1 = args;
1207         char *arg2 = NULL;
1208         char *ptr = args;
1209
1210         if (!args) return 0; /* syntax error */
1211
1212         /* Isolate first and second arg */
1213         while(*ptr && !isspace(*ptr)) ++ptr;
1214         if ( *ptr )
1215         {
1216                 *ptr='\0';
1217                 arg2=ptr+1;
1218                 while(*arg2 && isspace(*arg2)) ++arg2;
1219         }
1220
1221         if (strcmp(arg1, "list")==0)
1222         {
1223                 dev=linphone_core_get_sound_devices(lc);
1224                 for(i=0; dev[i]!=NULL; ++i){
1225                         linphonec_out("%i: %s\n",i,dev[i]);
1226                 }
1227                 return 1;
1228         }
1229
1230         if (strcmp(arg1, "show")==0)
1231         {
1232                 linphonec_out("Ringer device: %s\n",
1233                         linphone_core_get_ringer_device(lc));
1234                 linphonec_out("Playback device: %s\n",
1235                         linphone_core_get_playback_device(lc));
1236                 linphonec_out("Capture device: %s\n",
1237                         linphone_core_get_capture_device(lc));
1238                 return 1;
1239         }
1240
1241         if (strcmp(arg1, "use")==0 && arg2)
1242         {
1243                 if (strcmp(arg2, "files")==0)
1244                 {
1245                         linphonec_out("Using wav files instead of soundcard.\n");
1246                         linphone_core_use_files(lc,TRUE);
1247                         return 1;
1248                 }
1249
1250                 dev=linphone_core_get_sound_devices(lc);
1251                 index=atoi(arg2); /* FIXME: handle not-a-number */
1252                 for(i=0;dev[i]!=NULL;i++)
1253                 {
1254                         if (i!=index) continue;
1255
1256                         linphone_core_set_ringer_device(lc,dev[i]);
1257                         linphone_core_set_playback_device(lc,dev[i]);
1258                         linphone_core_set_capture_device(lc,dev[i]);
1259                         linphonec_out("Using sound device %s\n",dev[i]);
1260                         return 1;
1261                 }
1262                 linphonec_out("No such sound device\n");
1263                 return 1;
1264         }
1265         if (strcmp(arg1, "capture")==0)
1266         {
1267                 const char *devname=linphone_core_get_capture_device(lc);
1268                 if (!arg2){
1269                         linphonec_out("Using capture device #%i (%s)\n",
1270                                         devname_to_index(lc,devname),devname);
1271                 }else{
1272                         index=atoi(arg2); /* FIXME: handle not-a-number */
1273                         devname=index_to_devname(lc,index);
1274                         if (devname!=NULL){
1275                                 linphone_core_set_capture_device(lc,devname);
1276                                 linphonec_out("Using capture sound device %s\n",devname);
1277                                 return 1;
1278                         }
1279                         linphonec_out("No such sound device\n");
1280                 }
1281                 return 1;
1282         }
1283         if (strcmp(arg1, "playback")==0)
1284         {
1285                 const char *devname=linphone_core_get_playback_device(lc);
1286                 if (!arg2){
1287                         linphonec_out("Using playback device #%i (%s)\n",
1288                                         devname_to_index(lc,devname),devname);
1289                 }else{
1290                         index=atoi(arg2); /* FIXME: handle not-a-number */
1291                         devname=index_to_devname(lc,index);
1292                         if (devname!=NULL){
1293                                 linphone_core_set_playback_device(lc,devname);
1294                                 linphonec_out("Using playback sound device %s\n",devname);
1295                                 return 1;
1296                         }
1297                         linphonec_out("No such sound device\n");
1298                 }
1299                 return 1;
1300         }
1301         if (strcmp(arg1, "ring")==0)
1302         {
1303                 const char *devname=linphone_core_get_ringer_device(lc);
1304                 if (!arg2){
1305                         linphonec_out("Using ring device #%i (%s)\n",
1306                                         devname_to_index(lc,devname),devname);
1307                 }else{
1308                         index=atoi(arg2); /* FIXME: handle not-a-number */
1309                         devname=index_to_devname(lc,index);
1310                         if (devname!=NULL){
1311                                 linphone_core_set_ringer_device(lc,devname);
1312                                 linphonec_out("Using ring sound device %s\n",devname);
1313                                 return 1;
1314                         }
1315                         linphonec_out("No such sound device\n");
1316                 }
1317                 return 1;
1318         }
1319         return 0; /* syntax error */
1320 }
1321
1322 static int lpc_cmd_webcam(LinphoneCore *lc, char *args)
1323 {
1324         int i, index;
1325         const char **dev;
1326         char *arg1 = args;
1327         char *arg2 = NULL;
1328         char *ptr = args;
1329
1330         if (!args) return 0; /* syntax error */
1331
1332         /* Isolate first and second arg */
1333         while(*ptr && !isspace(*ptr)) ++ptr;
1334         if ( *ptr )
1335         {
1336                 *ptr='\0';
1337                 arg2=ptr+1;
1338                 while(*arg2 && isspace(*arg2)) ++arg2;
1339         }
1340
1341         if (strcmp(arg1, "list")==0)
1342         {
1343                 dev=linphone_core_get_video_devices(lc);
1344                 for(i=0; dev[i]!=NULL; ++i){
1345                         linphonec_out("%i: %s\n",i,dev[i]);
1346                 }
1347                 return 1;
1348         }
1349
1350         if (strcmp(arg1, "use")==0 && arg2)
1351         {
1352                 dev=linphone_core_get_video_devices(lc);
1353                 index=atoi(arg2); /* FIXME: handle not-a-number */
1354                 for(i=0;dev[i]!=NULL;i++)
1355                 {
1356                         if (i!=index) continue;
1357
1358                         linphone_core_set_video_device(lc, dev[i]);
1359                         linphonec_out("Using video device %s\n",dev[i]);
1360                         return 1;
1361                 }
1362                 linphonec_out("No such video device\n");
1363                 return 1;
1364         }
1365         return 0; /* syntax error */
1366 }
1367
1368 static int
1369 lpc_cmd_staticpic(LinphoneCore *lc, char *args)
1370 {
1371         char *arg1 = args;
1372         char *arg2 = NULL;
1373         char *ptr = args;
1374
1375         if (!args) return 0;  /* Syntax error */
1376
1377         /* Isolate first and second arg */
1378         while(*ptr && !isspace(*ptr)) ++ptr;
1379         if ( *ptr )
1380         {
1381                 *ptr='\0';
1382                 arg2=ptr+1;
1383                 while(*arg2 && isspace(*arg2)) ++arg2;
1384         }
1385
1386         if (strcmp(arg1, "set")==0 && arg2) {
1387                 linphone_core_set_static_picture(lc, arg2);
1388                 return 1;
1389         }
1390
1391         if (strcmp(arg1, "fps")==0) {
1392           if (arg2) {
1393                 float fps = atof(arg2); /* FIXME: Handle not-a-float */
1394                 linphone_core_set_static_picture_fps(lc, fps);
1395                 return 1;
1396           } else {
1397                 float fps;
1398                 fps = linphone_core_get_static_picture_fps(lc);
1399                 linphonec_out("Current FPS %f\n", fps);
1400                 return 1;
1401           }
1402         }
1403
1404         return 0; /* Syntax error */
1405 }
1406
1407 static int lpc_cmd_pause(LinphoneCore *lc, char *args){
1408
1409         if(linphone_core_in_call(lc))
1410         {
1411                 linphone_core_pause_call(lc,linphone_core_get_current_call(lc));
1412                 return 1;
1413         }
1414         linphonec_out("you can only pause when a call is in process\n");
1415     return 0;
1416 }
1417
1418 static int lpc_cmd_resume(LinphoneCore *lc, char *args){
1419         
1420         if(linphone_core_in_call(lc))
1421         {
1422                 linphonec_out("There is already a call in process pause or stop it first");
1423                 return 1;
1424         }
1425         if (args)
1426         {
1427                 long id;
1428                 int n = sscanf(args, "%li", &id);
1429                 if (n == 1){
1430                         LinphoneCall *call=linphonec_get_call (id);
1431                         if (call){
1432                                 if(linphone_core_resume_call(lc,call)==-1){
1433                                         linphonec_out("There was a problem to resume the call check the remote address you gave %s\n",args);
1434                                 }
1435                         }
1436                         return 1;
1437                 }else return 0;
1438         }
1439         else
1440         {
1441                 const MSList *calls = linphone_core_get_calls(lc);
1442                 int nbcalls=ms_list_size(calls);
1443                 if( nbcalls == 1)
1444                 {
1445                         if(linphone_core_resume_call(lc,calls->data) < 0)
1446                         {
1447                                 linphonec_out("There was a problem to resume the unique call.\n");
1448                         }
1449                         return 1;
1450                 }else if (nbcalls==0){
1451                         linphonec_out("There is no calls at this time.\n");
1452                         return 1;
1453                 }else{
1454                         linphonec_out("There are %i calls at this time, please specify call id as given with 'calls' command.\n");
1455                 }
1456         }
1457         return 0;
1458     
1459 }
1460
1461 /***************************************************************************
1462  *
1463  *  Commands helper functions
1464  *
1465  ***************************************************************************/
1466
1467
1468 static void
1469 linphonec_proxy_add(LinphoneCore *lc)
1470 {
1471         bool_t enable_register=FALSE;
1472         LinphoneProxyConfig *cfg;
1473
1474         linphonec_out("Adding new proxy setup. Hit ^D to abort.\n");
1475
1476         /*
1477          * SIP Proxy address
1478          */
1479         while (1)
1480         {
1481                 char *input=linphonec_readline("Enter proxy sip address: ");
1482                 char *clean;
1483
1484                 if ( ! input ) {
1485                         linphonec_out("Aborted.\n");
1486                         return;
1487                 }
1488
1489                 /* Strip blanks */
1490                 clean=lpc_strip_blanks(input);
1491                 if ( ! *clean ) {
1492                         free(input);
1493                         continue;
1494                 }
1495
1496                 cfg=linphone_proxy_config_new();
1497                 if (linphone_proxy_config_set_server_addr(cfg,clean)<0)
1498                 {
1499                         linphonec_out("Invalid sip address (sip:sip.domain.tld).\n");
1500                         free(input);
1501                         linphone_proxy_config_destroy(cfg);
1502                         continue;
1503                 }
1504                 free(input);
1505                 break;
1506         }
1507
1508         /*
1509          * SIP Proxy identity
1510          */
1511         while (1)
1512         {
1513                 char *input=linphonec_readline("Your identity for this proxy: ");
1514                 char *clean;
1515
1516                 if ( ! input ) {
1517                         linphonec_out("Aborted.\n");
1518                         linphone_proxy_config_destroy(cfg);
1519                         return;
1520                 }
1521
1522                 /* Strip blanks */
1523                 clean=lpc_strip_blanks(input);
1524                 if ( ! *clean ) {
1525                         free(input);
1526                         continue;
1527                 }
1528
1529                 linphone_proxy_config_set_identity(cfg, clean);
1530                 if ( ! linphone_proxy_config_get_identity (cfg))
1531                 {
1532                         linphonec_out("Invalid identity (sip:name@sip.domain.tld).\n");
1533                         free(input);
1534                         continue;
1535                 }
1536                 free(input);
1537                 break;
1538         }
1539
1540         /*
1541          * SIP Proxy enable register
1542          */
1543         while (1)
1544         {
1545                 char *input=linphonec_readline("Do you want to register on this proxy (yes/no): ");
1546                 char *clean;
1547
1548                 if ( ! input ) {
1549                         linphonec_out("Aborted.\n");
1550                         linphone_proxy_config_destroy(cfg);
1551                         return;
1552                 }
1553
1554                 /* Strip blanks */
1555                 clean=lpc_strip_blanks(input);
1556                 if ( ! *clean ) {
1557                         free(input);
1558                         continue;
1559                 }
1560
1561                 if ( ! strcmp(clean, "yes") ) enable_register=TRUE;
1562                 else if ( ! strcmp(clean, "no") ) enable_register=FALSE;
1563                 else {
1564                         linphonec_out("Please answer with 'yes' or 'no'\n");
1565                         free(input);
1566                         continue;
1567                 }
1568                 linphone_proxy_config_enableregister(cfg, enable_register);
1569                 free(input);
1570                 break;
1571         }
1572
1573         /*
1574          * SIP Proxy registration expiration
1575          */
1576         if ( enable_register==TRUE )
1577         {
1578                 long int expires=0;
1579                 while (1)
1580                 {
1581                         char *input=linphonec_readline("Specify register expiration time"
1582                                 " in seconds (default is 600): ");
1583
1584                         if ( ! input ) {
1585                                 linphonec_out("Aborted.\n");
1586                                 linphone_proxy_config_destroy(cfg);
1587                                 return;
1588                         }
1589
1590                         expires=strtol(input, (char **)NULL, 10);
1591                         if ( expires == LONG_MIN || expires == LONG_MAX )
1592                         {
1593                                 linphonec_out("Invalid value: %s\n", strerror(errno));
1594                                 free(input);
1595                                 continue;
1596                         }
1597
1598                         linphone_proxy_config_expires(cfg, expires);
1599                         linphonec_out("Expiration: %d seconds\n", linphone_proxy_config_get_expires (cfg));
1600
1601                         free(input);
1602                         break;
1603                 }
1604         }
1605
1606         /*
1607          * SIP proxy route
1608          */
1609         while (1)
1610         {
1611                 char *input=linphonec_readline("Specify route if needed: ");
1612                 char *clean;
1613
1614                 if ( ! input ) {
1615                         linphonec_out("Aborted.\n");
1616                         linphone_proxy_config_destroy(cfg);
1617                         return;
1618                 }
1619
1620                 /* Strip blanks */
1621                 clean=lpc_strip_blanks(input);
1622                 if ( ! *clean ) {
1623                         free(input);
1624                         linphonec_out("No route specified.\n");
1625                         break;
1626                 }
1627
1628                 linphone_proxy_config_set_route(cfg, clean);
1629                 if ( ! linphone_proxy_config_get_route(cfg) )
1630                 {
1631                         linphonec_out("Invalid route.\n");
1632                         free(input);
1633                         continue;
1634                 }
1635
1636                 free(input);
1637                 break;
1638         }
1639
1640         /*
1641          * Final confirmation 
1642          */
1643         while (1)
1644         {
1645                 char *input;
1646                 char *clean;
1647
1648                 linphonec_out("--------------------------------------------\n");
1649                 linphonec_proxy_display(cfg);
1650                 linphonec_out("--------------------------------------------\n");
1651                 input=linphonec_readline("Accept the above proxy configuration (yes/no) ?: ");
1652
1653
1654                 if ( ! input ) {
1655                         linphonec_out("Aborted.\n");
1656                         linphone_proxy_config_destroy(cfg);
1657                         return;
1658                 }
1659
1660                 /* Strip blanks */
1661                 clean=lpc_strip_blanks(input);
1662                 if ( ! *clean ) {
1663                         free(input);
1664                         continue;
1665                 }
1666
1667                 if ( ! strcmp(clean, "yes") ) break;
1668                 else if ( ! strcmp(clean, "no") )
1669                 {
1670                         linphonec_out("Declined.\n");
1671                         linphone_proxy_config_destroy(cfg);
1672                         free(input);
1673                         return;
1674                 }
1675
1676                 linphonec_out("Please answer with 'yes' or 'no'\n");
1677                 free(input);
1678                 continue;
1679         }
1680
1681
1682         linphone_core_add_proxy_config(lc,cfg);
1683
1684         /* automatically set the last entered proxy as the default one */
1685         linphone_core_set_default_proxy(lc,cfg);
1686
1687         linphonec_out("Proxy added.\n");
1688 }
1689
1690 static void
1691 linphonec_proxy_display(LinphoneProxyConfig *cfg)
1692 {
1693         const char *route=linphone_proxy_config_get_route(cfg);
1694         const char *identity=linphone_proxy_config_get_identity(cfg);
1695         linphonec_out("sip address: %s\nroute: %s\nidentity: %s\nregister: %s\nexpires: %i\nregistered: %s\n",
1696                         linphone_proxy_config_get_addr(cfg),
1697                         (route!=NULL)? route:"",
1698                         (identity!=NULL)?identity:"",
1699                         linphone_proxy_config_register_enabled (cfg)?"yes":"no",
1700                         linphone_proxy_config_get_expires (cfg),
1701                         linphone_proxy_config_is_registered(cfg) ? "yes" : "no");
1702 }
1703
1704 static void linphonec_proxy_show(LinphoneCore *lc, int index)
1705 {
1706         const MSList *elem;
1707         int i;
1708         for(elem=linphone_core_get_proxy_config_list(lc),i=0;elem!=NULL;elem=elem->next,++i){
1709                 if (index==i){
1710                         LinphoneProxyConfig *cfg=(LinphoneProxyConfig *)elem->data;
1711                         linphonec_proxy_display(cfg);
1712                         return;
1713                 }
1714         }
1715         linphonec_out("No proxy with index %i\n", index);
1716 }
1717
1718 static void
1719 linphonec_proxy_list(LinphoneCore *lc)
1720 {
1721         const MSList *proxies;
1722         int n;
1723         int def=linphone_core_get_default_proxy(lc,NULL);
1724         
1725         proxies=linphone_core_get_proxy_config_list(lc);
1726         for(n=0;proxies!=NULL;proxies=ms_list_next(proxies),n++){
1727                 if (n==def)
1728                         linphonec_out("****** Proxy %i - this is the default one - *******\n",n);
1729                 else 
1730                         linphonec_out("****** Proxy %i *******\n",n);
1731                 linphonec_proxy_display((LinphoneProxyConfig*)proxies->data);
1732         }
1733         if ( ! n ) linphonec_out("No proxies defined\n");
1734 }
1735
1736 static void
1737 linphonec_proxy_remove(LinphoneCore *lc, int index)
1738 {
1739         const MSList *proxies;
1740         LinphoneProxyConfig *cfg;
1741         proxies=linphone_core_get_proxy_config_list(lc);
1742         cfg=(LinphoneProxyConfig*)ms_list_nth_data(proxies,index);
1743         if (cfg==NULL){
1744                 linphonec_out("No such proxy.\n");
1745                 return;
1746         }
1747         linphone_core_remove_proxy_config(lc,cfg);
1748         linphonec_out("Proxy %s removed.\n", linphone_proxy_config_get_addr(cfg));
1749 }
1750
1751 static int
1752 linphonec_proxy_use(LinphoneCore *lc, int index)
1753 {
1754         const MSList *proxies;
1755         LinphoneProxyConfig *cfg;
1756         proxies=linphone_core_get_proxy_config_list(lc);
1757         cfg=(LinphoneProxyConfig*)ms_list_nth_data(proxies,index);
1758         if (cfg==NULL){
1759                 linphonec_out("No such proxy (try 'proxy list').");
1760                 return 0;
1761         }
1762         linphone_core_set_default_proxy(lc,cfg);
1763         return 1;
1764 }
1765
1766 static void
1767 linphonec_friend_display(LinphoneFriend *fr)
1768 {
1769         LinphoneAddress *uri=linphone_address_clone(linphone_friend_get_address(fr));
1770         char *str;
1771         
1772         linphonec_out("name: %s\n", linphone_address_get_display_name(uri));
1773         linphone_address_set_display_name(uri,NULL);
1774         str=linphone_address_as_string(uri);
1775         linphonec_out("address: %s\n", str);
1776 }
1777
1778 static int
1779 linphonec_friend_list(LinphoneCore *lc, char *pat)
1780 {
1781         const MSList *friend;
1782         int n;
1783
1784         if (pat) {
1785                 pat=lpc_strip_blanks(pat);
1786                 if (!*pat) pat = NULL;
1787         }
1788
1789         friend = linphone_core_get_friend_list(lc);
1790         for(n=0; friend!=NULL; friend=ms_list_next(friend), ++n )
1791         {
1792                 if ( pat ) {
1793                         const char *name = linphone_address_get_display_name(
1794                             linphone_friend_get_address((LinphoneFriend*)friend->data));
1795                         if (name && ! strstr(name, pat) ) continue;
1796                 }
1797                 linphonec_out("****** Friend %i *******\n",n);
1798                 linphonec_friend_display((LinphoneFriend*)friend->data);
1799         }
1800
1801         return 1;
1802 }
1803
1804 static int
1805 linphonec_friend_call(LinphoneCore *lc, unsigned int num)
1806 {
1807         const MSList *friend = linphone_core_get_friend_list(lc);
1808         unsigned int n;
1809         char *addr;
1810
1811         for(n=0; friend!=NULL; friend=ms_list_next(friend), ++n )
1812         {
1813                 if ( n == num )
1814                 {
1815                         int ret;
1816                         addr = linphone_address_as_string(linphone_friend_get_address((LinphoneFriend*)friend->data));
1817                         ret=lpc_cmd_call(lc, addr);
1818                         ms_free(addr);
1819                         return ret;
1820                 }
1821         }
1822         linphonec_out("No such friend %u\n", num);
1823         return 1;
1824 }
1825
1826 #ifndef WIN32
1827 static int
1828 linphonec_friend_add(LinphoneCore *lc, const char *name, const char *addr)
1829 {
1830         LinphoneFriend *newFriend;
1831
1832         char url[PATH_MAX];
1833
1834         snprintf(url, PATH_MAX, "%s <%s>", name, addr);
1835         newFriend = linphone_friend_new_with_addr(url);
1836         linphone_core_add_friend(lc, newFriend);
1837         return 0;
1838 }
1839 #endif
1840
1841 static int
1842 linphonec_friend_delete(LinphoneCore *lc, int num)
1843 {
1844         const MSList *friend = linphone_core_get_friend_list(lc);
1845         unsigned int n;
1846
1847         for(n=0; friend!=NULL; friend=ms_list_next(friend), ++n )
1848         {
1849                 if ( n == num )
1850                 {
1851                         linphone_core_remove_friend(lc, friend->data);
1852                         return 0;
1853                 }
1854         }
1855
1856         if (-1 == num) 
1857         {
1858                 unsigned int i;
1859                 for (i = 0 ; i < n ; i++)
1860                         linphonec_friend_delete(lc, 0);
1861                 return 0;
1862         }
1863
1864         linphonec_out("No such friend %u\n", num);
1865         return 1;
1866 }
1867
1868 static void
1869 linphonec_display_command_help(LPC_COMMAND *cmd)
1870 {
1871         if ( cmd->doc ) linphonec_out ("%s\n", cmd->doc);
1872         else linphonec_out("%s\n", cmd->help);
1873 }
1874
1875
1876 static int lpc_cmd_register(LinphoneCore *lc, char *args){
1877         char identity[512];
1878         char proxy[512];
1879         char passwd[512];
1880         LinphoneProxyConfig *cfg;
1881         const MSList *elem;
1882     
1883         if (!args)
1884         {
1885                 /* it means that you want to register the default proxy */
1886                 LinphoneProxyConfig *cfg=NULL;
1887                 linphone_core_get_default_proxy(lc,&cfg);
1888                 if (cfg)
1889                 {
1890                         if(!linphone_proxy_config_is_registered(cfg)) {
1891                                 linphone_proxy_config_enable_register(cfg,TRUE);
1892                                 linphone_proxy_config_done(cfg);
1893                         }else{
1894                                 linphonec_out("default proxy already registered\n");
1895                         }
1896                 }else{
1897                         linphonec_out("we do not have a default proxy\n");
1898                         return 0;
1899                 }
1900                 return 1;
1901         }
1902         passwd[0]=proxy[0]=identity[0]='\0';
1903         sscanf(args,"%s %s %s",identity,proxy,passwd);
1904         if (proxy[0]=='\0' || identity[0]=='\0'){
1905                 linphonec_out("Missing parameters, see help register\n");
1906                 return 1;
1907         }
1908         if (passwd[0]!='\0'){
1909                 LinphoneAddress *from;
1910                 LinphoneAuthInfo *info;
1911                 if ((from=linphone_address_new(identity))!=NULL){
1912                         char realm[128];
1913                         snprintf(realm,sizeof(realm)-1,"\"%s\"",linphone_address_get_domain(from));
1914                         info=linphone_auth_info_new(linphone_address_get_username(from),NULL,passwd,NULL,NULL);
1915                         linphone_core_add_auth_info(lc,info);
1916                         linphone_address_destroy(from);
1917                         linphone_auth_info_destroy(info);
1918                 }
1919         }
1920         elem=linphone_core_get_proxy_config_list(lc);
1921         if (elem) {
1922                 cfg=(LinphoneProxyConfig*)elem->data;
1923                 linphone_proxy_config_edit(cfg);
1924         }
1925         else cfg=linphone_proxy_config_new();
1926         linphone_proxy_config_set_identity(cfg,identity);
1927         linphone_proxy_config_set_server_addr(cfg,proxy);
1928         linphone_proxy_config_enable_register(cfg,TRUE);
1929         if (elem) linphone_proxy_config_done(cfg);
1930         else linphone_core_add_proxy_config(lc,cfg);
1931         linphone_core_set_default_proxy(lc,cfg);
1932         return 1;
1933 }
1934
1935 static int lpc_cmd_unregister(LinphoneCore *lc, char *args){
1936         LinphoneProxyConfig *cfg=NULL;
1937         linphone_core_get_default_proxy(lc,&cfg);
1938         if (cfg && linphone_proxy_config_is_registered(cfg)) {
1939                 linphone_proxy_config_edit(cfg);
1940                 linphone_proxy_config_enable_register(cfg,FALSE);
1941                 linphone_proxy_config_done(cfg);
1942         }else{
1943                 linphonec_out("unregistered\n");
1944         }
1945         return 1;
1946 }
1947
1948 static int lpc_cmd_duration(LinphoneCore *lc, char *args){
1949         LinphoneCallLog *cl;
1950         const MSList *elem=linphone_core_get_call_logs(lc);
1951         for(;elem!=NULL;elem=elem->next){
1952                 if (elem->next==NULL){
1953                         cl=(LinphoneCallLog*)elem->data;
1954                         linphonec_out("%i seconds\n",cl->duration);
1955                 }
1956         }
1957         return 1;
1958 }
1959
1960 static int lpc_cmd_status(LinphoneCore *lc, char *args)
1961 {
1962         LinphoneProxyConfig *cfg;
1963         
1964         if ( ! args ) return 0;
1965         linphone_core_get_default_proxy(lc,&cfg);
1966         if (strstr(args,"register"))
1967         {
1968                 if (cfg)
1969                 {
1970                         if (linphone_proxy_config_is_registered(cfg)){
1971                                 linphonec_out("registered, identity=%s duration=%i\n",
1972                                         linphone_proxy_config_get_identity(cfg),
1973                                         linphone_proxy_config_get_expires(cfg));
1974                         }else if (linphone_proxy_config_register_enabled(cfg)){
1975                                 linphonec_out("registered=-1\n");
1976                         }else linphonec_out("registered=0\n");
1977                 }
1978                 else linphonec_out("registered=0\n");
1979         }
1980         else if (strstr(args,"autoanswer"))
1981         {
1982                 if (cfg && linphone_proxy_config_is_registered(cfg))
1983                         linphonec_out("autoanswer=%i\n",linphonec_get_autoanswer());
1984                 else linphonec_out("unregistered\n");
1985         }
1986         else if (strstr(args,"hook"))
1987         {
1988                 LinphoneCall *call=linphone_core_get_current_call (lc);
1989                 LinphoneCallState call_state=LinphoneCallIdle;
1990                 if (call) call_state=linphone_call_get_state(call);
1991
1992                 switch(call_state){
1993                         case LinphoneCallOutgoingInit:
1994                                 linphonec_out("hook=outgoing_init sip:%s\n",linphonec_get_callee());
1995                         break;
1996                         case LinphoneCallOutgoingProgress:
1997                                 linphonec_out("hook=dialing sip:%s\n",linphonec_get_callee());
1998                         break;
1999                         case LinphoneCallOutgoingRinging:
2000                                 linphonec_out("hook=ringing sip:%s\n",linphonec_get_callee());
2001                         break;
2002                         case LinphoneCallPaused:
2003                                 linphonec_out("hook=paused sip:%s\n",linphonec_get_callee());
2004                         break;
2005                         case LinphoneCallIdle:
2006                                 linphonec_out("hook=offhook\n");
2007                         break;
2008                         case LinphoneCallStreamsRunning:
2009                         case LinphoneCallConnected:
2010                                 if (linphone_call_get_dir(call)==LinphoneCallOutgoing){
2011                                         linphonec_out("Call out, hook=%s duration=%i, muted=%s rtp-xmit-muted=%s\n", linphonec_get_callee(),
2012                                               linphone_core_get_current_call_duration(lc),
2013                                               linphone_core_is_mic_muted (lc) ? "yes" : "no",
2014                                               linphone_core_is_rtp_muted(lc) ? "yes"  : "no");
2015                                 }else{
2016                                         linphonec_out("hook=answered duration=%i %s\n" ,
2017                                                 linphone_core_get_current_call_duration(lc), linphonec_get_caller());
2018                                 }
2019                                 break;
2020                         case LinphoneCallIncomingReceived:
2021                                 linphonec_out("Incoming call from %s\n",linphonec_get_caller());
2022                                 break;
2023                         default:
2024                                 break;
2025                 }
2026                 
2027         }
2028         else return 0;
2029
2030         return 1;
2031 }
2032
2033 static int lpc_cmd_ports(LinphoneCore *lc, char *args)
2034 {
2035         int port;
2036         if ( ! args ){
2037                 linphonec_out("sip port = %i\naudio rtp port = %i\nvideo rtp port = %i\n",
2038                         linphone_core_get_sip_port(lc),
2039                         linphone_core_get_audio_port(lc),
2040                         linphone_core_get_video_port(lc));
2041                 return 1;
2042         }
2043         if (sscanf(args,"sip %i",&port)==1){
2044                 linphonec_out("Setting sip port to %i\n",port);
2045                 linphone_core_set_sip_port(lc,port);
2046         }else return 0;
2047
2048         return 1;
2049 }
2050
2051 static int lpc_cmd_param(LinphoneCore *lc, char *args)
2052 {
2053         char section[20], param[20], value[50];
2054         const char *string;
2055
2056         if (args == NULL) {
2057                 return 0;
2058         }
2059         switch (sscanf(args,"%s %s %s",section,param,value)) {
2060                 // case 1 might show all current settings under a section
2061                 case 2:
2062                         string = lp_config_get_string(linphone_core_get_config(lc), section, param, "(undef)");
2063                         linphonec_out("current value: %s\n", string);
2064                         break;
2065                 case 3:
2066                         if (lp_config_get_string(linphone_core_get_config(lc), section, param, NULL) != NULL) {
2067                                 lp_config_set_string(linphone_core_get_config(lc), section, param, value);
2068                         // no indication of existence
2069                                 linphonec_out("updated value: %s\n", value);
2070                         } else {
2071                                 linphonec_out("only update of existing variables are allowed\n");
2072                         }
2073                         break;
2074                 default:
2075                         return 0;
2076     }
2077         return 1;
2078 }
2079
2080 static int lpc_cmd_speak(LinphoneCore *lc, char *args){
2081 #ifndef WIN32
2082         char voice[64];
2083         char *sentence;
2084         char cl[128];
2085         char *wavfile;
2086         int status;
2087         FILE *file;
2088         
2089     if (!args) return 0;
2090         memset(voice,0,sizeof(voice));
2091         sscanf(args,"%s63",voice);
2092         sentence=args+strlen(voice);
2093         wavfile=tempnam("/tmp/","linphonec-espeak-");
2094         snprintf(cl,sizeof(cl),"espeak -v %s -s 100 -w %s --stdin",voice,wavfile);
2095         file=popen(cl,"w");
2096         if (file==NULL){
2097                 ms_error("Could not open pipe to espeak !");
2098                 return 1;
2099         }
2100         fprintf(file,"%s",sentence);
2101         status=pclose(file);
2102         if (WEXITSTATUS(status)==0){
2103                 linphone_core_set_play_file(lc,wavfile);
2104         }else{
2105                 linphonec_out("espeak command failed.");
2106         }
2107 #else
2108         linphonec_out("Sorry, this command is not implemented in windows version.");
2109 #endif
2110         return 1;
2111 }
2112
2113 static int lpc_cmd_acodec(LinphoneCore *lc, char *args){
2114     return lpc_cmd_codec(AUDIO, lc, args);
2115 }
2116
2117 static int lpc_cmd_vcodec(LinphoneCore *lc, char *args){
2118     return lpc_cmd_codec(VIDEO, lc, args);
2119 }
2120
2121 static int lpc_cmd_codec(int type, LinphoneCore *lc, char *args){
2122         char *arg1 = args;
2123         char *arg2 = NULL;
2124         char *ptr = args;
2125
2126         if (!args) return 0;
2127
2128         /* Isolate first and second arg */
2129         while(*ptr && !isspace(*ptr)) ++ptr;
2130         if ( *ptr )
2131         {
2132                 *ptr='\0';
2133                 arg2=ptr+1;
2134                 while(*arg2 && isspace(*arg2)) ++arg2;
2135         }
2136
2137         if (strcmp(arg1,"enable")==0)
2138         {
2139 #ifdef HAVE_READLINE
2140                 rl_inhibit_completion=1;
2141 #endif
2142         if (!strcmp(arg2,"all")) linphonec_codec_enable(type,lc,-1);
2143         else linphonec_codec_enable(type,lc,atoi(arg2));
2144 #ifdef HAVE_READLINE
2145                 rl_inhibit_completion=0;
2146 #endif
2147         }
2148         else if (strcmp(arg1,"list")==0)
2149         {
2150                 linphonec_codec_list(type,lc);
2151         }
2152         else if (strcmp(arg1,"disable")==0)
2153         {
2154         if (!strcmp(arg2,"all")) linphonec_codec_disable(type,lc,-1);
2155         else linphonec_codec_disable(type,lc,atoi(arg2));
2156         }
2157         else
2158         {
2159                 return 0; /* syntax error */
2160         }
2161
2162         return 1;
2163 }
2164
2165 static void linphonec_codec_list(int type, LinphoneCore *lc){
2166         PayloadType *pt;
2167         int index=0;
2168         const MSList *node=NULL;
2169
2170     if (type == AUDIO) {
2171       node=linphone_core_get_audio_codecs(lc);
2172     } else if(type==VIDEO) {
2173       node=linphone_core_get_video_codecs(lc);
2174     }
2175
2176         for(;node!=NULL;node=ms_list_next(node)){
2177                 pt=(PayloadType*)(node->data);
2178         linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate, 
2179                     linphone_core_payload_type_enabled(lc,pt) ? "enabled" : "disabled");
2180                 index++;
2181         }
2182 }
2183
2184 static void linphonec_codec_enable(int type, LinphoneCore *lc, int sel_index){
2185         PayloadType *pt;
2186         int index=0;
2187         const MSList *node=NULL;
2188
2189         if (type == AUDIO) {
2190                 node=linphone_core_get_audio_codecs(lc);
2191         } else if(type==VIDEO) {
2192                 node=linphone_core_get_video_codecs(lc);
2193         }
2194
2195     for(;node!=NULL;node=ms_list_next(node)){
2196         if (index == sel_index || sel_index == -1) {
2197                     pt=(PayloadType*)(node->data);
2198             linphone_core_enable_payload_type (lc,pt,TRUE);
2199             linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate, "enabled");
2200         }
2201                 index++;
2202         }
2203 }
2204
2205 static void linphonec_codec_disable(int type, LinphoneCore *lc, int sel_index){
2206         PayloadType *pt;
2207         int index=0;
2208         const MSList *node=NULL;
2209
2210         if (type == AUDIO) {
2211                 node=linphone_core_get_audio_codecs(lc);
2212         } else if(type==VIDEO) {
2213                 node=linphone_core_get_video_codecs(lc);
2214         }
2215
2216         for(;node!=NULL;node=ms_list_next(node)){
2217                 if (index == sel_index || sel_index == -1) {
2218                         pt=(PayloadType*)(node->data);
2219                         linphone_core_enable_payload_type (lc,pt,FALSE);
2220                         linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate, "disabled");
2221                 }
2222                 index++;
2223         }
2224 }
2225
2226 static int lpc_cmd_echocancellation(LinphoneCore *lc, char *args){
2227         char *arg1 = args;
2228         char *arg2 = NULL;
2229         char *ptr = args;
2230         LpConfig *config=linphone_core_get_config(lc);
2231
2232         if (!args) return 0;
2233
2234         /* Isolate first and second arg */
2235         while(*ptr && !isspace(*ptr)) ++ptr;
2236         if ( *ptr )
2237         {
2238                 *ptr='\0';
2239                 arg2=ptr+1;
2240                 while(*arg2 && isspace(*arg2)) ++arg2;
2241         }
2242
2243         if (strcmp(arg1,"on")==0){
2244         int delay, tail_len, frame_size;
2245         int n;
2246
2247         linphone_core_enable_echo_cancellation(lc,1);
2248
2249         if (arg2 != 0) {
2250             n = sscanf(arg2, "%d %d %d", &delay, &tail_len, &frame_size);
2251
2252             if (n == 1) {   
2253                 lp_config_set_int(config,"sound","ec_delay",delay);
2254             }
2255             else if (n == 2) {
2256                 lp_config_set_int(config,"sound","ec_delay",delay);
2257                 lp_config_set_int(config,"sound","ec_tail_len",tail_len);
2258             }
2259             else if (n == 3) {
2260                 lp_config_set_int(config,"sound","ec_delay",delay);
2261                 lp_config_set_int(config,"sound","ec_tail_len",tail_len);
2262                 lp_config_set_int(config,"sound","ec_framesize",frame_size);
2263             }
2264         }
2265     }
2266     else if (strcmp(arg1,"off")==0){
2267         linphone_core_enable_echo_cancellation(lc,0);
2268     }
2269     else if (strcmp(arg1,"show")==0){
2270         linphonec_out("echo cancellation is %s; delay %d, tail length %d, frame size %d\n", 
2271             linphone_core_echo_cancellation_enabled(lc) ? "on" : "off",
2272             lp_config_get_int(config,"sound","ec_delay",0),
2273             lp_config_get_int(config,"sound","ec_tail_len",0),
2274             lp_config_get_int(config,"sound","ec_framesize",0));        
2275     }
2276     else {
2277         return 0;
2278     }
2279
2280     return 1;
2281 }
2282
2283 static int lpc_cmd_echolimiter(LinphoneCore *lc, char *args){
2284         if (args){
2285                 if (strcmp(args,"on")==0){
2286                         linphone_core_enable_echo_limiter (lc,TRUE);
2287                 }else if (strcmp(args,"off")==0){
2288                         linphone_core_enable_echo_limiter (lc,FALSE);
2289                 }
2290         }
2291         linphonec_out("Echo limiter is now %s.\n",linphone_core_echo_limiter_enabled (lc) ? "on":"off");
2292         return 1;
2293 }
2294
2295 static int lpc_cmd_mute_mic(LinphoneCore *lc, char *args)
2296 {
2297         linphone_core_mute_mic(lc, 1);
2298         return 1;
2299 }
2300
2301 static int lpc_cmd_unmute_mic(LinphoneCore *lc, char *args){
2302         linphone_core_mute_mic(lc, 0);
2303         return 1;
2304 }
2305
2306 static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args)
2307 {
2308         bool_t rtp_xmit_off=FALSE;
2309         char *status;
2310
2311         if(args){
2312                 if(strstr(args,"1"))rtp_xmit_off=TRUE;
2313                 if(linphone_core_get_current_call (lc)==NULL)
2314                         linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_xmit_off);
2315                 else 
2316                         linphonec_out("nortp-on-audio-mute: call in progress - cannot change state\n");
2317         }
2318         rtp_xmit_off=linphone_core_get_rtp_no_xmit_on_audio_mute(lc);
2319         if (rtp_xmit_off) status="off";
2320         else status="on";
2321         linphonec_out("rtp transmit %s when audio muted\n",status);
2322         return 1;
2323 }
2324
2325 #ifdef VIDEO_ENABLED
2326 static int _lpc_cmd_video_window(LinphoneCore *lc, char *args, bool_t is_preview){
2327         char subcommand[64];
2328         int a,b;
2329         int err;
2330         VideoParams *params=is_preview ? &lpc_preview_params : &lpc_video_params;
2331
2332         if (!args) return 0;
2333         err=sscanf(args,"%s %i %i",subcommand,&a,&b);
2334         if (err>=1){
2335                 if (strcmp(subcommand,"pos")==0){
2336                         if (err<3) return 0;
2337                         params->x=a;
2338                         params->y=b;
2339                         params->refresh=TRUE;
2340                 }else if (strcmp(subcommand,"size")==0){
2341                         if (err<3) return 0;
2342                         params->w=a;
2343                         params->h=b;
2344                         params->refresh=TRUE;
2345                 }else if (strcmp(subcommand,"show")==0){
2346                         params->show=TRUE;
2347                         params->refresh=TRUE;
2348                         if (is_preview) linphone_core_enable_video_preview (lc,TRUE);
2349                 }else if (strcmp(subcommand,"hide")==0){
2350                         params->show=FALSE;
2351                         params->refresh=TRUE;
2352                         if (is_preview) linphone_core_enable_video_preview (lc,FALSE);
2353                 }else if (strcmp(subcommand,"id")==0){
2354                         if (err == 1){
2355                                 linphonec_out("vwindow id: 0x%x\n",is_preview ? linphone_core_get_native_preview_window_id (lc) :
2356                                               linphone_core_get_native_video_window_id (lc));
2357                                 return 1;
2358                         } else if (err != 2) return 0;
2359                         params->wid=a;
2360                         if (is_preview)
2361                                 linphone_core_set_native_preview_window_id (lc,a);
2362                         else
2363                                 linphone_core_set_native_video_window_id(lc,a);
2364                 }else if (is_preview==TRUE){
2365                         if (strcmp(subcommand,"integrated")==0){
2366                                 linphone_core_use_preview_window (lc,FALSE);
2367                         }else if (strcmp(subcommand,"standalone")==0){
2368                                 linphone_core_use_preview_window(lc,TRUE);
2369                         }else return 0;
2370                 }else return 0;
2371         }
2372         return 1;
2373 }
2374
2375 static int lpc_cmd_video_window(LinphoneCore *lc, char *args){
2376         return _lpc_cmd_video_window(lc, args, FALSE);
2377 }
2378
2379 static int lpc_cmd_preview_window(LinphoneCore *lc, char *args){
2380         return _lpc_cmd_video_window(lc, args, TRUE);
2381 }
2382 #endif
2383
2384 static void lpc_display_global_state(LinphoneCore *lc){
2385         linphonec_out("Global liblinphone state\n%s\n",
2386                       linphone_global_state_to_string(linphone_core_get_global_state(lc)));
2387 }
2388
2389 static void lpc_display_call_states(LinphoneCore *lc){
2390         LinphoneCall *call;
2391         const MSList *elem;
2392         char *tmp;
2393         linphonec_out("Call states\n"
2394                       "Id |            Destination              |      State\n"
2395                       "---------------------------------------------------------------\n");
2396         elem=linphone_core_get_calls(lc);
2397         if (elem==NULL){
2398                 linphonec_out("(empty)\n");
2399         }else{
2400                 for(;elem!=NULL;elem=elem->next){
2401                         call=(LinphoneCall*)elem->data;
2402                         tmp=linphone_call_get_remote_address_as_string (call);
2403                         linphonec_out("%-2i | %-35s | %s\n",(int)(long)linphone_call_get_user_pointer(call),
2404                                                   tmp,linphone_call_state_to_string(linphone_call_get_state(call)));
2405                         ms_free(tmp);
2406                 }
2407         }
2408 }
2409
2410 static void lpc_display_proxy_states(LinphoneCore *lc){
2411         const MSList *elem;
2412         linphonec_out("Proxy registration states\n"
2413                       "           Identity                      |      State\n"
2414                       "------------------------------------------------------------\n");
2415         elem=linphone_core_get_proxy_config_list (lc);
2416         if (elem==NULL) linphonec_out("(empty)\n");
2417         else {
2418                 for(;elem!=NULL;elem=elem->next){
2419                         LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
2420                         linphonec_out("%-40s | %s\n",linphone_proxy_config_get_identity (cfg),
2421                                                   linphone_registration_state_to_string(linphone_proxy_config_get_state(cfg)));
2422                 }
2423         }
2424 }
2425
2426 static int lpc_cmd_states(LinphoneCore *lc, char *args){
2427         if (args==NULL) {
2428                 lpc_display_global_state(lc);
2429                 lpc_display_call_states(lc);
2430                 lpc_display_proxy_states(lc);
2431                 return 1;
2432         }
2433         if (strcmp(args,"global")==0){
2434                 lpc_display_global_state(lc);
2435                 return 1;
2436         }
2437         if (strcmp(args,"proxies")==0){
2438                 lpc_display_proxy_states(lc);
2439                 return 1;
2440         }
2441         if (strcmp(args,"calls")==0){
2442                 lpc_display_call_states(lc);
2443                 return 1;
2444         }
2445         return 0;
2446 }
2447
2448 #ifdef VIDEO_ENABLED
2449 static int lpc_cmd_camera(LinphoneCore *lc, char *args){
2450         LinphoneCall *call=linphone_core_get_current_call(lc);
2451         bool_t activated=FALSE;
2452         
2453         if (linphone_core_video_enabled (lc)==FALSE){
2454                 linphonec_out("Video is disabled, re-run linphonec with -V option.");
2455                 return 1;
2456         }
2457
2458         if (args){
2459                 if (strcmp(args,"on")==0)
2460                         activated=TRUE;
2461                 else if (strcmp(args,"off")==0)
2462                         activated=FALSE;
2463                 else
2464                         return 0;
2465         }
2466
2467         if (call==NULL){
2468                 if (args){
2469                         linphonec_camera_enabled=activated;
2470                 }
2471                 if (linphonec_camera_enabled){
2472                         linphonec_out("Camera is enabled. Video stream will be setup immediately for outgoing and incoming calls.\n");
2473                 }else{
2474                         linphonec_out("Camera is disabled. Calls will be established with audio-only, with the possibility to later add video using 'camera on'.\n");
2475                 }
2476         }else{
2477                 const LinphoneCallParams *cp=linphone_call_get_current_params (call);
2478                 if (args){
2479                         linphone_call_enable_camera(call,activated);
2480                         if ((activated && !linphone_call_params_video_enabled (cp))){
2481                                 /*update the call to add the video stream*/
2482                                 LinphoneCallParams *ncp=linphone_call_params_copy(cp);
2483                                 linphone_call_params_enable_video(ncp,TRUE);
2484                                 linphone_core_update_call(lc,call,ncp);
2485                                 linphone_call_params_destroy (ncp);
2486                                 linphonec_out("Trying to bring up video stream...\n");
2487                         }
2488                 }
2489                 if (linphone_call_camera_enabled (call))
2490                                 linphonec_out("Camera is allowed for current call.\n");
2491                 else linphonec_out("Camera is dis-allowed for current call.\n");
2492         }
2493         return 1;
2494 }
2495
2496 static int lpc_cmd_snapshot(LinphoneCore *lc, char *args){
2497         LinphoneCall *call;
2498         if (!args) return 0;
2499         call=linphone_core_get_current_call(lc);
2500         if (call!=NULL){
2501                 linphone_call_take_video_snapshot(call,args);
2502                 linphonec_out("Taking video snapshot in file %s\n", args);
2503         }else linphonec_out("There is no active call.\n");
2504         return 1;
2505 }
2506
2507 static int lpc_cmd_vfureq(LinphoneCore *lc, char *arg){
2508         LinphoneCall *call;
2509         call=linphone_core_get_current_call(lc);
2510         if (call!=NULL){
2511                 linphone_call_send_vfu_request(call);
2512                 linphonec_out("VFU request sent\n");
2513         }else linphonec_out("There is no active call.\n");
2514         return 1;
2515 }
2516 #endif
2517
2518 static int lpc_cmd_identify(LinphoneCore *lc, char *args){
2519         LinphoneCall *call;
2520         const char *remote_ua;
2521         if (args==NULL){
2522                 call=linphone_core_get_current_call(lc);
2523                 if (call==NULL) {
2524                         linphonec_out("There is currently running call. Specify call id.\n");
2525                         return 0;
2526                 }
2527         }else{
2528                 call=linphonec_get_call(atoi(args));
2529                 if (call==NULL){
2530                         return 0;
2531                 }
2532         }
2533         remote_ua=linphone_call_get_remote_user_agent(call);
2534         if (remote_ua){
2535                 linphonec_out("Remote user agent string is: %s\n",remote_ua);
2536         }
2537         return 1;
2538 }
2539
2540 static int lpc_cmd_ringback(LinphoneCore *lc, char *args){
2541         if (!args) return 0;
2542         if (strcmp(args,"disable")==0){
2543                 linphone_core_set_remote_ringback_tone(lc,NULL);
2544                 linphonec_out("Disabling ringback tone.\n");
2545                 return 1;
2546         }
2547         linphone_core_set_remote_ringback_tone (lc,args);
2548         linphonec_out("Using %s as ringback tone to be played to callers.",args);
2549         return 1;
2550 }
2551
2552 /***************************************************************************
2553  *
2554  *  Command table management funx
2555  *
2556  ***************************************************************************/
2557
2558 /*
2559  * Find a command given its name
2560  */
2561 static LPC_COMMAND *
2562 lpc_find_command(const char *name)
2563 {
2564         int i;
2565
2566         for (i=0; commands[i].name; ++i)
2567         {
2568                 if (strcmp(name, commands[i].name) == 0)
2569                         return &commands[i];
2570         }
2571
2572         for (i=0; advanced_commands[i].name; ++i)
2573         {
2574                 if (strcmp(name, advanced_commands[i].name) == 0)
2575                         return &advanced_commands[i];
2576         }
2577
2578         return (LPC_COMMAND *)NULL;
2579 }
2580
2581
2582 /****************************************************************************
2583  *
2584  * $Log: commands.c,v $
2585  * Revision 1.39  2008/07/03 15:08:34  smorlat
2586  * api cleanups, interface in progress.
2587  *
2588  * Revision 1.38  2008/06/17 20:38:59  smorlat
2589  * added missing file.
2590  *
2591  * Revision 1.37  2008/04/09 09:26:00  smorlat
2592  * merge various patches
2593  * H264 support.
2594  *
2595  * Revision 1.36  2007/08/01 14:47:53  strk
2596  *         * console/commands.c: Clean up commands 'nat', 'stun'
2597  *           and 'firewall' to be more intuitive.
2598  *
2599  * Revision 1.35  2007/06/27 09:01:25  smorlat
2600  * logging improvements.
2601  *
2602  * Revision 1.34  2007/02/20 10:17:13  smorlat
2603  * linphonec friends patch2
2604  *
2605  * Revision 1.31  2006/09/22 07:22:47  smorlat
2606  * linphonecore api changes.
2607  *
2608  * Revision 1.30  2006/09/08 15:32:57  smorlat
2609  * support for using files instead of soundcard (used by linphonec only)
2610  *
2611  * Revision 1.29  2006/08/28 14:29:07  smorlat
2612  * fix bug.
2613  *
2614  * Revision 1.28  2006/08/21 12:49:59  smorlat
2615  * merged several little patches.
2616  *
2617  * Revision 1.27  2006/07/17 18:45:00  smorlat
2618  * support for several event queues in ortp.
2619  * glib dependency removed from coreapi/ and console/
2620  *
2621  * Revision 1.26  2006/04/14 15:16:36  smorlat
2622  * soundcard use did nothing !
2623  *
2624  * Revision 1.25  2006/04/06 20:09:33  smorlat
2625  * add linphonec command to see and select sound devices.
2626  *
2627  * Revision 1.24  2006/03/04 11:17:10  smorlat
2628  * mediastreamer2 in progress.
2629  *
2630  * Revision 1.23  2006/02/20 21:14:01  strk
2631  * Handled syntax errors with 'friend' command
2632  *
2633  * Revision 1.22  2006/02/20 10:20:29  strk
2634  * Added substring-based filter support for command 'friend list'
2635  *
2636  * Revision 1.21  2006/02/02 15:39:18  strk
2637  * - Added 'friend list' and 'friend call' commands
2638  * - Allowed for multiple DTFM send in a single line
2639  * - Added status-specific callback (bare version)
2640  *
2641  * Revision 1.20  2006/01/26 11:54:34  strk
2642  * More robust 'nat' command handler (strip blanks in args)
2643  *
2644  * Revision 1.19  2006/01/26 09:48:05  strk
2645  * Added limits.h include
2646  *
2647  * Revision 1.18  2006/01/26 02:18:05  strk
2648  * Added new commands 'nat use' and 'nat unuse'.
2649  * These will required a pending patch to linphonecore.c
2650  * in order to work.
2651  *
2652  * Revision 1.17  2006/01/20 14:12:33  strk
2653  * Added linphonec_init() and linphonec_finish() functions.
2654  * Handled SIGINT and SIGTERM to invoke linphonec_finish().
2655  * Handling of auto-termination (-t) moved to linphonec_finish().
2656  * Reworked main (input read) loop to not rely on 'terminate'
2657  * and 'run' variable (dropped). configfile_name allocated on stack
2658  * using PATH_MAX limit. Changed print_usage signature to allow
2659  * for an exit_status specification.
2660  *
2661  * Revision 1.16  2006/01/18 09:25:32  strk
2662  * Command completion inhibited in proxy addition and auth request prompts.
2663  * Avoided use of linphonec_readline's internal filename completion.
2664  *
2665  * Revision 1.15  2006/01/14 13:29:32  strk
2666  * Reworked commands interface to use a table structure,
2667  * used by command line parser and help function.
2668  * Implemented first level of completion (commands).
2669  * Added notification of invalid "answer" and "terminate"
2670  * commands (no incoming call, no active call).
2671  * Forbidden "call" intialization when a call is already active.
2672  * Cleaned up all commands, adding more feedback and error checks.
2673  *
2674  * Revision 1.14  2006/01/13 13:00:29  strk
2675  * Added linphonec.h. Code layout change (added comments, forward decl,
2676  * globals on top, copyright notices and Logs). Handled out-of-memory
2677  * condition on history management. Removed assumption on sizeof(char).
2678  * Fixed bug in authentication prompt (introduced by linphonec_readline).
2679  * Added support for multiple authentication requests (up to MAX_PENDING_AUTH).
2680  *
2681  *
2682  ****************************************************************************/