diff --git a/config.h.in b/config.h.in index caf5577caff2fc6fa08f065865f0957089dcc500..0d152b84fdd8a8ad33ee80a912911ea474f485bf 100644 --- a/config.h.in +++ b/config.h.in @@ -42,6 +42,9 @@ /* Define to 1 if you have the `pthread' library (-lpthread). */ #undef HAVE_LIBPTHREAD +/* Define to 1 if you have a fully functional readline library. */ +#undef HAVE_LIBREADLINE + /* Define if you have libz */ #undef HAVE_LIBZ diff --git a/configure.ac b/configure.ac index 2de9c150280de8f7ec17d112253112df2771363d..500d162dc8e0b083c8318bc080b44884d4e5e049 100644 --- a/configure.ac +++ b/configure.ac @@ -130,6 +130,7 @@ if test "x$with_speex" = "xyes" ; then fi AM_CONDITIONAL(USE_SPEEX, test "x$with_speex" = "xyes" ) +GNUPG_CHECK_READLINE dnl check for zeroconf (from apple) AC_ARG_ENABLE(zeroconf, @@ -224,7 +225,6 @@ src/Makefile \ src/sflphone \ src/audio/Makefile \ src/audio/gsm/Makefile \ -src/audio/OpenAL/Makefile \ src/audio/pacpp/Makefile \ src/audio/pacpp/include/Makefile \ src/audio/pacpp/include/portaudiocpp/Makefile \ @@ -233,6 +233,7 @@ src/audio/pacpp/source/portaudiocpp/Makefile \ src/config/Makefile \ src/gui/Makefile \ src/gui/qt/Makefile \ +src/gui/cli/Makefile \ src/gui/server/Makefile \ src/zeroconf/Makefile \ ringtones/Makefile \ diff --git a/m4/readline.m4 b/m4/readline.m4 new file mode 100644 index 0000000000000000000000000000000000000000..7fc996b9b8b7eee6b2877d7953ab88a6ebd3f5aa --- /dev/null +++ b/m4/readline.m4 @@ -0,0 +1,61 @@ +dnl Check for readline and dependencies +dnl Copyright (C) 2004 Free Software Foundation, Inc. +dnl +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. +dnl +dnl Defines HAVE_LIBREADLINE to 1 if a working readline setup is +dnl found, and sets @LIBREADLINE@ to the necessary libraries. + +AC_DEFUN([GNUPG_CHECK_READLINE], +[ + AC_ARG_WITH(readline, + AC_HELP_STRING([--with-readline=DIR], + [look for the readline library in DIR]), + [_do_readline=$withval],[_do_readline=yes]) + + if test "$_do_readline" != "no" ; then + if test -d "$withval" ; then + CPPFLAGS="${CPPFLAGS} -I$withval/include" + LDFLAGS="${LDFLAGS} -L$withval/lib" + fi + + for _termcap in "" "-ltermcap" "-lcurses" "-lncurses" ; do + _readline_save_libs=$LIBS + _combo="-lreadline${_termcap:+ $_termcap}" + LIBS="$LIBS $_combo" + + AC_MSG_CHECKING([whether readline via \"$_combo\" is present and sane]) + + AC_LINK_IFELSE(AC_LANG_PROGRAM([ +#include <stdio.h> +#include <readline/readline.h> +#include <readline/history.h> +],[ +add_history("foobar"); +rl_catch_signals=0; +rl_inhibit_completion=0; +rl_attempted_completion_function=NULL; +]),_found_readline=yes,_found_readline=no) + + AC_MSG_RESULT([$_found_readline]) + + LIBS=$_readline_save_libs + + if test $_found_readline = yes ; then + AC_DEFINE(HAVE_LIBREADLINE,1, + [Define to 1 if you have a fully functional readline library.]) + AC_SUBST(LIBREADLINE,$_combo) + break + fi + done + + unset _termcap + unset _readline_save_libs + unset _combo + unset _found_readline + fi +])dnl diff --git a/src/audio/Makefile.am b/src/audio/Makefile.am index d0fe8c8ee36d30c027cb4713b65f3bd3039faa86..cbb6a68f67897408e025064baf62ffa4c11f36ab 100644 --- a/src/audio/Makefile.am +++ b/src/audio/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm pacpp OpenAL +SUBDIRS = gsm pacpp noinst_LTLIBRARIES = libaudio.la @@ -28,7 +28,7 @@ audioloop.cpp ringbuffer.cpp $(SPEEX_SOURCES) AM_CXXFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/libs -I$(srcdir)/pacpp/include/ $(libccext2_CFLAGS) $(libccrtp1_CFLAGS) $(portaudio_CFLAGS) -I$(top_srcdir)/libs/portaudio/pa_common libaudio_la_LIBADD = gsm/libgsm.la pacpp/source/portaudiocpp/libportaudiocpp.la $(SPEEX_LIB) $(SAMPLERATE_LIB) libaudio_la_CPPFLAGS = $(SPEEX_FLAG) $(SAMPLERATE_FLAG) - + noinst_HEADERS = audioloop.h common.h ringbuffer.h alaw.h audiofile.h g711.h \ tonelist.h audiortp.h audiocodec.h audiolayer.h \ diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 36fcd9ffc58e4996464ecc3e41574dec2d00a880..6f2331a6dc7da36ead435a2d968218a0d2a50ac2 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -6,7 +6,7 @@ serverlib = server/libsflphoneguiserver.la #qt/sflphone-qt: # cd qt && make -SUBDIRS = $(serverdir) qt +SUBDIRS = $(serverdir) qt cli noinst_LTLIBRARIES = libguiframework.la diff --git a/src/gui/cli/LICENSE b/src/gui/cli/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..2ba72d57f699c9ec002a9020126c3a1f77b30313 --- /dev/null +++ b/src/gui/cli/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src/gui/cli/Makefile.am b/src/gui/cli/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..32af5a974a7e7798b45c18d33584e362469efd3c --- /dev/null +++ b/src/gui/cli/Makefile.am @@ -0,0 +1,22 @@ +libexec_PROGRAMS = sflphone-cli + +#-lncurses +AM_LDFLAGS = $(LIBREADLINE) +sflphone_cli_SOURCES = \ + calls.c calls.h \ + commons.h \ + core.c core.h \ + display.c display.h \ + eventloop.c eventloop.h \ + globals.c globals.h \ + main.c \ + net.c net.h \ + requests.c requests.h \ + seqs.c seqs.h \ + setup.c setup.h \ + sflphone.c \ + sflphone-events.c sflphone-events.h \ + sflphone.h \ + strutils.c strutils.h \ + user-input.c user-input.h + diff --git a/src/gui/cli/calls.c b/src/gui/cli/calls.c new file mode 100644 index 0000000000000000000000000000000000000000..8916309eade6236c6b69827bea13886af2e311e2 --- /dev/null +++ b/src/gui/cli/calls.c @@ -0,0 +1,101 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "calls.h" +#include "display.h" + +// malloc a new call +static struct call *new_call (char *, char *, char *); +static char *cstate2str (int); + +static callobj *calls_list = NULL; + + +callobj * +call_push_new (char *seqid, char *callid, char *destination) { + callobj *new; + + new = new_call (seqid, callid, destination); + + // Add call to the list. + if (calls_list == NULL) { + calls_list = new; + } else { + new->next = calls_list; + calls_list = new; + } + + return new; +} + +void +call_print_list (void) { + callobj *cptr = calls_list; + + if (cptr == NULL) { + display_info ("No call currently in progress !"); + return; + } + + display_info ("Calls in progress:"); + while (cptr != NULL) { + display_info ("* (%s) [%s] %s", cstate2str (cptr->state), + cptr->cid, cptr->dest); + cptr = cptr->next; + } +} + + +/******************************** + * PRIVATE FUNCTIONS * + ********************************/ +static char * +cstate2str (int state) { + switch (state) { + case TALKING: + return "Talking"; + break; + + case ON_HOLD: + return "On Hold"; + break; + + case CALLING: + default: + return "Calling"; + break; + } +} + +// Malloc new call descriptor +static struct call * +new_call (char *seqid, char *cid, char *destination) { + int len; + struct call *new; + + new = malloc (sizeof (struct call)); + if (new == NULL) { + perror ("malloc"); + exit (1); + } + + // Erase memory + bzero (new, sizeof (struct call)); + + // Put cid + len = (strlen(cid) > (CIDMAX - 1)) ? (CIDMAX - 1) : strlen(cid); + strncpy (new->cid, cid, len); + + // Put seq id + len = (strlen(seqid) > (CIDMAX - 1)) ? (CIDMAX - 1) : strlen(seqid); + strncpy (new->sid, seqid, len); + + // Put dest + if (destination != NULL) { + new->dest = strdup (destination); + } + + return new; +} + +/* EOF */ diff --git a/src/gui/cli/calls.h b/src/gui/cli/calls.h new file mode 100644 index 0000000000000000000000000000000000000000..5aed687fb6d86595ab8559a5e90f24ffb4ee03b6 --- /dev/null +++ b/src/gui/cli/calls.h @@ -0,0 +1,25 @@ +#ifndef __CALLS_H__ +#define __CALLS_H__ + +#define CIDMAX 32 + +enum callstate { + CALLING = 0, + TALKING, + ON_HOLD +}; + +struct call { + struct call *next; + char *dest; + char cid[CIDMAX]; + char sid[CIDMAX]; + enum callstate state; +}; + +typedef struct call callobj; + +void call_print_list (void); +callobj *call_push_new (char *, char *, char *); + +#endif // __CALLS_H__ diff --git a/src/gui/cli/commons.h b/src/gui/cli/commons.h new file mode 100644 index 0000000000000000000000000000000000000000..245ce91959b583819814313181b6cc387d41dd1b --- /dev/null +++ b/src/gui/cli/commons.h @@ -0,0 +1,12 @@ +#ifndef __COMMONS_H__ +#define __COMMONS_H__ +#include <strings.h> + +#define CONNECT_HOST "127.0.0.1" +#define CONNECT_PORT 3999 +#define FOREVER for(;;) + +#define IF_INIT if(0) +#define IF_GOT(STRING) else if (0 == strncasecmp (ibuf, STRING, strlen(STRING))) + +#endif // __COMMONS_H__ diff --git a/src/gui/cli/core.c b/src/gui/cli/core.c new file mode 100644 index 0000000000000000000000000000000000000000..afcdbb09b5715c6c4189cc892a434db85319f692 --- /dev/null +++ b/src/gui/cli/core.c @@ -0,0 +1,69 @@ +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "core.h" +#include "display.h" + +#define SFLPHONED_NAME "sflphoned" + +static char *core_path; +static int find_core (void); + +/* Runs the sflphone core daemon */ +int +run_core (void) { + int ret; + + if (!find_core ()) { + display_info ("Unable to find %s.", SFLPHONED_NAME); + display_info ("Point $SFLPHONE_CORE_DIR to its directory."); + exit (1); + } + + if (core_path == NULL) { + return -1; + } + + ret = fork (); + switch (ret) { + case 0: + /* core process */ + execl (core_path, NULL, NULL); + exit (0); + break; + case -1: + /* error */ + display_info ("Unable to fork(), call 911."); + exit (1); + default: + /* original process */ + sleep (1); /* Wait for core to init. */ + break; + } + return ret; +} + +/* Find the core sflphoned and set the full path */ +static int +find_core (void) { + char *envar; + + envar = getenv ("SFLPHONE_CORE_DIR"); + if (envar == NULL) { + return 0; + } + + core_path = (char *) malloc (strlen (envar) + 3 + strlen (SFLPHONED_NAME)); + if (core_path == NULL) { + return 0; + } + + snprintf (core_path, strlen (envar) + 3 + strlen (SFLPHONED_NAME), + "%s/%s", envar, SFLPHONED_NAME); + return 1; +} + +/* EOF */ diff --git a/src/gui/cli/core.h b/src/gui/cli/core.h new file mode 100644 index 0000000000000000000000000000000000000000..a21ce6462f4e8d3aa2ae61f95df4e573fb0403b1 --- /dev/null +++ b/src/gui/cli/core.h @@ -0,0 +1,8 @@ +#ifndef __CORE_H__ +#define __CORE_H__ + +#define CORE_PATH "/opt/SFLphone/bin/sflphoned" + +int run_core (void); + +#endif // __CORE_H__ diff --git a/src/gui/cli/display.c b/src/gui/cli/display.c new file mode 100644 index 0000000000000000000000000000000000000000..686c12845e55a34ac26cc63da1078988c3671448 --- /dev/null +++ b/src/gui/cli/display.c @@ -0,0 +1,30 @@ +#include <stdio.h> + +#include "display.h" + +#ifdef USE_ANSI +# define PROMPT "[1;36;40mSFL[0;36;40mphone[0m>" +#else +# define PROMPT "SFLphone>" +#endif + +// Display the SFLphone> prompt +void +display_prompt (void) { + printf ("%s ", PROMPT); + fflush (stdout); +} + +// Display incoming call info +void +display_inc_call (char *from) { + printf ("\r"); +#ifdef USE_ANSI + printf ("[1;37;45m***[1;33;44m Incoming Call from %s " + "[1;37;45m***[0m\n", from); +#else + printf ("*** Incoming Call from %s ***\n", from); +#endif +} + +/* EOF */ diff --git a/src/gui/cli/display.h b/src/gui/cli/display.h new file mode 100644 index 0000000000000000000000000000000000000000..df981fcfd6b2f88260ecdf63055916526611c3c4 --- /dev/null +++ b/src/gui/cli/display.h @@ -0,0 +1,25 @@ +#ifndef __DISPLAY_H__ +#define __DISPLAY_H__ + +#ifdef DEBUG +#include <stdio.h> +# ifdef USE_ANSI +# define debug(...) fprintf (stderr, "\r[33m[debug][0m " __VA_ARGS__) +# else +# define debug(...) fprintf (stderr, "\r[debug] " __VA_ARGS__) +# endif +#else +# define debug(...) +#endif + +void display_prompt (void); +void display_inc_call (char *); + + +#ifdef USE_ANSI +# define display_info(...) printf("[1;33;40m[Info] " __VA_ARGS__);printf("[0m\n"); +#else +#define display_info(...) printf ("[Info] " __VA_ARGS__);printf("\n"); +#endif + +#endif // __DISPLAY_H__ diff --git a/src/gui/cli/eventloop.c b/src/gui/cli/eventloop.c new file mode 100644 index 0000000000000000000000000000000000000000..342e6652d1b954efee91b1ffec39bf3dc7664465 --- /dev/null +++ b/src/gui/cli/eventloop.c @@ -0,0 +1,67 @@ +#include <sys/select.h> +#include <stdio.h> + +#include "commons.h" +#include "display.h" +#include "globals.h" +#include "user-input.h" +#include "sflphone.h" +#include "sflphone-events.h" + +int +event_loop (int socket) { + fd_set rfds, + wfds; + + /* get socket as FILE */ + fdsocket = fdopen (socket, "a+"); + if (fdsocket == NULL) { + perror ("fdopen"); + return -1; + } + + /* Ask SFLphone's core version */ + sflphone_ask_version (); + sflphone_get_events(); + + /* Main event loop */ + FOREVER { + FD_ZERO (&rfds); + FD_ZERO (&wfds); + FD_SET (socket, &rfds); // Watch socket + FD_SET (0, &rfds); // Watch stdin + + /* Wait for input, forever */ + display_prompt (); + select (socket+1, &rfds, NULL, NULL, NULL); + + /* React to socket input */ + if (FD_ISSET (socket, &rfds)) { + if (feof (fdsocket)) { + display_info ("SFLphone core closed the link. " + "Shutting down."); + break; + } else { + handle_event (); + } + } + + /* React to user input */ + if (FD_ISSET (0, &rfds)) { + if (handle_input () < 0) { + /* Exit if handle_input tells to. */ + break; + } + + // Break on EOF + if (feof (stdin)) { + display_info ("Got EOF. Bye bye !\n"); + break; + } + } + } + + return 0; +} + +/* EOF */ diff --git a/src/gui/cli/eventloop.h b/src/gui/cli/eventloop.h new file mode 100644 index 0000000000000000000000000000000000000000..f318bb08eafc6efeaaa9ce4d4c0e85a10eee445b --- /dev/null +++ b/src/gui/cli/eventloop.h @@ -0,0 +1,6 @@ +#ifndef __EVENTLOOP_H__ +#define __EVENTLOOP_H__ + +int event_loop (int); + +#endif // __EVENTLOOP_H__ diff --git a/src/gui/cli/globals.c b/src/gui/cli/globals.c new file mode 100644 index 0000000000000000000000000000000000000000..cf4257a32136002982b246503d3874a2fd6fd8a6 --- /dev/null +++ b/src/gui/cli/globals.c @@ -0,0 +1,8 @@ +#include <stdio.h> + +#include "globals.h" + +FILE *fdsocket = NULL; +int core_pid = 0; + +/* EOF */ diff --git a/src/gui/cli/globals.h b/src/gui/cli/globals.h new file mode 100644 index 0000000000000000000000000000000000000000..aad7729fe8fcd28d05669e0d270fe3b49de4f1a3 --- /dev/null +++ b/src/gui/cli/globals.h @@ -0,0 +1,9 @@ +#ifndef __GLOBALS_H__ +#define __GLOBALS_H__ + +#include <stdio.h> + +extern FILE *fdsocket; +extern int core_pid; + +#endif // __GLOBALS_H__ diff --git a/src/gui/cli/main.c b/src/gui/cli/main.c new file mode 100644 index 0000000000000000000000000000000000000000..0e1bf8d57cf8c0c3b7dc97e2f2c2f1b6dfbd4317 --- /dev/null +++ b/src/gui/cli/main.c @@ -0,0 +1,46 @@ +#include <stdio.h> +#include <unistd.h> + +#include "commons.h" +#include "core.h" +#include "display.h" +#include "eventloop.h" +#include "globals.h" +#include "net.h" + +#define MAX_RETRIES 5 + +int +main (int argc, char **argv) { + int socket; + int launched = 0; + int retry = 0; + + /* Init */ + + /* Connect */ + do { + //display_info ("Connecting to %s:%d...\n", CONNECT_HOST, CONNECT_PORT); + socket = create_socket (CONNECT_HOST, CONNECT_PORT); + if (socket < 0) { + if (!launched) { + // Attempt to launch sflphone. + launched = 1; + //display_info ("Attempting to run sflphoned."); + core_pid = run_core (); + } else { + sleep (1); + } + } else { + break; + } + retry++; + } while (retry < MAX_RETRIES); + + if (retry < MAX_RETRIES) { + return event_loop (socket); + } else { + display_info ("Cannot run sflphone daemon !"); + return 1; + } +} diff --git a/src/gui/cli/net.c b/src/gui/cli/net.c new file mode 100644 index 0000000000000000000000000000000000000000..9888db0c5ee8895eda3622d272e193de2d3cb794 --- /dev/null +++ b/src/gui/cli/net.c @@ -0,0 +1,46 @@ +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + + +int global_socket; + +int +create_socket (char *hostname, unsigned short portnum) { + struct hostent *hp; + struct sockaddr_in sa; + int sock; + + /* Check destination */ + if ((hp = gethostbyname (hostname)) == NULL) { + perror ("gethostbyname"); + return (-1); + } + + /* Alloc socket */ + sock = socket (PF_INET, SOCK_STREAM, 0); + if (sock < 0) { + perror ("socket"); + return (-1); + } + + /* Setup socket */ + bzero (&sa, sizeof(sa)); + bcopy (hp->h_addr, (char *)&sa.sin_addr, hp->h_length); + sa.sin_family = hp->h_addrtype; + sa.sin_port = htons ((unsigned short)portnum); + + /* Connect to sflphone */ + if (connect (sock, (const struct sockaddr *) &sa, sizeof(sa)) < 0) { + close(sock); + perror ("connect"); + return(-1); + } + + return (sock); +} + +/* EOF */ diff --git a/src/gui/cli/net.h b/src/gui/cli/net.h new file mode 100644 index 0000000000000000000000000000000000000000..e8b33060a195ff13f8f7edbe13e5c77e4dfa7dfd --- /dev/null +++ b/src/gui/cli/net.h @@ -0,0 +1,8 @@ +#ifndef __NET__H__ +#define __NET__H__ + +extern int global_socket; + +int create_socket (char *, unsigned short); + +#endif // __NET__H__ diff --git a/src/gui/cli/requests.c b/src/gui/cli/requests.c new file mode 100644 index 0000000000000000000000000000000000000000..5c2276b69b89c4581f86ab56e7a768be317e5f44 --- /dev/null +++ b/src/gui/cli/requests.c @@ -0,0 +1,120 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "requests.h" + +// malloc a new request +static struct request *new_request (char *, char *, void *); + +static reqobj *requests_list = NULL; + + +// Malloc new request +static struct request * +new_request (char *rid, char *subject, void *payload) { + int len; + struct request *req; + + req = malloc (sizeof (struct request)); + if (req == NULL) { + perror ("malloc"); + exit (1); + } + + // Erase memory + bzero (req, sizeof (struct request)); + + // Put rid + len = (strlen(rid) > (RIDMAX-1)) ? (RIDMAX-1) : strlen(rid); + strncpy (req->rid, rid, len); + + // Put subject + req->subject = strdup (subject); + + // Attach payload + if (payload != NULL) { + req->payload = payload; + } + + return req; +} + +void +request_push (int id, char *subject, void *payload) { + reqobj *newreq; + char tmp[RIDMAX]; + + snprintf (tmp, RIDMAX - 1, "seq%d", id); + + newreq = (reqobj *) new_request (tmp, subject, payload); + if (requests_list == NULL) { + // First item + requests_list = newreq; + } else { + // Add to the beginning of the list. + newreq->next = requests_list->next; + requests_list = newreq; + } +} + +reqobj * +request_find (char *sid) { + reqobj *candidate; + + if (requests_list == NULL) { + return NULL; + } + + candidate = requests_list; + + while (candidate != NULL) { + if (0 == strcmp (sid, candidate->rid)) { + return candidate; + } + candidate = candidate->next; + } + + // Not found + return NULL; +} + +reqobj * +request_pop (char *sid) { + reqobj *candidate; + reqobj *prev; + + if (requests_list == NULL) { + return NULL; + } + + candidate = prev = requests_list; + + while (candidate != NULL) { + if (0 == strcmp (sid, candidate->rid)) { + // dequeue + if (candidate == requests_list) { + requests_list = candidate->next; + } else { + prev->next = candidate->next; + } + return candidate; + } + + prev = candidate; + candidate = candidate->next; + } + + // Not found + return NULL; +} + +void +request_free (reqobj *item) { + if (item->subject != NULL) { + free (item->subject); + } + + free (item); +} + +/* EOF */ diff --git a/src/gui/cli/requests.h b/src/gui/cli/requests.h new file mode 100644 index 0000000000000000000000000000000000000000..beccdcd7437f11822aa0a72a83c1465bc79954ee --- /dev/null +++ b/src/gui/cli/requests.h @@ -0,0 +1,21 @@ +#ifndef __REQUESTS_H__ +#define __REQUESTS_H__ + +#define RIDMAX 32 + +struct request { + struct request *next; + char *subject; + char rid[RIDMAX]; + void *payload; +}; + +typedef struct request reqobj; + + +void request_free (reqobj *); +void request_push (int, char *, void *); +reqobj *request_pop (char *); +reqobj *request_find (char *); + +#endif // __REQUESTS_H__ diff --git a/src/gui/cli/seqs.c b/src/gui/cli/seqs.c new file mode 100644 index 0000000000000000000000000000000000000000..abad8a040178ea219ca78c9b4ef834fa136c437c --- /dev/null +++ b/src/gui/cli/seqs.c @@ -0,0 +1,18 @@ +#include "seqs.h" + + +unsigned int +get_next_seq (void) { + static unsigned int i = 0; + + return i++; +} + +unsigned int +get_next_callid (void) { + static unsigned int i = 0; + + return i++; +} + +/* EOF */ diff --git a/src/gui/cli/seqs.h b/src/gui/cli/seqs.h new file mode 100644 index 0000000000000000000000000000000000000000..9cf16db963ae21599edd714e224fb1504095446d --- /dev/null +++ b/src/gui/cli/seqs.h @@ -0,0 +1,8 @@ +#ifndef __SEQS_H__ +#define __SEQS_H__ + +unsigned int get_next_seq (void); +unsigned int get_next_callid (void); + +#endif // __SEQS_H__ + diff --git a/src/gui/cli/setup.c b/src/gui/cli/setup.c new file mode 100644 index 0000000000000000000000000000000000000000..0af9721113fed3c46a653d718404b918116ba19a --- /dev/null +++ b/src/gui/cli/setup.c @@ -0,0 +1,69 @@ +#include <stdio.h> +#include <stdlib.h> +#include <readline/readline.h> +#include <readline/history.h> +#include "display.h" +#include "setup.h" +#include "sflphone.h" + + + +int +setup_first (void) { + char *text; + + display_info ("Welcome to SFLphone."); + display_info ("This wizard will guide you to setup your first account."); + printf ("\n"); + + display_info ("Please enter your full name"); + text = readline ("ie. John doe> "); + if (text != NULL) { + sflphone_set_fullname (text); + free (text); + } + + display_info ("Please enter your SIP username."); + text = readline ("ie. 104> "); + if (text != NULL) { + sflphone_set_sipuser (text); + free (text); + } + + display_info ("Please enter your SIP domain."); + text = readline ("ie. mycompany.net> "); + if (text != NULL) { + sflphone_set_siphost (text); + free (text); + } + + display_info ("Please enter your SIP proxy address."); + text = readline ("ie. sip.mycompany.net> "); + if (text != NULL) { + sflphone_set_proxy (text); + free (text); + } + + display_info ("If you wish to use STUN, enter your server address."); + text = readline ("ie. stun.mycompany.net> "); + if (text != NULL) { + if (strlen (text) > 3) { + sflphone_set_stun (text); + } else { + display_info ("Answer was too short, ignored."); + } + free (text); + } + + printf ("\n"); + sflphone_list_audiodevs (); + display_info ("Now choose your audio device."); + text = readline ("Number to use? "); + if (text != NULL) { + free (text); + } + + display_info ("Setup done."); + return 1; +} + diff --git a/src/gui/cli/setup.h b/src/gui/cli/setup.h new file mode 100644 index 0000000000000000000000000000000000000000..5001d06f22b696898ca46402994eeaa5ac298779 --- /dev/null +++ b/src/gui/cli/setup.h @@ -0,0 +1,6 @@ +#ifndef __SETUP_H__ +#define __SETUP_H__ + +int setup_first (void); + +#endif // __SETUP_H__ diff --git a/src/gui/cli/sflphone-events.c b/src/gui/cli/sflphone-events.c new file mode 100644 index 0000000000000000000000000000000000000000..eeb40737d8c351b78eeac8997db9a2c4133ead6f --- /dev/null +++ b/src/gui/cli/sflphone-events.c @@ -0,0 +1,45 @@ +#include <stdio.h> +#include <string.h> + +#include "commons.h" +#include "display.h" +#include "globals.h" +#include "sflphone.h" +#include "sflphone-events.h" +#include "strutils.h" + +#define EVBUFSIZE 512 + +static char ibuf[EVBUFSIZE]; + +int +handle_event (void) { + bzero (ibuf, EVBUFSIZE); + fgets (ibuf, EVBUFSIZE, fdsocket); + clean_string (ibuf); + + if (strlen (ibuf) < 2) { + return 0; + } +// debug ("GOT %s\n", ibuf); + + IF_INIT{} + IF_GOT("100 ") { + // Info message ? + sflphone_handle_100 (token (ibuf)); + } + + IF_GOT("101 ") { + // Incoming event ? + sflphone_handle_101 (token (ibuf)); + } + + IF_GOT("200 ") { + // Info message ? + sflphone_handle_200 (token (ibuf)); + } + + return 0; +} + +/* EOF */ diff --git a/src/gui/cli/sflphone-events.h b/src/gui/cli/sflphone-events.h new file mode 100644 index 0000000000000000000000000000000000000000..1412345193a0abbe2ca34b16963c8693889d42ab --- /dev/null +++ b/src/gui/cli/sflphone-events.h @@ -0,0 +1,7 @@ +#ifndef __SFLPHONE_EVENTS_H__ +#define __SFLPHONE_EVENTS_H__ +#include <stdio.h> + +int handle_event (void); + +#endif // __SFLPHONE_EVENTS_H__ diff --git a/src/gui/cli/sflphone.c b/src/gui/cli/sflphone.c new file mode 100644 index 0000000000000000000000000000000000000000..d3cfba8c5fd45bd06ef2d52e12475ab3fa5abda4 --- /dev/null +++ b/src/gui/cli/sflphone.c @@ -0,0 +1,301 @@ +#include <stdio.h> +#include <string.h> + +#include "calls.h" +#include "commons.h" +#include "display.h" +#include "globals.h" +#include "requests.h" +#include "setup.h" +#include "sflphone.h" +#include "strutils.h" +#include "seqs.h" + +// get events signal = starting voip +void +sflphone_get_events(void) { + int id = get_next_seq(); + request_push(id, "getevents", NULL); + fprintf(fdsocket, "getevents seq%d\n", id); + fflush(fdsocket); +} +// Ask the core's version +void +sflphone_ask_version (void) { + int id = get_next_seq (); + + request_push (id, "version", NULL); + fprintf (fdsocket, "version seq%d\n", id); + fflush (fdsocket); +} + +/* Ask a list of available audio devices */ +void +sflphone_list_audiodevs (void) { + int id = get_next_seq (); + + request_push (id, "audiodevice", NULL); + fprintf (fdsocket, "list seq%d audiodevice\n", id); + fflush (fdsocket); +} + +// set the config full name +void +sflphone_set_fullname (char *s) { + clean_string (s); + if (strlen (s) < 1) { + return; + } + fprintf (fdsocket, "configset seq%d VoIPLink SIP.fullName %s\n", + get_next_seq (), s); + fflush (fdsocket); + display_info ("Set SIP User name: %s\n", s); +} + +// set the config sip user +void +sflphone_set_sipuser (char *s) { + clean_string (s); + if (strlen (s) < 1) { + return; + } + fprintf (fdsocket, "configset seq%d VoIPLink SIP.userPart %s\n", + get_next_seq (), s); + fprintf (fdsocket, "configset seq%d VoIPLink SIP.username %s\n", + get_next_seq (), s); + fflush (fdsocket); + display_info ("Set SIP User: %s\n", s); +} + +// set the config sip host +void +sflphone_set_siphost (char *s) { + clean_string (s); + if (strlen (s) < 3) { + return; + } + fprintf (fdsocket, "configset seq%d VoIPLink SIP.hostPart %s\n", + get_next_seq (), s); + fflush (fdsocket); + display_info ("Set SIP host: %s\n", s); +} + +// set the config sip password +void +sflphone_set_password (char *s) { + clean_string (s); + if (strlen (s) < 2) { + return; + } + fprintf (fdsocket, "configset seq%d VoIPLink SIP.password %s\n", + get_next_seq (), s); + fflush (fdsocket); + display_info ("Set SIP password: ****\n"); +} + +// set the config sip proxy +void +sflphone_set_proxy (char *s) { + clean_string (s); + if (strlen (s) < 3) { + return; + } + fprintf (fdsocket, "configset seq%d VoIPLink SIP.proxy %s\n", + get_next_seq (), s); + fflush (fdsocket); + display_info ("Set SIP proxy: %s\n", s); +} + +// set the config STUN usage +void +sflphone_set_stun (char *s) { + int use = 0; + + if (s[0] == '1') { + use = 1; + } + + fprintf (fdsocket, "configset seq%d VoIPLink SIP.useStun %d\n", + get_next_seq (), use); + fflush (fdsocket); + display_info ("Set SIP STUN usage: %d\n", use); +} + +// The user asks for a call +// dest is the destination to call +void +sflphone_call (char *dest) { + int accno = 1; // must change when multiple accounts. + int seq; + char call_id[CIDMAX]; + char seq_id[CIDMAX]; + callobj *calldesc; + + // dest is the destination like "5143456789" + // output pattern is like "call seq0 acc1 c1 5143456789" + if (dest == NULL) { + return; + } + clean_string (dest); + if (strlen (dest) < 1) { + return; + } + + // Alloc call parameters + bzero (call_id, CIDMAX); + bzero (seq_id, CIDMAX); + seq = get_next_seq (); + snprintf (call_id, CIDMAX - 1, "c%d", get_next_callid ()); + snprintf (seq_id, CIDMAX - 1, "seq%d", seq); + + // Push request, we are waiting for the next ack/cancel for this call. + request_push (seq, "call", (void *) calldesc); + + // Add call descriptor + call_push_new (seq_id, call_id, dest); + + // Send the command + fprintf (fdsocket, "call %s acc%d %s %s\n", seq_id, accno, call_id, dest); + fflush (fdsocket); +} + +// 100 type messages are for lists +void +sflphone_handle_100 (char *string) { + char *ptr; + char cseq[32]; + reqobj *request; + char *ibuf; + + + // Original Message: + // 100 seq234 Payload here + // ^--string points here + + // Isolate seq field (1st field of string) + ptr = token (string); + if (ptr == NULL) { + // Bogus string, should have 3 fields + debug ("Got bogus 100: %s\n", string); + return; + } + + + // Copy sequence field to cseq + // Message: + // 200 seq244 Payload here + // ^ ^--ptr points to here + // ^--string points to here. + bzero (cseq, 32); + strncpy (cseq, string, ((ptr - 1) - string)); + //debug ("Got a 100, seq=%s\n", cseq); + + + // find the associated request and get its subject + request = request_find (cseq); + if (request == NULL) { + // Irrelevant request + return; + } + ibuf = request->subject; + + // Look at the subject and react. + IF_INIT{} + + // This is an item from a list of audiodevs + IF_GOT("audiodev") { + print_urldecoded (ptr); + } + +} + +// 200 type messages are validations of some commands. we have +// to notify the user about some of them. +void +sflphone_handle_200 (char *string) { + char *ptr; + char cseq[32]; + reqobj *request; + char *ibuf; + + + // Original Message: + // 200 seq234 Payload here + // ^--string points here + + // Isolate seq field (1st field of string) + ptr = token (string); + if (ptr == NULL) { + // Bogus string, should have 3 fields + debug ("Got bogus 200: %s\n", string); + return; + } + + + // Copy sequence field to cseq + // Message: + // 200 seq244 Payload here + // ^ ^--ptr points to here + // ^--string points to here. + bzero (cseq, 32); + strncpy (cseq, string, ((ptr - 1) - string)); + //debug ("Got a 200, seq=%s\n", cseq); + + + // Pop the associated request and get its subject + request = request_find (cseq); + if (request == NULL) { + // Irrelevant request + return; + } + ibuf = request->subject; + + // Look at the subject and react. + IF_INIT{} + + // This message is related to an ongoing call + IF_GOT("call") { + // A call has been established + if (!strcmp (ptr, "Established")) { + } + } + + // Answer to a version request + IF_GOT("version") { + // Find version string. + display_info ("Core version: %s", ptr); + request_pop (cseq); + request_free (request); + } + + // End of audio devices list. + IF_GOT("audiodev") { + request_pop (cseq); + request_free (request); + } +} + +void +sflphone_handle_101 (char *string) { +} + +void +sflphone_quit(SFLPHONE_QUIT_STATE state) { + switch(state) { + case SFLPHONE_QUIT: + fprintf(fdsocket, "stop seq%d\n", get_next_seq()); + fflush(fdsocket); + display_info ("Quitting SFLphone"); + + break; + + case SFLPHONE_QUIT_SOFTLY: + fprintf(fdsocket, "quit seq%d\n", get_next_seq()); + fflush(fdsocket); + display_info ("Softly quitting SFLphone. SFLphone deamon still running"); + + break; + } +} + +/* EOF */ diff --git a/src/gui/cli/sflphone.h b/src/gui/cli/sflphone.h new file mode 100644 index 0000000000000000000000000000000000000000..be55b7dcdafcd3c3e12b0115204dd4ce3bfd08b4 --- /dev/null +++ b/src/gui/cli/sflphone.h @@ -0,0 +1,22 @@ +#ifndef __SFLPHONE_H__ +#define __SFLPHONE_H__ + +void sflphone_get_events(void); +void sflphone_ask_version (void); +void sflphone_list_audiodevs (void); +void sflphone_set_fullname (char *); +void sflphone_set_sipuser (char *); +void sflphone_set_siphost (char *); +void sflphone_set_password (char *); +void sflphone_set_proxy (char *); +void sflphone_set_stun (char *); +void sflphone_call (char *); + +void sflphone_handle_100 (char *); +void sflphone_handle_101 (char *); +void sflphone_handle_200 (char *); + +typedef enum { SFLPHONE_QUIT=0, SFLPHONE_QUIT_SOFTLY } SFLPHONE_QUIT_STATE; +void sflphone_quit(SFLPHONE_QUIT_STATE); + +#endif // __SFLPHONE_H__ diff --git a/src/gui/cli/strutils.c b/src/gui/cli/strutils.c new file mode 100644 index 0000000000000000000000000000000000000000..fbf3681595f2eed0d6f39744b306b4e22fa1ef35 --- /dev/null +++ b/src/gui/cli/strutils.c @@ -0,0 +1,93 @@ +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include "display.h" +#include "strutils.h" + +static void remove_cr (char *); + + +/* Get a pointer to the next token */ +char * +token (const char *string) { + char *ptr; + + /* find next token */ + ptr = strchr (string, TOKEN_DELIM); + if (ptr == NULL) { + return NULL; + } + else if (ptr[1] == '\0') { + return NULL; + } + else return (ptr + 1); +} + +/* Get a pointer to the Nth next token */ +char * +nthtoken (const char *original, int n) { + char *ptr; + int i = 0; + + ptr = (char *) original; + do { + /* find next token */ + ptr = token (ptr); + if (ptr == NULL) { + /* not found */ + return NULL; + } + else if (i < (n-1) && ptr[1] == '\0') { + /* end of string */ + return NULL; + } + + i++; + } while (i < n); + + return ptr; +} + + +void +clean_string (char *str) { + remove_cr (str); +} + +void +print_urldecoded (char *str) { + char *decoded; + int i; + + decoded = (char *) malloc (strlen (str) + 10); + if (decoded == NULL) { + perror ("malloc"); + exit (1); + } + + for (i = 0; i < strlen (str); i++) { + if (str[i] == '+') { + decoded[i] = ' '; + } + +#if 0 + else if (str[i] == '%' && isdigit (str[i+1]) && isdigit (str[i+2])) { + } +#endif + + } +} + + +/* remove cr/lf at end of str */ +static void +remove_cr (char *str) { + int i; + + for (i = 0; i < strlen (str); i++) { + if (str[i] == '\n' || str[i] == '\r') { + str[i] = '\0'; + break; + } + } +} diff --git a/src/gui/cli/strutils.h b/src/gui/cli/strutils.h new file mode 100644 index 0000000000000000000000000000000000000000..65f094c35220199d371eefdcc1f8d1b8e487d6c6 --- /dev/null +++ b/src/gui/cli/strutils.h @@ -0,0 +1,11 @@ +#ifndef __STRUTILS_H__ +#define __STRUTILS_H__ + +#define TOKEN_DELIM ' ' + +char *token (const char *); +char *nthtoken (const char *, int); +void clean_string (char *); +void print_urldecoded (char *); + +#endif // __STRUTILS_H__ diff --git a/src/gui/cli/user-input.c b/src/gui/cli/user-input.c new file mode 100644 index 0000000000000000000000000000000000000000..23c2f9aecb0a232233797121cb77f68c16dcee36 --- /dev/null +++ b/src/gui/cli/user-input.c @@ -0,0 +1,136 @@ +#include <stdio.h> +#include <string.h> + +#include "calls.h" +#include "commons.h" +#include "display.h" +#include "user-input.h" +#include "setup.h" +#include "sflphone.h" +#include "strutils.h" + +#define IBUFSIZE 512 + +static char ibuf[IBUFSIZE]; + +int +handle_input (void) { + bzero (ibuf, IBUFSIZE); + fgets (ibuf, IBUFSIZE, stdin); + clean_string (ibuf); + + if (strlen (ibuf) < 1) { + return 0; + } + + IF_INIT{} + + /* Ask the core version */ + IF_GOT("version") { + sflphone_ask_version (); + return 0; + } + + /* Run setup */ + IF_GOT("setup") { + setup_first (); + return 0; + } + + /* Display Help */ + IF_GOT("help") { + help_display (); + return 0; + } + + /* Quit application */ + IF_GOT("quit softly") { + sflphone_quit(SFLPHONE_QUIT_SOFTLY); + return -1; + } + + /* Quit application */ + IF_GOT("quit") { + sflphone_quit(SFLPHONE_QUIT); + return -1; + } + + /* Account setup commands */ + IF_GOT("register fullname ") { + // example: register fullname Bobbie Ewing + sflphone_set_fullname (nthtoken (ibuf, 2)); + return 0; + } + IF_GOT ("register sipuser ") { + // example: register sipuser 244 + sflphone_set_sipuser (nthtoken (ibuf, 2)); + return 0; + } + IF_GOT("register siphost ") { + // example: register siphost savoirfairelinux.net + sflphone_set_siphost (nthtoken (ibuf, 2)); + return 0; + } + IF_GOT("register password ") { + // example: register password sdfg0si1g + sflphone_set_password (nthtoken (ibuf, 2)); + return 0; + } + IF_GOT("register sipproxy ") { + // example: register sipproxy proxy.savoirfairelinux.net + sflphone_set_proxy (nthtoken (ibuf, 2)); + return 0; + } + IF_GOT("register stun ") { + // example: register stun stun.savoirfairelinux.net + sflphone_set_stun (nthtoken (ibuf, 2)); + return 0; + } + + /* Place a call */ + IF_GOT("call ") { + sflphone_call (token (ibuf)); + return 0; + } + + /* List calls */ + IF_GOT("calls") { + call_print_list (); + return 0; + } + + /* Answer incoming call */ + IF_GOT("answer") { + debug ("Answer call.\n"); + return 0; + } + + /* Hangup specific call */ + IF_GOT("hangup ") { + printf ("Hangup specific call.\n"); + return 0; + } + + /* Hangup current call */ + IF_GOT("hangup") { + printf ("Hangup current call.\n"); + return 0; + } + + /* Hold current call */ + IF_GOT("hold") { + printf ("Hold current call.\n"); + return 0; + } + + return 0; +} + +void +help_display (void) { + printf ("General call: call <number>, hangup <number>, answer\n"); + printf ("Current call: calls, hangup, hold\n"); + printf ("Configuration: setup\n"); + printf ("Register: register {fullname|sipuser|siphost|password|sipproxy|stun} <information>\n"); + printf ("Other: version, help, quit, quit softly\n"); +} diff --git a/src/gui/cli/user-input.h b/src/gui/cli/user-input.h new file mode 100644 index 0000000000000000000000000000000000000000..b4dac437d6027edd73eb0277ca6bc9619c68825c --- /dev/null +++ b/src/gui/cli/user-input.h @@ -0,0 +1,8 @@ +#ifndef __USER_INPUT_H__ +#define __USER_INPUT_H__ + + +int handle_input (void); +void help_display(void); + +#endif // __USER_INPUT_H__