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";
147 fprintf(stderr,"Could not fork\n");
152 /*we are the new process*/
155 fd = open("/dev/null", O_RDWR);
157 fprintf(stderr,"Could not open /dev/null\n");
165 if (execvp("linphonec",args)==-1){
166 fprintf(stderr,"Fail to spawn linphonec: %s\n",strerror(errno));
173 static void spawn_linphonec(int argc, char *argv[]){
174 PROCESS_INFORMATION pinfo;
176 ZeroMemory( &si, sizeof(si) );
178 ZeroMemory( &pinfo, sizeof(pinfo) );
181 BOOL ret=CreateProcess(NULL,"linphoned.exe --pipe -c NUL",
191 fprintf(stderr,"Spawning of linphonec.exe failed.\n");
193 WaitForInputIdle(pinfo.hProcess,1000);
199 static int send_generic_command(const char *command, int print_result){
200 char reply[DEFAULT_REPLY_SIZE];
202 err=send_command(command,reply,sizeof(reply),print_result);
203 if (err==0 && print_result) {
210 static int register_execute(int argc, char *argv[]){
217 if (strcmp(argv[i],"--host")==0){
222 }else if (strcmp(argv[i],"--username")==0){
227 }else if (strcmp(argv[i],"--password")==0){
234 if (username==NULL) {
235 fprintf(stderr,"Missing --username\n");
239 fprintf(stderr,"Missing --host\n");
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);
247 static int unregister_execute(int argc, char *argv[]){
248 return send_generic_command("unregister",FALSE);
252 static int dial_execute(int argc, char *argv[]){
255 snprintf(cmd,sizeof(cmd),"call %s",argv[0]);
256 return send_generic_command(cmd,TRUE);
263 static int status_execute(int argc, char *argv[]){
265 char reply[DEFAULT_REPLY_SIZE];
269 snprintf(cmd,sizeof(cmd),"status %s",argv[0]);
270 err=send_command(cmd,reply,sizeof(reply),TRUE);
273 err=make_status_value(reply);
282 static int parse_card_index(const char *reply){
284 reply=strstr(reply,"device #");
285 if (!reply || sscanf(reply,"device #%i",&index)!=1){
286 fprintf(stderr,"Error while parsing linphonec daemon output !\n");
291 static int soundcard_execute(int argc, char *argv[]){
293 char reply[DEFAULT_REPLY_SIZE];
296 snprintf(cmd,sizeof(cmd),"soundcard %s",argv[0]);
297 err=send_command(cmd,reply,sizeof(reply),TRUE);
300 return parse_card_index(reply);
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);
315 int main(int argc, char *argv[]){
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");
329 spawn_linphonec(argc-argi-1,&argv[argi+1]);
331 }else if (strcmp(argv[argi],"generic")==0){
333 return send_generic_command(argv[argi+1],1);
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);