]> sjero.net Git - linphone/blob - console/commands.c
add nortp mute feature
[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 "private.h"
38 #include "lpconfig.h"
39
40 #ifndef WIN32
41 #include <sys/wait.h>
42 #endif
43
44 /***************************************************************************
45  *
46  *  Forward declarations 
47  *
48  ***************************************************************************/
49
50 extern char *lpc_strip_blanks(char *input);
51
52 /* Command handlers */
53 static int lpc_cmd_help(LinphoneCore *, char *);
54 static int lpc_cmd_proxy(LinphoneCore *, char *);
55 static int lpc_cmd_call(LinphoneCore *, char *);
56 static int lpc_cmd_chat(LinphoneCore *, char *);
57 static int lpc_cmd_answer(LinphoneCore *, char *);
58 static int lpc_cmd_autoanswer(LinphoneCore *, char *);
59 static int lpc_cmd_terminate(LinphoneCore *, char *);
60 static int lpc_cmd_call_logs(LinphoneCore *, char *);
61 static int lpc_cmd_ipv6(LinphoneCore *, char *);
62 static int lpc_cmd_refer(LinphoneCore *, char *);
63 static int lpc_cmd_quit(LinphoneCore *, char *);
64 static int lpc_cmd_nat(LinphoneCore *, char *);
65 static int lpc_cmd_stun(LinphoneCore *, char *);
66 static int lpc_cmd_firewall(LinphoneCore *, char *);
67 static int lpc_cmd_friend(LinphoneCore *, char*);
68 static int lpc_cmd_soundcard(LinphoneCore *, char *);
69 static int lpc_cmd_webcam(LinphoneCore *, char *);
70 static int lpc_cmd_staticpic(LinphoneCore *, char *);
71 static int lpc_cmd_play(LinphoneCore *, char *);
72 static int lpc_cmd_record(LinphoneCore *, char *);
73 static int lpc_cmd_register(LinphoneCore *, char *);
74 static int lpc_cmd_unregister(LinphoneCore *, char *);
75 static int lpc_cmd_duration(LinphoneCore *lc, char *args);
76 static int lpc_cmd_status(LinphoneCore *lc, char *args);
77 static int lpc_cmd_ports(LinphoneCore *lc, char *args);
78 static int lpc_cmd_speak(LinphoneCore *lc, char *args);
79 static int lpc_cmd_codec(LinphoneCore *lc, char *args);
80 static int lpc_cmd_echocancellation(LinphoneCore *lc, char *args);
81 static int lpc_cmd_mute_mic(LinphoneCore *lc, char *args);
82 static int lpc_cmd_unmute_mic(LinphoneCore *lc, char *args);
83 static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args);
84
85 /* Command handler helpers */
86 static void linphonec_proxy_add(LinphoneCore *lc);
87 static void linphonec_proxy_display(LinphoneProxyConfig *lc);
88 static void linphonec_proxy_list(LinphoneCore *lc);
89 static void linphonec_proxy_remove(LinphoneCore *lc, int index);
90 static  int linphonec_proxy_use(LinphoneCore *lc, int index);
91 static void linphonec_proxy_show(LinphoneCore *lc,int index);
92 static void linphonec_friend_display(LinphoneFriend *fr);
93 static int linphonec_friend_list(LinphoneCore *lc, char *arg);
94 static void linphonec_display_command_help(LPC_COMMAND *cmd);
95 static int linphonec_friend_call(LinphoneCore *lc, unsigned int num);
96 #ifndef WIN32
97 static int linphonec_friend_add(LinphoneCore *lc, const char *name, const char *addr);
98 #endif
99 static int linphonec_friend_delete(LinphoneCore *lc, int num);
100 static int linphonec_friend_delete(LinphoneCore *lc, int num);
101 static void linphonec_codec_list(LinphoneCore *lc);
102 static void linphonec_codec_enable(LinphoneCore *lc, int index);
103 static void linphonec_codec_disable(LinphoneCore *lc, int index);
104
105
106
107 /* Command table management */
108 static LPC_COMMAND *lpc_find_command(const char *name);
109
110 void linphonec_out(const char *fmt,...);
111
112
113
114 /***************************************************************************
115  *
116  *  Global variables
117  *
118  ***************************************************************************/
119
120 /*
121  * Commands table.
122  */
123 LPC_COMMAND commands[] = {
124         { "help", lpc_cmd_help, "Print commands help", NULL },
125         { "call", lpc_cmd_call, "Call a SIP uri",
126                 "'call <sip-url>' "
127                 ": initiate a call to the specified destination."
128                 },
129         { "chat", lpc_cmd_chat, "Chat with a SIP uri",
130                 "'chat <sip-url> \"message\"' "
131                 ": send a chat message \"message\" to the specified destination."
132                 },
133         { "terminate", lpc_cmd_terminate, "Terminate the current call",
134                 NULL },
135         { "answer", lpc_cmd_answer, "Answer a call",
136                 "Accept an incoming call."
137         },
138         { "autoanswer", lpc_cmd_autoanswer, "Show/set auto-answer mode",
139                 "'autoanswer'       \t: show current autoanswer mode\n"
140                 "'autoanswer enable'\t: enable autoanswer mode\n"
141                 "'autoanswer disable'\t: disable autoanswer modeĀ \n"},
142         { "proxy", lpc_cmd_proxy, "Manage proxies",
143                 "'proxy list' : list all proxy setups.\n"
144                 "'proxy add' : add a new proxy setup.\n"
145                 "'proxy remove <index>' : remove proxy setup with number index.\n"
146                 "'proxy use <index>' : use proxy with number index as default proxy.\n"
147                 "'proxy unuse' : don't use a default proxy.\n"
148                 "'proxy show <index>' : show configuration and status of the proxy numbered by index.\n"
149                 "'proxy show default' : show configuration and status of the default proxy.\n"
150         },
151         { "soundcard", lpc_cmd_soundcard, "Manage soundcards",
152                 "'soundcard list' : list all sound devices.\n"
153                 "'soundcard show' : show current sound devices configuration.\n"
154                 "'soundcard use <index>' : select a sound device.\n"
155                 "'soundcard use files' : use .wav files instead of soundcard\n"
156         },
157         { "webcam", lpc_cmd_webcam, "Manage webcams",
158                 "'webcam list' : list all known devices.\n"
159                 "'webcam use <index>' : select a video device.\n"
160         },
161         { "staticpic", lpc_cmd_staticpic, "Manage static pictures when nowebcam",
162                 "'staticpic set' : Set path to picture that should be used.\n"
163         },
164         { "ipv6", lpc_cmd_ipv6, "Use IPV6",
165                 "'ipv6 status' : show ipv6 usage status.\n"
166                 "'ipv6 enable' : enable the use of the ipv6 network.\n"
167                 "'ipv6 disable' : do not use ipv6 network."
168         },
169         { "refer", lpc_cmd_refer,
170                 "Refer the current call to the specified destination.",
171                 "'refer <sip-url>' or 'r <sip-url>' "
172                 ": refer the current call to the specified destination."
173         },
174         { "nat", lpc_cmd_nat, "Set nat address",
175                 "'nat'        : show nat settings.\n"
176                 "'nat <addr>' : set nat address.\n"
177         },
178         { "stun", lpc_cmd_stun, "Set stun server address",
179                 "'stun'        : show stun settings.\n"
180                 "'stun <addr>' : set stun server address.\n"
181         },
182         { "firewall", lpc_cmd_firewall, "Set firewall policy",
183                 "'firewall'        : show current firewall policy.\n"
184                 "'firewall none'   : use direct connection.\n"
185                 "'firewall nat'    : use nat address given with the 'nat' command.\n"
186                 "'firewall stun'   : use stun server given with the 'stun' command.\n"
187         },
188         { "call-logs", lpc_cmd_call_logs, "Calls history", NULL },
189         { "friend", lpc_cmd_friend, "Manage friends",
190                 "'friend list [<pattern>]'    : list friends.\n"
191                 "'friend call <index>'        : call a friend.\n"
192                 "'friend add <name> <addr>'   : add friend, <name> must be quoted to include\n"
193             "                               spaces, <addr> has \"sip:\" added if it isn't\n"
194             "                               there.  Don't use '<' '>' around <addr>.\n"
195                 "'friend delete <index>'      : remove friend, 'all' removes all\n"
196         },
197         { "play", lpc_cmd_play, "play from a wav file",
198                 "This feature is available only in file mode (see 'help soundcard')\n"
199                 "'play <wav file>'    : play a wav file."
200         },
201         { "record", lpc_cmd_record, "record to a wav file",
202                 "This feature is available only in file mode (see 'help soundcard')\n"
203                 "'record <wav file>'    : record into wav file."
204         },
205         { "quit", lpc_cmd_quit, "Exit linphonec", NULL },
206         { "register", lpc_cmd_register, "Register in one line to a proxy" , "register <sip identity> <sip proxy> <password>"},
207         { "unregister", lpc_cmd_unregister, "Unregister from default proxy", NULL       },
208         { "duration", lpc_cmd_duration, "Print duration in seconds of the last call.", NULL },
209         { "status", lpc_cmd_status, "Print various status information", 
210                         "'status register'  \t: print status concerning registration\n"
211                         "'status autoanswer'\t: tell whether autoanswer mode is enabled\n"
212                         "'status hook'      \t: print hook status\n" },
213         { "ports", lpc_cmd_ports, "Network ports configuration", 
214                         "'ports'  \t: prints current used ports.\n"
215                         "'ports sip <port number>'\t: Sets the sip port.\n" },
216         { "speak", lpc_cmd_speak, "Speak a sentence using espeak TTS engine",
217                         "This feature is available only in file mode. (see 'help soundcard')\n"
218                         "'speak <voice name> <sentence>'        : speak a text using the specified espeak voice.\n"
219                         "Example for english voice: 'speak default Hello my friend !'"
220         },
221     { "codec", lpc_cmd_codec, "Codec configuration",
222             "'codec list' : list codecs\n"  
223             "'codec enable <index>' : enable available codec\n"  
224             "'codec disable <index>' : disable codecs" }, 
225     { "ec", lpc_cmd_echocancellation, "Echo cancellation",
226             "'ec on [<delay>] [<tail>] [<framesize>]' : turn EC on with given delay, tail length and framesize\n"
227             "'ec off' : turn echo cancellation (EC) off\n"
228             "'ec show' : show EC status" },
229         { "mute", lpc_cmd_mute_mic, 
230           "Mute microphone and suspend voice transmission."},
231         { "unmute", lpc_cmd_unmute_mic, 
232           "Unmute microphone and resume voice transmission."},
233         { "nortp-on-audio-mute", lpc_cmd_rtp_no_xmit_on_audio_mute,
234           "Set the rtp_no_xmit_on_audio_mute configuration parameter",
235           "   If set to 1 then rtp transmission will be muted when\n"
236           "   audio is muted , otherwise rtp is always sent."}, 
237         { (char *)NULL, (lpc_cmd_handler)NULL, (char *)NULL, (char *)NULL }
238 };
239
240 /***************************************************************************
241  *
242  *  Public interface 
243  *
244  ***************************************************************************/
245
246 /*
247  * Main command dispatcher.
248  * WARNING: modifies second argument!
249  *
250  * Always return 1 currently.
251  */
252 int
253 linphonec_parse_command_line(LinphoneCore *lc, char *cl)
254 {
255         char *ptr=cl;
256         char *args=NULL;
257         LPC_COMMAND *cmd;
258
259         /* Isolate first word and args */
260         while(*ptr && !isspace(*ptr)) ++ptr;
261         if (*ptr)
262         {
263                 *ptr='\0';
264                 /* set args to first nonblank */
265                 args=ptr+1;
266                 while(*args && isspace(*args)) ++args;
267         }
268
269         /* Handle DTMF */
270         if ( isdigit(*cl) || *cl == '#' || *cl == '*' )
271         {
272                 while ( isdigit(*cl) || *cl == '#' || *cl == '*' )
273                 {
274                         linphone_core_send_dtmf(lc, *cl);
275                         ms_sleep(1); // be nice
276                         ++cl;
277                 }
278
279                 // discard spurious trailing chars
280                 return 1;
281         }
282
283         /* Handle other kind of commands */
284         cmd=lpc_find_command(cl);
285         if ( !cmd )
286         {
287                 linphonec_out("'%s': Cannot understand this.\n", cl);
288                 return 1;
289         }
290
291         if ( ! cmd->func(lc, args) )
292         {
293                 linphonec_out("Syntax error.\n");
294                 linphonec_display_command_help(cmd);
295         }
296
297         return 1;
298 }
299
300 /*
301  * Generator function for command completion.
302  * STATE let us know whether to start from scratch;
303  * without any state (STATE==0), then we start at the
304  * top of the list.
305  */
306 char *
307 linphonec_command_generator(const char *text, int state)
308 {
309         static int index, len;
310         char *name;
311
312         if ( ! state )
313         {
314                 index=0;
315                 len=strlen(text);
316         }
317
318         /*
319          * Return the next name which partially matches
320          * from the commands list
321          */
322         while ((name=commands[index].name))
323         {
324                 ++index; /* so next call get next command */
325
326                 if (strncmp(name, text, len) == 0)
327                 {
328                         return ortp_strdup(name);
329                 }
330         }
331
332         return NULL;
333 }
334
335
336 /***************************************************************************
337  *
338  *  Command handlers 
339  *
340  ***************************************************************************/
341
342 static int
343 lpc_cmd_help(LinphoneCore *lc, char *arg)
344 {
345         int i=0;
346         LPC_COMMAND *cmd;
347
348         if (!arg || !*arg)
349         {
350                 linphonec_out("Commands are:\n");
351                 linphonec_out("---------------------------\n");
352
353                 while (commands[i].help)
354                 {
355                         linphonec_out("%10.10s\t%s\n", commands[i].name,
356                                 commands[i].help);
357                         i++;
358                 }
359                 
360                 linphonec_out("---------------------------\n");
361                 linphonec_out("Type 'help <command>' for more details.\n");
362
363                 return 1;
364         }
365
366         cmd=lpc_find_command(arg);
367         if ( !cmd )
368         {
369                 linphonec_out("No such command.\n");
370                 return 1;
371         }
372
373         linphonec_display_command_help(cmd);
374         return 1;
375
376 }
377
378 static char callee_name[256]={0};
379 static char caller_name[256]={0};
380
381 static int
382 lpc_cmd_call(LinphoneCore *lc, char *args)
383 {
384         if ( ! args || ! *args )
385         {
386                 return 0;
387         }
388
389         if ( lc->call != NULL )
390         {
391                 linphonec_out("Terminate current call first.\n");
392         }
393         else
394         {
395                 if ( -1 == linphone_core_invite(lc, args) )
396                 {
397                         linphonec_out("Error from linphone_core_invite.\n");
398                 }
399                 else
400                 {
401                         snprintf(callee_name,sizeof(callee_name),"%s",args);
402                 }
403         }
404         return 1;
405 }
406
407 static int
408 lpc_cmd_chat(LinphoneCore *lc, char *args)
409 {
410         char *arg1 = args;
411         char *arg2 = NULL;
412         char *ptr = args;
413
414         if (!args) return 0;
415
416         /* Isolate first and second arg */
417         while(*ptr && !isspace(*ptr)) ++ptr;
418         if ( *ptr )
419         {
420                 *ptr='\0';
421                 arg2=ptr+1;
422                 while(*arg2 && isspace(*arg2)) ++arg2;
423         }
424         else
425         {
426                 /* missing one parameter */
427                 return 0;
428         }
429         LinphoneChatRoom *cr = linphone_core_create_chat_room(lc,arg1);
430         linphone_chat_room_send_message(cr,arg2);
431         linphone_chat_room_destroy(cr);
432
433         return 1;
434 }
435
436 const char *linphonec_get_callee(){
437         return callee_name;
438 }
439
440 const char *linphonec_get_caller(){
441         return caller_name;
442 }
443
444 void linphonec_set_caller(const char *caller){
445         snprintf(caller_name,sizeof(caller_name)-1,"%s",caller);
446 }
447
448 static int
449 lpc_cmd_refer(LinphoneCore *lc, char *args)
450 {
451         if (args)
452                 linphone_core_refer(lc, args);
453         else{
454                 linphonec_out("refer needs an argument\n");
455         }
456         return 1;
457 }
458
459 static int
460 lpc_cmd_terminate(LinphoneCore *lc, char *args)
461 {
462         if ( -1 == linphone_core_terminate_call(lc, NULL) )
463         {
464                 linphonec_out("No active call.\n");
465         }
466         return 1;
467 }
468
469 static int
470 lpc_cmd_answer(LinphoneCore *lc, char *args)
471 {
472         if ( -1 == linphone_core_accept_call(lc, NULL) )
473         {
474                 linphonec_out("No incoming call.\n");
475         }
476         return 1;
477 }
478
479 static int
480 lpc_cmd_autoanswer(LinphoneCore *lc, char *args)
481 {
482         if ( ! args )
483         {
484                 if ( linphonec_get_autoanswer() ) {
485                         linphonec_out("Auto answer is enabled. Use 'autoanswer disable' to disable.\n");
486                 } else {
487                         linphonec_out("Auto answer is disabled. Use 'autoanswer enable' to enable.\n");
488                 }
489                 return 1;
490         }
491
492         if (strstr(args,"enable")){
493                 linphonec_set_autoanswer(TRUE);
494                 linphonec_out("Auto answer enabled.\n");
495         }else if (strstr(args,"disable")){
496                 linphonec_set_autoanswer(FALSE);
497                 linphonec_out("Auto answer disabled.\n");
498         }else return 0;
499         return 1;
500 }
501
502 static int
503 lpc_cmd_quit(LinphoneCore *lc, char *args)
504 {
505         linphonec_main_loop_exit();
506         return 1;
507 }
508
509 static int
510 lpc_cmd_nat(LinphoneCore *lc, char *args)
511 {
512         bool_t use;
513         const char *nat;
514
515         if ( args ) args=lpc_strip_blanks(args);
516
517         if ( args && *args )
518         {
519                 linphone_core_set_nat_address(lc, args);
520                 /* linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_NAT_ADDRESS); */
521         }
522
523         nat = linphone_core_get_nat_address(lc);
524         use = linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS;
525         linphonec_out("Nat address: %s%s\n", nat ? nat : "unspecified" , use ? "" : " (disabled - use 'firewall nat' to enable)");
526
527         return 1;
528 }
529
530 static int
531 lpc_cmd_stun(LinphoneCore *lc, char *args)
532 {
533         bool_t use;
534         const char *stun;
535
536         if ( args ) args=lpc_strip_blanks(args);
537
538         if ( args && *args )
539         {
540                 linphone_core_set_stun_server(lc, args);
541                 /* linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_STUN); */
542         }
543
544         stun = linphone_core_get_stun_server(lc);
545         use = linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_STUN;
546         linphonec_out("Stun server: %s%s\n", stun ? stun : "unspecified" , use? "" : " (disabled - use 'firewall stun' to enable)");
547
548         return 1;
549 }
550
551 static int
552 lpc_cmd_firewall(LinphoneCore *lc, char *args)
553 {
554         const char* setting=NULL;
555
556         if ( args ) args=lpc_strip_blanks(args);
557
558         if ( args && *args )
559         {
560                 if (strcmp(args,"none")==0)
561                 {
562                         linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL);
563                 }
564                 else if (strcmp(args,"stun")==0)
565                 {
566                         setting = linphone_core_get_stun_server(lc);
567                         if ( ! setting )
568                         {
569                                 linphonec_out("No stun server address is defined, use 'stun <address>' first\n");
570                                 return 1;
571                         }
572                         linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_STUN);
573                 }
574                 else if (strcmp(args,"nat")==0)
575                 {
576                         setting = linphone_core_get_nat_address(lc);
577                         if ( ! setting )
578                         {
579                                 linphonec_out("No nat address is defined, use 'nat <address>' first");
580                                 return 1;
581                         }
582                         linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_NAT_ADDRESS);
583                 }
584         }
585
586         switch(linphone_core_get_firewall_policy(lc))
587         {
588                 case LINPHONE_POLICY_NO_FIREWALL:
589                         linphonec_out("No firewall\n");
590                         break;
591                 case LINPHONE_POLICY_USE_STUN:
592                         linphonec_out("Using stun server %s to discover firewall address\n", setting ? setting : linphone_core_get_stun_server(lc));
593                         break;
594                 case LINPHONE_POLICY_USE_NAT_ADDRESS:
595                         linphonec_out("Using supplied nat address %s.\n", setting ? setting : linphone_core_get_nat_address(lc));
596                         break;
597         }
598         return 1;
599 }
600
601 #ifndef WIN32
602 /* Helper function for processing freind names */
603 static int
604 lpc_friend_name(char **args, char **name)
605 {
606         /* Use space as a terminator unless quoted */
607         if (('"' == **args) || ('\'' == **args)){
608                 char *end;
609                 char delim = **args;
610                 (*args)++;
611                 end = (*args);
612                 while ((delim != *end) && ('\0' != *end)) end++;
613                 if ('\0' == *end) {
614                         fprintf(stderr, "Mismatched quotes\n");
615                         return 0;
616                 }
617                 *name = *args;
618                 *end = '\0';
619                 *args = ++end;
620         } else {
621                 *name = strsep(args, " ");
622                 
623                 if (NULL == *args) { /* Means there was no separator */
624                         fprintf(stderr, "Either name or address is missing\n");
625                         return 0;
626                 }
627                 if (NULL == *name) return 0;
628         }
629         return 1;
630 }
631 #endif
632
633 static int
634 lpc_cmd_friend(LinphoneCore *lc, char *args)
635 {
636         int friend_num;
637
638         if ( args ) args=lpc_strip_blanks(args);
639
640         if ( ! args || ! *args ) return 0;
641
642         if ( !strncmp(args, "list", 4) )
643         {
644                 return linphonec_friend_list(lc, args+4);
645                 return 1;
646         }
647         else if ( !strncmp(args, "call", 4) )
648         {
649                 args+=4;
650                 if ( ! *args ) return 0;
651                 friend_num = strtol(args, NULL, 10);
652 #ifndef _WIN32_WCE              
653                 if ( errno == ERANGE ) {
654                         linphonec_out("Invalid friend number\n");
655                         return 0;
656                 }
657 #endif /*_WIN32_WCE*/
658                 linphonec_friend_call(lc, friend_num);
659                 return 1;
660         }
661         else if ( !strncmp(args, "delete", 6) )
662         {
663                 args+=6;
664                 if ( ! *args ) return 0;
665                 while (*args == ' ') args++;
666                 if ( ! *args ) return 0;
667                 if (!strncmp(args, "all", 3))
668                 {
669                         friend_num = -1;
670                 } 
671                 else
672                 {
673                         friend_num = strtol(args, NULL, 10);
674 #ifndef _WIN32_WCE              
675                         if ( errno == ERANGE ) {
676                                 linphonec_out("Invalid friend number\n");
677                                 return 0;
678                         }
679 #endif /*_WIN32_WCE*/
680                 }
681                 linphonec_friend_delete(lc, friend_num);
682                 return 1;
683         }
684         else if ( !strncmp(args, "add", 3) )
685         {
686 #ifndef WIN32
687                 char  *name;
688                 char  addr[80];
689                 char *addr_p = addr;
690                 char *addr_orig;
691
692                 args+=3;
693                 if ( ! *args ) return 0;
694                 while (*args == ' ') args++;
695                 if ( ! *args ) return 0;
696
697                 if (!lpc_friend_name(&args,  &name)) return 0;
698
699                 while (*args == ' ') args++;
700                 if ( ! *args ) return 0;
701                 if (isdigit(*args)) {
702                         strcpy (addr, "sip:");
703                         addr_p = addr + strlen("sip:");
704                 }
705                 addr_orig = strsep(&args, " ");
706                 if (1 >= strlen(addr_orig)) {
707                         fprintf(stderr, "A single-digit address is not valid\n");
708                         return 0;
709                 }
710                 strcpy(addr_p, addr_orig);
711                 linphonec_friend_add(lc, name, addr);
712 #else
713                 LinphoneFriend *new_friend;
714                 new_friend = linphone_friend_new_with_addr(args);
715                 linphone_core_add_friend(lc, new_friend);
716 #endif
717                 return 1;
718         }
719         return 0;
720 }
721
722 static int lpc_cmd_play(LinphoneCore *lc, char *args){
723         if ( args ) args=lpc_strip_blanks(args);
724         if ( ! args || ! *args ) return 0;
725         linphone_core_set_play_file(lc,args);
726         return 1;
727 }
728
729 static int lpc_cmd_record(LinphoneCore *lc, char *args){
730         if ( args ) args=lpc_strip_blanks(args);
731         if ( ! args || ! *args ) return 0;
732         linphone_core_set_record_file(lc,args);
733         return 1;
734 }
735
736 /*
737  * Modified input
738  */
739 static int
740 lpc_cmd_proxy(LinphoneCore *lc, char *args)
741 {
742         char *arg1 = args;
743         char *arg2 = NULL;
744         char *ptr = args;
745         int proxynum;
746
747         if ( ! arg1 ) return 0;
748
749         /* Isolate first and second arg */
750         while(*ptr && !isspace(*ptr)) ++ptr;
751         if ( *ptr )
752         {
753                 *ptr='\0';
754                 arg2=ptr+1;
755                 while(*arg2 && isspace(*arg2)) ++arg2;
756         }
757
758         if (strcmp(arg1,"add")==0)
759         {
760 #ifdef HAVE_READLINE
761                 rl_inhibit_completion=1;
762 #endif
763                 linphonec_proxy_add(lc);
764 #ifdef HAVE_READLINE
765                 rl_inhibit_completion=0;
766 #endif
767         }
768         else if (strcmp(arg1,"list")==0)
769         {
770                 linphonec_proxy_list(lc);
771         }
772         else if (strcmp(arg1,"remove")==0)
773         {
774                 linphonec_proxy_remove(lc,atoi(arg2));
775         }
776         else if (strcmp(arg1,"use")==0)
777         {
778                 if ( arg2 && *arg2 )
779                 {
780                         proxynum=atoi(arg2);
781                         if ( linphonec_proxy_use(lc, proxynum) )
782                                 linphonec_out("Default proxy set to %d.\n", proxynum);
783                 }
784                 else
785                 {
786                         proxynum=linphone_core_get_default_proxy(lc, NULL);
787                         if ( proxynum == -1 ) linphonec_out("No default proxy.\n");
788                         else linphonec_out("Current default proxy is %d.\n", proxynum);
789                 }
790         }else if (strcmp(arg1, "unuse")==0){
791                 linphone_core_set_default_proxy(lc, NULL);
792                 linphonec_out("Use no proxy.\n");
793         }
794
795         else if (strcmp(arg1, "show")==0)
796         {
797                 if (arg2 && *arg2)
798                 {
799                         if (strstr(arg2,"default"))
800                         {
801                 proxynum=linphone_core_get_default_proxy(lc, NULL);
802                 if ( proxynum < 0 ) {
803                         linphonec_out("No default proxy defined\n");
804                         return 1;
805                 }
806                 linphonec_proxy_show(lc,proxynum);
807                         }
808                         else
809                         {
810                 linphonec_proxy_show(lc, atoi(arg2));
811                         }
812                 }
813                 else return 0; /* syntax error */
814         }
815
816         else
817         {
818                 return 0; /* syntax error */
819         }
820
821         return 1;
822 }
823
824 static int
825 lpc_cmd_call_logs(LinphoneCore *lc, char *args)
826 {
827         const MSList *elem=linphone_core_get_call_logs(lc);
828         for (;elem!=NULL;elem=ms_list_next(elem))
829         {
830                 LinphoneCallLog *cl=(LinphoneCallLog*)elem->data;
831                 char *str=linphone_call_log_to_str(cl);
832                 linphonec_out("%s\n",str);
833                 ms_free(str);
834         }
835         return 1;
836 }
837
838 static int
839 lpc_cmd_ipv6(LinphoneCore *lc, char *arg1)
840 {
841         if ( ! arg1 )
842         {
843                 return 0; /* syntax error */
844         }
845
846         if (strcmp(arg1,"status")==0)
847         {
848                 linphonec_out("ipv6 use enabled: %s\n",linphone_core_ipv6_enabled(lc) ? "true":"false");
849         }
850         else if (strcmp(arg1,"enable")==0)
851         {
852                 linphone_core_enable_ipv6(lc,TRUE);
853                 linphonec_out("ipv6 use enabled.\n");
854         }
855         else if (strcmp(arg1,"disable")==0)
856         {
857                 linphone_core_enable_ipv6(lc,FALSE);
858                 linphonec_out("ipv6 use disabled.\n");
859         }
860         else
861         {
862                 return 0; /* syntax error */
863         }
864         return 1;
865 }
866
867 static int devname_to_index(LinphoneCore *lc, const char *devname){
868         const char **p;
869         int i;
870         for(i=0,p=linphone_core_get_sound_devices(lc);*p!=NULL;++p,++i){
871                 if (strcmp(devname,*p)==0) return i;
872         }
873         return -1;
874 }
875
876 static const char *index_to_devname(LinphoneCore *lc, int index){
877         const char **p;
878         int i;
879         for(i=0,p=linphone_core_get_sound_devices(lc);*p!=NULL;++p,++i){
880                 if (i==index) return *p;
881         }
882         return NULL;
883 }
884
885 static int lpc_cmd_soundcard(LinphoneCore *lc, char *args)
886 {
887         int i, index;
888         const char **dev;
889         char *arg1 = args;
890         char *arg2 = NULL;
891         char *ptr = args;
892
893         if (!args) return 0; /* syntax error */
894
895         /* Isolate first and second arg */
896         while(*ptr && !isspace(*ptr)) ++ptr;
897         if ( *ptr )
898         {
899                 *ptr='\0';
900                 arg2=ptr+1;
901                 while(*arg2 && isspace(*arg2)) ++arg2;
902         }
903
904         if (strcmp(arg1, "list")==0)
905         {
906                 dev=linphone_core_get_sound_devices(lc);
907                 for(i=0; dev[i]!=NULL; ++i){
908                         linphonec_out("%i: %s\n",i,dev[i]);
909                 }
910                 return 1;
911         }
912
913         if (strcmp(arg1, "show")==0)
914         {
915                 linphonec_out("Ringer device: %s\n",
916                         linphone_core_get_ringer_device(lc));
917                 linphonec_out("Playback device: %s\n",
918                         linphone_core_get_playback_device(lc));
919                 linphonec_out("Capture device: %s\n",
920                         linphone_core_get_capture_device(lc));
921                 return 1;
922         }
923
924         if (strcmp(arg1, "use")==0 && arg2)
925         {
926                 if (strcmp(arg2, "files")==0)
927                 {
928                         linphonec_out("Using wav files instead of soundcard.\n");
929                         linphone_core_use_files(lc,TRUE);
930                         return 1;
931                 }
932
933                 dev=linphone_core_get_sound_devices(lc);
934                 index=atoi(arg2); /* FIXME: handle not-a-number */
935                 for(i=0;dev[i]!=NULL;i++)
936                 {
937                         if (i!=index) continue;
938
939                         linphone_core_set_ringer_device(lc,dev[i]);
940                         linphone_core_set_playback_device(lc,dev[i]);
941                         linphone_core_set_capture_device(lc,dev[i]);
942                         linphonec_out("Using sound device %s\n",dev[i]);
943                         return 1;
944                 }
945                 linphonec_out("No such sound device\n");
946                 return 1;
947         }
948         if (strcmp(arg1, "capture")==0)
949         {
950                 const char *devname=linphone_core_get_capture_device(lc);
951                 if (!arg2){
952                         linphonec_out("Using capture device #%i (%s)\n",
953                                         devname_to_index(lc,devname),devname);
954                 }else{
955                         index=atoi(arg2); /* FIXME: handle not-a-number */
956                         devname=index_to_devname(lc,index);
957                         if (devname!=NULL){
958                                 linphone_core_set_capture_device(lc,devname);
959                                 linphonec_out("Using capture sound device %s\n",devname);
960                                 return 1;
961                         }
962                         linphonec_out("No such sound device\n");
963                 }
964                 return 1;
965         }
966         if (strcmp(arg1, "playback")==0)
967         {
968                 const char *devname=linphone_core_get_playback_device(lc);
969                 if (!arg2){
970                         linphonec_out("Using playback device #%i (%s)\n",
971                                         devname_to_index(lc,devname),devname);
972                 }else{
973                         index=atoi(arg2); /* FIXME: handle not-a-number */
974                         devname=index_to_devname(lc,index);
975                         if (devname!=NULL){
976                                 linphone_core_set_playback_device(lc,devname);
977                                 linphonec_out("Using playback sound device %s\n",devname);
978                                 return 1;
979                         }
980                         linphonec_out("No such sound device\n");
981                 }
982                 return 1;
983         }
984         if (strcmp(arg1, "ring")==0)
985         {
986                 const char *devname=linphone_core_get_ringer_device(lc);
987                 if (!arg2){
988                         linphonec_out("Using ring device #%i (%s)\n",
989                                         devname_to_index(lc,devname),devname);
990                 }else{
991                         index=atoi(arg2); /* FIXME: handle not-a-number */
992                         devname=index_to_devname(lc,index);
993                         if (devname!=NULL){
994                                 linphone_core_set_ringer_device(lc,devname);
995                                 linphonec_out("Using ring sound device %s\n",devname);
996                                 return 1;
997                         }
998                         linphonec_out("No such sound device\n");
999                 }
1000                 return 1;
1001         }
1002         return 0; /* syntax error */
1003 }
1004
1005 static int lpc_cmd_webcam(LinphoneCore *lc, char *args)
1006 {
1007         int i, index;
1008         const char **dev;
1009         char *arg1 = args;
1010         char *arg2 = NULL;
1011         char *ptr = args;
1012
1013         if (!args) return 0; /* syntax error */
1014
1015         /* Isolate first and second arg */
1016         while(*ptr && !isspace(*ptr)) ++ptr;
1017         if ( *ptr )
1018         {
1019                 *ptr='\0';
1020                 arg2=ptr+1;
1021                 while(*arg2 && isspace(*arg2)) ++arg2;
1022         }
1023
1024         if (strcmp(arg1, "list")==0)
1025         {
1026                 dev=linphone_core_get_video_devices(lc);
1027                 for(i=0; dev[i]!=NULL; ++i){
1028                         linphonec_out("%i: %s\n",i,dev[i]);
1029                 }
1030                 return 1;
1031         }
1032
1033         if (strcmp(arg1, "use")==0 && arg2)
1034         {
1035                 dev=linphone_core_get_video_devices(lc);
1036                 index=atoi(arg2); /* FIXME: handle not-a-number */
1037                 for(i=0;dev[i]!=NULL;i++)
1038                 {
1039                         if (i!=index) continue;
1040
1041                         linphone_core_set_video_device(lc, dev[i]);
1042                         linphonec_out("Using video device %s\n",dev[i]);
1043                         return 1;
1044                 }
1045                 linphonec_out("No such video device\n");
1046                 return 1;
1047         }
1048         return 0; /* syntax error */
1049 }
1050
1051 static int
1052 lpc_cmd_staticpic(LinphoneCore *lc, char *args)
1053 {
1054         char *arg1 = args;
1055         char *arg2 = NULL;
1056         char *ptr = args;
1057
1058         if (!args) return 0;  /* Syntax error */
1059
1060         /* Isolate first and second arg */
1061         while(*ptr && !isspace(*ptr)) ++ptr;
1062         if ( *ptr )
1063         {
1064                 *ptr='\0';
1065                 arg2=ptr+1;
1066                 while(*arg2 && isspace(*arg2)) ++arg2;
1067         }
1068
1069         if (strcmp(arg1, "set")==0 && arg2) {
1070                 linphone_core_set_static_picture(lc, arg2);
1071                 return 1;
1072         }
1073
1074         return 0; /* Syntax error */
1075 }
1076
1077
1078
1079 /***************************************************************************
1080  *
1081  *  Commands helper functions
1082  *
1083  ***************************************************************************/
1084
1085
1086 static void
1087 linphonec_proxy_add(LinphoneCore *lc)
1088 {
1089         bool_t enable_register=FALSE;
1090         LinphoneProxyConfig *cfg;
1091
1092         linphonec_out("Adding new proxy setup. Hit ^D to abort.\n");
1093
1094         /*
1095          * SIP Proxy address
1096          */
1097         while (1)
1098         {
1099                 char *input=linphonec_readline("Enter proxy sip address: ");
1100                 char *clean;
1101
1102                 if ( ! input ) {
1103                         linphonec_out("Aborted.\n");
1104                         return;
1105                 }
1106
1107                 /* Strip blanks */
1108                 clean=lpc_strip_blanks(input);
1109                 if ( ! *clean ) {
1110                         free(input);
1111                         continue;
1112                 }
1113
1114                 cfg=linphone_proxy_config_new();
1115                 if (linphone_proxy_config_set_server_addr(cfg,clean)<0)
1116                 {
1117                         linphonec_out("Invalid sip address (sip:sip.domain.tld).\n");
1118                         free(input);
1119                         linphone_proxy_config_destroy(cfg);
1120                         continue;
1121                 }
1122                 free(input);
1123                 break;
1124         }
1125
1126         /*
1127          * SIP Proxy identity
1128          */
1129         while (1)
1130         {
1131                 char *input=linphonec_readline("Your identity for this proxy: ");
1132                 char *clean;
1133
1134                 if ( ! input ) {
1135                         linphonec_out("Aborted.\n");
1136                         linphone_proxy_config_destroy(cfg);
1137                         return;
1138                 }
1139
1140                 /* Strip blanks */
1141                 clean=lpc_strip_blanks(input);
1142                 if ( ! *clean ) {
1143                         free(input);
1144                         continue;
1145                 }
1146
1147                 linphone_proxy_config_set_identity(cfg, clean);
1148                 if ( ! cfg->reg_identity )
1149                 {
1150                         linphonec_out("Invalid identity (sip:name@sip.domain.tld).\n");
1151                         free(input);
1152                         continue;
1153                 }
1154                 free(input);
1155                 break;
1156         }
1157
1158         /*
1159          * SIP Proxy enable register
1160          */
1161         while (1)
1162         {
1163                 char *input=linphonec_readline("Do you want to register on this proxy (yes/no): ");
1164                 char *clean;
1165
1166                 if ( ! input ) {
1167                         linphonec_out("Aborted.\n");
1168                         linphone_proxy_config_destroy(cfg);
1169                         return;
1170                 }
1171
1172                 /* Strip blanks */
1173                 clean=lpc_strip_blanks(input);
1174                 if ( ! *clean ) {
1175                         free(input);
1176                         continue;
1177                 }
1178
1179                 if ( ! strcmp(clean, "yes") ) enable_register=TRUE;
1180                 else if ( ! strcmp(clean, "no") ) enable_register=FALSE;
1181                 else {
1182                         linphonec_out("Please answer with 'yes' or 'no'\n");
1183                         free(input);
1184                         continue;
1185                 }
1186                 linphone_proxy_config_enableregister(cfg, enable_register);
1187                 free(input);
1188                 break;
1189         }
1190
1191         /*
1192          * SIP Proxy registration expiration
1193          */
1194         if ( enable_register==TRUE )
1195         {
1196                 long int expires=0;
1197                 while (1)
1198                 {
1199                         char *input=linphonec_readline("Specify register expiration time"
1200                                 " in seconds (default is 600): ");
1201
1202                         if ( ! input ) {
1203                                 linphonec_out("Aborted.\n");
1204                                 linphone_proxy_config_destroy(cfg);
1205                                 return;
1206                         }
1207
1208                         expires=strtol(input, (char **)NULL, 10);
1209                         if ( expires == LONG_MIN || expires == LONG_MAX )
1210                         {
1211                                 linphonec_out("Invalid value: %s\n", strerror(errno));
1212                                 free(input);
1213                                 continue;
1214                         }
1215
1216                         linphone_proxy_config_expires(cfg, expires);
1217                         linphonec_out("Expiration: %d seconds\n", cfg->expires);
1218
1219                         free(input);
1220                         break;
1221                 }
1222         }
1223
1224         /*
1225          * SIP proxy route
1226          */
1227         while (1)
1228         {
1229                 char *input=linphonec_readline("Specify route if needed: ");
1230                 char *clean;
1231
1232                 if ( ! input ) {
1233                         linphonec_out("Aborted.\n");
1234                         linphone_proxy_config_destroy(cfg);
1235                         return;
1236                 }
1237
1238                 /* Strip blanks */
1239                 clean=lpc_strip_blanks(input);
1240                 if ( ! *clean ) {
1241                         free(input);
1242                         linphonec_out("No route specified.\n");
1243                         break;
1244                 }
1245
1246                 linphone_proxy_config_set_route(cfg, clean);
1247                 if ( ! cfg->reg_route )
1248                 {
1249                         linphonec_out("Invalid route.\n");
1250                         free(input);
1251                         continue;
1252                 }
1253
1254                 free(input);
1255                 break;
1256         }
1257
1258         /*
1259          * Final confirmation 
1260          */
1261         while (1)
1262         {
1263                 char *input;
1264                 char *clean;
1265
1266                 linphonec_out("--------------------------------------------\n");
1267                 linphonec_proxy_display(cfg);
1268                 linphonec_out("--------------------------------------------\n");
1269                 input=linphonec_readline("Accept the above proxy configuration (yes/no) ?: ");
1270
1271
1272                 if ( ! input ) {
1273                         linphonec_out("Aborted.\n");
1274                         linphone_proxy_config_destroy(cfg);
1275                         return;
1276                 }
1277
1278                 /* Strip blanks */
1279                 clean=lpc_strip_blanks(input);
1280                 if ( ! *clean ) {
1281                         free(input);
1282                         continue;
1283                 }
1284
1285                 if ( ! strcmp(clean, "yes") ) break;
1286                 else if ( ! strcmp(clean, "no") )
1287                 {
1288                         linphonec_out("Declined.\n");
1289                         linphone_proxy_config_destroy(cfg);
1290                         free(input);
1291                         return;
1292                 }
1293
1294                 linphonec_out("Please answer with 'yes' or 'no'\n");
1295                 free(input);
1296                 continue;
1297         }
1298
1299
1300         linphone_core_add_proxy_config(lc,cfg);
1301
1302         /* automatically set the last entered proxy as the default one */
1303         linphone_core_set_default_proxy(lc,cfg);
1304
1305         linphonec_out("Proxy added.\n");
1306 }
1307
1308 static void
1309 linphonec_proxy_display(LinphoneProxyConfig *cfg)
1310 {
1311         linphonec_out("sip address: %s\nroute: %s\nidentity: %s\nregister: %s\nexpires: %i\nregistered: %s\n",
1312                         cfg->reg_proxy,
1313                         (cfg->reg_route!=NULL)?cfg->reg_route:"",
1314                         (cfg->reg_identity!=NULL)?cfg->reg_identity:"",
1315                         (cfg->reg_sendregister)?"yes":"no",
1316                         cfg->expires,
1317                         linphone_proxy_config_is_registered(cfg) ? "yes" : "no");
1318 }
1319
1320 static void linphonec_proxy_show(LinphoneCore *lc, int index)
1321 {
1322         const MSList *elem;
1323         int i;
1324         for(elem=linphone_core_get_proxy_config_list(lc),i=0;elem!=NULL;elem=elem->next,++i){
1325                 if (index==i){
1326                         LinphoneProxyConfig *cfg=(LinphoneProxyConfig *)elem->data;
1327                         linphonec_proxy_display(cfg);
1328                         return;
1329                 }
1330         }
1331         linphonec_out("No proxy with index %i\n", index);
1332 }
1333
1334 static void
1335 linphonec_proxy_list(LinphoneCore *lc)
1336 {
1337         const MSList *proxies;
1338         int n;
1339         int def=linphone_core_get_default_proxy(lc,NULL);
1340         
1341         proxies=linphone_core_get_proxy_config_list(lc);
1342         for(n=0;proxies!=NULL;proxies=ms_list_next(proxies),n++){
1343                 if (n==def)
1344                         linphonec_out("****** Proxy %i - this is the default one - *******\n",n);
1345                 else 
1346                         linphonec_out("****** Proxy %i *******\n",n);
1347                 linphonec_proxy_display((LinphoneProxyConfig*)proxies->data);
1348         }
1349         if ( ! n ) linphonec_out("No proxies defined\n");
1350 }
1351
1352 static void
1353 linphonec_proxy_remove(LinphoneCore *lc, int index)
1354 {
1355         const MSList *proxies;
1356         LinphoneProxyConfig *cfg;
1357         proxies=linphone_core_get_proxy_config_list(lc);
1358         cfg=(LinphoneProxyConfig*)ms_list_nth_data(proxies,index);
1359         if (cfg==NULL){
1360                 linphonec_out("No such proxy.\n");
1361                 return;
1362         }
1363         linphone_core_remove_proxy_config(lc,cfg);
1364         linphonec_out("Proxy %s removed.\n", cfg->reg_proxy);
1365         linphone_proxy_config_destroy(cfg);
1366 }
1367
1368 static int
1369 linphonec_proxy_use(LinphoneCore *lc, int index)
1370 {
1371         const MSList *proxies;
1372         LinphoneProxyConfig *cfg;
1373         proxies=linphone_core_get_proxy_config_list(lc);
1374         cfg=(LinphoneProxyConfig*)ms_list_nth_data(proxies,index);
1375         if (cfg==NULL){
1376                 linphonec_out("No such proxy (try 'proxy list').");
1377                 return 0;
1378         }
1379         linphone_core_set_default_proxy(lc,cfg);
1380         return 1;
1381 }
1382
1383 static void
1384 linphonec_friend_display(LinphoneFriend *fr)
1385 {
1386         LinphoneAddress *uri=linphone_address_clone(linphone_friend_get_address(fr));
1387         char *str;
1388         
1389         linphonec_out("name: %s\n", linphone_address_get_display_name(uri));
1390         linphone_address_set_display_name(uri,NULL);
1391         str=linphone_address_as_string(uri);
1392         linphonec_out("address: %s\n", str);
1393 }
1394
1395 static int
1396 linphonec_friend_list(LinphoneCore *lc, char *pat)
1397 {
1398         const MSList *friend;
1399         int n;
1400
1401         if (pat) {
1402                 pat=lpc_strip_blanks(pat);
1403                 if (!*pat) pat = NULL;
1404         }
1405
1406         friend = linphone_core_get_friend_list(lc);
1407         for(n=0; friend!=NULL; friend=ms_list_next(friend), ++n )
1408         {
1409                 if ( pat ) {
1410                         const char *name = linphone_address_get_display_name(
1411                             linphone_friend_get_address((LinphoneFriend*)friend->data));
1412                         if (name && ! strstr(name, pat) ) continue;
1413                 }
1414                 linphonec_out("****** Friend %i *******\n",n);
1415                 linphonec_friend_display((LinphoneFriend*)friend->data);
1416         }
1417
1418         return 1;
1419 }
1420
1421 static int
1422 linphonec_friend_call(LinphoneCore *lc, unsigned int num)
1423 {
1424         const MSList *friend = linphone_core_get_friend_list(lc);
1425         unsigned int n;
1426         char *addr;
1427
1428         for(n=0; friend!=NULL; friend=ms_list_next(friend), ++n )
1429         {
1430                 if ( n == num )
1431                 {
1432                         int ret;
1433                         addr = linphone_address_as_string(linphone_friend_get_address((LinphoneFriend*)friend->data));
1434                         ret=lpc_cmd_call(lc, addr);
1435                         ms_free(addr);
1436                         return ret;
1437                 }
1438         }
1439         linphonec_out("No such friend %u\n", num);
1440         return 1;
1441 }
1442
1443 #ifndef WIN32
1444 static int
1445 linphonec_friend_add(LinphoneCore *lc, const char *name, const char *addr)
1446 {
1447         LinphoneFriend *newFriend;
1448
1449         char url[PATH_MAX];
1450
1451         snprintf(url, PATH_MAX, "%s <%s>", name, addr);
1452         newFriend = linphone_friend_new_with_addr(url);
1453         linphone_core_add_friend(lc, newFriend);
1454         return 0;
1455 }
1456 #endif
1457
1458 static int
1459 linphonec_friend_delete(LinphoneCore *lc, int num)
1460 {
1461         const MSList *friend = linphone_core_get_friend_list(lc);
1462         unsigned int n;
1463
1464         for(n=0; friend!=NULL; friend=ms_list_next(friend), ++n )
1465         {
1466                 if ( n == num )
1467                 {
1468                         linphone_core_remove_friend(lc, friend->data);
1469                         return 0;
1470                 }
1471         }
1472
1473         if (-1 == num) 
1474         {
1475                 unsigned int i;
1476                 for (i = 0 ; i < n ; i++)
1477                         linphonec_friend_delete(lc, 0);
1478                 return 0;
1479         }
1480
1481         linphonec_out("No such friend %u\n", num);
1482         return 1;
1483 }
1484
1485 static void
1486 linphonec_display_command_help(LPC_COMMAND *cmd)
1487 {
1488         if ( cmd->doc ) linphonec_out ("%s\n", cmd->doc);
1489         else linphonec_out("%s\n", cmd->help);
1490 }
1491
1492
1493 static int lpc_cmd_register(LinphoneCore *lc, char *args){
1494         char identity[512];
1495         char proxy[512];
1496         char passwd[512];
1497         LinphoneProxyConfig *cfg;
1498         const MSList *elem;
1499     
1500         if (!args)
1501         {
1502                 /* it means that you want to register the default proxy */
1503                 LinphoneProxyConfig *cfg=NULL;
1504                 linphone_core_get_default_proxy(lc,&cfg);
1505                 if (cfg)
1506                 {
1507                         if(!linphone_proxy_config_is_registered(cfg)) {
1508                                 linphone_proxy_config_enable_register(cfg,TRUE);
1509                                 linphone_proxy_config_done(cfg);
1510                         }else{
1511                                 linphonec_out("default proxy already registered\n");
1512                         }
1513                 }else{
1514                         linphonec_out("we do not have a default proxy\n");
1515                         return 0;
1516                 }
1517                 return 1;
1518         }
1519         passwd[0]=proxy[0]=identity[0]='\0';
1520         sscanf(args,"%s %s %s",identity,proxy,passwd);
1521         if (proxy[0]=='\0' || identity[0]=='\0'){
1522                 linphonec_out("Missing parameters, see help register\n");
1523                 return 1;
1524         }
1525         if (passwd[0]!='\0'){
1526                 LinphoneAddress *from;
1527                 LinphoneAuthInfo *info;
1528                 if ((from=linphone_address_new(identity))!=NULL){
1529                         char realm[128];
1530                         snprintf(realm,sizeof(realm)-1,"\"%s\"",linphone_address_get_domain(from));
1531                         info=linphone_auth_info_new(linphone_address_get_username(from),NULL,passwd,NULL,NULL);
1532                         linphone_core_add_auth_info(lc,info);
1533                         linphone_address_destroy(from);
1534                         linphone_auth_info_destroy(info);
1535                 }
1536         }
1537         elem=linphone_core_get_proxy_config_list(lc);
1538         if (elem) {
1539                 cfg=(LinphoneProxyConfig*)elem->data;
1540                 linphone_proxy_config_edit(cfg);
1541         }
1542         else cfg=linphone_proxy_config_new();
1543         linphone_proxy_config_set_identity(cfg,identity);
1544         linphone_proxy_config_set_server_addr(cfg,proxy);
1545         linphone_proxy_config_enable_register(cfg,TRUE);
1546         if (elem) linphone_proxy_config_done(cfg);
1547         else linphone_core_add_proxy_config(lc,cfg);
1548         linphone_core_set_default_proxy(lc,cfg);
1549         return 1;
1550 }
1551
1552 static int lpc_cmd_unregister(LinphoneCore *lc, char *args){
1553         LinphoneProxyConfig *cfg=NULL;
1554         linphone_core_get_default_proxy(lc,&cfg);
1555         if (cfg && linphone_proxy_config_is_registered(cfg)) {
1556                 linphone_proxy_config_edit(cfg);
1557                 linphone_proxy_config_enable_register(cfg,FALSE);
1558                 linphone_proxy_config_done(cfg);
1559         }else{
1560                 linphonec_out("unregistered\n");
1561         }
1562         return 1;
1563 }
1564
1565 static int lpc_cmd_duration(LinphoneCore *lc, char *args){
1566         LinphoneCallLog *cl;
1567         const MSList *elem=linphone_core_get_call_logs(lc);
1568         for(;elem!=NULL;elem=elem->next){
1569                 if (elem->next==NULL){
1570                         cl=(LinphoneCallLog*)elem->data;
1571                         linphonec_out("%i seconds\n",cl->duration);
1572                 }
1573         }
1574         return 1;
1575 }
1576
1577 static int lpc_cmd_status(LinphoneCore *lc, char *args)
1578 {
1579         LinphoneProxyConfig *cfg;
1580         
1581         if ( ! args ) return 0;
1582         linphone_core_get_default_proxy(lc,&cfg);
1583         if (strstr(args,"register"))
1584         {
1585                 if (cfg)
1586                 {
1587                         if (linphone_proxy_config_is_registered(cfg)){
1588                                 linphonec_out("registered, identity=%s duration=%i\n",
1589                                         linphone_proxy_config_get_identity(cfg),
1590                                         linphone_proxy_config_get_expires(cfg));
1591                         }else if (linphone_proxy_config_register_enabled(cfg)){
1592                                 linphonec_out("registered=-1\n");
1593                         }else linphonec_out("registered=0\n");
1594                 }
1595                 else linphonec_out("registered=0\n");
1596         }
1597         else if (strstr(args,"autoanswer"))
1598         {
1599                 if (cfg && linphone_proxy_config_is_registered(cfg))
1600                         linphonec_out("autoanswer=%i\n",linphonec_get_autoanswer());
1601                 else linphonec_out("unregistered\n");
1602         }
1603         else if (strstr(args,"hook"))
1604         {
1605                 gstate_t call_state=linphone_core_get_state(lc,GSTATE_GROUP_CALL);
1606 /*
1607                 if (!cfg || !linphone_proxy_config_is_registered(cfg)){
1608                         linphonec_out("unregistered\n");
1609                         return 1;
1610                 }
1611  */
1612                 switch(call_state){
1613                         case GSTATE_CALL_OUT_INVITE:
1614                                 linphonec_out("hook=dialing\n");
1615                         break;
1616                         case GSTATE_CALL_IDLE:
1617                                 linphonec_out("hook=offhook\n");
1618                         break;
1619                         case GSTATE_CALL_OUT_CONNECTED:
1620                                 linphonec_out("Call out, hook=%s duration=%i, muted=%s rtp-xmit-muted=%s\n", linphonec_get_callee(),
1621                                               linphone_core_get_current_call_duration(lc),
1622                                               lc->audio_muted ? "yes" : "no",
1623                                               linphone_core_is_rtp_muted(lc) ? "yes"  : "no");
1624                         break;
1625                         case GSTATE_CALL_IN_CONNECTED:
1626                                 linphonec_out("hook=answered duration=%i\n" ,
1627                                         linphone_core_get_current_call_duration(lc));
1628                                 break;
1629                         case GSTATE_CALL_IN_INVITE:
1630                                 linphonec_out("Incoming call from %s\n",linphonec_get_caller());
1631                                 break;
1632                         default:
1633                                 break;
1634                 }
1635                 
1636         }
1637         else return 0;
1638
1639         return 1;
1640 }
1641
1642 static int lpc_cmd_ports(LinphoneCore *lc, char *args)
1643 {
1644         int port;
1645         if ( ! args ){
1646                 linphonec_out("sip port = %i\naudio rtp port = %i\nvideo rtp port = %i\n",
1647                         linphone_core_get_sip_port(lc),
1648                         linphone_core_get_audio_port(lc),
1649                         linphone_core_get_video_port(lc));
1650                 return 1;
1651         }
1652         if (sscanf(args,"sip %i",&port)==1){
1653                 linphonec_out("Setting sip port to %i\n",port);
1654                 linphone_core_set_sip_port(lc,port);
1655         }else return 0;
1656
1657         return 1;
1658 }
1659
1660 static int lpc_cmd_speak(LinphoneCore *lc, char *args){
1661 #ifndef WIN32
1662         char voice[64];
1663         char *sentence;
1664         char cl[128];
1665         char *wavfile;
1666         int status;
1667         FILE *file;
1668         
1669     if (!args) return 0;
1670         memset(voice,0,sizeof(voice));
1671         sscanf(args,"%s63",voice);
1672         sentence=args+strlen(voice);
1673         wavfile=tempnam("/tmp/","linphonec-espeak-");
1674         snprintf(cl,sizeof(cl),"espeak -v %s -s 100 -w %s --stdin",voice,wavfile);
1675         file=popen(cl,"w");
1676         if (file==NULL){
1677                 ms_error("Could not open pipe to espeak !");
1678                 return 1;
1679         }
1680         fprintf(file,"%s",sentence);
1681         status=pclose(file);
1682         if (WEXITSTATUS(status)==0){
1683                 linphone_core_set_play_file(lc,wavfile);
1684         }else{
1685                 linphonec_out("espeak command failed.");
1686         }
1687 #else
1688         linphonec_out("Sorry, this command is not implemented in windows version.");
1689 #endif
1690         return 1;
1691 }
1692
1693 static int lpc_cmd_codec(LinphoneCore *lc, char *args){
1694         char *arg1 = args;
1695         char *arg2 = NULL;
1696         char *ptr = args;
1697
1698         if (!args) return 0;
1699
1700         /* Isolate first and second arg */
1701         while(*ptr && !isspace(*ptr)) ++ptr;
1702         if ( *ptr )
1703         {
1704                 *ptr='\0';
1705                 arg2=ptr+1;
1706                 while(*arg2 && isspace(*arg2)) ++arg2;
1707         }
1708
1709         if (strcmp(arg1,"enable")==0)
1710         {
1711 #ifdef HAVE_READLINE
1712                 rl_inhibit_completion=1;
1713 #endif
1714         if (!strcmp(arg2,"all")) linphonec_codec_enable(lc,-1);
1715         else linphonec_codec_enable(lc,atoi(arg2));
1716 #ifdef HAVE_READLINE
1717                 rl_inhibit_completion=0;
1718 #endif
1719         }
1720         else if (strcmp(arg1,"list")==0)
1721         {
1722                 linphonec_codec_list(lc);
1723         }
1724         else if (strcmp(arg1,"disable")==0)
1725         {
1726         if (!strcmp(arg2,"all")) linphonec_codec_disable(lc,-1);
1727         else linphonec_codec_disable(lc,atoi(arg2));
1728         }
1729         else
1730         {
1731                 return 0; /* syntax error */
1732         }
1733
1734         return 1;
1735 }
1736
1737 static void linphonec_codec_list(LinphoneCore *lc){
1738         PayloadType *pt;
1739     codecs_config_t *config=&lc->codecs_conf;
1740         int index=0;
1741         MSList *node;
1742         for(node=config->audio_codecs;node!=NULL;node=ms_list_next(node)){
1743                 pt=(PayloadType*)(node->data);
1744         linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate, 
1745                     linphone_core_payload_type_enabled(lc,pt) ? "enabled" : "disabled");
1746                 index++;
1747         }
1748 }
1749
1750 static void linphonec_codec_enable(LinphoneCore *lc, int sel_index){
1751         PayloadType *pt;
1752     codecs_config_t *config=&lc->codecs_conf;
1753         int index=0;
1754         MSList *node;
1755     for(node=config->audio_codecs;node!=NULL;node=ms_list_next(node)){
1756         if (index == sel_index || sel_index == -1) {
1757                     pt=(PayloadType*)(node->data);
1758             pt->flags|=PAYLOAD_TYPE_ENABLED;
1759             linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate, "enabled");
1760         }
1761                 index++;
1762         }
1763 }
1764
1765 static void linphonec_codec_disable(LinphoneCore *lc, int sel_index){
1766         PayloadType *pt;
1767     codecs_config_t *config=&lc->codecs_conf;
1768         int index=0;
1769         MSList *node;
1770         for(node=config->audio_codecs;node!=NULL;node=ms_list_next(node)){
1771         if (index == sel_index || sel_index == -1) {
1772                 pt=(PayloadType*)(node->data);
1773             pt->flags&=~PAYLOAD_TYPE_ENABLED;
1774             linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate, "disabled");
1775         }
1776                 index++;
1777         }
1778 }
1779
1780 static int lpc_cmd_echocancellation(LinphoneCore *lc, char *args){
1781         char *arg1 = args;
1782         char *arg2 = NULL;
1783         char *ptr = args;
1784
1785         if (!args) return 0;
1786
1787         /* Isolate first and second arg */
1788         while(*ptr && !isspace(*ptr)) ++ptr;
1789         if ( *ptr )
1790         {
1791                 *ptr='\0';
1792                 arg2=ptr+1;
1793                 while(*arg2 && isspace(*arg2)) ++arg2;
1794         }
1795
1796         if (strcmp(arg1,"on")==0){
1797         int delay, tail_len, frame_size;
1798         int n;
1799
1800         linphone_core_enable_echo_cancellation(lc,1);
1801
1802         if (arg2 != 0) {
1803             n = sscanf(arg2, "%d %d %d", &delay, &tail_len, &frame_size);
1804
1805             if (n == 1) {   
1806                 lp_config_set_int(lc->config,"sound","ec_delay",delay);
1807             }
1808             else if (n == 2) {
1809                 lp_config_set_int(lc->config,"sound","ec_delay",delay);
1810                 lp_config_set_int(lc->config,"sound","ec_tail_len",tail_len);
1811             }
1812             else if (n == 3) {
1813                 lp_config_set_int(lc->config,"sound","ec_delay",delay);
1814                 lp_config_set_int(lc->config,"sound","ec_tail_len",tail_len);
1815                 lp_config_set_int(lc->config,"sound","ec_framesize",frame_size);
1816             }
1817         }
1818     }
1819     else if (strcmp(arg1,"off")==0){
1820         linphone_core_enable_echo_cancellation(lc,0);
1821     }
1822     else if (strcmp(arg1,"show")==0){
1823         linphonec_out("echo cancellation is %s; delay %d, tail length %d, frame size %d\n", 
1824             linphone_core_echo_cancellation_enabled(lc) ? "on" : "off",
1825             lp_config_get_int(lc->config,"sound","ec_delay",0),
1826             lp_config_get_int(lc->config,"sound","ec_tail_len",0),
1827             lp_config_get_int(lc->config,"sound","ec_framesize",0));        
1828     }
1829     else {
1830         return 0;
1831     }
1832
1833     return 1;
1834 }
1835
1836 static int lpc_cmd_mute_mic(LinphoneCore *lc, char *args)
1837 {
1838   if ( lc->call != NULL )
1839     linphone_core_mute_mic(lc, 1);
1840   return 1;
1841 }
1842
1843 static int lpc_cmd_unmute_mic(LinphoneCore *lc, char *args)
1844 {
1845   if ( lc->call != NULL )
1846     linphone_core_mute_mic(lc, 0);
1847   return 1;
1848 }
1849
1850 static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args)
1851 {
1852   bool_t rtp_xmit_off=FALSE;
1853   char *status;
1854   gstate_t call_state=linphone_core_get_state(lc,GSTATE_GROUP_CALL);
1855
1856   if(args){
1857     if(strstr(args,"1"))rtp_xmit_off=TRUE;
1858     if(call_state == GSTATE_CALL_IDLE)
1859       linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_xmit_off);
1860     else 
1861       linphonec_out("nortp-on-audio-mute: call in progress - cannot change state\n");
1862   }
1863   rtp_xmit_off=linphone_core_get_rtp_no_xmit_on_audio_mute(lc);
1864   if(rtp_xmit_off)status="off";
1865   else status="on";
1866   linphonec_out("rtp transmit %s when audio muted\n",status);
1867   return 1;
1868 }
1869
1870
1871 /***************************************************************************
1872  *
1873  *  Command table management funx
1874  *
1875  ***************************************************************************/
1876
1877 /*
1878  * Find a command given its name
1879  */
1880 static LPC_COMMAND *
1881 lpc_find_command(const char *name)
1882 {
1883         int i;
1884
1885         for (i=0; commands[i].name; ++i)
1886         {
1887                 if (strcmp(name, commands[i].name) == 0)
1888                         return &commands[i];
1889         }
1890
1891         return (LPC_COMMAND *)NULL;
1892 }
1893
1894
1895 /****************************************************************************
1896  *
1897  * $Log: commands.c,v $
1898  * Revision 1.39  2008/07/03 15:08:34  smorlat
1899  * api cleanups, interface in progress.
1900  *
1901  * Revision 1.38  2008/06/17 20:38:59  smorlat
1902  * added missing file.
1903  *
1904  * Revision 1.37  2008/04/09 09:26:00  smorlat
1905  * merge various patches
1906  * H264 support.
1907  *
1908  * Revision 1.36  2007/08/01 14:47:53  strk
1909  *         * console/commands.c: Clean up commands 'nat', 'stun'
1910  *           and 'firewall' to be more intuitive.
1911  *
1912  * Revision 1.35  2007/06/27 09:01:25  smorlat
1913  * logging improvements.
1914  *
1915  * Revision 1.34  2007/02/20 10:17:13  smorlat
1916  * linphonec friends patch2
1917  *
1918  * Revision 1.31  2006/09/22 07:22:47  smorlat
1919  * linphonecore api changes.
1920  *
1921  * Revision 1.30  2006/09/08 15:32:57  smorlat
1922  * support for using files instead of soundcard (used by linphonec only)
1923  *
1924  * Revision 1.29  2006/08/28 14:29:07  smorlat
1925  * fix bug.
1926  *
1927  * Revision 1.28  2006/08/21 12:49:59  smorlat
1928  * merged several little patches.
1929  *
1930  * Revision 1.27  2006/07/17 18:45:00  smorlat
1931  * support for several event queues in ortp.
1932  * glib dependency removed from coreapi/ and console/
1933  *
1934  * Revision 1.26  2006/04/14 15:16:36  smorlat
1935  * soundcard use did nothing !
1936  *
1937  * Revision 1.25  2006/04/06 20:09:33  smorlat
1938  * add linphonec command to see and select sound devices.
1939  *
1940  * Revision 1.24  2006/03/04 11:17:10  smorlat
1941  * mediastreamer2 in progress.
1942  *
1943  * Revision 1.23  2006/02/20 21:14:01  strk
1944  * Handled syntax errors with 'friend' command
1945  *
1946  * Revision 1.22  2006/02/20 10:20:29  strk
1947  * Added substring-based filter support for command 'friend list'
1948  *
1949  * Revision 1.21  2006/02/02 15:39:18  strk
1950  * - Added 'friend list' and 'friend call' commands
1951  * - Allowed for multiple DTFM send in a single line
1952  * - Added status-specific callback (bare version)
1953  *
1954  * Revision 1.20  2006/01/26 11:54:34  strk
1955  * More robust 'nat' command handler (strip blanks in args)
1956  *
1957  * Revision 1.19  2006/01/26 09:48:05  strk
1958  * Added limits.h include
1959  *
1960  * Revision 1.18  2006/01/26 02:18:05  strk
1961  * Added new commands 'nat use' and 'nat unuse'.
1962  * These will required a pending patch to linphonecore.c
1963  * in order to work.
1964  *
1965  * Revision 1.17  2006/01/20 14:12:33  strk
1966  * Added linphonec_init() and linphonec_finish() functions.
1967  * Handled SIGINT and SIGTERM to invoke linphonec_finish().
1968  * Handling of auto-termination (-t) moved to linphonec_finish().
1969  * Reworked main (input read) loop to not rely on 'terminate'
1970  * and 'run' variable (dropped). configfile_name allocated on stack
1971  * using PATH_MAX limit. Changed print_usage signature to allow
1972  * for an exit_status specification.
1973  *
1974  * Revision 1.16  2006/01/18 09:25:32  strk
1975  * Command completion inhibited in proxy addition and auth request prompts.
1976  * Avoided use of linphonec_readline's internal filename completion.
1977  *
1978  * Revision 1.15  2006/01/14 13:29:32  strk
1979  * Reworked commands interface to use a table structure,
1980  * used by command line parser and help function.
1981  * Implemented first level of completion (commands).
1982  * Added notification of invalid "answer" and "terminate"
1983  * commands (no incoming call, no active call).
1984  * Forbidden "call" intialization when a call is already active.
1985  * Cleaned up all commands, adding more feedback and error checks.
1986  *
1987  * Revision 1.14  2006/01/13 13:00:29  strk
1988  * Added linphonec.h. Code layout change (added comments, forward decl,
1989  * globals on top, copyright notices and Logs). Handled out-of-memory
1990  * condition on history management. Removed assumption on sizeof(char).
1991  * Fixed bug in authentication prompt (introduced by linphonec_readline).
1992  * Added support for multiple authentication requests (up to MAX_PENDING_AUTH).
1993  *
1994  *
1995  ****************************************************************************/