]> sjero.net Git - linphone/blob - console/shell.c
Aac-eld add missing header according to RFC3640 3.3.6
[linphone] / console / shell.c
1 /****************************************************************************
2  *  Copyright (C) 2009  Simon MORLAT <simon.morlat@linphone.org>
3  *
4  ****************************************************************************
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  ****************************************************************************/
21
22
23 #include <stdio.h>
24 #include <stdlib.h>
25
26
27 #ifdef WIN32
28 #include <windows.h>
29 #include <winbase.h>
30 #include <ws2tcpip.h>
31 #include <ctype.h>
32 #include <conio.h>
33 #else
34 #include <sys/socket.h>
35 #include <netdb.h>
36 #include <sys/un.h>
37
38 #endif
39
40 #include "ortp/ortp.h"
41
42 #define DEFAULT_REPLY_SIZE 4096
43
44 #define STATUS_REGISTERED (1<<0)
45 #define STATUS_REGISTERING (1<<1)
46 #define STATUS_DIALING (1<<2)
47 #define STATUS_AUTOANSWER (1<<3)
48 #define STATUS_IN_CONNECTED (1<<4) /* incoming call accepted */
49 #define STATUS_OUT_CONNECTED (1<<5) /*outgoing call accepted */
50
51
52 static int make_status_value(const char *status_string){
53         int ret=0;
54         if (strstr(status_string,"registered, identity=")){
55                 ret|=STATUS_REGISTERED;
56         }
57         if (strstr(status_string,"registered=-1")){
58                 ret|=STATUS_REGISTERING;
59         }
60         if (strstr(status_string,"autoanswer=1")){
61                 ret|=STATUS_AUTOANSWER;
62         }
63         if (strstr(status_string,"dialing")){
64                 ret|=STATUS_DIALING;
65         }
66         if (strstr(status_string,"Call out")){
67                 ret|=STATUS_OUT_CONNECTED;
68         }
69         if (strstr(status_string,"hook=answered")){
70                 ret|=STATUS_IN_CONNECTED;
71         }
72         return ret;
73 }
74
75 static int send_command(const char *command, char *reply, int reply_len, int print_errors){
76         ortp_pipe_t pp;
77         int i;
78         int err;
79         char path[128];
80 #ifndef WIN32
81         snprintf(path,sizeof(path)-1,"linphonec-%i",getuid());
82 #else
83         {
84                 char username[128];
85                 DWORD size=sizeof(username)-1;
86                 GetUserName(username,&size);
87                 snprintf(path,sizeof(path)-1,"linphonec-%s",username);
88         }
89 #endif
90         if ((pp=ortp_client_pipe_connect(path))==ORTP_PIPE_INVALID){
91                 if (print_errors) fprintf(stderr,"ERROR: Failed to connect pipe: %s\n",strerror(errno));
92                 return -1;
93         }
94         if (ortp_pipe_write(pp,(uint8_t*)command,strlen(command))==-1){
95                 if (print_errors) fprintf(stderr,"ERROR: Fail to send command to remote linphonec\n");
96                 ortp_client_pipe_close(pp);
97                 return -1;
98         }
99         /*wait for replies */
100         i=0;
101         while ((err=ortp_pipe_read(pp,(uint8_t*)&reply[i],reply_len-i-1))>0){
102                 i+=err;
103         }
104         reply[i]='\0';
105         ortp_client_pipe_close(pp);
106         return 0;
107 }
108
109 static void print_usage(void){
110         fprintf(stderr,"Usage:\nlinphonecsh <action> [arguments]\n"
111                         "where action is one of\n"
112                         "\tinit\t\t: spawn a linphonec daemon (first step to make other actions)\n"
113                         "\t\t\tfollowed by the arguments sent to linphonec\n"
114                         "\tgeneric\t\t: sends a generic command to the running linphonec daemon\n"
115                         "\t\t\tfollowed by the generic command surrounded by quotes,\n\t\t\t for example \"call sip:joe@example.net\"\n"
116                         "\tregister\t: register; arguments are \n\t\t\t--host <host>\n\t\t\t--username <username>\n\t\t\t--password <password>\n"
117                         "\tunregister\t: unregister\n"
118                         "\tdial\t\t: dial <sip uri or number>\n"
119                         "\tstatus\t\t: can be 'status register', 'status autoanswer' or 'status hook'\n"
120                         "\tsoundcard\t: can be 'soundcard capture', 'soundcard playback', 'soundcard ring',\n"
121                         "\t\t\t followed by an optional number representing the index of the soundcard,\n"
122                         "\t\t\t in which case the soundcard is set instead of just read.\n"
123                         "\texit\t\t: make the linphonec daemon to exit.\n"
124         );
125         exit(-1);
126 }
127
128 #define MAX_ARGS 10
129
130 #ifndef WIN32
131 static void spawn_linphonec(int argc, char *argv[]){
132         char * args[10];
133         int i,j;
134         pid_t pid;
135         j=0;
136         args[j++]="linphonec";
137         args[j++]="--pipe";
138         args[j++]="-c";
139         args[j++]="/dev/null";
140         for(i=0;i<argc;++i){
141                 args[j++]=argv[i];
142         }
143         args[j++]=NULL;
144
145 #ifdef __uClinux__
146         pid = vfork();
147 #else
148         pid = fork();
149 #endif
150         if (pid < 0){
151                 fprintf(stderr,"Could not fork\n");
152                 exit(-1);
153         }
154         if (pid == 0) {
155                 int fd;
156                 /*we are the new process*/
157                 setsid();
158                 
159                 fd = open("/dev/null", O_RDWR);
160                 if (fd==-1){
161                         fprintf(stderr,"Could not open /dev/null\n");
162                         exit(-1);
163                 }
164                 dup2(fd, 0);
165                 dup2(fd, 1);
166                 dup2(fd, 2);
167                 close(fd);
168                 
169                 if (execvp("linphonec",args)==-1){
170                         fprintf(stderr,"Fail to spawn linphonec: %s\n",strerror(errno));
171                         exit(-1);
172                 }
173         }
174 }
175 #else
176
177 static void spawn_linphonec(int argc, char *argv[]){
178         PROCESS_INFORMATION pinfo;
179         STARTUPINFO si;
180         ZeroMemory( &si, sizeof(si) );
181         si.cb = sizeof(si);
182         ZeroMemory( &pinfo, sizeof(pinfo) );
183
184
185         BOOL ret=CreateProcess(NULL,"linphoned.exe --pipe -c NUL",
186                 NULL,
187                 NULL,
188                 FALSE,
189                 0,
190                 NULL,
191                 NULL,
192                 &si,
193                 &pinfo);
194         if (!ret){
195                 fprintf(stderr,"Spawning of linphonec.exe failed.\n");
196         }else{
197                 WaitForInputIdle(pinfo.hProcess,1000);
198         }
199 }
200
201 #endif
202
203 static int send_generic_command(const char *command, int print_result){
204         char reply[DEFAULT_REPLY_SIZE];
205         int err;
206         err=send_command(command,reply,sizeof(reply),print_result);
207         if (err==0 && print_result) {
208                 printf("%s",reply);
209                 fflush(stdout);
210         }
211         return err;
212 }
213
214 static int register_execute(int argc, char *argv[]){
215         char cmd[512];
216         char *username=NULL;
217         char *host=NULL;
218         char *passwd=NULL;
219         int i;
220         for(i=0;i<argc;++i){
221                 if (strcmp(argv[i],"--host")==0){
222                         i++;
223                         if (i<argc){
224                                 host=argv[i];
225                         }else print_usage();
226                 }else if (strcmp(argv[i],"--username")==0){
227                         i++;
228                         if (i<argc){
229                                 username=argv[i];
230                         }else print_usage();
231                 }else if (strcmp(argv[i],"--password")==0){
232                         i++;
233                         if (i<argc){
234                                 passwd=argv[i];
235                         }else print_usage();
236                 }else print_usage();
237         }
238         if (username==NULL) {
239                 fprintf(stderr,"Missing --username\n");
240                 print_usage();
241         }
242         if (host==NULL) {
243                 fprintf(stderr,"Missing --host\n");
244                 print_usage();
245         }
246         if (passwd) snprintf(cmd,sizeof(cmd),"register sip:%s@%s sip:%s %s",username,host,host,passwd);
247         else snprintf(cmd,sizeof(cmd),"register sip:%s@%s sip:%s",username,host,host);
248         return send_generic_command(cmd,TRUE);
249 }
250
251 static int unregister_execute(int argc, char *argv[]){
252         return send_generic_command("unregister",FALSE);
253 }
254
255
256 static int dial_execute(int argc, char *argv[]){
257         char cmd[512];
258         if (argc==1){
259                 snprintf(cmd,sizeof(cmd),"call %s",argv[0]);
260                 return send_generic_command(cmd,TRUE);
261         }else{
262                 print_usage();
263         }
264         return -1;
265 }
266
267 static int status_execute(int argc, char *argv[]){
268         char cmd[512];
269         char reply[DEFAULT_REPLY_SIZE];
270         int err;
271         
272         if (argc==1){
273                 snprintf(cmd,sizeof(cmd),"status %s",argv[0]);
274                 err=send_command(cmd,reply,sizeof(reply),TRUE);
275                 if (err==0) {
276                         printf("%s",reply);
277                         err=make_status_value(reply);
278                 }
279                 return err;
280         }else{
281                 print_usage();
282         }
283         return -1;
284 }
285
286 static int parse_card_index(const char *reply){
287         int index=-1;
288         reply=strstr(reply,"device #");
289         if (!reply || sscanf(reply,"device #%i",&index)!=1){
290                 fprintf(stderr,"Error while parsing linphonec daemon output !\n");
291         }
292         return index;
293 }
294
295 static int soundcard_execute(int argc, char *argv[]){
296         char cmd[512];
297         char reply[DEFAULT_REPLY_SIZE];
298         int err;
299         if (argc==1){
300                 snprintf(cmd,sizeof(cmd),"soundcard %s",argv[0]);
301                 err=send_command(cmd,reply,sizeof(reply),TRUE);
302                 if (err==0) {
303                         printf("%s",reply);
304                         return parse_card_index(reply);
305                 }
306         }else if (argc==2){/*setting a soundcard */
307                 snprintf(cmd,sizeof(cmd),"soundcard %s %s",argv[0],argv[1]);
308                 err=send_command(cmd,reply,sizeof(reply),TRUE);
309                 if (err==0) {
310                         printf("%s",reply);
311                         return 0;
312                 }
313         }else{
314                 print_usage();
315         }
316         return -1;
317 }
318
319 int main(int argc, char *argv[]){
320         int argi;
321         if (argc<2){
322                 print_usage();
323                 return -1;
324         }
325         ortp_init();
326         for(argi=1;argi<argc;++argi){
327                 if (strcmp(argv[argi],"init")==0){
328                         /*check if there is running instance*/
329                         if (send_generic_command("help",0)==0){
330                                 fprintf(stderr,"A running linphonec has been found, not spawning a second one.\n");
331                                 return 0;
332                         }
333                         spawn_linphonec(argc-argi-1,&argv[argi+1]);
334                         return 0;
335                 }else if (strcmp(argv[argi],"generic")==0){
336                         if (argi+1<argc){
337                                 return send_generic_command(argv[argi+1],1);
338                         }else print_usage();
339                 }else if (strcmp(argv[argi],"register")==0){
340                         return register_execute(argc-argi-1,&argv[argi+1]);
341                 }else if (strcmp(argv[argi],"unregister")==0){
342                         return unregister_execute(argc-argi-1,&argv[argi+1]);
343                 }else if (strcmp(argv[argi],"dial")==0){
344                         return dial_execute(argc-argi-1,&argv[argi+1]);
345                 }else if (strcmp(argv[argi],"hangup")==0){
346                         send_generic_command("terminate",FALSE);
347                         send_generic_command("duration",TRUE);
348                 }else if (strcmp(argv[argi],"status")==0){
349                         return status_execute(argc-argi-1,&argv[argi+1]);
350                 }else if (strcmp(argv[argi],"soundcard")==0){
351                         return soundcard_execute(argc-argi-1,&argv[argi+1]);
352                 }else if (strcmp(argv[argi],"exit")==0){
353                         return send_generic_command("quit",TRUE);
354                 }else print_usage();
355         }
356         return 0;
357 }