1 /****************************************************************************
2 * Copyright (C) 2009 Simon MORLAT <simon.morlat@linphone.org>
4 ****************************************************************************
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.
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.
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.
20 ****************************************************************************/
34 #include <sys/socket.h>
40 #include "ortp/ortp.h"
42 #define DEFAULT_REPLY_SIZE 4096
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 */
52 static int make_status_value(const char *status_string){
54 if (strstr(status_string,"registered, identity=")){
55 ret|=STATUS_REGISTERED;
57 if (strstr(status_string,"registered=-1")){
58 ret|=STATUS_REGISTERING;
60 if (strstr(status_string,"autoanswer=1")){
61 ret|=STATUS_AUTOANSWER;
63 if (strstr(status_string,"dialing")){
66 if (strstr(status_string,"Call out")){
67 ret|=STATUS_OUT_CONNECTED;
69 if (strstr(status_string,"hook=answered")){
70 ret|=STATUS_IN_CONNECTED;
75 static int send_command(const char *command, char *reply, int reply_len, int print_errors){
81 snprintf(path,sizeof(path)-1,"linphonec-%i",getuid());
85 DWORD size=sizeof(username)-1;
86 GetUserName(username,&size);
87 snprintf(path,sizeof(path)-1,"linphonec-%s",username);
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));
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);
101 while ((err=ortp_pipe_read(pp,(uint8_t*)&reply[i],reply_len-i-1))>0){
105 ortp_client_pipe_close(pp);
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"
131 static void spawn_linphonec(int argc, char *argv[]){
136 args[j++]="linphonec";
139 args[j++]="/dev/null";
151 fprintf(stderr,"Could not fork\n");
156 /*we are the new process*/
159 fd = open("/dev/null", O_RDWR);
161 fprintf(stderr,"Could not open /dev/null\n");
169 if (execvp("linphonec",args)==-1){
170 fprintf(stderr,"Fail to spawn linphonec: %s\n",strerror(errno));
177 static void spawn_linphonec(int argc, char *argv[]){
178 PROCESS_INFORMATION pinfo;
180 ZeroMemory( &si, sizeof(si) );
182 ZeroMemory( &pinfo, sizeof(pinfo) );
185 BOOL ret=CreateProcess(NULL,"linphoned.exe --pipe -c NUL",
195 fprintf(stderr,"Spawning of linphonec.exe failed.\n");
197 WaitForInputIdle(pinfo.hProcess,1000);
203 static int send_generic_command(const char *command, int print_result){
204 char reply[DEFAULT_REPLY_SIZE];
206 err=send_command(command,reply,sizeof(reply),print_result);
207 if (err==0 && print_result) {
214 static int register_execute(int argc, char *argv[]){
221 if (strcmp(argv[i],"--host")==0){
226 }else if (strcmp(argv[i],"--username")==0){
231 }else if (strcmp(argv[i],"--password")==0){
238 if (username==NULL) {
239 fprintf(stderr,"Missing --username\n");
243 fprintf(stderr,"Missing --host\n");
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);
251 static int unregister_execute(int argc, char *argv[]){
252 return send_generic_command("unregister",FALSE);
256 static int dial_execute(int argc, char *argv[]){
259 snprintf(cmd,sizeof(cmd),"call %s",argv[0]);
260 return send_generic_command(cmd,TRUE);
267 static int status_execute(int argc, char *argv[]){
269 char reply[DEFAULT_REPLY_SIZE];
273 snprintf(cmd,sizeof(cmd),"status %s",argv[0]);
274 err=send_command(cmd,reply,sizeof(reply),TRUE);
277 err=make_status_value(reply);
286 static int parse_card_index(const char *reply){
288 reply=strstr(reply,"device #");
289 if (!reply || sscanf(reply,"device #%i",&index)!=1){
290 fprintf(stderr,"Error while parsing linphonec daemon output !\n");
295 static int soundcard_execute(int argc, char *argv[]){
297 char reply[DEFAULT_REPLY_SIZE];
300 snprintf(cmd,sizeof(cmd),"soundcard %s",argv[0]);
301 err=send_command(cmd,reply,sizeof(reply),TRUE);
304 return parse_card_index(reply);
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);
319 int main(int argc, char *argv[]){
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");
333 spawn_linphonec(argc-argi-1,&argv[argi+1]);
335 }else if (strcmp(argv[argi],"generic")==0){
337 return send_generic_command(argv[argi+1],1);
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);