]> sjero.net Git - linphone/blob - linphone/console/shell.c
0f0906439c10db1e46322412313cc8d88e226580
[linphone] / 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         pid = vfork();
146         if (pid < 0){
147                 fprintf(stderr,"Could not fork\n");
148                 exit(-1);
149         }
150         if (pid == 0) {
151                 int fd;
152                 /*we are the new process*/
153                 setsid();
154                 
155                 fd = open("/dev/null", O_RDWR);
156                 if (fd==-1){
157                         fprintf(stderr,"Could not open /dev/null\n");
158                         exit(-1);
159                 }
160                 dup2(fd, 0);
161                 dup2(fd, 1);
162                 dup2(fd, 2);
163                 close(fd);
164                 
165                 if (execvp("linphonec",args)==-1){
166                         fprintf(stderr,"Fail to spawn linphonec: %s\n",strerror(errno));
167                         exit(-1);
168                 }
169         }
170 }
171 #else
172
173 static void spawn_linphonec(int argc, char *argv[]){
174         PROCESS_INFORMATION pinfo;
175         STARTUPINFO si;
176         ZeroMemory( &si, sizeof(si) );
177         si.cb = sizeof(si);
178         ZeroMemory( &pinfo, sizeof(pinfo) );
179
180
181         BOOL ret=CreateProcess(NULL,"linphoned.exe --pipe -c NUL",
182                 NULL,
183                 NULL,
184                 FALSE,
185                 0,
186                 NULL,
187                 NULL,
188                 &si,
189                 &pinfo);
190         if (!ret){
191                 fprintf(stderr,"Spawning of linphonec.exe failed.\n");
192         }else{
193                 WaitForInputIdle(pinfo.hProcess,1000);
194         }
195 }
196
197 #endif
198
199 static int send_generic_command(const char *command, int print_result){
200         char reply[DEFAULT_REPLY_SIZE];
201         int err;
202         err=send_command(command,reply,sizeof(reply),print_result);
203         if (err==0 && print_result) {
204                 printf("%s",reply);
205                 fflush(stdout);
206         }
207         return err;
208 }
209
210 static int register_execute(int argc, char *argv[]){
211         char cmd[512];
212         char *username=NULL;
213         char *host=NULL;
214         char *passwd=NULL;
215         int i;
216         for(i=0;i<argc;++i){
217                 if (strcmp(argv[i],"--host")==0){
218                         i++;
219                         if (i<argc){
220                                 host=argv[i];
221                         }else print_usage();
222                 }else if (strcmp(argv[i],"--username")==0){
223                         i++;
224                         if (i<argc){
225                                 username=argv[i];
226                         }else print_usage();
227                 }else if (strcmp(argv[i],"--password")==0){
228                         i++;
229                         if (i<argc){
230                                 passwd=argv[i];
231                         }else print_usage();
232                 }else print_usage();
233         }
234         if (username==NULL) {
235                 fprintf(stderr,"Missing --username\n");
236                 print_usage();
237         }
238         if (host==NULL) {
239                 fprintf(stderr,"Missing --host\n");
240                 print_usage();
241         }
242         if (passwd) snprintf(cmd,sizeof(cmd),"register sip:%s@%s sip:%s %s",username,host,host,passwd);
243         else snprintf(cmd,sizeof(cmd),"register sip:%s@%s sip:%s",username,host,host);
244         return send_generic_command(cmd,TRUE);
245 }
246
247 static int unregister_execute(int argc, char *argv[]){
248         return send_generic_command("unregister",FALSE);
249 }
250
251
252 static int dial_execute(int argc, char *argv[]){
253         char cmd[512];
254         if (argc==1){
255                 snprintf(cmd,sizeof(cmd),"call %s",argv[0]);
256                 return send_generic_command(cmd,TRUE);
257         }else{
258                 print_usage();
259         }
260         return -1;
261 }
262
263 static int status_execute(int argc, char *argv[]){
264         char cmd[512];
265         char reply[DEFAULT_REPLY_SIZE];
266         int err;
267         
268         if (argc==1){
269                 snprintf(cmd,sizeof(cmd),"status %s",argv[0]);
270                 err=send_command(cmd,reply,sizeof(reply),TRUE);
271                 if (err==0) {
272                         printf("%s",reply);
273                         err=make_status_value(reply);
274                 }
275                 return err;
276         }else{
277                 print_usage();
278         }
279         return -1;
280 }
281
282 static int parse_card_index(const char *reply){
283         int index=-1;
284         reply=strstr(reply,"device #");
285         if (!reply || sscanf(reply,"device #%i",&index)!=1){
286                 fprintf(stderr,"Error while parsing linphonec daemon output !\n");
287         }
288         return index;
289 }
290
291 static int soundcard_execute(int argc, char *argv[]){
292         char cmd[512];
293         char reply[DEFAULT_REPLY_SIZE];
294         int err;
295         if (argc==1){
296                 snprintf(cmd,sizeof(cmd),"soundcard %s",argv[0]);
297                 err=send_command(cmd,reply,sizeof(reply),TRUE);
298                 if (err==0) {
299                         printf("%s",reply);
300                         return parse_card_index(reply);
301                 }
302         }else if (argc==2){/*setting a soundcard */
303                 snprintf(cmd,sizeof(cmd),"soundcard %s %s",argv[0],argv[1]);
304                 err=send_command(cmd,reply,sizeof(reply),TRUE);
305                 if (err==0) {
306                         printf("%s",reply);
307                         return 0;
308                 }
309         }else{
310                 print_usage();
311         }
312         return -1;
313 }
314
315 int main(int argc, char *argv[]){
316         int argi;
317         if (argc<2){
318                 print_usage();
319                 return -1;
320         }
321         ortp_init();
322         for(argi=1;argi<argc;++argi){
323                 if (strcmp(argv[argi],"init")==0){
324                         /*check if there is running instance*/
325                         if (send_generic_command("help",0)==0){
326                                 fprintf(stderr,"A running linphonec has been found, not spawning a second one.\n");
327                                 return 0;
328                         }
329                         spawn_linphonec(argc-argi-1,&argv[argi+1]);
330                         return 0;
331                 }else if (strcmp(argv[argi],"generic")==0){
332                         if (argi+1<argc){
333                                 return send_generic_command(argv[argi+1],1);
334                         }else print_usage();
335                 }else if (strcmp(argv[argi],"register")==0){
336                         return register_execute(argc-argi-1,&argv[argi+1]);
337                 }else if (strcmp(argv[argi],"unregister")==0){
338                         return unregister_execute(argc-argi-1,&argv[argi+1]);
339                 }else if (strcmp(argv[argi],"dial")==0){
340                         return dial_execute(argc-argi-1,&argv[argi+1]);
341                 }else if (strcmp(argv[argi],"hangup")==0){
342                         send_generic_command("terminate",FALSE);
343                         send_generic_command("duration",TRUE);
344                 }else if (strcmp(argv[argi],"status")==0){
345                         return status_execute(argc-argi-1,&argv[argi+1]);
346                 }else if (strcmp(argv[argi],"soundcard")==0){
347                         return soundcard_execute(argc-argi-1,&argv[argi+1]);
348                 }else if (strcmp(argv[argi],"exit")==0){
349                         return send_generic_command("quit",TRUE);
350                 }else print_usage();
351         }
352         return 0;
353 }