From 639a23e72021cec646700c09db368ff33601c58d Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Sat, 24 Nov 2007 14:45:25 +0100 Subject: [PATCH] Incorporate ant-phone 0.1.13 --- .gitignore | 23 + AUTHORS | 11 + COPYING | 340 ++++++++++ ChangeLog | 143 +++++ Makefile.am | 7 + NEWS | 0 TODO | 74 +++ autogen.sh | 8 + configure.ac | 77 +++ doc/Makefile.am | 7 + doc/ant-phone.1 | 60 ++ po/.gitignore | 19 + po/LINGUAS | 3 + po/Makevars | 41 ++ po/POTFILES.in | 24 + po/de.po | 669 +++++++++++++++++++ po/fr.po | 662 +++++++++++++++++++ po/it.po | 661 +++++++++++++++++++ po/nl.po | 663 +++++++++++++++++++ po/ro.po | 661 +++++++++++++++++++ po/sv.po | 668 +++++++++++++++++++ po/tr.po | 662 +++++++++++++++++++ po/vi.po | 666 +++++++++++++++++++ src/.gitignore | 11 + src/Makefile.am | 88 +++ src/aboutlogo.xpm | 338 ++++++++++ src/ant-phone.c | 261 ++++++++ src/backspace.xpm | 14 + src/callerid.c | 926 +++++++++++++++++++++++++++ src/callerid.h | 72 +++ src/calleridlexer.l | 92 +++ src/calleridparser.y | 86 +++ src/client.c | 84 +++ src/client.h | 25 + src/controlpad.c | 490 ++++++++++++++ src/controlpad.h | 29 + src/fxgenerator.c | 145 +++++ src/fxgenerator.h | 28 + src/g711.c | 281 ++++++++ src/g711.h | 32 + src/globals.h | 37 ++ src/gtk.c | 842 ++++++++++++++++++++++++ src/gtk.h | 30 + src/gtksettings.c | 631 ++++++++++++++++++ src/gtksettings.h | 17 + src/hangup.xpm | 19 + src/icon16x16.xpm | 108 ++++ src/icon32x32.xpm | 190 ++++++ src/icon48x48.xpm | 256 ++++++++ src/icon64x64.xpm | 316 +++++++++ src/in.xpm | 17 + src/isdn.c | 562 ++++++++++++++++ src/isdn.h | 67 ++ src/isdnlexer.h | 25 + src/isdnlexer.l | 281 ++++++++ src/isdnparser.y | 178 ++++++ src/isdntree.c | 105 +++ src/isdntree.h | 55 ++ src/llcheck.c | 468 ++++++++++++++ src/llcheck.h | 30 + src/mediation.c | 466 ++++++++++++++ src/mediation.h | 39 ++ src/mute.xpm | 20 + src/out.xpm | 17 + src/pickup.xpm | 19 + src/record.xpm | 15 + src/recording.c | 239 +++++++ src/recording.h | 72 +++ src/redial.xpm | 15 + src/server.c | 149 +++++ src/server.h | 40 ++ src/session.c | 1453 ++++++++++++++++++++++++++++++++++++++++++ src/session.h | 272 ++++++++ src/settings.c | 601 +++++++++++++++++ src/settings.h | 40 ++ src/sound.c | 408 ++++++++++++ src/sound.h | 47 ++ src/util.c | 365 +++++++++++ src/util.h | 56 ++ 79 files changed, 17718 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 TODO create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 doc/Makefile.am create mode 100644 doc/ant-phone.1 create mode 100644 po/.gitignore create mode 100644 po/LINGUAS create mode 100644 po/Makevars create mode 100644 po/POTFILES.in create mode 100644 po/de.po create mode 100644 po/fr.po create mode 100644 po/it.po create mode 100644 po/nl.po create mode 100644 po/ro.po create mode 100644 po/sv.po create mode 100644 po/tr.po create mode 100644 po/vi.po create mode 100644 src/.gitignore create mode 100644 src/Makefile.am create mode 100644 src/aboutlogo.xpm create mode 100644 src/ant-phone.c create mode 100644 src/backspace.xpm create mode 100644 src/callerid.c create mode 100644 src/callerid.h create mode 100644 src/calleridlexer.l create mode 100644 src/calleridparser.y create mode 100644 src/client.c create mode 100644 src/client.h create mode 100644 src/controlpad.c create mode 100644 src/controlpad.h create mode 100644 src/fxgenerator.c create mode 100644 src/fxgenerator.h create mode 100644 src/g711.c create mode 100644 src/g711.h create mode 100644 src/globals.h create mode 100644 src/gtk.c create mode 100644 src/gtk.h create mode 100644 src/gtksettings.c create mode 100644 src/gtksettings.h create mode 100644 src/hangup.xpm create mode 100644 src/icon16x16.xpm create mode 100644 src/icon32x32.xpm create mode 100644 src/icon48x48.xpm create mode 100644 src/icon64x64.xpm create mode 100644 src/in.xpm create mode 100644 src/isdn.c create mode 100644 src/isdn.h create mode 100644 src/isdnlexer.h create mode 100644 src/isdnlexer.l create mode 100644 src/isdnparser.y create mode 100644 src/isdntree.c create mode 100644 src/isdntree.h create mode 100644 src/llcheck.c create mode 100644 src/llcheck.h create mode 100644 src/mediation.c create mode 100644 src/mediation.h create mode 100644 src/mute.xpm create mode 100644 src/out.xpm create mode 100644 src/pickup.xpm create mode 100644 src/record.xpm create mode 100644 src/recording.c create mode 100644 src/recording.h create mode 100644 src/redial.xpm create mode 100644 src/server.c create mode 100644 src/server.h create mode 100644 src/session.c create mode 100644 src/session.h create mode 100644 src/settings.c create mode 100644 src/settings.h create mode 100644 src/sound.c create mode 100644 src/sound.h create mode 100644 src/util.c create mode 100644 src/util.h 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 */