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