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