source: mediastreamer2/linphone/console/commands.c @ 266:ce389a286464

Last change on this file since 266:ce389a286464 was 266:ce389a286464, checked in by strk <strk@…>, 4 years ago

Improve help messages

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@269 3f6dc0c8-ddfe-455d-9043-3cd528dc4637

File size: 35.4 KB
Line 
1/****************************************************************************
2 *
3 *  $Id: commands.c,v 1.39 2008/07/03 15:08:34 smorlat Exp $
4 *
5 *  Copyright (C) 2006  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#include <errno.h>
30#include <limits.h>
31#include <ctype.h>
32#include <unistd.h>
33#include <linphonecore.h>
34#include "linphonec.h"
35
36/***************************************************************************
37 *
38 *  Forward declarations
39 *
40 ***************************************************************************/
41
42extern char *lpc_strip_blanks(char *input);
43
44/* Command handlers */
45static int lpc_cmd_help(LinphoneCore *, char *);
46static int lpc_cmd_proxy(LinphoneCore *, char *);
47static int lpc_cmd_call(LinphoneCore *, char *);
48static int lpc_cmd_answer(LinphoneCore *, char *);
49static int lpc_cmd_autoanswer(LinphoneCore *, char *);
50static int lpc_cmd_terminate(LinphoneCore *, char *);
51static int lpc_cmd_call_logs(LinphoneCore *, char *);
52static int lpc_cmd_ipv6(LinphoneCore *, char *);
53static int lpc_cmd_refer(LinphoneCore *, char *);
54static int lpc_cmd_quit(LinphoneCore *, char *);
55static int lpc_cmd_nat(LinphoneCore *, char *);
56static int lpc_cmd_stun(LinphoneCore *, char *);
57static int lpc_cmd_firewall(LinphoneCore *, char *);
58static int lpc_cmd_friend(LinphoneCore *, char*);
59static int lpc_cmd_soundcard(LinphoneCore *, char *);
60static int lpc_cmd_play(LinphoneCore *, char *);
61static int lpc_cmd_record(LinphoneCore *, char *);
62static int lpc_cmd_register(LinphoneCore *, char *);
63static int lpc_cmd_unregister(LinphoneCore *, char *);
64static int lpc_cmd_duration(LinphoneCore *lc, char *args);
65static int lpc_cmd_status(LinphoneCore *lc, char *args);
66
67/* Command handler helpers */
68static void linphonec_proxy_add(LinphoneCore *lc);
69static void linphonec_proxy_display(LinphoneProxyConfig *lc);
70static void linphonec_proxy_list(LinphoneCore *lc);
71static void linphonec_proxy_remove(LinphoneCore *lc, int index);
72static  int linphonec_proxy_use(LinphoneCore *lc, int index);
73static void linphonec_proxy_show(LinphoneCore *lc,int index);
74static void linphonec_friend_display(LinphoneFriend *fr);
75static int linphonec_friend_list(LinphoneCore *lc, char *arg);
76static void linphonec_display_command_help(LPC_COMMAND *cmd);
77static int linphonec_friend_call(LinphoneCore *lc, unsigned int num);
78static int linphonec_friend_add(LinphoneCore *lc, const char *name, const char *addr);
79static int linphonec_friend_delete(LinphoneCore *lc, int num);
80
81
82
83/* Command table management */
84static LPC_COMMAND *lpc_find_command(const char *name);
85
86void linphonec_out(const char *fmt,...);
87
88
89
90/***************************************************************************
91 *
92 *  Global variables
93 *
94 ***************************************************************************/
95
96/*
97 * Commands table.
98 */
99LPC_COMMAND commands[] = {
100        { "help", lpc_cmd_help, "Print commands help", NULL },
101        { "call", lpc_cmd_call, "Call a SIP uri",
102                "'call <sip-url>' or 'c <sip-url>' "
103                ": initiate a call to the specified destination."
104                },
105        { "terminate", lpc_cmd_terminate, "Terminate the current call",
106                NULL },
107        { "answer", lpc_cmd_answer, "Answer a call",
108                "Accept an incoming call."
109        },
110        { "autoanswer", lpc_cmd_autoanswer, "Enable auto-answer mode",
111                "'autoanswer enable'\t: enable autoanswer mode\n"
112                "'autoanswer disable'\t: disable autoanswer mode \n"},
113        { "proxy", lpc_cmd_proxy, "Manage proxies",
114                "'proxy list' : list all proxy setups.\n"
115                "'proxy add' : add a new proxy setup.\n"
116                "'proxy remove <index>' : remove proxy setup with number index.\n"
117                "'proxy use <index>' : use proxy with number index as default proxy.\n"
118                "'proxy unuse' : don't use a default proxy."
119                "'proxy show <index>' : show configuration and status of the proxy numbered by index.\n"
120                "'proxy show default' : show configuration and status of the default proxy.\n"
121        },
122        { "soundcard", lpc_cmd_soundcard, "Manage soundcards",
123                "'soundcard list' : list all sound devices.\n"
124                "'soundcard use <index>' : select a sound device.\n"
125                "'soundcard use files' : use .wav files instead of soundcard\n"
126        },
127        { "ipv6", lpc_cmd_ipv6, "Use IPV6",
128                "'ipv6 status' : show ipv6 usage status.\n"
129                "'ipv6 enable' : enable the use of the ipv6 network.\n"
130                "'ipv6 disable' : do not use ipv6 network."
131        },
132        { "refer", lpc_cmd_refer,
133                "Refer the current call to the specified destination.",
134                "'refer <sip-url>' or 'r <sip-url>' "
135                ": refer the current call to the specified destination."
136        },
137        { "nat", lpc_cmd_nat, "Set nat address",
138                "'nat'        : show nat settings.\n"
139                "'nat <addr>' : set nat address.\n"
140        },
141        { "stun", lpc_cmd_stun, "Set stun server address",
142                "'stun'        : show stun settings.\n"
143                "'stun <addr>' : set stun server address.\n"
144        },
145        { "firewall", lpc_cmd_firewall, "Set firewall policy",
146                "'firewall'        : show current firewall policy.\n"
147                "'firewall none'   : use direct connection.\n"
148                "'firewall nat'    : use nat address given with the 'nat' command.\n"
149                "'firewall stun'   : use stun server given with the 'stun' command.\n"
150        },
151        { "call-logs", lpc_cmd_call_logs, "Calls history",
152                NULL },
153        { "friend", lpc_cmd_friend, "Manage friends",
154                "'friend list [<pattern>]'    : list friends.\n"
155                "'friend call <index>'        : call a friend.\n"
156                "'friend add <name> <addr>'   : add friend, <name> must be quoted to include\n"
157            "                               spaces, <addr> has \"sip:\" added if it isn't\n"
158            "                               there.  Don't use '<' '>' around <addr>.\n"
159                "'friend delete <index>'      : remove friend, 'all' removes all\n"
160        },
161        { "play", lpc_cmd_play, "play from a wav file",
162                "This feature is available only in file mode (see 'help soundcard')\n"
163                "'play <wav file>'    : play a wav file."
164        },
165        { "record", lpc_cmd_record, "record to a wav file",
166                "This feature is available only in file mode (see 'help soundcard')\n"
167                "'record <wav file>'    : record into wav file."
168        },
169        { "quit", lpc_cmd_quit, "Exit linphonec", NULL },
170        { "register", lpc_cmd_register, "Register in one line to a proxy" , "register <sip identity> <sip proxy> <password>"},
171        { "unregister", lpc_cmd_unregister, "Unregister from default proxy", NULL       },
172        { "duration", lpc_cmd_duration, "Print duration in seconds of the last call.", NULL },
173        { "status", lpc_cmd_status, "Print various status information", 
174                        "'status register' \t: print status concerning registration\n"
175                        "'status autoanswer'\t: tell whether autoanswer mode is enabled\n"
176                        "'status hook' \t: print hook status\n" },
177                                       
178        { (char *)NULL, (lpc_cmd_handler)NULL, (char *)NULL, (char *)NULL }
179};
180
181/***************************************************************************
182 *
183 *  Public interface
184 *
185 ***************************************************************************/
186
187/*
188 * Main command dispatcher.
189 * WARNING: modifies second argument!
190 *
191 * Always return 1 currently.
192 */
193int
194linphonec_parse_command_line(LinphoneCore *lc, char *cl)
195{
196        char *ptr=cl;
197        char *args=NULL;
198        LPC_COMMAND *cmd;
199
200        /* Isolate first word and args */
201        while(*ptr && !isspace(*ptr)) ++ptr;
202        if (*ptr)
203        {
204                *ptr='\0';
205                /* set args to first nonblank */
206                args=ptr+1;
207                while(*args && isspace(*args)) ++args;
208        }
209
210        /* Handle DTMF */
211        if ( isdigit(*cl) || *cl == '#' || *cl == '*' )
212        {
213                while ( isdigit(*cl) || *cl == '#' || *cl == '*' )
214                {
215                        linphone_core_send_dtmf(lc, *cl);
216                        ms_sleep(1); // be nice
217                        ++cl;
218                }
219
220                // discard spurious trailing chars
221                return 1;
222        }
223
224        /* Handle other kind of commands */
225        cmd=lpc_find_command(cl);
226        if ( !cmd )
227        {
228                linphonec_out("'%s': Cannot understand this.\n", cl);
229                return 1;
230        }
231
232        if ( ! cmd->func(lc, args) )
233        {
234                linphonec_out("Syntax error.\n");
235                linphonec_display_command_help(cmd);
236        }
237
238        return 1;
239}
240
241/*
242 * Generator function for command completion.
243 * STATE let us know whether to start from scratch;
244 * without any state (STATE==0), then we start at the
245 * top of the list.
246 */
247char *
248linphonec_command_generator(const char *text, int state)
249{
250        static int index, len;
251        char *name;
252
253        if ( ! state )
254        {
255                index=0;
256                len=strlen(text);
257        }
258
259        /*
260         * Return the next name which partially matches
261         * from the commands list
262         */
263        while ((name=commands[index].name))
264        {
265                ++index; /* so next call get next command */
266
267                if (strncmp(name, text, len) == 0)
268                {
269                        return strdup(name);
270                }
271        }
272
273        return NULL;
274}
275
276
277/***************************************************************************
278 *
279 *  Command handlers
280 *
281 ***************************************************************************/
282
283static int
284lpc_cmd_help(LinphoneCore *lc, char *arg)
285{
286        int i=0;
287        LPC_COMMAND *cmd;
288
289        if (!arg || !*arg)
290        {
291                linphonec_out("Commands are:\n");
292                linphonec_out("---------------------------\n");
293
294                while (commands[i].help)
295                {
296                        linphonec_out("%10.10s\t%s\n", commands[i].name,
297                                commands[i].help);
298                        i++;
299                }
300               
301                linphonec_out("---------------------------\n");
302                linphonec_out("Type 'help <command>' for more details.\n");
303
304                return 1;
305        }
306
307        cmd=lpc_find_command(arg);
308        if ( !cmd )
309        {
310                linphonec_out("No such command.\n");
311                return 1;
312        }
313
314        linphonec_display_command_help(cmd);
315        return 1;
316
317}
318
319static char callee_name[256]={0};
320
321static int
322lpc_cmd_call(LinphoneCore *lc, char *args)
323{
324        if ( ! args || ! *args )
325        {
326                return 0;
327        }
328
329        if ( lc->call != NULL )
330        {
331                linphonec_out("Terminate current call first.\n");
332        }
333        else
334        {
335                if ( -1 == linphone_core_invite(lc, args) )
336                {
337                        linphonec_out("Error from linphone_core_invite.\n");
338                }
339                else
340                {
341                        snprintf(callee_name,sizeof(callee_name),"%s",args);
342                }
343        }
344        return 1;
345}
346
347static const char *linphonec_get_callee(){
348        return callee_name;
349}
350
351static int
352lpc_cmd_refer(LinphoneCore *lc, char *args)
353{
354        if (args)
355                linphone_core_refer(lc, args);
356        else{
357                linphonec_out("refer needs an argument\n");
358        }
359        return 1;
360}
361
362static int
363lpc_cmd_terminate(LinphoneCore *lc, char *args)
364{
365        if ( -1 == linphone_core_terminate_call(lc, NULL) )
366        {
367                linphonec_out("No active call.\n");
368        }
369        return 1;
370}
371
372static int
373lpc_cmd_answer(LinphoneCore *lc, char *args)
374{
375        if ( -1 == linphone_core_accept_call(lc, NULL) )
376        {
377                linphonec_out("No incoming call.\n");
378        }
379        return 1;
380}
381
382static int
383lpc_cmd_autoanswer(LinphoneCore *lc, char *args)
384{
385        if (strstr(args,"enable")){
386                linphonec_set_autoanswer(TRUE);
387        }else if (strstr(args,"disable")){
388                linphonec_set_autoanswer(FALSE);
389        }else return 0;
390        return 1;
391}
392
393static int
394lpc_cmd_quit(LinphoneCore *lc, char *args)
395{
396        linphonec_finish(EXIT_SUCCESS);
397        return 1;
398}
399
400static int
401lpc_cmd_nat(LinphoneCore *lc, char *args)
402{
403        bool_t use;
404        const char *nat;
405
406        if ( args ) args=lpc_strip_blanks(args);
407
408        if ( args && *args )
409        {
410                linphone_core_set_nat_address(lc, args);
411                /* linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_NAT_ADDRESS); */
412        }
413
414        nat = linphone_core_get_nat_address(lc);
415        use = linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS;
416        linphonec_out("Nat address: %s%s\n", nat ? nat : "unspecified" , use ? "" : " (disabled - use 'firewall nat' to enable)");
417
418        return 1;
419}
420
421static int
422lpc_cmd_stun(LinphoneCore *lc, char *args)
423{
424        bool_t use;
425        const char *stun;
426
427        if ( args ) args=lpc_strip_blanks(args);
428
429        if ( args && *args )
430        {
431                linphone_core_set_stun_server(lc, args);
432                /* linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_STUN); */
433        }
434
435        stun = linphone_core_get_stun_server(lc);
436        use = linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_STUN;
437        linphonec_out("Stun server: %s%s\n", stun ? stun : "unspecified" , use? "" : " (disabled - use 'firewall stun' to enable)");
438
439        return 1;
440}
441
442static int
443lpc_cmd_firewall(LinphoneCore *lc, char *args)
444{
445        const char* setting=NULL;
446
447        if ( args ) args=lpc_strip_blanks(args);
448
449        if ( args && *args )
450        {
451                if (strcmp(args,"none")==0)
452                {
453                        linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL);
454                }
455                else if (strcmp(args,"stun")==0)
456                {
457                        setting = linphone_core_get_stun_server(lc);
458                        if ( ! setting )
459                        {
460                                linphonec_out("No stun server address is defined, use 'stun <address>' first");
461                                return 1;
462                        }
463                        linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_STUN);
464                }
465                else if (strcmp(args,"nat")==0)
466                {
467                        setting = linphone_core_get_nat_address(lc);
468                        if ( ! setting )
469                        {
470                                linphonec_out("No nat address is defined, use 'nat <address>' first");
471                                return 1;
472                        }
473                        linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_NAT_ADDRESS);
474                }
475        }
476
477        switch(linphone_core_get_firewall_policy(lc))
478        {
479                case LINPHONE_POLICY_NO_FIREWALL:
480                        linphonec_out("No firewall\n");
481                        break;
482                case LINPHONE_POLICY_USE_STUN:
483                        linphonec_out("Using stun server %s to discover firewall address\n", setting ? setting : linphone_core_get_stun_server(lc));
484                        break;
485                case LINPHONE_POLICY_USE_NAT_ADDRESS:
486                        linphonec_out("Using supplied nat address %s.\n", setting ? setting : linphone_core_get_nat_address(lc));
487                        break;
488        }
489        return 1;
490}
491
492#ifndef WIN32
493/* Helper function for processing freind names */
494static int
495lpc_friend_name(char **args, char **name)
496{
497        /* Use space as a terminator unless quoted */
498        if (('"' == **args) || ('\'' == **args)){
499                char *end;
500                char delim = **args;
501                (*args)++;
502                end = (*args);
503                while ((delim != *end) && ('\0' != *end)) end++;
504                if ('\0' == *end) {
505                        fprintf(stderr, "Mismatched quotes\n");
506                        return 0;
507                }
508                *name = *args;
509                *end = '\0';
510                *args = ++end;
511        } else {
512                *name = strsep(args, " ");
513               
514                if (NULL == *args) { /* Means there was no separator */
515                        fprintf(stderr, "Either name or address is missing\n");
516                        return 0;
517                }
518                if (NULL == *name) return 0;
519        }
520        return 1;
521}
522#endif
523
524static int
525lpc_cmd_friend(LinphoneCore *lc, char *args)
526{
527        int friend_num;
528
529        if ( args ) args=lpc_strip_blanks(args);
530
531        if ( ! args || ! *args ) return 0;
532
533        if ( !strncmp(args, "list", 4) )
534        {
535                return linphonec_friend_list(lc, args+4);
536                return 1;
537        }
538        else if ( !strncmp(args, "call", 4) )
539        {
540                args+=4;
541                if ( ! *args ) return 0;
542                friend_num = strtol(args, NULL, 10);
543                if ( errno == ERANGE ) {
544                        linphonec_out("Invalid friend number\n");
545                        return 0;
546                }
547                linphonec_friend_call(lc, friend_num);
548                return 1;
549        }
550        else if ( !strncmp(args, "delete", 6) )
551        {
552                args+=6;
553                if ( ! *args ) return 0;
554                while (*args == ' ') args++;
555                if ( ! *args ) return 0;
556                if (!strncmp(args, "all", 3))
557                {
558                        friend_num = -1;
559                } 
560                else
561                {
562                        friend_num = strtol(args, NULL, 10);
563                        if ( errno == ERANGE ) {
564                                linphonec_out("Invalid friend number\n");
565                                return 0;
566                        }
567                }
568                linphonec_friend_delete(lc, friend_num);
569                return 1;
570        }
571        else if ( !strncmp(args, "add", 3) )
572        {
573#ifndef WIN32
574                char  *name;
575                char  addr[80];
576                char *addr_p = addr;
577                char *addr_orig;
578
579                args+=3;
580                if ( ! *args ) return 0;
581                while (*args == ' ') args++;
582                if ( ! *args ) return 0;
583
584                if (!lpc_friend_name(&args,  &name)) return 0;
585
586                while (*args == ' ') args++;
587                if ( ! *args ) return 0;
588                if (isdigit(*args)) {
589                        strcpy (addr, "sip:");
590                        addr_p = addr + strlen("sip:");
591                }
592                addr_orig = strsep(&args, " ");
593                if (1 >= strlen(addr_orig)) {
594                        fprintf(stderr, "A single-digit address is not valid\n");
595                        return 0;
596                }
597                strcpy(addr_p, addr_orig);
598                linphonec_friend_add(lc, name, addr);
599#else
600                LinphoneFriend *new_friend;
601                new_friend = linphone_friend_new_with_addr(args);
602                linphone_core_add_friend(lc, new_friend);
603#endif
604                return 1;
605        }
606        return 0;
607}
608
609static int lpc_cmd_play(LinphoneCore *lc, char *args){
610        if ( args ) args=lpc_strip_blanks(args);
611        if ( ! args || ! *args ) return 0;
612        linphone_core_set_play_file(lc,args);
613        return 1;
614}
615
616static int lpc_cmd_record(LinphoneCore *lc, char *args){
617        if ( args ) args=lpc_strip_blanks(args);
618        if ( ! args || ! *args ) return 0;
619        linphone_core_set_record_file(lc,args);
620        return 1;
621}
622
623/*
624 * Modified input
625 */
626static int
627lpc_cmd_proxy(LinphoneCore *lc, char *args)
628{
629        char *arg1 = args;
630        char *arg2 = NULL;
631        char *ptr = args;
632        int proxynum;
633
634        if ( ! arg1 ) return 0;
635
636        /* Isolate first and second arg */
637        while(*ptr && !isspace(*ptr)) ++ptr;
638        if ( *ptr )
639        {
640                *ptr='\0';
641                arg2=ptr+1;
642                while(*arg2 && isspace(*arg2)) ++arg2;
643        }
644
645        if (strcmp(arg1,"add")==0)
646        {
647#ifdef HAVE_READLINE
648                rl_inhibit_completion=1;
649#endif
650                linphonec_proxy_add(lc);
651#ifdef HAVE_READLINE
652                rl_inhibit_completion=0;
653#endif
654        }
655        else if (strcmp(arg1,"list")==0)
656        {
657                linphonec_proxy_list(lc);
658        }
659        else if (strcmp(arg1,"remove")==0)
660        {
661                linphonec_proxy_remove(lc,atoi(arg2));
662        }
663        else if (strcmp(arg1,"use")==0)
664        {
665                if ( arg2 && *arg2 )
666                {
667                        proxynum=atoi(arg2);
668                        if ( linphonec_proxy_use(lc, proxynum) )
669                                linphonec_out("Default proxy set to %d.\n", proxynum);
670                }
671                else
672                {
673                        proxynum=linphone_core_get_default_proxy(lc, NULL);
674                        if ( proxynum == -1 ) linphonec_out("No default proxy.\n");
675                        else linphonec_out("Current default proxy is %d.\n", proxynum);
676                }
677        }else if (strcmp(arg1, "unuse")==0){
678                linphone_core_set_default_proxy(lc, NULL);
679                linphonec_out("Use no proxy.\n");
680        }else if (strcmp(arg1,"show")==0){
681                if (arg2 && *arg2){
682                        if (strstr(arg2,"default")==0){
683                                proxynum=linphone_core_get_default_proxy(lc, NULL);
684                                linphonec_proxy_show(lc,proxynum);
685                        }else linphonec_proxy_show(lc,atoi(arg2));
686                }
687        }else
688        {
689                linphonec_out("Syntax error - see 'help proxy'\n");
690        }
691
692        return 1;
693}
694
695static int
696lpc_cmd_call_logs(LinphoneCore *lc, char *args)
697{
698        MSList *elem=linphone_core_get_call_logs(lc);
699        for (;elem!=NULL;elem=ms_list_next(elem))
700        {
701                LinphoneCallLog *cl=(LinphoneCallLog*)elem->data;
702                char *str=linphone_call_log_to_str(cl);
703                linphonec_out("%s\n",str);
704                ms_free(str);
705        }
706        return 1;
707}
708
709static int
710lpc_cmd_ipv6(LinphoneCore *lc, char *arg1)
711{
712        if ( ! arg1 )
713        {
714                linphonec_out("Syntax error - see 'help ipv6'\n");
715                return 1;
716        }
717
718        if (strcmp(arg1,"status")==0)
719        {
720                linphonec_out("ipv6 use enabled: %s\n",linphone_core_ipv6_enabled(lc) ? "true":"false");
721        }
722        else if (strcmp(arg1,"enable")==0)
723        {
724                linphone_core_enable_ipv6(lc,TRUE);
725                linphonec_out("ipv6 use enabled.\n");
726        }
727        else if (strcmp(arg1,"disable")==0)
728        {
729                linphone_core_enable_ipv6(lc,FALSE);
730                linphonec_out("ipv6 use disabled.\n");
731        }
732        else
733        {
734                linphonec_out("Syntax error - see 'help ipv6'\n");
735        }
736        return 1;
737}
738
739static int lpc_cmd_soundcard(LinphoneCore *lc, char *cmd){
740        int i;
741        if (cmd==NULL){
742                linphonec_out("Syntax error - see 'help soundcard'\n");
743                return 1;
744        }
745        if (strcmp(cmd,"list")==0){
746                const char **dev=linphone_core_get_sound_devices(lc);
747                for(i=0;dev[i]!=NULL;i++){
748                        linphonec_out("%i: %s\n",i,dev[i]);
749                }
750                return 1;
751        }else{
752                char *tmp=alloca(strlen(cmd)+1);
753                char *card=alloca(strlen(cmd)+1);
754                int index;
755                int n=sscanf(cmd,"%s %s",tmp,card);
756                if (n==2 && strcmp(tmp,"use")==0){
757                        if (strcmp(card,"files")==0) {
758                                linphonec_out("Using wav files instead of soundcard.\n");
759                                linphone_core_use_files(lc,TRUE);
760                                return 1;
761                        }else{
762                                const char **dev=linphone_core_get_sound_devices(lc);
763                                index=atoi(card);
764                                for(i=0;dev[i]!=NULL;i++){
765                                        if (i==index){
766                                                linphone_core_set_ringer_device(lc,dev[i]);
767                                                linphone_core_set_playback_device(lc,dev[i]);
768                                                linphone_core_set_capture_device(lc,dev[i]);
769                                                linphonec_out("Using sound device %s\n",dev[i]);
770                                                return 1;
771                                        }
772                                }
773                                linphonec_out("no such sound device\n");
774                                return 1;
775                        }
776                }
777                linphonec_out("Syntax error - see 'help soundcard'\n");
778        }
779        return 1;
780}
781
782/***************************************************************************
783 *
784 *  Commands helper functions
785 *
786 ***************************************************************************/
787
788
789static void
790linphonec_proxy_add(LinphoneCore *lc)
791{
792        bool_t enable_register=FALSE;
793        LinphoneProxyConfig *cfg;
794
795        linphonec_out("Adding new proxy setup. Hit ^D to abort.\n");
796
797        /*
798         * SIP Proxy address
799         */
800        while (1)
801        {
802                char *input=linphonec_readline("Enter proxy sip address: ");
803                char *clean;
804
805                if ( ! input ) {
806                        linphonec_out("Aborted.\n");
807                        return;
808                }
809
810                /* Strip blanks */
811                clean=lpc_strip_blanks(input);
812                if ( ! *clean ) {
813                        free(input);
814                        continue;
815                }
816
817                cfg=linphone_proxy_config_new();
818                if (linphone_proxy_config_set_server_addr(cfg,clean)<0)
819                {
820                        linphonec_out("Invalid sip address (sip:sip.domain.tld).\n");
821                        free(input);
822                        linphone_proxy_config_destroy(cfg);
823                        continue;
824                }
825                free(input);
826                break;
827        }
828
829        /*
830         * SIP Proxy identity
831         */
832        while (1)
833        {
834                char *input=linphonec_readline("Your identity for this proxy: ");
835                char *clean;
836
837                if ( ! input ) {
838                        linphonec_out("Aborted.\n");
839                        linphone_proxy_config_destroy(cfg);
840                        return;
841                }
842
843                /* Strip blanks */
844                clean=lpc_strip_blanks(input);
845                if ( ! *clean ) {
846                        free(input);
847                        continue;
848                }
849
850                linphone_proxy_config_set_identity(cfg, clean);
851                if ( ! cfg->reg_identity )
852                {
853                        linphonec_out("Invalid identity (sip:name@sip.domain.tld).\n");
854                        free(input);
855                        continue;
856                }
857                free(input);
858                break;
859        }
860
861        /*
862         * SIP Proxy enable register
863         */
864        while (1)
865        {
866                char *input=linphonec_readline("Do you want to register on this proxy (yes/no): ");
867                char *clean;
868
869                if ( ! input ) {
870                        linphonec_out("Aborted.\n");
871                        linphone_proxy_config_destroy(cfg);
872                        return;
873                }
874
875                /* Strip blanks */
876                clean=lpc_strip_blanks(input);
877                if ( ! *clean ) {
878                        free(input);
879                        continue;
880                }
881
882                if ( ! strcmp(clean, "yes") ) enable_register=TRUE;
883                else if ( ! strcmp(clean, "no") ) enable_register=FALSE;
884                else {
885                        linphonec_out("Please answer with 'yes' or 'no'\n");
886                        free(input);
887                        continue;
888                }
889                linphone_proxy_config_enableregister(cfg, enable_register);
890                free(input);
891                break;
892        }
893
894        /*
895         * SIP Proxy registration expiration
896         */
897        if ( enable_register==TRUE )
898        {
899                long int expires=0;
900                while (1)
901                {
902                        char *input=linphonec_readline("Specify register expiration time"
903                                " in seconds (default is 600): ");
904
905                        if ( ! input ) {
906                                linphonec_out("Aborted.\n");
907                                linphone_proxy_config_destroy(cfg);
908                                return;
909                        }
910
911                        expires=strtol(input, (char **)NULL, 10);
912                        if ( expires == LONG_MIN || expires == LONG_MAX )
913                        {
914                                linphonec_out("Invalid value: %s\n", strerror(errno));
915                                free(input);
916                                continue;
917                        }
918
919                        linphone_proxy_config_expires(cfg, expires);
920                        linphonec_out("Expiration: %d seconds\n", cfg->expires);
921
922                        free(input);
923                        break;
924                }
925        }
926
927        /*
928         * SIP proxy route
929         */
930        while (1)
931        {
932                char *input=linphonec_readline("Specify route if needed: ");
933                char *clean;
934
935                if ( ! input ) {
936                        linphonec_out("Aborted.\n");
937                        linphone_proxy_config_destroy(cfg);
938                        return;
939                }
940
941                /* Strip blanks */
942                clean=lpc_strip_blanks(input);
943                if ( ! *clean ) {
944                        free(input);
945                        linphonec_out("No route specified.\n");
946                        break;
947                }
948
949                linphone_proxy_config_set_route(cfg, clean);
950                if ( ! cfg->reg_route )
951                {
952                        linphonec_out("Invalid route.\n");
953                        free(input);
954                        continue;
955                }
956
957                free(input);
958                break;
959        }
960
961        /*
962         * Final confirmation
963         */
964        while (1)
965        {
966                char *input;
967                char *clean;
968
969                linphonec_out("--------------------------------------------\n");
970                linphonec_proxy_display(cfg);
971                linphonec_out("--------------------------------------------\n");
972                input=linphonec_readline("Accept the above proxy configuration (yes/no) ?: ");
973
974
975                if ( ! input ) {
976                        linphonec_out("Aborted.\n");
977                        linphone_proxy_config_destroy(cfg);
978                        return;
979                }
980
981                /* Strip blanks */
982                clean=lpc_strip_blanks(input);
983                if ( ! *clean ) {
984                        free(input);
985                        continue;
986                }
987
988                if ( ! strcmp(clean, "yes") ) break;
989                else if ( ! strcmp(clean, "no") )
990                {
991                        linphonec_out("Declined.\n");
992                        linphone_proxy_config_destroy(cfg);
993                        free(input);
994                        return;
995                }
996
997                linphonec_out("Please answer with 'yes' or 'no'\n");
998                free(input);
999                continue;
1000        }
1001
1002
1003        linphone_core_add_proxy_config(lc,cfg);
1004
1005        /* automatically set the last entered proxy as the default one */
1006        linphone_core_set_default_proxy(lc,cfg);
1007
1008        linphonec_out("Proxy added.\n");
1009}
1010
1011static void
1012linphonec_proxy_display(LinphoneProxyConfig *cfg)
1013{
1014        linphonec_out("sip address: %s\nroute: %s\nidentity: %s\nregister: %s\nexpires: %i\nregistered: %s\n",
1015                        cfg->reg_proxy,
1016                        (cfg->reg_route!=NULL)?cfg->reg_route:"",
1017                        (cfg->reg_identity!=NULL)?cfg->reg_identity:"",
1018                        (cfg->reg_sendregister)?"yes":"no",
1019                        cfg->expires,
1020                        linphone_proxy_config_is_registered(cfg) ? "yes" : "no");
1021}
1022
1023static void linphonec_proxy_show(LinphoneCore *lc, int index){
1024        const MSList *elem;
1025        int i;
1026        for(elem=linphone_core_get_proxy_config_list(lc),i=0;elem!=NULL;elem=elem->next,++i){
1027                if (index==i){
1028                        LinphoneProxyConfig *cfg=(LinphoneProxyConfig *)elem->data;
1029                        linphonec_proxy_display(cfg);
1030                        return;
1031                }
1032        }
1033        linphonec_out("No proxy with index %i",index);
1034}
1035
1036static void
1037linphonec_proxy_list(LinphoneCore *lc)
1038{
1039        const MSList *proxies;
1040        int n;
1041        int def=linphone_core_get_default_proxy(lc,NULL);
1042       
1043        proxies=linphone_core_get_proxy_config_list(lc);
1044        for(n=0;proxies!=NULL;proxies=ms_list_next(proxies),n++){
1045                if (n==def)
1046                        linphonec_out("****** Proxy %i - this is the default one - *******\n",n);
1047                else 
1048                        linphonec_out("****** Proxy %i *******\n",n);
1049                linphonec_proxy_display((LinphoneProxyConfig*)proxies->data);
1050        }
1051}
1052
1053static void
1054linphonec_proxy_remove(LinphoneCore *lc, int index)
1055{
1056        const MSList *proxies;
1057        LinphoneProxyConfig *cfg;
1058        proxies=linphone_core_get_proxy_config_list(lc);
1059        cfg=(LinphoneProxyConfig*)ms_list_nth_data(proxies,index);
1060        if (cfg==NULL){
1061                linphonec_out("No such proxy.\n");
1062                return;
1063        }
1064        linphone_core_remove_proxy_config(lc,cfg);
1065        linphonec_out("Proxy %s removed.\n", cfg->reg_proxy);
1066        linphone_proxy_config_destroy(cfg);
1067}
1068
1069static int
1070linphonec_proxy_use(LinphoneCore *lc, int index)
1071{
1072        const MSList *proxies;
1073        LinphoneProxyConfig *cfg;
1074        proxies=linphone_core_get_proxy_config_list(lc);
1075        cfg=(LinphoneProxyConfig*)ms_list_nth_data(proxies,index);
1076        if (cfg==NULL){
1077                linphonec_out("No such proxy (try 'proxy list').");
1078                return 0;
1079        }
1080        linphone_core_set_default_proxy(lc,cfg);
1081        return 1;
1082}
1083
1084static void
1085linphonec_friend_display(LinphoneFriend *fr)
1086{
1087        char *name = linphone_friend_get_name(fr);
1088        char *addr = linphone_friend_get_addr(fr);
1089        //char *url = linphone_friend_get_url(fr);
1090
1091        linphonec_out("name: %s\n", name);
1092        linphonec_out("address: %s\n", addr);
1093}
1094
1095static int
1096linphonec_friend_list(LinphoneCore *lc, char *pat)
1097{
1098        const MSList *friend;
1099        int n;
1100
1101        if (pat) {
1102                pat=lpc_strip_blanks(pat);
1103                if (!*pat) pat = NULL;
1104        }
1105
1106        friend = linphone_core_get_friend_list(lc);
1107        for(n=0; friend!=NULL; friend=ms_list_next(friend), ++n )
1108        {
1109                if ( pat ) {
1110                        char *name = linphone_friend_get_name(friend->data);
1111                        if ( ! strstr(name, pat) ) continue;
1112                }
1113                linphonec_out("****** Friend %i *******\n",n);
1114                linphonec_friend_display((LinphoneFriend*)friend->data);
1115        }
1116
1117        return 1;
1118}
1119
1120static int
1121linphonec_friend_call(LinphoneCore *lc, unsigned int num)
1122{
1123        const MSList *friend = linphone_core_get_friend_list(lc);
1124        unsigned int n;
1125        char *addr;
1126
1127        for(n=0; friend!=NULL; friend=ms_list_next(friend), ++n )
1128        {
1129                if ( n == num )
1130                {
1131                        addr = linphone_friend_get_addr(friend->data);
1132                        return lpc_cmd_call(lc, addr);
1133                }
1134        }
1135        linphonec_out("No such friend %u\n", num);
1136        return 1;
1137}
1138
1139static int
1140linphonec_friend_add(LinphoneCore *lc, const char *name, const char *addr)
1141{
1142        LinphoneFriend *newFriend;
1143
1144        char url[PATH_MAX];
1145
1146        snprintf(url, PATH_MAX, "%s <%s>", name, addr);
1147        newFriend = linphone_friend_new_with_addr(url);
1148        linphone_core_add_friend(lc, newFriend);
1149        return 0;
1150}
1151
1152static int
1153linphonec_friend_delete(LinphoneCore *lc, int num)
1154{
1155        const MSList *friend = linphone_core_get_friend_list(lc);
1156        unsigned int n;
1157
1158        for(n=0; friend!=NULL; friend=ms_list_next(friend), ++n )
1159        {
1160                if ( n == num )
1161                {
1162                        linphone_core_remove_friend(lc, friend->data);
1163                        return 0;
1164                }
1165        }
1166
1167        if (-1 == num) 
1168        {
1169                unsigned int i;
1170                for (i = 0 ; i < n ; i++)
1171                        linphonec_friend_delete(lc, 0);
1172                return 0;
1173        }
1174
1175        linphonec_out("No such friend %u\n", num);
1176        return 1;
1177}
1178
1179static void
1180linphonec_display_command_help(LPC_COMMAND *cmd)
1181{
1182        if ( cmd->doc ) linphonec_out ("%s\n", cmd->doc);
1183        else linphonec_out("%s\n", cmd->help);
1184}
1185
1186
1187static int lpc_cmd_register(LinphoneCore *lc, char *args){
1188        char identity[512];
1189        char proxy[512];
1190        char passwd[512];
1191        LinphoneProxyConfig *cfg;
1192        const MSList *elem;
1193        passwd[0]=proxy[0]=identity[0]='\0';
1194        sscanf(args,"%s %s %s",identity,proxy,passwd);
1195        if (proxy[0]=='\0' || identity[0]=='\0'){
1196                linphonec_out("Missing parameters, see help register\n");
1197                return 1;
1198        }
1199        if (passwd[0]!='\0'){
1200                osip_from_t *from;
1201                LinphoneAuthInfo *info;
1202                osip_from_init(&from);
1203                if (osip_from_parse(from,identity)==0){
1204                        info=linphone_auth_info_new(from->url->username,NULL,passwd,NULL,NULL);
1205                        linphone_core_add_auth_info(lc,info);
1206                }
1207                osip_from_free(from);
1208        }
1209        elem=linphone_core_get_proxy_config_list(lc);
1210        if (elem) {
1211                cfg=(LinphoneProxyConfig*)elem->data;
1212                linphone_proxy_config_edit(cfg);
1213        }
1214        else cfg=linphone_proxy_config_new();
1215        linphone_proxy_config_set_identity(cfg,identity);
1216        linphone_proxy_config_set_server_addr(cfg,proxy);
1217        linphone_proxy_config_enable_register(cfg,TRUE);
1218        if (elem) linphone_proxy_config_done(cfg);
1219        else linphone_core_add_proxy_config(lc,cfg);
1220        linphone_core_set_default_proxy(lc,cfg);
1221        return 1;
1222}
1223
1224static int lpc_cmd_unregister(LinphoneCore *lc, char *args){
1225        LinphoneProxyConfig *cfg=NULL;
1226        linphone_core_get_default_proxy(lc,&cfg);
1227        if (cfg && linphone_proxy_config_is_registered(cfg)) {
1228                linphone_proxy_config_edit(cfg);
1229                linphone_proxy_config_enable_register(cfg,FALSE);
1230                linphone_proxy_config_done(cfg);
1231        }else{
1232                linphonec_out("unregistered\n");
1233        }
1234        return 1;
1235}
1236
1237static int lpc_cmd_duration(LinphoneCore *lc, char *args){
1238        LinphoneCallLog *cl;
1239        const MSList *elem=linphone_core_get_call_logs(lc);
1240        for(;elem!=NULL;elem=elem->next){
1241                if (elem->next==NULL){
1242                        cl=(LinphoneCallLog*)elem->data;
1243                        linphonec_out("%i seconds\n",cl->duration);
1244                }
1245        }
1246        return 1;
1247}
1248
1249static int lpc_cmd_status(LinphoneCore *lc, char *args){
1250        LinphoneProxyConfig *cfg;
1251        linphone_core_get_default_proxy(lc,&cfg);
1252        if (strstr(args,"register")){
1253                if (cfg){
1254                        if (linphone_proxy_config_is_registered(cfg)){
1255                                linphonec_out("registered, identity=%s duration=%i\n",
1256                                        linphone_proxy_config_get_identity(cfg),
1257                                        linphone_proxy_config_get_expires(cfg));
1258                        }else if (linphone_proxy_config_register_enabled(cfg)){
1259                                linphonec_out("registered=-1\n");
1260                        }else linphonec_out("registered=0\n");
1261                }else linphonec_out("registered=0\n");
1262        }else if (strstr(args,"autoanswer")){
1263                if (cfg && linphone_proxy_config_is_registered(cfg))
1264                        linphonec_out("autoanswer=%i\n",linphonec_get_autoanswer());
1265                else linphonec_out("unregistered\n");
1266        }else if (strstr(args,"hook")){
1267                gstate_t call_state=linphone_core_get_state(lc,GSTATE_GROUP_CALL);
1268                if (!cfg || !linphone_proxy_config_is_registered(cfg)){
1269                        linphonec_out("unregistered\n");
1270                        return 1;
1271                }
1272                switch(call_state){
1273                        case GSTATE_CALL_OUT_INVITE:
1274                                linphonec_out("hook=dialing\n");
1275                        break;
1276                        case GSTATE_CALL_IDLE:
1277                                linphonec_out("hook=offhook\n");
1278                        break;
1279                        case GSTATE_CALL_OUT_CONNECTED:
1280                                linphonec_out("Call out, hook=%s duration=%i\n", linphonec_get_callee(),
1281                                        linphone_core_get_current_call_duration(lc));
1282                        break;
1283                        case GSTATE_CALL_IN_CONNECTED:
1284                                linphonec_out("hook=answered duration=%i\n" ,
1285                                        linphone_core_get_current_call_duration(lc));
1286                        default:
1287                                break;
1288                }
1289               
1290        }else return 0;
1291        return 1;
1292}
1293
1294/***************************************************************************
1295 *
1296 *  Command table management funx
1297 *
1298 ***************************************************************************/
1299
1300/*
1301 * Find a command given its name
1302 */
1303static LPC_COMMAND *
1304lpc_find_command(const char *name)
1305{
1306        int i;
1307
1308        for (i=0; commands[i].name; ++i)
1309        {
1310                if (strcmp(name, commands[i].name) == 0)
1311                        return &commands[i];
1312        }
1313
1314        return (LPC_COMMAND *)NULL;
1315}
1316
1317
1318/****************************************************************************
1319 *
1320 * $Log: commands.c,v $
1321 * Revision 1.39  2008/07/03 15:08:34  smorlat
1322 * api cleanups, interface in progress.
1323 *
1324 * Revision 1.38  2008/06/17 20:38:59  smorlat
1325 * added missing file.
1326 *
1327 * Revision 1.37  2008/04/09 09:26:00  smorlat
1328 * merge various patches
1329 * H264 support.
1330 *
1331 * Revision 1.36  2007/08/01 14:47:53  strk
1332 *         * console/commands.c: Clean up commands 'nat', 'stun'
1333 *           and 'firewall' to be more intuitive.
1334 *
1335 * Revision 1.35  2007/06/27 09:01:25  smorlat
1336 * logging improvements.
1337 *
1338 * Revision 1.34  2007/02/20 10:17:13  smorlat
1339 * linphonec friends patch2
1340 *
1341 * Revision 1.31  2006/09/22 07:22:47  smorlat
1342 * linphonecore api changes.
1343 *
1344 * Revision 1.30  2006/09/08 15:32:57  smorlat
1345 * support for using files instead of soundcard (used by linphonec only)
1346 *
1347 * Revision 1.29  2006/08/28 14:29:07  smorlat
1348 * fix bug.
1349 *
1350 * Revision 1.28  2006/08/21 12:49:59  smorlat
1351 * merged several little patches.
1352 *
1353 * Revision 1.27  2006/07/17 18:45:00  smorlat
1354 * support for several event queues in ortp.
1355 * glib dependency removed from coreapi/ and console/
1356 *
1357 * Revision 1.26  2006/04/14 15:16:36  smorlat
1358 * soundcard use did nothing !
1359 *
1360 * Revision 1.25  2006/04/06 20:09:33  smorlat
1361 * add linphonec command to see and select sound devices.
1362 *
1363 * Revision 1.24  2006/03/04 11:17:10  smorlat
1364 * mediastreamer2 in progress.
1365 *
1366 * Revision 1.23  2006/02/20 21:14:01  strk
1367 * Handled syntax errors with 'friend' command
1368 *
1369 * Revision 1.22  2006/02/20 10:20:29  strk
1370 * Added substring-based filter support for command 'friend list'
1371 *
1372 * Revision 1.21  2006/02/02 15:39:18  strk
1373 * - Added 'friend list' and 'friend call' commands
1374 * - Allowed for multiple DTFM send in a single line
1375 * - Added status-specific callback (bare version)
1376 *
1377 * Revision 1.20  2006/01/26 11:54:34  strk
1378 * More robust 'nat' command handler (strip blanks in args)
1379 *
1380 * Revision 1.19  2006/01/26 09:48:05  strk
1381 * Added limits.h include
1382 *
1383 * Revision 1.18  2006/01/26 02:18:05  strk
1384 * Added new commands 'nat use' and 'nat unuse'.
1385 * These will required a pending patch to linphonecore.c
1386 * in order to work.
1387 *
1388 * Revision 1.17  2006/01/20 14:12:33  strk
1389 * Added linphonec_init() and linphonec_finish() functions.
1390 * Handled SIGINT and SIGTERM to invoke linphonec_finish().
1391 * Handling of auto-termination (-t) moved to linphonec_finish().
1392 * Reworked main (input read) loop to not rely on 'terminate'
1393 * and 'run' variable (dropped). configfile_name allocated on stack
1394 * using PATH_MAX limit. Changed print_usage signature to allow
1395 * for an exit_status specification.
1396 *
1397 * Revision 1.16  2006/01/18 09:25:32  strk
1398 * Command completion inhibited in proxy addition and auth request prompts.
1399 * Avoided use of linphonec_readline's internal filename completion.
1400 *
1401 * Revision 1.15  2006/01/14 13:29:32  strk
1402 * Reworked commands interface to use a table structure,
1403 * used by command line parser and help function.
1404 * Implemented first level of completion (commands).
1405 * Added notification of invalid "answer" and "terminate"
1406 * commands (no incoming call, no active call).
1407 * Forbidden "call" intialization when a call is already active.
1408 * Cleaned up all commands, adding more feedback and error checks.
1409 *
1410 * Revision 1.14  2006/01/13 13:00:29  strk
1411 * Added linphonec.h. Code layout change (added comments, forward decl,
1412 * globals on top, copyright notices and Logs). Handled out-of-memory
1413 * condition on history management. Removed assumption on sizeof(char).
1414 * Fixed bug in authentication prompt (introduced by linphonec_readline).
1415 * Added support for multiple authentication requests (up to MAX_PENDING_AUTH).
1416 *
1417 *
1418 ****************************************************************************/
Note: See TracBrowser for help on using the repository browser.