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