--- linphone-1.3.99.6.old/console/linphonec.c 2006-07-18 18:11:45.000000000 +0200 +++ linphone-1.3.99.6-ext/console/linphonec.c 2006-08-01 10:06:01.000000000 +0200 @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include "linphonec.h" #include "../config.h" @@ -46,6 +48,12 @@ int nitems; } LPC_AUTH_STACK; +struct t_pidfile { + char file_name[PATH_MAX]; + int fd; + FILE *file; +}; + /*************************************************************************** * * Forward declarations @@ -82,6 +90,11 @@ const char *from, const char *msg); static void linphonec_display_status (LinphoneCore * lc, char *something); +/* IPC */ +static int save_pid(struct t_pidfile *pidfile); +static void remove_pid(struct t_pidfile *pidfile); +static void external_command(int signo); + /*************************************************************************** * * Global variables @@ -101,6 +114,8 @@ static char configfile_name[PATH_MAX]; static char *sipAddr = NULL; /* for autocall */ char prompt[PROMPT_MAX_LEN]; +struct t_pidfile pidfile; +static char ecmdfile_name[PATH_MAX]; LinphoneCoreVTable linphonec_vtable = { show:(ShowInterfaceCb) stub, @@ -286,6 +301,10 @@ mylogfile = NULL; snprintf(configfile_name, PATH_MAX, "%s/.linphonerc", getenv("HOME")); + snprintf(ecmdfile_name, PATH_MAX, "%s/%s/command", + getenv("HOME"), EXTCMD_DIR); + snprintf(pidfile.file_name, PATH_MAX, "%s/%s/pid", + getenv("HOME"), EXTCMD_DIR); /* Handle configuration filename changes */ @@ -348,11 +367,20 @@ */ linphonec_initialize_readline(); + /* + * Save PID + */ + if (save_pid(&pidfile)) + printf("If you want sent external command to linphonec, you will need " + "to get my PID in other way. E.g. using pen and paper you can remember" + " that my PID is %d.\n", getpid()); + /* * Initialize signal handlers */ signal(SIGTERM, linphonec_finish); signal(SIGINT, linphonec_finish); + signal(SIGUSR1, external_command); return 1; } @@ -367,6 +395,11 @@ { printf("Terminating...\n"); + /* Stop recieving external commands by ignoring SIGUSR1 */ + signal(SIGUSR1, SIG_IGN); + /* Delete PID file */ + remove_pid(&pidfile); + /* Terminate any pending call */ linphonec_parse_command_line(&linphonec, "terminate"); @@ -909,6 +942,133 @@ return input; } + +/* + * Tries to read command from temp file and execute it + */ + +void external_command(int signo) +{ + int fd; + ssize_t length=0, bitlen=0; + char buf[LINE_MAX_LEN]; + char *strippedbuf; + + //printf("Recieved signal %d; Awaiting external command...\n", signo); + + if (-1 != (fd=open(ecmdfile_name, O_RDONLY))) { + + while (0 < (bitlen=read(fd, buf+length, LINE_MAX_LEN-1-length))) + length+=bitlen; + if (bitlen==-1) + printf("Error while reading external command file: %s: %s\n", + ecmdfile_name, strerror(errno)); + else { + buf[length]='\x0'; + strippedbuf=lpc_strip_blanks(buf); + + printf("Recieved external command: '%s'\n", strippedbuf); + + /* I hope linphonec_parse_command_line() copyies value of strippedbuf. + * Otherwise after leaving this handler we lose stack. Maybe we + * should use global variable. */ + linphonec_parse_command_line(&linphonec, strippedbuf); + } + + close(fd); + } + else { + printf("Could not open command file %s: %s\n", ecmdfile_name, + strerror(errno)); + printf("Don't interrupt me if you have nothing to " + "say!\n"); + } + + + if (SIG_ERR==signal(SIGUSR1, external_command)) { + printf("Error while restoring SIGUSR1 handler\n"); + } + +} + + +/* + * It saves PID of linphonec to the user's config directory as a reference for + * SIGUSR1 signaler sending external command. + * + * On success returns 0 and pidfile->file contains locked *File stream. + * Otherwise return nonzero value and pidfile->file is NULL. + * + * There is a question about clients running on different computers? User can + * be registered under more contacts. He will be reachable from any place + * (i.e. all computers will be * ringing), but he wants initiate a call from + * localhost using externel command. Current implementation doesn't support + * concurent external command listeners. + */ +int save_pid(struct t_pidfile *pidfile) { + struct flock lock; + + pidfile->file=NULL; + + if (-1 == (pidfile->fd=open(pidfile->file_name, O_CREAT|O_WRONLY, + S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH))) { + printf("Error while opening PID file: %s: %s\n", pidfile->file_name, + strerror(errno)); + return(-1); + } + + + lock.l_type=F_WRLCK; + lock.l_whence=SEEK_SET; + lock.l_start=0; + lock.l_len=0; + + if (-1 == fcntl(pidfile->fd, F_SETLK, &lock)) { + printf("Error while locking PID file: %s: %s\n", pidfile->file_name, + strerror(errno)); + printf("File seems be locked by another running linphone/c instance.\n"); + return(-1); + } + + if (-1 == ftruncate(pidfile->fd, 0)) { + printf("Can't truncate PID file: %s: %s\n", pidfile->file_name, + strerror(errno)); + close(pidfile->fd); + return(-1); + } + + if (NULL ==(pidfile->file = fdopen(pidfile->fd, "w"))) { + printf("Error while opening PID file stream: %s: %s\n", + pidfile->file_name, strerror(errno)); + close(pidfile->fd); + return(-1); + } + + if (0>fprintf(pidfile->file, "%d", getpid()) || fflush(pidfile->file)) { + printf("Error while writing PID into file: %s: %s\n", pidfile->file_name, + strerror(errno)); + fclose(pidfile->file); + return(-1); + } + + return(0); +} + + +/* + * Delete PID file and unlock it. + */ +void remove_pid(struct t_pidfile *pidfile) { + if (pidfile->file && pidfile->file_name) + if (unlink(pidfile->file_name)) + printf("Error while removing PID file: %s: %s\n", pidfile->file_name, + strerror(errno)); + if (pidfile->file) { + fclose(pidfile->file); + pidfile->file=NULL; + } +} + /**************************************************************************** * * $Log: linphonec.c,v $