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