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