diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d434d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +ABOUT-NLS +INSTALL +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +config.guess +config.h +config.h.in +config.log +config.rpath +config.status +config.sub +configure +depcomp +ant-phone-*.tar.gz +install-sh +intl +m4 +missing +mkinstalldirs +stamp-h1 +ylwrap diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..59e362d --- /dev/null +++ b/AUTHORS @@ -0,0 +1,11 @@ +Roland Stigge (lead developer / maintainer) + +Joerg Mayer (automake/autoconf Support) + +Lars Volkhardt (save callerid list to file) + +Mario Andrés Pagella (project logo) + +Translators: + FACORAT Fabrice (French) + Roel Koelewijn (Dutch) diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/COPYING @@ -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. + + + Copyright (C) + + 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) year 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. + + , 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/ChangeLog b/ChangeLog new file mode 100644 index 0000000..a607a0a --- /dev/null +++ b/ChangeLog @@ -0,0 +1,143 @@ +ant-phone 0.1.13, 2007-04-29, Roland Stigge + * Included Italian translation + +ant-phone 0.1.12, 2006-04-18, Roland Stigge + * Updated Swedish translation + +ant-phone 0.1.11, 2005-11-29, Roland Stigge + * Added Swedish, Turkish and Vietnamese translations + +ant-phone 0.1.10, 2004-01-09, Roland Stigge + * src/session.c: Added debug messages to gtk_handle_isdn_input + * Updated po/fr.po + +ant-phone 0.1.9, 2004-01-09, Roland Stigge + * README: Added reference to mailing list and archives + * Updated po/fr.po + +ant-phone 0.1.8, 2003-11-18, Roland Stigge + * src/isdn.h: Fixed ISDN_CONFIG_FILENAME to be /etc/isdn/isdn.conf + * src/callerid.c: Fixed segfault in cid_calls_merge() + +ant-phone 0.1.7, 2003-10-31, Roland Stigge + * Updated po/nl.po + +ant-phone 0.1.6, 2003-10-01, Roland Stigge + * Fixed yyloc compile warning, updating flex and bison source for + options and callerid (solves parsers location issue) + * Applied SuSE (Opteron, ...) porting patches, thanks to + Philipp Thomas : + ant-phone-codecleanup.diff + ant-phone-gettext_version.diff + ant-phone-isdn_log_name.diff + ant-phone-makefile.diff + * Adjusted to automake-1.7 + * Added lexer/parser for isdnformat(5) to get name of calls file + from i4l config file + * Obsoleted optionslexer in favour of isdnparser (nearly same format) + to conform rc file to isdnformat(5) + * Added ro.po translation file (Romanian) + +ant-phone 0.1.5, 2003-07-30, Roland Stigge + * Fixed bad codeset (UTF-8) in localized command line output + * Updated po/fr.po + * Fixed bug in resampling code for playback + * Added xpm icons in src/: 16x16, 32x32, 48x48, 64x64 + * Added auto detection between /var/lib/isdn/calls and + /var/log/isdn/calls as input file for callerid history + +ant-phone 0.1.4, 2003-07-06, Roland Stigge + * Fixed parse error in src/callerid.c (line 422 in version 0.1.3) + * Updated po/nl.po + * Coded variable size for buttons (suitable for i18n) in src/gtk.c + +ant-phone 0.1.3, 2003-07-06, Roland Stigge + * Fixed: recording of parts of one session to different files + (now dependent on session->vcon_time) + * Added playback / copy / deletion of recorded sessions to context + menu of CallerID rows + * Added po/fr.po, thanks to FACORAT Fabrice + * Fixed gettext_noop warning in globals.h (commented out #define) + * Fixed default notebook page in settings to first one + * Fixed focus on dial combo box after keypad (digit) input + * Added po/nl.po, thanks to roel koelewijn + * Changed gettext marks for menus (with "_" even for + gtk_item_factory_get_item() requests) to prevent ambiguousness + * Settings notebook: leave default page 1 instead of forcing focus + for msn_entry + +ant-phone 0.1.2, 2003-06-29, Roland Stigge + * Created hierarchy in source package structure (doc/, src/, ...) + * Port to GTK+ 2.x + * New logo, added to "About" window + * Added internationalization via GNU gettext; included po/de.po + +ant-phone 0.1.1, 2003-05-28, Roland Stigge + * Code cleanup + * Use gtk_window_present() for popup on GTK+ >= 2.0 + * Let keypad Enter act as Enter in dial combo box + * Added %s on substitution in execution string (= caller's number), + fixes problem that %n actually substitutes to own msn + * configure.ac: Added complaints on missing library sndfile + * Added copying permission statement to all source files + to conform to GNU advice on GPL usage + +ant-phone 0.1.0, 2003-04-27, Roland Stigge + * Added recording (depends on libsndfile) + * Added option to popup on incoming call + * Added configurable preset buttons + * Added isdnlog data import + * Added context menu to CallerID list + * Added delete function to CallerID list + * Added tracking for unanswered calls in CallerID list and in window + title + +ant-phone 0.0.8, 2002-12-09, Roland Stigge + * fixed "local bind: No such file or directory" and exit on startup + +ant-phone 0.0.7, 2002-12-06, Roland Stigge + * fixed include mistake in isdn.c + * added caller id saved history patch by + Lars Volkhardt + * added lexer/parser for caller id saved history file + * ant-phone now doesn't try to open sound device(s) at startup + when in audio release mode + * made number of caller id entries configurable + * added option to start a command when incoming call comes + * added command line option to let an already running ant make a call + +ant-phone 0.0.6, 2002-11-22, Roland Stigge + * made release audio mode default + * release audio also in settings + * added control pad (for dialing / generating touchtones) + * added touchtone generator + * added mute function + +ant-phone 0.0.5, 2002-11-13, Roland Stigge + * autoconf/automake support by Joerg Mayer + * added saved options / history files + * added "release audio devices on idle" + +ant-phone 0.0.4, 2002-11-03, Roland Stigge + * fixed gcc-3.2 warnings (session.c, sound.c), + reported by Joerg Mayer + * fixed delay problem with ALSA + +ant-phone 0.0.3, 2002-11-01, Roland Stigge + * fixed "Warning: Got audio input in ready mode." + * minor bug fixes + * added/improved GUI elements + * added installer (make install target) + * added man page + * added line level checker + +ant-phone 0.0.2, 2002-10-16, Roland Stigge + * renamed package to prevent "confusion" with ANT (Another Neat Tool) + * added caller id support + * added vanity number support + * added playing sound on incoming and outgoing calls + * bug fixes (hanging sound init) + +ant 0.0.1, 2002-09-23, Roland Stigge + * first release of ANT (ANT is Not a Telephone) + * basic functionality diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..7f6c5ab --- /dev/null +++ b/Makefile.am @@ -0,0 +1,7 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = intl doc src po + +EXTRA_DIST = config.rpath autogen.sh ABOUT-NLS + +AUTOMAKE_OPTIONS = dist-bzip2 diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/TODO b/TODO new file mode 100644 index 0000000..1848b4a --- /dev/null +++ b/TODO @@ -0,0 +1,74 @@ +Bugs: +===== +* Recording chopped up (only recorded file) +* Incoming delay +* Kernel cpu consumption in conversation mode. This is a kernel-internal + problem. While reading blocks from kernel OSS devices and ttyI, select(s) + seems to consume lot's of cpu time in kernel space while NOT BLOCKING! + -> not a big problem for now, just less idle tasks ;) + -> The problem doesn't seem to appear with ALSA + +Feature requests: +================= +* Real time support +* client/server architecture (ttyI network forward) (Sven Geggus , Arne Börs , martin@stigge.org) +* Makeln (Joerg Brueggemann ) +* database connection (caller id, times of incoming / outgoing, ...) + +Christoph Schütz : +* echo compensation +* configurable different ringtones (for different callers) + +Steffen Barszus : +* kde-kicker integration (drag number, pop up menu: number input) + +Pinto Joel : +* recording / scripting + +Roel Koelewijn : +* KDE address book integration +* TAPI telephone (dialling) support +* connection to external DB (Phonebook CDs) + +Martin Stigge : +* sorting callerid list +* playback soundfiles in converation mode + +arnd.feldmueller@t-online.de: +* answering machine +* DB, SQL, CSV input/output + +Arthur J. Schotgerrits : +* answering machine + +Matthias Fenner : +* command line interface + +Daniel Nöthen : +* mixer support (muting) +* (configurable?) auto set input to mic (reset on exit) +* separate configuration of logged / ringing msns + +Philipp Thomas : +* CAPI support, native ALSA support (both in Linux 2.6) (needed for SuSE 9.1 prepared for 02/2004) + +wolfgang@rohdewald.de: +* "execute on recorded message" option + +* aRTs support +* IP telephony support + +Feature ideas: (tell me to move some of them to "feature requests") +============== +* graphical sound visualization +* compensate sample drift (difference between isdn and oss) +* BSD (and possibly other) UNIX support +* H.323 client functionality +* encryption support +* adaptive (pre-)amp / echo compensation +* answering machine +* website enhancements / maintenance +* Remove remaining deprecated GTK+ functions, adjust to new API +* Logarithmical line level meter + +* improve calls file finding by parsing /etc/isdn/callerid.conf diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..bd4f5dc --- /dev/null +++ b/autogen.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +#gettextize --force --copy --intl --no-changelog +autopoint --force +aclocal +autoheader +automake --copy --add-missing --force-missing --gnu +autoconf diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..38cf921 --- /dev/null +++ b/configure.ac @@ -0,0 +1,77 @@ +# Process this file with autoconf to produce a configure script. +AC_INIT(ant-phone) +AM_INIT_AUTOMAKE(ant-phone, "0.1.13", ant-phone-devel@nongnu.org) +AC_PREREQ(2.53) +AC_CONFIG_SRCDIR([config.h.in]) +AM_CONFIG_HEADER([config.h]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_INSTALL + +AM_PROG_LEX +if test "$LEX" != flex; then + LEX="$SHELL $missing_dir/missing flex" + AC_SUBST(LEX_OUTPUT_ROOT, lex.yy) + AC_SUBST(LEXLIB, '') +fi +AC_PROG_YACC + +# Checks for libraries. +AC_CHECK_LIB([m], [floor]) +AC_CHECK_LIB([sndfile], [sf_open],, AC_MSG_ERROR(You need the libsndfile headers to build this package)) + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([fcntl.h limits.h math.h pwd.h stddef.h stdlib.h string.h sys/ioctl.h sys/stat.h sys/time.h sys/types.h termios.h unistd.h sndfile.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_HEADER_TIME + +# Checks for library functions. +AC_PROG_GCC_TRADITIONAL +AC_FUNC_MALLOC +AC_TYPE_SIGNAL +AC_FUNC_STRFTIME +AC_CHECK_FUNCS([floor select strdup strstr strtol mkdir strcasecmp]) + +# GTK+ 2.0: +PKG_CHECK_MODULES(DEPS, gtk+-2.0) +AC_SUBST(DEPS_CFLAGS) +AC_SUBST(DEPS_LIBS) + +# +# If we're running gcc, add '-Wall -W' to CFLAGS, and add +# '-D_U_="__attribute__((unused))"' as well, so we can use _U_ to +# flag unused function arguments and not get warnings about them. +# +# Otherwise, add '-D_U_=""', so that _U_ used to flag an unused function +# argument will compile with non-GCC compilers. +# +AC_MSG_CHECKING(to see if we can add '-Wall -W' to CFLAGS) +if test x$GCC != x ; then + CFLAGS="$CFLAGS -D_U_=\"__attribute__((unused))\" -Wall -W -D_GNU_SOURCE -O3" + AC_MSG_RESULT(yes) +else + CFLAGS="-D_U_=\"\" $CFLAGS" + AC_MSG_RESULT(no) +fi + +# GNU gettext +AM_GNU_GETTEXT +AM_GNU_GETTEXT_VERSION(0.16.1) + +# directory containing configuration support files +# defaults to package root +#AC_CONFIG_AUX_DIR + +AC_CONFIG_FILES([Makefile + intl/Makefile + po/Makefile.in + doc/Makefile + src/Makefile]) +AC_OUTPUT + diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..d4c9db9 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,7 @@ +## Process this file with automake to produce Makefile.in + +man_MANS = ant-phone.1 + +EXTRA_DIST = \ + $(man_MANS) + diff --git a/doc/ant-phone.1 b/doc/ant-phone.1 new file mode 100644 index 0000000..2bbcfad --- /dev/null +++ b/doc/ant-phone.1 @@ -0,0 +1,60 @@ +.TH ant-phone 1 "27 April 2003" "Version 0.1.0" "ANT Manual Pages" +.SH NAME +ant-phone \- an interactive ISDN telephone application +.SH SYNOPSIS +.B ant-phone +.RI [ options ] +.SH DESCRIPTION +ant-phone is part of ANT (ANT is Not a Telephone). It let's you make and receive telephone calls and talk via sound devices. It uses ISDN4Linux ttyI devices. +.SH OPTIONS +ant-phone accepts the following options: +.TP +.B \-h, \-\-help +Show summary of options +.TP +.B \-v, \-\-version +Print version information +.TP +.B \-r, \-\-cleanup +Remove stale socket file left by accident by a previous run of ANT. You only need this option if ANT says: "local bind: Address already in use" +.TP +.BI "\-d, \-\-debug" [ = debuglevel] +Print additional runtime debugging data to stdout, debuglevel = 1..2 +.TP +.BI "\-i, \-\-soundin=" device +OSS compatible device for input (recording), +default: /dev/dsp +.TP +.BI "\-o, \-\-soundout=" device +OSS compatible device for output (playback), +default: /dev/dsp +.TP +.BI "\-m, \-\-msn=" msn +identifying MSN (for outgoing calls), 0 for master MSN of this +termination/port, +default: 0 +.TP +.BI "\-l, \-\-msns=" msns +MSNs to listen on, semicolon-separated list or '*', +default: * +.TP +.BI "\-c, \-\-call=" number +Make a running instance of ANT make a call to the specified number, +useful for calling from an external address book application +.SH NOTES +If the used sound devices (arguments of \-\-soundin and \-\-soundout) +are equal, a full duplex sound device is needed. +.SH FILES +.TP +.I ~/.ant-phone/history +the last dialed numbers +.TP +.I ~/.ant-phone/options +user specific options file +.TP +.I ~/.ant-phone/callerid +saved history of incoming and outgoing calls +.SH BUGS +The GTK+ main loop consumes all the system CPU time. This is due to the Linux kernel select() call consuming the time while waiting for a completed data block. This only appears with some Linux kernel OSS drivers, not with ALSA. +.SH AUTHORS +ANT was developed by Roland Stigge , based on ideas from IVCALL, Copyright 2002 Lennart Poettering. G.711 handling by Sun Microsystems. Contributions by Joerg Mayer , Lars Volkhardt . diff --git a/po/.gitignore b/po/.gitignore new file mode 100644 index 0000000..5ba69d7 --- /dev/null +++ b/po/.gitignore @@ -0,0 +1,19 @@ +Makefile.in.in +Makevars.template +POTFILES +Rules-quot +*.gmo +boldquot.sed +en@boldquot.header +en@boldquot.insert-header +en@boldquot.po +en@quot.header +en@quot.insert-header +en@quot.po +ant-phone.pot +insert-header.sin +quot.sed +remove-potcdate.sed +remove-potcdate.sin +stamp-po + diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..0177e02 --- /dev/null +++ b/po/LINGUAS @@ -0,0 +1,3 @@ +# Set of available languages. +en@quot en@boldquot +de fr it nl ro sv tr vi diff --git a/po/Makevars b/po/Makevars new file mode 100644 index 0000000..7c7910a --- /dev/null +++ b/po/Makevars @@ -0,0 +1,41 @@ +# Makefile variables for PO directory in any package using GNU gettext. + +# Usually the message domain is the same as the package name. +DOMAIN = $(PACKAGE) + +# These two variables depend on the location of this directory. +subdir = po +top_builddir = .. + +# These options get passed to xgettext. +XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ --from-code=ISO-8859-15 + +# This is the copyright holder that gets inserted into the header of the +# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding +# package. (Note that the msgstr strings, extracted from the package's +# sources, belong to the copyright holder of the package.) Translators are +# expected to transfer the copyright for their translations to this person +# or entity, or to disclaim their copyright. The empty string stands for +# the public domain; in this case the translators are expected to disclaim +# their copyright. +COPYRIGHT_HOLDER = Roland Stigge + +# This is the email address or URL to which the translators shall report +# bugs in the untranslated strings: +# - Strings which are not entire sentences, see the maintainer guidelines +# in the GNU gettext documentation, section 'Preparing Strings'. +# - Strings which use unclear terms or require additional context to be +# understood. +# - Strings which make invalid assumptions about notation of date, time or +# money. +# - Pluralisation problems. +# - Incorrect English spelling. +# - Incorrect formatting. +# It can be your email address, or a mailing list address where translators +# can write to without being subscribed, or the URL of a web page through +# which the translators can contact you. +MSGID_BUGS_ADDRESS = stigge@antcom.de + +# This is the list of locale categories, beyond LC_MESSAGES, for which the +# message catalogs shall be used. It is usually empty. +EXTRA_LOCALE_CATEGORIES = diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 0000000..23d2411 --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,24 @@ +# List of source files containing translatable strings. +# Copyright (C) 2003 Roland Stigge + +src/ant-phone.c +src/callerid.c +src/calleridlexer.l +src/calleridparser.y +src/client.c +src/controlpad.c +src/fxgenerator.c +src/gtk.c +src/gtksettings.c +src/isdn.c +src/llcheck.c +src/mediation.c +src/isdnlexer.l +src/isdnparser.y +src/recording.c +src/server.c +src/session.c +src/settings.c +src/sound.c +src/util.c + diff --git a/po/de.po b/po/de.po new file mode 100644 index 0000000..bace7c9 --- /dev/null +++ b/po/de.po @@ -0,0 +1,669 @@ +# German translation of the ant-phone package +# Copyright (C) 2003 Roland Stigge +# This file is distributed under the same license as the ant-phone package. +# Roland Stigge , 2003 +# +msgid "" +msgstr "" +"Project-Id-Version: ant-phone 0.1.2\n" +"Report-Msgid-Bugs-To: stigge@antcom.de\n" +"POT-Creation-Date: 2004-04-03 18:51+0200\n" +"PO-Revision-Date: 2003-06-29 18:01+ZONE\n" +"Last-Translator: Roland Stigge \n" +"Language-Team: German \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-15\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/ant-phone.c:170 +#, c-format +msgid "" +"Usage: %s [OPTION...]\n" +"\n" +"Options:\n" +" -h, --help Show this help message\n" +" -v, --version Print version information\n" +" -r, --cleanup Remove stale socket file (left by accident by\n" +" previous run)\n" +" -d, --debug[=level] Print additional runtime debugging data to stdout\n" +" level = 1..2\n" +" -i, --soundin=DEVICE OSS compatible device for input (recording),\n" +" default: /dev/dsp\n" +" -o, --soundout=DEVICE OSS compatible device for output (playback),\n" +" default: /dev/dsp\n" +" -m, --msn=MSN identifying MSN (for outgoing calls), 0 for " +"master\n" +" MSN of this termination/port\n" +" default: 0\n" +" -l, --msns=MSNS MSNs to listen on, semicolon-separated list or " +"'*'\n" +" default: *\n" +" -c, --call=NUMBER Call specified number\n" +"\n" +"Note: If arguments of --soundin and --soundout are equal, a full duplex\n" +" sound device is needed.\n" +msgstr "" +"Aufruf: %s [OPTION...]\n" +"\n" +"Optionen:\n" +" -h, --help Diese Hilfe ausgeben\n" +" -v, --version Versionsinformation ausgeben\n" +" -r, --cleanup Alte Socketdatei löschen (evtl. aus Versehen vom\n" +" vorigen Aufruf übrig gelassen)\n" +" -d, --debug[=level] Zusätzliche Testinformationen auf Standardausgabe\n" +" ausgeben (level = 1..2)\n" +" -i, --soundin=DEVICE OSS-kompatibles Gerät für die Eingabe (Aufnahme),\n" +" Voreinstellung: /dev/dsp\n" +" -o, --soundout=DEVICE OSS-kompatibles Gerät für die Ausgabe " +"(Wiedergabe),\n" +" Voreinstellung: /dev/dsp\n" +" -m, --msn=MSN identifizierende MSN (für abgehende Rufe), 0 für\n" +" Haupt-MSN dieses Anschlusses,\n" +" Voreinstellung: 0\n" +" -l, --msns=MSNS MSNs, auf welche reagiert wird, Strichpunkt-\n" +" getrennte Liste oder '*',\n" +" Voreinstellung: *\n" +" -c, --call=NUMBER Angegebene Nummer anrufen\n" +"\n" +"Anmerkung: Wenn die Argumente von --soundin und --soundout gleich sind, " +"wird\n" +" ein Full-Duplex- (/Zwei-Wege-) Gerät verwendet.\n" + +#: src/ant-phone.c:221 +#, c-format +msgid "Calling %s... " +msgstr "Rufe %s ... " + +#: src/ant-phone.c:225 +#, c-format +msgid "successful.\n" +msgstr "erfolgreich.\n" + +#: src/callerid.c:131 +msgid "Delete Entry" +msgstr "Lösche Zeile" + +#: src/callerid.c:143 +msgid "" +"Are you sure you want to\n" +"delete this entry?" +msgstr "" +"Wollen Sie diesen Eintrag\n" +"wirklich löschen?" + +#: src/callerid.c:148 +msgid "Delete recording" +msgstr "Lösche Aufnahme" + +#: src/callerid.c:266 +#, c-format +msgid "Enter the base filename for %s file" +msgstr "Basisdateiname für die %s Datei" + +#: src/callerid.c:312 +msgid "Do you really want to delete this recording?" +msgstr "Wollen Sie diese Aufnahme wirklich löschen?" + +#: src/callerid.c:336 src/callerid.c:362 +msgid "/_Playback" +msgstr "/_Wiedergabe" + +#: src/callerid.c:337 src/callerid.c:366 +msgid "/_Save as..." +msgstr "/_Sichern unter..." + +#: src/callerid.c:338 src/callerid.c:370 +msgid "/Delete _Recording" +msgstr "/Lösche _Aufnahme" + +#: src/callerid.c:340 src/callerid.c:374 +msgid "/_Delete Row" +msgstr "/_Lösche Zeile" + +#: src/callerid.c:423 src/gtksettings.c:455 +msgid "Caller ID" +msgstr "Caller ID" + +#: src/callerid.c:426 +msgid "Date/Time" +msgstr "Datum/Zeit" + +#: src/callerid.c:427 +msgid "Type" +msgstr "Typ" + +#: src/callerid.c:428 +msgid "From" +msgstr "Von" + +#: src/callerid.c:429 +msgid "To" +msgstr "Nach" + +#: src/callerid.c:430 +msgid "Duration" +msgstr "Dauer" + +#: src/callerid.c:759 +msgid "(UNKNOWN)" +msgstr "(UNBEKANNT)" + +#: src/callerid.c:828 +#, c-format +msgid "ANT: %d unanswered" +msgstr "ANT: %d unbeantwortet" + +#: src/controlpad.c:101 +#, c-format +msgid "Preset %c" +msgstr "Kurzwahl %c" + +#: src/controlpad.c:108 +#, c-format +msgid "Please input new preset data for button %c:" +msgstr "Bitte geben Sie die neue Kurzwahlsequenz für Taste %c ein:" + +#: src/controlpad.c:121 +msgid "Name:" +msgstr "Name:" + +#: src/controlpad.c:124 src/gtk.c:561 +msgid "Number:" +msgstr "Nummer:" + +#: src/controlpad.c:144 src/gtk.c:212 src/gtk.c:331 src/gtk.c:408 +#: src/gtksettings.c:571 src/llcheck.c:422 +msgid "OK" +msgstr "OK" + +#: src/controlpad.c:157 src/gtksettings.c:616 src/session.c:68 +msgid "Cancel" +msgstr "Abbruch" + +#: src/controlpad.c:315 +msgid "Backspace" +msgstr "Rückschritt" + +#: src/controlpad.c:315 +msgid "Preset 1" +msgstr "Kurzwahl 1" + +#: src/controlpad.c:316 +msgid "Clear Number" +msgstr "Nummer rücksetzen" + +#: src/controlpad.c:316 +msgid "Preset 2" +msgstr "Kurzwahl 2" + +#: src/controlpad.c:317 +msgid "Redial" +msgstr "Wahlwiederholung" + +#: src/controlpad.c:317 +msgid "Preset 3" +msgstr "Kurzwahl 3" + +#: src/controlpad.c:318 +msgid "Mute Microphone" +msgstr "Mikro stummschalten" + +#: src/controlpad.c:318 +msgid "Preset 4" +msgstr "Kurzwahl 4" + +#: src/controlpad.c:351 +msgid "Control" +msgstr "Steuerung" + +#: src/controlpad.c:423 +msgid "Recording" +msgstr "Aufnahme" + +#: src/controlpad.c:434 +msgid "Record to file" +msgstr "In Datei aufnehmen" + +#: src/controlpad.c:445 +msgid "Record local channel" +msgstr "lokalen Kanal aufnehmen" + +#: src/controlpad.c:456 +msgid "Record remote channel" +msgstr "entfernten Kanal aufnehmen" + +#: src/gtk.c:230 src/gtksettings.c:229 +msgid "ANT Note" +msgstr "ANT Notiz" + +#: src/gtk.c:231 +msgid "" +"Can't open audio device.\n" +"Please stop other applications using\n" +"the audio device(s) or check your\n" +"device settings and try again." +msgstr "" +"Kann das Tonausgabegerät nicht öffnen.\n" +"Bitte halten Sie andere Programme,\n" +"welche das Gerät / die Geräte verwenden, an,\n" +"oder prüfen Sie die Geräteeinstellungen,\n" +"und versuchen Sie es erneut." + +#: src/gtk.c:260 +msgid "Sound input device:" +msgstr "Toneingabegerät:" + +#: src/gtk.c:261 +msgid "Input speed:" +msgstr "Eingabegeschwindigkeit:" + +#: src/gtk.c:261 src/gtk.c:264 src/gtk.c:265 src/gtk.c:267 src/gtk.c:271 +#: src/gtk.c:274 src/gtk.c:275 src/gtk.c:277 +msgid "[inactive]" +msgstr "[inaktiv]" + +#: src/gtk.c:263 +msgid "Input sample size (bits):" +msgstr "Eingabewortbreite (Bits):" + +#: src/gtk.c:265 src/gtk.c:275 +msgid "Input fragment size (samples):" +msgstr "Eingabefragmentgröße (Worte):" + +#: src/gtk.c:267 +msgid "Input channels:" +msgstr "Eingabekanäle:" + +#: src/gtk.c:270 +msgid "Sound output device:" +msgstr "Tonausgabegerät:" + +#: src/gtk.c:271 +msgid "Output speed:" +msgstr "Ausgabegeschwindigkeit:" + +#: src/gtk.c:273 +msgid "Output sample size (bits):" +msgstr "Ausgabewortbreite (Bits):" + +#: src/gtk.c:277 +msgid "Output channels:" +msgstr "Ausgabekanäle:" + +#: src/gtk.c:280 +msgid "ISDN device:" +msgstr "ISDN-Gerät:" + +#: src/gtk.c:281 +msgid "ISDN speed (samples):" +msgstr "ISDN-Geschwindigkeit (Worte):" + +#: src/gtk.c:282 +msgid "ISDN sample size (bits):" +msgstr "ISDN-Wortbreite (Bits):" + +#: src/gtk.c:283 +msgid "ISDN fragment size (bytes):" +msgstr "ISDN-Fragmentgröße (Bytes):" + +#: src/gtk.c:295 +msgid "ANT Info" +msgstr "ANT Info" + +#: src/gtk.c:366 +msgid "About ANT" +msgstr "Über ANT" + +#: src/gtk.c:382 +#, c-format +msgid "" +"ANT (ANT is Not a Telephone) Version %s\n" +"Copyright 2002, 2003 Roland Stigge\n" +"\n" +"This is an ISDN telephone application\n" +"written for GNU/Linux and ISDN4Linux for\n" +"communicating via a full duplex soundcard (or\n" +"multiple sound devices if you like) and an\n" +"audio capable ISDN4Linux ISDN device\n" +"\n" +"Contact:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"Mailing list: ant-phone-devel@nongnu.org" +msgstr "" +"ANT (ANT is Not a Telephone) Version %s\n" +"Copyright 2002, 2003 Roland Stigge\n" +"\n" +"Dies ist eine ISDN-Telefonanwendung, welche für\n" +"GNU/Linux und ISDN4Linux für die Kommunikation\n" +"mit einem Full-Duplex- (/Zwei-Wege-) Gerät (oder\n" +"mehreren Ton-Ein-/Ausgabegeräten) und einem\n" +"audio-fähigen ISDN4Linux-ISDN-Gerät geschrieben wurde\n" +"\n" +"Kontakt:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"Mailingliste: ant-phone-devel@nongnu.org" + +#: src/gtk.c:420 +msgid "ANT License" +msgstr "ANT Lizenz" + +#: src/gtk.c:421 +msgid "" +"ANT (ANT is Not a Telephone)\n" +"Copyright (C) 2002, 2003 Roland Stigge\n" +"\n" +"This program is free software; you can redistribute it and/or\n" +"modify it under the terms of the GNU General Public License\n" +"as published by the Free Software Foundation; either version 2\n" +"of the License, or (at your option) any later version.\n" +"\n" +"This program is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n" +"\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program; if not, write to the Free Software\n" +"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." +msgstr "" +"ANT (ANT is Not a Telephone)\n" +"Copyright (C) 2002, 2003 Roland Stigge\n" +"\n" +"Dieses Programm ist Freie Software; Sie können es unter den\n" +"Bedingungen der GNU General Public License Version 2 oder (nach\n" +"Belieben) neuer, wie von der Free Software Foundation\n" +"veröffentlicht, weitergeben und/oder modifizieren.\n" +"\n" +"Dieses Programm wird in der Hoffnung, dass es nützlich sein wird,\n" +"herausgegeben. Es wird jedoch KEINE GARANTIE übernommen. Selbst\n" +"die implizite Garantie der MARKTGÄNGIGKEIT oder TAUGLICHKEIT FÜR\n" +"EINEN BESTIMMTEN ZWECK kann nicht gewährleistet werden.\n" +"Siehe GNU General Public License für Details.\n" +"\n" +"Sie sollten eine Kopie der GNU General Public License\n" +"zusammen mit diesem Programm erhalten haben. Falls nicht,\n" +"schreiben Sie bitte an die\n" +"\n" +"Free Software Foundation, Inc.\n" +"59 Temple Place - Suite 330\n" +"Boston\n" +"MA 02111-1307\n" +"USA." + +#: src/gtk.c:454 +msgid "/Phon_e" +msgstr "/_Telefon" + +#: src/gtk.c:455 +msgid "/Phone/_Info Window" +msgstr "/Telefon/_Info Fenster" + +#: src/gtk.c:456 src/gtk.c:504 +msgid "/Phone/_Line Level Check" +msgstr "/Telefon/_Pegelkontrolle" + +#: src/gtk.c:458 +msgid "/Phone/" +msgstr "/Telefon/" + +#: src/gtk.c:459 +msgid "/Phone/_Quit" +msgstr "/Telefon/_Beenden" + +#: src/gtk.c:461 +msgid "/_View" +msgstr "/_Ansicht" + +#: src/gtk.c:462 src/gtk.c:492 +msgid "/View/_Caller ID Monitor" +msgstr "/Ansicht/_Caller-ID-Anzeige" + +#: src/gtk.c:464 src/gtk.c:495 +msgid "/View/_Line Level Meters" +msgstr "/Ansicht/_Pegelanzeigen" + +#: src/gtk.c:466 src/gtk.c:498 +msgid "/View/Control _Pad" +msgstr "/Ansicht/_Steuerfeld" + +#: src/gtk.c:468 +msgid "/_Options" +msgstr "/_Optionen" + +#: src/gtk.c:469 src/gtk.c:501 +msgid "/Options/_Settings" +msgstr "/Optionen/_Einstellungen" + +#: src/gtk.c:471 +msgid "/_Help" +msgstr "/_Hilfe" + +#: src/gtk.c:472 +msgid "/Help/_About" +msgstr "/Hilfe/_Über" + +#: src/gtk.c:473 +msgid "/Help/_License" +msgstr "/Hilfe/_Lizenz" + +#: src/gtk.c:551 src/gtksettings.c:431 src/session.c:68 +msgid "Dialing" +msgstr "Wählen" + +#: src/gtk.c:783 src/gtk.c:784 +msgid "MUTED" +msgstr "STUMM" + +#: src/gtksettings.c:230 +msgid "Bad isdn/sound device settings, please try again." +msgstr "" +"Ungültige Einstellungen der ISDN/Ton-Ein-/Ausgabegeräte, bitte neu versuchen." + +#: src/gtksettings.c:293 +msgid "ANT Settings" +msgstr "ANT Einstellungen" + +#: src/gtksettings.c:306 +msgid "Application" +msgstr "Anwendung" + +#: src/gtksettings.c:308 +msgid "Options" +msgstr "Optionen" + +#: src/gtksettings.c:320 +msgid "Save options on exit" +msgstr "Beim Beenden Optionen sichern" + +#: src/gtksettings.c:327 +msgid "Popup main window on incoming call" +msgstr "Bei kommenden Rufen in den Vordergrund bringen" + +#: src/gtksettings.c:333 +msgid "Execute on incoming call:" +msgstr "Bei kommenden Rufen ausführen:" + +#: src/gtksettings.c:344 +msgid "Recording Format" +msgstr "Aufnahmeformat" + +#: src/gtksettings.c:354 +msgid "Microsoft WAV, uLaw" +msgstr "" + +#: src/gtksettings.c:364 +msgid "Microsoft WAV, 16-bit signed" +msgstr "" + +#: src/gtksettings.c:374 +msgid "Apple/SGI AIFF, uLaw" +msgstr "" + +#: src/gtksettings.c:384 +msgid "Apple/SGI AIFF, 16-bit signed" +msgstr "" + +#: src/gtksettings.c:397 +msgid "Phone" +msgstr "Telefon" + +#: src/gtksettings.c:399 +msgid "ISDN" +msgstr "" + +#: src/gtksettings.c:411 +msgid "Identifying MSN:" +msgstr "Identifizierende MSN:" + +#: src/gtksettings.c:421 +msgid "Listen to MSNs:" +msgstr "Höre auf MSNs:" + +#: src/gtksettings.c:443 +msgid "Dial history size:" +msgstr "Größe der Wählhistorie:" + +#: src/gtksettings.c:467 +msgid "Maximum CID rows:" +msgstr "Maximale CID-Zeilen:" + +#: src/gtksettings.c:475 src/gtksettings.c:503 +msgid "[no limit]" +msgstr "[keine Begrenzung]" + +#: src/gtksettings.c:484 +msgid "Read isdnlog data on startup" +msgstr "isdnlog-Daten beim Start lesen" + +#: src/gtksettings.c:491 +msgid "Maximum days to read from isdnlog:" +msgstr "Maximale Anzahl Tage, welche von isdnlog gelesen werden:" + +#: src/gtksettings.c:520 +msgid "Sound Devices" +msgstr "Ton-Ein-/Ausgabegeräte" + +#: src/gtksettings.c:522 +msgid "OSS" +msgstr "" + +#: src/gtksettings.c:534 +msgid "Input sound device:" +msgstr "Ton-Eingabegerät:" + +#: src/gtksettings.c:546 +msgid "Output sound device:" +msgstr "Ton-Ausgabegerät" + +#: src/gtksettings.c:559 +msgid "Release unused devices" +msgstr "Unbenutzte Ton-Ein-/Ausgabegeräte freigeben" + +#: src/gtksettings.c:609 +msgid "Save" +msgstr "Sichern" + +#: src/llcheck.c:371 +msgid "Line Level Check" +msgstr "Pegelkontrolle" + +#: src/llcheck.c:383 +msgid "" +"Please check the line input level\n" +"and adjust it using your favorite\n" +"mixer application.\n" +"You can also play a sound\n" +"to test the sound output." +msgstr "" +"Bitte testen Sie den Pegel\n" +"und justieren Sie ihn mit dem\n" +"Mixerprogramm Ihrer Wahl.\n" +"Sie können auch einen Ton ausgeben\n" +"lassen, um die Klangausgabe zu prüfen." + +#: src/llcheck.c:405 +msgid "Play sound" +msgstr "Ton ausgeben" + +#: src/session.c:65 +msgid "Ready" +msgstr "Bereit" + +#: src/session.c:65 +msgid "Dial" +msgstr "Wählen" + +#: src/session.c:65 src/session.c:69 src/session.c:70 +msgid "Hang up" +msgstr "Auflegen" + +#: src/session.c:66 src/session.c:67 +msgid "RING" +msgstr "KLINGELN" + +#: src/session.c:66 src/session.c:67 +msgid "Answer" +msgstr "Antworten" + +#: src/session.c:66 src/session.c:67 +msgid "Reject" +msgstr "Ablehnen" + +#: src/session.c:68 src/session.c:69 src/session.c:70 src/session.c:71 +msgid "Pick up" +msgstr "Abheben" + +#: src/session.c:69 +msgid "B-Channel open" +msgstr "B-Kanal offen" + +#: src/session.c:70 +msgid "Setup" +msgstr "Einstellungen" + +#: src/session.c:71 +msgid "Playback" +msgstr "/Wiedergabe" + +#: src/session.c:71 +msgid "Stop" +msgstr "Einstellungen" + +#: src/session.c:377 +#, c-format +msgid "Preset %d" +msgstr "Kurzwahl %d" + +#: src/session.c:699 +msgid "(HW ERROR)" +msgstr "(HW FEHLER)" + +#: src/session.c:1000 +msgid "Audio OFF" +msgstr "Ton AUS" + +#: src/session.c:1000 +msgid "Audio ON" +msgstr "Ton AN" + +#: src/session.c:1097 +msgid "(BUSY)" +msgstr "(BESETZT)" + +#: src/session.c:1103 +msgid "(TIMEOUT)" +msgstr "" + +#: src/session.c:1139 +msgid "(RUNG)" +msgstr "(RUF)" + +#: src/session.c:1381 +msgid "(ABORTED)" +msgstr "(ABGEBROCHEN)" + +#: src/session.c:1389 +msgid "(REJECTED)" +msgstr "(ABGELEHNT)" diff --git a/po/fr.po b/po/fr.po new file mode 100644 index 0000000..232998b --- /dev/null +++ b/po/fr.po @@ -0,0 +1,662 @@ +# Messages français pour GNU concernant ant-phone. +# Copyright © 2004 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Michel Robitaille , traducteur depuis/since 1996. +# +msgid "" +msgstr "" +"Project-Id-Version: GNU ant-phone 0.1.4\n" +"Report-Msgid-Bugs-To: stigge@antcom.de\n" +"POT-Creation-Date: 2004-04-03 18:51+0200\n" +"PO-Revision-Date: 2004-05-10 08:00-0500\n" +"Last-Translator: Michel Robitaille \n" +"Language-Team: French \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8-bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: src/ant-phone.c:170 +#, c-format +msgid "" +"Usage: %s [OPTION...]\n" +"\n" +"Options:\n" +" -h, --help Show this help message\n" +" -v, --version Print version information\n" +" -r, --cleanup Remove stale socket file (left by accident by\n" +" previous run)\n" +" -d, --debug[=level] Print additional runtime debugging data to stdout\n" +" level = 1..2\n" +" -i, --soundin=DEVICE OSS compatible device for input (recording),\n" +" default: /dev/dsp\n" +" -o, --soundout=DEVICE OSS compatible device for output (playback),\n" +" default: /dev/dsp\n" +" -m, --msn=MSN identifying MSN (for outgoing calls), 0 for " +"master\n" +" MSN of this termination/port\n" +" default: 0\n" +" -l, --msns=MSNS MSNs to listen on, semicolon-separated list or " +"'*'\n" +" default: *\n" +" -c, --call=NUMBER Call specified number\n" +"\n" +"Note: If arguments of --soundin and --soundout are equal, a full duplex\n" +" sound device is needed.\n" +msgstr "" +"Usage: %s [OPTION...]\n" +"\n" +"Options:\n" +" -h, --help affichier l'aide-mémoire\n" +" -v, --version affichier la version du logiciel\n" +" -r, --cleanup enlever le fichier du socket figé (laissé lors\n" +" l'exécution précédente)\n" +" -d, --debug[=niveau] afficher des informations additionnelles de mises " +"au point sur stdout\n" +" niveau = 1..2\n" +" -i, --soundin=PERI PÉRIphérique compatible OSS pour la sortie " +"(enregistrement),\n" +" par défaut: /dev/dsp\n" +" -o, --soundout=PERI PÉRIphérique compatible OSS pour l'entrée " +"(écoute),\n" +" par défaut: /dev/dsp\n" +" -m, --msn=MSN identificateur MSN (pour les appels sortant), 0 " +"pour maître\n" +" MSN de terminaison/port\n" +" par défaut: 0\n" +" -l, --msns=MSNS MSNs d'écoute, liste séparée par des « ; » ou '*'\n" +" par défaut: *\n" +" -c, --call=NUMÉRO numéro d'appel spécifique\n" +"\n" +"Note: si les arguments de --soundin et --soundout sont identiques, un " +"périphérique\n" +" de son fonctionnant en mode duplex est nécessaire.\n" + +#: src/ant-phone.c:221 +#, c-format +msgid "Calling %s... " +msgstr "Appel en cour %s... " + +#: src/ant-phone.c:225 +#, c-format +msgid "successful.\n" +msgstr "succès.\n" + +#: src/callerid.c:131 +msgid "Delete Entry" +msgstr "Détruire l'entrée" + +#: src/callerid.c:143 +msgid "" +"Are you sure you want to\n" +"delete this entry?" +msgstr "" +"Êtes-vous certains de vouloir\n" +"détruire cette entrée?" + +#: src/callerid.c:148 +msgid "Delete recording" +msgstr "Destruction de l'enregistrement" + +#: src/callerid.c:266 +#, c-format +msgid "Enter the base filename for %s file" +msgstr "Fournir le nom de base du fichier %s" + +#: src/callerid.c:312 +msgid "Do you really want to delete this recording?" +msgstr "Désirez-vous réellement détruire cet enregistrement?" + +#: src/callerid.c:336 src/callerid.c:362 +msgid "/_Playback" +msgstr "/_Playback (ré-écoute" + +#: src/callerid.c:337 src/callerid.c:366 +msgid "/_Save as..." +msgstr "/_Sauvagarder sous..." + +#: src/callerid.c:338 src/callerid.c:370 +msgid "/Delete _Recording" +msgstr "/Détruire l'_Enregistrement" + +#: src/callerid.c:340 src/callerid.c:374 +msgid "/_Delete Row" +msgstr "/_Détruire la rangée" + +#: src/callerid.c:423 src/gtksettings.c:455 +msgid "Caller ID" +msgstr "Identificateur de l'appelant" + +#: src/callerid.c:426 +msgid "Date/Time" +msgstr "Date/Heure" + +#: src/callerid.c:427 +msgid "Type" +msgstr "Type" + +#: src/callerid.c:428 +msgid "From" +msgstr "De" + +#: src/callerid.c:429 +msgid "To" +msgstr "À" + +#: src/callerid.c:430 +msgid "Duration" +msgstr "Durée" + +#: src/callerid.c:759 +msgid "(UNKNOWN)" +msgstr "(INCONNU)" + +#: src/callerid.c:828 +#, c-format +msgid "ANT: %d unanswered" +msgstr "ANT: %d non répondus" + +#: src/controlpad.c:101 +#, c-format +msgid "Preset %c" +msgstr "Présélection %c" + +#: src/controlpad.c:108 +#, c-format +msgid "Please input new preset data for button %c:" +msgstr "SVP fournir les nouvelles données de présélection pour le bouton %c:" + +#: src/controlpad.c:121 +msgid "Name:" +msgstr "Nom:" + +#: src/controlpad.c:124 src/gtk.c:561 +msgid "Number:" +msgstr "Numéro:" + +#: src/controlpad.c:144 src/gtk.c:212 src/gtk.c:331 src/gtk.c:408 +#: src/gtksettings.c:571 src/llcheck.c:422 +msgid "OK" +msgstr "OK" + +#: src/controlpad.c:157 src/gtksettings.c:616 src/session.c:68 +msgid "Cancel" +msgstr "Annuler" + +#: src/controlpad.c:315 +msgid "Backspace" +msgstr "Espace arrière" + +#: src/controlpad.c:315 +msgid "Preset 1" +msgstr "Présélection 1" + +#: src/controlpad.c:316 +msgid "Clear Number" +msgstr "Effacer le numéro" + +#: src/controlpad.c:316 +msgid "Preset 2" +msgstr "Présélection 2" + +#: src/controlpad.c:317 +msgid "Redial" +msgstr "Recomposer" + +#: src/controlpad.c:317 +msgid "Preset 3" +msgstr "Présélection 3" + +#: src/controlpad.c:318 +msgid "Mute Microphone" +msgstr "Éteindre le microphone" + +#: src/controlpad.c:318 +msgid "Preset 4" +msgstr "Présélection 4" + +#: src/controlpad.c:351 +msgid "Control" +msgstr "Contrôle" + +#: src/controlpad.c:423 +msgid "Recording" +msgstr "Enregistrement en cours" + +#: src/controlpad.c:434 +msgid "Record to file" +msgstr "Enregistrer dans un fichier" + +#: src/controlpad.c:445 +msgid "Record local channel" +msgstr "Enregister sur canal local" + +#: src/controlpad.c:456 +msgid "Record remote channel" +msgstr "Enregistrer sur canal distant" + +#: src/gtk.c:230 src/gtksettings.c:229 +msgid "ANT Note" +msgstr "Note ANT" + +#: src/gtk.c:231 +msgid "" +"Can't open audio device.\n" +"Please stop other applications using\n" +"the audio device(s) or check your\n" +"device settings and try again." +msgstr "" +"Ne peut ouvrir le périphérique audio.\n" +"SVP stopper les autres applications utilisant\n" +"le périphérique audio ou vérifier la\n" +"configuration du périphérique et essayer à nouveau." + +#: src/gtk.c:260 +msgid "Sound input device:" +msgstr "Entrée du périphérique de son:" + +#: src/gtk.c:261 +msgid "Input speed:" +msgstr "Vitesse d'entrée" + +#: src/gtk.c:261 src/gtk.c:264 src/gtk.c:265 src/gtk.c:267 src/gtk.c:271 +#: src/gtk.c:274 src/gtk.c:275 src/gtk.c:277 +msgid "[inactive]" +msgstr "[inactif]" + +#: src/gtk.c:263 +msgid "Input sample size (bits):" +msgstr "Taille d'échantillon d'entrée (en bits):" + +#: src/gtk.c:265 src/gtk.c:275 +msgid "Input fragment size (samples):" +msgstr "Taille de fragment d'entrée (échantillons)" + +#: src/gtk.c:267 +msgid "Input channels:" +msgstr "Canaux d'entrée:" + +#: src/gtk.c:270 +msgid "Sound output device:" +msgstr "Sortie du périphérique de son:" + +#: src/gtk.c:271 +msgid "Output speed:" +msgstr "Vitesse de sortie:" + +#: src/gtk.c:273 +msgid "Output sample size (bits):" +msgstr "Taille d'échantillon de sortie (en bits):" + +#: src/gtk.c:277 +msgid "Output channels:" +msgstr "Canaux de sortie:" + +#: src/gtk.c:280 +msgid "ISDN device:" +msgstr "Périphérique ISDN:" + +#: src/gtk.c:281 +msgid "ISDN speed (samples):" +msgstr "Vitesse ISDN (échantillons):" + +#: src/gtk.c:282 +msgid "ISDN sample size (bits):" +msgstr "Taille d'échantillon ISDN (en bits):" + +#: src/gtk.c:283 +msgid "ISDN fragment size (bytes):" +msgstr "Taille de fragment ISDN (en octets):" + +#: src/gtk.c:295 +msgid "ANT Info" +msgstr "Info ANT" + +#: src/gtk.c:366 +msgid "About ANT" +msgstr "À propos de ANT" + +#: src/gtk.c:382 +#, c-format +msgid "" +"ANT (ANT is Not a Telephone) Version %s\n" +"Copyright 2002, 2003 Roland Stigge\n" +"\n" +"This is an ISDN telephone application\n" +"written for GNU/Linux and ISDN4Linux for\n" +"communicating via a full duplex soundcard (or\n" +"multiple sound devices if you like) and an\n" +"audio capable ISDN4Linux ISDN device\n" +"\n" +"Contact:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"Mailing list: ant-phone-devel@nongnu.org" +msgstr "" +"ANT (ANT est « Not » un Téléphone) Version %s\n" +"Copyright 2002, 2003 Roland Stigge\n" +"\n" +"C'est un logiciel de téléphone ISDN\n" +"écrit pour GNU/Linux et ISDN4Linux pour\n" +"communiquer à l'aide d'une carte de son fonctionnant en mode duplex complet\n" +"( ou de multiples périphériques de son si vous le désirez) et un\n" +"périphérique audio supportant ISDN4Linux ISDN\n" +"\n" +"Contact:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"Liste de courriel: ant-phone-devel@nongnu.org" + +#: src/gtk.c:420 +msgid "ANT License" +msgstr "Licence ANT" + +#: src/gtk.c:421 +msgid "" +"ANT (ANT is Not a Telephone)\n" +"Copyright (C) 2002, 2003 Roland Stigge\n" +"\n" +"This program is free software; you can redistribute it and/or\n" +"modify it under the terms of the GNU General Public License\n" +"as published by the Free Software Foundation; either version 2\n" +"of the License, or (at your option) any later version.\n" +"\n" +"This program is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n" +"\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program; if not, write to the Free Software\n" +"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." +msgstr "" +"ANT (ANT est « Not » un Téléphone)\n" +"Copyright © 2002, 2003 Roland Stigge\n" +"\n" +"Ce logiciel est libre; vous pouvez le redistribuer selon les termes de la\n" +"licence GNU General Public License. AUCUNE garantie n'est donnée.\n" +"tel que publiée par la Free Software Foundation; tel que la version 2\n" +"de la licence ou (selon votre choix) n'importe quelle version subséquente.\n" +"\n" +"Ce logiciel est distribué dans l'espoir qu'il soit utile,\n" +"mais AUCUNE garantie n'est donnée tant pour des raisons COMMERCIALES que\n" +"pour RÉPONDRE À UN BESOIN PARTICULIER. Consulter la licence\n" +"Licence Publique Générale GNU pour plus de détails.\n" +"\n" +"Vous devriez avoir reçu copie de la Licence Publique Générale de GNU\n" +"avec GNU Anubis; sinon, écrire à la Free Software Foundation, Inc.,\n" +"59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." + +#: src/gtk.c:454 +msgid "/Phon_e" +msgstr "/_Téléphone" + +#: src/gtk.c:455 +msgid "/Phone/_Info Window" +msgstr "/Téléphone/_Fenêtre Info" + +#: src/gtk.c:456 src/gtk.c:504 +msgid "/Phone/_Line Level Check" +msgstr "/Téléphone/_Vérification du niveau de la ligne" + +#: src/gtk.c:458 +msgid "/Phone/" +msgstr "/Téléphone/" + +#: src/gtk.c:459 +msgid "/Phone/_Quit" +msgstr "/Téléphone/_Quitter" + +#: src/gtk.c:461 +msgid "/_View" +msgstr "/_Visionner" + +#: src/gtk.c:462 src/gtk.c:492 +msgid "/View/_Caller ID Monitor" +msgstr "/Visionner/_ID appelant" + +#: src/gtk.c:464 src/gtk.c:495 +msgid "/View/_Line Level Meters" +msgstr "/Visionner/_Niveau de ligne" + +#: src/gtk.c:466 src/gtk.c:498 +msgid "/View/Control _Pad" +msgstr "/Visionner/_Panneau de contrôle" + +#: src/gtk.c:468 +msgid "/_Options" +msgstr "/_Options" + +#: src/gtk.c:469 src/gtk.c:501 +msgid "/Options/_Settings" +msgstr "/Options/_Configurations" + +#: src/gtk.c:471 +msgid "/_Help" +msgstr "/_Aide" + +#: src/gtk.c:472 +msgid "/Help/_About" +msgstr "/AIde/_A propos" + +#: src/gtk.c:473 +msgid "/Help/_License" +msgstr "/Aide/_Licence" + +#: src/gtk.c:551 src/gtksettings.c:431 src/session.c:68 +msgid "Dialing" +msgstr "Composition en cours" + +#: src/gtk.c:783 src/gtk.c:784 +msgid "MUTED" +msgstr "SILENCIEUX" + +#: src/gtksettings.c:230 +msgid "Bad isdn/sound device settings, please try again." +msgstr "Mauvais ISDN/configuration du périphérique, svp essayez à nouveau" + +#: src/gtksettings.c:293 +msgid "ANT Settings" +msgstr "Configurations ANT" + +#: src/gtksettings.c:306 +msgid "Application" +msgstr "Application" + +#: src/gtksettings.c:308 +msgid "Options" +msgstr "Options" + +#: src/gtksettings.c:320 +msgid "Save options on exit" +msgstr "Sauvegarder les options à la fin de l'exécution" + +#: src/gtksettings.c:327 +msgid "Popup main window on incoming call" +msgstr "Popup la fenêtre principale lors de l'arrivée d'un appel" + +#: src/gtksettings.c:333 +msgid "Execute on incoming call:" +msgstr "Éxécuter lors d'un appel entrant:" + +#: src/gtksettings.c:344 +msgid "Recording Format" +msgstr "Formet d'enregistement" + +#: src/gtksettings.c:354 +msgid "Microsoft WAV, uLaw" +msgstr "WAV Microsoft, uLaw" + +#: src/gtksettings.c:364 +msgid "Microsoft WAV, 16-bit signed" +msgstr "WAV Microsoft, 16 bits signés" + +#: src/gtksettings.c:374 +msgid "Apple/SGI AIFF, uLaw" +msgstr "Aple/SGI AIFF, uLaw" + +#: src/gtksettings.c:384 +msgid "Apple/SGI AIFF, 16-bit signed" +msgstr "Apple/SGI AIFF, 16 bits signés" + +#: src/gtksettings.c:397 +msgid "Phone" +msgstr "Téléphone" + +#: src/gtksettings.c:399 +msgid "ISDN" +msgstr "ISDN" + +#: src/gtksettings.c:411 +msgid "Identifying MSN:" +msgstr "MSN identifiant:" + +#: src/gtksettings.c:421 +msgid "Listen to MSNs:" +msgstr "Écoute des MSN:" + +#: src/gtksettings.c:443 +msgid "Dial history size:" +msgstr "Taille du fichier hiostorique des appels:" + +#: src/gtksettings.c:467 +msgid "Maximum CID rows:" +msgstr "Maximum de rangées CID:" + +#: src/gtksettings.c:475 src/gtksettings.c:503 +msgid "[no limit]" +msgstr "[pas de limite]" + +#: src/gtksettings.c:484 +msgid "Read isdnlog data on startup" +msgstr "Lire le journal isdnlog lors du démarrage" + +#: src/gtksettings.c:491 +msgid "Maximum days to read from isdnlog:" +msgstr "Nombre de jours maximum pour lire à partir du journal isdnlog:" + +#: src/gtksettings.c:520 +msgid "Sound Devices" +msgstr "Périphérique de son" + +#: src/gtksettings.c:522 +msgid "OSS" +msgstr "OSS" + +#: src/gtksettings.c:534 +msgid "Input sound device:" +msgstr "Périphérique d'entrée de son:" + +#: src/gtksettings.c:546 +msgid "Output sound device:" +msgstr "Périphérique de sortie de son:" + +#: src/gtksettings.c:559 +msgid "Release unused devices" +msgstr "Relâcher les périphériques non utilisés" + +#: src/gtksettings.c:609 +msgid "Save" +msgstr "Sauvegader" + +#: src/llcheck.c:371 +msgid "Line Level Check" +msgstr "Vérification du niveau des lignes" + +#: src/llcheck.c:383 +msgid "" +"Please check the line input level\n" +"and adjust it using your favorite\n" +"mixer application.\n" +"You can also play a sound\n" +"to test the sound output." +msgstr "" +"SVP vérifier le niveau de la ligne d'entrée\n" +"et ajustez le pour utiliser votre application de mixage favorite.\n" +"Vous pouvcz aussi faire l'écoute d'un fichier de son pour tester\n" +"la sortie de son." + +#: src/llcheck.c:405 +msgid "Play sound" +msgstr "Faire entendre le son" + +#: src/session.c:65 +msgid "Ready" +msgstr "Prêt" + +#: src/session.c:65 +msgid "Dial" +msgstr "Composer" + +#: src/session.c:65 src/session.c:69 src/session.c:70 +msgid "Hang up" +msgstr "Raccrocher" + +#: src/session.c:66 src/session.c:67 +msgid "RING" +msgstr "SONERIE" + +#: src/session.c:66 src/session.c:67 +msgid "Answer" +msgstr "Répondre" + +#: src/session.c:66 src/session.c:67 +msgid "Reject" +msgstr "Rejetr" + +#: src/session.c:68 src/session.c:69 src/session.c:70 src/session.c:71 +msgid "Pick up" +msgstr "Décrocher" + +#: src/session.c:69 +msgid "B-Channel open" +msgstr "Canal-B ouvert" + +#: src/session.c:70 +msgid "Setup" +msgstr "Configuration" + +#: src/session.c:71 +msgid "Playback" +msgstr "Ré-écoute" + +#: src/session.c:71 +msgid "Stop" +msgstr "Stopper" + +#: src/session.c:377 +#, c-format +msgid "Preset %d" +msgstr "Préselection %d" + +#: src/session.c:699 +msgid "(HW ERROR)" +msgstr "(ERREUR matérielle)" + +#: src/session.c:1000 +msgid "Audio OFF" +msgstr "Audio à l'arrêt" + +#: src/session.c:1000 +msgid "Audio ON" +msgstr "Audio en marche" + +#: src/session.c:1097 +msgid "(BUSY)" +msgstr "(OCCUPÉ)" + +#: src/session.c:1103 +msgid "(TIMEOUT)" +msgstr "(MINUTERIE EXPIRÉE)" + +#: src/session.c:1139 +msgid "(RUNG)" +msgstr "(A SONNÉ)" + +#: src/session.c:1381 +msgid "(ABORTED)" +msgstr "(ARRÊT DEMANDÉ)" + +#: src/session.c:1389 +msgid "(REJECTED)" +msgstr "(REJETÉ)" diff --git a/po/it.po b/po/it.po new file mode 100644 index 0000000..14059d6 --- /dev/null +++ b/po/it.po @@ -0,0 +1,661 @@ +# Messaggi italiani riguardanti GNU ant-phone +# Messages français pour GNU concernant ant-phone. +# Copyright © 2004 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Luca Mariot +msgid "" +msgstr "" +"Project-Id-Version: GNU ant-phone 0.1.12\n" +"Report-Msgid-Bugs-To: stigge@antcom.de\n" +"POT-Creation-Date: 2004-04-03 18:51+0200\n" +"PO-Revision-Date: 2007-01-06 08:00-0500\n" +"Last-Translator: Luca Mariot \n" +"Language-Team: Italian\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8-bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: src/ant-phone.c:170 +#, c-format +msgid "" +"Usage: %s [OPTION...]\n" +"\n" +"Options:\n" +" -h, --help Show this help message\n" +" -v, --version Print version information\n" +" -r, --cleanup Remove stale socket file (left by accident by\n" +" previous run)\n" +" -d, --debug[=level] Print additional runtime debugging data to stdout\n" +" level = 1..2\n" +" -i, --soundin=DEVICE OSS compatible device for input (recording),\n" +" default: /dev/dsp\n" +" -o, --soundout=DEVICE OSS compatible device for output (playback),\n" +" default: /dev/dsp\n" +" -m, --msn=MSN identifying MSN (for outgoing calls), 0 for " +"master\n" +" MSN of this termination/port\n" +" default: 0\n" +" -l, --msns=MSNS MSNs to listen on, semicolon-separated list or " +"'*'\n" +" default: *\n" +" -c, --call=NUMBER Call specified number\n" +"\n" +"Note: If arguments of --soundin and --soundout are equal, a full duplex\n" +" sound device is needed.\n" +msgstr "" +"Usage: %s [OPZIONE...]\n" +"\n" +"Options:\n" +" -h, --help mostra questo messaggio di aiuto\n" +" -v, --version mostra informazioni sulla versione\n" +" -r, --cleanup rimuove il vecchio file di socket (lasciato\n" +" accidentalmente da esecuzioni precedenti)\n" +" -d, --debug[=livello] stampa dati di debug aggiuntivi su stdout\n" +" livello = 1..2\n" +" -i, --soundin=PERI PERIeriferica compatibile con OSS per l'entrata " +"(registrazione),\n" +" per default: /dev/dsp\n" +" -o, --soundout=PERI PERIferica compatibile con OSS per l'uscita " +"(ascolto),\n" +" per default: /dev/dsp\n" +" -m, --msn=MSN MSN identificativo (per le chiamate uscenti), 0 " +"per il master\n" +" MSN di terminazione/port\n" +" per default: 0\n" +" -l, --msns=MSNS MSNs d'ascolto, lista separata da « ; » ou '*'\n" +" per default: *\n" +" -c, --call=NUMERO Chiama il numero specifico\n" +"\n" +"Nota: se gli argomenti di --soundin e --soundout sono uguali, è necessaria\n" +" una scheda audio full-duplex.\n" + +#: src/ant-phone.c:221 +#, c-format +msgid "Calling %s... " +msgstr "Chiamata in corso %s... " + +#: src/ant-phone.c:225 +#, c-format +msgid "successful.\n" +msgstr "eseguito.\n" + +#: src/callerid.c:131 +msgid "Delete Entry" +msgstr "Cancellare Voce" + +#: src/callerid.c:143 +msgid "" +"Are you sure you want to\n" +"delete this entry?" +msgstr "" +"Siete sicuri di voler\n" +"cancellare questa voce?" + +#: src/callerid.c:148 +msgid "Delete recording" +msgstr "Cancellazione della registrazione" + +#: src/callerid.c:266 +#, c-format +msgid "Enter the base filename for %s file" +msgstr "Inserire il nome di base del file %s" + +#: src/callerid.c:312 +msgid "Do you really want to delete this recording?" +msgstr "Volete davvero cancellare questa registrazione?" + +#: src/callerid.c:336 src/callerid.c:362 +msgid "/_Playback" +msgstr "/_Playback (riascolta" + +#: src/callerid.c:337 src/callerid.c:366 +msgid "/_Save as..." +msgstr "/_Salva con nome..." + +#: src/callerid.c:338 src/callerid.c:370 +msgid "/Delete _Recording" +msgstr "/Cancellare la _Registrazione" + +#: src/callerid.c:340 src/callerid.c:374 +msgid "/_Delete Row" +msgstr "/_Cancellare riga" + +#: src/callerid.c:423 src/gtksettings.c:455 +msgid "Caller ID" +msgstr "Identificativo del chiamante" + +#: src/callerid.c:426 +msgid "Date/Time" +msgstr "Data/Ora" + +#: src/callerid.c:427 +msgid "Type" +msgstr "Tipo" + +#: src/callerid.c:428 +msgid "From" +msgstr "Da" + +#: src/callerid.c:429 +msgid "To" +msgstr "A" + +#: src/callerid.c:430 +msgid "Duration" +msgstr "Durata" + +#: src/callerid.c:759 +msgid "(UNKNOWN)" +msgstr "(IGNOTO)" + +#: src/callerid.c:828 +#, c-format +msgid "ANT: %d unanswered" +msgstr "ANT: %d chiamata non risposta" + +#: src/controlpad.c:101 +#, c-format +msgid "Preset %c" +msgstr "Preselezione %c" + +#: src/controlpad.c:108 +#, c-format +msgid "Please input new preset data for button %c:" +msgstr "Prego inserire i nuovi dati per il pulsante di preset %c:" + +#: src/controlpad.c:121 +msgid "Name:" +msgstr "Nome:" + +#: src/controlpad.c:124 src/gtk.c:561 +msgid "Number:" +msgstr "Numero:" + +#: src/controlpad.c:144 src/gtk.c:212 src/gtk.c:331 src/gtk.c:408 +#: src/gtksettings.c:571 src/llcheck.c:422 +msgid "OK" +msgstr "OK" + +#: src/controlpad.c:157 src/gtksettings.c:616 src/session.c:68 +msgid "Cancel" +msgstr "Annulla" + +#: src/controlpad.c:315 +msgid "Backspace" +msgstr "Backspace" + +#: src/controlpad.c:315 +msgid "Preset 1" +msgstr "Preselezione 1" + +#: src/controlpad.c:316 +msgid "Clear Number" +msgstr "Cancellare numero" + +#: src/controlpad.c:316 +msgid "Preset 2" +msgstr "Preselezione 2" + +#: src/controlpad.c:317 +msgid "Redial" +msgstr "Ricomponi" + +#: src/controlpad.c:317 +msgid "Preset 3" +msgstr "Preselezione 3" + +#: src/controlpad.c:318 +msgid "Mute Microphone" +msgstr "Setta a muto il microfono" + +#: src/controlpad.c:318 +msgid "Preset 4" +msgstr "Preselezione 4" + +#: src/controlpad.c:351 +msgid "Control" +msgstr "Controllo" + +#: src/controlpad.c:423 +msgid "Recording" +msgstr "Registrazione in corso..." + +#: src/controlpad.c:434 +msgid "Record to file" +msgstr "Registra in un file" + +#: src/controlpad.c:445 +msgid "Record local channel" +msgstr "Registra su canale locale" + +#: src/controlpad.c:456 +msgid "Record remote channel" +msgstr "Registra su canale remoto" + +#: src/gtk.c:230 src/gtksettings.c:229 +msgid "ANT Note" +msgstr "Nota di ANT" + +#: src/gtk.c:231 +msgid "" +"Can't open audio device.\n" +"Please stop other applications using\n" +"the audio device(s) or check your\n" +"device settings and try again." +msgstr "" +"Impossibile aprire la periferica audio.\n" +"Prego chiudere gli altri programmi che usano\n" +"la scheda audio o verificarne\n" +"la configurazione e riprovare." + +#: src/gtk.c:260 +msgid "Sound input device:" +msgstr "Periferica per l'input audio:" + +#: src/gtk.c:261 +msgid "Input speed:" +msgstr "Velocità d'input:" + +#: src/gtk.c:261 src/gtk.c:264 src/gtk.c:265 src/gtk.c:267 src/gtk.c:271 +#: src/gtk.c:274 src/gtk.c:275 src/gtk.c:277 +msgid "[inactive]" +msgstr "[inattivo]" + +#: src/gtk.c:263 +msgid "Input sample size (bits):" +msgstr "Dimensione campione d'input (in bit):" + +#: src/gtk.c:265 src/gtk.c:275 +msgid "Input fragment size (samples):" +msgstr "Dimensione frammento per l'input (campioni):" + +#: src/gtk.c:267 +msgid "Input channels:" +msgstr "Canali d'input:" + +#: src/gtk.c:270 +msgid "Sound output device:" +msgstr "Periferica per l'output audio:" + +#: src/gtk.c:271 +msgid "Output speed:" +msgstr "Velocità d'output:" + +#: src/gtk.c:273 +msgid "Output sample size (bits):" +msgstr "Dimensione campione d'output (in bit):" + +#: src/gtk.c:277 +msgid "Output channels:" +msgstr "Canali d'output:" + +#: src/gtk.c:280 +msgid "ISDN device:" +msgstr "Periferica ISDN:" + +#: src/gtk.c:281 +msgid "ISDN speed (samples):" +msgstr "Velocità ISDN (campioni):" + +#: src/gtk.c:282 +msgid "ISDN sample size (bits):" +msgstr "Dimensioni campione ISDN (in bit)):" + +#: src/gtk.c:283 +msgid "ISDN fragment size (bytes):" +msgstr "Dimensione frammento ISDN (in byte):" + +#: src/gtk.c:295 +msgid "ANT Info" +msgstr "Info ANT" + +#: src/gtk.c:366 +msgid "About ANT" +msgstr "A proposito di ANT" + +#: src/gtk.c:382 +#, c-format +msgid "" +"ANT (ANT is Not a Telephone) Version %s\n" +"Copyright 2002, 2003 Roland Stigge\n" +"\n" +"This is an ISDN telephone application\n" +"written for GNU/Linux and ISDN4Linux for\n" +"communicating via a full duplex soundcard (or\n" +"multiple sound devices if you like) and an\n" +"audio capable ISDN4Linux ISDN device\n" +"\n" +"Contact:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"Mailing list: ant-phone-devel@nongnu.org" +msgstr "" +"ANT (ANT Non è un Telefono) Versione %s\n" +"Copyright 2002, 2003 Roland Stigge\n" +"\n" +"E' un'applicazione di telefonia\n" +"scritta per GNU/Linux e ISDN4Linux per\n" +"comunicare tramite una scheda audio full duplex\n" +"(o più schede audio se preferite) e una\n" +"scheda ISDN supportata da ISDN4Linux\n" +"capace di gestire l'audio.\n" +"\n" +"Contatto:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"Mailing List: ant-phone-devel@nongnu.org" + +#: src/gtk.c:420 +msgid "ANT License" +msgstr "Licenza di ANT" + +#: src/gtk.c:421 +msgid "" +"ANT (ANT is Not a Telephone)\n" +"Copyright (C) 2002, 2003 Roland Stigge\n" +"\n" +"This program is free software; you can redistribute it and/or\n" +"modify it under the terms of the GNU General Public License\n" +"as published by the Free Software Foundation; either version 2\n" +"of the License, or (at your option) any later version.\n" +"\n" +"This program is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n" +"\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program; if not, write to the Free Software\n" +"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." +msgstr "" +"ANT (ANT Non è un Telefono)\n" +"Copyright © 2002, 2003 Roland Stigge\n" +"\n" +"Questo programma è libero; potete ridistribuirlo secondo i termini della\n" +"licenza GNU General Public License, come pubblicata dalla Free Software\n" +"Foundation, sia la versione 2 della licenza, o.\n" +"(se preferite) qualsiasi versione successiva.\n" +"\n" +"Questo programma viene distribuito con la speranza che possa essere\n" +"utile, ma SENZA ALCUNA GARANZIA, sia per ragioni COMMERCIALI che per\n" +"SOPPERIRE AD UN BISOGNO PARTICOLARE. Si veda la GNU General Public License\n" +"per maggiori dettagli.\n" +"\n" +"Dovreste aver ricevuto una copia della GNU General Public License insieme\n" +"a questo programma; in caso contrario, scrivete alla Free Software\n" +"Foundation, Inc. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." + +#: src/gtk.c:454 +msgid "/Phon_e" +msgstr "/_Telefono" + +#: src/gtk.c:455 +msgid "/Phone/_Info Window" +msgstr "/Telefono/_Finestra Informazioni" + +#: src/gtk.c:456 src/gtk.c:504 +msgid "/Phone/_Line Level Check" +msgstr "/Telefono/_Verifica segnale della linea" + +#: src/gtk.c:458 +msgid "/Phone/" +msgstr "/Telefono/" + +#: src/gtk.c:459 +msgid "/Phone/_Quit" +msgstr "/Telefono/_Esci" + +#: src/gtk.c:461 +msgid "/_View" +msgstr "/_Visualizza" + +#: src/gtk.c:462 src/gtk.c:492 +msgid "/View/_Caller ID Monitor" +msgstr "/Visualizza/_Monitor ID chiamante" + +#: src/gtk.c:464 src/gtk.c:495 +msgid "/View/_Line Level Meters" +msgstr "/Visualizza/_Livello della linea" + +#: src/gtk.c:466 src/gtk.c:498 +msgid "/View/Control _Pad" +msgstr "/Visionner/_Pannello di controllo" + +#: src/gtk.c:468 +msgid "/_Options" +msgstr "/_Opzioni" + +#: src/gtk.c:469 src/gtk.c:501 +msgid "/Options/_Settings" +msgstr "/Optioni/_Configurazioni" + +#: src/gtk.c:471 +msgid "/_Help" +msgstr "/_Aiuto" + +#: src/gtk.c:472 +msgid "/Help/_About" +msgstr "/Aiuto/_About" + +#: src/gtk.c:473 +msgid "/Help/_License" +msgstr "/Aiut/_Licenza" + +#: src/gtk.c:551 src/gtksettings.c:431 src/session.c:68 +msgid "Dialing" +msgstr "Chiamata in corso" + +#: src/gtk.c:783 src/gtk.c:784 +msgid "MUTED" +msgstr "MUTO" + +#: src/gtksettings.c:230 +msgid "Bad isdn/sound device settings, please try again." +msgstr "Configurazione periferica isdn/audio non valida, prego riprovare." + +#: src/gtksettings.c:293 +msgid "ANT Settings" +msgstr "Configurazione ANT" + +#: src/gtksettings.c:306 +msgid "Application" +msgstr "Applicazione" + +#: src/gtksettings.c:308 +msgid "Options" +msgstr "Opzioni" + +#: src/gtksettings.c:320 +msgid "Save options on exit" +msgstr "Salva le opzioni all'uscita" + +#: src/gtksettings.c:327 +msgid "Popup main window on incoming call" +msgstr "Popup finestra principale su chiamate in entrata" + +#: src/gtksettings.c:333 +msgid "Execute on incoming call:" +msgstr "Éseguire su chiamate in entrata" + +#: src/gtksettings.c:344 +msgid "Recording Format" +msgstr "Format di registrazione" + +#: src/gtksettings.c:354 +msgid "Microsoft WAV, uLaw" +msgstr "Microsoft WAV, uLaw" + +#: src/gtksettings.c:364 +msgid "Microsoft WAV, 16-bit signed" +msgstr "Microsoft WAV, 16 bit con segno" + +#: src/gtksettings.c:374 +msgid "Apple/SGI AIFF, uLaw" +msgstr "Apple/SGI AIFF, uLaw" + +#: src/gtksettings.c:384 +msgid "Apple/SGI AIFF, 16-bit signed" +msgstr "Apple/SGI AIFF, 16 bits con segno" + +#: src/gtksettings.c:397 +msgid "Phone" +msgstr "Telefono" + +#: src/gtksettings.c:399 +msgid "ISDN" +msgstr "ISDN" + +#: src/gtksettings.c:411 +msgid "Identifying MSN:" +msgstr "MSN identificativo:" + +#: src/gtksettings.c:421 +msgid "Listen to MSNs:" +msgstr "Ascolta i MSN:" + +#: src/gtksettings.c:443 +msgid "Dial history size:" +msgstr "Dimensioni file cronologia:" + +#: src/gtksettings.c:467 +msgid "Maximum CID rows:" +msgstr "Massimo numero di righe CID:" + +#: src/gtksettings.c:475 src/gtksettings.c:503 +msgid "[no limit]" +msgstr "[nessun limite]" + +#: src/gtksettings.c:484 +msgid "Read isdnlog data on startup" +msgstr "Leggere i dati di isdnlog all'avvio" + +#: src/gtksettings.c:491 +msgid "Maximum days to read from isdnlog:" +msgstr "Numero massimo di giorni da leggere su isdnlog:" + +#: src/gtksettings.c:520 +msgid "Sound Devices" +msgstr "Periferica Audio" + +#: src/gtksettings.c:522 +msgid "OSS" +msgstr "OSS" + +#: src/gtksettings.c:534 +msgid "Input sound device:" +msgstr "Periferica d'input audio:" + +#: src/gtksettings.c:546 +msgid "Output sound device:" +msgstr "Periferica d'output audio:" + +#: src/gtksettings.c:559 +msgid "Release unused devices" +msgstr "Liberare periferiche inutilizzate" + +#: src/gtksettings.c:609 +msgid "Save" +msgstr "Salva" + +#: src/llcheck.c:371 +msgid "Line Level Check" +msgstr "Verifica livello di linea" + +#: src/llcheck.c:383 +msgid "" +"Please check the line input level\n" +"and adjust it using your favorite\n" +"mixer application.\n" +"You can also play a sound\n" +"to test the sound output." +msgstr "" +"Prego controlla il livello della linea d'entrata\n" +"e modificatela usando il vostro mixer preferito.\n" +"Potete anche utilizzare un file audio per testare\n" +"l'uscita audio." + +#: src/llcheck.c:405 +msgid "Play sound" +msgstr "Play" + +#: src/session.c:65 +msgid "Ready" +msgstr "Pronto" + +#: src/session.c:65 +msgid "Dial" +msgstr "Componi" + +#: src/session.c:65 src/session.c:69 src/session.c:70 +msgid "Hang up" +msgstr "Aggancia" + +#: src/session.c:66 src/session.c:67 +msgid "RING" +msgstr "SUONERIA" + +#: src/session.c:66 src/session.c:67 +msgid "Answer" +msgstr "Rispondi" + +#: src/session.c:66 src/session.c:67 +msgid "Reject" +msgstr "Rifiuta" + +#: src/session.c:68 src/session.c:69 src/session.c:70 src/session.c:71 +msgid "Pick up" +msgstr "Alza la cornetta" + +#: src/session.c:69 +msgid "B-Channel open" +msgstr "Canale B aperto" + +#: src/session.c:70 +msgid "Setup" +msgstr "Configurazione" + +#: src/session.c:71 +msgid "Playback" +msgstr "Playback" + +#: src/session.c:71 +msgid "Stop" +msgstr "Stop" + +#: src/session.c:377 +#, c-format +msgid "Preset %d" +msgstr "Preselezione %d" + +#: src/session.c:699 +msgid "(HW ERROR)" +msgstr "(ERRORE HARDWARE)" + +#: src/session.c:1000 +msgid "Audio OFF" +msgstr "Audio OFF" + +#: src/session.c:1000 +msgid "Audio ON" +msgstr "Audio ON" + +#: src/session.c:1097 +msgid "(BUSY)" +msgstr "(OCCUPATO)" + +#: src/session.c:1103 +msgid "(TIMEOUT)" +msgstr "(TEMPO SCADUTO)" + +#: src/session.c:1139 +msgid "(RUNG)" +msgstr "(HA SUONATO)" + +#: src/session.c:1381 +msgid "(ABORTED)" +msgstr "(ANNULLATO)" + +#: src/session.c:1389 +msgid "(REJECTED)" +msgstr "(RIFIUTATO)" diff --git a/po/nl.po b/po/nl.po new file mode 100644 index 0000000..eb1b952 --- /dev/null +++ b/po/nl.po @@ -0,0 +1,663 @@ +# Dutch translation of ant-phone. +# Copyright (C) 2003 Free Software Foundation, Inc. +# This file is distributed under the same license as the ant-phone package. +# Elros Cyriatan , 2003. +# +msgid "" +msgstr "" +"Project-Id-Version: ant-phone 0.1.4\n" +"Report-Msgid-Bugs-To: stigge@antcom.de\n" +"POT-Creation-Date: 2004-04-03 18:51+0200\n" +"PO-Revision-Date: 2003-10-19 21:54+0100\n" +"Last-Translator: Elros Cyriatan \n" +"Language-Team: Dutch \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/ant-phone.c:170 +#, c-format +msgid "" +"Usage: %s [OPTION...]\n" +"\n" +"Options:\n" +" -h, --help Show this help message\n" +" -v, --version Print version information\n" +" -r, --cleanup Remove stale socket file (left by accident by\n" +" previous run)\n" +" -d, --debug[=level] Print additional runtime debugging data to stdout\n" +" level = 1..2\n" +" -i, --soundin=DEVICE OSS compatible device for input (recording),\n" +" default: /dev/dsp\n" +" -o, --soundout=DEVICE OSS compatible device for output (playback),\n" +" default: /dev/dsp\n" +" -m, --msn=MSN identifying MSN (for outgoing calls), 0 for " +"master\n" +" MSN of this termination/port\n" +" default: 0\n" +" -l, --msns=MSNS MSNs to listen on, semicolon-separated list or " +"'*'\n" +" default: *\n" +" -c, --call=NUMBER Call specified number\n" +"\n" +"Note: If arguments of --soundin and --soundout are equal, a full duplex\n" +" sound device is needed.\n" +msgstr "" +"Gebruik: %s [OPTIE...]\n" +"\n" +"Opties:\n" +" -h, --help Dit hulpbericht weergeven\n" +" -v, --version Versie informatie weergeven\n" +" -r, --cleanup Per ongeluk (van vorige sessie) overgebleven\n" +" socket-bestand verwijderen\n" +" -d, --debug[=niveau] Extra runtime debug gegevens naar stdout zenden\n" +" niveau = 1..2\n" +" -i, --soundin=APPARAAT OSS-compatibel apparaat voor invoer (opname),\n" +" standaard: /dev/dsp\n" +" -o, --soundout=APPARAAT OSS-compatibel apparaat voor uitvoer (afspelen),\n" +" standaard: /dev/dsp\n" +" -m, --msn=MSN identificerende MSN (voor uitgaande gesprekken), 0 " +"voor hoofd\n" +" MSN van deze afsluiting/poort\n" +" standaard: 0\n" +" -l, --msns=MSNS MSNs om naar te luisteren, punt-komma gescheiden " +"lijst of '*'\n" +" standaard: *\n" +" -c, --call=NUMMER Opgegeven nummer bellen\n" +"\n" +"Let op: als argumenten van --soundin en --soundout gelijk zijn, is een full " +"duplex\n" +" geluidsapparaat nodig.\n" + +#: src/ant-phone.c:221 +#, c-format +msgid "Calling %s... " +msgstr "Bezig met bellen %s..." + +#: src/ant-phone.c:225 +#, c-format +msgid "successful.\n" +msgstr "succesvol.\n" + +#: src/callerid.c:131 +msgid "Delete Entry" +msgstr "Ingang verwijderen" + +#: src/callerid.c:143 +msgid "" +"Are you sure you want to\n" +"delete this entry?" +msgstr "" +"Weet u zeker dat u deze\n" +"ingang wilt verwijderen?" + +#: src/callerid.c:148 +msgid "Delete recording" +msgstr "Opname verwijderen" + +#: src/callerid.c:266 +#, c-format +msgid "Enter the base filename for %s file" +msgstr "Geef de basis-bestandsnaam voor %s bestand" + +#: src/callerid.c:312 +msgid "Do you really want to delete this recording?" +msgstr "Wilt u deze opname echt verwijderen?" + +#: src/callerid.c:336 src/callerid.c:362 +msgid "/_Playback" +msgstr "/_Afspelen" + +#: src/callerid.c:337 src/callerid.c:366 +msgid "/_Save as..." +msgstr "/_Opslaan als..." + +#: src/callerid.c:338 src/callerid.c:370 +msgid "/Delete _Recording" +msgstr "/_Opname verwijderen" + +#: src/callerid.c:340 src/callerid.c:374 +msgid "/_Delete Row" +msgstr "/_Rij verwijderen" + +#: src/callerid.c:423 src/gtksettings.c:455 +msgid "Caller ID" +msgstr "Beller ID" + +#: src/callerid.c:426 +msgid "Date/Time" +msgstr "Datum/Tijd" + +#: src/callerid.c:427 +msgid "Type" +msgstr "Soort" + +#: src/callerid.c:428 +msgid "From" +msgstr "Van" + +#: src/callerid.c:429 +msgid "To" +msgstr "Naar" + +#: src/callerid.c:430 +msgid "Duration" +msgstr "Lengte" + +#: src/callerid.c:759 +msgid "(UNKNOWN)" +msgstr "(ONBEKEND)" + +#: src/callerid.c:828 +#, c-format +msgid "ANT: %d unanswered" +msgstr "ANT: %d niet-beantwoord" + +#: src/controlpad.c:101 +#, c-format +msgid "Preset %c" +msgstr "Voorkeuze %c" + +#: src/controlpad.c:108 +#, c-format +msgid "Please input new preset data for button %c:" +msgstr "Geef a.u.b. nieuwe voorkeuze gegevens voor knop %c:" + +#: src/controlpad.c:121 +msgid "Name:" +msgstr "Naam:" + +#: src/controlpad.c:124 src/gtk.c:561 +msgid "Number:" +msgstr "Nummer:" + +#: src/controlpad.c:144 src/gtk.c:212 src/gtk.c:331 src/gtk.c:408 +#: src/gtksettings.c:571 src/llcheck.c:422 +msgid "OK" +msgstr "OK" + +#: src/controlpad.c:157 src/gtksettings.c:616 src/session.c:68 +msgid "Cancel" +msgstr "Annuleren" + +#: src/controlpad.c:315 +msgid "Backspace" +msgstr "Backspace" + +#: src/controlpad.c:315 +msgid "Preset 1" +msgstr "Voorkeuze 1" + +#: src/controlpad.c:316 +msgid "Clear Number" +msgstr "Nummer wissen" + +#: src/controlpad.c:316 +msgid "Preset 2" +msgstr "Voorkeuze 2" + +#: src/controlpad.c:317 +msgid "Redial" +msgstr "Opnieuw bellen" + +#: src/controlpad.c:317 +msgid "Preset 3" +msgstr "Voorkeuze 3" + +#: src/controlpad.c:318 +msgid "Mute Microphone" +msgstr "Microfoon uit" + +#: src/controlpad.c:318 +msgid "Preset 4" +msgstr "Voorkeuze 4" + +#: src/controlpad.c:351 +msgid "Control" +msgstr "Bediening" + +#: src/controlpad.c:423 +msgid "Recording" +msgstr "Opname" + +#: src/controlpad.c:434 +msgid "Record to file" +msgstr "Opnemen naar bestand" + +#: src/controlpad.c:445 +msgid "Record local channel" +msgstr "Lokaal kanaal opnemen" + +#: src/controlpad.c:456 +msgid "Record remote channel" +msgstr "Kanaal op afstand opnemen" + +#: src/gtk.c:230 src/gtksettings.c:229 +msgid "ANT Note" +msgstr "ANT Bericht" + +#: src/gtk.c:231 +msgid "" +"Can't open audio device.\n" +"Please stop other applications using\n" +"the audio device(s) or check your\n" +"device settings and try again." +msgstr "" +"Kan geluidsapparaat niet openen.\n" +"Stop a.u.b. andere toepassingen die\n" +"het/de geluidsapparaat(en) gebruik(en)\n" +"of controleer uw apparaatinstellingen,\n" +"en probeer het opnieuw." + +#: src/gtk.c:260 +msgid "Sound input device:" +msgstr "Geluidsapparaat invoer:" + +#: src/gtk.c:261 +msgid "Input speed:" +msgstr "Invoersnelheid:" + +#: src/gtk.c:261 src/gtk.c:264 src/gtk.c:265 src/gtk.c:267 src/gtk.c:271 +#: src/gtk.c:274 src/gtk.c:275 src/gtk.c:277 +msgid "[inactive]" +msgstr "[inactief]" + +#: src/gtk.c:263 +msgid "Input sample size (bits):" +msgstr "Invoer monstergrootte (bits):" + +#: src/gtk.c:265 src/gtk.c:275 +msgid "Input fragment size (samples):" +msgstr "Invoer fragmentgrootte (monsters):" + +#: src/gtk.c:267 +msgid "Input channels:" +msgstr "Invoerkanalen:" + +#: src/gtk.c:270 +msgid "Sound output device:" +msgstr "Geluidsapparaat uitvoer:" + +#: src/gtk.c:271 +msgid "Output speed:" +msgstr "Uitvoersnelheid:" + +#: src/gtk.c:273 +msgid "Output sample size (bits):" +msgstr "Uitvoer monstergrootte (bits):" + +#: src/gtk.c:277 +msgid "Output channels:" +msgstr "Uitvoerkanalen:" + +#: src/gtk.c:280 +msgid "ISDN device:" +msgstr "ISDN-apparaat:" + +#: src/gtk.c:281 +msgid "ISDN speed (samples):" +msgstr "ISDN snelheid (monsters):" + +#: src/gtk.c:282 +msgid "ISDN sample size (bits):" +msgstr "ISDN monstergrootte (bits):" + +#: src/gtk.c:283 +msgid "ISDN fragment size (bytes):" +msgstr "ISDN fragmentgrootte (bytes):" + +#: src/gtk.c:295 +msgid "ANT Info" +msgstr "ANT Info" + +#: src/gtk.c:366 +msgid "About ANT" +msgstr "Over ANT" + +#: src/gtk.c:382 +#, c-format +msgid "" +"ANT (ANT is Not a Telephone) Version %s\n" +"Copyright 2002, 2003 Roland Stigge\n" +"\n" +"This is an ISDN telephone application\n" +"written for GNU/Linux and ISDN4Linux for\n" +"communicating via a full duplex soundcard (or\n" +"multiple sound devices if you like) and an\n" +"audio capable ISDN4Linux ISDN device\n" +"\n" +"Contact:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"Mailing list: ant-phone-devel@nongnu.org" +msgstr "" +"ANT (ANT is Niet een Telefoon) Versie %s\n" +"Copyright 2002, 2003 Roland Stigge\n" +"\n" +"Dit is een ISDN telefoon toepassing\n" +"geschreven voor GNU/Linux en ISDN4Linux om\n" +"te communiceren via een full duplex geluidskaart\n" +"(of meerdere geluidsapparaten als u dat wilt) en\n" +"een ISDN4Linux ISDN-apparaat dat geluid\n" +"ondersteunt.\n" +"\n" +"Contact:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"E-mail lijst: ant-phone-devel@nongnu.org" + +#: src/gtk.c:420 +msgid "ANT License" +msgstr "ANT Licentie" + +#: src/gtk.c:421 +msgid "" +"ANT (ANT is Not a Telephone)\n" +"Copyright (C) 2002, 2003 Roland Stigge\n" +"\n" +"This program is free software; you can redistribute it and/or\n" +"modify it under the terms of the GNU General Public License\n" +"as published by the Free Software Foundation; either version 2\n" +"of the License, or (at your option) any later version.\n" +"\n" +"This program is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n" +"\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program; if not, write to the Free Software\n" +"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." +msgstr "" +"ANT (ANT is Niet een Telefoon)\n" +"Copyright (C) 2002, 2003 Roland Stigge\n" +"\n" +"This program is free software; you can redistribute it and/or\n" +"modify it under the terms of the GNU General Public License\n" +"as published by the Free Software Foundation; either version 2\n" +"of the License, or (at your option) any later version.\n" +"\n" +"This program is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n" +"\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program; if not, write to the Free Software\n" +"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." + +#: src/gtk.c:454 +msgid "/Phon_e" +msgstr "/_Telefoon" + +#: src/gtk.c:455 +msgid "/Phone/_Info Window" +msgstr "/Telefoon/_Info" + +#: src/gtk.c:456 src/gtk.c:504 +msgid "/Phone/_Line Level Check" +msgstr "/Telefoon/Lijnniveau _controle" + +#: src/gtk.c:458 +msgid "/Phone/" +msgstr "/Telefoon/" + +#: src/gtk.c:459 +msgid "/Phone/_Quit" +msgstr "/Telefoon/_Afsluiten" + +#: src/gtk.c:461 +msgid "/_View" +msgstr "/B_eeld" + +#: src/gtk.c:462 src/gtk.c:492 +msgid "/View/_Caller ID Monitor" +msgstr "/Beeld/_Beller ID lijst" + +#: src/gtk.c:464 src/gtk.c:495 +msgid "/View/_Line Level Meters" +msgstr "/Beeld/_Lijnniveau meters" + +#: src/gtk.c:466 src/gtk.c:498 +msgid "/View/Control _Pad" +msgstr "/Beeld/Bedienings_paneel" + +#: src/gtk.c:468 +msgid "/_Options" +msgstr "/_Opties" + +#: src/gtk.c:469 src/gtk.c:501 +msgid "/Options/_Settings" +msgstr "/Opties/_Instellingen" + +#: src/gtk.c:471 +msgid "/_Help" +msgstr "/_Hulp" + +#: src/gtk.c:472 +msgid "/Help/_About" +msgstr "/Hulp/_Info" + +#: src/gtk.c:473 +msgid "/Help/_License" +msgstr "/Help/_Licentie" + +#: src/gtk.c:551 src/gtksettings.c:431 src/session.c:68 +msgid "Dialing" +msgstr "Bezig met bellen" + +#: src/gtk.c:783 src/gtk.c:784 +msgid "MUTED" +msgstr "GELUID UIT" + +#: src/gtksettings.c:230 +msgid "Bad isdn/sound device settings, please try again." +msgstr "" +"Slechte ISDN/geluid apparaat instellingen, probeer alstublieft opnieuw." + +#: src/gtksettings.c:293 +msgid "ANT Settings" +msgstr "ANT Instellingen" + +#: src/gtksettings.c:306 +msgid "Application" +msgstr "Toepassing" + +#: src/gtksettings.c:308 +msgid "Options" +msgstr "Opties" + +#: src/gtksettings.c:320 +msgid "Save options on exit" +msgstr "Opties opslaan bij afsluiten" + +#: src/gtksettings.c:327 +msgid "Popup main window on incoming call" +msgstr "Venster openen bij inkomend gesprek" + +#: src/gtksettings.c:333 +msgid "Execute on incoming call:" +msgstr "Uitvoeren bij inkomend gesprek:" + +#: src/gtksettings.c:344 +msgid "Recording Format" +msgstr "Opname formaat" + +#: src/gtksettings.c:354 +msgid "Microsoft WAV, uLaw" +msgstr "Microsoft WAV, uLaw" + +#: src/gtksettings.c:364 +msgid "Microsoft WAV, 16-bit signed" +msgstr "Microsoft WAV, 16-bit met teken" + +#: src/gtksettings.c:374 +msgid "Apple/SGI AIFF, uLaw" +msgstr "Apple/SGI AIFF, uLaw" + +#: src/gtksettings.c:384 +msgid "Apple/SGI AIFF, 16-bit signed" +msgstr "Apple/SGI AIFF, 16-bit met teken" + +#: src/gtksettings.c:397 +msgid "Phone" +msgstr "Telefoon" + +#: src/gtksettings.c:399 +msgid "ISDN" +msgstr "ISDN" + +#: src/gtksettings.c:411 +msgid "Identifying MSN:" +msgstr "Identificerende MSN:" + +#: src/gtksettings.c:421 +msgid "Listen to MSNs:" +msgstr "Luisteren-naar MSNs:" + +#: src/gtksettings.c:443 +msgid "Dial history size:" +msgstr "Belgeschiedenis grootte:" + +#: src/gtksettings.c:467 +msgid "Maximum CID rows:" +msgstr "Maximaal aantal CID rijen:" + +#: src/gtksettings.c:475 src/gtksettings.c:503 +msgid "[no limit]" +msgstr "[geen grens]" + +#: src/gtksettings.c:484 +msgid "Read isdnlog data on startup" +msgstr "Gegevens isdnlog lezen bij opstarten" + +#: src/gtksettings.c:491 +msgid "Maximum days to read from isdnlog:" +msgstr "Maximaal aantal dagen om te lezen van isdnlog:" + +#: src/gtksettings.c:520 +msgid "Sound Devices" +msgstr "Geluidsapparaten" + +#: src/gtksettings.c:522 +msgid "OSS" +msgstr "OSS" + +#: src/gtksettings.c:534 +msgid "Input sound device:" +msgstr "Geluidsapparaat invoer:" + +#: src/gtksettings.c:546 +msgid "Output sound device:" +msgstr "Geluidsapparaat uitvoer:" + +#: src/gtksettings.c:559 +msgid "Release unused devices" +msgstr "Ongebruikte apparaten vrijgeven" + +#: src/gtksettings.c:609 +msgid "Save" +msgstr "Opslaan" + +#: src/llcheck.c:371 +msgid "Line Level Check" +msgstr "Lijnniveau controle" + +#: src/llcheck.c:383 +msgid "" +"Please check the line input level\n" +"and adjust it using your favorite\n" +"mixer application.\n" +"You can also play a sound\n" +"to test the sound output." +msgstr "" +"Controleer alstublieft het lijn invoer\n" +"niveau en pas het aan met de\n" +"volumeregeling toepassing.\n" +"U kunt ook een geluid afspelen om\n" +"geluidsuitvoer te testen." + +#: src/llcheck.c:405 +msgid "Play sound" +msgstr "Geluid afspelen" + +#: src/session.c:65 +msgid "Ready" +msgstr "Gereed" + +#: src/session.c:65 +msgid "Dial" +msgstr "Bellen" + +#: src/session.c:65 src/session.c:69 src/session.c:70 +msgid "Hang up" +msgstr "Ophangen" + +#: src/session.c:66 src/session.c:67 +msgid "RING" +msgstr "TELEFOON GAAT OVER" + +#: src/session.c:66 src/session.c:67 +msgid "Answer" +msgstr "Beantwoorden" + +#: src/session.c:66 src/session.c:67 +msgid "Reject" +msgstr "Verwerpen" + +#: src/session.c:68 src/session.c:69 src/session.c:70 src/session.c:71 +msgid "Pick up" +msgstr "Opnemen" + +#: src/session.c:69 +msgid "B-Channel open" +msgstr "B-kanaal open" + +#: src/session.c:70 +msgid "Setup" +msgstr "Configuratie" + +#: src/session.c:71 +msgid "Playback" +msgstr "Afspelen" + +#: src/session.c:71 +msgid "Stop" +msgstr "Stoppen" + +#: src/session.c:377 +#, c-format +msgid "Preset %d" +msgstr "Voorkeuze %d" + +#: src/session.c:699 +msgid "(HW ERROR)" +msgstr "(HW FOUT)" + +#: src/session.c:1000 +msgid "Audio OFF" +msgstr "Geluid UIT" + +#: src/session.c:1000 +msgid "Audio ON" +msgstr "Geluid AAN" + +#: src/session.c:1097 +msgid "(BUSY)" +msgstr "(BEZIG)" + +#: src/session.c:1103 +msgid "(TIMEOUT)" +msgstr "(TIME-OUT)" + +#: src/session.c:1139 +msgid "(RUNG)" +msgstr "(TELEFOON GING OVER)" + +#: src/session.c:1381 +msgid "(ABORTED)" +msgstr "(AFGEBROKEN)" + +#: src/session.c:1389 +msgid "(REJECTED)" +msgstr "(VERWORPEN)" diff --git a/po/ro.po b/po/ro.po new file mode 100644 index 0000000..21ff25d --- /dev/null +++ b/po/ro.po @@ -0,0 +1,661 @@ +# Mesajele în limba românã pentru pachetul ant-phone. +# Copyright (C) 2003 Free Software Foundation, Inc. +# Acest fi?ier este distribuit sub aceea?i licen?? ca pachetul ant-phone. +# Eugen Hoanca , 2003. +msgid "" +msgstr "" +"Project-Id-Version: ant-phone 0.1.4\n" +"Report-Msgid-Bugs-To: stigge@antcom.de\n" +"POT-Creation-Date: 2004-04-03 18:51+0200\n" +"PO-Revision-Date: 2003-08-18 08:26+0300\n" +"Last-Translator: Eugen Hoanca \n" +"Language-Team: Romanian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-2\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/ant-phone.c:170 +#, c-format +msgid "" +"Usage: %s [OPTION...]\n" +"\n" +"Options:\n" +" -h, --help Show this help message\n" +" -v, --version Print version information\n" +" -r, --cleanup Remove stale socket file (left by accident by\n" +" previous run)\n" +" -d, --debug[=level] Print additional runtime debugging data to stdout\n" +" level = 1..2\n" +" -i, --soundin=DEVICE OSS compatible device for input (recording),\n" +" default: /dev/dsp\n" +" -o, --soundout=DEVICE OSS compatible device for output (playback),\n" +" default: /dev/dsp\n" +" -m, --msn=MSN identifying MSN (for outgoing calls), 0 for " +"master\n" +" MSN of this termination/port\n" +" default: 0\n" +" -l, --msns=MSNS MSNs to listen on, semicolon-separated list or " +"'*'\n" +" default: *\n" +" -c, --call=NUMBER Call specified number\n" +"\n" +"Note: If arguments of --soundin and --soundout are equal, a full duplex\n" +" sound device is needed.\n" +msgstr "" +"Folosire: %s [OPÞIUNE...]\n" +"\n" +"Opþiuni:\n" +" -h, --help Afiºeazã acest mesaj de ajutor\n" +" -v, --version Afiºeazã informaþii despre versiune\n" +" -r, --cleanup ªterge fiºierul de socket blocat (lãsat accidental " +"de\n" +" o rulare precedentã)\n" +" -d, --debug[=nivel] Afiºeazã date suplimentare de debug la stdout\n" +" nivel = 1..2\n" +" -i, --soundin=DISPOZITIV dispozitiv compatibil OSS pentru intrare " +"(înregistrare),\n" +" implicit: /dev/dsp\n" +" -o, --soundout=DEVICE dispozitiv compatibil OSS pentru ieºire " +"(playback),\n" +" implicit: /dev/dsp\n" +" -m, --msn=MSN identificare MSN (pentru apeluri efectuate), 0 " +"pentru master\n" +" MSN al acestei terminaþi/port\n" +" implicit: 0\n" +" -l, --msns=MSNS MSNuri pe care sã se asculte, listã separatã prin " +"punct ºi virgulã sau '*'\n" +" implicit: *\n" +" -c, --call=NUMÃR Apeleazã numãrul specificat\n" +"\n" +"Notã: Dacã parametrii --soundin ºi --soundout sunt egali, va fi necesar un\n" +" dispozitiv de sunet full-duplex.\n" + +#: src/ant-phone.c:221 +#, c-format +msgid "Calling %s... " +msgstr "Apelare %s... " + +#: src/ant-phone.c:225 +#, c-format +msgid "successful.\n" +msgstr "succes.\n" + +#: src/callerid.c:131 +msgid "Delete Entry" +msgstr "ªterge Intrarea" + +#: src/callerid.c:143 +msgid "" +"Are you sure you want to\n" +"delete this entry?" +msgstr "" +"Sunteþi sigur cã vreþi sã ºtergeþi\n" +"aceastã intrare?" + +#: src/callerid.c:148 +msgid "Delete recording" +msgstr "ªterge înregistrare" + +#: src/callerid.c:266 +#, c-format +msgid "Enter the base filename for %s file" +msgstr "Introduceþi numele de fiºier de bazã pentru fiºierul %s" + +#: src/callerid.c:312 +msgid "Do you really want to delete this recording?" +msgstr "Chiar vreþi sã ºtergeþi aceastã înregistrare?" + +#: src/callerid.c:336 src/callerid.c:362 +msgid "/_Playback" +msgstr "/_Playback" + +#: src/callerid.c:337 src/callerid.c:366 +msgid "/_Save as..." +msgstr "/_Salvare ca..." + +#: src/callerid.c:338 src/callerid.c:370 +msgid "/Delete _Recording" +msgstr "/ªterge În_registrare" + +#: src/callerid.c:340 src/callerid.c:374 +msgid "/_Delete Row" +msgstr "/ªterge Rân_d" + +#: src/callerid.c:423 src/gtksettings.c:455 +msgid "Caller ID" +msgstr "ID Apelant(Caller ID)" + +#: src/callerid.c:426 +msgid "Date/Time" +msgstr "Datã/Orã" + +#: src/callerid.c:427 +msgid "Type" +msgstr "Tip" + +#: src/callerid.c:428 +msgid "From" +msgstr "De la" + +#: src/callerid.c:429 +msgid "To" +msgstr "Cãtre" + +#: src/callerid.c:430 +msgid "Duration" +msgstr "durata" + +#: src/callerid.c:759 +msgid "(UNKNOWN)" +msgstr "(NECUNOSCUT)" + +#: src/callerid.c:828 +#, c-format +msgid "ANT: %d unanswered" +msgstr "ANT: %d fãrã rãspuns" + +#: src/controlpad.c:101 +#, c-format +msgid "Preset %c" +msgstr "Preset %c" + +#: src/controlpad.c:108 +#, c-format +msgid "Please input new preset data for button %c:" +msgstr "Vã rugãm introduceþi date preset noi pentru butonul %c:" + +#: src/controlpad.c:121 +msgid "Name:" +msgstr "Nume:" + +#: src/controlpad.c:124 src/gtk.c:561 +msgid "Number:" +msgstr "Numãr:" + +#: src/controlpad.c:144 src/gtk.c:212 src/gtk.c:331 src/gtk.c:408 +#: src/gtksettings.c:571 src/llcheck.c:422 +msgid "OK" +msgstr "OK" + +#: src/controlpad.c:157 src/gtksettings.c:616 src/session.c:68 +msgid "Cancel" +msgstr "Renunþare" + +#: src/controlpad.c:315 +msgid "Backspace" +msgstr "Backspace" + +#: src/controlpad.c:315 +msgid "Preset 1" +msgstr "Preset 1" + +#: src/controlpad.c:316 +msgid "Clear Number" +msgstr "ªterge Numãr" + +#: src/controlpad.c:316 +msgid "Preset 2" +msgstr "Preset 2" + +#: src/controlpad.c:317 +msgid "Redial" +msgstr "Formeazã din nou" + +#: src/controlpad.c:317 +msgid "Preset 3" +msgstr "Preset 3" + +#: src/controlpad.c:318 +msgid "Mute Microphone" +msgstr "Inhibã Microfon" + +#: src/controlpad.c:318 +msgid "Preset 4" +msgstr "Preset 4" + +#: src/controlpad.c:351 +msgid "Control" +msgstr "Control" + +#: src/controlpad.c:423 +msgid "Recording" +msgstr "Înregistrare" + +#: src/controlpad.c:434 +msgid "Record to file" +msgstr "Înregistreazã în fiºier" + +#: src/controlpad.c:445 +msgid "Record local channel" +msgstr "Înregistreazã canal local" + +#: src/controlpad.c:456 +msgid "Record remote channel" +msgstr "Înregistreazã canalul remote" + +#: src/gtk.c:230 src/gtksettings.c:229 +msgid "ANT Note" +msgstr "ANT Notã" + +#: src/gtk.c:231 +msgid "" +"Can't open audio device.\n" +"Please stop other applications using\n" +"the audio device(s) or check your\n" +"device settings and try again." +msgstr "" +"Nu se poate accesa dispozitivul audio.\n" +"Vã rugãm opriþi alte aplicaþii care folosesc\n" +"dispozitivul(ele) audio sau verifcaþi\n" +"setãrile dispozitivului ºi încercaþi din nou." + +#: src/gtk.c:260 +msgid "Sound input device:" +msgstr "Dispozitiv intrare de sunet:" + +#: src/gtk.c:261 +msgid "Input speed:" +msgstr "Vitezã de intrare(input):" + +#: src/gtk.c:261 src/gtk.c:264 src/gtk.c:265 src/gtk.c:267 src/gtk.c:271 +#: src/gtk.c:274 src/gtk.c:275 src/gtk.c:277 +msgid "[inactive]" +msgstr "[inactiv]" + +#: src/gtk.c:263 +msgid "Input sample size (bits):" +msgstr "Mãrime de intrare (biþi):" + +#: src/gtk.c:265 src/gtk.c:275 +msgid "Input fragment size (samples):" +msgstr "Mãrime intrare fragment (exemple):" + +#: src/gtk.c:267 +msgid "Input channels:" +msgstr "Canale de intrare:" + +#: src/gtk.c:270 +msgid "Sound output device:" +msgstr "Dispozitiv ieºire de sunet:" + +#: src/gtk.c:271 +msgid "Output speed:" +msgstr "Vitezã de ieºire:" + +#: src/gtk.c:273 +msgid "Output sample size (bits):" +msgstr "Mãrime de ieºire (biþi):" + +#: src/gtk.c:277 +msgid "Output channels:" +msgstr "Canale de ieºire:" + +#: src/gtk.c:280 +msgid "ISDN device:" +msgstr "Dispozitiv ISDN:" + +#: src/gtk.c:281 +msgid "ISDN speed (samples):" +msgstr "Vitezã ISDN (exemple):" + +#: src/gtk.c:282 +msgid "ISDN sample size (bits):" +msgstr "Mãrime exemplu ISDN (biþi)" + +#: src/gtk.c:283 +msgid "ISDN fragment size (bytes):" +msgstr "Mãrime fragment ISDN (octeþi):" + +#: src/gtk.c:295 +msgid "ANT Info" +msgstr "ANT Info" + +#: src/gtk.c:366 +msgid "About ANT" +msgstr "Despre ANT" + +#: src/gtk.c:382 +#, c-format +msgid "" +"ANT (ANT is Not a Telephone) Version %s\n" +"Copyright 2002, 2003 Roland Stigge\n" +"\n" +"This is an ISDN telephone application\n" +"written for GNU/Linux and ISDN4Linux for\n" +"communicating via a full duplex soundcard (or\n" +"multiple sound devices if you like) and an\n" +"audio capable ISDN4Linux ISDN device\n" +"\n" +"Contact:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"Mailing list: ant-phone-devel@nongnu.org" +msgstr "" +"ANT (ANT Nu este un Telefon) Versiunea %s\n" +"Copyright 2002, 2003 Roland Stigge\n" +"\n" +"Aceasta este o aplicaþie de telefon ISDN\n" +"scrisã pentru GNU/Linux ºi ISDN4Linux pentru\n" +"comunicarea printr-o placã de sunet full-duplex (sau\n" +"mai multe plãci de sunet dacã vreþi) ºi un\n" +"dispozitivISDN capabil de sunet ISDN4Linux\n" +"\n" +"Contact:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"Listã de discuþii: ant-phone-devel@nongnu.org" + +#: src/gtk.c:420 +msgid "ANT License" +msgstr "ANT Licenþã" + +#: src/gtk.c:421 +msgid "" +"ANT (ANT is Not a Telephone)\n" +"Copyright (C) 2002, 2003 Roland Stigge\n" +"\n" +"This program is free software; you can redistribute it and/or\n" +"modify it under the terms of the GNU General Public License\n" +"as published by the Free Software Foundation; either version 2\n" +"of the License, or (at your option) any later version.\n" +"\n" +"This program is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n" +"\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program; if not, write to the Free Software\n" +"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." +msgstr "" +"ANT (ANT Nu este un Telefon)\n" +"Copyright (C) 2002, 2003 Roland Stigge\n" +"\n" +"Acest program este software liber; puteþi sã-l redistribuiþi ºi/" +"saumodificaþi sub termenii Licenþei Publice Generale GNU\n" +"publicatã de Free Software Foundation; fie versiunea 2\n" +"a Licenþei, fie (opþiunea dumneavoastrã) orice versiune ulterioarã\n" +"\n" +"Acest program este distribuit în speranþa cã va fi folositor,\n" +"dar FÃRà NICI O GARANÞIE; chiar fãrã garanþia sugeratã de\n" +"VANDABILITATE sau MODIFICARE ÎN SCOP PERSONAL. Citiþi\n" +"Licenþa Publicã Generalã GNU pentru mai multe detalii.\n" +"\n" +"Ar fi trebui sã fi primit ºi o copie a Licenþei Publice Generale GNU \n" +"împreunã cu acest progra,; dacã nu, scrieþi la Free Software\n" +"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." + +#: src/gtk.c:454 +msgid "/Phon_e" +msgstr "/T_elefon" + +#: src/gtk.c:455 +msgid "/Phone/_Info Window" +msgstr "/Telefon/Fereastrã _Info" + +#: src/gtk.c:456 src/gtk.c:504 +msgid "/Phone/_Line Level Check" +msgstr "/Phone/Verificare nivel _linie" + +#: src/gtk.c:458 +msgid "/Phone/" +msgstr "/Telefon/" + +#: src/gtk.c:459 +msgid "/Phone/_Quit" +msgstr "/Telefon/Ieºire(_Quit)" + +#: src/gtk.c:461 +msgid "/_View" +msgstr "/_Vizualizare" + +#: src/gtk.c:462 src/gtk.c:492 +msgid "/View/_Caller ID Monitor" +msgstr "/Vizualizare/Monitor_Caller ID" + +#: src/gtk.c:464 src/gtk.c:495 +msgid "/View/_Line Level Meters" +msgstr "/Vizualizare/Monitoare Nivel _Linie" + +#: src/gtk.c:466 src/gtk.c:498 +msgid "/View/Control _Pad" +msgstr "/Vizualizare/_Pad Control" + +#: src/gtk.c:468 +msgid "/_Options" +msgstr "/_Opþiuni" + +#: src/gtk.c:469 src/gtk.c:501 +msgid "/Options/_Settings" +msgstr "/Opþiuni/_Setãri" + +#: src/gtk.c:471 +msgid "/_Help" +msgstr "/Ajutor(_Help)" + +#: src/gtk.c:472 +msgid "/Help/_About" +msgstr "/Ajutor/Despre(_About)" + +#: src/gtk.c:473 +msgid "/Help/_License" +msgstr "/Ajutor/_Licenþã" + +#: src/gtk.c:551 src/gtksettings.c:431 src/session.c:68 +msgid "Dialing" +msgstr "Apelare" + +#: src/gtk.c:783 src/gtk.c:784 +msgid "MUTED" +msgstr "TRECUT PE MUTE" + +#: src/gtksettings.c:230 +msgid "Bad isdn/sound device settings, please try again." +msgstr "Setãri greºite isdn/sunet, încercaþi din nou." + +#: src/gtksettings.c:293 +msgid "ANT Settings" +msgstr "ANT Setãri" + +#: src/gtksettings.c:306 +msgid "Application" +msgstr "Aplicaþie" + +#: src/gtksettings.c:308 +msgid "Options" +msgstr "Optiuni" + +#: src/gtksettings.c:320 +msgid "Save options on exit" +msgstr "Salveazã opþiunile la ieºire" + +#: src/gtksettings.c:327 +msgid "Popup main window on incoming call" +msgstr "Scoate în evidenþã (popup) fereastra principalã când sunã telefonul" + +#: src/gtksettings.c:333 +msgid "Execute on incoming call:" +msgstr "Executã atunci când sunã telefonul:" + +#: src/gtksettings.c:344 +msgid "Recording Format" +msgstr "Format Înregistrare" + +#: src/gtksettings.c:354 +msgid "Microsoft WAV, uLaw" +msgstr "Microsoft WAV, uLaw" + +#: src/gtksettings.c:364 +msgid "Microsoft WAV, 16-bit signed" +msgstr "Microsoft WAV, 16-biþi cu semn (signed)" + +#: src/gtksettings.c:374 +msgid "Apple/SGI AIFF, uLaw" +msgstr "Apple/SGI AIFF, uLaw" + +#: src/gtksettings.c:384 +msgid "Apple/SGI AIFF, 16-bit signed" +msgstr "Apple/SGI AIFF, 16-biþi cu smen (signed)" + +#: src/gtksettings.c:397 +msgid "Phone" +msgstr "Telefon" + +#: src/gtksettings.c:399 +msgid "ISDN" +msgstr "ISDN" + +#: src/gtksettings.c:411 +msgid "Identifying MSN:" +msgstr "Indetificare MSN:" + +#: src/gtksettings.c:421 +msgid "Listen to MSNs:" +msgstr "Ascultare MSNuri:" + +#: src/gtksettings.c:443 +msgid "Dial history size:" +msgstr "Mãrime istoric apelãri:" + +#: src/gtksettings.c:467 +msgid "Maximum CID rows:" +msgstr "Maxim de rânduri CID:" + +#: src/gtksettings.c:475 src/gtksettings.c:503 +msgid "[no limit]" +msgstr "[nelimitat]" + +#: src/gtksettings.c:484 +msgid "Read isdnlog data on startup" +msgstr "Citeºte date isdnlog la început" + +#: src/gtksettings.c:491 +msgid "Maximum days to read from isdnlog:" +msgstr "Maximum de zile de citit din isdnlog:" + +#: src/gtksettings.c:520 +msgid "Sound Devices" +msgstr "Dispozitive de Sunet:" + +#: src/gtksettings.c:522 +msgid "OSS" +msgstr "OSS" + +#: src/gtksettings.c:534 +msgid "Input sound device:" +msgstr "Dispozitiv de intrare de sunet:" + +#: src/gtksettings.c:546 +msgid "Output sound device:" +msgstr "Dispozitiv de ieºire de sunet:" + +#: src/gtksettings.c:559 +msgid "Release unused devices" +msgstr "Elibereazã(release) dispozitivele nefolosite" + +#: src/gtksettings.c:609 +msgid "Save" +msgstr "Salveazã" + +#: src/llcheck.c:371 +msgid "Line Level Check" +msgstr "Verificare Nivel Linie" + +#: src/llcheck.c:383 +msgid "" +"Please check the line input level\n" +"and adjust it using your favorite\n" +"mixer application.\n" +"You can also play a sound\n" +"to test the sound output." +msgstr "" +"Verificaþi nivelul de intrare al liniei\n" +"ºi ajustaþi-l folosind aplicaþia\n" +"de mixer preferatã.\n" +"Puteþi de asemenea sã ascultaþi un sunet\n" +"pentru a testa ieºirea de sunet." + +#: src/llcheck.c:405 +msgid "Play sound" +msgstr "Ascultare sunet" + +#: src/session.c:65 +msgid "Ready" +msgstr "Pregãtit(ready)" + +#: src/session.c:65 +msgid "Dial" +msgstr "Apelare" + +#: src/session.c:65 src/session.c:69 src/session.c:70 +msgid "Hang up" +msgstr "Întrerupere(hang-up)" + +#: src/session.c:66 src/session.c:67 +msgid "RING" +msgstr "SUNÃ(RING)" + +#: src/session.c:66 src/session.c:67 +msgid "Answer" +msgstr "Rãspuns" + +#: src/session.c:66 src/session.c:67 +msgid "Reject" +msgstr "Refuzare" + +#: src/session.c:68 src/session.c:69 src/session.c:70 src/session.c:71 +msgid "Pick up" +msgstr "Ridicare receptor" + +#: src/session.c:69 +msgid "B-Channel open" +msgstr "Canalul B deschis" + +#: src/session.c:70 +msgid "Setup" +msgstr "Setup" + +#: src/session.c:71 +msgid "Playback" +msgstr "Playback" + +#: src/session.c:71 +msgid "Stop" +msgstr "Stop" + +#: src/session.c:377 +#, c-format +msgid "Preset %d" +msgstr "Preset %d" + +#: src/session.c:699 +msgid "(HW ERROR)" +msgstr "(EROARE HW)" + +#: src/session.c:1000 +msgid "Audio OFF" +msgstr "Audio DEZACTIVAT" + +#: src/session.c:1000 +msgid "Audio ON" +msgstr "Audio ACTIVAT" + +#: src/session.c:1097 +msgid "(BUSY)" +msgstr "(OCUPAT)" + +#: src/session.c:1103 +msgid "(TIMEOUT)" +msgstr "(TIMP EXPIRAT)" + +#: src/session.c:1139 +msgid "(RUNG)" +msgstr "(SUNAT)" + +#: src/session.c:1381 +msgid "(ABORTED)" +msgstr "(RENUNÞAT)" + +#: src/session.c:1389 +msgid "(REJECTED)" +msgstr "(REJFUZAT)" diff --git a/po/sv.po b/po/sv.po new file mode 100644 index 0000000..643caeb --- /dev/null +++ b/po/sv.po @@ -0,0 +1,668 @@ +# Swedish translation of ant-phone. +# Copyright (C) 2005 Roland Stigge +# This file is distributed under the same license as the ant-phone package. +# Daniel Nylander , 2005. +# +msgid "" +msgstr "" +"Project-Id-Version: ant-phone 0.1.4\n" +"Report-Msgid-Bugs-To: stigge@antcom.de\n" +"POT-Creation-Date: 2004-04-03 18:51+0200\n" +"PO-Revision-Date: 2006-01-06 21:08+0100\n" +"Last-Translator: Daniel Nylander \n" +"Language-Team: Swedish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/ant-phone.c:170 +#, c-format +msgid "" +"Usage: %s [OPTION...]\n" +"\n" +"Options:\n" +" -h, --help Show this help message\n" +" -v, --version Print version information\n" +" -r, --cleanup Remove stale socket file (left by accident by\n" +" previous run)\n" +" -d, --debug[=level] Print additional runtime debugging data to stdout\n" +" level = 1..2\n" +" -i, --soundin=DEVICE OSS compatible device for input (recording),\n" +" default: /dev/dsp\n" +" -o, --soundout=DEVICE OSS compatible device for output (playback),\n" +" default: /dev/dsp\n" +" -m, --msn=MSN identifying MSN (for outgoing calls), 0 for " +"master\n" +" MSN of this termination/port\n" +" default: 0\n" +" -l, --msns=MSNS MSNs to listen on, semicolon-separated list or " +"'*'\n" +" default: *\n" +" -c, --call=NUMBER Call specified number\n" +"\n" +"Note: If arguments of --soundin and --soundout are equal, a full duplex\n" +" sound device is needed.\n" +msgstr "" +"Användning: %s [FLAGGA...]\n" +"\n" +"Flaggor:\n" +" -h, --help Visar detta hjälpmeddelande\n" +" -v, --version Skriv ut versionsinformation\n" +" -r, --cleanup Ta bort hängda socketfiler (kvarlämnade av " +"misstag\n" +" frÃ¥n tidigare körning)\n" +" -d, --debug[=nivÃ¥] Skriv ut ytterligare körtidsdata för felsökning " +"till\n" +" standard ut nivÃ¥ = 1..2\n" +" -i, --soundin=ENHET OSS-kompatibel enhet för indata (inspelning),\n" +" förval: /dev/dsp\n" +" -o, --soundout=ENHET OSS-kompatibel enhet för utdata (uppspelning),\n" +" förval: /dev/dsp\n" +" -m, --msn=MSN identifierar MSN (för utgÃ¥ende samtal), 0 för " +"master\n" +" MSN för denna ändpunkt/port\n" +" förval: 0\n" +" -l, --msns=MSNS MSN:er att lyssna pÃ¥, lista separerad med " +"semikolon\n" +" eller \"*\"\n" +" förval: *\n" +" -c, --call=NUMMER Ring angivet nummer\n" +"\n" +"Notera: Om argumenten för --soundin och --soundout är samma behövs ett\n" +" ljudkort med stöd för full duplex.\n" +"Skicka synpunkter pÃ¥ översättningen till tp-sv@listor.tp-sv.se\n" + +#: src/ant-phone.c:221 +#, c-format +msgid "Calling %s... " +msgstr "Ringer %s..." + +#: src/ant-phone.c:225 +#, c-format +msgid "successful.\n" +msgstr "lyckades.\n" + +#: src/callerid.c:131 +msgid "Delete Entry" +msgstr "Ta bort post" + +#: src/callerid.c:143 +msgid "" +"Are you sure you want to\n" +"delete this entry?" +msgstr "" +"Är du säker att du vill\n" +"ta bort denna post?" + +#: src/callerid.c:148 +msgid "Delete recording" +msgstr "Ta bort inspelning" + +#: src/callerid.c:266 +#, c-format +msgid "Enter the base filename for %s file" +msgstr "Ange basfilnamnet för filen %s" + +#: src/callerid.c:312 +msgid "Do you really want to delete this recording?" +msgstr "Vill du verkligen ta bort denna inspelning?" + +#: src/callerid.c:336 src/callerid.c:362 +msgid "/_Playback" +msgstr "/U_ppspelning" + +#: src/callerid.c:337 src/callerid.c:366 +msgid "/_Save as..." +msgstr "/_Spara som..." + +#: src/callerid.c:338 src/callerid.c:370 +msgid "/Delete _Recording" +msgstr "/Ta bo_rt inspelning" + +#: src/callerid.c:340 src/callerid.c:374 +msgid "/_Delete Row" +msgstr "/Ta bort ra_d" + +#: src/callerid.c:423 src/gtksettings.c:455 +msgid "Caller ID" +msgstr "Nummerpresentation" + +#: src/callerid.c:426 +msgid "Date/Time" +msgstr "Datum/Tid" + +#: src/callerid.c:427 +msgid "Type" +msgstr "Typ" + +#: src/callerid.c:428 +msgid "From" +msgstr "FrÃ¥n" + +#: src/callerid.c:429 +msgid "To" +msgstr "Till" + +#: src/callerid.c:430 +msgid "Duration" +msgstr "Längd" + +#: src/callerid.c:759 +msgid "(UNKNOWN)" +msgstr "(OKÄND)" + +#: src/callerid.c:828 +#, c-format +msgid "ANT: %d unanswered" +msgstr "ANT: %d obesvarade" + +#: src/controlpad.c:101 +#, c-format +msgid "Preset %c" +msgstr "Förval %c" + +#: src/controlpad.c:108 +#, c-format +msgid "Please input new preset data for button %c:" +msgstr "Mata in ny förvalsdata för knapp %c:" + +#: src/controlpad.c:121 +msgid "Name:" +msgstr "Namn:" + +#: src/controlpad.c:124 src/gtk.c:561 +msgid "Number:" +msgstr "Nummer:" + +#: src/controlpad.c:144 src/gtk.c:212 src/gtk.c:331 src/gtk.c:408 +#: src/gtksettings.c:571 src/llcheck.c:422 +msgid "OK" +msgstr "OK" + +#: src/controlpad.c:157 src/gtksettings.c:616 src/session.c:68 +msgid "Cancel" +msgstr "Avbryt" + +#: src/controlpad.c:315 +msgid "Backspace" +msgstr "Baksteg" + +#: src/controlpad.c:315 +msgid "Preset 1" +msgstr "Förval 1" + +#: src/controlpad.c:316 +msgid "Clear Number" +msgstr "Rensa nummer" + +#: src/controlpad.c:316 +msgid "Preset 2" +msgstr "Förval 2" + +#: src/controlpad.c:317 +msgid "Redial" +msgstr "Ã…teruppring" + +#: src/controlpad.c:317 +msgid "Preset 3" +msgstr "Förval 3" + +#: src/controlpad.c:318 +msgid "Mute Microphone" +msgstr "Tyst mikrofon" + +#: src/controlpad.c:318 +msgid "Preset 4" +msgstr "Förval 4" + +#: src/controlpad.c:351 +msgid "Control" +msgstr "Kontrollera" + +#: src/controlpad.c:423 +msgid "Recording" +msgstr "Spelar in" + +#: src/controlpad.c:434 +msgid "Record to file" +msgstr "Spela in till fil" + +#: src/controlpad.c:445 +msgid "Record local channel" +msgstr "Spela in lokal kanal" + +#: src/controlpad.c:456 +msgid "Record remote channel" +msgstr "Spela in fjärrkanal" + +#: src/gtk.c:230 src/gtksettings.c:229 +msgid "ANT Note" +msgstr "ANT-notering" + +#: src/gtk.c:231 +msgid "" +"Can't open audio device.\n" +"Please stop other applications using\n" +"the audio device(s) or check your\n" +"device settings and try again." +msgstr "" +"Kan inte öppna ljudenhet.\n" +"Vänligen stoppa andra applikationer\n" +"som använder ljudenheten eller\n" +"kontrollera dina enhetsinställningar\n" +"och försök igen." + +#: src/gtk.c:260 +msgid "Sound input device:" +msgstr "Enhet för ljudindata:" + +#: src/gtk.c:261 +msgid "Input speed:" +msgstr "Hastighet för indata:" + +#: src/gtk.c:261 src/gtk.c:264 src/gtk.c:265 src/gtk.c:267 src/gtk.c:271 +#: src/gtk.c:274 src/gtk.c:275 src/gtk.c:277 +msgid "[inactive]" +msgstr "[inaktiv]" + +#: src/gtk.c:263 +msgid "Input sample size (bits):" +msgstr "Samplingsstorlek för indata (bitar):" + +#: src/gtk.c:265 src/gtk.c:275 +msgid "Input fragment size (samples):" +msgstr "Fragmentstorlek för indata (sampling):" + +#: src/gtk.c:267 +msgid "Input channels:" +msgstr "Indatakanaler:" + +#: src/gtk.c:270 +msgid "Sound output device:" +msgstr "Enhet för ljudutdata:" + +#: src/gtk.c:271 +msgid "Output speed:" +msgstr "Utdatahastighet:" + +#: src/gtk.c:273 +msgid "Output sample size (bits):" +msgstr "Samplingsstorlek för utdata (bitar):" + +#: src/gtk.c:277 +msgid "Output channels:" +msgstr "Kanaler för utdata:" + +#: src/gtk.c:280 +msgid "ISDN device:" +msgstr "ISDN-enhet:" + +#: src/gtk.c:281 +msgid "ISDN speed (samples):" +msgstr "ISDN-hastighet (sampling):" + +#: src/gtk.c:282 +msgid "ISDN sample size (bits):" +msgstr "Samplingsstorlek för ISDN (bitar):" + +#: src/gtk.c:283 +msgid "ISDN fragment size (bytes):" +msgstr "Fragmentstorlek för ISDN (bytes):" + +#: src/gtk.c:295 +msgid "ANT Info" +msgstr "ANT-info" + +#: src/gtk.c:366 +msgid "About ANT" +msgstr "Om ANT" + +#: src/gtk.c:382 +#, c-format +msgid "" +"ANT (ANT is Not a Telephone) Version %s\n" +"Copyright 2002, 2003 Roland Stigge\n" +"\n" +"This is an ISDN telephone application\n" +"written for GNU/Linux and ISDN4Linux for\n" +"communicating via a full duplex soundcard (or\n" +"multiple sound devices if you like) and an\n" +"audio capable ISDN4Linux ISDN device\n" +"\n" +"Contact:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"Mailing list: ant-phone-devel@nongnu.org" +msgstr "" +"ANT (ANT is Not a Telephone) Version %s\n" +"Copyright 2002, 2003 Roland Stigge\n" +"\n" +"Detta är en applikation för ISDN-telefoner\n" +"skriven för GNU/Linux och ISDN4Linux för\n" +"att kommunicera via ett ljudkort med full\n" +"duplex (eller multipla ljudenheter om du vill)\n" +"och en ISDN4Linux ISDN-enhet kapabel\n" +"för ljud.\n" +"Kontakt:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"E-postlista: ant-phone-devel@nongnu.org" + +#: src/gtk.c:420 +msgid "ANT License" +msgstr "ANT-licens" + +#: src/gtk.c:421 +msgid "" +"ANT (ANT is Not a Telephone)\n" +"Copyright (C) 2002, 2003 Roland Stigge\n" +"\n" +"This program is free software; you can redistribute it and/or\n" +"modify it under the terms of the GNU General Public License\n" +"as published by the Free Software Foundation; either version 2\n" +"of the License, or (at your option) any later version.\n" +"\n" +"This program is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n" +"\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program; if not, write to the Free Software\n" +"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." +msgstr "" +"ANT (ANT is Not a Telephone)\n" +"Copyright (C) 2002, 2003 Roland Stigge\n" +"\n" +"Följande text är en informell översättning som enbart tillhandahÃ¥lls i\n" +"informativt syfte. För alla juridiska tolkningar gäller den engelska\n" +"originaltexten.\n" +"\n" +"Detta program är fri programvara. Du kan distribuera det och/eller\n" +"modifiera det under villkoren i GNU General Public License, publicerad\n" +"av Free Software Foundation, antingen version 2 eller (om du sÃ¥ vill)\n" +"nÃ¥gon senare version.\n" +"\n" +"Detta program distribueras i hopp om att det ska vara användbart,\n" +"men UTAN NÃ…GON SOM HELST GARANTI, även utan underförstÃ¥dd garanti\n" +"om SÄLJBARHET eller LÄMPLIGHET FÖR NÃ…GOT SPECIELLT ÄNDAMÃ…L. Se GNU\n" +"General Public License för ytterligare information.\n" +"\n" +"Du bör ha fÃ¥tt en kopia av GNU General Public License tillsammans\n" +"med detta program. Om inte, skriv till Free Software Foundation,\n" +"Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." + +#: src/gtk.c:454 +msgid "/Phon_e" +msgstr "/T_elefon" + +#: src/gtk.c:455 +msgid "/Phone/_Info Window" +msgstr "/Telefon/_Infofönster" + +#: src/gtk.c:456 src/gtk.c:504 +msgid "/Phone/_Line Level Check" +msgstr "/Telefon/_LinjenivÃ¥kontroll" + +#: src/gtk.c:458 +msgid "/Phone/" +msgstr "/Telefon/" + +#: src/gtk.c:459 +msgid "/Phone/_Quit" +msgstr "/Telefon/A_vsluta" + +#: src/gtk.c:461 +msgid "/_View" +msgstr "/_Visa" + +#: src/gtk.c:462 src/gtk.c:492 +msgid "/View/_Caller ID Monitor" +msgstr "/Visa/_Nummerpresentationsvisare" + +#: src/gtk.c:464 src/gtk.c:495 +msgid "/View/_Line Level Meters" +msgstr "/Visa/_LinjenivÃ¥mätare" + +#: src/gtk.c:466 src/gtk.c:498 +msgid "/View/Control _Pad" +msgstr "/Visa/Kontroll_panel" + +#: src/gtk.c:468 +msgid "/_Options" +msgstr "/Inställningar" + +#: src/gtk.c:469 src/gtk.c:501 +msgid "/Options/_Settings" +msgstr "/Inställningar/_Konfiguration" + +#: src/gtk.c:471 +msgid "/_Help" +msgstr "/_Hjälp" + +#: src/gtk.c:472 +msgid "/Help/_About" +msgstr "/Hjälp/Om" + +#: src/gtk.c:473 +msgid "/Help/_License" +msgstr "/Hjälp/_Licens" + +#: src/gtk.c:551 src/gtksettings.c:431 src/session.c:68 +msgid "Dialing" +msgstr "Ringer" + +#: src/gtk.c:783 src/gtk.c:784 +msgid "MUTED" +msgstr "TYST" + +#: src/gtksettings.c:230 +msgid "Bad isdn/sound device settings, please try again." +msgstr "Felaktiga inställningar för ISDN/ljudenhet, försök igen." + +#: src/gtksettings.c:293 +msgid "ANT Settings" +msgstr "ANT-inställningar" + +#: src/gtksettings.c:306 +msgid "Application" +msgstr "Applikation" + +#: src/gtksettings.c:308 +msgid "Options" +msgstr "Inställningar" + +#: src/gtksettings.c:320 +msgid "Save options on exit" +msgstr "Spara inställningar vid avslut" + +#: src/gtksettings.c:327 +msgid "Popup main window on incoming call" +msgstr "Visa huvudfönster vid inkommande samtal" + +#: src/gtksettings.c:333 +msgid "Execute on incoming call:" +msgstr "Kör vid inkommande samtal:" + +#: src/gtksettings.c:344 +msgid "Recording Format" +msgstr "Inspelningsformat" + +#: src/gtksettings.c:354 +msgid "Microsoft WAV, uLaw" +msgstr "Microsoft WAV, uLaw" + +#: src/gtksettings.c:364 +msgid "Microsoft WAV, 16-bit signed" +msgstr "Microsoft WAV, 16-bit signed" + +#: src/gtksettings.c:374 +msgid "Apple/SGI AIFF, uLaw" +msgstr "Apple/SGI AIFF, uLaw" + +#: src/gtksettings.c:384 +msgid "Apple/SGI AIFF, 16-bit signed" +msgstr "Apple/SGI AIFF, 16-bit signed" + +#: src/gtksettings.c:397 +msgid "Phone" +msgstr "Telefon" + +#: src/gtksettings.c:399 +msgid "ISDN" +msgstr "ISDN" + +#: src/gtksettings.c:411 +msgid "Identifying MSN:" +msgstr "Identifierar MSN:" + +#: src/gtksettings.c:421 +msgid "Listen to MSNs:" +msgstr "Lyssnar till MSN:" + +#: src/gtksettings.c:443 +msgid "Dial history size:" +msgstr "Storlek för samtalshistorik:" + +#: src/gtksettings.c:467 +msgid "Maximum CID rows:" +msgstr "Max rader för nummerpresentation:" + +#: src/gtksettings.c:475 src/gtksettings.c:503 +msgid "[no limit]" +msgstr "[ingen gräns]" + +#: src/gtksettings.c:484 +msgid "Read isdnlog data on startup" +msgstr "Läs isdnlog-data vid uppstart" + +#: src/gtksettings.c:491 +msgid "Maximum days to read from isdnlog:" +msgstr "Max antal dagar att läsa frÃ¥n isdnlog:" + +#: src/gtksettings.c:520 +msgid "Sound Devices" +msgstr "Ljudenheter" + +#: src/gtksettings.c:522 +msgid "OSS" +msgstr "OSS" + +#: src/gtksettings.c:534 +msgid "Input sound device:" +msgstr "Enhet för ljudindata:" + +#: src/gtksettings.c:546 +msgid "Output sound device:" +msgstr "Enhet för ljudutdata:" + +#: src/gtksettings.c:559 +msgid "Release unused devices" +msgstr "Släpp oanvända enheter" + +#: src/gtksettings.c:609 +msgid "Save" +msgstr "Spara" + +#: src/llcheck.c:371 +msgid "Line Level Check" +msgstr "LinjenivÃ¥kontroll" + +#: src/llcheck.c:383 +msgid "" +"Please check the line input level\n" +"and adjust it using your favorite\n" +"mixer application.\n" +"You can also play a sound\n" +"to test the sound output." +msgstr "" +"Vänligen kontrollera indatanivÃ¥n pÃ¥\n" +"linjen och justera den med din favorit\n" +"mixerapplikation.\n" +"Du kan ocksÃ¥ spela ett ljud för att\n" +"testa ljudutdatat." + +#: src/llcheck.c:405 +msgid "Play sound" +msgstr "Spela ljud" + +#: src/session.c:65 +msgid "Ready" +msgstr "Klar" + +#: src/session.c:65 +msgid "Dial" +msgstr "Ring" + +#: src/session.c:65 src/session.c:69 src/session.c:70 +msgid "Hang up" +msgstr "Lägg pÃ¥" + +#: src/session.c:66 src/session.c:67 +msgid "RING" +msgstr "RING" + +#: src/session.c:66 src/session.c:67 +msgid "Answer" +msgstr "Svara" + +#: src/session.c:66 src/session.c:67 +msgid "Reject" +msgstr "Neka" + +#: src/session.c:68 src/session.c:69 src/session.c:70 src/session.c:71 +msgid "Pick up" +msgstr "Lyft" + +#: src/session.c:69 +msgid "B-Channel open" +msgstr "B-kanal öppen" + +#: src/session.c:70 +msgid "Setup" +msgstr "Ställ in" + +#: src/session.c:71 +msgid "Playback" +msgstr "Uppspelning" + +#: src/session.c:71 +msgid "Stop" +msgstr "Stopp" + +#: src/session.c:377 +#, c-format +msgid "Preset %d" +msgstr "Förval %d" + +#: src/session.c:699 +msgid "(HW ERROR)" +msgstr "(HV FEL)" + +#: src/session.c:1000 +msgid "Audio OFF" +msgstr "Ljud AV" + +#: src/session.c:1000 +msgid "Audio ON" +msgstr "Ljud PÃ…" + +#: src/session.c:1097 +msgid "(BUSY)" +msgstr "(UPPTAGET)" + +#: src/session.c:1103 +msgid "(TIMEOUT)" +msgstr "(TIMEOUT)" + +#: src/session.c:1139 +msgid "(RUNG)" +msgstr "(RINGDE)" + +#: src/session.c:1381 +msgid "(ABORTED)" +msgstr "(AVBRUTEN)" + +#: src/session.c:1389 +msgid "(REJECTED)" +msgstr "(NEKAD)" diff --git a/po/tr.po b/po/tr.po new file mode 100644 index 0000000..56e6d66 --- /dev/null +++ b/po/tr.po @@ -0,0 +1,662 @@ +# translation of ant-phone-0.1.4.tr.po to Turkish +# Copyright (C) 2004 Free Software Foundation, Inc. +# This file is distributed under the same license as the ant-phone package. +# AyÅŸegül KurÅŸun , 2004. +# +msgid "" +msgstr "" +"Project-Id-Version: ant-phone 0.1.4\n" +"Report-Msgid-Bugs-To: stigge@antcom.de\n" +"POT-Creation-Date: 2004-04-03 18:51+0200\n" +"PO-Revision-Date: 2004-12-05 20:44+0200\n" +"Last-Translator: AyÅŸegül KurÅŸun \n" +"Language-Team: Turkish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.3.1\n" + +#: src/ant-phone.c:170 +#, c-format +msgid "" +"Usage: %s [OPTION...]\n" +"\n" +"Options:\n" +" -h, --help Show this help message\n" +" -v, --version Print version information\n" +" -r, --cleanup Remove stale socket file (left by accident by\n" +" previous run)\n" +" -d, --debug[=level] Print additional runtime debugging data to stdout\n" +" level = 1..2\n" +" -i, --soundin=DEVICE OSS compatible device for input (recording),\n" +" default: /dev/dsp\n" +" -o, --soundout=DEVICE OSS compatible device for output (playback),\n" +" default: /dev/dsp\n" +" -m, --msn=MSN identifying MSN (for outgoing calls), 0 for " +"master\n" +" MSN of this termination/port\n" +" default: 0\n" +" -l, --msns=MSNS MSNs to listen on, semicolon-separated list or " +"'*'\n" +" default: *\n" +" -c, --call=NUMBER Call specified number\n" +"\n" +"Note: If arguments of --soundin and --soundout are equal, a full duplex\n" +" sound device is needed.\n" +msgstr "" +"Kullanım: %s [SEÇENEK...]\n" +"\n" +"Seçenekler:\n" +" -h, --help bu yardım iletisini gösterir\n" +" -v, --version Sürüm bilgilerini yazdırır\n" +" -r, --cleanup Eski soket dosyalarını siler (önceki iÅŸlemden\n" +" kazara kalmış)\n" +" -d, --debug[=seviye] Standart çıktıya ek hata ayıklama bilgisi " +"yazdırır\n" +" seviye = 1..2\n" +" -i, --soundin=AYGIT OSS uyumlu girdi aygıtları (kayıt için)\n" +" öntanımlı: /dev/dsp\n" +" -o, --soundout=AYGIT OSS uyumlu çıktı aygıtları (çalmak için)\n" +" öntanımlı: /dev/dsp\n" +" -m, --msn=MSN MSN tanımlama (dışarı aramalar), bu uç/port'un\n" +" ana MSN'i için 0\n" +" öntanımlı: 0\n" +" -l, --msns=MSNS Dinlenecek MSN'ler, noktalı virgül ile ayrılmış\n" +" liste ya da '*'\n" +" -c, --call=NUMARA Belirtilen numarayı arar\n" +"\n" +"Not: EÄŸer --soundin ve --soundout seçeneklerinin deÄŸerleri aynı ise,\n" +"tam duplex bir ses aygıtı gereklidir.\n" + +#: src/ant-phone.c:221 +#, c-format +msgid "Calling %s... " +msgstr "%s aranıyor..." + +#: src/ant-phone.c:225 +#, c-format +msgid "successful.\n" +msgstr "baÅŸarılı.\n" + +#: src/callerid.c:131 +msgid "Delete Entry" +msgstr "Girdiyi Sil" + +#: src/callerid.c:143 +msgid "" +"Are you sure you want to\n" +"delete this entry?" +msgstr "" +"Bu girdiyi silmek\n" +"istediÄŸinize emin misiniz?" + +#: src/callerid.c:148 +msgid "Delete recording" +msgstr "Kaydı sil" + +#: src/callerid.c:266 +#, c-format +msgid "Enter the base filename for %s file" +msgstr "%s dosyasının temel dosya ismini girin" + +#: src/callerid.c:312 +msgid "Do you really want to delete this recording?" +msgstr "Gerçekten bu kaydı silmek istiyor musunuz?" + +#: src/callerid.c:336 src/callerid.c:362 +msgid "/_Playback" +msgstr "/_Çal" + +#: src/callerid.c:337 src/callerid.c:366 +msgid "/_Save as..." +msgstr "/_Farklı kaydet..." + +#: src/callerid.c:338 src/callerid.c:370 +msgid "/Delete _Recording" +msgstr "/Kaydı _Sil" + +#: src/callerid.c:340 src/callerid.c:374 +msgid "/_Delete Row" +msgstr "/S_atırı Sil" + +#: src/callerid.c:423 src/gtksettings.c:455 +msgid "Caller ID" +msgstr "Arayan Bilgisi" + +#: src/callerid.c:426 +msgid "Date/Time" +msgstr "Tarih/Zaman" + +#: src/callerid.c:427 +msgid "Type" +msgstr "Tür" + +#: src/callerid.c:428 +msgid "From" +msgstr "Kimden" + +#: src/callerid.c:429 +msgid "To" +msgstr "Kime" + +#: src/callerid.c:430 +msgid "Duration" +msgstr "Süre" + +#: src/callerid.c:759 +msgid "(UNKNOWN)" +msgstr "(BÄ°LÄ°NMEYEN)" + +#: src/callerid.c:828 +#, c-format +msgid "ANT: %d unanswered" +msgstr "ANT:%d cevaplanmamış" + +#: src/controlpad.c:101 +#, c-format +msgid "Preset %c" +msgstr "Önkurum %c" + +#: src/controlpad.c:108 +#, c-format +msgid "Please input new preset data for button %c:" +msgstr "Lütfen %c tuÅŸu için yeni önkurum bilgisini girin" + +#: src/controlpad.c:121 +msgid "Name:" +msgstr "Ä°sim:" + +#: src/controlpad.c:124 src/gtk.c:561 +msgid "Number:" +msgstr "Numara:" + +#: src/controlpad.c:144 src/gtk.c:212 src/gtk.c:331 src/gtk.c:408 +#: src/gtksettings.c:571 src/llcheck.c:422 +msgid "OK" +msgstr "Tamam" + +#: src/controlpad.c:157 src/gtksettings.c:616 src/session.c:68 +msgid "Cancel" +msgstr "Ä°ptal" + +#: src/controlpad.c:315 +msgid "Backspace" +msgstr "Geri al" + +#: src/controlpad.c:315 +msgid "Preset 1" +msgstr "Önkurum 1" + +#: src/controlpad.c:316 +msgid "Clear Number" +msgstr "Numarayı Sil" + +#: src/controlpad.c:316 +msgid "Preset 2" +msgstr "Önkurum 2" + +#: src/controlpad.c:317 +msgid "Redial" +msgstr "Yeniden Ara" + +#: src/controlpad.c:317 +msgid "Preset 3" +msgstr "Önkurum 3" + +#: src/controlpad.c:318 +msgid "Mute Microphone" +msgstr "Mikrofonu SessizleÅŸtir" + +#: src/controlpad.c:318 +msgid "Preset 4" +msgstr "Önkurum 4" + +#: src/controlpad.c:351 +msgid "Control" +msgstr "Kontrol" + +#: src/controlpad.c:423 +msgid "Recording" +msgstr "Kayıt" + +#: src/controlpad.c:434 +msgid "Record to file" +msgstr "Dosyaya kayıt" + +#: src/controlpad.c:445 +msgid "Record local channel" +msgstr "Yerel kanalları kaydet" + +#: src/controlpad.c:456 +msgid "Record remote channel" +msgstr "Uzak kanalları kaydet" + +#: src/gtk.c:230 src/gtksettings.c:229 +msgid "ANT Note" +msgstr "ANT Notu" + +#: src/gtk.c:231 +msgid "" +"Can't open audio device.\n" +"Please stop other applications using\n" +"the audio device(s) or check your\n" +"device settings and try again." +msgstr "" +"Ses aygıtı açılamıyor. \n" +"Lütfen ses aygıt(lar)ını kullanan\n" +"diÄŸer uygulamaları durdurun, ya da\n" +"aygıt ayarlarını kontrol edin\n" +"ve tekrar deneyin." + +#: src/gtk.c:260 +msgid "Sound input device:" +msgstr "Ses girdi aygıtı:" + +#: src/gtk.c:261 +msgid "Input speed:" +msgstr "Girdi hızı:" + +#: src/gtk.c:261 src/gtk.c:264 src/gtk.c:265 src/gtk.c:267 src/gtk.c:271 +#: src/gtk.c:274 src/gtk.c:275 src/gtk.c:277 +msgid "[inactive]" +msgstr "[etkin deÄŸil]" + +#: src/gtk.c:263 +msgid "Input sample size (bits):" +msgstr "Girdi örnek boyu (bit):" + +#: src/gtk.c:265 src/gtk.c:275 +msgid "Input fragment size (samples):" +msgstr "Girdi parçacık boyu (örnek):" + +#: src/gtk.c:267 +msgid "Input channels:" +msgstr "Girdi kanalları:" + +#: src/gtk.c:270 +msgid "Sound output device:" +msgstr "Ses çıktı aygıtı:" + +#: src/gtk.c:271 +msgid "Output speed:" +msgstr "Çıktı hızı:" + +#: src/gtk.c:273 +msgid "Output sample size (bits):" +msgstr "Çıktı örnek boyu (bit):" + +#: src/gtk.c:277 +msgid "Output channels:" +msgstr "Çıktı kanalları:" + +#: src/gtk.c:280 +msgid "ISDN device:" +msgstr "ISDN aygıtı:" + +#: src/gtk.c:281 +msgid "ISDN speed (samples):" +msgstr "ISDN hızı (örnekler):" + +#: src/gtk.c:282 +msgid "ISDN sample size (bits):" +msgstr "ISDN örnek boyu (bit):" + +#: src/gtk.c:283 +msgid "ISDN fragment size (bytes):" +msgstr "ISDN parçacık boyu (bayt):" + +#: src/gtk.c:295 +msgid "ANT Info" +msgstr "ANT Bilgi" + +#: src/gtk.c:366 +msgid "About ANT" +msgstr "ANT hakkında" + +#: src/gtk.c:382 +#, c-format +msgid "" +"ANT (ANT is Not a Telephone) Version %s\n" +"Copyright 2002, 2003 Roland Stigge\n" +"\n" +"This is an ISDN telephone application\n" +"written for GNU/Linux and ISDN4Linux for\n" +"communicating via a full duplex soundcard (or\n" +"multiple sound devices if you like) and an\n" +"audio capable ISDN4Linux ISDN device\n" +"\n" +"Contact:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"Mailing list: ant-phone-devel@nongnu.org" +msgstr "" +"ANT (ANT bir telefon deÄŸildir) Sürüm %s\n" +"Telif hakkı 2002, 2003 Roland Stigge\n" +"\n" +"Bu bir ISDN telefon uygulamasıdır.\n" +"GNU/Linux ve ISDN4Linux için\n" +"yazılmıştır.\n" +"Tam dupleks ses kartları (veya çok sayıda\n" +"ses aygıtı) ve ses yetenekli ISDN4Linux\n" +"ISDN aygıtı kullanarak iletiÅŸim kurmak\n" +"için hazırlanmıştır.\n" +"\n" +"Ä°letiÅŸim:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"E-Posta Listesi: ant-phone-devel@nongnu.org" + +#: src/gtk.c:420 +msgid "ANT License" +msgstr "ANT Lisansı" + +#: src/gtk.c:421 +msgid "" +"ANT (ANT is Not a Telephone)\n" +"Copyright (C) 2002, 2003 Roland Stigge\n" +"\n" +"This program is free software; you can redistribute it and/or\n" +"modify it under the terms of the GNU General Public License\n" +"as published by the Free Software Foundation; either version 2\n" +"of the License, or (at your option) any later version.\n" +"\n" +"This program is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n" +"\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program; if not, write to the Free Software\n" +"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." +msgstr "" +"ANT (ANT bir telefon deÄŸildir)\n" +"Telif Hakkı (C) 2002, 2003 Roland Stigge\n" +"\n" +"Bu program bir serbest yazılımdır. Bu yazılımı Free Software Foundation\n" +"tarafından yayınlanmış olan GNU Genel Kamu Lisansının 2. ya da daha sonraki\n" +"bir sürümünün koÅŸulları altında kopyalayabilir, dağıtabilir ve/veya\n" +"üzerinde deÄŸiÅŸiklik yapabilirsiniz.\n" +"\n" +"Bu program kullanışlı olabileceÄŸi umularak dağıtılmaktadır. Ancak,\n" +"hiçbir GARANTÄ°SÄ° YOKTUR; hatta SATILABÄ°LÄ°RLİĞİ veya HERHANGÄ° BÄ°R\n" +"AMACA UYGUNLUÄžU için bile garanti verilmez. Daha ayrıntılı bilgi\n" +"edinmek için GNU Genel Kamu Lisansına bakınız.\n" +"\n" +"GNU Genel Kamu Lisansının bir kopyasını bu yazılımla birlikte almış\n" +"olacaksınız; yoksa Free Software Foundation, Inc., 59 Temple Place\n" +"Suite 330, Boston, MA 02111-1307, USA. adresinden isteyebilirsiniz." + +#: src/gtk.c:454 +msgid "/Phon_e" +msgstr "/Telefon_" + +#: src/gtk.c:455 +msgid "/Phone/_Info Window" +msgstr "/Telefon/_Bilgi Penceresi" + +#: src/gtk.c:456 src/gtk.c:504 +msgid "/Phone/_Line Level Check" +msgstr "/Telefon/_Seviye Tespit Kontrolu" + +#: src/gtk.c:458 +msgid "/Phone/" +msgstr "/Telefon/" + +#: src/gtk.c:459 +msgid "/Phone/_Quit" +msgstr "/Telefon/_VazgeçiÅŸ" + +#: src/gtk.c:461 +msgid "/_View" +msgstr "/_Görüntü" + +#: src/gtk.c:462 src/gtk.c:492 +msgid "/View/_Caller ID Monitor" +msgstr "/Görüntü/_Çağıran Birim Monitörü" + +#: src/gtk.c:464 src/gtk.c:495 +msgid "/View/_Line Level Meters" +msgstr "/Görüntü/_Satır Seviyesi Ölçümü" + +#: src/gtk.c:466 src/gtk.c:498 +msgid "/View/Control _Pad" +msgstr "/Görüntü/Kontrol_Yüzey" + +#: src/gtk.c:468 +msgid "/_Options" +msgstr "/_Seçenekler" + +#: src/gtk.c:469 src/gtk.c:501 +msgid "/Options/_Settings" +msgstr "/Seçenekler/_Ayarlar" + +#: src/gtk.c:471 +msgid "/_Help" +msgstr "/_Yardım" + +#: src/gtk.c:472 +msgid "/Help/_About" +msgstr "/Yardım/_Hakkında" + +#: src/gtk.c:473 +msgid "/Help/_License" +msgstr "/Yardım/_Lisans" + +#: src/gtk.c:551 src/gtksettings.c:431 src/session.c:68 +msgid "Dialing" +msgstr "BaÄŸlantı" + +#: src/gtk.c:783 src/gtk.c:784 +msgid "MUTED" +msgstr "SESSÄ°Z" + +#: src/gtksettings.c:230 +msgid "Bad isdn/sound device settings, please try again." +msgstr "Kötü isdn/SES aygıtı ayarları, lütfen tekrar deneyin" + +#: src/gtksettings.c:293 +msgid "ANT Settings" +msgstr "ANT Ayarları" + +#: src/gtksettings.c:306 +msgid "Application" +msgstr "Uygulamalar" + +#: src/gtksettings.c:308 +msgid "Options" +msgstr "Seçenekler" + +#: src/gtksettings.c:320 +msgid "Save options on exit" +msgstr "Çıkışta seçenekleri kaydedin" + +#: src/gtksettings.c:327 +msgid "Popup main window on incoming call" +msgstr "Gelen aramada ana pencereyi açar" + +#: src/gtksettings.c:333 +msgid "Execute on incoming call:" +msgstr "Gelen aramada çalıştırılır:" + +#: src/gtksettings.c:344 +msgid "Recording Format" +msgstr "Kayıt Biçemi" + +#: src/gtksettings.c:354 +msgid "Microsoft WAV, uLaw" +msgstr "Microsoft WAV, uLaw" + +#: src/gtksettings.c:364 +msgid "Microsoft WAV, 16-bit signed" +msgstr "Microsoft WAV, signed 16 bit " + +#: src/gtksettings.c:374 +msgid "Apple/SGI AIFF, uLaw" +msgstr "Apple/SGI AIFF, uLaw" + +#: src/gtksettings.c:384 +msgid "Apple/SGI AIFF, 16-bit signed" +msgstr "Apple/SGI AIFF, signed 16 bit" + +#: src/gtksettings.c:397 +msgid "Phone" +msgstr "Telefon" + +#: src/gtksettings.c:399 +msgid "ISDN" +msgstr "ISDN" + +#: src/gtksettings.c:411 +msgid "Identifying MSN:" +msgstr "MSN'i tanımlama:" + +#: src/gtksettings.c:421 +msgid "Listen to MSNs:" +msgstr "MSN'leri dinleyin:" + +#: src/gtksettings.c:443 +msgid "Dial history size:" +msgstr "Arama tarihçe boyutu:" + +#: src/gtksettings.c:467 +msgid "Maximum CID rows:" +msgstr "Maksimum CID satırı:" + +#: src/gtksettings.c:475 src/gtksettings.c:503 +msgid "[no limit]" +msgstr "[sınırsız]" + +#: src/gtksettings.c:484 +msgid "Read isdnlog data on startup" +msgstr "isdn kütük bilgisini baÅŸlangıçta okur" + +#: src/gtksettings.c:491 +msgid "Maximum days to read from isdnlog:" +msgstr "Isdn kütüğünden okunacak maksimum gün sayısı:" + +#: src/gtksettings.c:520 +msgid "Sound Devices" +msgstr "Ses Aygıtları" + +#: src/gtksettings.c:522 +msgid "OSS" +msgstr "OSS" + +#: src/gtksettings.c:534 +msgid "Input sound device:" +msgstr "Girdi ses aygıtı:" + +#: src/gtksettings.c:546 +msgid "Output sound device:" +msgstr "Çıktı ses aygıtı:" + +#: src/gtksettings.c:559 +msgid "Release unused devices" +msgstr "Kullanılmayan aygıtları serbest bırakır" + +#: src/gtksettings.c:609 +msgid "Save" +msgstr "Kaydet" + +#: src/llcheck.c:371 +msgid "Line Level Check" +msgstr "Ses Seviye Kontrolü" + +#: src/llcheck.c:383 +msgid "" +"Please check the line input level\n" +"and adjust it using your favorite\n" +"mixer application.\n" +"You can also play a sound\n" +"to test the sound output." +msgstr "" +"Lütfen ses girdi seviyesini\n" +"kontrol edin ve favori ses miksi\n" +"uygulamalarınızı kullanarak \n" +"ayarlayın. Ses çıktısını kontrol etmek için\n" +"bir ses çalabilirsiniz." + +#: src/llcheck.c:405 +msgid "Play sound" +msgstr "Ses çalar" + +#: src/session.c:65 +msgid "Ready" +msgstr "Hazır" + +#: src/session.c:65 +msgid "Dial" +msgstr "BaÄŸlan" + +#: src/session.c:65 src/session.c:69 src/session.c:70 +msgid "Hang up" +msgstr "Telefonu kapa" + +#: src/session.c:66 src/session.c:67 +msgid "RING" +msgstr "ÇAL" + +#: src/session.c:66 src/session.c:67 +msgid "Answer" +msgstr "Cevap ver" + +#: src/session.c:66 src/session.c:67 +msgid "Reject" +msgstr "Reddet" + +#: src/session.c:68 src/session.c:69 src/session.c:70 src/session.c:71 +msgid "Pick up" +msgstr "Telefonu aç" + +#: src/session.c:69 +msgid "B-Channel open" +msgstr "B kanalı açık" + +#: src/session.c:70 +msgid "Setup" +msgstr "Ayarlar" + +#: src/session.c:71 +msgid "Playback" +msgstr "Bantkaydı" + +#: src/session.c:71 +msgid "Stop" +msgstr "Dur" + +#: src/session.c:377 +#, c-format +msgid "Preset %d" +msgstr "%d'yi önkurun" + +#: src/session.c:699 +msgid "(HW ERROR)" +msgstr "(HW HATASI)" + +#: src/session.c:1000 +msgid "Audio OFF" +msgstr "Ses kapalı" + +#: src/session.c:1000 +msgid "Audio ON" +msgstr "Ses açık" + +#: src/session.c:1097 +msgid "(BUSY)" +msgstr "(MEÅžGUL)" + +#: src/session.c:1103 +msgid "(TIMEOUT)" +msgstr "(ZAMAN AÅžIMI)" + +#: src/session.c:1139 +msgid "(RUNG)" +msgstr "(ÇALMIÅž)" + +#: src/session.c:1381 +msgid "(ABORTED)" +msgstr "(DURDURULDU)" + +#: src/session.c:1389 +msgid "(REJECTED)" +msgstr "(REDDEDÄ°LDÄ°)" diff --git a/po/vi.po b/po/vi.po new file mode 100644 index 0000000..8cc4d87 --- /dev/null +++ b/po/vi.po @@ -0,0 +1,666 @@ +# Vietnamese translation for ant-phone-0.1.4. +# Copyright © 2005 Roland Stigge +# This file is distributed under the same license as the ant-phone-0.1.4 package. +# Clytie Siddall , 2005. +# +msgid "" +msgstr "" +"Project-Id-Version: ant-phone 0.1.4\n" +"Report-Msgid-Bugs-To: stigge@antcom.de\n" +"POT-Creation-Date: 2004-04-03 18:51+0200\n" +"PO-Revision-Date: 2005-04-11 17:21+0930\n" +"Last-Translator: Clytie Siddall \n" +"Language-Team: Vietnamese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/ant-phone.c:170 +#, c-format +msgid "" +"Usage: %s [OPTION...]\n" +"\n" +"Options:\n" +" -h, --help Show this help message\n" +" -v, --version Print version information\n" +" -r, --cleanup Remove stale socket file (left by accident by\n" +" previous run)\n" +" -d, --debug[=level] Print additional runtime debugging data to stdout\n" +" level = 1..2\n" +" -i, --soundin=DEVICE OSS compatible device for input (recording),\n" +" default: /dev/dsp\n" +" -o, --soundout=DEVICE OSS compatible device for output (playback),\n" +" default: /dev/dsp\n" +" -m, --msn=MSN identifying MSN (for outgoing calls), 0 for " +"master\n" +" MSN of this termination/port\n" +" default: 0\n" +" -l, --msns=MSNS MSNs to listen on, semicolon-separated list or " +"'*'\n" +" default: *\n" +" -c, --call=NUMBER Call specified number\n" +"\n" +"Note: If arguments of --soundin and --soundout are equal, a full duplex\n" +" sound device is needed.\n" +msgstr "" +"Cách sá»­ dụng: %s [TÙY_CHỌN...]\n" +"\n" +"Tùy chá»n:\n" +" -h, --help Hiển thị thông Ä‘iệp _trợ giúp_ này\n" +" -v, --version Hiển thị thông tin _phiên bản_\n" +" -r, --cleanup Bá» tập tin ổ cắm cÅ© (còn lại bất ngá» sau chạy " +"trÆ°á»›c) (_xóa_) -d, --debug[=MỨC] In dữ liệu _gỡ lá»—i_ thá»i chạy thêm xuất " +"thiết bị xuất chuẩn (stdout)\n" +" MỨC = 1..2\n" +" -i, --soundin=THIIẾT_BỊ thiết bị gõ tÆ°Æ¡ng thích vá»›i phần má»m nguồn mở " +"(ghi)\n" +"\t\t\t\t(_âm thành vào_) mặc định: /dev/dsp\n" +" -o, --soundout=THIẾT_BỊ thiết bị xuất tÆ°Æ¡ng thích vá»›i phần má»m nguồn mở " +"(phát)\n" +"\t\t\t\t(_âm thành ra_) mặc định: /dev/dsp\n" +" -m, --msn=Sá» số Ä‘a ngÆ°á»i ký tên (Multiple Subscriber Number: MSN) " +"nhận biết để gá»i qua Ä‘iện thoại,\n" +"\t\t\t0 cho MSN chính của cổng/thiết bị cuối này, mặc định: 0\n" +" -l, --msns=NHá»®NG_Sá» Những MSN để nghe qua, danh sách phân cách bằng dấu " +"phẩy\n" +"\t\t\thay dấu sao '*', mặc định: *\n" +" -c, --call=Sá» _gá»i_ số Ä‘iện thoại ấy\n" +"\n" +"Ghi chú: nếu hai đối số --soundin (âm thành vào) và --soundout (âm thành " +"xuất\n" +"là bằng nhau thì cần thiết bị âm thành truyá»n dẫn hai chiếu đầy đủ (full " +"duplex).\n" + +#: src/ant-phone.c:221 +#, c-format +msgid "Calling %s... " +msgstr "Gá»i %s..." + +#: src/ant-phone.c:225 +#, c-format +msgid "successful.\n" +msgstr "được rồi.\n" + +#: src/callerid.c:131 +msgid "Delete Entry" +msgstr "Xóa bá» mục" + +#: src/callerid.c:143 +msgid "" +"Are you sure you want to\n" +"delete this entry?" +msgstr "" +"Bạn có chắc muốn xóa bá»\n" +"mục này không?" + +#: src/callerid.c:148 +msgid "Delete recording" +msgstr "Xóa bá» mục ghi" + +#: src/callerid.c:266 +#, c-format +msgid "Enter the base filename for %s file" +msgstr "Hãy nhập tên tập tin cÆ¡ bản cho tập tin %s" + +#: src/callerid.c:312 +msgid "Do you really want to delete this recording?" +msgstr "Bạn chắc muốn xóa bá» mục ghi này không?" + +#: src/callerid.c:336 src/callerid.c:362 +msgid "/_Playback" +msgstr "/_Phát lại" + +#: src/callerid.c:337 src/callerid.c:366 +msgid "/_Save as..." +msgstr "/_LÆ°u là..." + +#: src/callerid.c:338 src/callerid.c:370 +msgid "/Delete _Recording" +msgstr "/Xóa bá» mục _ghi" + +#: src/callerid.c:340 src/callerid.c:374 +msgid "/_Delete Row" +msgstr "/Xóa bá» _hàng" + +#: src/callerid.c:423 src/gtksettings.c:455 +msgid "Caller ID" +msgstr "Xem số ngÆ°á»i gá»i" + +#: src/callerid.c:426 +msgid "Date/Time" +msgstr "Ngày/Giá»" + +#: src/callerid.c:427 +msgid "Type" +msgstr "Loại" + +#: src/callerid.c:428 +msgid "From" +msgstr "Từ" + +#: src/callerid.c:429 +msgid "To" +msgstr "Cho" + +#: src/callerid.c:430 +msgid "Duration" +msgstr "Thá»i gian" + +#: src/callerid.c:759 +msgid "(UNKNOWN)" +msgstr "(không biết)" + +#: src/callerid.c:828 +#, c-format +msgid "ANT: %d unanswered" +msgstr "ANT: %d chÆ°a trả lá»i" + +#: src/controlpad.c:101 +#, c-format +msgid "Preset %c" +msgstr "Lập trÆ°á»›c %c" + +#: src/controlpad.c:108 +#, c-format +msgid "Please input new preset data for button %c:" +msgstr "Hãy nhập dữ liệu lập trÆ°á»›c má»›i cho cái nút %c:" + +#: src/controlpad.c:121 +msgid "Name:" +msgstr "Tên:" + +#: src/controlpad.c:124 src/gtk.c:561 +msgid "Number:" +msgstr "Số Ä‘t:" + +#: src/controlpad.c:144 src/gtk.c:212 src/gtk.c:331 src/gtk.c:408 +#: src/gtksettings.c:571 src/llcheck.c:422 +msgid "OK" +msgstr "Äược" + +#: src/controlpad.c:157 src/gtksettings.c:616 src/session.c:68 +msgid "Cancel" +msgstr "Thôi" + +#: src/controlpad.c:315 +msgid "Backspace" +msgstr "Phím Xóa lùi" + +#: src/controlpad.c:315 +msgid "Preset 1" +msgstr "Lập trÆ°á»›c 1" + +#: src/controlpad.c:316 +msgid "Clear Number" +msgstr "Xóa số" + +#: src/controlpad.c:316 +msgid "Preset 2" +msgstr "Lập trÆ°á»›c 2" + +#: src/controlpad.c:317 +msgid "Redial" +msgstr "Quay số lại" + +#: src/controlpad.c:317 +msgid "Preset 3" +msgstr "Lập trÆ°á»›c 3" + +#: src/controlpad.c:318 +msgid "Mute Microphone" +msgstr "Tắt máy vi âm" + +#: src/controlpad.c:318 +msgid "Preset 4" +msgstr "Lập trÆ°á»›c 4" + +#: src/controlpad.c:351 +msgid "Control" +msgstr "Äiá»u khiển" + +#: src/controlpad.c:423 +msgid "Recording" +msgstr "Ghi" + +#: src/controlpad.c:434 +msgid "Record to file" +msgstr "Ghi vào tập tin" + +#: src/controlpad.c:445 +msgid "Record local channel" +msgstr "Ghi kênh địa phÆ°Æ¡ng" + +#: src/controlpad.c:456 +msgid "Record remote channel" +msgstr "Ghi kênh từ xa" + +#: src/gtk.c:230 src/gtksettings.c:229 +msgid "ANT Note" +msgstr "Ant: chú thích" + +#: src/gtk.c:231 +msgid "" +"Can't open audio device.\n" +"Please stop other applications using\n" +"the audio device(s) or check your\n" +"device settings and try again." +msgstr "" +"Không mở được thiết bị âm thanh.\n" +"Hãy thôi các thiết bị khác sá»­ dụng\n" +"cùng thiết bị âm thanh ấy hay kiểm tra\n" +"thiết lập thiết bị và thá»­ lại." + +#: src/gtk.c:260 +msgid "Sound input device:" +msgstr "Thiết bị gõ âm thanh:" + +#: src/gtk.c:261 +msgid "Input speed:" +msgstr "Tốc Ä‘á»™ gõ:" + +#: src/gtk.c:261 src/gtk.c:264 src/gtk.c:265 src/gtk.c:267 src/gtk.c:271 +#: src/gtk.c:274 src/gtk.c:275 src/gtk.c:277 +msgid "[inactive]" +msgstr "[không làm gì]" + +#: src/gtk.c:263 +msgid "Input sample size (bits):" +msgstr "Cỡ mẫu gõ (theo bit):" + +#: src/gtk.c:265 src/gtk.c:275 +msgid "Input fragment size (samples):" +msgstr "Cỡ mảnh gõ (theo mẫu):" + +#: src/gtk.c:267 +msgid "Input channels:" +msgstr "Kênh gõ:" + +#: src/gtk.c:270 +msgid "Sound output device:" +msgstr "Thiết bị âm thanh xuất:" + +#: src/gtk.c:271 +msgid "Output speed:" +msgstr "Tốc Ä‘á»™ xuất:" + +#: src/gtk.c:273 +msgid "Output sample size (bits):" +msgstr "Cỡ mẫu xuât (theo bit):" + +#: src/gtk.c:277 +msgid "Output channels:" +msgstr "Kênh xuất:" + +#: src/gtk.c:280 +msgid "ISDN device:" +msgstr "Thiết bị ISDN:" + +#: src/gtk.c:281 +msgid "ISDN speed (samples):" +msgstr "Tốc Ä‘á»™ ISDN (theo mẫu):" + +#: src/gtk.c:282 +msgid "ISDN sample size (bits):" +msgstr "Cỡ mẫu ISDN (theo bit):" + +#: src/gtk.c:283 +msgid "ISDN fragment size (bytes):" +msgstr "Cỡ mảnh ISDN (theo byte):" + +#: src/gtk.c:295 +msgid "ANT Info" +msgstr "Thông tin ANT" + +#: src/gtk.c:366 +msgid "About ANT" +msgstr "Giá»›i thiệu ANT" + +#: src/gtk.c:382 +#, c-format +msgid "" +"ANT (ANT is Not a Telephone) Version %s\n" +"Copyright 2002, 2003 Roland Stigge\n" +"\n" +"This is an ISDN telephone application\n" +"written for GNU/Linux and ISDN4Linux for\n" +"communicating via a full duplex soundcard (or\n" +"multiple sound devices if you like) and an\n" +"audio capable ISDN4Linux ISDN device\n" +"\n" +"Contact:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"Mailing list: ant-phone-devel@nongnu.org" +msgstr "" +"ANT (ANT is Not a Telephone) phiên bản %s\n" +"(ANT không phải là má»™t máy Ä‘iện thoại)Bản quyá»n © năm 2002, 2003 Roland " +"Stigge\n" +"\n" +"Äây là má»™t ứng dụng Ä‘iện thoai ISDN\n" +"được tạo cho GNU/Linux và ISDN4Linux\n" +"để truyá»n thông qua thẻ âm thanh truyá»n dẫn\n" +"hai chiếu đầy đủ (hay số nhiá»u thiết bị nếu muốn)\n" +"và thiết bị ISDN ISDN4Linux có thể gởi âm thanh.\n" +"\n" +"Liên hệ:\n" +"Roland Stigge, stigge@antcom.de\n" +"http://www.antcom.de/\n" +"Há»™p thÆ° chung: ant-phone-devel@nongnu.org" + +#: src/gtk.c:420 +msgid "ANT License" +msgstr "Quyá»n ANT" + +#: src/gtk.c:421 +msgid "" +"ANT (ANT is Not a Telephone)\n" +"Copyright (C) 2002, 2003 Roland Stigge\n" +"\n" +"This program is free software; you can redistribute it and/or\n" +"modify it under the terms of the GNU General Public License\n" +"as published by the Free Software Foundation; either version 2\n" +"of the License, or (at your option) any later version.\n" +"\n" +"This program is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n" +"\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program; if not, write to the Free Software\n" +"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." +msgstr "" +"ANT (ANT is Not a Telephone)\n" +"Bản quyá»n © năm 2002, 2003 Roland Stigge\n" +"\n" +"ChÆ°Æ¡ng trình này là phần má»m tá»± do; bạn có thể phân phối nó lại và/hay\n" +"sá»­a đổi nó theo Ä‘iá»u kiện của Quyá»n Công Chung Gnu (GPL)\n" +"nhÆ° xuất do Tổ chức Phần má»m Tá»± do (Free Software Foundation)\n" +"hoặc phiên bản 2 của quyá»n ấy hoặc (tùy chá»n) bất cứ phiên bản sau nào.\n" +"\n" +"Chúng tôi phân phối chÆ°Æ¡ng trình này vì mong nó hữu ích,\n" +"nhÆ°ng nó không bảo đảm gì cả, không có bảo đảm ngụ ý ngay cả\n" +"khả năng bán hay khả năng làm việc dứt khoát.\n" +"Hãy xem Quyá»n Công Chung Gnu (GPL) để tìm chi tiết.\n" +"\n" +"Nếu bạn chÆ°a nhận má»™t bản Quyá»n Công Chung Gnu\n" +"(Gnu General Public Licence) cùng vá»›i chÆ°Æ¡ng trinh này thì hãy\n" +"viết cho Tổ chức Phần má»m Tá»± do:\n" +"Free SoftwareFoundation, Inc.,\n" +"59 Temple Place - Suite 330,\n" +"Boston, MA 02111-1307, USA (Mỹ)." + +#: src/gtk.c:454 +msgid "/Phon_e" +msgstr "/_Äiện thoại" + +#: src/gtk.c:455 +msgid "/Phone/_Info Window" +msgstr "/Äiện thoại/Cá»­a sổ thông t_in" + +#: src/gtk.c:456 src/gtk.c:504 +msgid "/Phone/_Line Level Check" +msgstr "/Äiện thoại/Kiểm tra mức _dòng" + +#: src/gtk.c:458 +msgid "/Phone/" +msgstr "/Äiện thoại/" + +#: src/gtk.c:459 +msgid "/Phone/_Quit" +msgstr "/Äiện thoại/_Thoát" + +#: src/gtk.c:461 +msgid "/_View" +msgstr "/_Xem" + +#: src/gtk.c:462 src/gtk.c:492 +msgid "/View/_Caller ID Monitor" +msgstr "/Xem/Theo dõi số ngÆ°á»i dùng" + +#: src/gtk.c:464 src/gtk.c:495 +msgid "/View/_Line Level Meters" +msgstr "/Xem/Äo mức _dòng" + +#: src/gtk.c:466 src/gtk.c:498 +msgid "/View/Control _Pad" +msgstr "/Xem/_Bảng Ä‘iá»u khiển" + +#: src/gtk.c:468 +msgid "/_Options" +msgstr "/Tùy _chá»n" + +#: src/gtk.c:469 src/gtk.c:501 +msgid "/Options/_Settings" +msgstr "/Tùy chá»n/Thiết _lập" + +#: src/gtk.c:471 +msgid "/_Help" +msgstr "/Trợ _giúp" + +#: src/gtk.c:472 +msgid "/Help/_About" +msgstr "/Trợ giúp/_Giá»›i thiệu" + +#: src/gtk.c:473 +msgid "/Help/_License" +msgstr "/Trợ giúp/_Quyá»n" + +#: src/gtk.c:551 src/gtksettings.c:431 src/session.c:68 +msgid "Dialing" +msgstr "Quay số" + +#: src/gtk.c:783 src/gtk.c:784 +msgid "MUTED" +msgstr "Tắt tiếng rồi" + +#: src/gtksettings.c:230 +msgid "Bad isdn/sound device settings, please try again." +msgstr "Có thiết lập thiết bị ISDN/âm thanh sai nên hay thá»­ lại." + +#: src/gtksettings.c:293 +msgid "ANT Settings" +msgstr "Thiết lập ANT" + +#: src/gtksettings.c:306 +msgid "Application" +msgstr "Ứng dụng" + +#: src/gtksettings.c:308 +msgid "Options" +msgstr "Tùy chá»n" + +#: src/gtksettings.c:320 +msgid "Save options on exit" +msgstr "LÆ°u tùy chá»n khi thoát" + +#: src/gtksettings.c:327 +msgid "Popup main window on incoming call" +msgstr "Bật lên cá»­a sổ chính khi nhận sá»± gá»i" + +#: src/gtksettings.c:333 +msgid "Execute on incoming call:" +msgstr "Thi hành khi nhận sá»± gá»i" + +#: src/gtksettings.c:344 +msgid "Recording Format" +msgstr "Dạng ghi" + +#: src/gtksettings.c:354 +msgid "Microsoft WAV, uLaw" +msgstr "Microsoft WAV, uLaw" + +#: src/gtksettings.c:364 +msgid "Microsoft WAV, 16-bit signed" +msgstr "Microsoft WAV, 16-bit đã ký tên" + +#: src/gtksettings.c:374 +msgid "Apple/SGI AIFF, uLaw" +msgstr "Apple/SGI AIFF, uLaw" + +#: src/gtksettings.c:384 +msgid "Apple/SGI AIFF, 16-bit signed" +msgstr "Apple/SGI AIFF, 16-bit đã ký tên" + +#: src/gtksettings.c:397 +msgid "Phone" +msgstr "Äiện thoại" + +#: src/gtksettings.c:399 +msgid "ISDN" +msgstr "ISDN" + +#: src/gtksettings.c:411 +msgid "Identifying MSN:" +msgstr "Số Ä‘a ngÆ°á»i ký tên (Multiplê Subscriber Number: MSN) nhân biết:" + +#: src/gtksettings.c:421 +msgid "Listen to MSNs:" +msgstr "Nghe qua những số Ä‘a ngÆ°á»i ký tên (MSN) này:" + +#: src/gtksettings.c:443 +msgid "Dial history size:" +msgstr "Cỡ lịch sá»­ quay số:" + +#: src/gtksettings.c:467 +msgid "Maximum CID rows:" +msgstr "Tối Ä‘a hàng số ngÆ°á»i gởi:" + +#: src/gtksettings.c:475 src/gtksettings.c:503 +msgid "[no limit]" +msgstr "[vô vùng] " + +#: src/gtksettings.c:484 +msgid "Read isdnlog data on startup" +msgstr "Äá»c dữ liệu isdnlog (bản ghi ISDN) khi khởi Ä‘á»™ng" + +#: src/gtksettings.c:491 +msgid "Maximum days to read from isdnlog:" +msgstr "Äá»c từ isdnlog (bản ghi ISDN) được số ngày (tối Ä‘a):" + +#: src/gtksettings.c:520 +msgid "Sound Devices" +msgstr "Thiết bị âm thanh" + +#: src/gtksettings.c:522 +msgid "OSS" +msgstr "Phần má»m nguồn mở tá»± do" + +#: src/gtksettings.c:534 +msgid "Input sound device:" +msgstr "Thiết bị âm thanh gõ:" + +#: src/gtksettings.c:546 +msgid "Output sound device:" +msgstr "Thiết bị âm thanh xuất:" + +#: src/gtksettings.c:559 +msgid "Release unused devices" +msgstr "Nhả các thiết bị chÆ°a sá»­ dụng lại" + +#: src/gtksettings.c:609 +msgid "Save" +msgstr "LÆ°u" + +#: src/llcheck.c:371 +msgid "Line Level Check" +msgstr "Kiểm tra mức dòng" + +#: src/llcheck.c:383 +msgid "" +"Please check the line input level\n" +"and adjust it using your favorite\n" +"mixer application.\n" +"You can also play a sound\n" +"to test the sound output." +msgstr "" +"Hãy kiểm tra mức gõ dòng\n" +"và Ä‘iá»u chỉnh nó bằng ứng dụng\n" +"hoà tiếng Æ°a thích của bạn.\n" +"Bạn cÅ©ng có thể phát tiếng\n" +"để thá»­ xuất âm thanh ra." + +#: src/llcheck.c:405 +msgid "Play sound" +msgstr "Phát âm thanh" + +#: src/session.c:65 +msgid "Ready" +msgstr "Sẵn sàng" + +#: src/session.c:65 +msgid "Dial" +msgstr "Quay số" + +#: src/session.c:65 src/session.c:69 src/session.c:70 +msgid "Hang up" +msgstr "Ngừng nói" + +#: src/session.c:66 src/session.c:67 +msgid "RING" +msgstr "REO" + +#: src/session.c:66 src/session.c:67 +msgid "Answer" +msgstr "Trả lá»i" + +#: src/session.c:66 src/session.c:67 +msgid "Reject" +msgstr "Loại ra" + +#: src/session.c:68 src/session.c:69 src/session.c:70 src/session.c:71 +msgid "Pick up" +msgstr "Lấy" + +#: src/session.c:69 +msgid "B-Channel open" +msgstr "Kênh-B mở" + +#: src/session.c:70 +msgid "Setup" +msgstr "Thiết lập" + +#: src/session.c:71 +msgid "Playback" +msgstr "Phát lại" + +#: src/session.c:71 +msgid "Stop" +msgstr "Ngừng" + +#: src/session.c:377 +#, c-format +msgid "Preset %d" +msgstr "Lập trÆ°á»›c %d" + +#: src/session.c:699 +msgid "(HW ERROR)" +msgstr "(Lá»—i phần cứng)" + +#: src/session.c:1000 +msgid "Audio OFF" +msgstr "TẮT âm thanh" + +#: src/session.c:1000 +msgid "Audio ON" +msgstr "MỞ âm thanh" + +#: src/session.c:1097 +msgid "(BUSY)" +msgstr "(BẬN)" + +#: src/session.c:1103 +msgid "(TIMEOUT)" +msgstr "(HẾT THỜI)" + +#: src/session.c:1139 +msgid "(RUNG)" +msgstr "(REO Rá»’I)" + +#: src/session.c:1381 +msgid "(ABORTED)" +msgstr "(BỊ HỦY BỎ Rá»’I)" + +#: src/session.c:1389 +msgid "(REJECTED)" +msgstr "(LOẠI BỎ Rá»’I)" diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..0b6059d --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,11 @@ +ant-phone +calleridlexer.c +calleridparser.c +calleridparser.h +gettext.h +isdnlexer.c +isdnparser.c +isdnparser.h +*.o +.deps + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..74ddbf5 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,88 @@ +## Process this file with automake to produce Makefile.in + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +bin_PROGRAMS = ant-phone + +ant_phone_SOURCES = \ + ant-phone.c \ + callerid.c \ + g711.c \ + gtk.c \ + isdn.c \ + llcheck.c \ + mediation.c \ + session.c \ + sound.c \ + util.c \ + settings.c \ + calleridlexer.l \ + calleridparser.y \ + isdnlexer.l \ + isdnparser.y \ + gtksettings.c \ + controlpad.c \ + fxgenerator.c \ + server.c \ + client.c \ + recording.c \ + isdntree.c + +noinst_HEADERS = \ + callerid.h \ + g711.h \ + gtk.h \ + isdn.h \ + llcheck.h \ + mediation.h \ + session.h \ + sound.h \ + util.h \ + settings.h \ + gtksettings.h \ + controlpad.h \ + fxgenerator.h \ + server.h \ + client.h \ + recording.h \ + globals.h \ + gettext.h \ + isdnlexer.h \ + isdntree.h + +EXTRA_DIST = \ + pickup.xpm \ + hangup.xpm \ + in.xpm \ + out.xpm \ + backspace.xpm \ + redial.xpm \ + mute.xpm \ + aboutlogo.xpm \ + record.xpm \ + icon16x16.xpm \ + icon32x32.xpm \ + icon48x48.xpm \ + icon64x64.xpm + +top_srcdir = @top_srcdir@ +subdir = src + +datadir = @datadir@ +localedir = $(datadir)/locale +DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@ + +LIBS = @LIBINTL@ @LIBS@ + +INCLUDES = -I../intl -I$(top_srcdir)/intl @DEPS_CFLAGS@ +AM_CFLAGS = -DVERSION='"@VERSION@"' -DPACKAGE='"@PACKAGE@"' @CFLAGS@ +AM_LDFLAGS = @DEPS_LIBS@ +LDADD = @LEXLIB@ + +AM_YFLAGS = -d +##YFLAGS = -d +AM_LFLAGS=-olex.yy.c +##LFLAGS=-Pcallerid + +BUILT_SOURCES = isdnparser.h calleridparser.h diff --git a/src/aboutlogo.xpm b/src/aboutlogo.xpm new file mode 100644 index 0000000..287fec4 --- /dev/null +++ b/src/aboutlogo.xpm @@ -0,0 +1,338 @@ +/* XPM */ +static char * aboutlogo_xpm[] = { +"150 83 252 2", +" g None", +". g #FFFFFF", +"+ g #FEFEFE", +"@ g #F5F5F5", +"# g #E4E4E4", +"$ g #C0C0C0", +"% g #B8B8B8", +"& g #B3B3B3", +"* g #B5B5B5", +"= g #BEBEBE", +"- g #CACACA", +"; g #EFEFEF", +"> g #9B9B9B", +", g #656565", +"' g #373737", +") g #262626", +"! g #1C1C1C", +"~ g #070707", +"{ g #030303", +"] g #000000", +"^ g #020202", +"/ g #060606", +"( g #0D0D0D", +"_ g #232323", +": g #4E4E4E", +"< g #A0A0A0", +"[ g #E6E6E6", +"} g #B6B6B6", +"| g #636363", +"1 g #222222", +"2 g #080808", +"3 g #010101", +"4 g #848484", +"5 g #FDFDFD", +"6 g #DDDDDD", +"7 g #7F7F7F", +"8 g #1B1B1B", +"9 g #292929", +"0 g #C1C1C1", +"a g #DCDCDC", +"b g #6E6E6E", +"c g #111111", +"d g #A8A8A8", +"e g #FCFCFC", +"f g #F9F9F9", +"g g #A9A9A9", +"h g #242424", +"i g #0A0A0A", +"j g #9A9A9A", +"k g #E9E9E9", +"l g #818181", +"m g #616161", +"n g #585858", +"o g #626262", +"p g #A1A1A1", +"q g #CDCDCD", +"r g #ECECEC", +"s g #FBFBFB", +"t g #EDEDED", +"u g #8E8E8E", +"v g #0F0F0F", +"w g #2A2A2A", +"x g #7C7C7C", +"y g #D6D6D6", +"z g #F4F4F4", +"A g #C4C4C4", +"B g #838383", +"C g #8B8B8B", +"D g #767676", +"E g #DFDFDF", +"F g #BABABA", +"G g #1A1A1A", +"H g #8C8C8C", +"I g #F2F2F2", +"J g #F6F6F6", +"K g #AEAEAE", +"L g #959595", +"M g #AFAFAF", +"N g #D0D0D0", +"O g #F7F7F7", +"P g #464646", +"Q g #050505", +"R g #575757", +"S g #F0F0F0", +"T g #A5A5A5", +"U g #DEDEDE", +"V g #CCCCCC", +"W g #565656", +"X g #B4B4B4", +"Y g #8A8A8A", +"Z g #C5C5C5", +"` g #D5D5D5", +" . g #6C6C6C", +".. g #141414", +"+. g #DBDBDB", +"@. g #D7D7D7", +"#. g #B9B9B9", +"$. g #EEEEEE", +"%. g #727272", +"&. g #939393", +"*. g #E7E7E7", +"=. g #AAAAAA", +"-. g #3F3F3F", +";. g #676767", +">. g #151515", +",. g #909090", +"'. g #4D4D4D", +"). g #6D6D6D", +"!. g #A3A3A3", +"~. g #9D9D9D", +"{. g #7E7E7E", +"]. g #828282", +"^. g #757575", +"/. g #7B7B7B", +"(. g #868686", +"_. g #BDBDBD", +":. g #E5E5E5", +"<. g #363636", +"[. g #040404", +"}. g #8F8F8F", +"|. g #858585", +"1. g #B0B0B0", +"2. g #777777", +"3. g #171717", +"4. g #272727", +"5. g #F8F8F8", +"6. g #A7A7A7", +"7. g #989898", +"8. g #C8C8C8", +"9. g #E1E1E1", +"0. g #E0E0E0", +"a. g #C7C7C7", +"b. g #414141", +"c. g #090909", +"d. g #535353", +"e. g #969696", +"f. g #F3F3F3", +"g. g #404040", +"h. g #FAFAFA", +"i. g #C6C6C6", +"j. g #606060", +"k. g #0C0C0C", +"l. g #BBBBBB", +"m. g #3D3D3D", +"n. g #505050", +"o. g #474747", +"p. g #BFBFBF", +"q. g #686868", +"r. g #787878", +"s. g #3E3E3E", +"t. g #2B2B2B", +"u. g #E3E3E3", +"v. g #D4D4D4", +"w. g #121212", +"x. g #303030", +"y. g #EBEBEB", +"z. g #EAEAEA", +"A. g #F1F1F1", +"B. g #6B6B6B", +"C. g #9E9E9E", +"D. g #4C4C4C", +"E. g #4A4A4A", +"F. g #101010", +"G. g #5D5D5D", +"H. g #ABABAB", +"I. g #D3D3D3", +"J. g #D8D8D8", +"K. g #CFCFCF", +"L. g #696969", +"M. g #666666", +"N. g #2C2C2C", +"O. g #ADADAD", +"P. g #A6A6A6", +"Q. g #B2B2B2", +"R. g #B1B1B1", +"S. g #393939", +"T. g #333333", +"U. g #C3C3C3", +"V. g #7D7D7D", +"W. g #747474", +"X. g #5A5A5A", +"Y. g #888888", +"Z. g #919191", +"`. g #9C9C9C", +" + g #BCBCBC", +".+ g #C2C2C2", +"++ g #D2D2D2", +"@+ g #8D8D8D", +"#+ g #7A7A7A", +"$+ g #646464", +"%+ g #595959", +"&+ g #717171", +"*+ g #5B5B5B", +"=+ g #0E0E0E", +"-+ g #0B0B0B", +";+ g #5E5E5E", +">+ g #999999", +",+ g #878787", +"'+ g #484848", +")+ g #454545", +"!+ g #323232", +"~+ g #1D1D1D", +"{+ g #A4A4A4", +"]+ g #1F1F1F", +"^+ g #424242", +"/+ g #191919", +"(+ g #6F6F6F", +"_+ g #131313", +":+ g #202020", +"<+ g #B7B7B7", +"[+ g #9F9F9F", +"}+ g #2F2F2F", +"|+ g #161616", +"1+ g #515151", +"2+ g #181818", +"3+ g #5C5C5C", +"4+ g #898989", +"5+ g #2E2E2E", +"6+ g #444444", +"7+ g #4B4B4B", +"8+ g #3C3C3C", +"9+ g #979797", +"0+ g #CBCBCB", +"a+ g #E2E2E2", +"b+ g #383838", +"c+ g #343434", +"d+ g #808080", +"e+ g #5F5F5F", +"f+ g #929292", +"g+ g #1E1E1E", +"h+ g #A2A2A2", +"i+ g #434343", +"j+ g #6A6A6A", +"k+ g #E8E8E8", +"l+ g #212121", +"m+ g #797979", +"n+ g #282828", +"o+ g #545454", +"p+ g #707070", +"q+ g #C9C9C9", +"r+ g #949494", +"s+ g #ACACAC", +"t+ g #D1D1D1", +"u+ g #555555", +"v+ g #3A3A3A", +"w+ g #737373", +"x+ g #494949", +"y+ g #2D2D2D", +"z+ g #353535", +"A+ g #D9D9D9", +"B+ g #DADADA", +"C+ g #4F4F4F", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + @ # $ % & & * = - ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . @ $ > , ' ) ! ~ { ] ] ^ / ( _ : < [ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . @ } | 1 2 3 ] ] ] ] ] ] ] ] ] ] ] ] ] { _ 4 ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . 5 6 7 8 { ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] 3 9 0 + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . + a b c ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] c d e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . f g h 3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] i j k 0 l m n n o b p q r . . . . . . . . . . . . . . . . . . . . . . . . . . s t + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . s u v ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] c ) / ] ] ] ] ] ] ] ~ w x y + . . . . . . . . . . . . . . . . . . z A u B C B D E . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . F c ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] G H I . . . . . . . . . . . . . . . J K L M N E O 5 + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . @ P ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Q R S . . . . . . . . . . . . . N T U 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . V ~ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] 3 W z . . . . . . . . . . . = X e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . Y ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Q B + . . . . . . . . + Z ` . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . + .] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ..+.. . . . . . . . @.#.+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . z $.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . + | ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] %.. . . . . . . z &.I . . . . . . . . . . + O [ *.$.+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; =.-.&.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . + ;.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] >.S . + y ,.'.).Y !.. . . . . . . [ F ~.{.C ].^.^./.(.4 _.. . . . . . . . . . . . . . . . . . . . . . . . . . . :.&.<.[.] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . |.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] 3 1.I 2.3.3 ] ] ] 4.> 5.. + [ 6.4 7.8.U k e + . . + O 9.` . . . . . . . . . . . . . . . . . . . . . . . . . 0.l 1 [.] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . a.Q ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] b.: ^ ] ] ] ] ] ] c.d.(./.e.9.f.+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . a ).3.^ ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . z g.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ^ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] {.+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . h.i.j.k.] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . l.>.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Q m.~.1 c.{ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] n.s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . f.% o.c.] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . e 7.>.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] i x f.p.q.p.M r.c.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ! @ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . $.p s.Q ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . s } ' ^ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ^ t.T f u.v.f . . J m Q ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] w.[.] ] ] ] ] ] ] ] ] ] x.O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p Q ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . y.j b.[.] ] ] ] ] ] ] ] ] ] ] 3 8 r.U + v.z.. . . . . A.B.( ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] [.o.v.! ] ] ] ] ] ] ] ] ] ] j.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . @ N 7 -.( ] ] ] ] ] ] >.D.C u.e . U v.+ . . . . . . f % E.F.] ] ] ] ] ] ] ] ] ] ] ] ..}.; + G.] ] ] ] ] ] ] ] ] Q H.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . s I I.=.u u g J.z e . . . :.K.+ . . . . . . . . . s y.T t.^././.{.{./.L.M.%.m & + . . X ~ ] ] ] ] ] ] ] ] N.$.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . z O.s . . . . . . . . . . . . * b 5 . . . . . . . . [ P.. . . f ;.Q ] ] ] ] ] ] >.Q.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + R.$.. . . . . . . . . . . . y.).*.. . . . . . . . . + < f.. . . J 7.S.F./ / 2 T.K s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . u.1.. . . . . . . . . . . . . u P.. . . . . . . . . . . $ 0 . . . . . O K.p.p.U.; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + T $.. . . . . . . . . . . . I 7 z . . . . . . . . . . . A.j e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . 5 ; J.#.j C V.W.G.R R R R X.%.D Y.Z.`.].+.I 5 . . . . . . . . . . +.+. . . . . . . . . . . . . P.# . . . . . . . . . . . . . I ++p @+#+$+R R %+&+B j = [ e . . . . . . . . . . . . . . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ,.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . + +.j *+x.=+i Q ] ] ] ] ] ] ] ] ] ] ] ] ] ] ..F.-+v T.;+>+0.+ . . . . . s `.f . e.,+|.).).).).).).D %.).d.'+O . . . . . . . . + y C P c i ^ ] ] ] ] ] ] ] ] 3 / ( 9 ;.& O . . . . . . . . D ).).).).).)+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] <.).).).).).).).).).)._.. . . . . . ", +". . . . . . . . . . . . . . e E C !+^ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] [.~+] ] ] ] ] ] 3 m.{+z.+ . . :.=.. . ]+] ] ] ] ] ] ] ] [.G { ] ] t . . . . . . S d ^+[.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] /+7 +.e . . . . . F.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . ", +". . . . . . . . . . . . . U (+w.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] _+=+] ] ] ] ] ] ] ] ] :+Y.k . <+0 . . ]+] ] ] ] ] ] ] ] ] c ..3 ] #.. . . . I < t.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] _+b *.. . . . F.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . ", +". . . . . . . . . . . f [+~+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] F.v ] ] ] ] ] ] ] ] ] ] [.}+X &.f . . ]+] ] ] ] ] ] ] ] ] { 3.2 ] #.. . 5 Z P ~ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] !+ ++ . . F.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . ", +". . . . . . . . . . ; W.2 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ~+3 ] ] ] ] ] ] ] ] ] ] ] ] i n h.. . ]+] ] ] ] ] ] ] ] ] ] -+..3 #.. J @+|+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] _+d + . F.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . ", +". . . . . . . . . t 1+Q ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] w.] ] ] ] ] ] ] ] ] ] ] ] ] 3 2+H + . ]+] ] ] ] ] ] ] ] ] ] 3 _+~ #.S 3+~ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] w.#.. F.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . ", +". . . . . . . . @ ;+3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] c U.. ]+] ] ] ] ] ] ] ] ] ] ] ] ] T E.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] x.k F.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . ", +". . . . . . . 5 4+Q ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] : f ]+] ] ] ] ] ] ] ] ] ] ] ] ] Q ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] 2.=+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . ", +". . . . . . . Z c ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ^ ( ~+5+6+7+7+m.5+_ >.2 3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] -+++]+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] 3 2 2+N.8+7+^+w |+~ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] _+{ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . ", +". . . . . . f -.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] 2 b.9+0+f.+ . . . . . f a+= 4+b+{ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] &.]+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] [.c+d+= k 5 . . . 5 :.} e+c ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] { { { { { { ^ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] 3 { { { { { { { { { { f+. . . . . . ", +". . . . . . R.[.] ] ] ] ] ] ] ] ] ] ] ] ] ] 3.`.f.. . . . . . . . . . . . . I B / ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j.g+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] { x.h+S . . . . . . . . . . 5 8.T.{ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] 8+p.p.p.p.p.D 3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] M.p.p.p.p.p.p.p.p.p.p.:.. . . . . . ", +". . . . . . i+] ] ] ] ] ] ] ] ] ] ] ] ] ] >.<++ . . . . . . . . . . . . . . . e V.[.] ] ] ] ] ] ] ] ] ] ] ] ] ] g.|+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] { j+k+. . . . . . . . . . . . . . :.E.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] /+. . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . A.3+T.! 3 ] ] ] ] ] ] ] ] ] ] Q >++ . . . . . . . . . . . . . . . . . [ g+] ] ] ] ] ] ] ] ] ] ] ] ] ] ]+-+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Q |.5.. . . . . . . . . . . . . . . . @.l+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] [.z . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . 5 5.f.9.Z !.2.X.w c [.^ 3 ] ^+s . . . . . . . . . . . . . . . . . . 5 ;+] ] ] ] ] ] ] ] ] ] ] ] ] ] -+[.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] { j+f . . . . . . . . . . . . . . . . . . 4 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ^ a . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . s :.F ~.m+8.. . . . . . . . . . . . . . . . . . . . l ] ] ] ] ] ] ] ] ] ] ] ] ] ] Q ^ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] _ 9.. . . . . . . . . . . . . . . . . . . q =+] ] ] ] ] ] ] ] ] ] ] ] ] ] 3 a.. . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ^.. . . . . . . . . . . . . . . . . . . . A.n+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] p . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + y.D ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ~ l.. . . . . . . . . . . . . . . . . . . . + m.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + $.Z >+o+) i ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] 3.t . . . . . . . . . . . . . . . . . . . . . D.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e k+a.[+W.b.g+-+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ) + . . . . . . . . . . . . . . . . . . . . . p+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . 5 ; q+~.#+'+1 v c.^ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] '+. . . . . . . . . . . . . . . . . . . . . . #+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . h.$.a.e.;.b.2+3 3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] B.. . . . . . . . . . . . . . . . . . . . . . r+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . s k+p.r.P =+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] r.. . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . r s+3+1 { ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y.. . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . . . z.Z.N.[.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . . 5 & !+Q ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] c.( ] ] ] ] ] ] ] ] ] ] ] ] ] ] c.{ ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . . h.Y.=+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ^ >.g.p+g I.B.] ] ] ] ] ] ] ] ] ] ] ] ] ] -+[.] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . s m+2 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] 3 Q F.x.n.].=.` J s + . . %.] ] ] ] ] ] ] ] ] ] ] ] ] ] -+[.] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . . 7./ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ^ ( w | 7.- r e . . . . . . . . . %.] ] ] ] ] ] ] ] ] ] ] ] ] ] -+[.] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . . t+-+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Q 8+@+q f . . . . . . . . . . . . . . %.] ] ] ] ] ] ] ] ] ] ] ] ] ] -+[.] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] }.. . . . . . . . . . . . . . . . . ", +". . . . + W ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] 2+7.f.. . . . . . . . . . . . . . . . . L.] ] ] ] ] ] ] ] ] ] ] ] ] ] -+[.] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y.. . . . . . . . . . . . . . . . . ", +". . . . ++c ] ] ] ] ] ] ] ] ] ] ] ] ] ] F.<++ . . . . . . . . . . . . . . . . . . u+] ] ] ] ] ] ] ] ] ] ] ] ] ] -+[.] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . C.3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] b . . . . . . . . . . . . . . . . . ", +". . . . 7.^ ] ] ] ] ] ] ] ] ] ] ] ] ] ] #++ . . . . . . . . . . . . . . . . . . 5.^+] ] ] ] ] ] ] ] ] ] ] ] ] ] v Q ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . <+{ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ).. . . . . . . . . . . . . . . . . ", +". . . . d.] ] ] ] ] ] ] ] ] ] ] ] ] ] [.K.. . . . . . . . . . . . . . . . . . . y._ ] ] ] ] ] ] ] ] ] ] ] ] ] ] w./ ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . - [.] ] ] ] ] ] ] ] ] ] ] ] ] ] ).. . . . . . . . . . . . . . . . . ", +". . . 5 v+] ] ] ] ] ] ] ] ] ] ] ] ] ] / a+. . . . . . . . . . . . . . . . . . . _.^ ] ] ] ] ] ] ] ] ] ] ] ] ] ] -+[.] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . - [.] ] ] ] ] ] ] ] ] ] ] ] ] ] ).. . . . . . . . . . . . . . . . . ", +". . . 5 N.] ] ] ] ] ] ] ] ] ] ] ] ] ] { % . . . . . . . . . . . . . . . . . . @ P ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] -+[.] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . - [.] ] ] ] ] ] ] ] ] ] ] ] ] ] d.. . . . . . . . . . . . . . . . . ", +". . . 5 ' ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] e+5 . . . . . . . . . . . . . . . . e x 3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] -+[.] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . 0+[.] ] ] ] ] ] ] ] ] ] ] ] ] ] S.5 . . . . . . . . . . . . . . . . ", +". . . . E.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] -+1.. . . . . . . . . . . . . . . ; w+{ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] 2 { ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . # Q ] ] ] ] ] ] ] ] ] ] ] ] ] ] ..8.. . . . . . . . 5 O . . . . . . ", +". . . . u 3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] |+6.s . . . . . . . . . . . f <+S.^ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . S / ] ] ] ] ] ] ] ] ] ] ] ] ] ] 3 N.{+S . . s :.X ].x+~.. . . . . . ", +". . . . Z i ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] c.m N + . . . . . . . z.> -.2 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . e ..] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Q _+y+<.! c Q 3 ] %.. . . . . . ", +". . . . 5 b.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] / z+w+`.{+{+7.%.-.i 3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . . T.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] E.. . . . . . ", +". . . . . p.=+] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . . x ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ~+. . . . . . ", +". . . . . . w+{ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . . Z { ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] =+J . . . . . ", +". . . . . . f.%+{ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ..j+8 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . . f s.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] / A+. . . . . ", +". . . . . . . t , { ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] 3 b.A e X.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . . . _.v ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ^ O.. . . . . ", +". . . . . . . . z (.w.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ~+Z.I . . & / ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . . . e H ~ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] 3 L . . . . . ", +". . . . . . . . . 5 0+o.[.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ^ ~+4+z.+ . . . J t.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] Y . . . . . . . . . . . . . . . . . . . . . . &.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] j . . . . . . . e H.]+3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] w+. . . . . ", +". . . . . . . . . . . + U.u+_+[.] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] [.>.D.!.A.. . . . . . . H [.{ { { { { { { { { { { { { { { { { { { { { { { { { { C . . . . . . . . . . . . . . . . . . . . . . r+{ { { { { { { { { { { { { { { j . . . . . . . . . k+l h / ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] 3 2 ]+H . . . . . ", +". . . . . . . . . . . . . . *.s+, b+~+w./ ] ] ] ] ] ] [.c ~+S.q.=.[ + . . . . . . . . . r 1.K K K K K K K K K K K K K K K K K K K K K K K K K K A+. . . . . . . . . . . . . . . . . . . . . . +.K K K K K K K K K K K K K K K B+. . . . . . . . . . . z * q.' G v ^ ] ] ] ] ] ] ~ _+~+5+C+Z.p.z . . . . . . ", +". . . . . . . . . . . . . . . . . s :.I.l.g [+> > > =.<+t+[ s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . f 0.q 1.!.> > > {+H.= v.:.f . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "}; diff --git a/src/ant-phone.c b/src/ant-phone.c new file mode 100644 index 0000000..809f6a7 --- /dev/null +++ b/src/ant-phone.c @@ -0,0 +1,261 @@ +/* + * + * ANT (ANT is Not a Telephone) + * Copyright 2002, 2003 Roland Stigge + * + * ISDN Telephone application for Linux and OSS + * (full duplex or multiple sound devices needed) + * + * Author: Roland Stigge, stigge@antcom.de + * Created: 2002-09-04 (got the idea already around christmas 2000) + * + * Tested with: Debian GNU/Linux + * + * + * Some basic ideas for this program are based on: + * * IVCALL, Copyright 2000 Lennart Poettering (GPL) + * + * This program uses sources from: + * * g711.c (by Sun Microsystems, BSD like license) from SoX + * + * Used libraries: + * * libsndfile (Erik de Castro Lopo ) + * * GTK+ + * + * Contributors: see AUTHORS file + * + * + * 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 + * + */ + +#include "config.h" + +/* regular GNU system includes */ +#include +#ifdef HAVE_STDLIB_H + #include +#endif +#ifdef HAVE_STDDEF_H + #include +#endif +#include +#include +#include +#ifdef HAVE_UNISTD_H + #include +#endif +#ifdef HAVE_SYS_TYPES_H + #include +#endif +#ifdef HAVE_TERMIOS_H + #include +#endif +#ifdef HAVE_FCNTL_H + #include +#endif +#include +#ifdef HAVE_LIMITS_H + #include +#endif +#include +#include /* GNU extension: long options */ +#include +#include +#include + +/* For debugging purposes */ +#include + +/* own header files */ +#include "globals.h" +#include "isdn.h" +#include "sound.h" +#include "mediation.h" +#include "gtk.h" +#include "session.h" +#include "util.h" +#include "client.h" +#include "server.h" + +int main(int argc, char *argv[]) { + struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"usage", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'v'}, + {"cleanup", no_argument, 0, 'r'}, + {"debug", optional_argument, 0, 'd'}, + {"soundin", required_argument, 0, 'i'}, + {"soundout", required_argument, 0, 'o'}, + {"msn", required_argument, 0, 'm'}, + {"msns", required_argument, 0, 'l'}, + {"call", required_argument, 0, 'c'}, + {0, 0, 0, 0} + }; + char *short_options = "hvrd::i:o:m:l:c:"; + int option_index = 0; + int c; + + /* temporary default values = "", will be changed by command line options + and options in options file */ + char *audio_device_name_in = ""; + char *audio_device_name_out = ""; + char *msn = ""; + char *msns = ""; + + int gtk_result; + +#ifdef DEBUG + mtrace(); + debug = DEBUG; +#endif + + /* prepare for i18n */ +#ifdef ENABLE_NLS + setlocale(LC_ALL, ""); + if (!bindtextdomain(PACKAGE, LOCALEDIR)) { + fprintf(stderr, "Error setting directory for textdomain (i18n).\n"); + } + output_codeset_save(); + if (!textdomain(PACKAGE)) { + fprintf(stderr, "Error setting domainname for gettext() " + "(internationalization).\n"); + } +#endif + + /* only useful for yet to code separate audio thread + (rt only for audio thread!) + struct sched_param schedpar; // scheduler structure for priority + int priority_min, priority_max; + + // linux realtime scheduling + if ((priority_min = sched_get_priority_min(SCHED_FIFO)) < 0) { + perror("Realtime scheduling setup"); + exit(1); + } + if ((priority_max = sched_get_priority_max(SCHED_FIFO)) < 0) { + perror("Realtime scheduling setup"); + exit(1); + } + schedpar.sched_priority = (priority_min + priority_max) / 2; // arbitrary + if (sched_setscheduler(0, SCHED_FIFO, &schedpar) < 0) { + perror("Activating realtime scheduler"); + } + // give up root privileges + if (setuid(getuid()) < 0) { + perror("Giving up root privileges"); + } + */ + + /* first: GTK+ internal parsing of command line arguments */ + gtk_init(&argc, &argv); + + /* parse command line options */ + while ((c = getopt_long(argc, argv, short_options, long_options, + &option_index)) != -1) { + switch(c) { + case 'h': /* help */ + printf(_("Usage: %s [OPTION...]\n\ +\n\ +Options:\n\ + -h, --help Show this help message\n\ + -v, --version Print version information\n\ + -r, --cleanup Remove stale socket file (left by accident by\n\ + previous run)\n\ + -d, --debug[=level] Print additional runtime debugging data to stdout\n\ + level = 1..2\n\ + -i, --soundin=DEVICE OSS compatible device for input (recording),\n\ + default: /dev/dsp\n\ + -o, --soundout=DEVICE OSS compatible device for output (playback),\n\ + default: /dev/dsp\n\ + -m, --msn=MSN identifying MSN (for outgoing calls), 0 for master\n\ + MSN of this termination/port\n\ + default: 0\n\ + -l, --msns=MSNS MSNs to listen on, semicolon-separated list or '*'\n\ + default: *\n\ + -c, --call=NUMBER Call specified number\n\ +\n\ +Note: If arguments of --soundin and --soundout are equal, a full duplex\n\ + sound device is needed.\n"), argv[0]); + exit(0); + case 'v': /* version */ + printf("ANT " VERSION "\n"); + exit(0); + case 'r': /* clean up: remove old locking files */ + if (-1 == unlink(server_local_socket_name())) { + perror("unlink old socket file"); + } + break; + case 'd': /* debug mode */ + if (optarg) { + debug = strtol(optarg, NULL, 0); + } else { + debug = 1; + } + break; + case 'i': /* sound input device */ + audio_device_name_in = optarg; + break; + case 'o': /* sound output device */ + audio_device_name_out = optarg; + break; + case 'm': /* identifying msn */ + msn = optarg; + break; + case 'l': /* msns to listen on, '*' or semicolon-separated list */ + msns = optarg; + break; + case 'c': + printf(_("Calling %s... "), optarg); + if (client_make_call(optarg)) { + printf("\nAn error occured while calling a running " PACKAGE ".\n"); + } else { + printf(_("successful.\n")); + } + exit(0); + break; + case '?': + exit(1); + } + } + /* no further arguments expected, so not handled */ + + output_codeset_set("UTF-8"); /* GTK needs UTF-8 strings */ + + if (session_init(&session, audio_device_name_in, audio_device_name_out, + msn, msns)) + { + fprintf(stderr, "Error at session init.\n"); + exit(1); + } else { + if (debug) + fprintf(stderr, "Init OK.\n"); + } + + /* gtk stuff, main loop */ + gtk_result = main_gtk(&session); + + if (session_deinit(&session)) { + fprintf(stderr, "Error at session exit\n"); + exit(1); + } else { + if (debug) + fprintf(stderr, "Quit OK.\n"); + } + output_codeset_set(NULL); /* restore saved codeset */ + + return gtk_result; +} + diff --git a/src/backspace.xpm b/src/backspace.xpm new file mode 100644 index 0000000..7e73911 --- /dev/null +++ b/src/backspace.xpm @@ -0,0 +1,14 @@ +/* XPM */ +static char * backspace_xpm[] = { +"14 9 2 1", +" c None", +". c #000000", +" . ", +" .. ", +" ... ", +" .............", +"..............", +" .............", +" ... ", +" .. ", +" . "}; diff --git a/src/callerid.c b/src/callerid.c new file mode 100644 index 0000000..87aa6d4 --- /dev/null +++ b/src/callerid.c @@ -0,0 +1,926 @@ +/* + * caller id related functions + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "config.h" + +/* regular GNU system includes */ +#include +#ifdef HAVE_STDLIB_H + #include +#endif +#include +#include +#include +#include +#include +#include +#include + +/* GTK */ +#include +#include + +/* own header files */ +#include "globals.h" +#include "callerid.h" +#include "session.h" +#include "util.h" +#include "isdn.h" + +/* graphical symbols */ +#include "in.xpm" +#include "out.xpm" +#include "record.xpm" + +/* + * returns a new data structure (for association with a row) + * filled with default values + */ +static gpointer cid_row_new(void) { + struct cid_row_t *rowdata = + (struct cid_row_t *) malloc(sizeof(struct cid_row_t)); + + rowdata->marked_unanswered = 0; + return (gpointer) rowdata; +} + +/* + * callback to be called for additional row data on destruction of row + */ +static void cid_row_destroy(gpointer rowdata) { + if (debug > 1) + fprintf(stderr, "debug: destroying rowdata at %p.\n", rowdata); + free(rowdata); +} + +/* called when caller id monitor state check button is toggled */ +void cid_toggle_cb(GtkWidget *widget _U_, gpointer data, guint action _U_) { + session_t *session = (session_t *) data; + + if (GTK_CHECK_MENU_ITEM (session->cid_check_menu_item)->active) { + gtk_widget_show(session->cid); + session->option_show_callerid = 1; + } else { + gtk_widget_hide(session->cid); + session->option_show_callerid = 0; + gtk_window_resize(GTK_WINDOW(session->main_window), 1, 1); + } +} + +/* + * Callback: called when a button was clicked in row delete dialog + */ +static void cid_delete_response_cb(GtkWidget* widget, gint response_id, + gpointer data) +{ + session_t* session = (session_t*) data; + guint row = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(widget), "row")); + char* filename = (char*) g_object_get_data(G_OBJECT(widget), "filename"); + GtkWidget* checkbutton = + (GtkWidget*) g_object_get_data(G_OBJECT(widget), "checkbutton"); + + if (response_id == GTK_RESPONSE_OK) { + if (filename && + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbutton))) + { + unlink(filename); + } + cid_mark_row(session, row, FALSE); /* to count unanswered calls */ + session->cid_num--; + /* decrease before removal: "select-row" signal submission -> other cb */ + gtk_clist_remove(GTK_CLIST(session->cid_list), row); + } + + if (filename) free(filename); + gtk_widget_destroy(widget); +} + +/* + * called on cid delete request + * + * -> deletes specified row without confirmation + */ +static void cid_request_delete(GtkWidget *widget _U_, gpointer data, + guint row) { + session_t* session = (session_t *) data; + GtkWidget* vbox; + GtkWidget* label; + GtkWidget* checkbutton; + char *filename = cid_get_record_filename(session, row); + + GtkWidget* dialog = gtk_dialog_new_with_buttons(_("Delete Entry"), + GTK_WINDOW(session->main_window), + GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, + NULL); + + vbox = gtk_vbox_new(FALSE, 16); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 16); + gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox); + gtk_widget_show(vbox); + + label = gtk_label_new(_("Are you sure you want to\ndelete this entry?")); + gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); + gtk_box_pack_start_defaults(GTK_BOX(vbox), label); + gtk_widget_show(label); + + checkbutton = gtk_check_button_new_with_label(_("Delete recording")); + if (filename) { /* default: checked */ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton), TRUE); + } else { /* if file doesn't exist, grey out */ + gtk_widget_set_sensitive(checkbutton, FALSE); + } + gtk_box_pack_start_defaults(GTK_BOX(vbox), checkbutton); + gtk_widget_show(checkbutton); + + g_object_set_data(G_OBJECT(dialog), "row", GUINT_TO_POINTER(row)); + g_object_set_data(G_OBJECT(dialog), "filename", (gpointer) filename); + g_object_set_data(G_OBJECT(dialog), "checkbutton", (gpointer) checkbutton); + g_signal_connect(dialog, "response", G_CALLBACK(cid_delete_response_cb), + session); + gtk_widget_show(dialog); +} + +/* + * called on key pressed in cid list + */ +static gint cid_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) { + + switch (event->keyval) { + case GDK_Delete: /* Delete dialog */ + case GDK_KP_Delete: + /* portability: GtkCList.selection is private! */ + if (GTK_CLIST(((session_t *) data)->cid_list)->selection) { + cid_request_delete(widget, data, + GPOINTER_TO_INT(GTK_CLIST(((session_t *) data)->cid_list)->selection->data)); + } + return TRUE; /* event handled */ + default: + return FALSE; + } +} + +/* + * Callback: called on playback request + */ +static void cid_playback(GtkWidget *widget _U_, gpointer data, guint row) { + session_t *session = (session_t *) data; + + session->effect_filename = cid_get_record_filename(session, row); + session->effect_playback_start_time = time(NULL); + session_set_state(session, STATE_PLAYBACK); +} + +/* + * Callback: called on "OK" click in "Save as..." file selection + */ +static void cid_save_as_filename_cb(GtkWidget *fs) { + char* sourcename = g_object_get_data(G_OBJECT(fs), "sourcename"); + const char* destbase = + gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)); + if (*destbase && *basename(destbase)) { + /* copy if something was entered */ + char* destination; + char* extension = filename_extension(sourcename); + if (0 <= asprintf(&destination, "%s.%s", destbase, extension)) { + /* actually copy if source and destination known */ + int buffer_size = 65536; + char* buffer = (char*) malloc(buffer_size); + if (buffer) { + int fd_in = open(sourcename, O_RDONLY); + if (fd_in != -1) { + int fd_out = open(destination, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); + if (fd_out != -1) { + int just_read; + do { + int to_write = just_read = read(fd_in, buffer, buffer_size); + int written = 1; + char* buffer_index = buffer; + while (to_write && written) { + written = write(fd_out, buffer_index, to_write); + to_write -= written; + buffer_index += written; + } + } while (just_read); + if (close(fd_out)) { + fprintf(stderr, "Error on closing destination file.\n"); + } + } else { + fprintf(stderr, + "Error on destination file (%s) open().\n", destination); + } + if (close(fd_in)) { + fprintf(stderr, "Error on source file.\n"); + } + } else { + fprintf(stderr, + "Error on source file (%s) open().\n", sourcename); + } + free(buffer); + } else { + fprintf(stderr, "Error on malloc().\n"); + } + free(destination); + } else { + fprintf(stderr, "Error on asprintf().\n"); + } + } + free(sourcename); + gtk_widget_destroy(GTK_WIDGET(fs)); +} + +/* + * Callback: called on "Save as..." request + */ +static void cid_save_as(GtkWidget *widget _U_, gpointer data, guint row) { + session_t* session = (session_t*) data; + char* sourcename = cid_get_record_filename(session, row); + char* extension = filename_extension(sourcename); + + if (extension) { + GtkWidget* fs; + char* title; + + if (0 > asprintf(&title, _("Enter the base filename for %s file"), + extension)) + { + fprintf(stderr, "Error on asprintf().\n"); + return; + } + fs = gtk_file_selection_new(title); + free(title); + g_signal_connect_swapped(GTK_OBJECT(GTK_FILE_SELECTION(fs)->cancel_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + g_object_set_data(G_OBJECT(fs), "sourcename", sourcename); + g_signal_connect_swapped(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), + "clicked", G_CALLBACK(cid_save_as_filename_cb), fs); + gtk_widget_show(fs); + } else { + fprintf(stderr, "Error: no filename extension found.\n"); + } +} + +/* + * Callback: called if something happened in the delete recording dialog + */ +static void cid_delete_rec_response_cb(GtkWidget* widget, gint response_id, + gpointer data) +{ + session_t *session = (session_t *) data; + + if (response_id == GTK_RESPONSE_OK) { + char* temp; + guint row = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(widget), "row")); + unlink(temp = cid_get_record_filename(session, row)); + free(temp); + cid_row_mark_record(session, row); + } + gtk_widget_destroy(widget); +} + +/* + * Callback: called on delete recording request + */ +static void cid_delete_rec(GtkWidget *widget _U_, gpointer data, guint row) { + session_t *session = (session_t *) data; + + GtkWidget* dialog = gtk_message_dialog_new(GTK_WINDOW(session->main_window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK_CANCEL, _("Do you really want to delete this recording?")); + g_signal_connect(dialog, "response", G_CALLBACK(cid_delete_rec_response_cb), + session); + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + g_object_set_data(G_OBJECT(dialog), "row", GINT_TO_POINTER(row)); + gtk_widget_show(dialog); +} + +/* + * called on mouse button pressed in cid list + */ +static gint cid_mouse_cb(GtkWidget *widget _U_, + GdkEventButton *event, gpointer data) { + session_t *session = (session_t *) data; + + if (event->button == 3) { /* popup menu */ + gint row; + gint column; + + if (gtk_clist_get_selection_info(GTK_CLIST(session->cid_list), + event->x, event->y, &row, &column)) { + + GtkItemFactoryEntry menu_items[] = { +/*path accel. callb. cb param. kind extra */ +{_("/_Playback"), NULL, cid_playback, row, "", NULL}, +{_("/_Save as..."), NULL, cid_save_as, row, "", NULL}, +{_("/Delete _Recording"),NULL, cid_delete_rec,row, "", NULL}, +{ "/Sep", NULL, NULL, 0, "", NULL}, +{_("/_Delete Row"), NULL, cid_request_delete, row, "", NULL} + }; + GtkMenu *menu = GTK_MENU(gtk_menu_new()); + GtkItemFactory *item_factory; + GtkAccelGroup *accel_group; + + gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]); + + GtkWidget *playback_item; + GtkWidget *save_as_item; + GtkWidget *delete_record_item; + GtkWidget *delete_item; + char* fn; + char* temp; + + accel_group = gtk_accel_group_new(); + item_factory = gtk_item_factory_new(GTK_TYPE_MENU, "", + accel_group); + gtk_item_factory_create_items_ac(item_factory, nmenu_items, menu_items, + session, 2); + + if (!(playback_item = gtk_item_factory_get_item(item_factory, + temp = stripchr(_("/_Playback"), '_')))) + fprintf(stderr, "Error getting playback_item.\n"); + free(temp); + if (!(save_as_item = gtk_item_factory_get_item(item_factory, + temp = stripchr(_("/_Save as..."), '_')))) + fprintf(stderr, "Error getting save_as_item.\n"); + free(temp); + if (!(delete_record_item = gtk_item_factory_get_item(item_factory, + temp = stripchr(_("/Delete _Recording"), '_')))) + fprintf(stderr, "Error getting delete_record_item_item.\n"); + free(temp); + if (!(delete_item = gtk_item_factory_get_item(item_factory, + temp = stripchr(_("/_Delete Row"), '_')))) + fprintf(stderr, "Error getting delete_item.\n"); + free(temp); + + if (!(session->state == STATE_READY && + (fn = cid_get_record_filename(session, row)))) { + gtk_widget_set_sensitive(playback_item, FALSE); + gtk_widget_set_sensitive(save_as_item, FALSE); + gtk_widget_set_sensitive(delete_record_item, FALSE); + } else { + free(fn); + } + + menu = GTK_MENU(gtk_item_factory_get_widget(item_factory, "")); + gtk_menu_set_accel_group(menu, accel_group); + + gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time); + } + return TRUE; /* event handled */ + } else { + return FALSE; + } +} + +/* + * called on row select (to unmark lines) + */ +static void cid_select_row_cb(GtkCList *list _U_, gint row, gint column _U_, + GdkEventButton *button _U_, gpointer data) { + session_t *session = (session_t *) data; + + if (row < session->cid_num) + cid_mark_row(session, row, FALSE); +} + +/* + * Returns the Caller ID section as GtkWidget, + * sets CID related members in session + * NOTE: caller has to gtk_widget_show() this widget + */ +GtkWidget *cid_new(session_t *session) { + GtkWidget *frame; /* frame with comment */ + GtkWidget *scrolled_window; /* the home for the clist */ + GtkWidget *clist; /* the list itself */ + GtkStyle *style; /* needed for preparing symbols */ + GtkWidget *pixmapwidget; /* record symbol */ + gchar *titles[CID_COL_NUMBER]; + + style = gtk_widget_get_style(session->main_window); + frame = gtk_frame_new(_("Caller ID")); + + titles[CID_COL_FLAGS ] = ""; + titles[CID_COL_TIME ] = _("Date/Time"); + titles[CID_COL_TYPE ] = _("Type"); + titles[CID_COL_FROM ] = _("From"); + titles[CID_COL_TO ] = _("To"); + titles[CID_COL_DURATION] = _("Duration"); + + gtk_container_set_border_width(GTK_CONTAINER(frame), 8); + + /* the scrolled window: no special adjustments */ + scrolled_window = gtk_scrolled_window_new(NULL, NULL); + /* always vertical scroll bar, horizontal... well... automatic means no ;) */ + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_container_add(GTK_CONTAINER(frame), scrolled_window); + gtk_container_set_border_width(GTK_CONTAINER(scrolled_window), 8); + gtk_widget_show(scrolled_window); + + /* the list widget */ + clist = gtk_clist_new_with_titles(CID_COL_NUMBER, titles); + session->symbol_record_pixmap = gdk_pixmap_create_from_xpm_d( + session->main_window->window, + &session->symbol_record_bitmap, + &style->bg[GTK_STATE_NORMAL], + (gchar **) record_xpm); + pixmapwidget = gtk_pixmap_new(session->symbol_record_pixmap, + session->symbol_record_bitmap); + gtk_clist_set_column_widget(GTK_CLIST(clist), CID_COL_FLAGS, pixmapwidget); + + /* default: GTK_SELECTION_MULTIPLE: */ + gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_BROWSE); + + gtk_clist_set_shadow_type(GTK_CLIST(clist), GTK_SHADOW_IN); + gtk_clist_set_column_width(GTK_CLIST(clist), CID_COL_FLAGS, 14); + gtk_clist_set_column_width(GTK_CLIST(clist), CID_COL_TIME, 128); + gtk_clist_set_column_width(GTK_CLIST(clist), CID_COL_TYPE, 30); + gtk_clist_set_column_width(GTK_CLIST(clist), CID_COL_FROM, 100); + gtk_clist_set_column_width(GTK_CLIST(clist), CID_COL_TO, 100); + gtk_clist_set_column_width(GTK_CLIST(clist), CID_COL_DURATION, 80); + /*gtk_clist_set_column_width(GTK_CLIST(clist), 5, 80);*/ + gtk_container_add(GTK_CONTAINER(scrolled_window), clist); + gtk_clist_column_titles_show(GTK_CLIST(clist)); + gtk_widget_set_size_request(clist, 500, 128); + + gtk_signal_connect(GTK_OBJECT(clist), "key-press-event", + GTK_SIGNAL_FUNC(cid_key_cb), session); + gtk_signal_connect(GTK_OBJECT(clist), "button-press-event", + GTK_SIGNAL_FUNC(cid_mouse_cb), session); + gtk_signal_connect(GTK_OBJECT(clist), "select-row", + GTK_SIGNAL_FUNC(cid_select_row_cb), session); + + gtk_widget_show(clist); + + /* set up IN/OUT symbols */ + session->symbol_in_pixmap = gdk_pixmap_create_from_xpm_d( + session->main_window->window, + &session->symbol_in_bitmap, + &style->bg[GTK_STATE_NORMAL], + (gchar **) in_xpm); + session->symbol_out_pixmap = gdk_pixmap_create_from_xpm_d( + session->main_window->window, + &session->symbol_out_bitmap, + &style->bg[GTK_STATE_NORMAL], + (gchar **) out_xpm); + session->cid = frame; + session->cid_list = clist; + session->cid_scrolled_window = scrolled_window; + + return frame; +} + +/* + * select last item in cid list and adjust view to end of list + */ +void cid_jump_to_end(session_t *session) { + GtkAdjustment *adj; + + gtk_clist_select_row(GTK_CLIST(session->cid_list), + session->cid_num - 1, 0); + + adj = gtk_scrolled_window_get_vadjustment( + GTK_SCROLLED_WINDOW(session->cid_scrolled_window)); + gtk_adjustment_set_value(adj, fmax(adj->lower, adj->upper - adj->page_size)); +} + +/* + * remove unneeded entries from caller id list (shorten log) + */ +void cid_normalize(session_t *session) { + while (session->cid_num_max && session->cid_num > session->cid_num_max) { + gtk_clist_remove(GTK_CLIST(session->cid_list), 0); + session->cid_num--; + } +} + +/* + * returns a dynamically allocated string in cid conformant time format + * caller has got to take care of freeing this memory after usage + */ +static char *cid_timestring(time_t t) { + char *date = (char *) malloc(20); + int len; + + date[0] = '\1'; + len = strftime(date, 20, "%Y-%m-%d %H:%M:%S", localtime(&t)); + if (len == 0 && date[0] != '\0') { + fprintf(stderr, "cid: Error calculating time with strftime.\n"); + return NULL; + } + + return date; +} + +/* + * insert new entry at end of list + * + * from == NULL, if still unknown + */ +void cid_add_line(session_t *session, + enum call_type_t ct, gchar *from, gchar *to) { + gchar *line[CID_COL_NUMBER]; + char *typestring; + + GdkPixmap *pixmap; + GdkBitmap *bitmap; + + /* First: date */ + line[CID_COL_TIME] = cid_timestring(session->ring_time); + + line[CID_COL_FLAGS] = ""; + line[CID_COL_TYPE] = ""; /* call type */ + + if (from == NULL) /* the from field */ + line[CID_COL_FROM] = "???"; + else + line[CID_COL_FROM] = from; + line[CID_COL_TO] = to; + + line[CID_COL_DURATION] = "???"; /* duration */ + + /* create line */ + session->cid_num = gtk_clist_append(GTK_CLIST(session->cid_list), line) + 1; + gtk_clist_set_row_data_full(GTK_CLIST(session->cid_list), + session->cid_num - 1, + cid_row_new(), cid_row_destroy); + + cid_normalize(session); + + /* actually set pixmap */ + if (ct == CALL_IN) { + pixmap = session->symbol_in_pixmap; + bitmap = session->symbol_in_bitmap; + typestring = "IN"; + } else { + pixmap = session->symbol_out_pixmap; + bitmap = session->symbol_out_bitmap; + typestring = "OUT"; + } + gtk_clist_set_pixtext(GTK_CLIST(session->cid_list), session->cid_num - 1 , + CID_COL_TYPE, typestring, 50, pixmap, bitmap); + + cid_jump_to_end(session); + + /* clean up */ + free(line[CID_COL_TIME]); +} + +/* + * set "date" field in last line + */ +void cid_set_date(session_t *session, time_t date) { + if (date) { + char *temp; + gtk_clist_set_text(GTK_CLIST(session->cid_list), + session->cid_num - 1, CID_COL_TIME, + temp = cid_timestring(date)); + free(temp); + } +} + +/* + * set "from" field in last line + */ +void cid_set_from(session_t *session, gchar *from) { + if (from) + gtk_clist_set_text(GTK_CLIST(session->cid_list), + session->cid_num - 1, CID_COL_FROM, from); +} + +/* + * complete last line with "duration" + * + * if message == NULL, current time will be used to calculate a duration + * if message != NULL, this string will be displayed in the Duration field (#4) + */ +void cid_set_duration(session_t *session, gchar *message) { + char *buf = timediff_str(time(NULL), session->vcon_time); + + if (message) + gtk_clist_set_text(GTK_CLIST(session->cid_list), session->cid_num - 1, + CID_COL_DURATION, message); + else + gtk_clist_set_text(GTK_CLIST(session->cid_list), session->cid_num - 1, + CID_COL_DURATION, buf); + free(buf); +} + +/* + * Add a line to clist (e.g. from saved caller id file) + */ +void cid_add_saved_line(session_t *session, char *date, char *type, + char *from, char *to, char *duration) { + if (debug > 1) + fprintf(stderr, "Caller ID add:\n" + "Date: |%s|, Type: |%s|, From: |%s|, To: |%s|, Dur: |%s|\n", + date, type, from, to, duration); + + cid_add_line(session, + !strncmp(type, "IN", 2) ? CALL_IN : CALL_OUT, from, to); + gtk_clist_set_text(GTK_CLIST(session->cid_list), + session->cid_num - 1, CID_COL_TIME, date); + gtk_clist_set_text(GTK_CLIST(session->cid_list), + session->cid_num - 1, CID_COL_DURATION, duration); + + cid_row_mark_record(session, session->cid_num - 1); + +} + +/* + * Merges isdnlog data into existing cid list + */ +void cid_calls_merge(session_t *session) { + int low, high, mid; /* bounds and helper index */ + time_t start = time(NULL) + - 60 * 60 * 24 * session->option_calls_merge_max_days; + int callstime; /* time of calls file line */ + char *cidstr; /* time of cid_list entry */ + size_t linelength = 100; /* buffer size */ + char *line = (char *) malloc (linelength); /* initial buffer for getline() */ + FILE *f = NULL; + + char from[41]; /* data to read from calls file */ + char to[41]; + int duration; + int date; + char type[4]; + + char *temp; + int rel; + int cidline; /* index into cid list */ + gchar *linearr[CID_COL_NUMBER]; /* line to insert to cid_list */ + GdkPixmap *pixmap; + GdkBitmap *bitmap; + + char *cache; /* tracks successive dates */ + + char* calls_filename; + + /* try to find isdnlog data file */ + calls_filename = isdn_get_calls_filename(); + if (calls_filename && (f = fopen(calls_filename, "r"))) { + if (debug) { + fprintf(stderr, "Using %s as source for isdnlog data.\n", calls_filename); + } + if (session->option_calls_merge_max_days) { + /* binary search on the file for the desired starting time if needed */ + if (debug >= 3) { + fprintf(stderr, "Binary search in calls file...\n"); + } + low = 0; + fseek(f, 0, SEEK_END); + high = ftell(f); + + while (high - low > 200) { + if (debug >= 3) { + fprintf(stderr, "low = %d, high = %d\n", low, high); + } + mid = (low + high) / 2; + fseek(f, mid, SEEK_SET); + getline(&line, &linelength, f); /* discard potentially partial line */ + if (-1 != getline(&line, &linelength, f)) { + if (!sscanf(line, "%*40[^|]|%*40[^|]|%*40[^|]|%*40[^|]|%*40[^|]|%d", + &callstime)) + break; + if (callstime < start) + low = mid; + else + high = mid; + } else + break; + } + fseek(f, low, SEEK_SET); + getline(&line, &linelength, f); + } + + /* read in all remaining lines: merge */ + cidline = 0; + cache = strdup(""); + while (!feof(f)) { + /* get new calls line */ + if (-1 == getline(&line, &linelength, f)) break; + if (sscanf(line, + "%*40[^|]|%40[^|]|%40[^|]|%d|%*40[^|]|%d|%*40[^|]|%1c", + from, to, &duration, &date, type) != 5) { + fprintf(stderr, "Warning: Incomplete data input from calls file.\n"); + break; + } + if ((temp = strchr(from, ' '))) *temp = '\0'; + if ((temp = strchr(to, ' '))) *temp = '\0'; + if (type[0] == 'I') { + type[1] = 'N'; + type[2] = '\0'; + pixmap = session->symbol_in_pixmap; + bitmap = session->symbol_in_bitmap; + } else { + type[1] = 'U'; + type[2] = 'T'; + type[3] = '\0'; + pixmap = session->symbol_out_pixmap; + bitmap = session->symbol_out_bitmap; + } + + /* prepare (text) line to merge */ + linearr[CID_COL_TIME] = cid_timestring((time_t)date); + linearr[CID_COL_TYPE] = type; + if (*from) + linearr[CID_COL_FROM] = from; + else + linearr[CID_COL_FROM] = "???"; + if (*to) + linearr[CID_COL_TO] = to; + else + linearr[CID_COL_TO] = "???"; + if (duration < 0) { + linearr[CID_COL_DURATION] = strdup(_("(UNKNOWN)")); + } else { + linearr[CID_COL_DURATION] = timediff_str(duration, (time_t) 0); + } + + /* where to merge it in? */ + rel = 1; /* init to merge by default */ + while (cidline < session->cid_num && + (gtk_clist_get_text(GTK_CLIST(session->cid_list), + cidline, CID_COL_TIME, &cidstr), + (rel = strcmp(cidstr, linearr[CID_COL_TIME])) < 0)) { + + cidline++; + } + + if ((rel > 0 && strcmp(linearr[CID_COL_TIME], cache) > 0) + || cidline == session->cid_num) { + /* only merge new and successive entries */ + + gtk_clist_insert(GTK_CLIST(session->cid_list), cidline, linearr); + gtk_clist_set_row_data_full(GTK_CLIST(session->cid_list), cidline, + cid_row_new(), cid_row_destroy); + gtk_clist_set_pixtext(GTK_CLIST(session->cid_list), + cidline, CID_COL_TYPE, type, 50, pixmap, bitmap); + session->cid_num++; + } + free(cache); + cache = linearr[CID_COL_TIME]; + free(linearr[CID_COL_DURATION]); + } + free(cache); + + cid_normalize(session); + + if (fclose(f)) + fprintf(stderr, "Error closing %s.\n", calls_filename); + } else { /* error on fopen() */ + fprintf(stderr, + "Warning: Couldn't open isdnlog calls logfile. Proceeding without it.\n"); + } + free(line); +} + +/* + * - marks caller id row as unanswered + * - sets window title to reflect number of unanswered calls + * + * input: session + * row number of specified row + * state 1 for mark, 0 for unmark + */ +void cid_mark_row(session_t *session, int row, int state) { + struct cid_row_t *rowdata = (struct cid_row_t *) gtk_clist_get_row_data( + GTK_CLIST(session->cid_list), row); + GdkColor color; + char *title; + + if (rowdata->marked_unanswered != state) { + if (state) { + gdk_color_parse("#FF8888", &color); + session->unanswered++; + rowdata->marked_unanswered = 1; + } else { + gdk_color_parse("#FFFFFF", &color); + session->unanswered--; + rowdata->marked_unanswered = 0; + } + gtk_clist_set_background(GTK_CLIST(session->cid_list), row, &color); + if (session->unanswered + && 0 < asprintf(&title, _("ANT: %d unanswered"), session->unanswered)) { + gtk_window_set_title(GTK_WINDOW(session->main_window), title); + free(title); + } else { + gtk_window_set_title(GTK_WINDOW(session->main_window), "ANT " VERSION); + } + } +} + +/* + * returns timestring with just digits + * - caller has got to free() the result + */ +char* cid_purify_timestring(char *s) { + char* t; + int length = 0; + char* result; + char* result_index; + + for (t=s; *t; t++) { + if (isdigit (*t)) + length++; + } + + result_index = result = (char*) malloc (length + 1); + + for (t=s; *t; t++) { + if (isdigit (*t)) { + *(result_index++) = *t; + } + } + *(result_index++) = '\0'; + + return result; +} + +/* + * returns name of sound filename, if it exists; NULL otherwise + * - caller has go to free() result + */ +char* cid_get_record_filename(session_t* session, int row) { + char* timestr; + char* homedir; + char* pattern; + glob_t g; + char* result; /* found something */ + + gtk_clist_get_text(GTK_CLIST(session->cid_list), row, CID_COL_TIME, ×tr); + timestr = cid_purify_timestring(timestr); + + if (!(homedir = get_homedir())) { + fprintf(stderr, "Warning: Couldn't get home dir.\n"); + return NULL; + } + + if (asprintf(&pattern, "%s/." PACKAGE "/recordings/%s.*", + homedir, timestr) < 0) { + fprintf(stderr, "Warning: " + "Couldn't allocate memory for filename globbing pattern.\n"); + return NULL; + } + + switch (glob(pattern, 0, NULL, &g)) { + case 0: + result = strdup(*(g.gl_pathv)); + break; + case GLOB_NOMATCH: + result = NULL; + break; + default: + fprintf(stderr, "Warning: " + "globbing error while looking up recorded conversation.\n"); + return NULL; + } + + globfree(&g); + free(pattern); + free(timestr); + + return result; +} + +/* + * marks row with record sign if recording available + * - deletes mark if recording was removed before + */ +void cid_row_mark_record(session_t* session, int row) { + char* fn; + + if ((fn = cid_get_record_filename(session, row))) { + gtk_clist_set_pixmap(GTK_CLIST(session->cid_list), row, CID_COL_FLAGS, + session->symbol_record_pixmap, session->symbol_record_bitmap); + free(fn); + } else { + gtk_clist_set_text(GTK_CLIST(session->cid_list), row, CID_COL_FLAGS, ""); + } + +} + diff --git a/src/callerid.h b/src/callerid.h new file mode 100644 index 0000000..9eb864f --- /dev/null +++ b/src/callerid.h @@ -0,0 +1,72 @@ +/* + * caller id related functions + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* GTK */ +#include + +/* own header files */ +#include "session.h" + +enum call_type_t { + CALL_IN, + CALL_OUT +}; + +/* + * (Sequential) positions of columns (order) + */ +enum cid_col_t { + CID_COL_FLAGS, + CID_COL_TIME, + CID_COL_TYPE, + CID_COL_FROM, + CID_COL_TO, + CID_COL_DURATION, + /*XXX, "Zone" */ + + CID_COL_NUMBER /* for calculating size */ +}; + +/* + * _additional_ (invisible) data associated with a row + */ +struct cid_row_t { + int marked_unanswered; +}; + +void cid_toggle_cb(GtkWidget *widget, gpointer data, guint action); +GtkWidget *cid_new(session_t *session); +void cid_add_line(session_t *session, + enum call_type_t ct, gchar *from, gchar *to); +void cid_set_date(session_t *session, time_t date); +void cid_set_from(session_t *session, gchar *from); +void cid_set_duration(session_t *session, gchar *message); +void cid_jump_to_end(session_t *session); +void cid_normalize(session_t *session); +void cid_add_saved_line(session_t *session, char *date, char *type, + char *from, char *to, char *duration); +void cid_calls_merge(session_t *session); +void cid_mark_row(session_t *session, int row, int state); +char* cid_get_record_filename(session_t* session, int row); +void cid_row_mark_record(session_t* session, int row); + diff --git a/src/calleridlexer.l b/src/calleridlexer.l new file mode 100644 index 0000000..6774a2e --- /dev/null +++ b/src/calleridlexer.l @@ -0,0 +1,92 @@ +%option prefix="callerid_" +%option nounput +%{ +/* + * saved caller id file lexer + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define YYSTYPE char * + +#include +#include "globals.h" +#include "calleridparser.h" +YYLTYPE callerid_lloc; + +void callerid_locate(); +%} + +LETTER [a-zA-Z] +DIGIT [0-9] +NOEM {LETTER}|{DIGIT}|[-:)(*#] + +%% + +"|"|!! callerid_locate(); return CID_TOKEN_DELIMITER; +{DIGIT}+-{DIGIT}+-{DIGIT}+" "{DIGIT}+:{DIGIT}+:{DIGIT}+ { + callerid_locate(); + callerid_lval = strdup(callerid_text); + return CID_TOKEN_DATE; + } +IN|OUT { + callerid_locate(); + callerid_lval = strdup(callerid_text); + return CID_TOKEN_TYPE; + } +({DIGIT}|[*#+?A-D])+ { + callerid_locate(); + callerid_lval = strdup(callerid_text); + return CID_TOKEN_NUMBER; + } +(!?{NOEM}+)+!? { + callerid_locate(); + callerid_lval = strdup(callerid_text); + return CID_TOKEN_MSG; + } + +\n callerid_locate(); return *callerid_text; +. callerid_locate(); + /* eat up rest (handled as white space) */ + +%% + +/* For portability's sake */ +int callerid_wrap() { return 1; } + +/* + * adjusts callerid_lloc according to callerid_text + */ +void callerid_locate() { + char* temp; + + callerid_lloc.first_line = callerid_lloc.last_line; + callerid_lloc.first_column = callerid_lloc.last_column; + + for (temp = yytext; *temp != '\0'; temp++) { + if (*temp == '\n') { + ++ callerid_lloc.last_line; + callerid_lloc.last_column = 1; + } else { + ++ callerid_lloc.last_column; + } + } +} + diff --git a/src/calleridparser.y b/src/calleridparser.y new file mode 100644 index 0000000..cf3c2d9 --- /dev/null +++ b/src/calleridparser.y @@ -0,0 +1,86 @@ +%name-prefix="callerid_" +%{ +/* + * saved callerid file parser + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* type for semantic values of symbols: malloc'ed strings */ +#define YYSTYPE char* + +/* let yyparse() accept one argument of type void * */ +#define YYPARSE_PARAM session + +/* regular GNU system includes */ +#include +#include + +/* own header files */ +#include "globals.h" +#include "util.h" +#include "callerid.h" + +int callerid_lex (void); +void callerid_error(const char *message); +%} + +/* terminal symbols */ +%token CID_TOKEN_DATE +%token CID_TOKEN_TYPE +%token CID_TOKEN_NUMBER +%token CID_TOKEN_MSG +%token CID_TOKEN_DELIMITER + +%% +settings : + | settings line +; + +line : '\n' + | CID_TOKEN_DATE CID_TOKEN_DELIMITER + CID_TOKEN_TYPE CID_TOKEN_DELIMITER + CID_TOKEN_NUMBER CID_TOKEN_DELIMITER + CID_TOKEN_NUMBER CID_TOKEN_DELIMITER + CID_TOKEN_MSG '\n' + { cid_add_saved_line(session, $1, $3, $5, $7, $9); + free($1); free($3); free($5); free($7); free($9); } + | error '\n' + { if (debug) + fprintf(stderr, + "Warning: Parsing callerid history file:%d, " + "recovering after error.\n", @1.last_line); + } +; + +%% + +/* + * callback for yyparse(), (also) called on errors (hopefully) handled + * by error token actions in grammar, but not if errors occur to + * often (bison needs 3 "correct" tokens to recover) + */ +void callerid_error(const char *message) { + if (debug) + fprintf(stderr, + "Warning: Parsing callerid history file line %d: %s.\n", + callerid_lloc.first_line, message); +} + diff --git a/src/client.c b/src/client.c new file mode 100644 index 0000000..3eb6b15 --- /dev/null +++ b/src/client.c @@ -0,0 +1,84 @@ +/* + * client functionality: + * * let a process issue commands (e.g. dial) + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* regular GNU system includes */ +#include +#include +#include +#include +#include +#include +#include + +/* own header files */ +#include "globals.h" +#include "client.h" +#include "server.h" +#include "util.h" + +/* + * (try to) connect to server and issue call command + * + * returns 0 on success, -1 otherwise + */ +int client_make_call(char *number) { + int sock; + struct sockaddr_un local_name; + size_t size; + char *filename; + int bytes; + char *msg; + + sock = socket(PF_LOCAL, SOCK_STREAM, 0); + if (sock < 0) { + perror("client: local socket()"); + return -1; + } + + filename = server_local_socket_name(); + + local_name.sun_family = AF_LOCAL; + strncpy(local_name.sun_path, filename, sizeof(local_name.sun_path)); + size = SUN_LEN(&local_name); + + if (connect(sock, (struct sockaddr *) &local_name, sizeof(local_name)) < 0) { + perror("client: local connect()"); + return -1; + } + + if (asprintf(&msg, "%c%s", LOCAL_MSG_CALL, number) < 0) { + fprintf(stderr, "asprintf error"); + return -1; + } + bytes = write(sock, msg, 1 + strlen(number) + 1); + if (bytes < 0) { + perror("socket write"); + return -1; + } + free(msg); + + close(sock); + free(filename); + return 0; +} diff --git a/src/client.h b/src/client.h new file mode 100644 index 0000000..edf9dee --- /dev/null +++ b/src/client.h @@ -0,0 +1,25 @@ +/* + * client functionality: + * * let a process issue commands (dial) + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +int client_make_call(char *number); diff --git a/src/controlpad.c b/src/controlpad.c new file mode 100644 index 0000000..2f1d650 --- /dev/null +++ b/src/controlpad.c @@ -0,0 +1,490 @@ +/* + * The key pad + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* regular GNU system includes */ +#include +#include +#include + +/* GTK */ +#include + +/* own header files */ +#include "globals.h" +#include "session.h" +#include "isdn.h" +#include "util.h" +#include "callerid.h" + +/* graphical symbols */ +#include "backspace.xpm" +#include "redial.xpm" +#include "mute.xpm" + + +/* + * called on preset edit confirmation (OK button) + * -> sets new preset values (name, number) and destroys window + * + * input: widget = the OK button, set data: + * "entry_name" - the entry with the new preset name + * "entry_number" - the entry with the new preset number + * "button" - the preset button + * "number" - the preset button number + * "window" - the window to destroy after setting values + * data = the session + */ +static void controlpad_preset_edit_ok(GtkWidget *widget, gpointer *data) { + session_t *session = (session_t *) data; + GtkWidget *entry_name = gtk_object_get_data(GTK_OBJECT(widget), + "entry_name"); + GtkWidget *entry_number = gtk_object_get_data(GTK_OBJECT(widget), + "entry_number"); + GtkWidget *button = gtk_object_get_data(GTK_OBJECT(widget), "button"); + int n = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(widget), "number")); + + free(session->preset_names[n]); + session->preset_names[n] = strdup(gtk_entry_get_text(GTK_ENTRY(entry_name))); + free(session->preset_numbers[n]); + session->preset_numbers[n] = strdup( + gtk_entry_get_text(GTK_ENTRY(entry_number))); + gtk_label_set_text(GTK_LABEL(GTK_BIN(button)->child), + gtk_entry_get_text(GTK_ENTRY(entry_name))); + + gtk_widget_destroy(gtk_object_get_data(GTK_OBJECT(widget), "window")); +} + +/* + * called on right-click on preset button to configure + * + * input: widget = the preset button + * event = the event (we determine the clicked mouse button from it) + * data = the session + */ +static gint controlpad_preset_edit_cb(GtkWidget *widget, GdkEventButton *event, + gpointer data) { + if (event->button == 3) { + session_t *session = (session_t *) data; + char *buttoncode = (char *)gtk_object_get_data(GTK_OBJECT(widget), "desc"); + int n = strtol(&buttoncode[1], NULL, 0); + GtkWidget *window; + GtkWidget *button_box; + GtkWidget *button; + GtkWidget *label; + GtkWidget *table; + GtkWidget *entry_name; + GtkWidget *entry_number; + char *title; + char *labeltext; + + window = gtk_dialog_new(); + asprintf(&title, _("Preset %c"), buttoncode[1] + 1); + gtk_window_set_title(GTK_WINDOW(window), title); + gtk_window_set_modal(GTK_WINDOW(window), TRUE); + + /* vbox area */ + gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(window)->vbox), 0); + asprintf(&labeltext, + _("Please input new preset data for button %c:"), buttoncode[1] + 1); + label = gtk_label_new(labeltext); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), label, + TRUE, FALSE, 0); + gtk_misc_set_padding(GTK_MISC(label), 10, 10); + gtk_widget_show(label); + + table = gtk_table_new(2, 2, FALSE); + gtk_container_set_border_width(GTK_CONTAINER(table), 10); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), table, + TRUE, FALSE, 0); + gtk_widget_show(table); + + label = gtk_label_new(_("Name:")); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); + gtk_widget_show(label); + label = gtk_label_new(_("Number:")); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); + gtk_widget_show(label); + + entry_name = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(entry_name), session->preset_names[n]); + gtk_table_attach_defaults(GTK_TABLE(table), entry_name, 1, 2, 0, 1); + gtk_widget_show(entry_name); + entry_number = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(entry_number), session->preset_numbers[n]); + gtk_table_attach_defaults(GTK_TABLE(table), entry_number, 1, 2, 1, 2); + gtk_widget_show(entry_number); + + /* action area */ + button_box = gtk_hbutton_box_new(); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->action_area), + button_box); + gtk_widget_show(button_box); + + /* OK button */ + button = gtk_button_new_with_label(_("OK")); + gtk_box_pack_start_defaults(GTK_BOX(button_box), button); + gtk_object_set_data(GTK_OBJECT(button), "entry_name", entry_name); + gtk_object_set_data(GTK_OBJECT(button), "entry_number", entry_number); + gtk_object_set_data(GTK_OBJECT(button), "button", widget); + gtk_object_set_data(GTK_OBJECT(button), "number", GINT_TO_POINTER(n)); + gtk_object_set_data(GTK_OBJECT(button), "window", window); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(controlpad_preset_edit_ok), + session); + gtk_widget_show(button); + + /* cancel button */ + button = gtk_button_new_with_label(_("Cancel")); + gtk_box_pack_start_defaults(GTK_BOX(button_box), button); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT(window)); + gtk_widget_show(button); + gtk_widget_show(window); + + free(labeltext); + free(title); + return TRUE; /* event handled */ + } else { + return FALSE; + } +} + +/* + * called when button in key pad clicked (except mute) + */ +static void controlpad_button_cb(GtkWidget *button, gpointer data) { + session_t *session = (session_t *) data; + char *c = (char *) gtk_object_get_data(GTK_OBJECT(button), "desc"); + char *temp; + + switch (session->state) { + case STATE_READY: /* manipulate dial box */ + if ((*c >= '0' && *c <= '9') || *c == '*' || *c == '#') { /* new char */ + gtk_entry_append_text(GTK_ENTRY(GTK_COMBO(session->dial_number_box) + ->entry), c); + } else if (*c == 'P') { /* preset button */ + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(session->dial_number_box)->entry), + session->preset_numbers[strtol(&c[1], NULL, 0)]); + } else if (*c == 'B') { /* clear one byte (Backspace) */ + temp = strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO( + session->dial_number_box)->entry))); + if (strlen(temp) > 0) { + temp[strlen(temp) - 1] = 0; + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(session->dial_number_box) + ->entry), temp); + } + free(temp); + } else if (*c == 'C') { /* clear entry */ + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(session->dial_number_box) + ->entry), ""); + } else if (*c == 'R') { /* Redial from history */ + do { + temp = g_list_nth_data(session->dial_number_history, + session->dial_number_history_pointer); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(session->dial_number_box) + ->entry), temp); + if (session->dial_number_history_pointer < + session->dial_number_history_maxlen) + session->dial_number_history_pointer++; + if (session->dial_number_history_pointer == + session->dial_number_history_maxlen) + session->dial_number_history_pointer = 0; + } while (*temp == '\0' && session->dial_number_history_pointer != 0); + } + gtk_widget_grab_focus(GTK_WIDGET(GTK_COMBO(session->dial_number_box) + ->entry)); + gtk_entry_set_position(GTK_ENTRY(GTK_COMBO(session->dial_number_box) + ->entry), -1); + break; + case STATE_CONVERSATION: /* touchtones */ + if ((*c >= '0' && *c <= '9') || *c == '*' || *c == '#') { /* new tt */ +#define TOUCHTONE_LENGTH 0.1 + session->touchtone_countdown_isdn = TOUCHTONE_LENGTH * ISDN_SPEED; + session->touchtone_countdown_audio = + TOUCHTONE_LENGTH * session->audio_speed_out; + session->touchtone_index = + *c == '*' ? 9 : *c == '0' ? 10 : *c == '#' ? 11 : *c - '1'; + } + break; + default: /* other states */ + ; + } +} + +/* + * called when mute button in key pad toggled + */ +static void controlpad_mute_cb(GtkWidget *button, gpointer data) { + session_t *session = (session_t *) data; + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) { /* muted */ + session->option_muted = 1; + gtk_widget_show(session->muted_warning); + } else { /* unmuted */ + session->option_muted = 0; + gtk_widget_hide(session->muted_warning); + } +} + +/* + * called when record / local / remote checkbutton has been toggled + */ +static void controlpad_record_cb(GtkWidget *button, gpointer data) { + session_t *session = (session_t *) data; + char *digits = NULL; + + if (button == session->record_checkbutton) { + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) { /* record! */ + session->option_record = 1; + if (session->state == STATE_CONVERSATION) { + if (recording_open(session->recorder, + digits = util_digitstime(&session->vcon_time), + session->option_recording_format)) + { + fprintf(stderr, "Error opening audio file.\n"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( + session->record_checkbutton), FALSE); + return; + } + free(digits); + cid_row_mark_record(session, session->cid_num - 1); + } + } else { /* don't record! */ + session->option_record = 0; + if (session->state == STATE_CONVERSATION) { + recording_write(session->recorder, session->rec_buf_local, + session->rec_buf_local_index, RECORDING_LOCAL); + recording_write(session->recorder, session->rec_buf_remote, + session->rec_buf_remote_index, RECORDING_REMOTE); + recording_close(session->recorder); + session->rec_buf_local_index = 0; + session->rec_buf_remote_index = 0; + } + } + gtk_widget_set_sensitive(session->record_checkbutton_local, + session->option_record); + gtk_widget_set_sensitive(session->record_checkbutton_remote, + session->option_record); + } else if (button == session->record_checkbutton_local) { + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) { + /* record local channel (if recording is selected at all)! */ + session->option_record_local = 1; + } else { /* don't record local channel! */ + session->option_record_local = 0; + } + } else { /* button == session->record_checkbutton_remote */ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) { + /* record remote channel (if recording is selected at all)! */ + session->option_record_remote = 1; + } else { /* don't record remote channel! */ + session->option_record_remote = 0; + } + } +} + +/* + * The key pad etc. + */ +GtkWidget *controlpad_new(session_t *session) { + char *labels[4][5] = {{"1", "2", "3", "B", session->preset_names[0]}, + {"4", "5", "6", "C", session->preset_names[1]}, + {"7", "8", "9", "R", session->preset_names[2]}, + {"*", "0", "#", "M", session->preset_names[3]}}; + char *tips[4][5] = { + {",-./", "abc", "def", N_("Backspace"), N_("Preset 1")}, + {"ghi", "jkl", "mno", N_("Clear Number"), N_("Preset 2")}, + {"pqrs", "tuv", "wxyz", N_("Redial"), N_("Preset 3")}, + {"", "0...9", "", N_("Mute Microphone"), N_("Preset 4")}}; + char *presetcodes[4] = {"P0", "P1", "P2", "P3"}; + + GtkWidget *frame; + GtkWidget *hbox; + GtkWidget *table; + GtkWidget *button; + + GtkWidget *recordframe; + GtkWidget *recordbox; + GtkWidget *record_checkbutton; + GtkWidget *record_checkbutton_local; + GtkWidget *record_checkbutton_remote; + + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkStyle *style; + GtkWidget *pixmapwid; + + GtkTooltips *tooltips; + + int i, j; + + tooltips = gtk_tooltips_new(); + /* tooltips are often grey by default and have to be set up with a gtkrc + file: + + style "gtk-tooltips-style" { + bg[NORMAL] = "#ffffc0" + } + widget "gtk-tooltips" style "gtk-tooltips-style" + */ + + frame = gtk_frame_new(_("Control")); + gtk_container_set_border_width(GTK_CONTAINER(frame), 8); + + hbox = gtk_hbox_new(FALSE, 15); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); + gtk_container_add(GTK_CONTAINER(frame), hbox); + gtk_widget_show(hbox); + + table = gtk_table_new(4, 3, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 5); + gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, FALSE, 5); + gtk_widget_show(table); + + for (i = 0; i < 5; i++) { /* columns */ + for (j = 0; j < 4; j++) { /* rows */ + if (i == 3 && j == 3) { /* mute */ + button = gtk_toggle_button_new(); + style = gtk_widget_get_style(session->main_window); + pixmap = gdk_pixmap_create_from_xpm_d(session->main_window->window, + &mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) mute_xpm); + pixmapwid = gtk_pixmap_new(pixmap, mask); + gtk_container_add(GTK_CONTAINER(button), pixmapwid); + gtk_widget_show(pixmapwid); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), + session->option_muted); + session->mute_button = button; + gtk_signal_connect(GTK_OBJECT(button), "toggled", + GTK_SIGNAL_FUNC(controlpad_mute_cb), session); + } else { /* everything else (except mute) */ + if (i == 3 && j == 0) { /* backspace icon */ + button = gtk_button_new(); + style = gtk_widget_get_style(session->main_window); + pixmap = gdk_pixmap_create_from_xpm_d(session->main_window->window, + &mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) backspace_xpm); + pixmapwid = gtk_pixmap_new(pixmap, mask); + gtk_container_add(GTK_CONTAINER(button), pixmapwid); + gtk_widget_show(pixmapwid); + } else if (i == 3 && j == 2) { /* redial icon */ + button = gtk_button_new(); + style = gtk_widget_get_style(session->main_window); + pixmap = gdk_pixmap_create_from_xpm_d(session->main_window->window, + &mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) redial_xpm); + pixmapwid = gtk_pixmap_new(pixmap, mask); + gtk_container_add(GTK_CONTAINER(button), pixmapwid); + gtk_widget_show(pixmapwid); + } else { /* icon with letter (or description) */ + button = gtk_button_new_with_label(labels[j][i]); + gtk_signal_connect(GTK_OBJECT(button), "button-press-event", + GTK_SIGNAL_FUNC(controlpad_preset_edit_cb), + session); + } + /* connect callback to widget */ + gtk_object_set_data(GTK_OBJECT(button), "desc", + i < 4 ? labels[j][i] : presetcodes[j]); + gtk_signal_connect(GTK_OBJECT(button), "pressed", + GTK_SIGNAL_FUNC(controlpad_button_cb), session); + } + if (*tips[j][i]) + gtk_tooltips_set_tip(tooltips, button, _(tips[j][i]), NULL); + gtk_table_attach_defaults(GTK_TABLE(table), button, i, i + 1, j, j + 1); + gtk_widget_set_size_request(button, i < 3 ? 30 : i == 3 ? 20 : 100, -1); + gtk_widget_show(button); + } + gtk_table_set_col_spacing(GTK_TABLE(table), i, i < 2 ? 5 : 15); + } + + recordframe = gtk_frame_new(_("Recording")); + gtk_box_pack_start(GTK_BOX(hbox), recordframe, TRUE, FALSE, 5); + gtk_widget_show(recordframe); + + recordbox = gtk_table_new(2, 3, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(recordbox), 0); + gtk_table_set_col_spacings(GTK_TABLE(recordbox), 20); + gtk_container_add(GTK_CONTAINER(recordframe), recordbox); + gtk_widget_show(recordbox); + + record_checkbutton = + gtk_check_button_new_with_label(_("Record to file")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(record_checkbutton), + session->option_record); + gtk_table_attach(GTK_TABLE(recordbox), record_checkbutton, + 0, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0); + gtk_widget_show(record_checkbutton); + gtk_signal_connect(GTK_OBJECT(record_checkbutton), "toggled", + GTK_SIGNAL_FUNC(controlpad_record_cb), session); + session->record_checkbutton = record_checkbutton; + + record_checkbutton_local = + gtk_check_button_new_with_label(_("Record local channel")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(record_checkbutton_local), + session->option_record_local); + gtk_table_attach(GTK_TABLE(recordbox), record_checkbutton_local, + 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0); + gtk_widget_show(record_checkbutton_local); + gtk_signal_connect(GTK_OBJECT(record_checkbutton_local), "toggled", + GTK_SIGNAL_FUNC(controlpad_record_cb), session); + session->record_checkbutton_local = record_checkbutton_local; + + record_checkbutton_remote = + gtk_check_button_new_with_label(_("Record remote channel")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(record_checkbutton_remote), + session->option_record_remote); + gtk_table_attach(GTK_TABLE(recordbox), record_checkbutton_remote, + 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, 0, 0, 0); + gtk_widget_show(record_checkbutton_remote); + gtk_signal_connect(GTK_OBJECT(record_checkbutton_remote), "toggled", + GTK_SIGNAL_FUNC(controlpad_record_cb), session); + session->record_checkbutton_remote = record_checkbutton_remote; + + if (!session->option_record) { + gtk_widget_set_sensitive(record_checkbutton_local, FALSE); + gtk_widget_set_sensitive(record_checkbutton_remote, FALSE); + } + + return frame; +} + +/* called when control pad state check button is toggled */ +void controlpad_toggle_cb(GtkWidget *widget _U_, + gpointer data, guint action _U_) { + session_t *session = (session_t *) data; + + if (GTK_CHECK_MENU_ITEM (session->controlpad_check_menu_item)->active) { + gtk_widget_show(session->controlpad); + session->option_show_controlpad = 1; + } else { + gtk_widget_hide(session->controlpad); + session->option_show_controlpad = 0; + /* shrink if no growing callerid monitor present */ + if (!session->option_show_callerid) + gtk_window_resize(GTK_WINDOW(session->main_window), 1, 1); + } +} + diff --git a/src/controlpad.h b/src/controlpad.h new file mode 100644 index 0000000..b2a702c --- /dev/null +++ b/src/controlpad.h @@ -0,0 +1,29 @@ +/* + * The key pad + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* GTK */ +#include + +GtkWidget *controlpad_new(session_t *session); +void controlpad_toggle_cb(GtkWidget *widget _U_, + gpointer data, guint action _U_); diff --git a/src/fxgenerator.c b/src/fxgenerator.c new file mode 100644 index 0000000..65cd68b --- /dev/null +++ b/src/fxgenerator.c @@ -0,0 +1,145 @@ +/* + * The sound effects generator + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* regular GNU system includes */ +#include +#include + +/* own header files */ +#include "globals.h" +#include "session.h" + +/* all time constants in seconds or Hz */ +#define RING_PERIOD 4 +#define RING_LENGTH 1.3 +#define RING_FREQUENCY 1300 +/* fade in/out reciprocal period: */ +#define RING_FADE_LENGTH 0.003 +#define RING_SHORT_PERIOD 0.044 +#define RING_SHORT_LENGTH (RING_SHORT_PERIOD / 2) +#define RINGING_FREQUENCY 425 + +/* + * Effect generator + * input: session: session, used element: audio_LUT_generate + * effect: the effect + * index: parameter for effect (e.g. which touchtone) + * EFFECT_TOUCHTONE: row * 3 + column (each 0-based) + * seconds: position of sample in seconds + * returns: generated ulaw sample + */ +unsigned char fxgenerate(session_t *session, enum effect_t effect, + int index, double seconds) { + unsigned char x; /* generated ulaw sample (return value) */ + double rest; /* monitor the period in seconds modulo 4 */ + double rest2; /* monitor (short) sinus period */ + double factor; /* envelope factor */ + double factor2; /* envelope help factor (short periods) */ + double f1, f2; /* frequencies for touchtones (row, column) */ + + switch(effect) { + case EFFECT_RING: /* somebody's calling */ + case EFFECT_TEST: /* play test sound */ + + if (effect == EFFECT_RING) { + rest = fmod(seconds, RING_PERIOD); /* 4 sec period */ + } else { + rest = seconds; /* infinite period */ + } + + rest2 = fmod(seconds, RING_SHORT_PERIOD); /* short period */ + + if (rest < RING_FADE_LENGTH) { /* fade in */ + factor = -cos(rest * M_PI / RING_FADE_LENGTH) / 2 + 0.5; + } else if (rest > RING_LENGTH - RING_FADE_LENGTH && + rest < RING_LENGTH) { /* fade out */ + factor = -cos((RING_LENGTH - rest) * 2 * M_PI / (RING_FADE_LENGTH * 2)) + / 2 + 0.5; + + } else if (rest >= RING_LENGTH) { /* pause */ + factor = 0; + } else { /* (potential) beep */ + factor = 1; + } + + if (rest2 > RING_SHORT_PERIOD - 0.5 * RING_FADE_LENGTH) { + /* fade in short period (1/2) */ + factor2 = -sin((RING_SHORT_PERIOD - rest2) + * 2 * M_PI / (RING_FADE_LENGTH * 2)) / 2 + 0.5; + } else if (rest2 < 0.5 * RING_FADE_LENGTH) { + /* fade in short period (2/2) */ + factor2 = sin(rest2 * 2 * M_PI / (RING_FADE_LENGTH * 2)) / 2 + 0.5; + } else if (rest2 > RING_SHORT_LENGTH - 0.5 * RING_FADE_LENGTH && + rest2 < RING_SHORT_LENGTH + 0.5 * RING_FADE_LENGTH) { + /* fade out short period */ + factor2 = -sin((rest2 - RING_SHORT_LENGTH) + * 2 * M_PI / (RING_FADE_LENGTH * 2)) / 2 + 0.5; + + } else if (rest2 <= RING_SHORT_LENGTH) { /* just beep */ + factor2 = 1; + } else { + factor2 = 0; /* short pause */ + } + + factor = factor * factor2; + + x = session->audio_LUT_generate[ + (int)(sin(seconds * 2 * M_PI * RING_FREQUENCY) + * factor * 127.5 + 127.5)]; + break; + + case EFFECT_RINGING: /* waiting for the other end to pick up the phone */ + rest = fmod(seconds, 5); + if (rest >= 2 && rest < 3) { + x = session->audio_LUT_generate[ /* beep */ + (int)(sin(seconds * 2 * M_PI * RINGING_FREQUENCY) * 127.5 + 127.5)]; + } else { + x = session->audio_LUT_generate[128]; /* pause */ + } + break; + case EFFECT_TOUCHTONE: /* clicked key pad in conversation mode */ + switch (index / 3) { /* row frequency */ + case 0: f1 = 697; break; + case 1: f1 = 770; break; + case 2: f1 = 852; break; + case 3: f1 = 941; break; + default: f1 = 0; + } + switch (index % 3) { /* column frequency */ + case 0: f2 = 1209; break; + case 1: f2 = 1336; break; + case 2: f2 = 1477; break; + case 3: f2 = 1633; break; + default: f2 = 0; + } + x = session->audio_LUT_generate[ + (int)((sin(seconds * 2 * M_PI * f1) + sin(seconds * 2 * M_PI * f2)) + / 2 * 127.5 * 0.7 + 127.5)]; + break; + default: + fprintf(stderr, "fxgenerate: Unknown effect.\n"); + x = 0; + } + + return x; +} diff --git a/src/fxgenerator.h b/src/fxgenerator.h new file mode 100644 index 0000000..75308ea --- /dev/null +++ b/src/fxgenerator.h @@ -0,0 +1,28 @@ +/* + * The sound effects generator + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* own header files */ +#include "session.h" + +unsigned char fxgenerate(session_t *session, enum effect_t, int index, + double seconds); diff --git a/src/g711.c b/src/g711.c new file mode 100644 index 0000000..d4e54b1 --- /dev/null +++ b/src/g711.c @@ -0,0 +1,281 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +#include "config.h" + +/* + * g711.c + * + * u-law, A-law and linear PCM conversions. + */ +#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ +#define QUANT_MASK (0xf) /* Quantization field mask. */ +#define NSEGS (8) /* Number of A-law segments. */ +#define SEG_SHIFT (4) /* Left shift for segment number. */ +#define SEG_MASK (0x70) /* Segment field mask. */ + +/* copy from CCITT G.711 specifications */ +unsigned char _u2a[128] = { /* u- to A-law conversions */ + 1, 1, 2, 2, 3, 3, 4, 4, + 5, 5, 6, 6, 7, 7, 8, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 27, 29, 31, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, + 46, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128}; + +unsigned char _a2u[128] = { /* A- to u-law conversions */ + 1, 3, 5, 7, 9, 11, 13, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 32, 33, 33, 34, 34, 35, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 48, 49, 49, + 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 64, + 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}; + +/* see libst.h */ +/*#ifdef SUPERCEDED*/ + +static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF, + 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF}; + +static int +search(int val, short *table, int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (val <= *table++) + return (i); + } + return (size); +} + +/* + * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law + * + * linear2alaw() accepts an 16-bit integer and encodes it as A-law data. + * + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +unsigned char +linear2alaw(int pcm_val) /* 2's complement (16-bit range) */ +{ + int mask; + int seg; + unsigned char aval; + + if (pcm_val >= 0) { + mask = 0xD5; /* sign (7th) bit = 1 */ + } else { + mask = 0x55; /* sign bit = 0 */ + pcm_val = -pcm_val - 8; + } + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_end, 8); + + /* Combine the sign, segment, and quantization bits. */ + + if (seg >= 8) /* out of range, return maximum value. */ + return (0x7F ^ mask); + else { + aval = seg << SEG_SHIFT; + if (seg < 2) + aval |= (pcm_val >> 4) & QUANT_MASK; + else + aval |= (pcm_val >> (seg + 3)) & QUANT_MASK; + return (aval ^ mask); + } +} + +/* + * alaw2linear() - Convert an A-law value to 16-bit linear PCM + * + */ +int +alaw2linear(unsigned char a_val) +{ + int t; + int seg; + + a_val ^= 0x55; + + t = (a_val & QUANT_MASK) << 4; + seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; + switch (seg) { + case 0: + t += 8; + break; + case 1: + t += 0x108; + break; + default: + t += 0x108; + t <<= seg - 1; + } + return ((a_val & SIGN_BIT) ? t : -t); +} + +#define BIAS (0x84) /* Bias for linear code. */ + +/* + * linear2ulaw() - Convert a linear PCM value to u-law + * + * In order to simplify the encoding process, the original linear magnitude + * is biased by adding 33 which shifts the encoding range from (0 - 8158) to + * (33 - 8191). The result can be seen in the following encoding table: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +unsigned char +linear2ulaw(int pcm_val) /* 2's complement (16-bit range) */ +{ + int mask; + int seg; + unsigned char uval; + + /* Get the sign and the magnitude of the value. */ + if (pcm_val < 0) { + pcm_val = BIAS - pcm_val; + mask = 0x7F; + } else { + pcm_val += BIAS; + mask = 0xFF; + } + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_end, 8); + + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + if (seg >= 8) /* out of range, return maximum value. */ + return (0x7F ^ mask); + else { + uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF); + return (uval ^ mask); + } + +} + +/* + * ulaw2linear() - Convert a u-law value to 16-bit linear PCM + * + * First, a biased linear code is derived from the code word. An unbiased + * output can then be obtained by subtracting 33 from the biased code. + * + * Note that this function expects to be passed the complement of the + * original code word. This is in keeping with ISDN conventions. + */ +int +ulaw2linear(unsigned char u_val) +{ + int t; + + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; + + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & QUANT_MASK) << 3) + BIAS; + t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; + + return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); +} + +/*#endif*/ + +/* A-law to u-law conversion */ +unsigned char +alaw2ulaw(unsigned char aval) +{ + aval &= 0xff; + return ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) : + (0x7F ^ _a2u[aval ^ 0x55])); +} + +/* u-law to A-law conversion */ +unsigned char +ulaw2alaw(unsigned char uval) +{ + uval &= 0xff; + return ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) : + (0x55 ^ (_u2a[0x7F ^ uval] - 1))); +} diff --git a/src/g711.h b/src/g711.h new file mode 100644 index 0000000..84e6c79 --- /dev/null +++ b/src/g711.h @@ -0,0 +1,32 @@ +/* + * G.711 conversion function header file + * (adjusted for g711.c from SoX) + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +unsigned char linear2alaw(int pcm_val); /* 2's complement (16-bit range) */ +int alaw2linear(unsigned char a_val); + +unsigned char linear2ulaw(int pcm_val); /* 2's complement (16-bit range) */ +int ulaw2linear(unsigned char u_val); + +unsigned char alaw2ulaw(unsigned char aval); +unsigned char ulaw2alaw(unsigned char uval); diff --git a/src/globals.h b/src/globals.h new file mode 100644 index 0000000..6f04395 --- /dev/null +++ b/src/globals.h @@ -0,0 +1,37 @@ +/* + * Global definitions to be included in ALL source files + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ANT_GLOBALS_H +#define _ANT_GLOBALS_H + +#include "config.h" + +/* GNU gettext introduction */ +#include +#include "gettext.h" +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +extern int debug; + +#endif /* globals.h */ diff --git a/src/gtk.c b/src/gtk.c new file mode 100644 index 0000000..df2eee3 --- /dev/null +++ b/src/gtk.c @@ -0,0 +1,842 @@ +/* + * gtk GUI functions + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "config.h" + +/* regular GNU system includes */ +#include +#include +#ifdef HAVE_STDLIB_H + #include +#endif +#include +#include + +/* GTK */ +#include +#include + +/* own header files */ +#include "globals.h" +#include "gtk.h" +#include "session.h" +#include "isdn.h" +#include "util.h" +#include "sound.h" +#include "callerid.h" +#include "llcheck.h" +#include "settings.h" +#include "gtksettings.h" +#include "controlpad.h" + +/* graphical symbols */ +#include "hangup.xpm" +#include "pickup.xpm" +#include "aboutlogo.xpm" +/* +#include "icon16x16.xpm" +#include "icon32x32.xpm" +*/ +#include "icon48x48.xpm" +/* +#include "icon64x64.xpm" +*/ + +/* call timeout_callback each of milliseconds */ +#define TIMER_DELAY 300 + +volatile int interrupted = 0; /* the caught signal will be stored here */ + +/* + * the quit (e.g. menu entry) callback + * prototype is this way to standardize to GtkItemFactoryCallback2 + * + * this function will always be called when gtk is to finish + * + * input: data: session + */ +static void quit(GtkWidget *widget _U_, gpointer data, guint action _U_) { + session_t *session = (session_t *) data; + + settings_history_write(session); /* write history */ + settings_callerid_write(session); /* write callerid history */ + + gtk_handle_hang_up_button(NULL, data); /* simulate hang_up_button */ + + /* some (GUI) de-initialization, not directly session related */ + llcheck_bar_deinit(session->llcheck_in); + llcheck_bar_deinit(session->llcheck_out); + + gtk_main_quit(); +} + +/* + * main window delete_event callback + * + * input: data: session + */ +gint delete_event(GtkWidget *widget, + GdkEvent *event _U_, + gpointer data) +{ + quit(widget, data, 0); + return FALSE; /* continue event handling */ +} + +/* handler for SIGTERM and SIGINT */ +void terminate_signal_callback(int sig) { + interrupted = sig; +} + +/* + * periodically (e.g. each 300 milliseconds) from gtk main loop called function + */ +gint timeout_callback(gpointer data) { + session_t *session = (session_t *) data; + + if (interrupted) { + switch(interrupted) { + case SIGINT: + if (debug) + fprintf(stderr, "Ctrl-C caught.\n"); + break; + case SIGTERM: + if (debug) + fprintf(stderr, "SIGTERM caught.\n"); + break; + default: + fprintf(stderr, "Warning: Unknown signal caught.\n"); + } + quit(NULL, data, 0); + } + + if (session->state == STATE_CONVERSATION) { + char *timediff = timediff_str(time(NULL), session->vcon_time); + char *buf; + + if (0 > asprintf(&buf, "%s %s", + state_data[session->state].status_bar, timediff)) + fprintf(stderr, "Warning: timeout_callback: asprintf error.\n"); + + gtk_statusbar_pop(GTK_STATUSBAR(session->status_bar), + session->phone_context_id); + gtk_statusbar_push(GTK_STATUSBAR(session->status_bar), + session->phone_context_id, + buf); + free(buf); + free(timediff); + } + + if (session->state == STATE_PLAYBACK) { + char *timediff = timediff_str(time(NULL), + session->effect_playback_start_time); + char *buf; + + if (0 > asprintf(&buf, "%s %s", + state_data[session->state].status_bar, timediff)) + fprintf(stderr, "Warning: timeout_callback: asprintf error.\n"); + + gtk_statusbar_pop(GTK_STATUSBAR(session->status_bar), + session->phone_context_id); + gtk_statusbar_push(GTK_STATUSBAR(session->status_bar), + session->phone_context_id, + buf); + free(buf); + free(timediff); + } + + return TRUE; /* call it again */ +} + + +/* + * some GUI tools + */ + +/* + * return a dialog window with a (big) label and an ok button to close + * (good for displaying a note) + * + * justification: justification of label (e.g. GTK_JUSTIFY_LEFT) + * + * NOTE: caller has to show the window itself with gtk_widget_show() + * and maybe want to make it modal with + * gtk_window_set_modal(GTK_WINDOW(window), TRUE); + */ +GtkWidget *ok_dialog_get(char *title, char *contents, + GtkJustification justification) { + GtkWidget *window; + GtkWidget *button_box; + GtkWidget *button; + GtkWidget *label; + + window = gtk_dialog_new(); + gtk_window_set_title(GTK_WINDOW(window), title); + + /* vbox area */ + gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(window)->vbox), 0); + label = gtk_label_new(contents); + gtk_label_set_justify(GTK_LABEL(label), justification); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), label, + TRUE, FALSE, 0); + gtk_misc_set_padding(GTK_MISC(label), 10, 10); + gtk_widget_show(label); + + /* action area */ + button_box = gtk_hbutton_box_new(); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->action_area), + button_box); + gtk_widget_show(button_box); + + /* OK button */ + button = gtk_button_new_with_label(_("OK")); + gtk_box_pack_start_defaults(GTK_BOX(button_box), button); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT(window)); + gtk_widget_show(button); + + /* caller has to show the window itself */ + + return window; +} + +/* + * shortcut to display a note about audio devices not available + */ +void show_audio_error_dialog(void) { + GtkWidget *dialog; + + dialog = ok_dialog_get(_("ANT Note"), + _("Can't open audio device.\n" + "Please stop other applications using\n" + "the audio device(s) or check your\n" + "device settings and try again."), + GTK_JUSTIFY_CENTER); + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + gtk_widget_show(dialog); +} + +/********************** + * some GUI callbacks * + **********************/ + +/* + * File Menu entries + */ + +struct info_row_t { + gchar *tag; + gchar *value; +}; + +/* Info window */ +static void cb_info_window(GtkWidget *widget _U_, gpointer data, + guint action _U_) { + session_t *session = (session_t *) data; + int inactive = session->option_release_devices && + (session->state == STATE_READY || session->state == STATE_RINGING_QUIET); + struct info_row_t rows[] = { + { N_("Sound input device:"), strdup(session->audio_device_name_in)}, + { N_("Input speed:"), inactive ? strdup(_("[inactive]")) : + ltostr(session->audio_speed_in) }, + { N_("Input sample size (bits):"), inactive ? + strdup(_("[inactive]")) : ltostr(session->audio_sample_size_in * 8)}, + { N_("Input fragment size (samples):"), inactive ? strdup(_("[inactive]")) : + ltostr(session->fragment_size_in / session->audio_sample_size_in)}, + { N_("Input channels:"), inactive ? strdup(_("[inactive]")) : ltostr(1) }, + { "", strdup("") }, + + { N_("Sound output device:"), strdup(session->audio_device_name_out)}, + { N_("Output speed:"), inactive ? strdup(_("[inactive]")) : + ltostr(session->audio_speed_out) }, + { N_("Output sample size (bits):"), inactive ? + strdup(_("[inactive]")) : ltostr(session->audio_sample_size_out*8)}, + { N_("Input fragment size (samples):"), inactive ? strdup(_("[inactive]")) : + ltostr(session->fragment_size_out / session->audio_sample_size_out)}, + { N_("Output channels:"), inactive ? strdup(_("[inactive]")) : ltostr(1) }, + { "", strdup("") }, + + { N_("ISDN device:"), strdup(session->isdn_device_name) }, + { N_("ISDN speed (samples):"), ltostr(8000) }, + { N_("ISDN sample size (bits):"), ltostr(8) }, + { N_("ISDN fragment size (bytes):"), ltostr(255) } + }; + unsigned int i; + + GtkWidget *window; /* the window itself, actually a GtkDialog */ + GtkWidget *table; /* for tag->value pairs */ + GtkWidget *label; + GtkWidget *button_box; + GtkWidget *button; + GtkWidget *separator; + + window = gtk_dialog_new(); + gtk_window_set_title(GTK_WINDOW(window), _("ANT Info")); + + /* the info area */ + table = gtk_table_new(sizeof(rows) / sizeof(struct info_row_t), 2, FALSE); + gtk_container_set_border_width(GTK_CONTAINER(table), 10); + gtk_table_set_col_spacings(GTK_TABLE(table), 10); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->vbox), table); + gtk_widget_show(table); + + for (i = 0; i < sizeof(rows) / sizeof(struct info_row_t); i++) { + if (strcmp(rows[i].tag, "")) { /* normal data */ + label = gtk_label_new(_(rows[i].tag)); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, i, i + 1); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_widget_show(label); + + label = gtk_label_new(rows[i].value); + gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, i, i + 1); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_widget_show(label); + } else { /* separator */ + separator = gtk_hseparator_new(); + gtk_table_attach(GTK_TABLE(table), separator, 0, 2, i, i + 1, + GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 5); + gtk_widget_show(separator); + } + + free(rows[i].value); /* free stdrup() mem */ + } + + /* action area */ + button_box = gtk_hbutton_box_new(); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->action_area), + button_box); + gtk_widget_show(button_box); + + button = gtk_button_new_with_label(_("OK")); + gtk_box_pack_start_defaults(GTK_BOX(button_box), button); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT(window)); + gtk_widget_show(button); + + gtk_window_set_modal(GTK_WINDOW(window), TRUE); + + /* show everything */ + gtk_widget_show(window); +} + +/* + * Options menu entries + */ +/* + * Help menu entries + */ + +/* the about menu entry callback */ +static void cb_about(GtkWidget *widget _U_, gpointer data _U_, guint action _U_) { + GtkWidget *window; + GtkWidget *button_box; + GtkWidget *button; + GtkWidget *label; + + GdkPixmap* pixmap; + GdkBitmap* mask; + GtkStyle* style; + GtkWidget* pixmapwidget; + + char *message; + + window = gtk_dialog_new(); + gtk_window_set_title(GTK_WINDOW(window), _("About ANT")); + + /* vbox area */ + gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(window)->vbox), 0); + + gtk_widget_realize(window); + style = gtk_widget_get_style(window); + pixmap = gdk_pixmap_create_from_xpm_d(window->window, + &mask, + NULL, + (gchar**) aboutlogo_xpm); + pixmapwidget = gtk_pixmap_new(pixmap, mask); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), + pixmapwidget, TRUE, TRUE, 0); + gtk_widget_show(pixmapwidget); + + asprintf(&message, _("ANT (ANT is Not a Telephone) Version %s\n" + "Copyright 2002, 2003 Roland Stigge\n\n" + "This is an ISDN telephone application\n" + "written for GNU/Linux and ISDN4Linux for\n" + "communicating via a full duplex soundcard (or\n" + "multiple sound devices if you like) and an\n" + "audio capable ISDN4Linux ISDN device\n\n" + "Contact:\n" + "Roland Stigge, stigge@antcom.de\n" + "http://www.antcom.de/\n" + "Mailing list: ant-phone-devel@nongnu.org"), VERSION); + label = gtk_label_new(message); + free(message); + gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), label, + TRUE, FALSE, 0); + gtk_misc_set_padding(GTK_MISC(label), 10, 10); + gtk_widget_show(label); + + /* action area */ + button_box = gtk_hbutton_box_new(); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->action_area), + button_box); + gtk_widget_show(button_box); + + /* OK button */ + button = gtk_button_new_with_label(_("OK")); + gtk_box_pack_start_defaults(GTK_BOX(button_box), button); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT(window)); + gtk_widget_show(button); + + gtk_widget_show(window); +} + +/* the about menu entry callback */ +static void cb_license(GtkWidget *widget _U_, gpointer data _U_, guint action _U_) { + GtkWidget *window = ok_dialog_get(_("ANT License"), + _("ANT (ANT is Not a Telephone)\n" + "Copyright (C) 2002, 2003 Roland Stigge\n" + "\n" + "This program is free software; you can redistribute it and/or\n" + "modify it under the terms of the GNU General Public License\n" + "as published by the Free Software Foundation; either version 2\n" + "of the License, or (at your option) any later version.\n" + "\n" + "This program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n" + "\n" + "You should have received a copy of the GNU General Public License\n" + "along with this program; if not, write to the Free Software\n" + "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, " + "USA."), GTK_JUSTIFY_CENTER); + + gtk_widget_show(window); +} + +/* + * get the main menu widget + * + * input: window: parent window to integrate accelerators + * returns: the widget yet to pack + * + * NOTE: assumes other parts to be initialized (maybe not shown already) + */ +GtkWidget *get_main_menu(GtkWidget *window, session_t *session) { + /* The main menu structure */ + GtkItemFactoryEntry main_menu_items[] = { +/*path accel. callb. cb par. kind extra */ +{_("/Phon_e"), NULL, NULL, 0, "", NULL}, +{_("/Phone/_Info Window"),NULL, cb_info_window,0, NULL, NULL}, +{_("/Phone/_Line Level Check"), + NULL, llcheck, 0, NULL, NULL}, +{_("/Phone/"), NULL, NULL, 0, "", NULL}, +{_("/Phone/_Quit"), "X", quit, 0, NULL, NULL}, + +{_("/_View"), NULL, NULL, 0, "", NULL}, +{_("/View/_Caller ID Monitor"), + NULL, cid_toggle_cb, 0, "", NULL}, +{_("/View/_Line Level Meters"), + NULL, llcheck_toggle_cb,0, "", NULL}, +{_("/View/Control _Pad"), NULL, controlpad_toggle_cb,0,"", NULL}, + +{_("/_Options"), NULL, NULL, 0, "", NULL}, +{_("/Options/_Settings"), NULL, gtksettings_cb,0, NULL, NULL}, + +{_("/_Help"), NULL, NULL, 0, "",NULL}, +{_("/Help/_About"), NULL, cb_about, 0, NULL, NULL}, +{_("/Help/_License"), NULL, cb_license, 0, NULL, NULL} + /* set to session by ..._create_items_ac -^ */ + }; + + GtkItemFactory *item_factory; + GtkAccelGroup *accel_group; + char* temp; + + gint nmenu_items = sizeof(main_menu_items) / sizeof(main_menu_items[0]); + + accel_group = gtk_accel_group_new(); + item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "
", + accel_group); + gtk_item_factory_create_items_ac(item_factory, nmenu_items, main_menu_items, + session, 2); + gtk_window_add_accel_group(GTK_WINDOW(window), accel_group); + + /* save connection to menu item(s), set defaults */ + session->cid_check_menu_item = gtk_item_factory_get_item(item_factory, + temp = stripchr(_("/View/_Caller ID Monitor"), '_')); + free(temp); + session->llcheck_check_menu_item = gtk_item_factory_get_item(item_factory, + temp = stripchr(_("/View/_Line Level Meters"), '_')); + free(temp); + session->controlpad_check_menu_item = gtk_item_factory_get_item(item_factory, + temp = stripchr(_("/View/Control _Pad"), '_')); + free(temp); + session->menuitem_settings = gtk_item_factory_get_item(item_factory, + temp = stripchr(_("/Options/_Settings"), '_')); + free(temp); + session->menuitem_line_check = gtk_item_factory_get_item(item_factory, + temp = stripchr(_("/Phone/_Line Level Check"), '_')); + free(temp); + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(session->cid_check_menu_item), + session->option_show_callerid); + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(session->llcheck_check_menu_item), + session->option_show_llcheck); + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(session->controlpad_check_menu_item), + session->option_show_controlpad); + + return gtk_item_factory_get_widget(item_factory, "
"); +} + +/* + * called on key pressed in combo box entry + */ +static gint entry_key_cb(GtkWidget *entry, GdkEventKey *event, gpointer data) { + session_t *session = (session_t *) data; + + if (event->keyval == GDK_KP_Enter) { /* catch keyboard keypad Enter */ + gtk_button_clicked(GTK_BUTTON(session->pick_up_button)); + /* the keyboard keypad Enter generates an unneeded character, so + discard it: */ + gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key-press-event"); + return TRUE; /* event handled */ + } else { + return FALSE; + } +} + +/* + * Get the basic dial box with entry and dial / hang up buttons + * sets dial box members in session + * NOTE: caller has to gtk_widget_show it itself + */ +GtkWidget *get_dial_box(session_t *session) { + GtkWidget *frame; + GtkWidget *hbox; + GtkWidget *label; + GtkWidget *label_hbox; + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkStyle *style; + GtkWidget *pixmapwid; + + frame = gtk_frame_new(_("Dialing")); + gtk_container_set_border_width(GTK_CONTAINER(frame), 8); + + /* dial hbox */ + hbox = gtk_hbox_new(FALSE, 10); + gtk_container_add(GTK_CONTAINER(frame), hbox); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 8); + gtk_widget_show(hbox); + + /* dial label */ + label = gtk_label_new(_("Number:")); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_widget_show(label); + + /* dial number combo box */ + session->dial_number_box = gtk_combo_new(); + gtk_combo_set_popdown_strings(GTK_COMBO(session->dial_number_box), + session->dial_number_history); + gtk_combo_set_use_arrows_always(GTK_COMBO(session->dial_number_box), TRUE); + gtk_widget_set_size_request(session->dial_number_box, 180, -1); + gtk_box_pack_start(GTK_BOX(hbox), session->dial_number_box, + TRUE, TRUE, 0); + gtk_widget_show(session->dial_number_box); + gtk_signal_disconnect(GTK_OBJECT(GTK_COMBO(session->dial_number_box)->entry), + GTK_COMBO(session->dial_number_box)->activate_id); + + /* pick up button */ + session->pick_up_button = gtk_button_new(); + gtk_box_pack_start(GTK_BOX(hbox), session->pick_up_button, FALSE, FALSE, 0); + gtk_signal_connect(GTK_OBJECT(session->pick_up_button), "clicked", + GTK_SIGNAL_FUNC(gtk_handle_pick_up_button), + (gpointer) session); + gtk_widget_show(session->pick_up_button); + + /* activate dial button when pressing enter in entry widget */ + gtk_signal_connect_object(GTK_OBJECT(GTK_COMBO(session->dial_number_box) + ->entry), + "activate", + GTK_SIGNAL_FUNC(gtk_button_clicked), + GTK_OBJECT(session->pick_up_button)); + /* handle special keys */ + gtk_signal_connect(GTK_OBJECT(GTK_COMBO(session->dial_number_box)->entry), + "key-press-event", GTK_SIGNAL_FUNC(entry_key_cb), session); + + /* pick up button hbox */ + label_hbox = gtk_hbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(session->pick_up_button), label_hbox); + gtk_widget_show(label_hbox); + + /* pick up button symbol */ + style = gtk_widget_get_style(session->main_window); + pixmap = gdk_pixmap_create_from_xpm_d(session->main_window->window, + &mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) pickup_xpm); + + pixmapwid = gtk_pixmap_new(pixmap, mask); + gtk_box_pack_start(GTK_BOX(label_hbox), pixmapwid, FALSE, FALSE, 2); + gtk_widget_show(pixmapwid); + + /* pick up button label */ + session->pick_up_label = gtk_label_new(NULL); + gtk_box_pack_start(GTK_BOX(label_hbox), session->pick_up_label, + TRUE, FALSE, 16); /* expand but fill up outside label */ + gtk_widget_show(session->pick_up_label); + + /* hang up button */ + session->hang_up_button = gtk_button_new(); + gtk_box_pack_start(GTK_BOX(hbox), session->hang_up_button, FALSE, FALSE, 0); + gtk_signal_connect(GTK_OBJECT(session->hang_up_button), "clicked", + GTK_SIGNAL_FUNC(gtk_handle_hang_up_button), + (gpointer) session); + gtk_widget_show(session->hang_up_button); + + /* pick up button hbox */ + label_hbox = gtk_hbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(session->hang_up_button), + label_hbox); + gtk_widget_show(label_hbox); + + /* pick up button symbol*/ + /* style = gtk_widget_get_style(session->main_window); */ + /* (already done for pickup button) */ + + pixmap = gdk_pixmap_create_from_xpm_d(session->main_window->window, + &mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) hangup_xpm); + + pixmapwid = gtk_pixmap_new(pixmap, mask); + gtk_box_pack_start(GTK_BOX(label_hbox), pixmapwid, FALSE, FALSE, 2); + gtk_widget_show(pixmapwid); + + /* hang up button label */ + session->hang_up_label = gtk_label_new(NULL); + gtk_box_pack_start(GTK_BOX(label_hbox), session->hang_up_label, + TRUE, FALSE, 16); /* expand but fill up outside label */ + gtk_widget_show(session->hang_up_label); + + return frame; +} + +/* + * main function for gtk GUI + * + * returns int to be returned from main() + */ +int main_gtk(session_t *session) { + GList* icon_list = NULL; + + GtkWidget *main_window; + GtkWidget *main_vbox; + GtkWidget *main_menu; + + GtkWidget *dialbox; + GtkWidget *cidbox; + + GtkWidget *dummy_label; /* needed to calculate the length of a text label */ + GtkRequisition requisition; + + GtkRcStyle *rc_style; + GdkColor color; + + /* the main window */ + session->main_window = main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(main_window), "ANT " VERSION); + + /* seems to cause window managers only to use the first one as icon (e.g.FVWM) + icon_list = g_list_append(icon_list, + (gpointer) gdk_pixbuf_new_from_xpm_data((const char**) icon16x16)); + icon_list = g_list_append(icon_list, + (gpointer) gdk_pixbuf_new_from_xpm_data((const char**) icon32x32)); + */ + icon_list = g_list_append(icon_list, + (gpointer) gdk_pixbuf_new_from_xpm_data((const char**) icon48x48)); + /* + icon_list = g_list_append(icon_list, + (gpointer) gdk_pixbuf_new_from_xpm_data((const char**) icon64x64)); + */ + gtk_window_set_icon_list(GTK_WINDOW(session->main_window), icon_list); + + gtk_signal_connect(GTK_OBJECT(main_window), "delete_event", + GTK_SIGNAL_FUNC(delete_event), (gpointer) session); + + gtk_container_set_border_width(GTK_CONTAINER(main_window), 0); + gtk_widget_realize(main_window); + + gtk_object_set(GTK_OBJECT(main_window), "allow_shrink", FALSE, NULL); + gtk_object_set(GTK_OBJECT(main_window), "allow_grow", TRUE, NULL); + + /* set some defaults */ + gtk_hbutton_box_set_spacing_default(16); /* space between buttons */ + gtk_hbutton_box_set_layout_default(GTK_BUTTONBOX_SPREAD); + + /* main vbox */ + main_vbox = gtk_vbox_new(FALSE, 0); /* not homogeneous, spacing = 0 */ + gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 0); + gtk_container_add(GTK_CONTAINER(main_window), main_vbox); + gtk_widget_show(main_vbox); + + /* contents of main vbox (wrong order to let menu depend on others): */ + + /* the dial hbox */ + dialbox = get_dial_box(session); + gtk_widget_show(dialbox); + + /* key pad */ + session->controlpad = controlpad_new(session); /* show later */ + + /* the caller id section */ + cidbox = cid_new(session); /* show later */ + + /* status bar */ + session->status_bar = gtk_statusbar_new(); + gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(session->status_bar), FALSE); + gtk_widget_show(session->status_bar); + session->phone_context_id = + gtk_statusbar_get_context_id(GTK_STATUSBAR(session->status_bar), "phone"); + gtk_statusbar_push(GTK_STATUSBAR(session->status_bar), + session->phone_context_id, ""); + + /* line level check inside status bar */ + session->llcheck = gtk_vbox_new(FALSE, 0); + gtk_box_pack_end(GTK_BOX(session->status_bar), + session->llcheck, FALSE, FALSE, 0); + + session->llcheck_in = + llcheck_bar_new(66, 10, 0, 200, 0); + gtk_box_pack_start(GTK_BOX(session->llcheck), + session->llcheck_in, FALSE, FALSE, 0); + gtk_widget_show(session->llcheck_in); + session->llcheck_out = + llcheck_bar_new(66, 10, 200, 0, 0); + gtk_box_pack_start(GTK_BOX(session->llcheck), + session->llcheck_out, FALSE, FALSE, 0); + gtk_widget_show(session->llcheck_out); + + /* audio warning inside status bar */ + session->audio_warning = gtk_statusbar_new(); + gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(session->audio_warning), + FALSE); + gdk_color_parse("#B00000", &color); + rc_style = gtk_rc_style_new(); + rc_style->fg[GTK_STATE_NORMAL] = color; + rc_style->color_flags[GTK_STATE_NORMAL] |= GTK_RC_FG; + gtk_widget_modify_style(GTK_STATUSBAR(session->audio_warning)->label, + rc_style); + gtk_rc_style_unref(rc_style); + gtk_box_pack_end(GTK_BOX(session->status_bar), + session->audio_warning, FALSE, FALSE, 0); + session->audio_context_id = + gtk_statusbar_get_context_id(GTK_STATUSBAR(session->audio_warning), + "audio"); + gtk_statusbar_push(GTK_STATUSBAR(session->audio_warning), + session->audio_context_id, ""); + /* mute warning inside status bar */ + session->muted_warning = gtk_statusbar_new(); + gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(session->muted_warning), + FALSE); + gdk_color_parse("#008000", &color); + rc_style = gtk_rc_style_new(); + rc_style->fg[GTK_STATE_NORMAL] = color; + rc_style->color_flags[GTK_STATE_NORMAL] |= GTK_RC_FG; + gtk_widget_modify_style(GTK_STATUSBAR(session->muted_warning)->label, + rc_style); + gtk_rc_style_unref(rc_style); + gtk_box_pack_end(GTK_BOX(session->status_bar), + session->muted_warning, FALSE, FALSE, 0); + session->muted_context_id = + gtk_statusbar_get_context_id(GTK_STATUSBAR(session->muted_warning), + "muted"); + gtk_statusbar_push(GTK_STATUSBAR(session->muted_warning), + session->muted_context_id, _("MUTED")); + dummy_label = gtk_label_new(_("MUTED")); + gtk_widget_show(dummy_label); + gtk_widget_size_request(dummy_label, &requisition); + gtk_widget_set_size_request(session->muted_warning, + requisition.width + 4, -1); + + /* main menu bar */ + main_menu = get_main_menu(main_window, session); /* main menu */ + gtk_widget_show(main_menu); + + /* pack items into main vbox (after main menu bar creation) */ + gtk_box_pack_start(GTK_BOX(main_vbox), main_menu, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(main_vbox), dialbox, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(main_vbox), session->controlpad, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(main_vbox), cidbox, TRUE, TRUE, 0); + gtk_box_pack_end(GTK_BOX(main_vbox), session->status_bar, FALSE, FALSE, 2); + + /* show items on demand */ + if (GTK_CHECK_MENU_ITEM(session->controlpad_check_menu_item)->active) + gtk_widget_show(session->controlpad); + if (GTK_CHECK_MENU_ITEM(session->cid_check_menu_item)->active) + gtk_widget_show(cidbox); + if (GTK_CHECK_MENU_ITEM(session->llcheck_check_menu_item)->active) + gtk_widget_show(session->llcheck); + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(session->mute_button))) + gtk_widget_show(session->muted_warning); + + /* show everything */ + gtk_widget_show(main_window); + + settings_history_read(session); /* get history from home dir dotfile */ + gtk_clist_freeze(GTK_CLIST(session->cid_list)); + settings_callerid_read(session); /* get callerid history */ + if (session->option_calls_merge) + cid_calls_merge(session); /* merge history from isdnlog */ + gtk_clist_thaw(GTK_CLIST(session->cid_list)); + cid_jump_to_end(session); + cid_jump_to_end(session); + + /* connect isdn and sound input handlers to gdk pseudo select */ + session_io_handlers_start(session); + + /* set up for initial state */ + session_set_state(session, STATE_READY); /* state is already in session */ + + /* set up additional handlers */ + gtk_timeout_add(TIMER_DELAY, timeout_callback, (gpointer) session); + signal(SIGINT, &terminate_signal_callback); + signal(SIGTERM, &terminate_signal_callback); + + /* gtk main loop */ + gtk_main(); + + /* some deinit */ + session_io_handlers_stop(session); + + return 0; +} + diff --git a/src/gtk.h b/src/gtk.h new file mode 100644 index 0000000..4d77f99 --- /dev/null +++ b/src/gtk.h @@ -0,0 +1,30 @@ +/* + * gtk GUI functions + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* own header files */ +#include "session.h" + +GtkWidget *ok_dialog_get(char *title, char *contents, + GtkJustification justification); +void show_audio_error_dialog(void); +int main_gtk(session_t *session); diff --git a/src/gtksettings.c b/src/gtksettings.c new file mode 100644 index 0000000..930d30a --- /dev/null +++ b/src/gtksettings.c @@ -0,0 +1,631 @@ +/* + * settings gtk GUI functions + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + */ + +#include "config.h" + +/* regular GNU system includes */ +#include +#include +#ifdef HAVE_STDLIB_H + #include +#endif + +/* GTK */ +#include + +/* own header files */ +#include "globals.h" +#include "session.h" +#include "isdn.h" +#include "sound.h" +#include "gtk.h" +#include "settings.h" +#include "recording.h" + +/* + * Load all settings from widgets into session + * -> used by gtksettings_cb_ok and gtksettings_cb_save + * + * input: widget: the widget with associated data widgets and session inside + * + * returns 0 on success, -1 otherwise (bad audio settings) + */ +static int gtksettings_try(GtkWidget *widget) { + session_t *session = gtk_object_get_data(GTK_OBJECT(widget), + "session"); + /* save current settings */ + char *old_msn = session->msn; + char *old_msns = session->msns; + int successful = 1; + GtkWidget *entry; + GtkWidget *button; + GSList *list; + + /* exec_on_incoming */ + entry = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(widget), + "exec_on_incoming_entry"); + if (entry) { + free(session->exec_on_incoming); + session->exec_on_incoming = strdup(gtk_entry_get_text(GTK_ENTRY(entry))); + } else + fprintf(stderr, "gtksettings_cb_ok: Error getting exec_on_incoming.\n"); + + /* popup checkbutton */ + button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(widget), + "popup_checkbutton"); + if (button) + session->option_popup = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); + else + fprintf(stderr, "gtksettings_cb_ok: Error getting popup state.\n"); + + /* recording_format */ + list = (GSList *) gtk_object_get_data(GTK_OBJECT(widget), "recording_format"); + if (list) { + while (list) { + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(list->data))) { + session->option_recording_format = (enum recording_format_t) + gtk_object_get_data(GTK_OBJECT(list->data), "rec_format"); + } + list = list->next; + } + } else + fprintf(stderr, "gtksettings_cb_ok: Error getting recording_format.\n"); + + /* msn */ + entry = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(widget), "msn_entry"); + if (entry) + session->msn = strdup(gtk_entry_get_text(GTK_ENTRY(entry))); + else + fprintf(stderr, "gtksettings_cb_ok: Error getting msn.\n"); + + /* msns */ + entry = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(widget), "msns_entry"); + if (entry) + session->msns = strdup(gtk_entry_get_text(GTK_ENTRY(entry))); + else + fprintf(stderr, "gtksettings_cb_ok: Error getting msns.\n"); + + /* history_entry */ + entry = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(widget), + "history_entry"); + if (entry) + session->dial_number_history_maxlen = + strtol(gtk_entry_get_text(GTK_ENTRY(entry)), NULL, 0); + else + fprintf(stderr, "gtksettings_cb_ok: Error getting history.\n"); + session->dial_number_history_pointer = 0; + + /* cid_max_entry */ + entry = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(widget), + "cid_max_entry"); + if (entry) + session->cid_num_max = + strtol(gtk_entry_get_text(GTK_ENTRY(entry)), NULL, 0); + else + fprintf(stderr, "gtksettings_cb_ok: " + "Error getting caller id maximum rows.\n"); + + /* cid_calls_merge_checkbutton */ + button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(widget), + "cid_calls_merge_checkbutton"); + if (button) + session->option_calls_merge = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); + else + fprintf(stderr, + "gtksettings_cb_ok: Error getting isdnlog calls_merge state.\n"); + /* cid_calls_merge_max_entry */ + entry = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(widget), + "cid_calls_merge_max_entry"); + if (entry) + session->option_calls_merge_max_days = + strtol(gtk_entry_get_text(GTK_ENTRY(entry)), NULL, 0); + else + fprintf(stderr, "gtksettings_cb_ok: " + "Error getting maximum number of days for isdnlog retrieval.\n"); + + /* save checkbutton */ + button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(widget), + "save_checkbutton"); + if (button) + session->option_save_options = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); + else + fprintf(stderr, + "gtksettings_cb_ok: Error getting save_options state.\n"); + + /* + * audio stop/start + */ + + if (session->audio_device_name_in) { /* shut down if defined */ + session_io_handlers_stop(session); + if (!session->option_release_devices) /* audio_close if normal mode */ + session_audio_deinit(session); + free(session->audio_device_name_in); + free(session->audio_device_name_out); + } + + /* audio_device_name_in */ + entry = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(widget), + "audio_device_name_in_entry"); + if (entry) + session->audio_device_name_in = + strdup(gtk_entry_get_text(GTK_ENTRY(entry))); + else + fprintf(stderr,"gtksettings_cb_ok: Error getting audio_device_name_in.\n"); + + /* audio_device_name_out */ + entry = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(widget), + "audio_device_name_out_entry"); + if (entry) + session->audio_device_name_out = + strdup(gtk_entry_get_text(GTK_ENTRY(entry))); + else + fprintf(stderr, + "gtksettings_cb_ok: Error getting audio_device_name_out.\n"); + + /* release checkbutton */ + button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(widget), + "release_checkbutton"); + if (button) + session->option_release_devices = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); + else + fprintf(stderr, + "gtksettings_cb_ok: Error getting release_devices state.\n"); + + if (!session->option_release_devices) { + if (session_audio_init(session)) { + successful = 0; + free(session->audio_device_name_in); + free(session->audio_device_name_out); + session->audio_device_name_in = NULL; /* flag for audio shut down */ + } + } + + if (session->audio_device_name_in) { /* OK or unknown */ + session_io_handlers_start(session); + session_set_state(session, STATE_READY); /* update everything */ + } + + /* try to apply msn settings */ + if (isdn_setMSN(session->isdn_fd, session->msn) || + isdn_setMSNs(session->isdn_fd, session->msns)) { + /* got some problem */ + free(session->msn); + free(session->msns); + session->msn = old_msn; + session->msns = old_msns; + isdn_setMSN(session->isdn_fd, session->msn); + isdn_setMSNs(session->isdn_fd, session->msns); + successful = 0; + } else { + /* everything's fine */ + free(old_msn); + free(old_msns); + } + + return !!successful - 1; +} + +/* + * clicked "ok" at gtksettings_cb + * input: window: the widget with associated data widgets and session inside + */ +static void gtksettings_cb_ok(GtkWidget *window) { + GtkWidget *ok_window; + + if (!gtksettings_try(window)) { /* changed settings */ + gtk_widget_destroy(window); + } else { /* settings error -> restored old settings -> display note */ + ok_window = ok_dialog_get(_("ANT Note"), + _("Bad isdn/sound device settings, please try again."), + GTK_JUSTIFY_CENTER); + gtk_window_set_modal(GTK_WINDOW(ok_window), TRUE); + gtk_widget_show(ok_window); + } +} + +/* clicked "Save" button at settings dialog (gtksettings_cb) */ +static void gtksettings_cb_save(GtkWidget *widget) { + session_t *session = gtk_object_get_data(GTK_OBJECT(widget), + "session"); + gtksettings_try(widget); + settings_options_write(session); +} + +/* clicked "Cancel" button at settings dialog (gtksettings_cb) */ +static void gtksettings_cb_cancel(GtkWidget *window) { + session_t *session = gtk_object_get_data(GTK_OBJECT(window), + "session"); + if (session->audio_device_name_in) /* audio not shut off */ + gtk_widget_destroy(window); +} + +/* + * callback for setting widget sensitivity on toggle button change + */ +static void toggle_sensitive_register(GtkToggleButton *button, + GtkWidget *widget) { + gtk_widget_set_sensitive(widget, gtk_toggle_button_get_active(button)); +} + +/* Settings menu entry callback */ +void gtksettings_cb(GtkWidget *widget _U_, gpointer data, guint action _U_) { + session_t *session = (session_t *) data; + GtkWidget *window; /* the dialog window itself */ + GtkWidget *button_box; /* box for buttons in standard way */ + GtkWidget *button; /* action area buttons */ + GtkWidget *table; /* tables in frames */ + GtkWidget *label; /* different labels */ + GtkWidget *frame; /* the frames to separate msn/msns from sound devices */ + GtkWidget *notebook; /* to separate options into topics */ + GtkWidget *vbox; /* the vbox inside notebook with frames */ + GtkWidget *vbox2; /* vbox inside frames */ + + /* widgets to save (to evaluate later) */ + GtkWidget *save_checkbutton; /* program page */ + GtkWidget *popup_checkbutton; + GtkWidget *exec_on_incoming_entry; + GtkWidget *msn_entry; /* phone page */ + GtkWidget *msns_entry; + GtkWidget *history_entry; + GtkWidget *cid_max_entry; + GtkWidget *audio_device_name_in_entry; /* sound devices page */ + GtkWidget *audio_device_name_out_entry; + GtkWidget *release_checkbutton; + GtkWidget *recformat_radiobutton; /* recording format */ + + GtkWidget *cid_calls_merge_checkbutton; + GtkWidget *cid_calls_merge_max_entry; + + char *s; /* temporary string */ + + window = gtk_dialog_new(); + gtk_window_set_title(GTK_WINDOW(window), _("ANT Settings")); + + /* the notebook inside the window / vbox area */ + notebook = gtk_notebook_new(); + gtk_container_set_border_width(GTK_CONTAINER(notebook), 5); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), notebook, + TRUE, TRUE, 0); + gtk_widget_show(notebook); + + /* Program page */ + vbox = gtk_vbox_new(FALSE, 0); + gtk_widget_show(vbox); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, + gtk_label_new(_("Application"))); + + frame = gtk_frame_new(_("Options")); + gtk_container_set_border_width(GTK_CONTAINER(frame), 10); + gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); + gtk_widget_show(frame); + + table = gtk_table_new(3, 2, FALSE); /* rows, columns, not homogeneous */ + gtk_container_add(GTK_CONTAINER(frame), table); + gtk_container_set_border_width(GTK_CONTAINER(table), 5); + gtk_table_set_row_spacings(GTK_TABLE(table), 5); + gtk_table_set_col_spacings(GTK_TABLE(table), 5); + gtk_widget_show(table); + + save_checkbutton = gtk_check_button_new_with_label(_("Save options on exit")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(save_checkbutton), + session->option_save_options); + gtk_table_attach_defaults(GTK_TABLE(table), save_checkbutton, 0,2,0,1); + gtk_widget_show(save_checkbutton); + + popup_checkbutton = + gtk_check_button_new_with_label(_("Popup main window on incoming call")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(popup_checkbutton), + session->option_popup); + gtk_table_attach_defaults(GTK_TABLE(table), popup_checkbutton, 0,2,1,2); + gtk_widget_show(popup_checkbutton); + + label = gtk_label_new(_("Execute on incoming call:")); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0,1,2,3); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_widget_show(label); + + exec_on_incoming_entry = gtk_entry_new(); + gtk_table_attach_defaults(GTK_TABLE(table), exec_on_incoming_entry, 1,2,2,3); + gtk_entry_set_text(GTK_ENTRY(exec_on_incoming_entry), + session->exec_on_incoming); + gtk_widget_show(exec_on_incoming_entry); + + frame = gtk_frame_new(_("Recording Format")); + gtk_container_set_border_width(GTK_CONTAINER(frame), 10); + gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); + gtk_widget_show(frame); + + vbox2 = gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(frame), vbox2); + gtk_widget_show(vbox2); + + recformat_radiobutton = gtk_radio_button_new_with_label(NULL, + _("Microsoft WAV, uLaw")); + gtk_box_pack_start(GTK_BOX(vbox2), recformat_radiobutton, FALSE, FALSE, 0); + gtk_widget_show(recformat_radiobutton); + gtk_object_set_data(GTK_OBJECT(recformat_radiobutton), + "rec_format", (gpointer) (RECORDING_FORMAT_WAV | RECORDING_FORMAT_ULAW)); + if (session->option_recording_format == (enum recording_format_t) + gtk_object_get_data(GTK_OBJECT(recformat_radiobutton), "rec_format")) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(recformat_radiobutton),TRUE); + + recformat_radiobutton = gtk_radio_button_new_with_label_from_widget( + GTK_RADIO_BUTTON(recformat_radiobutton), _("Microsoft WAV, 16-bit signed")); + gtk_box_pack_start(GTK_BOX(vbox2), recformat_radiobutton, FALSE, FALSE, 0); + gtk_widget_show(recformat_radiobutton); + gtk_object_set_data(GTK_OBJECT(recformat_radiobutton), + "rec_format", (gpointer) (RECORDING_FORMAT_WAV | RECORDING_FORMAT_S16)); + if (session->option_recording_format == (enum recording_format_t) + gtk_object_get_data(GTK_OBJECT(recformat_radiobutton), "rec_format")) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(recformat_radiobutton),TRUE); + + recformat_radiobutton = gtk_radio_button_new_with_label_from_widget( + GTK_RADIO_BUTTON(recformat_radiobutton), _("Apple/SGI AIFF, uLaw")); + gtk_box_pack_start(GTK_BOX(vbox2), recformat_radiobutton, FALSE, FALSE, 0); + gtk_widget_show(recformat_radiobutton); + gtk_object_set_data(GTK_OBJECT(recformat_radiobutton), + "rec_format", (gpointer) (RECORDING_FORMAT_AIFF | RECORDING_FORMAT_ULAW)); + if (session->option_recording_format == (enum recording_format_t) + gtk_object_get_data(GTK_OBJECT(recformat_radiobutton), "rec_format")) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(recformat_radiobutton),TRUE); + + recformat_radiobutton = gtk_radio_button_new_with_label_from_widget( + GTK_RADIO_BUTTON(recformat_radiobutton), _("Apple/SGI AIFF, 16-bit signed")); + gtk_box_pack_start(GTK_BOX(vbox2), recformat_radiobutton, FALSE, FALSE, 0); + gtk_widget_show(recformat_radiobutton); + gtk_object_set_data(GTK_OBJECT(recformat_radiobutton), + "rec_format", (gpointer) (RECORDING_FORMAT_AIFF | RECORDING_FORMAT_S16)); + if (session->option_recording_format == (enum recording_format_t) + gtk_object_get_data(GTK_OBJECT(recformat_radiobutton), "rec_format")) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(recformat_radiobutton),TRUE); + + /* Phone page */ + vbox = gtk_vbox_new(FALSE, 0); + gtk_widget_show(vbox); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, + gtk_label_new(_("Phone"))); + + frame = gtk_frame_new(_("ISDN")); + gtk_container_set_border_width(GTK_CONTAINER(frame), 10); + gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); + gtk_widget_show(frame); + + table = gtk_table_new(2, 2, FALSE); /* rows, columns, not homogeneous */ + gtk_container_add(GTK_CONTAINER(frame), table); + gtk_container_set_border_width(GTK_CONTAINER(table), 5); + gtk_table_set_row_spacings(GTK_TABLE(table), 5); + gtk_table_set_col_spacings(GTK_TABLE(table), 5); + gtk_widget_show(table); + + label = gtk_label_new(_("Identifying MSN:")); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0,1,0,1); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_widget_show(label); + + msn_entry = gtk_entry_new(); + gtk_table_attach_defaults(GTK_TABLE(table), msn_entry, 1,2,0,1); + gtk_entry_set_text(GTK_ENTRY(msn_entry), session->msn); + gtk_widget_show(msn_entry); + + label = gtk_label_new(_("Listen to MSNs:")); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0,1,1,2); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_widget_show(label); + + msns_entry = gtk_entry_new(); + gtk_table_attach_defaults(GTK_TABLE(table), msns_entry, 1,2,1,2); + gtk_entry_set_text(GTK_ENTRY(msns_entry), session->msns); + gtk_widget_show(msns_entry); + + frame = gtk_frame_new(_("Dialing")); + gtk_container_set_border_width(GTK_CONTAINER(frame), 10); + gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); + gtk_widget_show(frame); + + table = gtk_table_new(1, 2, FALSE); /* rows, columns, not homogeneous */ + gtk_container_add(GTK_CONTAINER(frame), table); + gtk_container_set_border_width(GTK_CONTAINER(table), 5); + gtk_table_set_row_spacings(GTK_TABLE(table), 5); + gtk_table_set_col_spacings(GTK_TABLE(table), 5); + gtk_widget_show(table); + + label = gtk_label_new(_("Dial history size:")); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0,1,0,1); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_widget_show(label); + + history_entry = gtk_entry_new(); + gtk_table_attach_defaults(GTK_TABLE(table), history_entry, 1,2,0,1); + asprintf(&s, "%u", session->dial_number_history_maxlen); + gtk_entry_set_text(GTK_ENTRY(history_entry), s); + free(s); + gtk_widget_show(history_entry); + + frame = gtk_frame_new(_("Caller ID")); + gtk_container_set_border_width(GTK_CONTAINER(frame), 10); + gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); + gtk_widget_show(frame); + + table = gtk_table_new(3, 2, FALSE); /* rows, columns, not homogeneous */ + gtk_container_add(GTK_CONTAINER(frame), table); + gtk_container_set_border_width(GTK_CONTAINER(table), 5); + gtk_table_set_row_spacings(GTK_TABLE(table), 5); + gtk_table_set_col_spacings(GTK_TABLE(table), 5); + gtk_widget_show(table); + + label = gtk_label_new(_("Maximum CID rows:")); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0,1,0,1); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_widget_show(label); + + cid_max_entry = gtk_entry_new(); + gtk_table_attach_defaults(GTK_TABLE(table), cid_max_entry, 1,2,0,1); + if (session->cid_num_max == 0) { + s = strdup(_("[no limit]")); + } else { + asprintf(&s, "%u", session->cid_num_max); + } + gtk_entry_set_text(GTK_ENTRY(cid_max_entry), s); + free(s); + gtk_widget_show(cid_max_entry); + + cid_calls_merge_checkbutton = gtk_check_button_new_with_label( + _("Read isdnlog data on startup")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cid_calls_merge_checkbutton), + session->option_calls_merge); + gtk_table_attach_defaults(GTK_TABLE(table), cid_calls_merge_checkbutton, + 0,2,1,2); + gtk_widget_show(cid_calls_merge_checkbutton); + + label = gtk_label_new(_("Maximum days to read from isdnlog:")); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0,1,2,3); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_widget_set_sensitive(label, session->option_calls_merge); + gtk_signal_connect(GTK_OBJECT(cid_calls_merge_checkbutton), "toggled", + GTK_SIGNAL_FUNC(toggle_sensitive_register), label); + gtk_widget_show(label); + + cid_calls_merge_max_entry = gtk_entry_new(); + gtk_table_attach_defaults(GTK_TABLE(table), cid_calls_merge_max_entry, + 1,2,2,3); + if (session->option_calls_merge_max_days == 0) { + s = strdup(_("[no limit]")); + } else { + asprintf(&s, "%u", session->option_calls_merge_max_days); + } + gtk_entry_set_text(GTK_ENTRY(cid_calls_merge_max_entry), s); + free(s); + gtk_widget_set_sensitive(cid_calls_merge_max_entry, + session->option_calls_merge); + gtk_signal_connect(GTK_OBJECT(cid_calls_merge_checkbutton), "toggled", + GTK_SIGNAL_FUNC(toggle_sensitive_register), + cid_calls_merge_max_entry); + gtk_widget_show(cid_calls_merge_max_entry); + + /* Sound devices page */ + vbox = gtk_vbox_new(FALSE, 0); + gtk_widget_show(vbox); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, + gtk_label_new(_("Sound Devices"))); + + frame = gtk_frame_new(_("OSS")); + gtk_container_set_border_width(GTK_CONTAINER(frame), 10); + gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); + gtk_widget_show(frame); + + table = gtk_table_new(3,2, FALSE); /* rows, columns, not homogeneous */ + gtk_container_add(GTK_CONTAINER(frame), table); + gtk_container_set_border_width(GTK_CONTAINER(table), 5); + gtk_table_set_row_spacings(GTK_TABLE(table), 5); + gtk_table_set_col_spacings(GTK_TABLE(table), 5); + gtk_widget_show(table); + + label = gtk_label_new(_("Input sound device:")); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0,1,0,1); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_widget_show(label); + + audio_device_name_in_entry = gtk_entry_new(); + gtk_table_attach_defaults(GTK_TABLE(table), audio_device_name_in_entry, + 1,2,0,1); + gtk_entry_set_text(GTK_ENTRY(audio_device_name_in_entry), + session->audio_device_name_in); + gtk_widget_show(audio_device_name_in_entry); + + label = gtk_label_new(_("Output sound device:")); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0,1,1,2); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_widget_show(label); + + audio_device_name_out_entry = gtk_entry_new(); + gtk_table_attach_defaults(GTK_TABLE(table), audio_device_name_out_entry, + 1,2,1,2); + gtk_entry_set_text(GTK_ENTRY(audio_device_name_out_entry), + session->audio_device_name_out); + gtk_widget_show(audio_device_name_out_entry); + + release_checkbutton = + gtk_check_button_new_with_label(_("Release unused devices")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(release_checkbutton), + session->option_release_devices); + gtk_table_attach_defaults(GTK_TABLE(table), release_checkbutton, 0,2,2,3); + gtk_widget_show(release_checkbutton); + + /* action area */ + button_box = gtk_hbutton_box_new(); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->action_area), + button_box); + gtk_widget_show(button_box); + + button = gtk_button_new_with_label(_("OK")); + gtk_box_pack_start_defaults(GTK_BOX(button_box), button); + + gtk_object_set_data(GTK_OBJECT(window), "session", (gpointer) session); + + gtk_object_set_data(GTK_OBJECT(window), "save_checkbutton", + (gpointer) save_checkbutton); + gtk_object_set_data(GTK_OBJECT(window), "popup_checkbutton", + (gpointer) popup_checkbutton); + gtk_object_set_data(GTK_OBJECT(window), "exec_on_incoming_entry", + (gpointer) exec_on_incoming_entry); + + gtk_object_set_data(GTK_OBJECT(window), "recording_format", + (gpointer) gtk_radio_button_group(GTK_RADIO_BUTTON(recformat_radiobutton))); + + gtk_object_set_data(GTK_OBJECT(window), "msn_entry", (gpointer) msn_entry); + gtk_object_set_data(GTK_OBJECT(window), "msns_entry", (gpointer) msns_entry); + gtk_object_set_data(GTK_OBJECT(window), "history_entry", + (gpointer) history_entry); + gtk_object_set_data(GTK_OBJECT(window), "cid_max_entry", + (gpointer) cid_max_entry); + gtk_object_set_data(GTK_OBJECT(window), "cid_calls_merge_checkbutton", + (gpointer) cid_calls_merge_checkbutton); + gtk_object_set_data(GTK_OBJECT(window), "cid_calls_merge_max_entry", + (gpointer) cid_calls_merge_max_entry); + + gtk_object_set_data(GTK_OBJECT(window), "audio_device_name_in_entry", + (gpointer) audio_device_name_in_entry); + gtk_object_set_data(GTK_OBJECT(window), "audio_device_name_out_entry", + (gpointer) audio_device_name_out_entry); + gtk_object_set_data(GTK_OBJECT(window), "release_checkbutton", + (gpointer) release_checkbutton); + + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtksettings_cb_ok), + GTK_OBJECT(window)); + gtk_widget_show(button); + + button = gtk_button_new_with_label(_("Save")); + gtk_box_pack_start_defaults(GTK_BOX(button_box), button); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtksettings_cb_save), + GTK_OBJECT(window)); + gtk_widget_show(button); + + button = gtk_button_new_with_label(_("Cancel")); + gtk_box_pack_start_defaults(GTK_BOX(button_box), button); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtksettings_cb_cancel), + GTK_OBJECT(window)); + gtk_signal_connect_object(GTK_OBJECT(window), "delete_event", + GTK_SIGNAL_FUNC(gtksettings_cb_cancel), + GTK_OBJECT(window)); + gtk_widget_show(button); + + gtk_window_set_modal(GTK_WINDOW(window), TRUE); + + /* show everything */ + gtk_widget_show(window); +} + diff --git a/src/gtksettings.h b/src/gtksettings.h new file mode 100644 index 0000000..bbd3566 --- /dev/null +++ b/src/gtksettings.h @@ -0,0 +1,17 @@ +/* + * gtk GUI functions + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + */ + +/* GTK */ +#include + +/* own header files */ +#include "session.h" + +void gtksettings_cb_ok(GtkWidget *widget, gpointer data); +void gtksettings_cb(GtkWidget *widget _U_, gpointer data, guint action _U_); diff --git a/src/hangup.xpm b/src/hangup.xpm new file mode 100644 index 0000000..607d8c6 --- /dev/null +++ b/src/hangup.xpm @@ -0,0 +1,19 @@ +/* XPM */ +static char * hangup_xpm[] = { +"16 14 2 1", +" c None", +". c #E20000", +" .. ", +" .. ", +" .. ", +" . .. . ", +" ...... ", +" .... ", +" .. ", +" ", +" ", +" ............ ", +" .............. ", +"..... .....", +"..... ....", +" .. .. "}; diff --git a/src/icon16x16.xpm b/src/icon16x16.xpm new file mode 100644 index 0000000..868d858 --- /dev/null +++ b/src/icon16x16.xpm @@ -0,0 +1,108 @@ +/* XPM */ +static char *icon16x16[] = { +/* columns rows colors chars-per-pixel */ +"16 16 86 1", +" c black", +". c #000100", +"X c #010101", +"o c #010201", +"O c #020302", +"+ c #040504", +"@ c #050605", +"# c #0B0C0B", +"$ c #0D0E0D", +"% c #0E0F0E", +"& c gray6", +"* c #111111", +"= c #131313", +"- c gray8", +"; c #141514", +": c #151615", +"> c #181818", +", c #191A19", +"< c gray10", +"1 c #1C1D1C", +"2 c gray13", +"3 c #262726", +"4 c #2C2C2C", +"5 c #2C2D2C", +"6 c #333433", +"7 c #343534", +"8 c #353635", +"9 c #373837", +"0 c gray22", +"q c #3A3B3A", +"w c #3C3D3C", +"e c #414241", +"r c #454645", +"t c gray28", +"y c #484948", +"u c #4E4E4E", +"i c #535453", +"p c #5A5B5A", +"a c #5D5E5D", +"s c gray37", +"d c #646564", +"f c #656565", +"g c #6D6E6D", +"h c #6E6F6E", +"j c #6F706F", +"k c #747474", +"l c #797979", +"z c #868686", +"x c gray55", +"c c #8E8F8E", +"v c #959595", +"b c gray59", +"n c #999A99", +"m c #A6A7A6", +"M c gray66", +"N c #A8A9A8", +"B c gray71", +"V c #B6B6B6", +"C c gray72", +"Z c #C0C0C0", +"A c #C3C3C3", +"S c #C5C5C5", +"D c gray78", +"F c #CBCBCB", +"G c gray82", +"H c #D2D2D2", +"J c gray84", +"K c #D7D7D7", +"L c #D8D8D8", +"P c gainsboro", +"I c gray88", +"U c #E1E1E1", +"Y c gray89", +"T c #E6E6E6", +"R c #E7E7E7", +"E c #E9E9E9", +"W c #EAEAEA", +"Q c gray94", +"! c #F1F1F1", +"~ c #F3F3F3", +"^ c gray96", +"/ c gray97", +"( c gray99", +") c #FDFDFD", +"_ c #FEFEFE", +"` c gray100", +/* pixels */ +"````````````````", +"````````````````", +"````````````````", +"```RJ```````````", +"``t 0sF(Q``````", +"`^= ,: 2uRQ`^xx`", +"``FbLYmBlKY`C g~", +"D,#: i=65: y@ 9", +"AzQ~8 @%Y`e b j^", +"Hp33: 6``d b k`", +"5#R`q +8``d n j`", +"s yw1 8``d B@%y", +"`ZmKWDDF``LD^LMA", +"````````````````", +"````````````````", +"````````````````" +}; diff --git a/src/icon32x32.xpm b/src/icon32x32.xpm new file mode 100644 index 0000000..fa4e7cf --- /dev/null +++ b/src/icon32x32.xpm @@ -0,0 +1,190 @@ +/* XPM */ +static char *icon32x32[] = { +/* columns rows colors chars-per-pixel */ +"32 32 152 2", +" c black", +". c #000100", +"X c #010101", +"o c #010201", +"O c gray1", +"+ c #030403", +"@ c #040404", +"# c #040504", +"$ c #070807", +"% c #080908", +"& c #090909", +"* c #0C0D0C", +"= c #0D0E0D", +"- c #0F100F", +"; c #111111", +": c #121312", +"> c #141514", +", c #181918", +"< c #191A19", +"1 c #1A1B1A", +"2 c gray11", +"3 c #1C1D1C", +"4 c #1D1E1D", +"5 c #1F201F", +"6 c #212221", +"7 c gray14", +"8 c #262726", +"9 c #2C2D2C", +"0 c #2E2F2E", +"q c #303130", +"w c #333433", +"e c #343534", +"r c #353635", +"t c #373837", +"y c gray22", +"u c #383938", +"i c #393A39", +"p c #3C3C3C", +"a c #3C3D3C", +"s c #3F3F3F", +"d c gray25", +"f c #414241", +"g c #474847", +"h c #4C4C4C", +"j c gray30", +"k c #4E4E4E", +"l c #505050", +"z c #505150", +"x c gray32", +"c c #525352", +"v c #535453", +"b c #555555", +"n c #555655", +"m c #565756", +"M c gray36", +"N c #5D5E5D", +"B c #5E5F5E", +"V c #5F5F5F", +"C c #606060", +"Z c #626362", +"A c gray39", +"S c #656565", +"D c gray40", +"F c #676767", +"G c #676867", +"H c #696A69", +"J c #6A6A6A", +"K c #6E6F6E", +"L c #717171", +"P c #767776", +"I c #777777", +"U c gray47", +"Y c gray48", +"T c #808080", +"R c gray51", +"E c #838383", +"W c gray52", +"Q c #858685", +"! c gray53", +"~ c #888988", +"^ c #898989", +"/ c #8A8B8A", +"( c gray56", +") c #909090", +"_ c #909190", +"` c #929392", +"' c #959595", +"] c #9D9D9D", +"[ c #A0A1A0", +"{ c #A2A2A2", +"} c gray64", +"| c #A4A5A4", +" . c #A5A5A5", +".. c #A5A6A5", +"X. c #A7A7A7", +"o. c #A7A8A7", +"O. c gray66", +"+. c #AAAAAA", +"@. c gray67", +"#. c #ABACAB", +"$. c gray68", +"%. c #AFAFAF", +"&. c gray69", +"*. c #B3B4B3", +"=. c gray71", +"-. c #B7B7B7", +";. c gray72", +":. c #BBBBBB", +">. c gray75", +",. c gray76", +"<. c gray77", +"1. c #C4C5C4", +"2. c #C8C8C8", +"3. c #CACACA", +"4. c gray80", +"5. c #CDCDCD", +"6. c #CDCECD", +"7. c gray81", +"8. c gray82", +"9. c gray84", +"0. c #D7D7D7", +"q. c gray85", +"w. c #DADADA", +"e. c gainsboro", +"r. c gray87", +"t. c #DFDFDF", +"y. c gray88", +"u. c #E1E1E1", +"i. c #E2E2E2", +"p. c gray89", +"a. c #E4E4E4", +"s. c gray90", +"d. c #E5E6E5", +"f. c #E6E6E6", +"g. c #E6E7E6", +"h. c #E7E7E7", +"j. c gray91", +"k. c #E9E9E9", +"l. c gray92", +"z. c #EEEEEE", +"x. c #F1F1F1", +"c. c gray95", +"v. c #F3F3F3", +"b. c #F4F4F4", +"n. c gray96", +"m. c #F6F6F6", +"M. c gray97", +"N. c gray98", +"B. c gray99", +"V. c #FDFDFD", +"C. c #FEFEFE", +"Z. c gray100", +/* pixels */ +"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.Z.Z.Z.f.-.} ;.b.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.Z.3.d . . . . 7 :.&.2.Z.Z.Z.Z.Z.j.b.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.b.; . . . . . . . . . p x.Z.b.f.b.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.y.. . . . . . . . . . . E ( +.f.y.r.j.Z.Z.Z.Z.Z.q.H j.Z.Z.", +"Z.Z.Z.Z.h . . . @ A l . . . . . . . r.Z.Z.Z.Z.Z.Z.9.c + . j.Z.Z.", +"Z.Z.Z.Z.Z.>.E ^ 5.m.Z.+.V L U ] . 2 m.Z.Z.Z.Z.Z.Z.! . . . j.Z.Z.", +"Z.Z.Z.x.<.+.} +.&.l.Z.r.j.y.7.x.y.f.,.X.%.0.Z.Z.y.Y . . . 5.y.z.", +"Z.z.V $ . . . + @ @ k 5.6 . # %.! ; . . . . r 8.= . . . . . . K ", +"N.r . . + q a 5 . . . r 6 . . 4 . , a , . . . 4 & . . . . . . K ", +"7.a , & ,.Z.Z.Z.H . . . = . . . _ Z.Z.N.c . . . +.Y . . . 8.f.x.", +"Z.Z.Z.b.Z.Z.Z.q.H . . . . . . p Z.Z.Z.Z.*.. . . +.! . . . j.Z.Z.", +"Z.Z.q.) V w = . . . . . . . . A Z.Z.Z.Z.2.. . . } ! . . . j.Z.Z.", +"b.b . . . $ 0 M c . . . # . . H Z.Z.Z.Z.3.. . . } ^ . . . j.Z.Z.", +"I . . # } b.Z.Z.` . . . # . . H Z.Z.Z.Z.3.. . . } ^ . . . f.Z.Z.", +"p . . 8 Z.Z.Z.Z.b . . . # . . H Z.Z.Z.Z.3.. . . } ` . . . q.Z.Z.", +"A . . . C -.} g . . . . . . . H Z.Z.Z.Z.3.. . . +.} . . . r V E ", +"f.0 . . . . . @ S = . . . . . H Z.Z.Z.Z.3.. . . } j.> . . . . d ", +"Z.N.] A k b ! q.Z.+./ ^ / / ^ >.Z.Z.Z.Z.h.^ / ^ q.Z.y.E c k S } ", +"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.", +"Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z." +}; diff --git a/src/icon48x48.xpm b/src/icon48x48.xpm new file mode 100644 index 0000000..27e7e6e --- /dev/null +++ b/src/icon48x48.xpm @@ -0,0 +1,256 @@ +/* XPM */ +static char *icon48x48[] = { +/* columns rows colors chars-per-pixel */ +"48 48 202 2", +" c black", +". c #000100", +"X c #010101", +"o c #010201", +"O c #020202", +"+ c #020302", +"@ c gray1", +"# c #030403", +"$ c #040404", +"% c #040504", +"& c gray2", +"* c #050605", +"= c #060606", +"- c #060706", +"; c #070707", +": c #070807", +"> c gray3", +", c #080908", +"< c #090909", +"1 c #0B0B0B", +"2 c #0C0C0C", +"3 c #0C0D0C", +"4 c #0D0E0D", +"5 c #0E0E0E", +"6 c #0E0F0E", +"7 c #0F100F", +"8 c #101110", +"9 c #111211", +"0 c gray7", +"q c #131413", +"w c gray8", +"e c #141514", +"r c #171817", +"t c #181918", +"y c #191A19", +"u c gray11", +"i c #1C1D1C", +"p c #1E1F1E", +"a c #202120", +"s c #212221", +"d c #222222", +"f c gray14", +"g c gray16", +"h c #2B2C2B", +"j c #2C2C2C", +"k c #2C2D2C", +"l c #2D2E2D", +"z c #2E2F2E", +"x c #2F302F", +"c c #313131", +"v c #313231", +"b c #323332", +"n c #343434", +"m c #353635", +"M c #373837", +"N c gray22", +"B c #393939", +"V c #393A39", +"C c gray23", +"Z c gray24", +"A c #3E3F3E", +"S c #404140", +"D c #434343", +"F c #434443", +"G c gray27", +"H c #454645", +"J c gray29", +"K c #4B4C4B", +"L c #4C4C4C", +"P c #4C4D4C", +"I c #4E4F4E", +"U c gray31", +"Y c #4F504F", +"T c #505150", +"R c #515251", +"E c gray32", +"W c #525352", +"Q c #535453", +"! c gray33", +"~ c #565756", +"^ c gray35", +"/ c #5A5A5A", +"( c #5A5B5A", +") c #5B5B5B", +"_ c #5C5D5C", +"` c gray37", +"' c #5F5F5F", +"] c gray39", +"[ c gray40", +"{ c DimGray", +"} c #696A69", +"| c #6A6B6A", +" . c #6D6D6D", +".. c gray43", +"X. c #707170", +"o. c #717171", +"O. c #727272", +"+. c #747474", +"@. c gray46", +"#. c #757675", +"$. c #777777", +"%. c gray47", +"&. c #787978", +"*. c #797A79", +"=. c #7A7B7A", +"-. c #7C7C7C", +";. c #7C7D7C", +":. c gray49", +">. c #7E7E7E", +",. c #7F807F", +"<. c #808080", +"1. c #838383", +"2. c #848484", +"3. c #868686", +"4. c gray53", +"5. c #888988", +"6. c #8B8B8B", +"7. c #8D8E8D", +"8. c gray56", +"9. c #949594", +"0. c #959595", +"q. c gray59", +"w. c #969796", +"e. c #979797", +"r. c gray60", +"t. c #9A9A9A", +"y. c #9B9B9B", +"u. c gray62", +"i. c #9F9F9F", +"p. c #A2A2A2", +"a. c gray64", +"s. c #A4A5A4", +"d. c #A5A5A5", +"f. c #A6A7A6", +"g. c #AAAAAA", +"h. c #ACACAC", +"j. c gray68", +"k. c #AEAEAE", +"l. c #AFAFAF", +"z. c gray69", +"x. c #B2B2B2", +"c. c gray70", +"v. c #B4B4B4", +"b. c gray71", +"n. c #B6B7B6", +"m. c gray72", +"M. c #B9B9B9", +"N. c #B9BAB9", +"B. c #BBBBBB", +"V. c gray74", +"C. c gray76", +"Z. c #C3C3C3", +"A. c gray78", +"S. c gray79", +"D. c #CACACA", +"F. c #CBCBCB", +"G. c #CDCDCD", +"H. c gray81", +"J. c #D0D0D0", +"K. c gray82", +"L. c LightGray", +"P. c gray83", +"I. c #D5D5D5", +"U. c gray84", +"Y. c #D7D7D7", +"T. c gray85", +"R. c #DADADA", +"E. c gray86", +"W. c #DDDDDD", +"Q. c #DDDEDD", +"!. c #DFDFDF", +"~. c gray88", +"^. c #E1E1E1", +"/. c #E2E2E2", +"(. c #E2E3E2", +"). c gray89", +"_. c #E4E4E4", +"`. c gray90", +"'. c #E7E7E7", +"]. c gray91", +"[. c gray92", +"{. c #ECECEC", +"}. c gray93", +"|. c #EEEEEE", +" X c #EFEFEF", +".X c gray94", +"XX c #F1F1F1", +"oX c gray95", +"OX c #F3F3F3", +"+X c #F4F4F4", +"@X c gray96", +"#X c gray97", +"$X c #F7F8F7", +"%X c #F8F8F8", +"&X c #F9F9F9", +"*X c gray98", +"=X c #FBFBFB", +"-X c gray99", +";X c #FDFDFD", +":X c #FEFEFE", +">X c #FEFFFE", +",X c gray100", +/* pixels */ +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X'.x.6.$.$.p.|.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,Xm.G & e g.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X:. & c & 2 C d.,X,X,X,X,X|.G.K.[.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X'.& 1.,X,X,X'.[.,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,XD. > !.!.m.'.,X*XK.K.G.!.,X,X,X,X,X,X,X,X,Xv.w.,X,X,X,X", +",X,X,X,X,X|.> A & C D.I.,X,X,X,X,X,X,X,X,X,X*Xa.x ' ,X,X,X,X", +",X,X,X,X,X,Xy.> C g.w.i D.,X,X,X,X,X,X,X,X,X,Xa.d ) ,X,X,X,X", +",X,X,X,X,X,X,X!.4.L c / d.[.*X,XW.] d l g f i.) > |.,X,X,X,X,X,X,X,X,X,XJ o ` ,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X|..X,X,X,XW.E.,X,XOX'.!.' D g.,X,X,X,X,X,X,X,X,X,X,XK o _ ,X,X,X,X", +",X,X,X,X,X!.x.8.:.$.&.3.5.N.|.,X,XK._.I.L.I.n.,X,X,X{.x.3.$.:.y.L.,X,X,XY.L.A o o o P L.L.L.|.", +",X,X,Xg.m o : o : ! K.W.b : e =X!.` : o x x.,Xe o o o o d.", +",X,Xo. o o & o o > m.b o e f.7 o o o o y.e o o o o d.", +",Xy. o f Q ` Y p o o x c o o o o m ) Y e o o 7 : o o o o o f.", +"$Xi o 1.=X,X,X,X,X$. o o o p o o C I.,X,X,X.XY o o 8.R.D o L R.R.R..X", +",X.XI.g.7.:.,X,X,X,X,X,X`. o o o o o o y .X,X,X,X,X,X'.& o o 5.,XK o ) ,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X|.N.$.o o o o o | ,X,X,X,X,X,X,Xe o o $.,XK o ' ,X,X,X,X", +",X,X,X,X@XD.w. .H p o o o o o 8.,X,X,X,X,X,X,Xh o o $.,XK o ' ,X,X,X,X", +",X,XG.) 9 o o o o o i.,X,X,X,X,X,X,Xx o o &.,XK o ` ,X,X,X,X", +",Xw.o o 7 C [ w.v.o o o : o o o i.,X,X,X,X,X,X,Xx o o &.,XK o o _ ,X,X,X,X", +"D.o o ) F.*X,X,X,X_.o o o o o o p.,X,X,X,X,X,X,Xx o &.,XK o o ) ,X,X,X,X", +"| o b ,X,X,X,X,X,XF. o o : o y.,X,X,X,X,X,X,Xx &.,X~ o o o Y ,X,X,X,X", +"Q o b ,X,X,X,X,X,X' o : o o o i.,X,X,X,X,X,X,Xx &.,X' F ,X,X,X,X", +"=. o o [ [.,X*XZ.K o o i.,X,X,X,X,X,X,Xx o &.,X| o : $.w.| v.", +"!.e o o : r 2 o o o o o o i.,X,X,X,X,X,X,Xx o o &.,Xi. o o o :.", +",XZ.r o , O.6. o o o i.,X,X,X,X,X,X,Xx o o $.,X@Xl o o / ", +",X,X{.3.m 2 2 m 1.W.,X|.W Y Y W Y Y Y W Y B.,X,X,X,X,X,X,XX.Y Q Y Y p.,X,X|.,.l : o e m w.", +",X,X,X,X,X,X@X.X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X*X.X$X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X", +",X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X" +}; diff --git a/src/icon64x64.xpm b/src/icon64x64.xpm new file mode 100644 index 0000000..4f2e51a --- /dev/null +++ b/src/icon64x64.xpm @@ -0,0 +1,316 @@ +/* XPM */ +static char *icon64x64[] = { +/* columns rows colors chars-per-pixel */ +"64 64 246 2", +" c black", +". c #000100", +"X c #010101", +"o c #010201", +"O c #020202", +"+ c #020302", +"@ c #030403", +"# c #040504", +"$ c gray2", +"% c #050605", +"& c #060606", +"* c #060706", +"= c #070707", +"- c #070807", +"; c #080908", +": c #090909", +"> c #090A09", +", c gray4", +"< c #0A0B0A", +"1 c #0B0C0B", +"2 c #0C0C0C", +"3 c #0C0D0C", +"4 c #0D0E0D", +"5 c #0E0E0E", +"6 c #0E0F0E", +"7 c gray6", +"8 c #0F100F", +"9 c #111111", +"0 c gray7", +"q c #121312", +"w c #141514", +"e c #161616", +"r c gray9", +"t c #171817", +"y c #191919", +"u c #191A19", +"i c #1A1B1A", +"p c #1B1B1B", +"a c #1B1C1B", +"s c gray11", +"d c #1C1D1C", +"f c #1D1E1D", +"g c #1E1F1E", +"h c gray12", +"j c #222222", +"k c #222322", +"l c #232323", +"z c #232423", +"x c gray14", +"c c #242524", +"v c gray15", +"b c #262726", +"n c #272827", +"m c #2C2C2C", +"M c #2C2D2C", +"N c #2D2E2D", +"B c gray18", +"V c #2E2F2E", +"C c #2F302F", +"Z c #313131", +"A c #323232", +"S c #333433", +"D c #343434", +"F c #343534", +"G c #393A39", +"H c #3F403F", +"J c gray25", +"K c #404140", +"L c #414141", +"P c #434343", +"I c #434443", +"U c #444444", +"Y c gray27", +"T c #454645", +"R c #464646", +"E c gray28", +"W c #484848", +"Q c #494949", +"! c gray29", +"~ c #4B4C4B", +"^ c #4D4E4D", +"/ c #4E4E4E", +"( c gray31", +") c #4F504F", +"_ c #515151", +"` c gray32", +"' c #535453", +"] c gray33", +"[ c #545554", +"{ c #555555", +"} c #565756", +"| c #575857", +" . c #585958", +".. c #595A59", +"X. c #5A5B5A", +"o. c #5B5B5B", +"O. c #5D5E5D", +"+. c gray37", +"@. c #5F5F5F", +"#. c #5F605F", +"$. c #606060", +"%. c #626262", +"&. c #626362", +"*. c #656565", +"=. c #666766", +"-. c #676767", +";. c #686968", +":. c DimGray", +">. c #6A6B6A", +",. c #6B6C6B", +"<. c #6C6C6C", +"1. c #6D6D6D", +"2. c gray43", +"3. c #6F706F", +"4. c #717171", +"5. c #717271", +"6. c #727272", +"7. c gray45", +"8. c #737473", +"9. c #747474", +"0. c gray46", +"q. c #757675", +"w. c #767776", +"e. c gray47", +"r. c #797979", +"t. c #797A79", +"y. c #7D7E7D", +"u. c #7E7E7E", +"i. c #7E7F7E", +"p. c gray50", +"a. c #808080", +"s. c gray51", +"d. c #838383", +"f. c #868786", +"g. c #888888", +"h. c gray54", +"j. c #8D8D8D", +"k. c #8D8E8D", +"l. c gray56", +"z. c #909090", +"x. c #909190", +"c. c gray57", +"v. c #939393", +"b. c gray58", +"n. c #949594", +"m. c #959595", +"M. c #969796", +"N. c #979797", +"B. c #989898", +"V. c gray60", +"C. c #9A9A9A", +"Z. c #9B9B9B", +"A. c #9D9D9D", +"S. c #9D9E9D", +"D. c gray62", +"F. c #9F9F9F", +"G. c #A0A0A0", +"H. c gray63", +"J. c gray65", +"K. c #A7A7A7", +"L. c #A9A9A9", +"P. c #AAAAAA", +"I. c #ABACAB", +"U. c #ACACAC", +"Y. c #AFAFAF", +"T. c gray69", +"R. c #B1B1B1", +"E. c #B1B2B1", +"W. c #B2B2B2", +"Q. c gray70", +"!. c #B4B4B4", +"~. c gray71", +"^. c #B7B7B7", +"/. c gray72", +"(. c #B9BAB9", +"). c gray73", +"_. c #BABBBA", +"`. c #BBBCBB", +"'. c #BCBCBC", +"]. c gray", +"[. c gray75", +"{. c #C1C1C1", +"}. c gray76", +"|. c gray77", +" X c #C5C5C5", +".X c #C6C6C6", +"XX c gray78", +"oX c #C8C8C8", +"OX c gray79", +"+X c #C9CAC9", +"@X c #CACACA", +"#X c #CBCBCB", +"$X c gray80", +"%X c #CCCDCC", +"&X c #CDCDCD", +"*X c #CDCECD", +"=X c gray81", +"-X c #CFD0CF", +";X c #D0D0D0", +":X c gray82", +">X c #D3D4D3", +",X c gray83", +".SXP . . . . 3 @.cXo.@ . . . . . . . . . . . . ` mXa . . . . . . . . . . . . . . 8X", +"SXSX^.; . . . . . . . . . . . . . . . . . . . H.P . . . . . P V . . . . . . . . . . . . . . . ,.p . . . . . . . . . . . . . . 0X", +"SXgXa . . . . . . 3 ^ 9.i.7. .j . . . . . . . V P . . . . . . . . . w ` w.w.` 3 . . . . . . . ; $ . . . . . . . . . . . . . . 8X", +"SXw.. . . . . . P iXSXSXSXSXSXSXd.. . . . . . . V . . . . . . . ; g.bXSXSXSXSXgXE . . . . . . . 7.*X*X3 . . . . . . K.*X*X*X*XmX", +"SX[.l.,.W l 1 t gXSXSXSXSXSXSXSXCXj . . . . . . 3 . . . . . . . Q.SXSXSXSXSXSXSXjXe . . . . . . 2.SXSX3 . . . . . . *XSXSXSXSXSX", +"SXSXSXSXSXSXlXiXSXSXSXSXSXSXSXSXSXP . . . . . . . . . . . . . ^ SXSXSXSXSXSXSXSXSX| . . . . . . ] SXSX8 . . . . . . :XSXSXSXSXSX", +"SXSXSXSXSXSXSXSXSXSXSXSXSXbX:XZ. .3 . . . . . . . . . . . . . Z.SXSXSXSXSXSXSXSXSXw.. . . . . . ~ SXSX8 . . . . . . :XSXSXSXSXSX", +"SXSXSXSXSXSXSXBX*XK.p.] m ; . . . . . . . . . . . . . . . . . ^.SXSXSXSXSXSXSXSXSXl.. . . . . . ~ SXSX8 . . . . . . =XSXSXSXSXSX", +"SXSXSXSX8Xd.H ; . . . . . . . . . . . . . . . . . . . . . . . =XSXSXSXSXSXSXSXSXSXb.. . . . . . ~ SXSX8 . . . . . . :XSXSXSXSXSX", +"SXSXrX] $ . . . . . . . . . . . 9 ; . . . . . . $ . . . . . . >XSXSXSXSXSXSXSXSXSXb.. . . . . . ~ SXSX8 . . . . . . :XSXSXSXSXSX", +"SX3Xs . . . . . . . $ p E 7.H.*XbXD . . . . . . ; . . . . . . >XSXSXSXSXSXSXSXSXSXb.. . . . . . ~ SXSX8 . . . . . . =XSXSXSXSXSX", +"BXB . . . . . . s x.8XSXSXSXSXSXSXS . . . . . . ; . . . . . . .bXSXSXSXSX:X! . . . . . . . . . . . . . . . .V . . . . . . . . . . . . . . . . . +#ifdef HAVE_STDLIB_H + #include +#endif +#ifdef HAVE_UNISTD_H + #include +#endif +#ifdef HAVE_TERMIOS_H + #include +#endif +#ifdef HAVE_FCNTL_H + #include +#endif +#ifdef HAVE_SYS_TIME_H + #include +#endif +#include +#include +#include + +/* own header files */ +#include "globals.h" +#include "isdn.h" + +static char* calls_filenames[] = +{ "/var/lib/isdn/calls", "/var/log/isdn/calls", "/var/log/isdn.log" }; +char* isdn_calls_filename_from_config = NULL; + +/* + * locks (via lock file) and opens a (free) ttyI device + * + * output: + * isdn_device_name, isdn_lockfile_name + * + * returns isdn file descriptor on success, -1 otherwise + */ +int open_isdn_device(char **isdn_device_name, char **isdn_lockfile_name) { + int i = 0; /* try from 0 */ + int found = 0; /* free file name found */ + char buf[64]; + int fd; + int n; + int pid; + + while (i < 64 && !found) { + snprintf(buf, sizeof(buf), "%s/LCK..ttyI%d", LOCK_PATH, i); + *isdn_lockfile_name = strdup(buf); + if ((fd = open(*isdn_lockfile_name, O_RDONLY)) >= 0) { /* exists */ + /* stale? -> remove (for re-use) */ + n = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (n > 0) { + if (n == 4) { + if (sizeof(int) == 4) + pid = *(int*) buf; + else + pid = 0; + } else { + buf[n] = 0; + sscanf(buf, "%d", &pid); + } + if (pid > 0) { + if (kill((pid_t) pid, 0) < 0 && errno == ESRCH) { /* stale */ + if (!unlink(*isdn_lockfile_name)) + found = 1; /* file removed */ + } + } + } + } else { + if (errno == ENOENT) + found = 1; /* file doesn't exist */ + } + if (!found) i++; + } + + if (found && i < 64) { /* got a valid lock file name */ + /* lock device */ + if ((fd = open(*isdn_lockfile_name, O_WRONLY | O_CREAT, 0666)) < 0) { + return -1; + } + snprintf(buf, sizeof(buf), "%10ld\n", (long)getpid()); + write(fd, buf, strlen(buf)); + close(fd); + + /* finally name and open the device itself */ + snprintf(buf, sizeof(buf), "/dev/ttyI%d", i); + *isdn_device_name = strdup(buf); + + /* tty device would possibly block on open -> O_NONBLOCK */ + return open(*isdn_device_name, O_RDWR | O_NONBLOCK); + } else + return -1; +} + +/* + * tries to read the given string from the specified tty (e.g. a ttyI) + * (waits for the string if not read immediately) + * + * input: + * fd tty file descriptor + * s (0-terminated) string to compare with + * timeout give up after this number of seconds + * 0: return immediately if no data available + * -1: no timeout + * got if got != NULL, store reference to result there + * + * output: + * got pointer to string containing buffer actually read if called + * with got != NULL + * -> will be NULL on error + * NOTE: caller is responsible to free the referenced buffer + * + * returns 0 on success, -1 otherwise + * + * NOTE: currently uses a fixed size buffer, implying a maximum number + * of bytes read + */ +int tty_read(int fd, char *s, int timeout, char **got) { + int failed = 0; /* 0 or 1*/ + int buf_last = 0; /* index of end of string ('\0') */ + char buf[256] = ""; + struct timeval tv, *tvp; + fd_set fds; + + if (timeout >= 0) { + tv.tv_sec = timeout; + tv.tv_usec = 0; + tvp = &tv; + } else + tvp = NULL; + + while (!strstr(buf, s) && !failed) { + FD_ZERO(&fds); + FD_SET(fd, &fds); + + if (buf_last == sizeof(buf) - 1) /* buffer full */ + failed = 1; + else { + if (select(FD_SETSIZE, &fds, 0, 0, tvp) == 1) { /* input ready */ + read(fd, &buf[buf_last], 1); /* read 1 more byte */ + buf[++buf_last] = 0; + } else { /* timeout or signal */ + failed = 1; + } + } + } + /* printf("%s\n", buf); */ + if (got != NULL) { + *got = strdup(buf); + } + return -failed; +} + +/* + * writes specified 0-terminated string to the specified tty + * + * returns 0 on success, -1 otherwise + */ +int tty_write(int fd, char *s) { + if (write(fd, s, strlen(s)) != (int)strlen(s)) { + return -1; + } + return 0; +} + +/* + * clears input and output queue of specified tty + * + * returns 0 on success, -1 otherwise + */ +int tty_clear(int fd) { + return tcflush(fd, TCIOFLUSH); +} + +/* + * ISDN initialization + * + * returns 0 on success, -1 otherwise + */ +int init_isdn_device(int isdn_fd, struct termios *backup) { + int failed = 0; + int flags; + char *(init_commands[]) = { + "AT&F\n", "OK\r\n", /* restore factory settings */ + "ATE0\n", "OK\r\n", /* echo off */ + /*"AT&B128\n", "OK\r\n",*/ /* set outgoing packet size */ + "ATI\n", "Linux ISDN\r\nOK\r\n", /* check for real isdn device */ + "AT+FCLASS=8\n", "OK\r\n", /* enable audio mode */ + "AT+VSM=6\n", "OK\r\n", /* set uLaw format */ + "ATS18=1\n", "OK\r\n", /* set audio mode (dial out) */ + "ATS14=4\n", "OK\r\n", /* layer-2 protocol = transparent */ + "ATS13.4=1\n", "OK\r\n", /* CALLER NUMBER after first RING */ + "ATS13.6=1\n", "OK\r\n", /* enable RUNG messages */ + "ATS23=1\n", "OK\r\n" /* Calling Party Number (CPN) extended RING */ + }; + struct termios settings; + unsigned int i; + + /* assume: + * ttyI speed is 64000 by default + */ + + /* switch O_NONBLOCK off (turned on while opening) */ + flags = fcntl(isdn_fd, F_GETFL, 0); + if (flags != -1) { + if (fcntl(isdn_fd, F_SETFL, flags & ~O_NONBLOCK) == -1) { + perror("G_GETFL"); + return -1; + } + } else { + perror("F_GETFL"); + return -1; + } + + if (tcgetattr(isdn_fd, &settings)) + return -1; + + memcpy(backup, &settings, sizeof(struct termios)); + + settings.c_lflag &= ~(ICANON | ECHO | ECHONL | ECHOCTL | ISIG); + settings.c_iflag &= ~(IXON | IXOFF | IXANY | IGNCR | ICRNL | INLCR ); + settings.c_iflag |= IGNPAR; + settings.c_cflag |= HUPCL; + settings.c_oflag &= ~ONLCR; + + settings.c_cc[VMIN] = 1; + settings.c_cc[VTIME] = 0; + + if (tcsetattr(isdn_fd, TCSANOW, &settings)) + return -1; + + i = 0; + + while (!failed && i < sizeof(init_commands) / sizeof(char*)) { + tty_clear(isdn_fd); + if (tty_write(isdn_fd, init_commands[i++])) + failed = 1; + else + if (tty_read(isdn_fd, init_commands[i++], ISDN_COMMAND_TIMEOUT, NULL)) + failed = 1; + } + + return -failed; +} + +/* + * ISDN de-initialization, restores termios settings + * + * returns 0 on success, -1 otherwise + */ +int deinit_isdn_device(int isdn_fd, struct termios *backup) { + return tcsetattr(isdn_fd, TCSANOW, backup); +} + +/* + * sets an MSN for the specified ttyI (originating MSN) + * fd is assumed to be in command mode + * + * returns 0 on success, -1 otherwise + */ +int isdn_setMSN(int isdn_fd, char *msn) { + char buf[256]; + + if (snprintf(buf, sizeof(buf), "AT&E%s\n", msn) >= (int)sizeof(buf)) { + fprintf(stderr, "Error: Specified MSN too long.\n"); + return -1; + } + tty_clear(isdn_fd); + if (tty_write(isdn_fd, buf)) + return -1; + else + if (tty_read(isdn_fd, "OK\r\n", ISDN_COMMAND_TIMEOUT, NULL)) + return -1; + return 0; +} + +/* + * sets MSNs for the specified ttyI (MSNs to listen on) + * fd is assumed to be in command mode + * msns: semicolon-separated list of msns + * + * returns 0 on success, -1 otherwise + */ +int isdn_setMSNs(int isdn_fd, char *msns) { + char buf[256]; + + if (snprintf(buf, sizeof(buf), "AT&L%s\n", msns) >= (int)sizeof(buf)) { + fprintf(stderr, "Error: Specified MSNs string too long.\n"); + return -1; + } + tty_clear(isdn_fd); + if (tty_write(isdn_fd, buf)) + return -1; + else + if (tty_read(isdn_fd, "OK\r\n", ISDN_COMMAND_TIMEOUT, NULL)) + return -1; + return 0; +} + +/* + * stops audio mode (enter command mode) + * + * input: self_hangup: we want to hang up ourselves + * + * returns 0 on success, -1 otherwise + */ +int isdn_stop_audio(int isdn_fd, int self_hangup) { + int result = 0; + unsigned char abort_sending[] = {DLE, DC4, 0}; + unsigned char end_of_audio[] = {DLE, ETX, 0}; + + char *got; + + tty_clear(isdn_fd); + + if (self_hangup) { /* we want to hang up ourselves */ + if (tty_write(isdn_fd, end_of_audio)) { /* ETX - end of audio */ + fprintf(stderr, "Error sending ETX (End of audio).\n"); + return -1; + } + if (tty_write(isdn_fd, abort_sending)) {/* abort sending (request) (DC4) */ + fprintf(stderr, "Error sending DC4 (abort sending).\n"); + return -1; + } + if (tty_read(isdn_fd, end_of_audio, ISDN_COMMAND_TIMEOUT, NULL)) { + fprintf(stderr, "Error waiting for ETX (End of audio).\n"); + return -1; + } + if (tty_read(isdn_fd, "\r\n", ISDN_COMMAND_TIMEOUT, NULL)) { + fprintf(stderr, "Error getting line break.\n"); + return -1; + } + if (tty_read(isdn_fd, "\r\n", ISDN_COMMAND_TIMEOUT, &got)) { + fprintf(stderr, "Error getting new line.\n"); + } + if (!strstr(got, "VCON")) { + fprintf(stderr, "Error getting status.\n"); + result = -1; + } + free(got); + } else { /* remote side hangup */ + if (tty_write(isdn_fd, end_of_audio)) { /* ETX - end of audio */ + fprintf(stderr, "Error sending ETX (End of audio).\n"); + return -1; + } + /* there doesn't seem to come anything after remote hangup ... (?) */ + } + tty_clear(isdn_fd); + return result; +} + +/* + * hang up isdn device + * + * NOTE: assumes command mode + * + * returns 0 on success, -1 otherwise + */ +int isdn_hangup(int isdn_fd) { + tty_clear(isdn_fd); + if (tty_write(isdn_fd, "ATH\n")) + return -1; + if (tty_read(isdn_fd, "OK\r\n", ISDN_COMMAND_TIMEOUT, NULL)) + return -1; + tty_clear(isdn_fd); + return 0; +} + +/* + * Set isdn device to block mode, assuming in audio mode + * + * in blockmode, the minimum number of bytes possible to read from specified + * ttyI will be set to DEFAULT_ISDNBUF_SIZE and non blocking reads and writes + * will be enabled + * + * input: + * isdn_fd file descriptor + * flag 0 == off, 1 == on + * + * returns 0 on success, -1 otherwise + */ +int isdn_blockmode(int isdn_fd, int flag) { + struct termios settings; + int min, time; + int flags; + + flags = fcntl(isdn_fd, F_GETFL, 0); + if (flags == -1) { + perror("F_GETFL"); + return -1; + } + + if (flag) { + min = DEFAULT_ISDNBUF_SIZE; + time = 0; /* 10 == 1sec */ + flags |= O_NONBLOCK; /* select consumes much cpu time with this */ + } else { + min = 1; + time = 0; + flags &= ~O_NONBLOCK; + } + + if (fcntl(isdn_fd, F_SETFL, flags) == -1) { + perror("G_GETFL"); + return -1; + } + + if (tcgetattr(isdn_fd, &settings)) { + perror("isdn_blockmode, tcgetattr"); + return -1; + } + + settings.c_cc[VMIN] = min; + settings.c_cc[VTIME] = time; + + if (tcsetattr(isdn_fd, TCSANOW, &settings)) { + perror("isdn_blockmode, tcsetattr"); + return -1; + } + + /* verify */ + if (tcgetattr(isdn_fd, &settings)) + return -1; + if (settings.c_cc[VMIN] != min) { + fprintf(stderr,"Error setting block size. New block size: %d.\n", + settings.c_cc[VMIN]); + return -1; + } + + return 0; +} + +/* + * closes ttyI device and removes lock file + * + * returns 0 on success, -1 otherwise + */ +int close_isdn_device(int isdn_fd, char *isdn_device_name, + char *isdn_lockfile_name) { + if (close(isdn_fd)) { + return -1; + } + if (unlink(isdn_lockfile_name)) { + fprintf(stderr, "Removing isdn device lock file: unlink error.\n"); + return -1; + } + free(isdn_lockfile_name); + free(isdn_device_name); + return 0; +} + +/* + * dials specified number (voice call) + * (proper ttyI init is assumed) + * + * returns: + * 0 on success (VCON) + * 1 on busy + * -1 otherwise (error / timeout) + */ +int isdn_dial(int isdn_fd, char *number, int timeout) { + char *s; + int result; + char *got; + + if ((s = (char*) malloc(strlen(number) + 5))) { + + snprintf(s, strlen(number) + 5, "ATD%s\n", number); + tty_clear(isdn_fd); + result = tty_write(isdn_fd, s); + free(s); + if (result) { + fprintf(stderr, "Error dialing.\n"); + return -1; + } + } + + if (tty_read(isdn_fd, "\r\n", timeout, NULL)) /* error / timeout */ + return -1; + + if (tty_read(isdn_fd, "\r\n", ISDN_COMMAND_TIMEOUT, &got)) + return -1; + + if (strstr(got, "BUSY\r\n")) { + free(got); + return 1; + } + + if (strstr(got, "VCON\r\n")) { + free(got); + return 0; + } + + free(got); + return -1; /* failed somehow */ +} + +/* + * sets ttyI to full duplex mode + * (should be called directly after VCON) + * + * returns 0 on success, -1 otherwise + */ +int isdn_set_full_duplex(int isdn_fd) { + tty_clear(isdn_fd); + if (tty_write(isdn_fd, "AT+VRX+VTX\n")) + return -1; + return 0; +} + +/* + * returns the name of the calls file (originally just /var/lib/isdn/calls) + * on error, returns NULL + */ +char* isdn_get_calls_filename(void) { + unsigned int i; + int fd; + + if (isdn_calls_filename_from_config && + (fd = open(isdn_calls_filename_from_config, O_RDONLY)) != -1) + { + close(fd); + if (debug) + fprintf(stderr, + "Using calls file listed in I4L config.\n"); + return isdn_calls_filename_from_config; + } + for (i = 0; i < sizeof(calls_filenames) / sizeof(char*); i++) { + if ((fd = open(calls_filenames[i], O_RDONLY)) != -1) { + close(fd); + return calls_filenames[i]; + } + } + return NULL; +} + diff --git a/src/isdn.h b/src/isdn.h new file mode 100644 index 0000000..e305af5 --- /dev/null +++ b/src/isdn.h @@ -0,0 +1,67 @@ +/* + * ISDN handling functions + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "config.h" + +#ifdef HAVE_TERMIOS_H + #include +#endif + +#define LOCK_PATH "/var/lock" + +#define DEFAULT_ISDNBUF_SIZE 255 +#define ISDN_COMMAND_TIMEOUT 1 + +/* 0 (master MSN) or MSN to use as identification on outgoing calls */ +#define DEFAULT_MSN "0" + +/* "*" (wildcard) or comma-separated list of MSNs */ +#define DEFAULT_MSNS "*" + +#define ISDN_SPEED 8000 + +#define ETX 0x03 +#define DC4 0x14 +#define DLE 0x10 + +#define ISDN_CONFIG_FILENAME "/etc/isdn/isdn.conf" + +extern char* isdn_calls_filename_from_config; + +int open_isdn_device(char **isdn_device_name, char **isdn_lockfile_name); +int init_isdn_device(int isdn_fd, struct termios *backup); +int deinit_isdn_device(int isdn_fd, struct termios *backup); +int isdn_setMSN(int isdn_fd, char *msn); +int isdn_setMSNs(int isdn_fd, char *msns); +int isdn_stop_audio(int isdn_fd, int self_hangup); +int isdn_hangup(int isdn_fd); +int isdn_blockmode(int isdn_fd, int flag); +int close_isdn_device(int isdn_fd, char *isdn_device_name, + char *isdn_lockfile_name); +int isdn_dial(int isdn_fd, char *number, int timeout); +int isdn_set_full_duplex(int isdn_fd); +int tty_read(int fd, char *s, int timeout, char **got); +int tty_write(int fd, char *s); +int tty_clear(int fd); +char* isdn_get_calls_filename(void); + diff --git a/src/isdnlexer.h b/src/isdnlexer.h new file mode 100644 index 0000000..52a0cf7 --- /dev/null +++ b/src/isdnlexer.h @@ -0,0 +1,25 @@ +/* + * isdn4linux options file format additional lexer declarations + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +void isdn_lexer_init(char* filename); +void isdn_lexer_deinit(); diff --git a/src/isdnlexer.l b/src/isdnlexer.l new file mode 100644 index 0000000..13c138e --- /dev/null +++ b/src/isdnlexer.l @@ -0,0 +1,281 @@ +%option prefix="isdn_" +%option nounput +%{ +/* + * isdn4linux options file format lexer + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define YYSTYPE char* + +/* GNU headers */ +#include +#include + +/* own headers */ +#include "globals.h" +#include "isdnparser.h" +#include "isdnlexer.h" + +typedef struct isdn_include_t isdn_include_t; +struct isdn_include_t { + char* filename; + YYLTYPE location; + YY_BUFFER_STATE state; + isdn_include_t* next; +}; + +isdn_include_t* isdn_include_list; +char* isdn_filename; +YYLTYPE isdn_lloc; + +void isdn_locate(); +%} + +LETTER [a-zA-Z] +DIGIT [0-9] +STRING ([^ {}"\n]|\\\n)+ + +/* exclusive start condition for C-style comments */ +%x _INCLUDE_ +%x _VALUE_ +%% + +INCLUDE([ \t]|"\\\n")*"(" { + isdn_locate(); + BEGIN(_INCLUDE_); + } +<_INCLUDE_>[^ \t)]+ { /* got absolute or relative (to the current + * file) filename + */ + isdn_include_t* temp = (isdn_include_t*) + malloc(sizeof(isdn_include_t)); + isdn_include_t* i; /* iterator */ + int loop_detected; + FILE* temp_in; + + isdn_locate(); + temp->filename = isdn_filename; + temp->location = isdn_lloc; + temp->state = YY_CURRENT_BUFFER; + temp->next = isdn_include_list; + isdn_include_list = temp; + + if (isdn_text[0] == '/') { /* absolute path */ + isdn_filename = strdup(isdn_text); + } else { /* relative path */ + char* path1 = strdup(isdn_filename); /* old + name */ + char* path2 = dirname(path1); /* just dir */ + + asprintf(&isdn_filename, "%s/%s", + path2, isdn_text); + free(path1); + } + + /* loop detection */ + loop_detected = 0; + for (i = isdn_include_list; + i != NULL && !loop_detected; + i = i->next) + { + if (!strcmp(i->filename, isdn_filename)) + loop_detected = 1; + } + + if (loop_detected || + !(temp_in = fopen(isdn_filename, "r"))) + { + /* ignoring non-existent included file */ + if (debug) { + if (loop_detected) + fprintf(stderr, "Loop detected "); + else + fprintf(stderr, "Error "); + fprintf(stderr, + "reading ISDN options file %s " + "from %s. Ignoring.\n", + isdn_filename, temp->filename); + } + /* recover to old buffer */ + free(isdn_filename); + isdn_filename = temp->filename; + isdn_include_list = temp->next; + free(temp); + } else { + /* include file OK */ + isdn_in = temp_in; + if (debug) + fprintf(stderr, + "Reading options file %s " + "from %s ...\n", + isdn_filename, temp->filename); + yy_switch_to_buffer( + yy_create_buffer(isdn_in, YY_BUF_SIZE)); + BEGIN(INITIAL); + isdn_lloc.first_line = 1; + isdn_lloc.last_line = 1; + isdn_lloc.first_column = 1; + isdn_lloc.last_column = 1; + } + } +<> { /* end of current file */ + if (!isdn_include_list) { /* last buffer */ + yyterminate(); + } else { /* restore previous buffer */ + isdn_include_t* temp = isdn_include_list; + + if (debug) + fprintf(stderr, "Returning to %s ...\n", + temp->filename); + yy_delete_buffer(YY_CURRENT_BUFFER); + yy_switch_to_buffer(temp->state); + BEGIN(_INCLUDE_); + isdn_lloc = temp->location; + free(isdn_filename); + isdn_filename = temp->filename; + isdn_include_list = temp->next; + free(temp); + } + } +<_INCLUDE_>[ \t]+ { /* eat whitespace in _INCLUDE_ mode */ + isdn_locate(); + } +<_INCLUDE_>")" { /* return to normal mode */ + isdn_locate(); + BEGIN(INITIAL); + } +{LETTER}+({DIGIT}|{LETTER})* { /* NAME */ + isdn_locate(); + isdn_lval = strdup(isdn_text); + return ISDN_TOKEN_NAME; + } +<_VALUE_>([ \t]|"\\\n")+ { /* whitespace */ + isdn_locate(); + } +<_VALUE_>"{" { /* subsection begin */ + isdn_locate(); + BEGIN(INITIAL); + return *isdn_text; + } +<_VALUE_>(""|{STRING}(([ \t]|"\\\n")+{STRING})*)\n { /* VALUE */ + isdn_locate(); + isdn_lval = strdup(isdn_text); + isdn_lval = realloc(isdn_lval, + strlen(isdn_text)); + isdn_lval[strlen(isdn_text) - 1] = '\0'; + BEGIN(INITIAL); + return ISDN_TOKEN_VALUE; + } +<_VALUE_>\"[^"]*\"([ \t]|"\\\n")*\n { /* quoted VALUE */ + int len = strchr(isdn_text + 1, '"') - isdn_text; + + isdn_locate(); + isdn_lval = (char *)malloc(len); + strncpy(isdn_lval, isdn_text + 1, len - 1); + isdn_lval[len - 1] = '\0'; + BEGIN(INITIAL); + return ISDN_TOKEN_VALUE; + } +"#".* { /* eat up comments */ + isdn_locate(); + } +"=" { + isdn_locate(); + BEGIN(_VALUE_); + return *isdn_text; + } +([ \t]|"\\\n")+ { /* eat up whitespace */ + isdn_locate(); + } +("}"|"["|"]") { /* subsection end or NAME bracket */ + isdn_locate(); + return *isdn_text; + } +\n { /* real new line */ + isdn_locate(); + } +. { /* eat up rest */ + isdn_locate(); + if (debug) { + fprintf(stderr, + "isdnlexer: Unrecognized character: %c " + "at %d:%d\n", + *isdn_text, + isdn_lloc.first_line, + isdn_lloc.first_column); + } + } + +%% + +/* For portability's sake */ +int isdn_wrap() { return 1; } + +/* + * adjusts isdn_lloc according to isdn_text + */ +void isdn_locate() { + char* temp; + + isdn_lloc.first_line = isdn_lloc.last_line; + isdn_lloc.first_column = isdn_lloc.last_column; + + for (temp = yytext; *temp != '\0'; temp++) { + if (*temp == '\n') { + ++ isdn_lloc.last_line; + isdn_lloc.last_column = 1; + } else { + ++ isdn_lloc.last_column; + } + } +} + +/* + * to be called directly before the parser run + * + * on success, isdn_in contains valid FILE* handle, else NULL + */ +void isdn_lexer_init(char* filename) { + isdn_lloc.first_line = 1; + isdn_lloc.first_column = 1; + isdn_lloc.last_line = 1; + isdn_lloc.last_column = 1; + isdn_include_list = NULL; + if (debug) + fprintf(stderr, "Reading options file: %s ...\n", filename); + if (!(isdn_in = fopen(filename, "r"))) { + fprintf(stderr, "Error opening options file %s.\n", filename); + } else { + isdn_filename = strdup(filename); + } +} + +/* + * to be called directly after the parser run + */ +void isdn_lexer_deinit() { + if (fclose(isdn_in) == EOF) { + fprintf(stderr, "Warning: Couldn't close options file.\n"); + } + free(isdn_filename); +} + diff --git a/src/isdnparser.y b/src/isdnparser.y new file mode 100644 index 0000000..17868d4 --- /dev/null +++ b/src/isdnparser.y @@ -0,0 +1,178 @@ +%name-prefix="isdn_" +%{ +/* + * isdn4linux options file format parser + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* regular GNU system includes */ +#include +#include + +/* own header files */ +#include "globals.h" +#include "util.h" +#include "settings.h" +#include "isdntree.h" + +typedef struct isdn_list_store_t isdn_list_store_t; +struct isdn_list_store_t { + isdn_tree_node_t* list; /* list itself (start) */ + isdn_tree_node_t** last; /* pointer to pointer to last element */ + /* (which in turn should always be NULL) */ +}; + +int isdn_lex(void); +void isdn_error(const char *message); +%} + +/* types of semantic values */ +%union { + char* s; + isdn_list_store_t list; + isdn_tree_node_t* element; +} + +/* terminal symbols */ +%token ISDN_TOKEN_NAME +%token ISDN_TOKEN_VALUE + +/* non terminal symbols */ +%type config; +%type sections; +%type section; +%type entries; +%type entry; +%type value; + +%% + +config : entries sections + { + if ($1.list == NULL) { + $$ = $2; + } else { + $$.list = $1.list; + *$1.last = $2.list; + $$.last = $2.last; + } + isdn_tree = $$.list; + } +; + +sections : { $$.list = NULL; $$.last = NULL; } + | sections section + { + if ($1.list == NULL) { + $$.list = $2; + $$.last = &$2->next; + } else { + $$.list = $1.list; + *$1.last = $2; + $$.last = &$2->next; + } + } +; + +section : '[' ISDN_TOKEN_NAME ']' entries + { + if (!($$ = + (isdn_tree_node_t*) malloc(sizeof(isdn_tree_node_t)))) + { + fprintf(stderr, "Error: Out of memory.\n"); + exit(1); + } + $$->type = ISDN_NODE_TYPE_SECTION; + $$->name = $2; + $$->content.section = $4.list; + /* finally: only list needed */ + $$->next = NULL; + } +; + +entries : { $$.list = NULL; $$.last = NULL; } + | entries entry + { + if ($1.list == NULL) { + $$.list = $2; + $$.last = &$2->next; + } else { + $$.list = $1.list; + *$1.last = $2; + $$.last = &$2->next; + } + } + | entries error + { + fprintf(stderr, "Error region from %d:%d up to %d:%d.\n", + @2.first_line, @2.first_column, + @2.last_line, @2.last_column); + $$ = $1; + } +; + +entry : ISDN_TOKEN_NAME '=' value + { + if (!($$ = + (isdn_tree_node_t*) malloc(sizeof(isdn_tree_node_t)))) + { + fprintf(stderr, "Error: Out of memory.\n"); + exit(1); + } + $$->type = ISDN_NODE_TYPE_ENTRY; + $$->name = $1; + $$->content.value = $3; + $$->next = NULL; + } + | ISDN_TOKEN_NAME '=' '{' config '}' + { + if (!($$ = + (isdn_tree_node_t*) malloc(sizeof(isdn_tree_node_t)))) + { + fprintf(stderr, "Error: Out of memory.\n"); + exit(1); + } + $$->type = ISDN_NODE_TYPE_SUBSECTION; + $$->name = $1; + $$->content.subsection = $4.list; + /* finally: only list needed */ + $$->next = NULL; + } +; + +value : ISDN_TOKEN_VALUE + | ISDN_TOKEN_NAME +; + +%% + +/* + * callback for yyparse(), (also) called on errors (hopefully) handled + * by error token actions in grammar, but not if errors occur to + * often (bison needs 3 "correct" tokens to recover) + */ +void isdn_error(const char *message) { + if (debug) + fprintf(stderr, + "Warning: Parsing isdn options file: %d:%d: %s.\n", + isdn_lloc.first_line, isdn_lloc.first_column, message); +} + diff --git a/src/isdntree.c b/src/isdntree.c new file mode 100644 index 0000000..774918e --- /dev/null +++ b/src/isdntree.c @@ -0,0 +1,105 @@ +/* + * isdn4linux options file tree support + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* GNU headers */ +#include +#include + +/* own headers */ +#include "isdntree.h" + +isdn_tree_node_t* isdn_tree; + +/* + * helper function for isdn_tree_dump recursively dumping the tree + */ +static void isdn_tree_dump_list(isdn_tree_node_t* list, int indent) { + while (list != NULL) { + switch (list->type) { + case ISDN_NODE_TYPE_ENTRY: + printf("%*sEntry \"%s\" => \"%s\"\n", + indent, "", list->name, list->content.value); + break; + case ISDN_NODE_TYPE_SECTION: + printf("%*sSection [%s]:\n", + indent, "", list->name); + isdn_tree_dump_list(list->content.section, indent + 2); + break; + case ISDN_NODE_TYPE_SUBSECTION: + printf("%*sSubsection \"%s\":\n", + indent, "", list->name); + isdn_tree_dump_list(list->content.subsection, indent + 2); + break; + default: + fprintf(stderr, "Unknown ISDN_NODE_TYPE\n"); + } + + list = list->next; + } +} + +/* + * dump whole tree to stdout + */ +void isdn_tree_dump() { + printf("ISDN config dump:\n"); + isdn_tree_dump_list(isdn_tree, 2); +} + +/* + * helper for isdn_tree_free + * -> recursive release of memory from tree + */ +static void isdn_tree_free_list(isdn_tree_node_t* list) { + while (list != NULL) { + isdn_tree_node_t* temp; + + free(list->name); + + switch (list->type) { + case ISDN_NODE_TYPE_ENTRY: + free(list->content.value); + break; + case ISDN_NODE_TYPE_SECTION: + isdn_tree_free_list(list->content.section); + break; + case ISDN_NODE_TYPE_SUBSECTION: + isdn_tree_free_list(list->content.subsection); + break; + default: + fprintf(stderr, "Unknown ISDN_NODE_TYPE\n"); + } + + temp = list->next; + free(list); + list = temp; + } +} + +/* + * cleans up: releases all memory associated with tree + */ +void isdn_tree_free() { + isdn_tree_free_list(isdn_tree); +} + diff --git a/src/isdntree.h b/src/isdntree.h new file mode 100644 index 0000000..539d702 --- /dev/null +++ b/src/isdntree.h @@ -0,0 +1,55 @@ +/* + * isdn4linux options file tree support + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ISDNTREE_H +#define _ISDNTREE_H + +typedef enum isdn_node_type_t isdn_node_type_t; +typedef union isdn_node_value_t isdn_node_value_t; +typedef struct isdn_tree_node_t isdn_tree_node_t; + +enum isdn_node_type_t { + ISDN_NODE_TYPE_ENTRY, + ISDN_NODE_TYPE_SECTION, + ISDN_NODE_TYPE_SUBSECTION +}; + +union isdn_node_value_t { + char* value; + isdn_tree_node_t* section; + isdn_tree_node_t* subsection; +}; + +struct isdn_tree_node_t { + isdn_node_type_t type; + char* name; + isdn_node_value_t content; + isdn_tree_node_t* next; /* it's actually a list */ +}; + +extern isdn_tree_node_t* isdn_tree; + +void isdn_tree_dump(); +void isdn_tree_free(); + +#endif /* _ISDNTREE_H */ diff --git a/src/llcheck.c b/src/llcheck.c new file mode 100644 index 0000000..febd821 --- /dev/null +++ b/src/llcheck.c @@ -0,0 +1,468 @@ +/* + * line level checker functions + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "config.h" + +/* regular GNU system includes */ +#include +#ifdef HAVE_STDLIB_H + #include +#endif +#ifdef HAVE_UNISTD_H + #include +#endif +#include + +/* GTK */ +#include + +/* own header files */ +#include "globals.h" +#include "llcheck.h" +#include "session.h" +#include "gtk.h" + +/* constants */ + +/* number of milliseconds for history */ +#define HISTORY_TIME 1500 + +/* + * the chain link type for the maximum history + */ +struct history_t { + double value; + struct history_t *next; +}; + +/* + * return an empty (all zero) history of fixed size (10) + */ +struct history_t *history_new(void) { + struct history_t *root = NULL; + struct history_t *temp; + int i; + + for (i = 0; i < 10; i++) { + temp = root; + root = (struct history_t *)malloc(sizeof(struct history_t)); + root->value = 0.0; + root->next = temp; + } + + return root; +} + +/* + * free memory allocated for history + */ +void history_free(struct history_t *history) { + while (history != NULL) { + struct history_t *next = history->next; + free(history); + history = next; + } +} + +/* + * appends x to history (rotating) and returns maximum value in whole history + * + * NOTE: history is assumed to be non-empty + */ +double history_append(struct history_t **history, double x) { + double result = x; + struct history_t **hist = &(*history)->next; + + /* get new maximum */ + while (*hist != NULL) { + if ((*hist)->value > result) + result = (*hist)->value; + hist = &(*hist)->next; + } + + /* append */ + *hist = *history; /* hist is ** to last element -> append old first one */ + *history = (*history)->next; + (*hist)->next = NULL; + (*hist)->value = x; + + return result; +} + +/* + * sets history to all zero + */ +void history_reset(struct history_t *history) { + while (history) { + history->value = 0.0; + history = history->next; + } +} + +/* + * called when OK button is clicked + */ +static void llcheck_quit(GtkObject *window) { + session_t *session = gtk_object_get_data(window, "session"); + GtkWidget *bar = gtk_object_get_data(window, "bar"); + + /* remove own and restore old handlers */ + gtk_input_remove(session->gtk_audio_input_tag); + session_io_handlers_start(session); + + /* stop effect */ + session_effect_stop(session); + + llcheck_bar_deinit(bar); + + gtk_widget_destroy(GTK_WIDGET(window)); + session_set_state(session, STATE_READY); +} + +/* + * gdk callback on audio input + * + * input: widget: the llcheck_bar + */ +static void llcheck_handle_audio_input(gpointer widget, gint fd _U_, + GdkInputCondition condition _U_) { + session_t *session = gtk_object_get_data(widget, "session"); + int i, got; + int max = 0; + unsigned char sample; + + got = read(session->audio_fd_in, session->audio_inbuf, + session->fragment_size_in); + + if (got != -1) { + for (i = 0; i < got; + i += session->audio_sample_size_in) { + + if (session->audio_sample_size_in == 1) { + sample = session->audio_LUT_analyze[ + session->audio_LUT_out[(int)(session->audio_inbuf[i])]]; + } else { /* audio_sample_size == 2 */ + /* multiple byte samples are used "little endian" in int + to look up in LUT (see mediation_makeLUT) */ + sample = session->audio_LUT_analyze[ + session->audio_LUT_out[(int)(session->audio_inbuf[i]) | + (int)(session->audio_inbuf[i+1]) << 8]]; + } + + if (abs((int)sample - 128) > max) + max = abs((int)sample - 128); + } + + llcheck_bar_set(widget, (double)max / 128); + + } else { + switch (errno) { + case EAGAIN: + fprintf(stderr, + "llcheck_handle_audio_input: " + "EAGAIN - no data immediately available.\n"); + break; + case EBADF: + fprintf(stderr, + "llcheck_handle_audio_input: " + "EBADF - invalid file descriptor.\n"); + break; + case EINTR: + fprintf(stderr, + "llcheck_handle_audio_input: EINTR - interrupted by signal.\n"); + break; + case EIO: + fprintf(stderr, + "llcheck_handle_audio_input: EIO - hardware error.\n"); + break; + } + } +} + +/* + * called when sound is requested in level check window + * + * input: widget: (play) button + * data: session pointer + */ +static void llcheck_play(GtkWidget *widget, gpointer data) { + session_t *session = (session_t *)data; + GtkWidget *bar = gtk_object_get_data(GTK_OBJECT(widget), "bar"); + + if (session->effect != EFFECT_NONE) { /* already playing -> stop feeding */ + gtk_input_remove(session->effect_tag); + } + + /* carefully reset audio */ + gtk_input_remove(session->gtk_audio_input_tag); + session_reset_audio(session); + session->gtk_audio_input_tag = gtk_input_add_full(session->audio_fd_in, + GDK_INPUT_READ, + llcheck_handle_audio_input, + NULL, + (gpointer) bar, + NULL); + + /* start recording (again) */ + read(session->audio_fd_in, session->audio_inbuf, + session->fragment_size_in); + + /* finally, start playing */ + session_effect_start(session, EFFECT_TEST); +} + +/* + * Returns a line level check bar + * input: width, height: size of the whole widget + * r, g, b: color of bright bar, dark bar will be some derivative + * of it + * + */ +GtkWidget *llcheck_bar_new(gint width, gint height, + unsigned char r, unsigned char g, unsigned char b) { + GtkWidget *progress_bar; + GtkWidget *bar; + GtkRcStyle *style; + GdkColor color; + + /* the result to prepare */ + bar = gtk_hbox_new(FALSE, 0); + gtk_widget_set_size_request(bar, width, height); + gtk_object_set_data(GTK_OBJECT(bar), "width", GINT_TO_POINTER(width)); + + /* progress bar: fast/slow relation progressbar */ + progress_bar = gtk_progress_bar_new(); + style = gtk_rc_style_new(); + + style->color_flags[GTK_STATE_PRELIGHT] = GTK_RC_BG; + color.red = r * 257; color.green = g * 257; color.blue = b * 257; + gdk_colormap_alloc_color(gtk_widget_get_colormap(bar), &color, + TRUE, TRUE); + style->bg[GTK_STATE_PRELIGHT] = color; + + style->color_flags[GTK_STATE_NORMAL] = GTK_RC_BG; + color.red = r * 257 * 2 / 3; + color.green = g * 257 * 2 / 3; + color.blue = b * 257 * 2 / 3; + gdk_colormap_alloc_color(gtk_widget_get_colormap(bar), &color, + TRUE, TRUE); + style->bg[GTK_STATE_NORMAL] = color; + + gtk_widget_modify_style(progress_bar, style); + gtk_rc_style_unref(style); + gtk_progress_set_percentage(GTK_PROGRESS(progress_bar), 0.0); /* 0..1 */ + gtk_object_set_data(GTK_OBJECT(bar), "pbar1", (gpointer) progress_bar); + gtk_widget_set_size_request(progress_bar, 1, -1); /* 1..width-1 */ + gtk_box_pack_start(GTK_BOX(bar), progress_bar, TRUE, TRUE, 0); + gtk_widget_show(progress_bar); + + /* progress bar: rest */ + progress_bar = gtk_progress_bar_new(); + style = gtk_rc_style_new(); + style->color_flags[GTK_STATE_NORMAL] = GTK_RC_BG; + color.red = r * 257 / 3; + color.green = g * 257 / 3; + color.blue = b * 257 / 3; + gdk_colormap_alloc_color(gtk_widget_get_colormap(bar), &color, + TRUE, TRUE); + style->bg[GTK_STATE_NORMAL] = color; + gtk_widget_modify_style(progress_bar, style); + gtk_rc_style_unref(style); + gtk_progress_set_percentage(GTK_PROGRESS(progress_bar), 0.0); + gtk_widget_set_size_request(progress_bar, width - 1, -1); /* 1..width-1 */ + gtk_object_set_data(GTK_OBJECT(bar), "pbar2", (gpointer) progress_bar); + gtk_object_set_data(GTK_OBJECT(bar), "history", (gpointer) history_new()); + gtk_box_pack_start(GTK_BOX(bar), progress_bar, TRUE, TRUE, 0); + gtk_widget_show(progress_bar); + + return bar; +} + +/* + * set state of line level check bar and update maximum history + * + * input: bar: llcheck_bar + * max: the current maximum (0.0 <= max <= 1.0) + */ +void llcheck_bar_set(GtkWidget *bar, double max) { + /* the maximum area */ + GtkWidget *pbar1 = + (GtkWidget *)gtk_object_get_data(GTK_OBJECT(bar), "pbar1"); + /* the dark area */ + GtkWidget *pbar2 = + (GtkWidget *)gtk_object_get_data(GTK_OBJECT(bar), "pbar2"); + struct history_t *history = + (struct history_t *)gtk_object_get_data(GTK_OBJECT(bar), "history"); + double maxmax = history_append(&history, max); + int width = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(bar), "width")); + /* saving additional width + (bar->allocation.width is valid only with shown widgets) */ + int pbar1size; + double percentage; + + gtk_object_set_data(GTK_OBJECT(bar), "history", history); + + pbar1size = maxmax * (width - 2) + 1; + gtk_widget_set_size_request(pbar1, pbar1size, -1); + gtk_widget_set_size_request(pbar2, width - pbar1size, -1); + percentage = maxmax > 0.0 ? max / maxmax : 0.0; + gtk_progress_set_percentage(GTK_PROGRESS(pbar1), percentage); +} + +/* + * set line level check bar to all zero (history included); + */ +void llcheck_bar_reset(GtkWidget *bar) { + struct history_t *history = + (struct history_t *)gtk_object_get_data(GTK_OBJECT(bar), "history"); + + history_reset(history); + llcheck_bar_set(bar, 0.0); +} + +/* + * deinit bar (free history mem ...) + */ +void llcheck_bar_deinit(GtkWidget *bar) { + struct history_t *history = gtk_object_get_data(GTK_OBJECT(bar), "history"); + history_free(history); +} + +/* + * The Line level check callback + * -> displays dialog window with level check bar and play button + * -> modal + */ +void llcheck(GtkWidget *widget _U_, gpointer data, guint action _U_) { + session_t *session = (session_t *) data; + + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *button_box; + GtkWidget *button; + GtkWidget *label; + GtkWidget *bar; + + /* set to service state -> open audio device */ + if (!session_set_state(session, STATE_SERVICE)) { + + /* the window itself */ + window = gtk_dialog_new(); + gtk_window_set_title(GTK_WINDOW(window), _("Line Level Check")); + + gtk_object_set(GTK_OBJECT(window), "allow_shrink", FALSE, NULL); + gtk_object_set(GTK_OBJECT(window), "allow_grow", FALSE, NULL); + + /* new big vbox */ + vbox = gtk_vbox_new(FALSE, 10); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->vbox), vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 10); + gtk_widget_show(vbox); + + /* message label */ + label = gtk_label_new(_("Please check the line input level\n" + "and adjust it using your favorite\n" + "mixer application.\n" + "You can also play a sound\n" + "to test the sound output.")); + gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); + gtk_box_pack_start(GTK_BOX(vbox), label, + FALSE, FALSE, 0); + gtk_widget_show(label); + + /* the line level check bar */ + bar = llcheck_bar_new(300, 20, 200, 0, 0); + gtk_box_pack_start(GTK_BOX(vbox), bar, FALSE, FALSE, 0); + gtk_widget_show(bar); + + /* action area */ + button_box = gtk_hbutton_box_new(); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->action_area), + button_box); + gtk_widget_show(button_box); + + /* the play button */ + button = gtk_button_new_with_label(_("Play sound")); + gtk_box_pack_start_defaults(GTK_BOX(button_box), button); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(llcheck_play), + (gpointer) session ); + gtk_widget_show(button); + + /* save session in window (quit(): audio handling) */ + gtk_object_set_data(GTK_OBJECT(window), "session", (gpointer) session); + /* save bar in window (quit(): destroy) */ + gtk_object_set_data(GTK_OBJECT(window), "bar", (gpointer) bar); + /* save session in bar widget (input handling) */ + gtk_object_set_data(GTK_OBJECT(bar), "session", (gpointer) session); + /* save bar in button (in case play button is pressed) */ + gtk_object_set_data(GTK_OBJECT(button), "bar", (gpointer) bar); + + /* the OK button */ + button = gtk_button_new_with_label(_("OK")); + gtk_box_pack_start_defaults(GTK_BOX(button_box), button); + + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(llcheck_quit), GTK_OBJECT(window)); + /* handler for kill function of window */ + gtk_signal_connect_object(GTK_OBJECT(window), "delete_event", + GTK_SIGNAL_FUNC(llcheck_quit), GTK_OBJECT(window)); + + gtk_widget_show(button); + + gtk_window_set_modal(GTK_WINDOW(window), TRUE); + + /* remove old and set up own audio input handler */ + session_io_handlers_stop(session); + session->gtk_audio_input_tag = gtk_input_add_full(session->audio_fd_in, + GDK_INPUT_READ, + llcheck_handle_audio_input, + NULL, + (gpointer) bar, + NULL); + + read(session->audio_fd_in, session->audio_inbuf, /* start recording */ + session->fragment_size_in); + + /* show everything */ + gtk_widget_show(window); + } else { + show_audio_error_dialog(); + } +} + +/* called when line levels view check button is toggled */ +void llcheck_toggle_cb(GtkWidget *widget _U_, gpointer data, guint action _U_) { + session_t *session = (session_t *) data; + + if (GTK_CHECK_MENU_ITEM (session->llcheck_check_menu_item)->active) { + gtk_widget_show(session->llcheck); + session->option_show_llcheck = 1; + } else { + gtk_widget_hide(session->llcheck); + session->option_show_llcheck = 0; + /* shrink if no growing callerid monitor present */ + if (!session->option_show_callerid) + gtk_window_resize(GTK_WINDOW(session->main_window), 1, 1); + } +} diff --git a/src/llcheck.h b/src/llcheck.h new file mode 100644 index 0000000..954280d --- /dev/null +++ b/src/llcheck.h @@ -0,0 +1,30 @@ +/* + * line level checker functions + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +GtkWidget *llcheck_bar_new(gint width, gint height, + unsigned char r, unsigned char g, unsigned char b); +void llcheck_bar_set(GtkWidget *bar, double max); +void llcheck_bar_reset(GtkWidget *bar); +void llcheck_bar_deinit(GtkWidget *bar); +void llcheck(GtkWidget *widget, gpointer data, guint action); +void llcheck_toggle_cb(GtkWidget *widget, gpointer data, guint action); diff --git a/src/mediation.c b/src/mediation.c new file mode 100644 index 0000000..52832eb --- /dev/null +++ b/src/mediation.c @@ -0,0 +1,466 @@ +/* + * functions for mediation between ISDN and OSS + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * + * NOTE: + * * for performance reasons, separate recording buffers are filled while + * mediating + */ + +#include "config.h" + +/* regular GNU system includes */ +#include +#ifdef HAVE_STDLIB_H + #include +#endif +#ifdef HAVE_UNISTD_H + #include +#endif +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include + +/* own header files */ +#include "globals.h" +#include "session.h" +/* ulaw conversion (LUT) */ +#include "g711.h" +#include "isdn.h" +#include "sound.h" +#include "util.h" +#include "mediation.h" +#include "llcheck.h" +#include "fxgenerator.h" +#include "recording.h" + +/* + * allocate memory and build look-up-tables for audio <-> isdn conversion + * + * input: + * format_in, LUT_in: used audio format and pointer to look-up-table + * for conversion of isdn -> audio + * format_out, LUT_out: the same for audio -> isdn + * LUT_generate: table for conversion of 8 bit unsigned -> isdn + * LUT_analyze: table for conversion of isdn -> 8 bit unsigned + * + * return: 0 on success, -1 otherwise + * + * NOTE: the caller has to free the memory of LUT_* itself + */ +int mediation_makeLUT(int format_in, unsigned char **LUT_in, + int format_out, unsigned char **LUT_out, + unsigned char **LUT_generate, + unsigned char **LUT_analyze, + short **LUT_ulaw2short) { + int sample_size_in; + int sample_size_out; + int buf_size_in; + int buf_size_out; + int sample; + int i; + short s; + + /* Allocation */ + sample_size_in = sample_size_from_format(format_in); /* isdn -> audio */ + if (sample_size_in == 0 || + !(*LUT_in = (unsigned char *)malloc(buf_size_in = sample_size_in * 256))) + return -1; + + sample_size_out = sample_size_from_format(format_out); /* audio -> isdn */ + if (sample_size_out == 0 || + !(*LUT_out = + (unsigned char *)malloc(buf_size_out = + (1 + (sample_size_out - 1) * 255) * 256))) + return -1; + + if (!(*LUT_generate = (unsigned char*) malloc (256))) + return -1; + if (!(*LUT_analyze = (unsigned char*) malloc (256))) + return -1; + if (!(*LUT_ulaw2short = (short*) malloc (256*sizeof(short)))) + return -1; + + /* Calculation */ + for (i = 0; i < buf_size_in; i += sample_size_in) { /* isdn -> audio */ + switch(format_in) { + case AFMT_U8: + (*LUT_in)[i] = (unsigned char)((ulaw2linear((unsigned char)i) / 256 & + 0xff) ^ 0x80); + break; + + case AFMT_S8: + (*LUT_in)[i] = (unsigned char)(ulaw2linear((unsigned char)i) / 256 & + 0xff); + break; + + case AFMT_MU_LAW: + (*LUT_in)[i] = (unsigned char)i; + break; + + case AFMT_S16_LE: + sample = ulaw2linear((unsigned char)(i / 2)); + (*LUT_in)[i] = (unsigned char)(sample & 0xff); + (*LUT_in)[i+1] = (unsigned char)(sample >> 8 & 0xff); + break; + + case AFMT_S16_BE: + sample = ulaw2linear((unsigned char)(i / 2)); + (*LUT_in)[i+1] = (unsigned char)(sample & 0xff); + (*LUT_in)[i] = (unsigned char)(sample >> 8 & 0xff); + break; + + case AFMT_U16_LE: + sample = ulaw2linear((unsigned char)(i / 2)); + (*LUT_in)[i] = (unsigned char)(sample & 0xff); + (*LUT_in)[i+1] = (unsigned char)((sample >> 8 & 0xff) ^ 0x80); + break; + + case AFMT_U16_BE: + sample = ulaw2linear((unsigned char)(i / 2)); + (*LUT_in)[i+1] = (unsigned char)(sample & 0xff); + (*LUT_in)[i] = (unsigned char)((sample >> 8 & 0xff) ^ 0x80); + break; + + default: + fprintf(stderr, + "Error: " + "Unsupported format appeared while building input LUT.\n"); + return -1; + } + } + + for (i = 0; i < buf_size_out; i++) { /* audio -> isdn */ + switch(format_out) { + case AFMT_U8: + (*LUT_out)[i] = linear2ulaw((i - 128) * 256); + break; + + case AFMT_S8: + (*LUT_out)[i] = linear2ulaw(i * 256); + break; + + case AFMT_MU_LAW: + (*LUT_out)[i] = (unsigned char)i; + break; + + /* next 4 cases: + input int i stores first buffer byte in low byte */ + case AFMT_S16_LE: + (*LUT_out)[i] = linear2ulaw((int)(signed char)(i >> 8) << 8 | + (int)(i & 0xff)); + break; + + case AFMT_S16_BE: + (*LUT_out)[i] = linear2ulaw((int)(signed char)(i & 0xff) << 8 | + (int)(i >> 8)); + break; + + case AFMT_U16_LE: + (*LUT_out)[i] = linear2ulaw(i - 32768); + break; + + case AFMT_U16_BE: + (*LUT_out)[i] = linear2ulaw(((i & 0xff) << 8 | i >> 8) - 32768); + break; + + default: + fprintf(stderr, + "Error: " + "Unsupported format appeared while building output LUT.\n"); + return -1; + } + } + + for (i = 0; i < 256; i++) { /* 8 bit unsigned -> isdn -> 8 bit unsigned */ + (*LUT_generate)[i] = linear2ulaw((i - 128) * 256); + (*LUT_ulaw2short)[i] = s = ulaw2linear((unsigned char)i); /* ulaw->short */ + (*LUT_analyze)[i] = (unsigned char)((s / 256 & 0xff) ^ 0x80); + } + + return 0; +} + +/* + * writes buffer carefully out to file (ttyI / audio device) + * + * returns 0 on success, -1 otherwise (write error) + */ +int write_buf(int fd, unsigned char *outbuf, int outbuf_size) { + int towrite = outbuf_size; + int written = 0; + + /* write until everything has been written */ + while (towrite && (written != -1 || errno == EAGAIN)) { + written = write(fd, &outbuf[outbuf_size - towrite], towrite); + if (debug >= 2) + fprintf(stderr, "Wrote %d bytes to device.\n", written); + if (written != -1) + towrite -= written; + else + if (errno == EAGAIN) { + if (debug) + fprintf(stderr, "write_buf: EAGAIN\n"); + ant_sleep(SHORT_INTERVAL); + } + } + if (written == -1) { + perror("write_buf"); + return -1; + } + return 0; +} + +/* XXX: smooth samples when converting speeds in next 2 functions */ + +/* + * process isdn input from ttyI to sound device + * + * to be called after select found block to read in isdn file descriptor + */ +void process_isdn_source(session_t *session) { + int got, i, j; + unsigned char inbyte; /* byte read from ttyI */ + int to_process; /* number of samples to process + (according to ratio / ratio_support_count) */ + unsigned char sample; /* 8 bit unsigned sample */ + int max = 0; /* for llcheck */ + + short s; /* libsndfile sample data */ + + got = read(session->isdn_fd, session->isdn_inbuf, + session->isdn_inbuf_size); + + if (debug >= 2) + fprintf(stderr, "From isdn: got %d bytes.\n", got); + + if (got != -1) { + for (i = 0; i < got; i++) { + inbyte = session->isdn_inbuf[i]; + if (!session->escape == (inbyte != DLE)) { + /* normal mode or last byte was an escape in DLE mode */ + + /* input line level check */ + sample = session->audio_LUT_analyze[inbyte]; + if (abs((int)sample - 128) > max) + max = abs((int)sample - 128); + + /* recording */ + if (session->option_record) { + if (session->option_record_remote) + s = session->audio_LUT_ulaw2short[inbyte]; + else + s = 0; + session->rec_buf_remote[session->rec_buf_remote_index++] = s; + if (session->rec_buf_remote_index >= session->rec_buf_remote_size) { + if (recording_write(session->recorder, session->rec_buf_remote, + session->rec_buf_remote_size, RECORDING_REMOTE)) + fprintf(stderr, "Warning: Recording (remote) error.\n"); + session->rec_buf_remote_index = 0; + } + } + + /* touchtone to audio: after llcheck to monitor other end */ + if (session->touchtone_countdown_audio > 0) { + inbyte = fxgenerate(session, EFFECT_TOUCHTONE, + session->touchtone_index, + (double)session->touchtone_countdown_audio / + ISDN_SPEED); /* playing reverse is ok */ + session->touchtone_countdown_audio--; + } + + /* mediation */ + to_process = (int)floor((double)(session->samples_in + 1) * + session->ratio_in) - + (int)floor((double)session->samples_in * + session->ratio_in); + /* printf("isdn -> audio: to_process == %d\n", to_process); */ + for (j = 0; j < to_process; j++) { + if (session->audio_sample_size_out == 1) { + session->audio_outbuf[session->audio_outbuf_index++] = + session->audio_LUT_in[(int)inbyte]; + } else { /* audio_sample_size == 2 */ + session->audio_outbuf[session->audio_outbuf_index++] = + session->audio_LUT_in[(int)inbyte * 2]; + session->audio_outbuf[session->audio_outbuf_index++] = + session->audio_LUT_in[(int)inbyte * 2 + 1]; + } + if (session->audio_outbuf_index >= session->fragment_size_out) { + if (write_buf(session->audio_fd_out, session->audio_outbuf, + session->fragment_size_out)) + session->aborted = 1; + session->audio_outbuf_index = 0; + } + } + + session->samples_in++; + + if (session->escape) { + session->escape = 0; + if (debug) fprintf(stderr, "debug: escape mode off after 2x DLE.\n"); + } + } else if (!session->escape && inbyte == DLE) { /* new escape: DLE */ + session->escape = 1; + if (debug) + fprintf(stderr, "debug: ttyI DLE escape mode on.\n"); + } else /* i.e. if (*escape) */ { + if (inbyte == DC4 || inbyte == ETX) { + session->hangup = 1; + } else {/* else: must be a touchtone: ignored */ + if (debug) { + if ((inbyte >= '0' && inbyte <= '9') || inbyte == '#' || + inbyte =='*' || (inbyte >= 'A' && inbyte <= 'D')) + fprintf(stderr, "Touchtone %c received.\n", inbyte); + else + fprintf(stderr, "Warning: Unknown escape sequence received.\n"); + } + } + + session->escape = 0; + if (debug) fprintf(stderr, + "debug: escape mode off after special char.\n"); + } + } + + llcheck_bar_set(session->llcheck_in, (double)max / 128); + + } else { + fprintf(stderr, "process_isdn_source: read error (return -1).\n"); + } +} + +/* + * process audio input from sound device to isdn tty + * + * to be called after select found fragment(s) to read from + */ +void process_audio_source(session_t *session) { + int i, j, got, n; + unsigned char sample; /* the ulaw sample */ + short s = 0; /* libsndfile sample data */ + /* the ulaw sample when muted: */ + unsigned char zero = session->audio_LUT_generate[128]; + int to_process; /* number of samples to process + (according to ratio / ratio_support_count) */ + unsigned char sampleu8; /* 8 bit unsigned sample */ + int max = 0; /* for llcheck */ + + got = read(session->audio_fd_in, session->audio_inbuf, + session->fragment_size_in); + + if (debug >= 2) + fprintf(stderr, "From audio: got %d bytes.\n", got); + + if (got != -1) { + for (i = 0; i < got; + i += session->audio_sample_size_in, session->samples_out++) { + + to_process = (int)floor((double)(session->samples_out + 1) + * session->ratio_out) - + (int)floor((double)session->samples_out + * session->ratio_out); + /* printf("audio -> isdn: to_process == %d\n", to_process); */ + for (j = 0; j < to_process; j++) { + if (session->audio_sample_size_in == 1) { + sample = session->audio_LUT_out[(int)(session->audio_inbuf[i])]; + } else { /* audio_sample_size == 2 */ + /* multiple byte samples are used "little endian" in int + to look up in LUT (see mediation_makeLUT) */ + sample = session->audio_LUT_out[(int)(session->audio_inbuf[i]) | + (int)(session->audio_inbuf[i+1]) + << 8]; + } + + /* touchtone to isdn: before llcheck to monitor it */ + if (session->touchtone_countdown_isdn > 0) { + sample = fxgenerate(session, EFFECT_TOUCHTONE, + session->touchtone_index, + (double)session->touchtone_countdown_isdn / + ISDN_SPEED /* playing reverse is ok */ ); + session->touchtone_countdown_isdn--; + } + + if (session->option_muted) /* zero if muted */ + sample = zero; + + /* input line level check */ + sampleu8 = session->audio_LUT_analyze[sample]; + if (abs((int)sampleu8 - 128) > max) + max = abs((int)sampleu8 - 128); + + /* recording */ + if (session->option_record) { + if (session->option_record_local) + s = session->audio_LUT_ulaw2short[sample]; + else + s = 0; + session->rec_buf_local[session->rec_buf_local_index++] = s; + if (session->rec_buf_local_index >= session->rec_buf_local_size) { + if (recording_write(session->recorder, session->rec_buf_local, + session->rec_buf_local_size, RECORDING_LOCAL)) + fprintf(stderr, "Warning: Recording (local) error.\n"); + session->rec_buf_local_index = 0; + } + } + + n = (sample == DLE) ? 2 : 1; /* again if DLE escape */ + while (n > 0) { + session->isdn_outbuf[session->isdn_outbuf_index++] = sample; + if (session->isdn_outbuf_index >= session->isdn_outbuf_size) { + /* write outbuf out */ + if (write_buf(session->isdn_fd, session->isdn_outbuf, + session->isdn_outbuf_size)) + session->aborted = 1; + session->isdn_outbuf_index = 0; + } + n--; + } + } + } + + llcheck_bar_set(session->llcheck_out, (double)max / 128); + + } else { + switch (errno) { + case EAGAIN: + if (debug) + fprintf(stderr, + "process_audio_source: " + "EAGAIN - no data immediately available (that's ok).\n"); + break; + case EBADF: + fprintf(stderr, + "process_audio_source: EBADF - invalid file descriptor.\n"); + break; + case EINTR: + fprintf(stderr, + "process_audio_source: EINTR - interrupted by signal.\n"); + break; + case EIO: + fprintf(stderr, + "process_audio_source: EIO - hardware error.\n"); + break; + } + } +} diff --git a/src/mediation.h b/src/mediation.h new file mode 100644 index 0000000..da2bcd1 --- /dev/null +++ b/src/mediation.h @@ -0,0 +1,39 @@ +/* + * functions for mediation between ISDN and OSS + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "session.h" + +/* mediation internal recording buffer (number of shorts): */ +#define MEDIATION_RECBUFSIZE 16384 + +extern int finished; +extern int hangup; + +int mediation_makeLUT(int format_in, unsigned char **LUT_in, + int format_out, unsigned char **LUT_out, + unsigned char **LUT_generate, + unsigned char **LUT_analyze, + short **LUT_ulaw2short); +int write_buf(int fd, unsigned char *outbuf, int outbuf_size); +void process_isdn_source(session_t *session); +void process_audio_source(session_t *session); diff --git a/src/mute.xpm b/src/mute.xpm new file mode 100644 index 0000000..288b6a9 --- /dev/null +++ b/src/mute.xpm @@ -0,0 +1,20 @@ +/* XPM */ +static char * mute_xpm[] = { +"14 14 3 1", +" c None", +". c #000000", +"+ c #B70000", +" ... ", +" ..... ", +" ++ ......", +" ++ ......", +" ++ ......", +" ++...... ", +" ++.. ", +"++++++++++++ ", +"++++++++++++ ", +" ..++ ", +" ...++ ", +" .. ++ ", +" . ++ ", +". ++ "}; diff --git a/src/out.xpm b/src/out.xpm new file mode 100644 index 0000000..a10e96e --- /dev/null +++ b/src/out.xpm @@ -0,0 +1,17 @@ +/* XPM */ +static char * out_xpm[] = { +"22 11 3 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"................. ", +".++++++++++++++++. ", +".++..++.++.+.....+. ", +".+.++.+.++.+++.++++. ", +".+.++.+.++.+++.+++++. ", +".+.++.+.++.+++.++++++.", +".+.++.+.++.+++.+++++. ", +".+.++.+.++.+++.++++. ", +".++..+++..++++.+++. ", +".++++++++++++++++. ", +"................. "}; diff --git a/src/pickup.xpm b/src/pickup.xpm new file mode 100644 index 0000000..c4c855b --- /dev/null +++ b/src/pickup.xpm @@ -0,0 +1,19 @@ +/* XPM */ +static char * pickup_xpm[] = { +"16 14 2 1", +" c None", +". c #20A000", +" .. ", +" .... ", +" ...... ", +" . .. . ", +" .. ", +" .. ", +" .. ", +" ", +" ", +" ............ ", +" .............. ", +"..... .....", +"..... ....", +" .. .. "}; diff --git a/src/record.xpm b/src/record.xpm new file mode 100644 index 0000000..a5c7f83 --- /dev/null +++ b/src/record.xpm @@ -0,0 +1,15 @@ +/* XPM */ +static char * record_xpm[] = { +"9 9 3 1", +" c None", +". c #FF0000", +"+ c #000000", +" .... ", +" ...... ", +"........ ", +"........+", +"........+", +"........+", +" ......++", +" ....++ ", +" ++++ "}; diff --git a/src/recording.c b/src/recording.c new file mode 100644 index 0000000..6e9f8f8 --- /dev/null +++ b/src/recording.c @@ -0,0 +1,239 @@ +/* + * recording functions + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "config.h" + +/* regular GNU system includes */ +#include +#include +#include + +/* sndfile audio file reading/writing library */ +#include + +/* own header files */ +#include "globals.h" +#include "isdn.h" +#include "recording.h" +#include "util.h" + +/* recorder internal buffer size (number of items, 1 item = 2 shorts): */ +#define RECORDING_BUFSIZE 16384 + +/* + * Carefully opens a file and prepares recorder + * * when the file exists, new data will be appended + * + * File format: + * + * input: + * recorder: struct to be filled with recorder state for recording session + * until recording_close() + * filename: the base file name. It will be expanded + * with full path and extension + * + * returns: 0 on success, -1 otherwise + */ +int recording_open(struct recorder_t *recorder, char *filename, + enum recording_format_t format) { + SF_INFO sfinfo; + char *homedir; + char *fn; + + /* prepare path and file */ + touch_dotdir(); + + if (!(homedir = get_homedir())) { + fprintf(stderr, "Warning: Couldn't get home dir.\n"); + return -1; + } + if (asprintf(&fn, "%s/." PACKAGE "/recordings", homedir) < 0) { + fprintf(stderr, "Warning: " + "recording_open: Couldn't allocate memory for directory name.\n"); + return -1; + } + if (touch_dir(fn) < 0) { + if (debug) + fprintf(stderr, + "Warning: recording_open: Can't reach directory %s.\n", fn); + return -1; + } + free(fn); + + if (asprintf(&fn, "%s/." PACKAGE "/recordings/%s.%s", homedir, filename, format & RECORDING_FORMAT_WAV ? "wav" : "aiff") + < 0) { + fprintf(stderr, "Warning: " + "recording_open: Couldn't allocate memory for directory name.\n"); + return -1; + } + + if (access(fn, F_OK)) { /* file doesn't exist */ + sfinfo.format = + (format & RECORDING_FORMAT_WAV ? SF_FORMAT_WAV : SF_FORMAT_AIFF) | + (format & RECORDING_FORMAT_S16 ? SF_FORMAT_PCM_16 : SF_FORMAT_ULAW); + sfinfo.channels = 2; + sfinfo.samplerate = ISDN_SPEED; + if (!(recorder->sf = sf_open(fn, SFM_WRITE, &sfinfo))) { + fprintf(stderr, "recording_open: sf_open (file creation) error.\n"); + return -1; + } + } else { /* file already exists */ + sfinfo.format = 0; + if (!(recorder->sf = sf_open(fn, SFM_RDWR, &sfinfo))) { + fprintf(stderr, "recording_open: sf_open (reopen) error.\n"); + return -1; + } + if (sf_seek(recorder->sf, 0, SEEK_END) == -1) { + fprintf(stderr, "recording_open: sf_seek error.\n"); + return -1; + } + } + recorder->filename = fn; + if (!(recorder->queue = + (struct recqueue_t *) malloc (sizeof(struct recqueue_t)))) { + fprintf(stderr, "recording_open: recorder->queue malloc error.\n"); + return -1; + } + if (!(recorder->queue->buf = + (short *) malloc (RECORDING_BUFSIZE * sizeof(short) * 2))) { + fprintf(stderr, "recording_open: recorder->queue->buf malloc error.\n"); + return -1; + } + recorder->queue->next = NULL; + recorder->current_local = recorder->current_remote = recorder->queue; + recorder->localindex = 0; + recorder->remoteindex = 0; + return 0; +} + +/* + * writes specified number of shorts to file + * + * input: + * recorder: struct with sound file state + * buf, size: the buffer of shorts with its size (number of shorts) + * channel: RECORDING_LOCAL or RECORDING_REMOTE + * + * returns: 0 on success, -1 otherwise + */ +int recording_write(struct recorder_t *recorder, short *buf, int size, + enum recording_channel_t channel) { + int i; + struct recqueue_t **link_this; /* alias for current_local or current_remote */ + int *buf_index_this; /* alias for localindex or remoteindex */ + struct recqueue_t *temp; + + if (channel == RECORDING_LOCAL) { + link_this = &recorder->current_local; + buf_index_this = &recorder->localindex; + } else { + link_this = &recorder->current_remote; + buf_index_this = &recorder->remoteindex; + } + + for (i = 0; i < size; i++) { + (*link_this)->buf[(*buf_index_this)++ * 2 + channel] = buf[i]; + if (*buf_index_this >= RECORDING_BUFSIZE) { /* one buffer full */ + if ((*link_this)->next == NULL) { /* expand list */ + if (!((*link_this)->next = + (struct recqueue_t *) malloc (sizeof(struct recqueue_t)))) { + fprintf(stderr, "recording_write: buffer allocation error.\n"); + return -1; + } + if (!((*link_this)->next->buf = + (short *) malloc (RECORDING_BUFSIZE * sizeof(short) * 2))) { + fprintf(stderr, "recording_write: buffer allocation error.\n"); + return -1; + } + (*link_this)->next->next = NULL; + } + + *link_this = (*link_this)->next; /* go further in list */ + *buf_index_this = 0; + + if (recorder->queue != recorder->current_local && + recorder->queue != recorder->current_remote) { + /* write out buffer */ + sf_writef_short(recorder->sf, recorder->queue->buf, RECORDING_BUFSIZE); + + temp = recorder->queue; + recorder->queue = recorder->queue->next; + free(temp->buf); + free(temp); + } + } + } + return 0; +} + +/* + * finishes recording to file, writes remaining data from queue to file + * (eventually filling a dangling channeln with silence) + * + * input: + * recorder: struct with sound file state + * + * returns: 0 on success, -1 otherwise + */ +int recording_close(struct recorder_t *recorder) { + struct recqueue_t **link_this; /* aliases for the links and their buffer - */ + struct recqueue_t **link_other; + int *buf_index_this; /* indices to traverse */ + int *buf_index_other; + enum recording_channel_t channel; + struct recqueue_t *temp; + + /* set last, unavailable samples to zero */ + if (recorder->queue == recorder->current_local) { /* traverse local samples */ + link_this = &recorder->current_local; + link_other = &recorder->current_remote; + buf_index_this = &recorder->localindex; + buf_index_other = &recorder->remoteindex; + channel = RECORDING_LOCAL; + } else { /* traverse remote samples */ + link_this = &recorder->current_remote; + link_other = &recorder->current_local; + buf_index_this = &recorder->remoteindex; + buf_index_other = &recorder->localindex; + channel = RECORDING_REMOTE; + } + + while (*link_this != NULL) { /* traverse all chain links */ + while ((*link_this != *link_other && *buf_index_this < RECORDING_BUFSIZE) + || *buf_index_this < *buf_index_other) { /* all remaining samples */ + (*link_this)->buf[(*buf_index_this)++ * 2 + channel] = 0; + } + sf_writef_short(recorder->sf, (*link_this)->buf, *buf_index_this); + + *buf_index_this = 0; + temp = *link_this; + *link_this = (*link_this)->next; + free(temp->buf); + free(temp); + } + + if (!sf_close(recorder->sf)) return -1; + free(recorder->filename); + return 0; +} + diff --git a/src/recording.h b/src/recording.h new file mode 100644 index 0000000..ec495ec --- /dev/null +++ b/src/recording.h @@ -0,0 +1,72 @@ +/* + * recording functions + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ANT_RECORDING_H +#define _ANT_RECORDING_H + +#include "config.h" + +/* regular GNU system includes */ +#include + +/* sndfile audio file reading/writing library */ +#include + +enum recording_format_t { + RECORDING_FORMAT_WAV = 0x10, + RECORDING_FORMAT_AIFF = 0x20, + + RECORDING_FORMAT_ULAW = 0x01, + RECORDING_FORMAT_S16 = 0x02, + + RECORDING_FORMAT_MAJOR = 0xF0, + RECORDING_FORMAT_MINOR = 0x0F +}; + +enum recording_channel_t { + RECORDING_LOCAL = 0, + RECORDING_REMOTE = 1 +}; + +struct recqueue_t { + struct recqueue_t *next; + short *buf; +}; + +struct recorder_t { + SNDFILE *sf; /* sndfile state */ + char *filename; /* audio file name */ + struct recqueue_t *queue; /* buffer queue for communication with libsndfile */ + struct recqueue_t *current_local; /* current queue element for local input */ + struct recqueue_t *current_remote;/* current queue element for remote input */ + int localindex; /* indices into current block in queue */ + int remoteindex; +}; + +int recording_open(struct recorder_t *recorder, char *filename, + enum recording_format_t format); +int recording_write(struct recorder_t *recorder, short *buf, int size, + enum recording_channel_t channel); +int recording_close(struct recorder_t *recorder); + +#endif /* recording.h */ diff --git a/src/redial.xpm b/src/redial.xpm new file mode 100644 index 0000000..766b5bb --- /dev/null +++ b/src/redial.xpm @@ -0,0 +1,15 @@ +/* XPM */ +static char * redial_xpm[] = { +"14 10 2 1", +" c None", +". c #000000", +" ... ... ", +" .. ....... ", +" .. ....... ", +".. .........", +". .........", +". .........", +".. .........", +" .. ....... ", +" .. ....... ", +" ... ... "}; diff --git a/src/server.c b/src/server.c new file mode 100644 index 0000000..1e808eb --- /dev/null +++ b/src/server.c @@ -0,0 +1,149 @@ +/* + * server functionality: + * * let other processes issue commands (e.g. dial) + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* regular GNU system includes */ +#include +#include +#include +#include +#include +#include +#include + +/* own header files */ +#include "globals.h" +#include "server.h" +#include "session.h" +#include "util.h" + +/* + * returns the name of the local socket file + * + * NOTE: caller has to free himself the allocated memory + */ +char *server_local_socket_name(void) { + char *filename; + + if (asprintf(&filename, "%s/." PACKAGE "/%s", + get_homedir(), SERVER_LOCAL_SOCKET_NAME) < 0) { + fprintf(stderr, + "Warning: Couldn't allocate memory for history filename.\n"); + return NULL; + } + return filename; +} + +/* + * init server setup for session + */ +int server_init(session_t *session) { + struct sockaddr_un local_name; + int local_sock; + size_t size; + char *filename; + + filename = server_local_socket_name(); + + local_name.sun_family = AF_LOCAL; + strncpy(local_name.sun_path, filename, sizeof(local_name.sun_path)); + size = SUN_LEN(&local_name); + + free(filename); + + local_sock = socket(PF_LOCAL, SOCK_STREAM, 0); /* open socket */ + if (local_sock < 0) { + perror("local socket"); + return -1; + } + + if (touch_dotdir()) + return -1; + + /* bind (file) name to socket */ + if (bind(local_sock, (struct sockaddr *) &local_name, size)) { + perror("local bind"); + fprintf(stderr, + "This program was possibly killed by accident on last run.\n" + "In this case, try running it with option -r.\n"); + return -1; + } + + if (listen(local_sock, SERVER_CONNECTIONS_MAX_PENDING) < 0) { + perror("listen"); + return -1; + } + + session->local_sock = local_sock; + + return 0; +} + +/* + * callback for local input on session->local_socket + */ +void server_handle_local_input(gpointer data, gint fd _U_, + GdkInputCondition condition _U_) { + session_t *session = (session_t *) data; + int sock; /* the actual socket */ + struct sockaddr_un clientname; /* data about connecting client */ + socklen_t size; + char buffer[SERVER_INBUF_SIZE]; + int bytes; + + sock = accept(session->local_sock, (struct sockaddr *) &clientname, &size); + if (sock < 0) { + perror("local accept"); + } + + bytes = read(sock, buffer, SERVER_INBUF_SIZE); + if (bytes > 0) { /* got message */ + if (buffer[0] == LOCAL_MSG_CALL) { + if (debug) fprintf(stderr, "Request (%d bytes): call %s.\n", + bytes, &buffer[1]); + session_make_call(session, &buffer[1]); + } + } else if (bytes < 0) { /* error */ + perror("local read"); + } else { /* EOF */ + fprintf(stderr, "local read: EOF"); + } + + close(sock); +} + + +/* + * deinit server setup for session + */ +int server_deinit(session_t *session) { + char *filename; + + close(session->local_sock); + if (-1 == unlink(filename = server_local_socket_name())) { + perror("unlink socket file"); + } + free(filename); + + return 0; +} diff --git a/src/server.h b/src/server.h new file mode 100644 index 0000000..04e2b36 --- /dev/null +++ b/src/server.h @@ -0,0 +1,40 @@ +/* + * server functionality: + * * let other processes issue commands (dial) + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* own header files */ +#include "session.h" + +#define SERVER_LOCAL_SOCKET_NAME ".socket" +#define SERVER_CONNECTIONS_MAX_PENDING 5 +#define SERVER_INBUF_SIZE 1024 + +enum local_msg_t { + LOCAL_MSG_CALL +}; + +char *server_local_socket_name(void); +int server_init(session_t *session); +void server_handle_local_input(gpointer data, gint fd _U_, + GdkInputCondition condition _U_); +int server_deinit(session_t *session); diff --git a/src/session.c b/src/session.c new file mode 100644 index 0000000..460b536 --- /dev/null +++ b/src/session.c @@ -0,0 +1,1453 @@ +/* + * definitions for runtime session specific data handling + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "config.h" + +/* regular GNU system includes */ +#include +#include +#ifdef HAVE_STDLIB_H + #include +#endif +#ifdef HAVE_UNISTD_H + #include +#endif +#include +#include +#include + +/* GTK */ +#include + +/* libsndfile */ +#include + +/* own header files */ +#include "globals.h" +#include "session.h" +#include "sound.h" +#include "isdn.h" +#include "mediation.h" +#include "gtk.h" +#include "util.h" +#include "callerid.h" +#include "llcheck.h" +#include "settings.h" +#include "fxgenerator.h" +#include "server.h" + +/* + * This is our session. Currently just one globally. + */ +session_t session; + +struct state_data_t state_data[STATE_NUMBER] = { +{N_("Ready"), N_("Dial"), 1,N_("Hang up"),0},/* STATE_READY */ +{N_("RING"), N_("Answer"), 1,N_("Reject"), 1},/* STATE_RINGING */ +{N_("RING"), N_("Answer"), 1,N_("Reject"), 1},/* STATE_RINGING_QUIET */ +{N_("Dialing"), N_("Pick up"),0,N_("Cancel"), 1},/* STATE_DIALING */ +{N_("B-Channel open"),N_("Pick up"),0,N_("Hang up"),1},/* STATE_CONVERSATION */ +{N_("Setup"), N_("Pick up"),0,N_("Hang up"),0},/* STATE_SERVICE */ +{N_("Playback"), N_("Pick up"),0,N_("Stop") ,1} /* STATE_PLAYBACK */ +}; + +/* + * Simply opens audio devices for specified session + * + * returns 0 on success, -1 on error + */ +int session_audio_open(session_t *session) { + if (debug) + fprintf(stderr, "session_audio_open: Opening audio device(s).\n"); + if (open_audio_devices(session->audio_device_name_in, + session->audio_device_name_out, + 1, + session->format_priorities, + &session->audio_fd_in, + &session->audio_fd_out, + &session->fragment_size_in, + &session->fragment_size_out, + &session->audio_format_in, + &session->audio_format_out, + &session->audio_speed_in, + &session->audio_speed_out)) { + return -1; + } + return 0; +} + +/* + * Closes audio devices for specified session + * + * returns 0 on success, -1 on error + */ +int session_audio_close(session_t *session) { + if (debug) + printf("session_audio_close: Closing audio device(s).\n"); + if (close_audio_devices(session->audio_fd_in, session->audio_fd_out)) { + return -1; + } + return 0; +} + +/* + * init audio devices in session + * + * input: session->audio_device_name_in, session->audio_device_name_out + * + * returns 0 on success, -1 otherwise + * + * output: on success, session->audio_LUT* and session->audio_*buf are + * allocated (and set, if appropriate) + */ +int session_audio_init(session_t *session) { + /* message: open audio device(s) */ + if (debug) { + if (strcmp(session->audio_device_name_in, session->audio_device_name_out)) + { + /* different devices */ + fprintf(stderr, "Initializing %s and %s...\n", + session->audio_device_name_in, session->audio_device_name_out); + } else { + fprintf(stderr, "Initializing %s ...\n", + session->audio_device_name_in); + } + } + + /* other options */ + session->audio_speed_in = ISDN_SPEED; /* default audio speed */ + session->audio_speed_out = ISDN_SPEED; + + /* audio device buffer fragment sizes */ + session->fragment_size_in = DEFAULT_FRAGMENT_SIZE; + session->fragment_size_out = DEFAULT_FRAGMENT_SIZE; + + session->format_priorities = default_audio_priorities; + + if (session_audio_open(session)) { + fprintf(stderr, "Error initializing audio device(s).\n"); + return -1; + } + + session->ratio_in = (double)session->audio_speed_out / ISDN_SPEED; + session->ratio_out = (double)ISDN_SPEED / session->audio_speed_in; + + if (mediation_makeLUT(session->audio_format_out, &session->audio_LUT_in, + session->audio_format_in, &session->audio_LUT_out, + &session->audio_LUT_generate, + &session->audio_LUT_analyze, + &session->audio_LUT_ulaw2short)) { + fprintf(stderr, "Error building conversion look-up-table.\n"); + return -1; + } + + session->audio_sample_size_in = + sample_size_from_format(session->audio_format_in); + session->audio_sample_size_out = + sample_size_from_format(session->audio_format_out); + + /* allocate buffers */ + if (!(session->audio_inbuf = + (unsigned char *)malloc(session->fragment_size_in))) { + return -1; + } + if (!(session->audio_outbuf = + (unsigned char *)malloc(session->fragment_size_out))) { + return -1; + } + + return 0; +} + +/* + * init isdn in session + * + * input: session->msn, session->msns + * + * returns 0 on success, -1 otherwise + */ +int session_isdn_init(session_t *session) { + /* open and init isdn device */ + if (debug) + fprintf(stderr, "Initializing ISDN device...\n"); + if ((session->isdn_fd = + open_isdn_device(&session->isdn_device_name, + &session->isdn_lockfile_name)) < 0) { + fprintf(stderr, "Error opening isdn device.\n"); + return -1; + } + if (init_isdn_device(session->isdn_fd, &session->isdn_backup)) { + fprintf(stderr, "Error initializing isdn device.\n"); + return -1; + } + + session->isdn_inbuf_size = session->isdn_outbuf_size = DEFAULT_ISDNBUF_SIZE; + + /* allocate buffers */ + if (!(session->isdn_inbuf = + (unsigned char *)malloc(session->isdn_inbuf_size))) { + return -1; + } + if (!(session->isdn_outbuf = + (unsigned char *)malloc(session->isdn_outbuf_size))) { + return -1; + } + + if (isdn_setMSN(session->isdn_fd, session->msn) || + isdn_setMSNs(session->isdn_fd, session->msns)) { + fprintf(stderr, "Error setting MSN properties.\n"); + return -1; + } + + session->isdn_inbuf_len = 0; + session->isdn_inbuf[0] = 1; + + return 0; +} + +/* + * init recording related things in session + */ +int session_recording_init(session_t *session) { + /* mediation recording stuff */ + session->rec_buf_local_size = MEDIATION_RECBUFSIZE; + session->rec_buf_remote_size = MEDIATION_RECBUFSIZE; + session->rec_buf_local_index = 0; + session->rec_buf_remote_index = 0; + if (!(session->rec_buf_local = + (short *) malloc(session->rec_buf_local_size * sizeof(short)))) { + return -1; + } + if (!(session->rec_buf_remote = + (short *) malloc(session->rec_buf_remote_size * sizeof(short)))) { + return -1; + } + + if (!(session->recorder = + (struct recorder_t *)malloc(sizeof(struct recorder_t)))) { + return -1; + } + + return 0; +} + +/* + * deinit recording related things in session + */ +int session_recording_deinit(session_t *session) { + free(session->rec_buf_local); + free(session->rec_buf_remote); + free(session->recorder); + return 0; +} + +/* + * de-allocates memory used by audio buffers of session + * -> prepares de-initialization + * -> is part of session_audio_free() + */ +void session_audio_free(session_t *session) { + free(session->audio_inbuf); + free(session->audio_outbuf); + + free(session->audio_LUT_in); + free(session->audio_LUT_out); + free(session->audio_LUT_generate); + free(session->audio_LUT_analyze); + free(session->audio_LUT_ulaw2short); +} + +/* + * close audio device(s) and clean up (deallocate buffers) + * + * returns 0 on success, -1 otherwise + */ +int session_audio_deinit(session_t *session) { + /* free allocated buffers */ + session_audio_free(session); + + /* close audio device(s) */ + if (debug) + fprintf(stderr, "Closing sound device(s)...\n"); + if (session_audio_close(session)) { + fprintf(stderr, "Error closing sound device(s).\n"); + return -1; + } + + return 0; +} + +/* + * close isdn device and clean up (deallocate buffers) + * + * returns 0 on success, -1 otherwise + */ +int session_isdn_deinit(session_t *session) { + /* free allocated buffers */ + free(session->isdn_inbuf); + free(session->isdn_outbuf); + + if (debug) + fprintf(stderr, "Closing ISDN device...\n"); + /* de-init / restore isdn device */ + if (deinit_isdn_device(session->isdn_fd, &session->isdn_backup)) { + fprintf(stderr, "Error restoring ttyI state.\n"); + } + /* close isdn device */ + if (close_isdn_device(session->isdn_fd, + session->isdn_device_name, + session->isdn_lockfile_name)) { + fprintf(stderr, "Error closing isdn device.\n"); + } + + return 0; +} + +/* + * initialize a session (isdn device, audio device) and read options file + * + * input: + * session: empty struct waiting for work + * audio_device_name_in, audio_device_name_out: name(s) of audio device(s) + * msn: msn to use + * + * NOTE: The latter 4 parameters are only the requested ones. When they are + * overridden by the options file, the resulting values will be different + * + * output: session: initialized session struct + * + * returns 0 on success, -1 otherwise + */ +int session_init(session_t *session, + char *audio_device_name_in, + char *audio_device_name_out, + char *msn, char *msns) { + int i; + + /* + * first: set all defaults possibly overridden by options file + */ + + session->dial_number_history = NULL; + session->dial_number_history = g_list_append(session->dial_number_history, + strdup("")); + session->dial_number_history_maxlen = 10; /* config overrides this */ + session->cid_num_max = 100; /* 0 means no limit */ + + /* options defaults */ + session->option_save_options = 1; /* save options automatically (on exit) */ + session->option_release_devices = 1; + session->option_show_llcheck = 1; + session->option_show_callerid = 1; + session->option_show_controlpad = 1; + session->option_muted = 0; + session->option_record = 0; + session->option_record_local = 1; + session->option_record_remote = 1; + session->option_recording_format = + RECORDING_FORMAT_WAV | RECORDING_FORMAT_ULAW; + session->option_popup = 1; + + session->option_calls_merge = 1; + session->option_calls_merge_max_days = 10; + + session->exec_on_incoming = strdup(""); + + for (i = 0; i < 4; i++) { + asprintf(&session->preset_names[i], _("Preset %d"), i + 1); + session->preset_numbers[i] = strdup(""); + } + + session->audio_device_name_in = strdup(audio_device_name_in); + session->audio_device_name_out = strdup(audio_device_name_out); + session->msn = strdup(msn); + session->msns = strdup(msns); + + session->from = strdup(""); + session->to = strdup(""); + + settings_options_read(session); /* override defaults analyzing options file */ + + /* command line configurable parameters: set to hard coded defaults + if no setting was made (either at command line or in options file) */ + if (!strcmp(session->audio_device_name_in, "")) { + free(session->audio_device_name_in); + session->audio_device_name_in = strdup(DEFAULT_AUDIO_DEVICE_NAME_IN); + } + if (!strcmp(session->audio_device_name_out, "")) { + free(session->audio_device_name_out); + session->audio_device_name_out = strdup(DEFAULT_AUDIO_DEVICE_NAME_OUT); + } + if (!strcmp(session->msn, "")) { + free(session->msn); + session->msn = strdup(DEFAULT_MSN); + } + if (!strcmp(session->msns, "")) { + free(session->msns); + session->msns = strdup(DEFAULT_MSNS); + } + + /* other defaults */ + session->dial_number_history_pointer = 0; + session->touchtone_countdown_isdn = 0; + session->touchtone_countdown_audio = 0; + session->touchtone_index = 0; + + session->ring_time = 0; + session->unanswered = 0; + + /* setup audio and isdn */ + if (!session->option_release_devices) + if (session_audio_init(session) < 0) return -1; + if (session_isdn_init(session) < 0) return -1; + if (session_recording_init(session) < 0) return -1; + + session->state = STATE_READY; /* initial state */ + + session->effect = EFFECT_NONE; + + /* init server functionality */ + if (server_init(session) < 0) return -1; + + return 0; +} + +/* + * helper function to free single element data from g_list + * (used by session_deinit) + */ +void free_g_list_element(gpointer data, gpointer user_data _U_) { + free(data); +} + +/* + * de-initialize a session (isdn device, audio device) + * + * input: session: session to de-initialize + * + * returns 0 on success, -1 otherwise + */ +int session_deinit(session_t *session) { + int i; + + /* deinit server functionality */ + if (server_deinit(session) < 0) return -1; + + if (session->option_save_options) settings_options_write(session); + + /* free dial_number_history */ + g_list_foreach(session->dial_number_history, free_g_list_element, NULL); + g_list_free(session->dial_number_history); + + /* close devices and clean up (buffers) */ + if (session_isdn_deinit(session) < 0) return -1; + if (!session->option_release_devices) + if (session_audio_deinit(session) < 0) return -1; + + if (session_recording_deinit(session) < 0) return -1; + + free(session->exec_on_incoming); + + /* clean up pre-set options */ + free(session->audio_device_name_in); + free(session->audio_device_name_out); + free(session->msn); + free(session->msns); + + /* clean up rest */ + for (i = 0; i < 4; i++) { + free(session->preset_names[i]); + free(session->preset_numbers[i]); + } + free(session->from); + free(session->to); + + return 0; +} + +/* + * set up handlers for audio/ISDN input + */ +void session_io_handlers_start(session_t *session) { + if (!(session->option_release_devices && + (session->state == STATE_READY || + session->state == STATE_RINGING_QUIET))) { + session->gtk_audio_input_tag = gtk_input_add_full(session->audio_fd_in, + GDK_INPUT_READ, + gtk_handle_audio_input, + NULL, + (gpointer) session, + NULL); + } + session->gtk_isdn_input_tag = gtk_input_add_full(session->isdn_fd, + GDK_INPUT_READ, + gtk_handle_isdn_input, + NULL, + (gpointer) session, + NULL); + + /* server functionality */ + session->gtk_local_input_tag = gtk_input_add_full(session->local_sock, + GDK_INPUT_READ, + server_handle_local_input, + NULL, + (gpointer) session, + NULL); +} + +/* + * remove handlers for audio/ISDN input + */ +void session_io_handlers_stop(session_t *session) { + if (!(session->option_release_devices && + (session->state == STATE_READY || + session->state == STATE_RINGING_QUIET))) { + gtk_input_remove(session->gtk_audio_input_tag); + } + gtk_input_remove(session->gtk_isdn_input_tag); + gtk_input_remove(session->gtk_local_input_tag); +} + +/* + * Resets audio devices by closing and reopening + * + * assumes audio in open, initialized (possibly used) state + * + * WARNING: * Stop I/O handlers first! + * * Only resets currently used device(s). To use another device, + * use session_audio_deinit() and session_audio_init() + * + * returns 0 on success, -1 on error + */ +int session_reset_audio(session_t *session) { + int result = 0; + + if (!(session->option_release_devices && + (session->state == STATE_READY || + session->state == STATE_RINGING_QUIET))) { + if (session_audio_close(session)) { + fprintf(stderr, "Error closing audio device(s) while resetting.\n"); + result = -1; + } + if (session_audio_open(session)) { + fprintf(stderr, "Error reopening audio device(s) while resetting.\n"); + result = -1; + } + } + return result; +} + +/* + * Callback for new unhandled modem string + * + * This function will be called, whenever we got a new unhandled modem string. + * That means that it's called unless modem answers were stolen by response + * handlers in functions like isdn_setMSN or isdn_hangup where "OK\r\n" will + * be checked for + */ +void session_new_modem_string_callback(session_t *session) { + /* modem string is in session->isdn_inbuf */ + if (debug) + /* new line is in isdn_inbuf */ + fprintf(stderr, "|%s", session->isdn_inbuf); +} + +/* + * Tries to read isdn device in command mode, returns immediately + * (non blocking). If we have a partially filled input buffer, continue + * with that + * + * input: session struct with open isdn_fd of ttyI in command mode + * + * output: command (or partial command) read in + * session->isdn_inbuf, session->isdn_inbuf_len + * + * returns with 1 if we got a new line (else 0) + * + * NOTE: * completed lines are 0-terminated at session->isdn_inbuf_len, + * non-compleded lines are 1-terminated there + * * completed lines are actually terminated by "\r\n\0" + */ +static int isdn_try_read_line(session_t *session) { + int total = 0; /* number of bytes read in this call */ + struct timeval tv; + fd_set fds; + int num; /* number of file descriptors with data (0/1) */ + + tv.tv_sec = 0; /* return immediately */ + tv.tv_usec = 0; + + do { + FD_ZERO(&fds); + FD_SET(session->isdn_fd, &fds); + + num = select(FD_SETSIZE, &fds, 0, 0, &tv); + if (num > 0) { /* got another char: append to buffer */ + + if (session->isdn_inbuf[session->isdn_inbuf_len] == 0 || + session->isdn_inbuf_len == session->isdn_inbuf_size - 1) { + /* we have to start new line or buffer is full -> reset buffer */ + session->isdn_inbuf_len = 0; + session->isdn_inbuf[0] = 1; + } + + read(session->isdn_fd, &session->isdn_inbuf[session->isdn_inbuf_len], 1); + total ++; + session->isdn_inbuf[++session->isdn_inbuf_len] = 1; + + if (session->isdn_inbuf_len >= 2 && + session->isdn_inbuf[session->isdn_inbuf_len - 2] == '\r' && + session->isdn_inbuf[session->isdn_inbuf_len - 1] == '\n') { + /* end of line */ + session->isdn_inbuf[session->isdn_inbuf_len] = 0; + } + } + } while (num > 0 && session->isdn_inbuf[session->isdn_inbuf_len] != 0); + if (session->isdn_inbuf[session->isdn_inbuf_len] == 0 && total > 0) { + session_new_modem_string_callback(session); + return 1; + } else + return 0; +} + +/* do some initialization of full duplex conversation mode */ +void session_init_conversation(session_t *session) { + session->samples_in = 0; + session->samples_out = 0; + + session->audio_outbuf_index = 0; + session->isdn_outbuf_index = 0; + + session->escape = 0; + + session->hangup = 0; + session->aborted = 0; + + session->no_input = 0; +} + +/* + * do some deinitialization of full duplex conversation mode + * + * return: self_hangup: 1 == we hangup, 0 == other side hung up + */ +void session_deinit_conversation(session_t *session, int self_hangup) { + if (session->option_record) { + recording_write(session->recorder, session->rec_buf_local, + session->rec_buf_local_index, RECORDING_LOCAL); + recording_write(session->recorder, session->rec_buf_remote, + session->rec_buf_remote_index, RECORDING_REMOTE); + recording_close(session->recorder); + } + session->rec_buf_local_index = 0; + session->rec_buf_remote_index = 0; + + session_io_handlers_stop(session); + session_reset_audio(session); + session_io_handlers_start(session); + + if (isdn_blockmode(session->isdn_fd, 0)) + fprintf(stderr, "Warning: " + "Switching back to normal isdn tty mode not successful.\n"); + + /* go back to command mode */ + if (isdn_stop_audio(session->isdn_fd, self_hangup)) { + fprintf(stderr, "Error switching back to command mode.\n"); + } + + /* isdn hangup */ + if (isdn_hangup(session->isdn_fd)) { + fprintf(stderr, "Error hanging up.\n"); + } + + session->isdn_inbuf_len = 0; + session->isdn_inbuf[0] = 1; +} + +/* + * will be called directly after getting VCON from ttyI + * includes state transition + */ +void session_start_conversation(session_t *session) { + char *digits; /* time in digits form */ + + if (isdn_set_full_duplex(session->isdn_fd)) { + /* ISDN full duplex (REC start command) error */ + fprintf(stderr, "Error setting full duplex audio mode.\n"); + isdn_hangup(session->isdn_fd); + session_set_state(session, STATE_READY); + cid_set_duration(session, _("(HW ERROR)")); + } else { /* full duplex ok: audio mode */ + session->vcon_time = time(NULL); /* for caller id monitor */ + cid_set_date(session, session->vcon_time); + session_set_state(session, STATE_CONVERSATION); + if (session->option_record) { + if ((digits = util_digitstime(&session->vcon_time))) { + if (recording_open(session->recorder, digits, + session->option_recording_format)) { + fprintf(stderr, "Error opening audio file.\n"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( + session->record_checkbutton), FALSE); + } + free(digits); + cid_row_mark_record(session, session->cid_num - 1); + } else { + fprintf(stderr, "Error generating audio filename.\n"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( + session->record_checkbutton), FALSE); + } + } + if (isdn_blockmode(session->isdn_fd, 1)) /* blockmode error */ + fprintf(stderr, + "Warning: Switching to ISDN blockmode not successful.\n"); + session_init_conversation(session); /* init some conversation variables */ + + session_io_handlers_stop(session); + session_reset_audio(session); + session_io_handlers_start(session); + + /* start with first block to start recording */ + process_audio_source(session); + } +} + +/* + * to be called by a timeout and everyone who wants to stop a running effect + * to go back to STATE_READY + */ +gint session_effect_stop_cb(gpointer data) { + session_t *session = (session_t *) data; + + session_set_state(session, STATE_READY); + + return FALSE; /* don't call me regularly */ +} + +/* + * To be called when we can write another block to sound device + */ +void session_effect_callback(gpointer data, + gint source _U_, GdkInputCondition condition _U_) +{ + session_t *session = (session_t *) data; + int pos = 0; /* position in raw byte output buffer */ + int i; + int index_out = 0; /* logical position (sample number) in output buffer */ + unsigned char x; /* generated ulaw sample */ + int just_read = 0; + int sndfile_buffer_index = 0; + double speed_factor = (double)session->effect_sndfile_buffer_frames / + (session->fragment_size_out / session->audio_sample_size_out); + /* factor from audio device to sndfile */ + + if (session->effect == EFFECT_SOUNDFILE) { + just_read = sf_readf_short(session->effect_sndfile, + session->effect_sndfile_buffer, session->effect_sndfile_buffer_frames); + } + for (i = 0; i < session->effect_sfinfo.channels; i++) + session->effect_sndfile_buffer[session->effect_sndfile_buffer_frames * + session->effect_sfinfo.channels + i] = + session->effect_sndfile_buffer[(session->effect_sndfile_buffer_frames-1) * + session->effect_sfinfo.channels + i]; + + /* fill buffer */ + while (pos < session->fragment_size_out) { + if (session->effect == EFFECT_SOUNDFILE) { + double sum = 0.0; + double leftbound = speed_factor * index_out; /* sndfile bounds */ + double rightbound = speed_factor * (index_out + 1); + double dummy; + double frac = modf(leftbound, &dummy); + + while (leftbound < rightbound) { + double frame_sum = 0; + double weight; + if (rightbound - leftbound < 1.0) + weight = rightbound - leftbound; + else + weight = 1.0; + + sndfile_buffer_index = (int)leftbound; + if (sndfile_buffer_index < just_read) { + int t_count; + for (t_count=0; t_count < session->effect_sfinfo.channels; t_count++){ + frame_sum += (1.0 - frac) * session->effect_sndfile_buffer[ + sndfile_buffer_index * session->effect_sfinfo.channels + t_count] + + frac * session->effect_sndfile_buffer[ + (sndfile_buffer_index+1)*session->effect_sfinfo.channels+t_count]; + } + frame_sum /= session->effect_sfinfo.channels; + } else { + frame_sum = 0; + } + sum += weight * frame_sum; + leftbound += 1.0; + } + sum /= speed_factor; + x = session->audio_LUT_generate[(int)sum / 256 + 128]; + } else { + double seconds = (double)session->effect_pos / session->audio_speed_out; + x = fxgenerate(session, session->effect, 0, seconds); + } + if (session->audio_sample_size_out == 1) { + session->audio_outbuf[pos++] = session->audio_LUT_in[(int)x]; + } else { /* audio_sample_size == 2 */ + session->audio_outbuf[pos++] = session->audio_LUT_in[(int)x * 2]; + session->audio_outbuf[pos++] = session->audio_LUT_in[(int)x * 2 + 1]; + } + index_out ++; + session->effect_pos++; + } + + /* play it! */ + write_buf(session->audio_fd_out, + session->audio_outbuf, + session->fragment_size_out); + + if (session->effect == EFFECT_SOUNDFILE && + just_read < session->effect_sndfile_buffer_frames && + session->effect_filename) + { + gtk_timeout_add( + 1000 * session->fragment_size_out / session->audio_sample_size_out * + (audio_get_write_fragments_total(session->audio_fd_out) - + audio_get_write_fragments_number(session->audio_fd_out)) / + session->audio_speed_out, + session_effect_stop_cb, session); + /* session->effect_filename provides a flag if we already want to stop */ + free(session->effect_filename); + session->effect_filename = NULL; + } +} + +/* + * Start an effect (effect_t) playing on the sound device + * + * on kind == EFFECT_SOUNDFILE, session->effect_filename should be + * initialized so that session_effect_stop can free() it afterwards + */ +void session_effect_start(session_t *session, enum effect_t kind) { + if (kind == EFFECT_SOUNDFILE) { + session->effect_sfinfo.format = 0; + if (!(session->effect_sndfile = + sf_open(session->effect_filename, SFM_READ, &session->effect_sfinfo))) + { + fprintf(stderr, "Error on opening sound file.\n"); + } + session->effect_sndfile_buffer_frames = + session->fragment_size_out / session->audio_sample_size_out * + session->effect_sfinfo.samplerate / session->audio_speed_out; + session->effect_sndfile_buffer = (short*) malloc (sizeof(short) * + (session->effect_sndfile_buffer_frames + 1) * /* doubled dummy at end */ + session->effect_sfinfo.channels); + + } + session->effect_tag = gtk_input_add_full(session->audio_fd_out, + GDK_INPUT_WRITE, + session_effect_callback, + NULL, + (gpointer) session, + NULL); + + session->effect = kind; + session->effect_pos = 0; +} + +/* + * Reset sound device and unset callback + */ +void session_effect_stop(session_t *session) { + if (session->effect != EFFECT_NONE) { /* stop only if already playing */ + if (session->effect == EFFECT_SOUNDFILE) { + sf_close(session->effect_sndfile); + free(session->effect_sndfile_buffer); + } + gtk_input_remove(session->effect_tag); + session->effect = EFFECT_NONE; + } + session_io_handlers_stop(session); + session_reset_audio(session); + session_io_handlers_start(session); +} + +/* + * Sets status bar audio state (e.g. "AUDIO OFF") + * hide if note is "" + */ +void session_audio_notify(session_t *session, char *note) { + GtkWidget *dummy_label; /* needed to adjust size of sub-statusbar */ + GtkRequisition requisition; + + gtk_widget_hide(session->audio_warning); + if (*note) { + gtk_statusbar_pop(GTK_STATUSBAR(session->audio_warning), + session->audio_context_id); + gtk_statusbar_push(GTK_STATUSBAR(session->audio_warning), + session->audio_context_id, note); + + dummy_label = gtk_label_new(note); + gtk_widget_show(dummy_label); + gtk_widget_size_request(dummy_label, &requisition); + gtk_widget_set_size_request(session->audio_warning, + requisition.width + 4, -1); + + gtk_widget_show(session->audio_warning); + } +} + +/* + * Sets new state in session and GUI (also handles audio state) + * + * returns 0 on success, -1 otherwise (can't open audio device) + */ +int session_set_state(session_t *session, enum state_t state) { + int result = 0; + + /* open / close audio when needed, set state */ + session_io_handlers_stop(session); + if (session->option_release_devices && state != session->state) { + if (state == STATE_READY && session->state != STATE_RINGING_QUIET) { + /* release */ + session_audio_deinit(session); + } else if ((session->state == STATE_READY || + session->state == STATE_RINGING_QUIET) && + state != STATE_READY && state != STATE_RINGING_QUIET) { + /* (try to) resume */ + if (session_audio_init(session)) { + state = session->state; + result = -1; + } + } + } + session->state = state; + session_io_handlers_start(session); + + /* some menu items are selected only in STATE_READY */ + gtk_widget_set_sensitive(session->menuitem_settings, state == STATE_READY); + gtk_widget_set_sensitive(session->menuitem_line_check, state == STATE_READY); + + /* start / stop effects when needed */ + switch (state) { + case STATE_DIALING: + if (session->effect == EFFECT_NONE) + session_effect_start(session, EFFECT_RINGING); + if (debug) fprintf(stderr, "New state: STATE_DIALING\n"); + break; + case STATE_RINGING: + if (session->option_popup) { + gtk_window_present(GTK_WINDOW(session->main_window)); + } + if (session->effect == EFFECT_NONE) + session_effect_start(session, EFFECT_RING); + if (debug) fprintf(stderr, "New state: STATE_RINGING\n"); + break; + case STATE_RINGING_QUIET: + if (session->option_popup) { + gtk_window_present(GTK_WINDOW(session->main_window)); + } + if (debug) fprintf(stderr, "New state: STATE_RINGING_QUIET\n"); + break; + case STATE_READY: + gtk_widget_grab_focus(GTK_WIDGET(GTK_COMBO(session->dial_number_box) + ->entry)); + if (session->effect != EFFECT_NONE) + session_effect_stop(session); + if (debug) fprintf(stderr, "New state: STATE_READY\n"); + break; + case STATE_CONVERSATION: + if (session->effect != EFFECT_NONE) + session_effect_stop(session); + session->touchtone_countdown_isdn = 0; + session->touchtone_countdown_audio = 0; + if (debug) fprintf(stderr, "New state: STATE_CONVERSATION\n"); + break; + case STATE_SERVICE: + if (debug) fprintf(stderr, "New state: STATE_SERVICE\n"); + break; + case STATE_PLAYBACK: + if (session->effect == EFFECT_NONE) + session_effect_start(session, EFFECT_SOUNDFILE); + if (debug) fprintf(stderr, "New state: STATE_PLAYBACK\n"); + break; + default: + fprintf(stderr, "Warning: session_set_state: Unhandled state.\n"); + } + + /* audio on / off notify */ + if (session->option_release_devices) { + session_audio_notify(session, + state == STATE_READY || state == STATE_RINGING_QUIET ? + _("Audio OFF") : _("Audio ON")); + } else { + session_audio_notify(session, ""); + } + + /* status line */ + gtk_statusbar_pop(GTK_STATUSBAR(session->status_bar), + session->phone_context_id); + gtk_statusbar_push(GTK_STATUSBAR(session->status_bar), + session->phone_context_id, + _(state_data[state].status_bar)); + + gtk_label_set_text(GTK_LABEL(session->pick_up_label), + _(state_data[state].pick_up_label)); + gtk_widget_set_sensitive(session->pick_up_button, + state_data[state].pick_up_state); + + gtk_label_set_text(GTK_LABEL(session->hang_up_label), + _(state_data[state].hang_up_label)); + gtk_widget_set_sensitive(session->hang_up_button, + state_data[state].hang_up_state); + + if (state == STATE_READY) { + llcheck_bar_reset(session->llcheck_in); + llcheck_bar_reset(session->llcheck_out); + } + + return result; +} + +/* + * Callback: reinitialize isdn input watchdog + */ +static gboolean gtk_isdn_input_defer_timeout(session_t* session) { + session->gtk_isdn_input_tag = gtk_input_add_full(session->isdn_fd, + GDK_INPUT_READ, + gtk_handle_isdn_input, + NULL, + (gpointer) session, + NULL); + return FALSE; /* don't call me regularly */ +} + +/* defer 300 milliseconds if appropriate */ +#define DEFER_INTERVAL 300 + +/* + * put a graceful delay into GTK main loop to prevent permanent isdn input + * callback + */ +static void gtk_isdn_input_defer(session_t* session) { + gtk_input_remove(session->gtk_isdn_input_tag); + session->gtk_isdn_input_tag = + gtk_timeout_add(DEFER_INTERVAL, + (GtkFunction) gtk_isdn_input_defer_timeout, + session); +} + +/* + * callback for gtk on isdn input + * + * input: data: session (session_t *) + * fd: file descriptor where we got the input from + * condition: will be GDK_INPUT_READ in this case + */ +void gtk_handle_isdn_input(gpointer data, gint fd _U_, + GdkInputCondition condition _U_) { + session_t *session = (session_t *) data; + char *temp; + + switch (session->state) { + case STATE_READY: /* we are in command mode */ + if (isdn_try_read_line(session)){ /* got new line: something happened */ + if (!strncmp(session->isdn_inbuf, "RING/", 5)) { /* -> RINGING state */ + session->isdn_inbuf[session->isdn_inbuf_len - 2] = 0; + /* caller id update */ + session->ring_time = time(NULL); + + /* save callee's number */ + free(session->to); + session->to = strdup(&session->isdn_inbuf[5]); + + cid_add_line(session, CALL_IN, NULL, session->to); + + if (session_set_state(session, STATE_RINGING)) + session_set_state(session, STATE_RINGING_QUIET); + + } else { /* something else */ + if (debug) + fprintf(stderr, "Unknown message from ISDN device.\n"); + } + } + break; + case STATE_DIALING: + if (isdn_try_read_line(session)){ /* a response to our dial request */ + if (strstr(session->isdn_inbuf, "BUSY\r\n")) { /* get back to READY */ + session_set_state(session, STATE_READY); + cid_set_duration(session, _("(BUSY)")); + } else if (strstr(session->isdn_inbuf, "VCON\r\n")) { /* let's go! */ + session_start_conversation(session); /* including state transition */ + } else if (strstr(session->isdn_inbuf, "NO CARRIER\r\n")) { + /* timeout? */ + session_set_state(session, STATE_READY); + cid_set_duration(session, _("(TIMEOUT)")); + } else { /* got some other modem answer string while dialing out */ + if (debug) + fprintf(stderr, "Unknown message from ISDN device.\n"); + } + } + break; + case STATE_RINGING: + case STATE_RINGING_QUIET: + if (isdn_try_read_line(session)){ /* got new line: something happened */ + if (strstr(session->isdn_inbuf, "VCON\r\n")) { /* let's go! */ + /* will only come in STATE_RINGING */ + session_start_conversation(session); /* including state transition */ + } else if (strstr(session->isdn_inbuf, "CALLER NUMBER: ")) { + /* got Caller ID */ + session->isdn_inbuf[session->isdn_inbuf_len - 2] = 0; + + /* save caller's number */ + free(session->from); + session->from = strdup(&session->isdn_inbuf[15]); + + /* complete from field */ + cid_set_from(session, session->from); + + /* execute command if given */ + if (session->exec_on_incoming) { + temp = strdup(session->exec_on_incoming); + substitute(&temp, "%n", session->to); + substitute(&temp, "%s", session->from); + execute(temp); + free(temp); + } + + } else if (strstr(session->isdn_inbuf, "RUNG\r\n")) { + /* caller giving up */ + session_set_state(session, STATE_READY); + cid_set_duration(session, _("(RUNG)")); + cid_mark_row(session, session->cid_num - 1, TRUE); + } else { /* got some other modem answer string while it rings */ + if (debug) + fprintf(stderr, "Unknown message from ISDN device.\n"); + } + } + break; + case STATE_CONVERSATION: + process_isdn_source(session); + if (session->samples_in >= ISDN_SPEED) + session->samples_in %= ISDN_SPEED; + session->no_input = 0; + + if (session->aborted || session->hangup) { /* That's it! */ + + if (session->hangup) + session_deinit_conversation(session, 0); /* 0 == other side hung up */ + else + session_deinit_conversation(session, 1); /* 1 == let's hang up (I/O error) */ + + session_set_state(session, STATE_READY); + cid_set_duration(session, NULL); + } + break; + case STATE_SERVICE: + if (debug) + fprintf(stderr, "Note: Got ISDN input in service mode.\n"); + gtk_isdn_input_defer(session); + break; + case STATE_PLAYBACK: + if (debug) + fprintf(stderr, "Note: Got ISDN input in playback mode.\n"); + gtk_isdn_input_defer(session); + break; + default: + fprintf(stderr, + "Warning: gtk_handle_isdn_input: Unknown session state.\n"); + gtk_isdn_input_defer(session); + } +} + +/* + * callback for gtk on audio isdn input + * + * input: data: session (session_t *) + * fd: file descriptor where we got the input from + * condition: will be GDK_INPUT_READ in this case + */ +void gtk_handle_audio_input(gpointer data, gint fd _U_, + GdkInputCondition condition _U_) { + session_t *session = (session_t *) data; + + switch (session->state) { + case STATE_READY: /* we are in command mode */ + if (debug > 1) + fprintf(stderr, "Warning: Got audio input in ready mode (ALSA?).\n"); + /* flush audio input */ + read(session->audio_fd_in, + session->audio_inbuf, session->fragment_size_in); + break; + case STATE_DIALING: + if (debug > 1) + fprintf(stderr, "Warning: Got audio input in dialing mode (ALSA?).\n"); + /* flush audio input */ + read(session->audio_fd_in, + session->audio_inbuf, session->fragment_size_in); + break; + case STATE_RINGING: + if (debug > 1) + fprintf(stderr, "Warning: Got audio input in ringing mode (ALSA?).\n"); + /* flush audio input */ + read(session->audio_fd_in, + session->audio_inbuf, session->fragment_size_in); + break; + case STATE_RINGING_QUIET: + if (debug > 1) + fprintf(stderr, + "Warning: Got audio input in QUIET ringing mode.\n"); + /* flush audio input */ + read(session->audio_fd_in, + session->audio_inbuf, session->fragment_size_in); + break; + case STATE_CONVERSATION: + process_audio_source(session); + if (session->samples_out >= session->audio_speed_in) + session->samples_out %= session->audio_speed_in; + session->no_input++; + + /* if no more input from isdn came, assume abort and switch back */ + if (session->no_input >= 10) { + /* XXX: reasonable number? */ + if (isdn_blockmode(session->isdn_fd, 0)) + fprintf(stderr, "Error: Could not switching off isdn blockmode.\n"); + session->no_input = 0; + } + if (session->aborted) { /* That's it! */ + + session_deinit_conversation(session, 1); + /* 1 == let's hang up (I/O error) */ + + session_set_state(session, STATE_READY); + cid_set_duration(session, NULL); + } + break; + case STATE_SERVICE: + if (debug > 1) + fprintf(stderr, "Warning: Got audio input in service mode (ALSA?).\n"); + /* flush audio input */ + read(session->audio_fd_in, + session->audio_inbuf, session->fragment_size_in); + break; + case STATE_PLAYBACK: + if (debug > 1) + fprintf(stderr, "Warning: Got audio input in playback mode (ALSA?).\n"); + /* flush audio input */ + read(session->audio_fd_in, + session->audio_inbuf, session->fragment_size_in); + break; + default: + fprintf(stderr, + "Warning: gtk_handle_audio_input: Unknown session state.\n"); + /* flush audio input */ + read(session->audio_fd_in, + session->audio_inbuf, session->fragment_size_in); + } +} + +/* + * initiates dialing to specified number + * -> changes contents of dial entry and simulates pick up button + */ +void session_make_call(session_t *session, char *number) { + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(session->dial_number_box)->entry), + number); + gtk_button_clicked(GTK_BUTTON(session->pick_up_button)); +} + +/* + * callback for GTK on pick up button clicked + * + * input: widget: the button + * data: will be a (session_t *) + */ +void gtk_handle_pick_up_button(GtkWidget *widget _U_, gpointer data) { + session_t *session = (session_t *) data; + char *s; /* the modem dial string */ + const char *number; /* the number to dial "inside" gtk (entry) */ + char *clear_number; /* number after un_vanity() */ + int result; + + switch (session->state) { + case STATE_READY: /* we are in command mode and want to dial */ + number = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(session->dial_number_box) + ->entry)); + /* replace letters with numbers ("Vanity" Numbers) */ + clear_number = un_vanity(strdup(number)); + if ((s = (char*) malloc(strlen(clear_number) + 5)) && + strcmp(clear_number, "")) { + if (!session_set_state(session, STATE_DIALING)) { + /* dial only if audio is on etc. */ + snprintf(s, strlen(clear_number) + 5, "ATD%s\n", clear_number); + + tty_clear(session->isdn_fd); + result = tty_write(session->isdn_fd, s); + free(s); + if (result) { + fprintf(stderr, "Error dialing.\n"); + } else { + + /* update dial combo box */ + session_history_add(session, number); + + /* caller id update */ + session->ring_time = time(NULL); + cid_add_line(session, CALL_OUT, session->msn, clear_number); + + /* save caller's and callee's number */ + free(session->from); + session->from = strdup(session->msn); + free(session->to); + session->to = strdup(clear_number); + } + } else { + show_audio_error_dialog(); + } + } + + free(clear_number); + break; + + case STATE_DIALING: /* already dialing! */ + break; + case STATE_RINGING: /* we want to pick up the phone while it rings */ + tty_clear(session->isdn_fd); + if (tty_write(session->isdn_fd, "ATA\n")) + fprintf(stderr, "Error answering call.\n"); + break; + case STATE_RINGING_QUIET: + if (!session_set_state(session, STATE_RINGING)) { + tty_clear(session->isdn_fd); + if (tty_write(session->isdn_fd, "ATA\n")) + fprintf(stderr, "Error answering call.\n"); + } else { + show_audio_error_dialog(); + } + break; + case STATE_CONVERSATION: /* channel already working */ + fprintf(stderr, + "Non-sense warning: Pick up button pressed in conversation mode\n"); + break; + case STATE_SERVICE: + fprintf(stderr, + "Non-sense warning: Pick up button pressed in service mode\n"); + break; + case STATE_PLAYBACK: + fprintf(stderr, + "Non-sense warning: Pick up button pressed in playback mode\n"); + break; + default: + fprintf(stderr, + "Warning: gtk_handle_pick_up_button: Unknown session state.\n"); + } +} + +/* + * callback for GTK on hang up button clicked, !!! also called on exit !!! + * + * input: widget: the button, NULL when called directly (on exit) + * data: will be a (session_t *) + */ +void gtk_handle_hang_up_button(GtkWidget *widget _U_, gpointer data) { + session_t *session = (session_t *) data; + + switch (session->state) { + case STATE_READY: /* we are already in command mode */ + break; + case STATE_DIALING:/* abort dialing */ + tty_clear(session->isdn_fd); + if (tty_write(session->isdn_fd, "ATH\n")) + fprintf(stderr, "Error answering call.\n"); + session_set_state(session, STATE_READY); + cid_set_duration(session, _("(ABORTED)")); + break; + case STATE_RINGING: /* reject call */ + case STATE_RINGING_QUIET: /* reject call */ + tty_clear(session->isdn_fd); + if (tty_write(session->isdn_fd, "ATH\n")) + fprintf(stderr, "Error answering call.\n"); + session_set_state(session, STATE_READY); + cid_set_duration(session, _("(REJECTED)")); + break; + case STATE_CONVERSATION: /* hang up (while b-channel is open) */ + session_deinit_conversation(session, 1); /* 1 == we hang up ourselves ;) */ + + session_set_state(session, STATE_READY); + cid_set_duration(session, NULL); + break; + case STATE_SERVICE: + fprintf(stderr, + "Non-sense warning: Hang up button pressed in service mode\n"); + break; + case STATE_PLAYBACK: + session_set_state(session, STATE_READY); + break; + default: + fprintf(stderr, + "Warning: gtk_handle_hang_up_button: Unknown session state.\n"); + } +} + +/* + * cut session->dial_number_history to specified size + * (session->dial_number_history_maxlen) + * -> and redisplay in session->dial_number_box + */ +static void session_history_normalize(session_t *session) { + /* cut size if needed */ + while (g_list_length(session->dial_number_history) > + session->dial_number_history_maxlen + 1) { + free(g_list_nth_data(session->dial_number_history, + g_list_length(session->dial_number_history) - 1)); + session->dial_number_history = g_list_remove_link( + session->dial_number_history, + g_list_last(session->dial_number_history)); + } + gtk_combo_set_popdown_strings(GTK_COMBO(session->dial_number_box), + session->dial_number_history); +} + +/* + * Add line to history of dial number combo box at start (first row) + * and care about maximum size of history + * + * number will be copied, so caller has to care about it's associated memory + */ +void session_history_add(session_t *session, const char *number) { + char *temp = strdup(number); + + session->dial_number_history = g_list_insert( + session->dial_number_history, temp, 1); + session_history_normalize(session); +} + +/* + * like session_history_add but _appending_ number to list + */ +void session_history_append(session_t *session, char *number) { + char *temp = strdup(number); + + session->dial_number_history = g_list_append( + session->dial_number_history, temp); + session_history_normalize(session); +} + diff --git a/src/session.h b/src/session.h new file mode 100644 index 0000000..6b5fdc2 --- /dev/null +++ b/src/session.h @@ -0,0 +1,272 @@ +/* + * definitions for runtime session specific data handling + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ANT_SESSION_H +#define _ANT_SESSION_H + +#include "config.h" + +/* regular GNU system includes */ +#ifdef HAVE_TERMIOS_H + #include +#endif +#include + +/* GTK */ +#include + +/* own header files */ +#include "recording.h" + +#define SESSION_PRESET_SIZE 4 + +enum state_t { + STATE_READY, /* completely idle */ + STATE_RINGING, /* somebody's calling */ + STATE_RINGING_QUIET, /* same as above, audio off (device blocked) */ + STATE_DIALING, /* we are dialing out */ + STATE_CONVERSATION, /* we are talking */ + STATE_SERVICE, /* special mode (llcheck) */ + STATE_PLAYBACK, /* sound playback, usually recorded conversation */ + + STATE_NUMBER /* dummy to calculate size */ +}; + +enum effect_t { + EFFECT_NONE, /* nothing is played currently */ + EFFECT_RING, /* somebody's calling */ + EFFECT_RINGING, /* waiting for the other end to pick up the phone */ + EFFECT_TEST, /* play test sound (e.g. line level check) */ + EFFECT_TOUCHTONE,/* play a touchtone */ + EFFECT_SOUNDFILE /* play sound from file */ +}; + +/* + * Data needed for setting the session state (the state is the index) + */ +struct state_data_t { + char *status_bar; + char *pick_up_label; + int pick_up_state; + char *hang_up_label; + int hang_up_state; +}; + +struct state_data_t state_data[STATE_NUMBER]; + +/* + * session data + */ +typedef struct { + /* audio device data */ + char *audio_device_name_in; /* allocated memory! */ + char *audio_device_name_out; /* allocated memory! */ + int audio_fd_in; /* audio device file descriptors */ + int audio_fd_out; + unsigned int audio_speed_in; /* sound device recording speed */ + unsigned int audio_speed_out; /* sound device playback speed */ + int fragment_size_in; /* sound device buffer fragment sizes in bytes */ + int fragment_size_out; + int *format_priorities; /* 0-terminated sorted list of preferenced formats */ + int audio_format_in; /* the actual formats */ + int audio_format_out; + int audio_sample_size_in; /* number of bytes of a sample */ + int audio_sample_size_out; + unsigned char *audio_inbuf; /* buffer: should have size fragment_size_in */ + unsigned char *audio_outbuf; /* buffer: should have size fragment_size_out */ + int audio_outbuf_index; /* needed for conversation mode output memory */ + + /* isdn data */ + char* isdn_device_name; /* "/dev/ttyIxx", xx == 0 .. 63 */ + int isdn_fd; + char* isdn_lockfile_name; + int isdn_inbuf_size; + int isdn_outbuf_size; + unsigned char *isdn_inbuf; /* 8 bit ulaw */ + unsigned char *isdn_outbuf; + int isdn_inbuf_len; /* index of '\0' in audio_inbuf in command mode, + if char at this index != 0 -> reading line */ + int isdn_outbuf_index; /* needed for conversation mode output memory */ + int escape; /* escape mode/state RECEIVING isdn data */ + int no_input; /* after this many select calls without isdn input + get back from blockmode */ + struct termios isdn_backup; /* saved state to restore on exit */ + + char *from; /* caller's number */ + char *to; /* callee's number */ + + /* mediation data */ + /* Look-up-tables for audio <-> isdn conversion: */ + unsigned char *audio_LUT_in; /* isdn -> audio */ + unsigned char *audio_LUT_out; /* audio -> isdn */ + unsigned char *audio_LUT_generate; /* 8 bit unsigned -> isdn */ + unsigned char *audio_LUT_analyze; /* isdn -> 8 bit unsigned */ + short *audio_LUT_ulaw2short; /* unsigned char (ulaw) -> short */ + double ratio_in; /* ratio: audio output rate / isdn input rate */ + double ratio_out; /* ratio: isdn output rate / audio input rate */ + unsigned int samples_in; /* ring counter of samples: from isdn */ + unsigned int samples_out; /* ... ... : from sound device */ + + /* recording data */ + short *rec_buf_local; /* pointers to recording buffers */ + short *rec_buf_remote; + int rec_buf_local_index; /* number of shorts in local recording buffer */ + int rec_buf_remote_index; /* number of shorts in local recording buffer */ + int rec_buf_local_size; /* recording buffer sizes */ + int rec_buf_remote_size; + struct recorder_t *recorder; /* recorder internal data */ + + /* GUI elements in this session (GTK specific) */ + GtkWidget *main_window; /* the main window (with style ...) */ + GtkWidget *pick_up_button; /* the pick up button to enable / disable */ + GtkWidget *pick_up_label; /* the label on the pick up button */ + GtkWidget *hang_up_button; /* the hang up button to enable / disable */ + GtkWidget *hang_up_label; /* the label on the hang up button */ + GtkWidget *dial_number_box; /* the dial number combo box */ + GList *dial_number_history; /* the last called numbers */ + unsigned int dial_number_history_maxlen; /* how many numbers to remember */ + unsigned int dial_number_history_pointer; /* which one to use next if req */ + GtkWidget *status_bar; /* the status bar */ + gint phone_context_id; /* a context for the status bar */ + GtkWidget *audio_warning; /* inside status bar */ + gint audio_context_id; /* a context for audio_warning */ + + GtkWidget *llcheck; /* line level check widget inside status bar */ + GtkWidget *llcheck_in; /* input level meter */ + GtkWidget *llcheck_out; /* output level meter */ + GtkWidget *llcheck_check_menu_item; /* state of line levels (status bar) */ + + guint gtk_isdn_input_tag; /* these tags are saved to later remove handlers */ + guint gtk_audio_input_tag; + + GtkWidget *controlpad; /* key pad etc. */ + GtkWidget *controlpad_check_menu_item; /* display state of control pad */ + GtkWidget *mute_button; /* toggle button */ + GtkWidget *muted_warning; /* show in status bar if muted */ + gint muted_context_id; /* a context for the status bar */ + + GtkWidget *record_checkbutton; /* recording checkbutton */ + GtkWidget *record_checkbutton_local; /* local recording checkbutton */ + GtkWidget *record_checkbutton_remote; /* remote recording checkbutton */ + + /* caller id related */ + GtkWidget *cid; /* the caller id widget itself (to show/hide) */ + GtkWidget *cid_check_menu_item; /* to handle state of cid monitor (show?) */ + GtkWidget *cid_list; /* the list to hold the individual call data */ + GtkWidget *cid_scrolled_window; /* the home of the clist with adjustments */ + gint cid_num; /* number of rows in list */ + gint cid_num_max; /* maximum number of rows in list */ + time_t vcon_time; /* the start of conversation mode (for duration calc.) */ + time_t ring_time; /* the first sign of the conversation (dial/ring) */ + /* the symbols for the CList */ + GdkPixmap *symbol_in_pixmap; + GdkBitmap *symbol_in_bitmap; + GdkPixmap *symbol_out_pixmap; + GdkBitmap *symbol_out_bitmap; + GdkPixmap *symbol_record_pixmap; + GdkBitmap *symbol_record_bitmap; + + GtkWidget *menuitem_settings; /* Menu items to select / deselect */ + GtkWidget *menuitem_line_check; + + /* ringing etc. */ + guint effect_tag; /* remove this callback after e.g. ringing */ + enum effect_t effect; /* which effect is currently been played? */ + unsigned int effect_pos; /* sample position in effect */ + char* effect_filename; /* the file to playback */ + SNDFILE* effect_sndfile; /* the handle */ + SF_INFO effect_sfinfo; /* info struct about effect_sndfile */ + short* effect_sndfile_buffer;/*temporary buffer to construct playback output*/ + int effect_sndfile_buffer_frames;/*number of frames of effect_sndfile_buffer*/ + time_t effect_playback_start_time; /* start time of playback */ + int touchtone_countdown_isdn; /* number of samples yet to play */ + int touchtone_countdown_audio; + int touchtone_index; /* which touchtone */ + + /* phone specific */ + enum state_t state; /* which state we are currently in */ + int hangup; /* remote hangup */ + int aborted; /* i/o error (isdn or audio) */ + + char* msn; /* originating msn, allocated memory! */ + char* msns; /* comma-separated list of msns to listen on, allocated memory!*/ + + int unanswered; /* unanswered calls for this session */ + + /* some options (useful for options file handling) */ + int option_save_options; /* save options on exit */ + int option_release_devices; /* close sound devices while not needed */ + int option_show_llcheck; /* show line level checks in main window */ + int option_show_callerid; /* show callerid part in main window */ + int option_show_controlpad; /* show control pad (key pad etc.) */ + int option_muted; /* mute microphone (other party gets zeros) */ + int option_record; /* record to file */ + int option_record_local; /* record local channel */ + int option_record_remote; /* record remote channel */ + enum recording_format_t option_recording_format; /* recording file format */ + + int option_calls_merge; /* merge isdnlog */ + int option_calls_merge_max_days; + + char *exec_on_incoming; /* string with command to execute on incoming call */ + int option_popup; /* push main window to foreground on incoming call */ + + char* preset_names[SESSION_PRESET_SIZE]; /* names and numbers for */ + char* preset_numbers[SESSION_PRESET_SIZE]; /* preset buttons */ + + int local_sock; /* unix domain socket for local server functionality */ + guint gtk_local_input_tag; /* gtk tag for gtk main loop select */ +} session_t; + +extern session_t session; + +int session_set_state(session_t *session, enum state_t state); +void session_io_handlers_start(session_t *session); +void session_io_handlers_stop(session_t *session); +int session_reset_audio(session_t *session); +int session_audio_open(session_t *session); +int session_audio_close(session_t *session); +int session_audio_init(session_t *session); +int session_audio_deinit(session_t *session); + +int session_init(session_t *session, + char *audio_device_name_in, + char *audio_device_name_out, + char *msn, char *msns); +void session_audio_free(session_t *session); +int session_deinit(session_t *session); + +void session_effect_start(session_t *session, enum effect_t kind); +void session_effect_stop(session_t *session); + +void gtk_handle_isdn_input(gpointer data, gint fd, + GdkInputCondition condition); +void gtk_handle_audio_input(gpointer data, gint fd, + GdkInputCondition condition); +void session_make_call(session_t *session, char *number); +void gtk_handle_pick_up_button(GtkWidget *widget, gpointer data); +void gtk_handle_hang_up_button(GtkWidget *widget, gpointer data); + +void session_history_add(session_t *session, const char *number); +void session_history_append(session_t *session, char *number); +#endif /* session.h */ diff --git a/src/settings.c b/src/settings.c new file mode 100644 index 0000000..93010d5 --- /dev/null +++ b/src/settings.c @@ -0,0 +1,601 @@ +/* + * functions for dotfile handling (options, history, ...) + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * + * To add a new option, do the following: + * -> set default in session_init() + * -> add entry in settings_option_set() + * -> add entry in settings_options_write() + * -> of course, set it in gtksettings (also set_data()!) / whatever + * -> get it back in gtksettings_try() + */ + +/* regular GNU system includes */ +#include +#include +#include +#include +#include +#include + +/* own header files */ +#include "globals.h" +#include "session.h" +#include "settings.h" +#include "calleridparser.h" +#include "util.h" +#include "callerid.h" + +#include "isdn.h" +#include "isdnlexer.h" +#include "isdnparser.h" +#include "isdntree.h" + +extern FILE *callerid_in; +int callerid_parse(void *session); +extern FILE *isdn_in; +int isdn_parse(); + +/* + * sets an option for the specified session + * + * used as callback from yyparse() + */ +void settings_option_set(session_t *session, char *option, char *value) { + int i_value = INT_MIN; /* set value to 0 or 1 if appropriate */ + + if (!strcmp(value, "0") || !strcasecmp(value, "false") || + !strcasecmp(value, "off")) { + i_value = 0; + } else + if (!strcmp(value, "1") || !strcasecmp(value, "true") || + !strcasecmp(value, "on")) { + i_value = 1; + } else + i_value = strtol(value, NULL, 0); + + /* Settings */ + if (i_value != INT_MIN) { + if (!strcmp(option, "HistorySize")) { + session->dial_number_history_maxlen = i_value; + } + if (!strcmp(option, "CallerIDSize")) { + session->cid_num_max = i_value; + } + + if (!strcmp(option, "SaveOptions")) { + session->option_save_options = (i_value == 0 ? 0 : 1); + } + + if (!strcmp(option, "ExecOnIncoming")) { + free(session->exec_on_incoming); + session->exec_on_incoming = strdup(value); + } + if (!strcmp(option, "PopupOnIncoming")) { + session->option_popup = (i_value == 0 ? 0 : 1); + } + + if (!strcmp(option, "RecordingFormat")) { + if (!strcasecmp(value, "aiff")) { + session->option_recording_format = + (session->option_recording_format & ~RECORDING_FORMAT_MAJOR) + | RECORDING_FORMAT_AIFF; + } else { /* wav */ + session->option_recording_format = + (session->option_recording_format & ~RECORDING_FORMAT_MAJOR) + | RECORDING_FORMAT_WAV; + } + } + if (!strcmp(option, "RecordingEncoding")) { + if (!strcasecmp(value, "s16")) { + session->option_recording_format = + (session->option_recording_format & ~RECORDING_FORMAT_MINOR) + | RECORDING_FORMAT_S16; + } else { /* ulaw */ + session->option_recording_format = + (session->option_recording_format & ~RECORDING_FORMAT_MINOR) + | RECORDING_FORMAT_ULAW; + } + } + + if (!strncmp(option, "PresetName", 10)) { + int num = strtol(&option[10], NULL, 0); + if (0 <= num && num < SESSION_PRESET_SIZE) { + free(session->preset_names[num]); + session->preset_names[num] = strdup(value); + } + } + if (!strncmp(option, "PresetNumber", 12)) { + int num = strtol(&option[12], NULL, 0); + if (0 <= num && num < SESSION_PRESET_SIZE) { + free(session->preset_numbers[num]); + session->preset_numbers[num] = strdup(value); + } + } + + if (!strcmp(option, "MergeIsdnlog")) { + session->option_calls_merge = (i_value == 0 ? 0 : 1); + } + if (!strcmp(option, "MergeIsdnlogDays")) { + session->option_calls_merge_max_days = i_value; + } + + if (!strcmp(option, "AudioDeviceIn") && + !strcmp(session->audio_device_name_in, "")) { /* may be overridden */ + free(session->audio_device_name_in); + session->audio_device_name_in = strdup(value); + } + if (!strcmp(option, "AudioDeviceOut") && + !strcmp(session->audio_device_name_out, "")) { /* may be overridden */ + free(session->audio_device_name_out); + session->audio_device_name_out = strdup(value); + } + if (!strcmp(option, "ReleaseAudioDevices")) { + session->option_release_devices = (i_value == 0 ? 0 : 1); + } + if (!strcmp(option, "IdentifyingMSN") && + !strcmp(session->msn, "")) { /* may be overridden */ + free(session->msn); + session->msn = strdup(value); + } + if (!strcmp(option, "ListenOnMSNs") && + !strcmp(session->msns, "")) { /* may be overridden */ + free(session->msns); + session->msns = strdup(value); + } + + /* GUI state */ + if (!strcmp(option, "ShowCallerID")) { + session->option_show_callerid = (i_value == 0 ? 0 : 1); + } + if (!strcmp(option, "ShowLLCheckers")) { + session->option_show_llcheck = (i_value == 0 ? 0 : 1); + } + if (!strcmp(option, "ShowControlPad")) { + session->option_show_controlpad = (i_value == 0 ? 0 : 1); + } + if (!strcmp(option, "Muted")) { + session->option_muted = (i_value == 0 ? 0 : 1); + } + if (!strcmp(option, "RecordToFile")) { + session->option_record = (i_value == 0 ? 0 : 1); + } + if (!strcmp(option, "RecordLocalChannel")) { + session->option_record_local = (i_value == 0 ? 0 : 1); + } + if (!strcmp(option, "RecordRemoteChannel")) { + session->option_record_remote = (i_value == 0 ? 0 : 1); + } + + } +} + +/* + * Read options from options file and isdn4linux config + * + * Here, we parse the config file and _change_ options. The defaults + * will be all set at init time + */ +void settings_options_read(session_t *session) { + char *homedir; + char *filename; + + /* read isdn4linux config */ + isdn_lexer_init(ISDN_CONFIG_FILENAME); + if (!isdn_in) { + fprintf(stderr, "Warning: Couldn't read ISDN config file.\n"); + } else { + isdn_tree_node_t* node; + + isdn_parse(); + isdn_lexer_deinit(); + if (debug > 1) { + printf("ISDN config file (%s) contents:\n", ISDN_CONFIG_FILENAME); + isdn_tree_dump(); + } + /* get calls file name if possible */ + node = isdn_tree; + while (node != NULL) { + if (node->type == ISDN_NODE_TYPE_SECTION && + !strcmp(node->name, "ISDNLOG")) + { + isdn_tree_node_t* entry = node->content.section; + + while (entry != NULL ) { + if (entry->type == ISDN_NODE_TYPE_ENTRY && + !strcmp(entry->name, "LOGFILE")) + { + if (isdn_calls_filename_from_config) + free(isdn_calls_filename_from_config); + isdn_calls_filename_from_config = strdup(entry->content.value); + } + entry = entry->next; + } + } + node = node->next; + } + + isdn_tree_free(); + } + + if (!(homedir = get_homedir())) { + fprintf(stderr, "Warning: Couldn't get home dir.\n"); + return; + } + + /* dotfile */ + if (asprintf(&filename, "%s/." PACKAGE "/%s", + homedir, SETTINGS_OPTIONS_FILENAME) < 0) + { + fprintf(stderr, + "Warning: Couldn't allocate memory for options filename.\n"); + return; + } + + isdn_lexer_init(filename); + if (!isdn_in) { + fprintf(stderr, "Warning: No options file available.\n"); + } else { + isdn_tree_node_t* node; + + isdn_parse(); + isdn_lexer_deinit(); + node = isdn_tree; + if (debug > 1) { + printf("Options file (%s) contents:\n", filename); + isdn_tree_dump(); + } + /* actually set options */ + while (node != NULL) { + switch (node->type) { + case ISDN_NODE_TYPE_ENTRY: + if (debug) + printf("Setting \"%s\" to \"%s\"...\n", + node->name, node->content.value); + settings_option_set(session, node->name, node->content.value); + break; + case ISDN_NODE_TYPE_SECTION: + fprintf(stderr, "Warning: Unexpected section \"%s\".\n", node->name); + break; + case ISDN_NODE_TYPE_SUBSECTION: + fprintf(stderr, + "Warning: Unexpected subsection \"%s\".\n", node->name); + break; + default: + fprintf(stderr, "Unknown ISDN_NODE_TYPE\n"); + } + + node = node->next; + } + + isdn_tree_free(); + } + free(filename); +} + +/* + * write options to options file (in dotfile directory) + */ +void settings_options_write(session_t *session) { + int i; + char *homedir; + char *filename; + FILE *f; + + if (!(homedir = get_homedir())) { + fprintf(stderr, "Warning: Couldn't get home dir.\n"); + return; + } + + if (touch_dotdir()) + return; + + if (asprintf(&filename, "%s/." PACKAGE "/%s", + homedir, SETTINGS_OPTIONS_FILENAME) < 0) { + fprintf(stderr, + "Warning: Couldn't allocate memory for options filename.\n"); + return; + } + + if ((f = fopen(filename, "w"))) { + fprintf(f, "# " PACKAGE " options file \n\n"); + + fprintf(f, "#\n# Number of dialed numbers to remember\n#\n"); + fprintf(f, "HistorySize = %u\n\n", session->dial_number_history_maxlen); + + fprintf(f, "#\n# Maximum number of rows Caller ID window\n#\n"); + fprintf(f, "CallerIDSize = %u\n\n", session->cid_num_max); + + fprintf(f, "#\n# Automatically save options on exit?\n#\n"); + fprintf(f, "SaveOptions = %d\n\n", session->option_save_options); + + fprintf(f, "#\n# Execute an arbitrary command on incoming call\n#\n"); + fprintf(f, "ExecOnIncoming = \"%s\"\n\n", session->exec_on_incoming); + + fprintf(f, "#\n# When activated, the main window will be pushed to " + "foreground\n# on incoming call\n#\n"); + fprintf(f, "PopupOnIncoming = \"%d\"\n\n", session->option_popup); + + fprintf(f, "#\n# Audio recording device\n#\n"); + fprintf(f, "AudioDeviceIn = %s\n\n", session->audio_device_name_in); + + fprintf(f, "#\n# Audio playback device, " + "may be the same as AudioDeviceIn\n#\n"); + fprintf(f, "AudioDeviceOut = %s\n\n", session->audio_device_name_out); + + fprintf(f, "#\n# Release audio devices in idle (\"Ready\") mode " + "(when not needed)\n#\n"); + fprintf(f, "ReleaseAudioDevices = %d\n\n",session->option_release_devices); + + fprintf(f, "#\n# MSN (Multiple Subscriber Number) to send to identify\n" + "# ourselves at called party\n#\n"); + fprintf(f, "IdentifyingMSN = %s\n\n", session->msn); + + fprintf(f, "#\n# These are the MSNs we want to listen on " + "(and accept calls)\n#\n"); + fprintf(f, "ListenOnMSNs = %s\n\n", session->msns); + + fprintf(f, "#\n# Show Caller ID frame in main window?\n#\n"); + fprintf(f, "ShowCallerID = %d\n\n", session->option_show_callerid); + + fprintf(f, "#\n# Show Line Level Checkers in main window?\n#\n"); + fprintf(f, "ShowLLCheckers = %d\n\n", session->option_show_llcheck); + + fprintf(f, "#\n# Show control pad (key pad etc.) in main window?\n#\n"); + fprintf(f, "ShowControlPad = %d\n\n", session->option_show_controlpad); + + fprintf(f, "#\n# Turn on to make the other party receive silence\n#\n"); + fprintf(f, "Muted = %d\n\n", session->option_muted); + + fprintf(f, "#\n# Record Audio stream to file?\n#\n"); + fprintf(f, "RecordToFile = %d\n\n", session->option_record); + + fprintf(f, "#\n# When RecordToFile is set, record local channel?\n#\n"); + fprintf(f, "RecordLocalChannel = %d\n\n", session->option_record_local); + + fprintf(f, "#\n# When RecordToFile is set, record remote channel?\n#\n"); + fprintf(f, "RecordRemoteChannel = %d\n\n", session->option_record_remote); + + fprintf(f, "#\n# Recording file format\n" + "# (\"wav\" for Microsoft WAV / " + "\"aiff\" for Apple/SGI AIFF)\n#\n"); + fprintf(f, "RecordingFormat = \"%s\"\n\n", + (session->option_recording_format & RECORDING_FORMAT_MAJOR) == + RECORDING_FORMAT_WAV ? "wav" : "aiff"); + fprintf(f, "#\n# Recording file encoding\n" + "# (\"ulaw\" for uLaw / \"s16\" for 16-bit signed)\n#\n"); + fprintf(f, "RecordingEncoding = \"%s\"\n\n", + (session->option_recording_format & RECORDING_FORMAT_MINOR) == + RECORDING_FORMAT_S16 ? "s16" : "ulaw"); + + fprintf(f, "#\n# Preset Names and Numbers\n#\n"); + for (i = 0; i < SESSION_PRESET_SIZE; i++) { + fprintf(f, "PresetName%d = \"%s\"\n", i, session->preset_names[i]); + fprintf(f, "PresetNumber%d = \"%s\"\n", i, session->preset_numbers[i]); + } + fprintf(f, "\n"); + + fprintf(f, + "#\n# Merge isdnlog callerid history to local history at startup?\n#\n"); + fprintf(f, "MergeIsdnlog = %d\n\n", session->option_calls_merge); + fprintf(f, "#\n# Get data from this number of last days when retrieving " + "data from\n" + "# isdnlog at startup\n" + "# (set to 0 if you prefer an unlimited number of days)\n#\n"); + fprintf(f, "MergeIsdnlogDays = %d\n\n", + session->option_calls_merge_max_days); + + if (fclose(f) == EOF) { + fprintf(stderr, "Warning: Couldn't close options file.\n"); + } + } else if (debug) { + fprintf(stderr, "Warning: Can't write to options file.\n"); + } + free(filename); +} + +/* Read history file and set dial combo box */ +void settings_history_read(session_t *session) { + char *homedir; + char *filename; + FILE *f; + char *lineptr = NULL; + size_t linesize = 0; + ssize_t got; + + if (!(homedir = get_homedir())) { + fprintf(stderr, "Warning: Couldn't get home dir.\n"); + return; + } + + if (asprintf(&filename, "%s/." PACKAGE "/%s", + homedir, SETTINGS_HISTORY_FILENAME) < 0) { + fprintf(stderr, + "Warning: Couldn't allocate memory for history filename.\n"); + return; + } + + if (debug) + fprintf(stdout, "Info: History Filename: %s.\n", filename); + if ((f = fopen(filename, "r"))) { + do { + got = getline(&lineptr, &linesize, f); + if (lineptr[got - 1] == '\n') { + lineptr[got - 1] = '\0'; + } + if (got > 0 && strlen(lineptr) > 0) { + session_history_append(session, lineptr); + if (debug) + fprintf(stdout, "Info: History Number: %s.\n", lineptr); + } + } while (got > 0); + + if (fclose(f) == EOF) { + fprintf(stderr, "Warning: Couldn't close history file.\n"); + } + } else if (debug) { + fprintf(stderr, "Warning: No history file available.\n"); + } + + free(filename); + + if (lineptr) free(lineptr); +} + +/* + * helper function writing the specified line s to stream f + * used as callback by settings_history_write + */ +static void settings_history_write_line(gpointer s, gpointer f) { + if (strcmp(s, "")) { + fprintf(f, "%s\n", (char*)s); + } +} + +/* + * write out dial history file + */ +void settings_history_write(session_t *session) { + char *homedir; + char *filename; + FILE *f; + + if (!(homedir = get_homedir())) { + fprintf(stderr, "Warning: Couldn't get home dir.\n"); + return; + } + + if (touch_dotdir()) + return; + + if (asprintf(&filename, "%s/." PACKAGE "/%s", + homedir, SETTINGS_HISTORY_FILENAME) < 0) { + fprintf(stderr, + "Warning: Couldn't allocate memory for history filename.\n"); + return; + } + + if ((f = fopen(filename, "w"))) { + g_list_foreach(session->dial_number_history, + settings_history_write_line, f); + + if (fclose(f) == EOF) { + fprintf(stderr, "Warning: Couldn't close history file.\n"); + } + } else if (debug) { + fprintf(stderr, "Warning: Can't write to history file.\n"); + } + + free(filename); +} + +/* Read callerid history file */ +void settings_callerid_read(session_t *session) { + char *homedir; + char *filename; + + if (!(homedir = get_homedir())) { + fprintf(stderr, "Warning: Couldn't get home dir.\n"); + return; + } + + if (asprintf(&filename, "%s/." PACKAGE "/%s", + homedir, SETTINGS_CALLERID_HISTORY_FILENAME) < 0) { + fprintf(stderr, "Warning: " + "Couldn't allocate memory for caller id history filename.\n"); + return; + } + + if ((callerid_in = fopen(filename, "r"))) { + callerid_parse(session); + if (fclose(callerid_in) == EOF) { + fprintf(stderr, "Warning: Couldn't close callerid history file.\n"); + } + } else if (debug) { + fprintf(stderr, "Warning: No caller id history file available.\n"); + } + + free(filename); +} + +/* + * write out callerid history file + */ +void settings_callerid_write(session_t *session) { + char *homedir; + char *filename; + FILE *f; + int akt_line; + gchar *date; + gchar *type; + gchar *from; + gchar *to; + gchar *duration; + + if (!(homedir = get_homedir())) { + fprintf(stderr, "Warning: Couldn't get home dir.\n"); + return; + } + + if (touch_dotdir()) + return; + + if (asprintf(&filename, "%s/." PACKAGE "/%s", + homedir, SETTINGS_CALLERID_HISTORY_FILENAME) < 0) { + fprintf(stderr, "Warning: " + "Couldn't allocate memory for callerid history filename.\n"); + return; + } + + if ((f = fopen(filename, "w"))) { + for (akt_line = 0; akt_line < session->cid_num; akt_line++) + { + gtk_clist_get_text(GTK_CLIST(session->cid_list), akt_line, + CID_COL_TIME, &date); + gtk_clist_get_pixtext(GTK_CLIST(session->cid_list), akt_line, + CID_COL_TYPE, &type, NULL, NULL, NULL); + gtk_clist_get_text(GTK_CLIST(session->cid_list), akt_line, + CID_COL_FROM, &from); + gtk_clist_get_text(GTK_CLIST(session->cid_list), akt_line, + CID_COL_TO, &to); + gtk_clist_get_text(GTK_CLIST(session->cid_list), akt_line, + CID_COL_DURATION, &duration); + + fprintf (f, "%-19s|%-3s|%-20s|%-20s|%-10s\n", + date, type, from, to, duration); + if (debug > 1) + fprintf(stderr, "%-19s|%-3s|%-20s|%-20s|%-10s\n", + date, type, from, to, duration); + + } + + if (fclose(f) == EOF) { + fprintf(stderr, "Warning: Couldn't close callerid history file.\n"); + } + } else if (debug) { + fprintf(stderr, "Warning: Can't write to callerid history file.\n"); + } + + free(filename); + +} + diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 0000000..90e0544 --- /dev/null +++ b/src/settings.h @@ -0,0 +1,40 @@ +/* + * functions for dotfile handling (options, history, ...) + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* own header files */ +#include "session.h" + +#define SETTINGS_OPTIONS_FILENAME "options" +#define SETTINGS_HISTORY_FILENAME "history" +#define SETTINGS_CALLERID_HISTORY_FILENAME "callerid" + + +void settings_option_set(session_t *session, char *option, char *value); +void settings_options_read(session_t *session); +void settings_options_write(session_t *session); + +void settings_history_read(session_t *session); +void settings_history_write(session_t *session); + +void settings_callerid_read(session_t *session); +void settings_callerid_write(session_t *session); diff --git a/src/sound.c b/src/sound.c new file mode 100644 index 0000000..67b6818 --- /dev/null +++ b/src/sound.c @@ -0,0 +1,408 @@ +/* + * OSS sound handling functions + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "config.h" + +/* GNU headers */ +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_UNISTD_H + #include +#endif +#ifdef HAVE_FCNTL_H + #include +#endif +#include +#include +#include +#ifdef HAVE_STDLIB_H + #include +#endif +#include + +/* own header files */ +#include "globals.h" +#include "sound.h" + +int default_audio_priorities[] = {AFMT_S16_LE,/* try formats in this order */ \ + AFMT_S16_BE,\ + AFMT_U16_LE,\ + AFMT_U16_BE,\ + AFMT_U8,\ + AFMT_S8,\ + /* ulaw at last because no native soundcard support assumed */ \ + AFMT_MU_LAW,\ + 0}; /* end of list */ +/* + * common initialization for a specific audio device + * + * NOTE: Assumes opened device, but leaves it in a state not able for further + * use when not successful. The device has to be closed and opened again. + * + * input: audio_fd: valid file descriptor of an audio device, + * format, number of channels, requested sampling rate + * requested fragment sizes + * + * returns: 0 if successful, non-zero otherwise + * + * output: speed: actually sampling rate + * fragment_size: actually fragment size for this device + * + */ +int init_audio_device(int audio_fd, int format, int channels, int *speed, + int *fragment_size) { + int temp_format; + int temp_channels; + int temp_speed; + int formats_mask; + int fragment_arg; + + /* set fragment size */ + fragment_arg = 0x7FFF0000 + logb(*fragment_size); + + if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &fragment_arg)) { + perror("SNDCTL_DSP_SETFRAGMENT"); + return(-1); + } + + /* query supported audio formats */ + if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &formats_mask) == -1) { + perror("SNDCTL_DSP_GETFMTS"); + return(-1); + } + if (!(formats_mask & format)) { /* requested format not supported */ + return(-1); /* caller should try another one */ + } + + /* audio format */ + temp_format = format; + if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &temp_format) == -1) { + perror("SNDCTL_DSP_SETFMT"); + return(-1); + } + + /* number of channels */ + temp_channels = channels; + if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &temp_channels) == -1) { + perror("SNDCTL_DSP_CHANNELS"); + return(-1); + } + if (temp_channels != channels) { + fprintf(stderr, "Error: %d not supported as number of channels", channels); + return(-1); + } + + /* sampling rate */ + temp_speed = *speed; + if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &temp_speed) == -1) { + perror("SNDCTL_DSP_SPEED"); + /* rarely returned because of oss' liberal use of other possible speeds */ + return(-1); + } + *speed = temp_speed; /* actually used speed */ + + /* "verify" fragment size: + * let the driver actually calculate the fragment size + */ + if (ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_arg)) { + perror("SNDCTL_DSP_GETBLKSIZE"); + return(-1); + } + if (fragment_arg != *fragment_size) + fprintf(stderr, "Note: Using non-default fragment size %d.\n", + fragment_arg); + *fragment_size = fragment_arg; + + return 0; +} + +/* + * opens the audio device(s). if in_audio_device_name and out_audio_device_name + * are equal, full duplex mode is assumed + * + * input: in_audio_device_name, out_audio_device_name: strings + * channels: requestes number of channels (1 / 2) + * format_priorities: list of sorted integers with valid sound formats + * (e.g. AFMT_U8). the first working one will be used + * speed_in, speed_out: requested speeds (equal for full duplex) + * + * returns: 0 if successful + * -1 if not successful + * + * output: + * audio_fd_in, audio_fd_out: file descriptors + * fragment_size_in, fragment_size_out: device buffer fragment sizes + * format_in, format_out: actually used formats + * speed_in, speed_out: actually used speeds + */ +int open_audio_devices(char *in_audio_device_name, + char *out_audio_device_name, + int channels, int *format_priorities, + int *audio_fd_in, int *audio_fd_out, + int *fragment_size_in, int *fragment_size_out, + int *format_in, int *format_out, + int *speed_in, int *speed_out) { + int audio_fd; + int initresult; + int capabilities; + int *priority; + + /* try to open the sound device */ + if (strcmp(in_audio_device_name, out_audio_device_name) == 0) { + /* same device for input and output: full duplex */ + + for (initresult = -1, priority = format_priorities; + priority && initresult; priority++) { /* try different formats */ + if ((audio_fd = open(in_audio_device_name, O_RDWR | O_NONBLOCK, 0)) + == -1) { + perror(in_audio_device_name); + return(-1); + } + /* device is in non-blocking mode now */ + + *audio_fd_in = audio_fd; + *audio_fd_out = audio_fd; + + /* set device to full duplex mode */ + if (ioctl(audio_fd, SNDCTL_DSP_SETDUPLEX, 0)) { + perror("SNDCTL_DSP_SETDUPLEX"); + return(-1); + } + if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &capabilities)) { + perror("SNDCTL_DSP_GETCAPS"); + return(-1); + } + if (!(capabilities & DSP_CAP_DUPLEX)) { + fprintf(stderr, "Error: device doesn't support full duplex mode\n"); + return(-1); + } + + /* *speed_in assumed to be equal to *speed_out */ + *format_in = *priority; /* get new format to try */ + initresult = init_audio_device(audio_fd, *format_in, channels, speed_in, + fragment_size_in); + if (initresult) /* let's retry (and re-open) */ + close_audio_devices(*audio_fd_in, *audio_fd_out); + } + *format_out = *format_in; + *speed_out = *speed_in; + *fragment_size_out = *fragment_size_in; + return initresult; + } else { + /* different devices for input and output */ + + for (initresult = -1, priority = format_priorities; + initresult && priority; priority++) { + if ((audio_fd = open(in_audio_device_name, O_RDONLY | O_NONBLOCK, 0)) == + -1) { + perror(in_audio_device_name); + return(-1); + } + /* device is in non-blocking mode now */ + + *audio_fd_in = audio_fd; + *format_in = *priority; + initresult = init_audio_device(audio_fd, *format_in, channels, speed_in, + fragment_size_in); + if (initresult) /* let's retry (and re-open) */ + if (close(audio_fd)) { + perror("close audio in device"); + return -1; + } + } + + if (initresult) return initresult; /* no chance */ + + for (initresult = -1, priority = format_priorities; + initresult && priority; priority++) { + if ((audio_fd = open(out_audio_device_name, O_WRONLY | O_NONBLOCK, 0)) + == -1) { + perror(out_audio_device_name); + if (close(*audio_fd_in)) { /* error -> close audio_in device */ + perror("close audio in device"); + } + return(-1); + } + /* device is in non-blocking mode now */ + + *audio_fd_out = audio_fd; + *format_out = *priority; + + initresult = init_audio_device(audio_fd, *format_out, channels, + speed_out, fragment_size_out); + if (initresult) /* let's retry (and re-open) */ + if (close(audio_fd)) { + perror("close audio out device"); + return -1; + } + } + return initresult; + } +} + +/* + * stops audio playback and recording on specified file descriptors + */ +int audio_stop(int audio_fd_in, int audio_fd_out) { + /* Instead of ioctl SNDCTL_DSP_RESET, OSS Programmer's Guide recommends + * closing and reopening the devices (-> close/open_audio_devices). + * Here, we flush the input buffer and use SNDCTL_DSP_RESET + * to clean up for further recording, but on restart, old input comes again. + */ + int result; + int frag_size; + char *buf; /* temporary allocated buffer */ + + struct timeval tv; + fd_set fds; + int num; /* number of file descriptors with data (0/1) */ + + /* flush input buffer */ + if (ioctl(audio_fd_in, SNDCTL_DSP_GETBLKSIZE, &frag_size)) + fprintf(stderr, "Error obtaining audio input fragment size " + "with SNDCTL_DSP_GETBLKSIZE in audio_stop().\n"); + else { + buf = (char *) malloc(frag_size); + + tv.tv_sec = 0; /* return immediately */ + tv.tv_usec = 0; + + do { + FD_ZERO(&fds); + FD_SET(audio_fd_in, &fds); + + num = select(FD_SETSIZE, &fds, 0, 0, &tv); /* return immediately */ + if (num > 0) + read(audio_fd_in, buf, frag_size); + } while (num > 0); + if (num == -1) + perror("select at audio_stop"); + free(buf); + } + + /* stop device */ + if (audio_fd_in == audio_fd_out) + result = ioctl(audio_fd_in, SNDCTL_DSP_RESET, 0); + else + result = ioctl(audio_fd_in, SNDCTL_DSP_RESET, 0) | + ioctl(audio_fd_out, SNDCTL_DSP_RESET, 0); + + return result; +} + +/* + * Closes specified input/output file descriptors + * returns 0 on success, -1 on error + */ +int close_audio_devices(int audio_fd_in, int audio_fd_out) { + audio_stop(audio_fd_in, audio_fd_out); + + if (close(audio_fd_in) == -1) { + perror("close audio device"); + return -1; + } + if (audio_fd_in != audio_fd_out) + if (close(audio_fd_out) == -1) { + perror("close audio device"); + return -1; + } + return 0; +} + +/* + * returns number of bytes per sample for the specified + * OSS format (e.g. AFMT_U8) + * + * returns >= 1 on success, 0 otherwise (when format not supported) + */ +int sample_size_from_format(int format) { + switch(format) { + case AFMT_U8: + case AFMT_S8: + case AFMT_MU_LAW: + return 1; + + case AFMT_S16_LE: + case AFMT_S16_BE: + case AFMT_U16_LE: + case AFMT_U16_BE: + return 2; + + default: + return 0; + } +} + +/* + * returns the number of available fragents that can be read immediately + * from specified sound device file descriptor fd + */ +int audio_get_read_fragments_number(int fd) { + audio_buf_info info; + + if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) == -1) { + perror("SNDCTL_DSP_GETISPACE"); + } + return info.fragments; +} + +/* + * returns the total number of fragents available for OSS at + * specified sound device file descriptor fd for reading + */ +int audio_get_read_fragments_total(int fd) { + audio_buf_info info; + + if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) == -1) { + perror("SNDCTL_DSP_GETISPACE"); + } + return info.fragstotal; +} + +/* + * returns the number of fragents that can be written (non-blocking) to + * specified sound device file descriptor fd + */ +int audio_get_write_fragments_number(int fd) { + audio_buf_info info; + + if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == -1) { + perror("SNDCTL_DSP_GETOSPACE"); + } + return info.fragments; +} + +/* + * returns the total number of fragents available for OSS at + * specified sound device file descriptor fd for writing + */ +int audio_get_write_fragments_total(int fd) { + audio_buf_info info; + + if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == -1) { + perror("SNDCTL_DSP_GETOSPACE"); + } + return info.fragstotal; +} diff --git a/src/sound.h b/src/sound.h new file mode 100644 index 0000000..eadafe0 --- /dev/null +++ b/src/sound.h @@ -0,0 +1,47 @@ +/* + * OSS sound handling functions + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include + +#define DEFAULT_FRAGMENT_SIZE 1024 +#define DEFAULT_AUDIO_DEVICE_NAME_IN "/dev/dsp" +#define DEFAULT_AUDIO_DEVICE_NAME_OUT "/dev/dsp" + +extern int default_audio_priorities[]; + +int init_audio_device(int audio_fd, int format, int channels, int *speed, + int *fragment_size); +int open_audio_devices(char *in_audio_device_name, + char *out_audio_device_name, + int channels, int *format_priorities, + int *audio_fd_in, int *audio_fd_out, + int *fragment_size_in, int *fragment_size_out, + int *format_in, int *format_out, + int *speed_in, int *speed_out); +int close_audio_devices(int audio_fd_in, int audio_fd_out); +int audio_stop(int audio_fd_in, int audio_fd_out); +int sample_size_from_format(int format); +int audio_get_read_fragments_number(int fd); +int audio_get_read_fragments_total(int fd); +int audio_get_write_fragments_number(int fd); +int audio_get_write_fragments_total(int fd); diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..8e0785f --- /dev/null +++ b/src/util.c @@ -0,0 +1,365 @@ +/* + * miscellaneous glibc extending functions + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "config.h" + +/* regular GNU system includes */ +#include +#include +#ifdef HAVE_STDLIB_H + #include +#endif +#ifdef HAVE_SYS_TIME_H + #include +#endif +#include +#include +#include +#include +#include + +/* own header files */ +#include "globals.h" +#include "util.h" + +/* declared in globals.h, defined here */ +int debug = 0; + +/* Subtract the `struct timeval' values X and Y, + * storing the result in RESULT. + * Return 1 if the difference is negative, otherwise 0. + */ +int timeval_subtract (struct timeval *result, + struct timeval *x, + struct timeval *y) { + /* Perform the carry for the later subtraction by updating y. */ + if (x->tv_usec < y->tv_usec) { + int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; + y->tv_usec -= 1000000 * nsec; + y->tv_sec += nsec; + } + if (x->tv_usec - y->tv_usec > 1000000) { + int nsec = (x->tv_usec - y->tv_usec) / 1000000; + y->tv_usec += 1000000 * nsec; + y->tv_sec -= nsec; + } + + /* Compute the time remaining to wait. + tv_usec is certainly positive. */ + result->tv_sec = x->tv_sec - y->tv_sec; + result->tv_usec = x->tv_usec - y->tv_usec; + + /* Return 1 if result is negative. */ + return x->tv_sec < y->tv_sec; +} + +/* sleeps usecs microseconds (will be interrupted by signals) */ +void ant_sleep(int usecs) { + struct timespec requested; + struct timespec remaining; + + requested.tv_sec = 0; + requested.tv_nsec = usecs * 1000; + nanosleep(&requested, &remaining); +} + +/* + * convert vanity number (case insensitive: 'b','B' -> '2') in-place + */ +char *un_vanity(char *s) { + char *temp = s; + + while (*temp) { + switch (*temp) { + case 'a': case 'b': case 'c': case 'A': case 'B': case 'C': + *temp = '2'; + break; + case 'd': case 'e': case 'f': case 'D': case 'E': case 'F': + *temp = '3'; + break; + case 'g': case 'h': case 'i': case 'G': case 'H': case 'I': + *temp = '4'; + break; + case 'j': case 'k': case 'l': case 'J': case 'K': case 'L': + *temp = '5'; + break; + case 'm': case 'n': case 'o': case 'M': case 'N': case 'O': + *temp = '6'; + break; + case 'p': case 'q': case 'r': case 's': + case 'P': case 'Q': case 'R': case 'S': + *temp = '7'; + break; + case 't': case 'u': case 'v': case 'T': case 'U': case 'V': + *temp = '8'; + break; + case 'w': case 'x': case 'y': case 'z': + case 'W': case 'X': case 'Y': case 'Z': + *temp = '9'; + break; + } + temp++; + } + + return s; +} + +/* + * returns a string representing the time difference between the + * specified times + * + * NOTE: caller has to free() the returned string itself. + */ +char *timediff_str(time_t time1, time_t time0) { + int duration; + char *buf; + int hours; + int minutes; + int seconds; + + buf = (char *)malloc(9); + + duration = (int)difftime(time1, time0); + seconds = duration % 60; + minutes = (duration / 60) % 60; + hours = duration / (60 * 60); + if (snprintf(buf, 9, "%02d:%02d:%02d", hours, minutes, seconds) >= 9) + buf[8] = '\0'; + + return buf; +} + +/* + * returns a string with the specified long int as content + * + * NOTE: caller has to free() the returned memory + */ +char *ltostr(long int i) { + char *s; + + if (asprintf(&s, "%ld", i) < 0) + return NULL; + + return s; +} + +/* + * forks and executes given command (with arguments) via sh + */ +void execute(char *command) { + pid_t result = fork(); + char *argv[] = {"sh", "-c", command, NULL}; + + if (result == -1) { /* error */ + fprintf(stderr, "Fork error.\n"); + } else if (result == 0) { /* we are the child */ + if (execvp("sh", argv)) { + fprintf(stderr, "Exec error.\n"); + exit(1); + } + } +} + +/* + * return home dir, returned buffer must not be freed but will be overwritten + * by subsequent calls (or calls to getpwuid()) + * returns NULL on error + */ +char *get_homedir(void) { + struct passwd *user; + + if (!(user = getpwuid(getuid()))) { + return NULL; + } + + if (user->pw_dir == NULL || !strcmp(user->pw_dir, "") || + user->pw_dir[strlen(user->pw_dir) - 1] == '/') { + return NULL; + } + + return user->pw_dir; +} + +/* + * When the specified directory doesn't exist, create it (755) + * (used by options and history write functions) + * returns 0 on success, -1 otherwise + */ +int touch_dir(char *dirname) { + + if (!mkdir(dirname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) + return 0; + + if (errno == EEXIST) return 0; + + return -1; +} + +/* + * Creates dotdir (in homedir) if it doesn't exist + * + * returns 0 on success, -1 otherwise + */ +int touch_dotdir(void) { + char *homedir; + char *filename; + + if (!(homedir = get_homedir())) { + fprintf(stderr, "Warning: Couldn't get home dir.\n"); + return -1; + } + + if (asprintf(&filename, "%s/." PACKAGE, homedir) < 0) { + fprintf(stderr, + "Warning: Couldn't allocate memory for configuration directory.\n"); + return -1; + } + if (touch_dir(filename) < 0) { + if (debug) + fprintf(stderr, "Warning: Can't reach configuration directory.\n"); + return -1; + } + free(filename); + + return 0; +} + +/* + * in the string s, substitute x by y + * NOTE: s is dynamically allocated and will be re-allocated by this function + * + * returns the number of substitutions + */ +int substitute(char **s, char *x, char *y) { + int result = 0; + char *pos; + char *temp; + + while ((pos = strstr(*s, x))) { /* while we found something: substitute */ + *pos = '\0'; + asprintf(&temp, "%s%s%s", *s, y, &pos[strlen(x)]); + free(*s); + *s = temp; + + result ++; + } + + return result; +} + +/* + * returns the date in the form of only digits, e.g. YYYYMMDDhhmmss + * the resulting string is dynamically allocated and should be deallocated + * with free(). + * + * returns NULL on error + */ +char *util_digitstime(time_t *time) { + char *s = (char *)malloc(15); + int len; + + s[0] = '\1'; + len = strftime(s, 15, "%Y%m%d%H%M%S", localtime(time)); + + if (len == 0 && s[0] != '\0') { + return NULL; + } else { + return s; + } +} + +/* + * returns a string where all occurences of the character c are removed + * from the input string s + * NOTE: caller has to free() the result + */ +char* stripchr(char* s, char c) { + int count = 1; /* trailing space */ + char* temp; + char* result; + + for (temp = s; *temp; temp++) { + if (*temp != c) + count++; + } + if ((result = (char*) malloc (count))) { + temp = result; + while (*s) { + if (*s != c) { + *temp = *s; + temp ++; + } + s++; + } + *temp = '\0'; + } + + return result; +} + +/* + * returns the filename extension for the specified file / path + * or NULL on problems + */ +char* filename_extension(char* fn) { + char* result = strrchr(fn, '.'); + if (result) { + result++; + if (strchr(result, '/')) { + result = NULL; + } + } + return result; +} + +/* + * saves the current codeset globally for further calls to output_codeset_set() + * -> returns 0 on success, -1 otherwise (default: sets codeset to "UTF-8") + */ +static char* output_codeset = NULL; /* the saved codeset */ +int output_codeset_save(void) { + if (!(output_codeset = bind_textdomain_codeset(PACKAGE, NULL))) { + output_codeset = strdup("UTF-8"); + return -1; + } else { + output_codeset = strdup(output_codeset); + return 0; + } +} + +/* + * sets the output codeset GNU gettext produces while translating messages + * if codeset == 0, a saved values will be used. + * (save with: output_codeset_save()) + * -> returns 0 on success, -1 otherwise + */ +int output_codeset_set(char* codeset) { + if (!codeset) + codeset = output_codeset; + if (!bind_textdomain_codeset(PACKAGE, codeset)) { + fprintf(stderr, "Error setting gettext output codeset to %s.\n", codeset); + return -1; + } + return 0; +} + diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..c81cb66 --- /dev/null +++ b/src/util.h @@ -0,0 +1,56 @@ +/* + * miscellaneous glibc extending functions + * + * This file is part of ANT (Ant is Not a Telephone) + * + * Copyright 2002, 2003 Roland Stigge + * + * ANT 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. + * + * ANT 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 ANT; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ANT_UTIL_H +#define _ANT_UTIL_H + +#include "config.h" + +/* regular GNU system includes */ +#ifdef HAVE_SYS_TIME_H + #include +#endif +#include + +#define SHORT_INTERVAL 10000 +/* 10 milliseconds */ + +int timeval_subtract (struct timeval *result, + struct timeval *x, + struct timeval *y); +void ant_sleep(int usecs); +char *un_vanity(char *s); +char *timediff_str(time_t time1, time_t time0); +char *ltostr(long int i); +void execute(char *command); +char *get_homedir(void); +int touch_dir(char *dirname); +int touch_dotdir(void); +int substitute(char **s, char *x, char *y); +char *util_digitstime(time_t *time); +char* stripchr(char* s, char c); +char* filename_extension(char* fn); +int output_codeset_save(void); +int output_codeset_set(char* codeset); + +#endif /* util.h */