cwirc-2.0.0.orig/0000755000175000017500000000000010434147004012044 5ustar pg4ipg4icwirc-2.0.0.orig/COPYING0000644000175000017500000004307007673742777013140 0ustar pg4ipg4i GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 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. cwirc-2.0.0.orig/Changelog0000644000175000017500000003435210433704736013677 0ustar pg4ipg4i2.0.0 (20/05/2006): - Added an entry to disable the decoder 1.8.8 (05/08/2004): - Corrected a bug in the incoming signal buffering that would overwrite buffered events when frames would come too fast during the fade-out period, just after a buffer underrun. 1.8.7 (25/07/2004): - Added a section in the README to explain how to use CWirc with the aRts daemon. - The DTR line is now explicitely set so that CWirc can read back the state of the Morse key contact(s), even if another program left the serial port in a bad state. 1.8.6 (19/07/2004): - Made the plugin stub filter out CWirc frames even when the plugin is disabled, so it's now possible to close the CWirc panel and keep chatting normally on a Morse channel. - Made the plugin stub correctly handle channel locks on different IRC servers, and made it warn the user when a lock is stale. 1.8.5 (08/07/2004): - Corrected the README and added a French translation of it. - Added the -fPIC flag to build the plugin's object files. - Changed the Debian package maintainer and merged his changes. 1.8.4 (20/06/2004): - Corrected a bug that would leave the I/O process running alone if the GUI quit without stopping it properly. - Made the extension API's shared memory key really random. - CWirc now tries to renice itself if the frontend binary is installed suid root, in order to get better I/O performances and cure the scratchy sound problem with low-end sound devices and loaded systems. 1.8.3 (18/06/2004): - Made the sound fragment writing routine less fragile. - Doubled the automatic decoder's speed indicator as a decoder reset button. - Fixed a bug where the CWirc front-end would stop if X-Chat was started from an xterm and the terminal was resized. 1.8.2 (13/06/2004): - Reduced the memory and disk footprint. - General code cleanup. - Made the keyer settings tab become inactive when the selected key type is "straight". - Changed all references to "QRM" into the correct "QRN". - Fixed a GTK error message when starting the GUI. - Fixed a bug that could prevent an extension to be run again if it failed to run once. 1.8.1 (13/04/2004): - Now the plugin doesn't report incoming morse from any source but the current IRC channel, on the current CWirc channel. - Fixed a bug that would make CWirc occasionally send malformed frames containing null events when running with the CW output set to "sounder". 1.8.0 (01/04/2004): - Re-implemented the keyer, with a full set of options. - The frontend now checks its version number against the plugin's, to avoid using an incompatible shared memory structure. 1.7.7 (26/03/2004): - Added "About" tab to give general information about CWirc - Made the cwirc window non-resizable. - Added two new keyer modes besides mode-A and mode-B : a dit memory mode and a dit+dah memory mode. 1.7.6 (23/03/2004): - An undecoded character is now indicated by an underscore in the morse decoder line, and not a question mark, so it's more readable and less confusing. - Corrected the '8' sign in the DOT code table and removed the E-circumflex sign from the French morse code table because it conflicted with the slash sign. 1.7.5 (20/02/2004): - Added a sidetone mode, to key Morse code locally without actually sending anything. This is good to adjust keys and generally play without bothering anyone else, exactly like the equivalent function found on most real transceivers. - Now the Morse decoder also decodes the local key. - Implemented the new ITU "commat" Morse sign ('@' sign, as in emails) and corrected the 'VA' prosign in the Morse code table. 1.7.4 (27/01/2004): - Corrected a bug that spawned an infinity of error popups if writing to the sound device generated an error despite the sound device having been opened and set up successfully. 1.7.3 (14/01/2004): - Added rules to create a binary and source RPMs. 1.7.2 (06/01/2004): - Added DOT code support in the automatic decoder. - Made replying to CTCP queries and returning the current channel number the default behaviour. 1.7.1 (10/11/2003): - The accuracy of sent and received timing events has been improved dramatically. - A bad data corruption bug in the frame sending routine has been corrected. 1.7.0 (09/11/2003): - Added a CWirc extension interface. - Made the ipc routines more generic. - Corrected the sound mixing to implement volume and squelch properly. - Implemented an extension to the existing frame format to allow high-speed Morse to pass through IRC within the flood limits imposed by IRC servers. 1.6.1 (28/10/2003): - The channel lock is now reset when the plugin is re-enabled. - Modified the Makefile to build CWirc on NetBSD. 1.6.0 (18/10/2003): - Added French Morse code in the automatic Morse decoder. - Added IRC channel locking and unlocking commands (/CWLOCK and /CWUNLOCK). - Reorganized the main panel so the presentation of the preset channels is more logical. 1.5.0 (15/10/2003): - Added 5 preset CW channels, instead of just one adjustment. - Added the X-Chat "xchat-plugin.h" include file in the CWirc distribution, so it's not necessary to download the entire X-Chat source tree if the file isn't provided by the distribution. - Modified the Makefile and #ifdef'ed bits of the source code to build CWirc for FreeBSD cleanly and without patch. 1.4.2 (02/10/2003): - Changed key_t types to int, removed Linux-only and Intel-only signals, added missing #include in plugin.c, changed #include to #include in io.c and modified the Makefile to facilitate the port of CWirc to FreeBSD. - Added a patch and instructions to build CWirc on FreeBSD. 1.4.1 (01/10/2003): - Corrected a minor bug in the morse frame validity testing. 1.4.0 (26/09/2003): - Added Russian and Japanese morse in the automatic CW decoder. - Corrected a bug in the decoder's buffer scrolling. - Made the front-end wait a bit before quitting on an error to allow the plugin portion to catch the error message. 1.3.1 (09/09/2003): - Made the QRM louder and corrected its implementation. - Corrected the QRM mixing. - Corrected a bug in the GUI where the callsign text entry would always be disabled at startup. - Made the squelch more sensitive 1.3.0 (06/09/2003): - Added adjustable QRM simulation. - Added signal strength and sporadic-E propagation simulation, based on the physical distance between operators, calculated from advertised grid square locations of the operators. - Extended the CW frame protocol to pass grid square locations. Added optional grid square location in the GUI. - Added optional grid square reporting in the CTCP CWIRC query. - Added a squelch in the main panel. - Corrected the sound mixing to match that of a real ham radio. Added soft incoming signal fadeout. - Moved the creation of outgoing CW frames back to cwframe.c where it belongs. - Many minor corrections. 1.2.3 (30/08/2003): - Improved the accuracy of the Morse decoder. 1.2.2 (28/08/2003): - Made the plugin answer channel-wide CTCP CWIRC queries. - CW frames sent as notices are now decoded and played. 1.2.1 (24/08/2003): - Reordered the functions in plugin.c to follow the order in the list of prototypes. - Made the decoder line frame stick to the decoder line. - Improved the sound quality when mixing several CW sound sources. - Simplified the S-meter and morse key icon drawing routines, and modified the CW beep generator, to be more CPU-friendly on slower machines. - Fixed the dependency against X-Chat in the debian binary package. - Added "CWirc" button in the userlist buttons. 1.2.0 (16/08/2003): - Added the ability to play morse code as sounder clicks. - Regular morse beeps are now smoother. - Changed the "FINE" setting into "RX pitch", and added "TX pitch" and "Volume" controls in the main panel. - Made the mouse keying zone show either a straight key or an iambic key according to the keying mode it is emulating. - Added a received morse speed indicator in the automatic decoder line. - Slightly corrected the automatic keyer WPM timing. - Made the automatic decoder more resilient to temporary variations of the received morse speed. 1.1.0 (09/08/2003): - Extended the frame format to include an explicit callsign. - Added optional custom CTCP query, to report the CWirc version, user's callsign and current CW channel. - Added a page in the GUI to change the callsign and control whether it's sent in the morse frames or not, and control how CTCP queries are replied to. - Reviewed all the strcpy() and strncpy() calls in the code to make sure they can't overflow. - The semaphore ID and shared memory ID are now random, so two instances of CWirc running on the same box don't conflict. 1.0.1 (07/08/2003): - Made the main GUI window tabbed. - Made various parts of the GUI go gray when they become irrelevant, such as the iambic keyer settings when the key is set to "straight". 1.0.0 (06/08/2003): - Split CWirc into a X-Chat plugin stub and a executable front-end called by the plugin. - Replaced the X11 user interface with a full-featured GTK+ gui. - Added automatic configuration file creation and saving. - Made the receive buffering adjustable. - Made opening the sound device non-blocking. - Added uninstall target in the Makefile. - Fixed many small bugs. 0.9.2 (01/08/2003): - Corrected the automatic morse decoder and extended it to include prosigns. - Added a schematic to build a CW oscillator driven by the serial port, and a schematic to connect a morse key to a serial port. 0.9.1 (28/07/2003): - Fixed an incorrect Linux real-time clock include file that broke the build in RedHat 9 - Modified the process termination code to be more graceful - The I/O process now makes sure the external sounder is de-activated before stopping - Brought the memory usage under control 0.9.0 (27/07/2003): - Added support for morse output on an external sounder connected to a serial port. - Rationalized the format of the configuration file. - Corrected the Makefile to avoid error messages on non-Debian boxes. - Redone all the documentation 0.8.2 (23/07/2003): - Added a rule to create a Debian binary package 0.8.1 (19/07/2003): - Added an explanation of iambic timings. - Corrected the man page. 0.8.0 (15/07/2003): - Made the morse frame format more compact, so CWirc wastes less of the IRC server's bandwidth, and the user can key faster without being throttled or kicked for flooding. The new format isn't compatible with previous formats, and the maximum cw channel goes from 9999 to 3999 as a result. - Made the plugin less verbose when sending or receiving morse. - Changed the maximum WPM to 60. - Bias the received morse sound pitch according to the entire nick of the sender, not just the first letter, so "joe" and "jane" don't sound the same. - Corrected 2 sound init error messages. 0.7.0 (13/07/2003): - Modified the sound I/O module to output sound at 44.1KHz, stereo, 16 bits in order to use larger sound fragments to avoid problems with some sound devices, and modified the code sections dependent on timing accordingly. - Removed the audio chopping problems. - Improved the automatic morse decoder. - Modified the Makefile to dump a help message by default inviting users to set the paths to the X-Chat plugin include file and base installation directory. 0.6.0 (11/07/2003): - Added an automatic morse decoder in the form of a scrolling line of decoded morse characters at the bottom of the control panel - Added explicit font names in the X user interface module. - Corrected minor bugs. 0.5.1 (11/07/2003): - Added support for sending morse frames through DCC CHAT. 0.5.0 (09/07/2003): - Modularized and cleaned up the source code - Added a fake S-meter - Made CWirc ignore morse frames received on channels other than the channel currently in focus - Better error reporting 0.4.2 (08/07/2003): - Made CWirc decode morse frames sent as private messages. 0.4.1 (07/07/2003): - Added a 1 second delay before starting to emit morse code received from IRC, so our buffer doesn't underrun as easily when the IRC connection lags. 0.4.0 (06/07/2003): - Added the possibility of keying morse in straight or iambic mode using the mouse buttons, by clicking in special zones on the control panel. Clicking in these zones also serve to change the keying mode for the serial morse key. - CWirc can now be used without a real key, using only the mouse as input device. 0.3.0 (05/07/2003): - Turned the I/O and user interface threads into old-fashioned processes with IPC communication because X-Chat isn't thread-safe. - Made the morse frame format more compact so the IRC server is less likely to detect flooding and kick the IRC client. - Added filters to hide sent or received raw morse frames. - Added a title for the control panel. - Made closing the control panel disable the plugin. - Changed the "/CWENABLE" command into "/CW". 0.2.1 (04/07/2003): - Removed bugs in the resource cleanup code when the plugin is disabled or uninstalled that caused it and X-Chat to segfault. 0.2.0 (03/07/2003): - Recoded the entire program into an X-Chat plugin instead of a (bad) standalone IRC client. It works just like before, but allows the user to use all the features of X-Chat at the same time. It also features a simple graphical panel that is functionally the same as the old command line. - Corrected and simplified the iambic implementation - Added a man page 0.1.0 (01/07/2003): - Added support for iambic keyers, in mode A or B. 0.0.2 (20/06/2003): - Corrected cwirc to use different serial ports and alternate configuration files 0.0.1 (18/06/2003): - First release cwirc-2.0.0.orig/Makefile0000644000175000017500000002161110433704747013521 0ustar pg4ipg4i##### PLEASE SET THE FOLLOWING VARIABLES FIRST ################################ # - Set TARGET_OS to LINUX, FREEBSD or NETBSD. # # - PLUGIN_INSTALL_DIRECTORY is where the CWirc plugin stub (cwirc.so) is # installed. It should be the X-Chat plugins directory, so the CWirc # plugin is loaded automatically when X-Chat starts. # # - FRONTEND_INSTALL_DIRECTORY is where the CWirc frontend executable is # installed. It should be a bin directory in the PATH, so the plugin # portion can execute it. # # - CWIRC_EXTENSIONS_DIRECTORY is where CWirc will look for extension programs. # # - Define any additional linker flags your system might need in EXTRA_LDFLAGS # (for example, "-lossaudio" with NetBSD 1.6.1) ################################################################################ #TARGET_OS= #PLUGIN_INSTALL_DIRECTORY= #FRONTEND_INSTALL_DIRECTORY= #CWIRC_EXTENSIONS_DIRECTORY= #EXTRA_LDFLAGS= # Use these with Debian GNU/Linux for example #TARGET_OS=LINUX #PLUGIN_INSTALL_DIRECTORY=/usr/lib/xchat/plugins #FRONTEND_INSTALL_DIRECTORY=/usr/bin #CWIRC_EXTENSIONS_DIRECTORY=/usr/lib/cwirc/extensions #EXTRA_LDFLAGS= # Use these with FreeBSD 5.1 for example #TARGET_OS=FREEBSD #PLUGIN_INSTALL_DIRECTORY=/usr/X11R6/lib/xchat/plugins #FRONTEND_INSTALL_DIRECTORY=/usr/X11R6/bin #CWIRC_EXTENSIONS_DIRECTORY=/usr/X11R6/lib/cwirc/extensions #EXTRA_LDFLAGS= # Use these with NetBSD 1.6.1 for example #TARGET_OS=NETBSD #PLUGIN_INSTALL_DIRECTORY=/usr/pkg/lib/xchat/plugins #FRONTEND_INSTALL_DIRECTORY=/usr/pkg/bin #CWIRC_EXTENSIONS_DIRECTORY=/usr/pkg/lib/cwirc/extensions #EXTRA_LDFLAGS=-lossaudio ################################################################################ VERSION=2.0.0 PLUGIN=cwirc.so FRONTEND=cwirc_frontend RM=/bin/rm CP=/bin/cp MKDIR=/bin/mkdir TAR=tar PWD=pwd CC=gcc STRIP=strip XCHAT_PLUGIN_INCLUDE_PATH=xchat XCHAT_INC=-I$(XCHAT_PLUGIN_INCLUDE_PATH) CFLAGS=-Wall -Wstrict-prototypes -O2 -D$(TARGET_OS) GTK_CFLAGS=`pkg-config --cflags gtk+-2.0` LDFLAGS=-lm ${EXTRA_LDFLAGS} GTK_LDFLAGS=`pkg-config --libs gtk+-2.0` all: missing_settings \ $(PLUGIN) \ $(FRONTEND) install: missing_settings \ $(PLUGIN) \ $(FRONTEND) $(MKDIR) -p $(PLUGIN_INSTALL_DIRECTORY) $(MKDIR) -p $(CWIRC_EXTENSIONS_DIRECTORY) $(CP) $(PLUGIN) $(PLUGIN_INSTALL_DIRECTORY) $(MKDIR) -p $(FRONTEND_INSTALL_DIRECTORY) $(CP) $(FRONTEND) $(FRONTEND_INSTALL_DIRECTORY) uninstall: missing_settings $(RM) -f $(PLUGIN_INSTALL_DIRECTORY)/$(PLUGIN) $(RM) -f $(FRONTEND_INSTALL_DIRECTORY)/$(FRONTEND) PLUGIN_OBJS= plugin.shared.o \ ipc.shared.o \ grid.shared.o \ propagation.shared.o \ cwframe.shared.o FRONTEND_OBJS= frontend.o \ io.o \ gui.o \ ipc.o \ keyer.o \ grid.o \ propagation.o \ cwsound.o \ cwdecoder.o \ cwframe.o \ rcfile.o \ extension.o $(PLUGIN): $(PLUGIN_OBJS) $(CC) -shared $(LDFLAGS) -o $@ $(PLUGIN_OBJS) $(STRIP) $@ $(FRONTEND): $(FRONTEND_OBJS) $(CC) $(LDFLAGS) $(GTK_LDFLAGS) -o $@ $(FRONTEND_OBJS) $(STRIP) $@ plugin.shared.o: plugin.c \ $(XCHAT_PLUGIN_INCLUDE_PATH)/xchat-plugin.h \ types.h \ common.h \ cwirc.h \ cwframe.h \ ipc.h $(CC) $(CFLAGS) $(XCHAT_INC) -fPIC -c -o $@ plugin.c frontend.o: frontend.c \ types.h \ cwirc.h \ common.h \ rcfile.h \ io.h \ gui.h \ extension.h \ ipc.h $(CC) $(CFLAGS) $(XCHAT_INC) -c -o $@ frontend.c io.o: io.c \ types.h \ io.h \ cwirc.h \ keyer.h \ cwsound.h \ cwdecoder.h \ propagation.h \ extension.h \ ipc.h $(CC) $(CFLAGS) -c -o $@ io.c gui.o: gui.c \ types.h \ gui.h \ common.h \ cwirc.h \ rcfile.h \ grid.h \ io.h \ cwdecoder.h \ extension.h \ keyer.h \ ipc.h \ smeter.xpm \ sidetone.xpm \ straightkey.xpm \ iambickey.xpm $(CC) $(CFLAGS) $(GTK_CFLAGS) -c -o $@ gui.c keyer.o: keyer.c \ types.h \ keyer.h $(CC) $(CFLAGS) -c -o $@ keyer.c grid.o: grid.c \ grid.h $(CC) $(CFLAGS) -c -o $@ grid.c grid.shared.o: grid.c \ grid.h $(CC) $(CFLAGS) -fPIC -c -o $@ grid.c propagation.o: propagation.c \ propagation.h $(CC) $(CFLAGS) -c -o $@ propagation.c propagation.shared.o: propagation.c \ propagation.h $(CC) $(CFLAGS) -fPIC -c -o $@ propagation.c cwsound.o: cwsound.c \ types.h \ cwsound.h \ sounder_down.h \ sounder_up.h $(CC) $(CFLAGS) -c -o $@ cwsound.c cwframe.o: cwframe.c \ types.h \ cwframe.h \ cwirc.h \ grid.h \ propagation.h \ io.h \ ipc.h $(CC) $(CFLAGS) -c -o $@ cwframe.c cwframe.shared.o: cwframe.c \ types.h \ cwframe.h \ cwirc.h \ grid.h \ propagation.h \ io.h \ ipc.h $(CC) $(CFLAGS) -fPIC -c -o $@ cwframe.c cwdecoder.o: cwdecoder.c \ types.h \ cwdecoder.h \ morsecodes.h \ cwirc.h $(CC) $(CFLAGS) -c -o $@ cwdecoder.c ipc.o: ipc.c \ ipc.h $(CC) $(CFLAGS) -c -o $@ ipc.c ipc.shared.o: ipc.c \ ipc.h $(CC) $(CFLAGS) -fPIC -c -o $@ ipc.c rcfile.o: rcfile.c \ types.h \ rcfile.h \ cwirc.h \ grid.h \ io.h \ cwdecoder.h $(CC) $(CFLAGS) -c -o $@ rcfile.c extension.o: extension.c \ types.h \ cwirc.h \ extension.h \ ipc.h \ common.h $(CC) $(CFLAGS) -c -o $@ extension.c sounder_down.h: sounder_down.wav \ mksndinclude ./mksndinclude sounder_down > $@ < sounder_down.wav sounder_up.h: sounder_up.wav \ mksndinclude ./mksndinclude sounder_up > $@ < sounder_up.wav mksndinclude: mksndinclude.c \ types.h $(CC) $(CFLAGS) -o $@ mksndinclude.c common.h: echo "#define FRONTEND \"$(FRONTEND)\"" > $@ echo "#define VERSION \"$(VERSION)\"" >> $@ echo "#define EXTENSIONS_DIR \ \"$(CWIRC_EXTENSIONS_DIRECTORY)\"" >> $@ clean: $(RM) -f $(FRONTEND) $(RM) -f *.so $(RM) -f *.o $(RM) -f common.h $(RM) -f sounder_down.h $(RM) -f sounder_up.h $(RM) -f mksndinclude $(RM) -rf release missing_settings: @(if [ ! "$(TARGET_OS)" ] || \ [ ! "$(PLUGIN_INSTALL_DIRECTORY)" ] || \ [ ! "$(FRONTEND_INSTALL_DIRECTORY)" ] || \ [ ! "$(CWIRC_EXTENSIONS_DIRECTORY)" ];then \ echo; \ echo "*** Please edit the Makefile to ***"; \ echo "**** set the target OS and the ****"; \ echo "**** CWirc installation paths. ****"; \ echo; \ exit 1; \ fi) ########## RELEASE ONLY SECTION ################################################ SRCFILES= COPYING Changelog Makefile README LISEZMOI RELEASE_NOTES\ schematics/rs232_key_connection.jpg \ schematics/cw_oscillator.jpg cwdecoder.c cwframe.c \ cwsound.c frontend.c extension.c grid.c gui.c keyer.c \ io.c ipc.c mksndinclude.c plugin.c propagation.c \ rcfile.c \ cwdecoder.h cwframe.h cwirc.h cwsound.h extension.h \ grid.h gui.h keyer.h io.h ipc.h morsecodes.h \ propagation.h rcfile.h types.h xchat/xchat-plugin.h \ xchat/README.xchat_include_file \ straightkey.xpm iambickey.xpm smeter.xpm sidetone.xpm \ sounder_down.wav sounder_up.wav \ debian/changelog debian/compat debian/control \ debian/copyright debian/rules debian/watch \ rpm/cwirc.spec rpm/rpmmacros release: source_release debian_release rpm_release source_release: release/cwirc-$(VERSION).tar.gz release/cwirc-$(VERSION).tar.gz: $(MKDIR) -p release/cwirc-$(VERSION) $(CP) --parents -a $(SRCFILES) release/cwirc-$(VERSION) $(TAR) -C release -cvzf $@ cwirc-$(VERSION) $(RM) -r release/cwirc-$(VERSION) debian_release: release/cwirc-$(VERSION).tar.gz $(MKDIR) -p release/debian $(TAR) -C release/debian -zxf $< (cd release/debian/cwirc-$(VERSION) && \ dpkg-buildpackage -rfakeroot) $(RM) -rf release/debian/cwirc-$(VERSION) rpm_release: release/cwirc-$(VERSION).tar.gz $(MKDIR) -p release/rpm/RPM/BUILD $(MKDIR) -p release/rpm/RPM/RPMS $(MKDIR) -p release/rpm/RPM/SOURCES $(MKDIR) -p release/rpm/RPM/SPECS $(MKDIR) -p release/rpm/RPM/SRPMS (if [ -f ~/.rpmmacros ];then \ $(CP) -a ~/.rpmmacros release/rpm/RPM; \ fi) $(CP) rpm/rpmmacros ~/.rpmmacros (RPMTOPDIR=`cd release/rpm/RPM && $(PWD)`; \ echo "%_topdir $$RPMTOPDIR" >> ~/.rpmmacros) $(CP) release/cwirc-$(VERSION).tar.gz release/rpm/RPM/SOURCES $(CP) rpm/cwirc.spec release/rpm/RPM/SPECS rpm -ba release/rpm/RPM/SPECS/cwirc.spec $(CP) release/rpm/RPM/RPMS/*/*.rpm release/rpm $(CP) release/rpm/RPM/SRPMS/*.src.rpm release/rpm $(RM) ~/.rpmmacros (if [ -f release/rpm/RPM/.rpmmacros ];then \ $(CP) -a release/rpm/RPM/.rpmmacros ~; \ fi) $(RM) -rf release/rpm/RPM ################################################################################ cwirc-2.0.0.orig/README0000644000175000017500000012705110433706416012741 0ustar pg4ipg4i CWirc X-Chat morse plugin ------------------------- 2.0.0 ----- F8EJF Pierre-Philippe Coupard 20/05/2006 CWirc is a plugin for the X-Chat IRC client to transmit raw morse code over the internet using IRC servers as reflectors. The transmitted morse code can be received in near real-time by other X-Chat clients with the CWirc plugin. CWirc tries to emulate a standard amateur radio rig : it sends and receives morse over virtual channels, and it can listen to multiple senders transmitting on the same channel. Morse code is keyed locally using a straight or iambic key connected to a serial port, or using the mouse buttons, and the sound is played through the soundcard, or through an external sounder. Note that CWirc doesn't do any morse decoding : it simply transmits and receives morse code timing events. A standard IRC user on the same IRC channel you're transmitting morse on will only see coded lines when morse code is transmitted. Only other CWirc users can receive what you send. 1 - Installing CWirc - Edit the Makefile to set the target OS (LINUX, FREEBSD or NETBSD) and the installation paths for the CWirc binaries. - Build the program by typing "make" - Install the plugin and its frontend program by typing "make install" as root 2 - Using CWirc CWirc is composed of two parts : a X-Chat plugin stub that intercept and sends morse frames as IRC text, and a frontend application that interacts with the user through a graphical interface. The frontend application is meant to be loaded by the plugin only, and cannot be used as a standalone program. To use CWirc, it is necessary that X-Chat loads the plugin part first. Normally, the CWirc plugin is installed in the X-Chat plugins directory as "cwirc.so" and is automatically loaded by X-Chat at startup. You can verify it's loaded properly by going in the "Windows" --> "Plugins and Scripts" menu in X-Chat and checking that CWirc appears in the list. When the "cwirc.so" file is loaded, it adds a new command to X-Chat, called "/CW" (you can do "/HELP CW" to verify this), and it also adds a "CWirc" button in the userlist buttons (if you don't see it, try enabling "Userlist button enabled" in the "Preferences -> User list" menu. The "/CW" command or the "CWirc" button enable and disable the plugin. Note that CWirc should have no incidence whatsoever on your normal IRC chatting on any channel, but it will always silently filter out incoming morse frames, whether it is enabled or not, so you can chat normally on a morse-dedicated IRC channel even with the plugin disabled. When enabling the plugin, the frontend application is called and the CWirc control panel appears outside of X-Chat. In the control panel, there are six tabs: the main tab for regular use, as well as the keyer settings, simulation, personal information, I/O configuration and "about" tabs. 2.1 - The main tab 2.1.1 - The S-meter / sidetone mode toggle This is an emulated classic needle signal meter. When signal strength simulation (see below) is used, it shows the strength of the incoming signal. When no simulation is used, it is simply decorative and move from S0 to S9+30 no matter what signal is sent or received. When the S-meter is clicked, CWirc switches to sidetone mode. When it's clicked again, CWirc goes back to normal mode. In sidetone mode, you can key without actually sending anything. This is useful when adjusting a key, or to train keying morse code, without bothering anybody on the channel. 2.1.2 - The Channel setting CWirc has a concept of "CW channel", as opposed to IRC channel. They are not the same. Think of it as the frequency you'd dial on your radio rig. You can only send or receive morse on one CW channel. CWirc ignores morse sent to other CW channels. There are 4000 CW channels available (0->3999), therefore on any given IRC channel, there can be up to 4000 distinct QSOs going on. The top "PR x" selector selects one of 5 preset channels. The bottom channel setting sets the CW channel for that preset channel. You can therefore program up to 5 favorite CW channels : for example, you could set channel 1 at 1000 for the CQ channel, channel 2 at 1100 for the channel you usually QSY to, channel 3 at 912 to listen to the news channel ... 2.1.3 - The RX pitch setting This setting changes the sound pitch of received morse beeps, allowing you to play your correspondant's signal at a frequency you're confortable with, or helping you discriminate between different operators transmitting on the same channel, if you "have an ear" for a particular audio frequency. NOTE: this setting does nothing if CWirc plays sounder clicks instead of beeps, or if the CW output is an external sounder only (see below). 2.1.4 - The TX pitch setting This setting changes the sound pitch of your own signal played back to you locally. You can adjust it in sidetone mode (see above) to avoid sending garbage on the channel. NOTE: this setting does nothing if CWirc plays sounder clicks instead of beeps, or if the CW output is an external sounder only (see below). 2.1.5 - The Squelch setting If you use QRN simulation (see below), fake radio static is played continuously and it quickly gets very tiring. Like on a real radio, to cut off the background noise when it's not useful (when you're not actually transmitting or receiving anything), set the squelch high enough to stop the background noise, and low enough to re-enable the sound when a signal comes. Note that if you use signal strength and/or sporadic-E simulation (see below), using the squelch can make you miss weak signals. 2.1.6 - The AF gain setting This changes the volume of beeps or sounder clicks played throught the sound card. Note that your computer's actual mixer device isn't used to set the volume : CWirc simply generates lower amplitude sound signals internally. 2.1.7 - The Key setting This setting tells CWirc to read mouse clicks on the mouse keying zone, or a real morse key connected to a serial port (see below), as a straight key, or as paddles using the internal automatic keyer. The icon displayed in the mouse keying zone changes to a straight key or an iambic key accordingly. 2.1.8 - The Iambic keyer speed setting If you set "Key" to "iambic", you can set the automatic keyer's speed in words per minutes. The keyer will function in that speed according to the settings in the "Keyer settings" tab (see below). 2.1.9 - The mouse keying zone If you enabled the mouse as CW input (see below), you can key morse code with the mouse by leaving the pointer in the morse key icon and using the buttons as key or paddles. If you set "Key" to "iambic", the left and right mouse buttons act as paddles. If you set "Key" to "straight", either mouse button emulates the key. 2.1.10 - The automatic morse decoder At the bottom of the control panel, there is a line with morse characters decoded from the morse signal currently received. The morse decoder that generates those characters simulates a real automatic decoder connected to the audio output of a real radio rig. Therefore, it will work only if only one person is transmitting at a time. If several people send morse together on the same CW channel, like in a pile-up, or if you transmit over someone else's signal, the decoder will get confused and generate garbage. If you really need to decode a particular sender in a pile-up with the decoder, you could use the IRC command "/IGNORE" to silence all the other senders. If you use signal strength and/or sporadic-E simulation, the decoder will not work if the incoming signal is too weak or fluctuating, or will not decode properly. Similarly, if a strong signal and a weak signal are received at the same time, only the strong signal will be decoded. If more than one strong signal arrive at the same time, the decoder will get confused. Also, the decoder needs to "hear" a little signal before synchronizing correctly with a sender, or with you. Therefore, the first character(s) will be garbled as the decoder guesses the timing of the morse code. It will resync similarly if the sender suddenly changes his/her keying speed dramatically, or if you yourself don't send at a speed close to that of your correspondant. Finally, although the decoder makes allowances for slightly incorrect morse timings and drifting keying speed, it still needs to receive somewhat clean morse code to work well. You're better off using your ears to copy a bad sender, or a sender using a very atypical dit weighing. The decoder is also useful in sidetone mode (see above) to train keying clean morse with proper timing. NOTE: If you conduct a QSO in a code that's not modern morse code or DOT code, like in genuine American morse code, the decoder will produce garbage. 2.1.11 - The automatic morse decoder's speed indicator / reset button The received morse speed indicator at the right of the decoded text, in words per minute, is an measure of your correspondant's keying speed. It is measured from the raw received or sent signal, therefore it can be quite approximative. If the decoder gets confused with two superimposed signals, or a signal with fluctuating strength, the speed indicator becomes wild and means nothing. If the morse code doesn't use a dit weighing of 50%, the speed indicator will also be skewed. This indicator also doubles as a morse decoder reset button. Pressing it will erase the current decoded characters buffer and will reset the automatic decoder. 2.1.12 - The automatic morse decoder's language selector At the right of the morse decoder speed indicator, you can select which language or code set you would like the decoder to use to decode incoming signals. At the moment, English (international), French, Russian, Japanese (katakana) morse code, and historic DOT code (which isn't morse) are supported. In order to view decoded characters in a language other than English, (english morse or DOT) you need to have a real Unicode/ISO-10646 font set installed on your system. If you are interested in using a non-English morse code set, chances are your machine is already setup correctly. Otherwise, a good start if you want to configure your fonts correctly under X is to read the "XFree86 Font De-uglification HOWTO" document available at : http://www.tldp.org/HOWTO/FDU/index.html If you find the decoder distracting, or if you can't resist looking at it when training to copy, simply select "No decoder" to disable it entirely. 2.2 - The Keyer settings tab This tab lets you adjust the iambic keyer to your liking. Keyer features and settings are a very personal issue : iambic keyers from different manufacturers (or home-made keyers), and sometimes different models from the same manufacturer, have slightly different responses to an operator's input, and most people tend to prefer the features displayed by whichever keyer they first learned iambic keying with. The CWirc keyer can be adjusted to match almost any existing iambic keyer. 2.2.1 - The iambic mode selector Set the iambic mode you would like the CWirc keyer to use. The iambic mode (A or B) only changes the behaviour of the keyer when both paddles are released after having been squeezed together (i.e. iambic keying) : in mode-A, when both paddles are released in the middle of an element being sent (dit or dah), the element is completed, then the keyer stops. In mode-B, the element is completed, then the keyer automatically sends an extra opposing element, then stops. If your Cs consistently come out as Ks, you're probably using mode-A when you really want mode-B. Conversely, if your Ks consistently come out as Cs, you probably want to use mode-A. 2.2.2 - The dit memory and dah memory If you enable the dit memory, when the keyer sees the dit paddle being hit, however briefly, during the sending of a dah, it "remembers" it and sends the dit at the next possible occasion. Similarly, the dah memory enables the automatic insertion of a dah by touching the dah paddle while a dit is being sent out. Typically, dit/dah memory is used to make Ns and As by tapping the two paddles quickly one after the other (but not squeezing, that would make the keyer go into iambic mode). It's also very useful to make letters such as Y, Q, L or F by sending a stream of dahs or dits, and inserting a dit or a dah by tapping the opposing paddle at the right moment. 2.2.3 - The mid-element mode-B mode Most mode-B keyers automatically insert an opposing element when releasing both paddles anytime during the element currently being sent, in iambic mode. Some mode-B keyers however seem to make a distinction between the case where both paddles are released before the middle of the element currently being sent, and the case where they're released after. In the former case, those keyers don't send an opposing element, while they do in the latter. Those keyers seem to be a minority though. If your As consistently come out as Rs and your Us as Fs, but your keying is otherwise fine in mode-B, you might want to try this option. 2.2.4 - The auto character spacing When this option is enabled, the keyer forces you to wait the correct time between letters. Try using this if you consistently run letters together. 2.2.5 - The auto word spacing In addition to the auto character spacing, you can use this option to force the keyer to make you wait the correct time between words and help you format your transmission perfectly. Try using this if you consistently fail to leave enough time between words. Be aware however that this option requires an otherwise good keying to be used efficiently, as it will force you to wait a full inter-word pause each time you hesistate on a letter. 2.2.6 - The "invert paddles" option If you're left handed, or if you're used to key using the left paddle as dah paddle and the right paddle as dit paddle, enable this option. 2.2.7 - The dit weight setting Back when radios often showed a certain lag between the moment a key was depressed and the moment it would start transmitting, it was often useful to artificially increase the length of the elements sent by the keyer, so that they would end up being sent on the air with the proper timing by the radio. Today, most transceivers don't need this trick to send properly formatted CW, but some operators have kept their non-standard dit weight because it sounds better, or to "personalize" their signal. The CWirc keyer allows you to change the dit weight as well, although it's completely useless to do CW over the net. The value corresponding to the standard morse code timing is 50%. NOTE: don't overdo it : if you set the dit weight too far off 50%, most people won't be comfortable copying you, and some might even not copy you at all. 2.3 - The Simulation tab This tab lets you set CWirc to experience an approximation of what a real radio sounds like, to train copying signals that are less than perfect and a little less "artificial" and computer-generated than with the basic settings. 2.3.1 - the QRN simulation box Check "simulate QRN" to add noise and static to incoming signals. Use the "QRN level" slider to set the level of noise you want. The level of QRN you've chosen registers on the S-meter in the main tab. 2.3.2 - The Propagation simulation box Check "simulate signal strength for signals with grid squares" to make CWirc generate a fake signal strength for incoming signals that have been sent with a grid square location as part of the signal. For this to work, you have to have your own grid square set in the Personal info tab (see below) : the way CWirc knows what signal strength to give to an incoming signal is by calculating the distance between you and the person who emits the signal, hence it must know your location as well as the sender's. It's up to the sender to disclose his/her own grid square : if he/she doesn't want to disclose it, his/her signal will be given a default signal strength that you can set with the bottom slider marked "default signal strength for signals without grid squares". In addition to the basic signal strength simulation, you can add sporadic-E simulation by checking "simulate sporadic-E for weak signals". Real sporadic-E is a type of ionospheric E-layer reflection caused by small patches of unusually dense ionization in the atmosphere that makes many long distance contacts possible on VHF. Such reflected signals tends to come and go quickly as the patches of ionization move up in the atmosphere, making those long contacts challenging to establish and maintain. With sporadic-E simulation enabled, CWirc makes the strength of all weak signals it receives (approximately under S3) fluctuate as if they came from a sporadic-E reflection. 2.4 - The Personal info tab 2.4.1 - The Callsign setting If you are a ham, you can set your callsign for other users to see in your morse messages, or when they query your information with the /CTCP CWIRC command (see below). 2.4.2 - The Grid square setting Set the grid square corresponding to your present physical location here if you want to be able to use signal strength and sporadic-E simulation. If you don't know your grid square location, you can find it on the following webpage, with the grid map, or if you know your latitude and longitude : http://www4.plala.or.jp/nomrax/GL/index.html CWirc accepts grid squares in the basic 4-character format ("AB12"), or the more accurate 6-character ("AB12CD") format. 2.4.3 - The "send callsign with CW" button If you select this, CWirc will send your callsign along with your CW signal, and other CWirc users will be able to see it when they receive your signal. If you choose to broadcast your callsign, it will be sent in scrambled form in the IRC message, so only other CWirc users will be able to see it. This is useful if you want to keep your normal anonymous IRC nick for casual IRC chatting, but you want to go by your ham callsign with other CWirc users at the same time. 2.4.4 - The "send grid square with CW" button If you select this, your grid square location will be sent along with your CW signal, allowing remote CWirc users to use signal strength simulation options with your signal. If you choose to broadcast your grid square, it will be sent in scrambled form in the IRC message. If you you want to stay vague about where you are, enter your grid square in 4-character format (they define an area that measures approximately 70 miles x 100 miles in the continental US). 2.4.5 - The CTCP settings CWirc can reply to a custom CTCP query (CTCP CWIRC) to report what version you are using, what channel you are currently on, what your callsign is or what your grid square location is. If you don't want to disclose any of these details, un-check the "reply to CTCP CWIRC queries" setting. If you check it, it'll give anybody who types "/CTCP CWIRC" the version of your CWirc client. Additionally, you can also check "send callsign in CTCP reply", "send grid square in CTCP reply, or "send current channel in CTCP reply" to give those details along with the CWirc version. 2.5 - The I/O configuration tab This tab allows you to set the parameters for the CW input and output devices, and the buffering policy. The settings in the I/O configuration tab are only effective after your click on the "Change/Save" button. If a parameter is erroneous, an error popup window will inform you of the reason. 2.5.1 - The CW input setting To key morse code, you can use the mouse by clicking on the mouse keying zone (see above), a real morse key connected to a serial port (see below) or both. If you choose "real key" or "both", the "Serial device" setting needs to be set. 2.5.2 - The CW output setting To play morse code, CWirc can use a soundcard, an external sounder or CW oscillator connected to a serial port (see below), or both. If you choose "soundcard" or "both", the "Sound device" setting needs to be set. If you choose "sounder", the "Serial device" setting needs to be set. NOTE: if you use both a real morse key and a sounder, they will share the same serial port. NOTE: if you use a sounder, you shouldn't use signal strength simulation as well. The reason is that weak signals, below a certain threshold, will simply not be played on the sounder. NOTE: the "sounder" option (external sounder as sole CW output) isn't available under FreeBSD or NetBSD, as these OSes don't provide a proper /dev/rtc implementation, therefore CWirc always needs the soundcard to pace itself. 2.5.3 - The CW sound setting If "CW output" is set to "soundcard" or "both", you can choose to play incoming and outgoing morse code as regular beeps, or as sounder clicks. Most "modern" hams should choose beeps here. Sounder clicks are really a feature for those who are interested in historical landline telegraphy, who want to experience the sound of yesteryear's telegraphy as heard in railway telegraph stations, or want to try out the original American morse code (which is different from the international morse code everybody knows today). Note that the sounder clicks played by CWirc come from an actual Vail sounder, and the timings of the sounder's arm going up and down are accurately reproduced. 2.5.4 - The Key debounce setting When using a real morse key connected to a serial port, its contact(s) will read at regular interval to determine its/their states. If you get spurrious dits or dahs while keying, it's possible that your key contact(s) "bounce" when they make or break the electrical contact. Contact "bouncing" is a common electrical phenomenon that occurs with nearly all electrical switches. To alleviate the problem, increase the value of "Key debounce" until the problem disappears. NOTE: the lower the "Key debounce" value, the better, especially if you're a fast keyer. If you feel your key is sluggish and/or misses elements when you key fast, try lowering the value. 2.5.5 - The Recv buffering setting This tells CWirc how long (in milliseconds) it should pre-buffer incoming morse from the IRC server. On IRC servers that are reasonably responsive, 1000 ms (1 s) is usually enough. If you're connected to an IRC server with a lot of lag, try increasing the buffering value. If you're connected to a local IRC server, of if you receive morse from an operator in a DCC CHAT connection (see below), you can lower the value. The more you increase the buffering value, the less your CWirc client will be subject to buffer underruns, but the more the receive latency will increase. 2.5.6 - Sound device If "CW output" is set to "soundcard" or "both", this tells CWirc which sound device to use to access the soundcard. Usually it's "/dev/dsp" under Linux, "/dev/dsp0.0" under FreeBSD, or "/dev/audio0" under NetBSD, if you only have one soundcard. NOTE: if you want to use the aRts daemon with CWirc, you can with the artsdsp wrapper and some tinkering, at the expense of sound latency: - In the KDE sound system preferences, enable the sound system if not already enabled of course, enable "Run with the highest possible priority (realtime priority)" and set the sound buffer slider to the lowest possible level. - As root, rename the "cwirc_frontend" binary (usually installed in /usr/bin or /usr/local/bin) to "cwirc_frontend.REAL" - As root, edit a new shell script called "cwirc_frontend" where the real frontend binary was, with the following lines in it: #!/bin/sh artsdsp cwirc_frontend.REAL $* and make it executable by invoking chmod +x cwirc_frontend - Restart CWirc and ensure the sound device is set to "/dev/dsp". The sound should then be redirected to the aRts sound daemon. 2.5.7 - Serial device If "CW input" is set to "real key" or "both", or "CW output" is set to "sounder" or "both", this tells CWirc which serial device the real morse key and/or the sounder are connected to. Use /dev/ttyS0 for COM1, /dev/ttyS1 for COM2 ... under Linux, or /dev/cuaa0 for COM1, /dev/cuaa1 for COM2 ... under FreeBSD, or /dev/tty00 for COM1, /dev/tty01 for COM2 ... under NetBSD. 2.6 - Conducting QSOs in an IRC channel When CWirc is configured to your liking, try connecting to an IRC server and joining a channel bearing morse traffic. Don't forget to set the channel to the same as used by other parties in the channel (typically 1000 is the general CQ channel). The morse you send will be emitted on the IRC channel as encoded lines every 2 seconds. Similarly, your CWirc client will receive incoming morse sent in encoded lines. Note that morse received on channels other than the one you are currently ignored will be silently ignored. IMPORTANT: CWirc uses a protocol that looks very much like high-speed garbage to non-CWirc users. Please be considerate and do NOT use CWirc on general IRC channels (i.e. not dedicated to morse traffic) unless you know the chatters and you ask them first. 2.7 - Conducting QSOs outside of the IRC channel It is possible that you want to discuss things outside of the IRC channel, so not everybody who happens to be tuned to your CW channel can hear what you say. It's possible to /QUERY the other person and send him/her morse in private, as you would to send normal IRC private messages. You still need to be on the same CW channel though. You can also DCC CHAT with the other party : in that case, the connection between the other party and you is direct, bypassing the IRC server, which has the big advantage of reducing the lag between the 2 CWirc clients, and ensuring you won't get kicked out of the IRC channel for flooding. 2.8 - IRC channel locking Normally, CWirc receives and sends morse from whatever channel you have currently in focus. If you just do morse, that's usually good enough. However, it's possible that you might want to send/receive morse to/from one IRC channel while doing something else in another. Typically, the situation is when you're sitting on a channel waiting for a CQ and you want to chat with friends on another IRC channel in the meantime. You can instruct CWirc to not follow the channel currently in focus. To that, put the IRC channel you want to use in morse in focus and issue the "/CWLOCK" command : CWirc then tells you that it's locked on that IRC channel. You're then free to do whatever you want on other channels and CWirc will stay on the channel you locked it on. If you want to lock CWirc onto another channel, simply put the new channel in focus and use the "/CWLOCK" command again. If you want to revert to the default mode of following the channel in focus, issue the "/CWUNLOCK" command. Note that you can lock and unlock CWirc on private chat and DCC CHAT windows as well. 2.9 - Notes on using simulation If you use signal strength simulation, and especially if you add sporadic-E simulation on top of it, it is entirely possible to not hear an incoming signal despite the fact that CWirc reports receiving it, if it is too weak (typically the remote sender is too far away physically) or if it is too attenuated by the sporadic-E simulation. Also, while it is possible, it's a bad idea to use signal strength or sporadic-E simulation with a sounder : if the signal is too weak, the sound of the sounder will simply be cut-off, because it's a device that is either on or off. Finally, while possible too, note that using sounder clicks with QRN, signal strength or sporadic-E simulation makes no sense : sounders were used for land-line telegraphy, and therefore never generated QRN or weak signal. 3 - Connecting a real morse key Keying morse with a mouse is okay when nothing else is available, but it's not ideal. If you have a real morse key, you can use it to key morse in CWirc by connecting it to your computer with a simple serial cable : 3.1 - Using a straight key Assuming your serial port uses a DB9 connector, the wiring is : DB9 pin number Key ===== 6 (DSR line) --------------------+-------------| 4 (DTR line) --------------------+-------------O Once the key is connected, configure CWirc by setting "CW input" to "real key" or "both" and "Key" to "straight". 3.2 - Using an iambic key Assuming your serial port uses a DB9 connector, the wiring is : DB9 pin number Key 8 (CTS line) --------------------+--------O--===== Right paddle 4 (DTR line) --------------------+--------| Common 6 (DSR line) --------------------+--------O--===== Left paddle Once the key is connected, configure CWirc by setting "CW input" to "real key" or "both" and "Key" to "iambic", then configure "Iambic keyer" to your liking. 4 - Connecting an external sounder A sounder, a CW oscillator, a lamp, or even the PTT of your radio rig can be controlled by CWirc through the RTS line on a serial port. That line can be made to change state following the received and sent morse code, in conjunction with, or in lieu of the soundcard. This is useful for various kinds of users : - People whose soundcard can't be opened by more than one process at a time, and who want to listen to something while doing CW at the same time - People who want to experience the original land telegraphy sound (i.e. the sounder), that wasn't beeps but clicking noises - Hams who want to retransmit an internet CW QSO on the air - Users with hearing problems who need a visual indication of dits and dahs Of course, ready-made devices that can be driven by a RS232 RTS line aren't usually available in retail stores, so you'll probably have to dust off your soldering iron. The easiest is probably to make a simple RTS-controlled relay box, with an optocoupler to protect your serial port, then use the relay to inject power in a commercially available training CW oscillator, a buzzer, a light bulb or a sounder coil. Assuming your serial port uses a DB9 connector, the wiring to connect your custom-made sounder (or whatever other device) is : DB9 pin number 7 (RTS line) --------------------+-------- Sounder output 5 (GND line) --------------------+-------- Sounder ground Once the key is connected, configure CWirc by setting "CW output" to "sounder" or "both". With a sounder device, if several operators send morse on the same CW channel, it's not possible to discriminate between them by the received tones, since the only information available with a single data line is the presence or absence of signal. NOTE: if you set "CW output" to "sounder" (available under Linux only), CWirc will not be able to use the soundcard to pace itself. As a result, it will try to use your computer's real-time clock instead, through the /dev/rtc interface. There are however several things you need to do to allow a user program like CWirc to use /dev/rtc : - Enable "Enhanced Real Time Clock Support" in the Linux kernel, either as a module or compiled in - Set permissions to open the /dev/rtc device file read-only as a normal user - Allow CWirc to ask /dev/rtc to generate 1024 interrupts per second by typing the following command in a console, as root : echo 1024 > /proc/sys/dev/rtc/max-user-freq (The easiest it to put that line in a bootup script, so it's always set up correctly each time you restart the machine.) If you use the soundcard output as well as the sounder, there is no need to do any of the above, as CWirc will automatically use the soundcard to synchronize itself whenever possible. 5 - CWirc extensions As of version 1.7.0, CWirc supports external extension programs. A simple interface allows a program specially designed or modified to work with CWirc to receive audio synchronously as you hear it, and key as you'd key. If you have extension programs installed, an extra tab will appear in CWirc so that you can start it. Note that only one extension can be running at any given time. 6 - Note on CWirc and CWCom interfacings The interfacing of external devices to a serial port used by CWirc is strictly identical to the one used by CWCom for Windows, by MRX Software (http://www.mrx.com.au/d_cwcom.htm). Consequently, if you already use CWCom in Windows with a key and/or a sounder connected to a serial port, you won't need to modify anything to your hardware setup to use CWirc in Unix. 7 - Solving the scratchy sound problem On some machines with low-end or integrated sound devices (typically SiS, i8x0 or VIA sound devices), CWirc may start to sound very nasty when the system gets loaded, even only a little. If you experience sound cuts and "scratchy" noises, try to set the CWirc frontend executable (usually /usr/bin/cwirc_frontend or /usr/local/bin/cwirc_frontend) suid root, by issuing the following commands as root: chown root /cwirc_frontend chmod u+s /cwirc_frontend then restarting CWirc. This should clear, or at least improve the bad sound problem. When CWirc is run suid root, it asks the system to give its I/O routine a better execution priority than most processes in the system, thereby reducing or suppressing sound buffer underruns that are the cause of "scratchy" noises. CWirc can only instruct the system to give it this better treatment if it has root permissions, hence the need to set the CWirc frontend executable file suid root. CWirc is normally installed as a regular, non-suid binary by default, because although the program drops its root privileges as soon as it has changed its own system priority, almost immediately at the beginning of the program, and therefore should be quite safe, suid programs are usually viewed as a security risk, and most users will be able to run CWirc fine without the better priority anyway. This is the reason why it is left to you to set the suid attribute on the CWirc frontend executable manually if you need it. If the problem seems to persist, you may want to check that CWirc effectively did manage to reprioritize its I/O routine with the root privilege. To do this, invoke: ps x | grep cwirc_frontend while CWirc is running, and check that one of the two "cwirc_frontend" processes has "<" marked next to it, meaning that it's a high-priority task. 8 - FAQ Q: When setting "CW output" to "sounder", when I try to enable the plugin, it says "Error : cannot open /dev/rtc." but I'm sure my kernel has real-time clock support, rtc support is setup properly and I have proper permissions to access /dev/rtc. A: Programs that use /dev/rtc, like VMware or mplayer, have exclusive control over the real-time clock and need to be stopped first before using CWirc. Try to do "lsof /dev/rtc" to check what process is currently using /dev/rtc. Q: When setting "CW output" to "sounder", when I try to enable the plugin, it says "cannot set /dev/rtc to generate 1024 interrupts per second." A: By default, the Linux kernel won't let non-root programs instruct the real-time clock to generate more than 64 interrupts per second. CWirc needs 1024, so it's necessary that you tell the kernel to lift that safety restriction. For details, see the section above on using a sounder. If you can't change the kernel setting, because you don't have root access to the box for example, you'll have to use the soundcard as well. Q: When I try to enable CWirc, X-Chat tells me "CWirc : error : cannot execute "cwirc_frontend" ". A: cwirc_frontend is the executable for the CWirc frontend. It needs to be in your search PATH for the plugin to be able to start it. Q: When I key, after a short while, the IRC server kicks me out A: A lot of data is transmitted to the IRC server as fast as possible when you key. Most IRC servers let you get away with one line sent every 2 seconds, but some servers may interpret that as flooding and kick you out. Also, if you're a fast keyer, the lines transmitted to the IRC server can get quite long and trip the server's flood detection too. Try using a more permissive server, keying less fast, or doing private QSOs in DCC CHAT. Q: The plugin starts fine but nothing happens when I key with my real key A: Make sure the serial device file you've set is the one you connected your key to. The plugin can't detect your morse key. Q: When someone transmits, the CW flow is chopped every now and then A: This is most likely due to lag between the person's machine and the IRC server, or between your machine and the IRC server. Try to increase the receive buffering, or try to connect to a more responsive, less busy server, or initiate a DCC CHAT with the other party to communicate directly without the IRC server. Q: I've increased the buffering and the sounds still cuts, or the sound cuts when I run many things on my system A: See the "Solving the scratchy sound problem" section above Q: A friend has CWirc installed, I can see some coded frames coming from him and he can see some of mine, and none of us can hear anything, or only partially. A: The frame format changed at version 0.3.0, at version 0.8.0 and again at version 1.7.0. Frames generated by previous versions of CWirc will be dismissed as normal text. Please upgrade to the latest version. Q: I've joined my favorite channel on my favorite IRC server, I've sent CQ to see if I could get a contact with other CWirc users, and I've been kicked off the channel / banned / insulted as a result. What's going on ? A: When the CWirc plugin is loaded, it filters out incoming and outgoing CW frames and simply displays "sending" or "receiving" (or nothing at all) to spare you of having to watch encoded garbage. However, non-CWirc users will see the garbage and will quickly interpret it as a very unfunny trick from you, and classify you as a nuisance. Please ask if there are any CWirc users on the channel in plain text first, then either /QUERY other users in private, DCC CHAT to them, or create another IRC channel, so regular IRC users aren't bothered. Q: Why isn't the "sounder" option available under FreeBSD or NetBSD, in the "CW output" setting ? A: Normally, CWirc uses the soundcard to pace itself, i.e. it takes advantage of the fact that it takes a very precise amount of time to play a chunk of audio. With the "sounder" option, the soundcard isn't used at all. Therefore, CWirc has to use another precise timing source. Under Linux, it's possible to use the /dev/rtc interface for this. Under FreeBSD or NetBSD, there is no such interface natively, and the rtc kernel module available as Linux emulation isn't complete and lacks some of the functions used by CWirc. As a result, the "sounder" option is simply disabled under these OSes. Q: What is this DOT thing in the decoder language selection ? A: DOT code isn't a language but an old telegraph code directly derived from a flag code. Most notably, it was used by the U.S. military during the American Civil War. DOT code is not morse code, and isn't in use anymore apart during living history events and reenactments. If you're interested in historical landline telegraphy and would like to setup a station to simulate a telegraph station of that period, you can use the sounder clicks simulator and switch the decoder to DOT code to help you copy this old code. Q: I key morse, but apparently nobody hears me A: Check that you're not in sidetone mode. In sidetone mode, CWirc works exactly like in normal mode, only it never transmits anything 9 - Contributions If you feel like improving the plugin, please send me your changes, I'll glady incorporate them. Also, if you run have an IRC server and would like to dedicate a channel to morse users, please let me know so I can post the address of your server for others to use. I personally use irc.freenode.net, which is a nice permissive IRC server. 10 - Credits Many thanks to the following people : - Patrick Maille for doing a lot of testing on different Linux flavors, and for his suggestions. - Juha Nygard for providing FreeBSD specific help and a shell account on his FreeBSD box. - Bill Meahan for providing NetBSD patches, testing and debugging help. - Ted Wagner & David T. Bock for their help to add DOT code in the automatic decoder. - Mac WA4CAW, for his time, help, and documentation, to figure out the iambic keyer timings. - Ted WA0EIR, for his help and obscure-bug-finding abilities. - Joop Stakenborg PG4I for maintaining the Debian package and for the bugfixes. 11 - Legalese This software is released under the terms of the General Public License. See the "COPYING" file for details. Oh, and yes, I forgot : DISCLAIMER : I am not responsible for any damage caused by this software, whether it's on your computer, your morse key, or if it wipes out your hard-drive, or if it sets off a nuclear bomb, etc ... cwirc-2.0.0.orig/LISEZMOI0000644000175000017500000015166310433706413013242 0ustar pg4ipg4i CWirc - plugin morse pour X-Chat -------------------------------- 2.0.0 ----- F8EJF Pierre-Philippe Coupard 20/05/2006 CWirc est un plugin pour le client IRC X-Chat pour transmettre du code morse par internet en utilisant des serveurs IRC comme rflecteurs. Le code morse transmis peut tre reu quasiment en temps rel par d'autres clients X-Chat munis du plugin CWirc. CWirc s'efforce d'imiter un vrai transceiver radio : il envoie et reoit le signal morse sur des canaux virtuels, et il peut recevoir plusieurs metteurs transmettant simultanment sur un mme canal. Le code morse est envoy localement l'aide d'un manipulateur de type pioche ou double contact connect un port srie, ou l'aide des boutons de la souris, et le son est mis par la carte son, ou bien par un sondeur externe. A noter que CWirc ne dcode pas le code morse : il transmet et reoit simplement des timings sonores. Un chatteur IRC normal sur le mme canal IRC sur lequel vous tes en train de transmettre en morse ne verra que des lignes codes. Seuls d'autres utilisateurs de CWirc peuvent recevoir vos transmissions. 1 - Installer CWirc - Editez le Makefile pour choisir le systme d'exploitation cible (LINUX, FREEBSD or NETBSD) et les chemins d'installation pour les excutable de CWirc. - Tapez "make" pour compiler le programme - Installez le plugin et son interface utilisateur en tapant "make install" en tant que root 2 - Utiliser CWirc CWirc est compos de deux parties : un plugin pour X-Chat qui intercepte et envoie le code morse sous forme de texte IRC, et un programme d'interface graphique spar pour interagir avec l'utilisateur. L'interface graphique est dmarre par le plugin uniquement, et ne peut pas tre utilise en tant que programme spar. Pour utiliser CWirc, X-Chat doit d'abord charger le plugin. Normalement, le plugin CWirc est install dans le rpertoire des plugins d'X-Chat sous le nom "cwirc.so", et est automatiquement charg par X-Chat au dmarrage. Vous pouvez vrifier qu'il a t charg correctement en allant dans le menu "Windows" -> "Plugins and Scripts" d'X-Chat vrifier que CWirc apparat dans la liste. Quand le fichier "cwirc.so" est charg, il ajoute une nouvelle commande appele "/CW" (faites "/HELP CW" pour le vrifier), et il ajoute galement un bouton "CWirc" dans les boutons utilisateurs d'X-Chat (si vous ne le voyez pas, essayez d'activer "Userlist button enabled" dans le menu "Preferences -> User list". La commande "/CW" et le bouton "CWirc" tous deux activent et dsactivent le plugin. A noter que CWirc ne devrait avoir aucune incidence sur vos discussions IRC normales, sur aucun canal, mais qu'il filtre en permanence les trames de morse, qu'il soit activ ou non, afin de vous permettre de chatter normalement sur un canal IRC ddi au morse mme quand le plugin est dsactiv. Lorsque le plugin est activ, l'interface graphique est appele et le panneau de contrle de CWirc apparat l'extrieur d'X-Chat. Dans le panneau de contrle, il y a six pages : la page principale ("Main") mais aussi les pages de rglage du gnrateur iambic ("Keyer settings"), de simulation, de gestion des informations personnelles ("Personal info"), de configuration d'entres/sorties ("I/O configuration") et d'information sur le programme ("About"). 2.1 - La page principale ("Main") 2.1.1 - Le S-mtre et bouton "sidetone" Il s'agit de la simulation d'un S-mtre aiguille classique. Quand la simulation de force du signal est utilise (voir plus bas), il indique la puissance du signal d'entre. Quand aucune simulation n'est utilise, il est simplement dcoratif et l'aiguille bouge de S0 a S9+30 quelle que soit la provenance du signal. Quand on clique sur le S-mtre, CWirc passe en mode "sidetone". Quand on clique nouveau, CWirc revient en mode normal. En mode "sidetone", vous pouvez manipuler localement sans mettre quoi que ce soit. C'est utile pour ajuster son manipulateur, ou pour s'entraner manipuler, sans dranger personne sur le canal. 2.1.2 - Le rglage du canal ("Channel") CWirc implmente le concept de "canal CW", diffrent du canal IRC. Il s'apparente la frquence que l'on slectionne sur un vrai transceiver radio. Vous pouvez envoyer ou recevoir du morse sur un seul canal CW la fois. CWirc ignore les signaux morses envoys sur les autres canaux CW. Il y a 4000 canaux CW disponibles (de 0 3999), par consquent sur un canal IRC donn, il peut y avoir jusqu' 4000 QSOs distincts en mme temps. Le slecteur "PR x" slectionne l'un des 5 canaux prrgls. Le numro du canal juste au dessous permet de rgler le canal CW pour le canal prrgl choisi. Ainsi, vous pouvez programmer jusqu' 5 canaux CW favoris : par exemple, vous pourriez rgler le canal prrgl no.1 sur 1000 pour le canal CQ, le canal no.2 sur 1100 pour le canal sur lequel vous faites QSY le plus souvent, le canal no.3 sur 912 pour couter le canal des nouvelles en morse, ... 2.1.3 - Le rglage de la tonalit du son reu ("RX pitch") Ce rglage change la hauteur du son du code morse reu, permettant d'couter votre correspondant la frquence audio qui vous est la plus confortable l'oreille, ou permettant de faire la distinction entre plusieurs oprateurs mettant sur le mme canal, si vous avez une "meilleure oreille" pour une tonalit particulire. NOTE: ce rglage est ineffectif si CWirc met des clics de sondeur la place de bips, ou si la sortie CW est un sondeur externe seul (voir plus bas). 2.1.4 - Le rglage de la tonalit du son mis ("TX pitch") Ce rglage change la hauteur du son de votre propre signal qui vous est renvoy localement. Vous pouvez l'ajuster en mode "sidetone" (voir ci-dessus) pour viter d'mettre n'importe quoi sur le canal. NOTE: ce rglage est ineffectif si CWirc met des clics de sondeur la place de bips, ou si la sortie CW est un sondeur externe seul (voir plus bas). 2.1.5 - Le rglage du silencieux ("Squelch") Si vous utilisez la simulation de QRN (voir plus bas), la statique radio simule est mise continuellement et devient rapidement fatiguante. Comme avec une vritable radio, pour couper le bruit de fond quand il n'est pas utile (quand vous n'tes pas en train d'mettre ou de recevoir quelque chose), rglez le silencieux assez haut pour couper le bruit de fond, et assez bas pour ractiver le son quand un signal utile arrive. Notez que si vous utilisez la simulation de force du signal et/ou la simulation de couche E sporadique (voir plus bas), utiliser le silencieux peut vous faire perdre des signaux faibles. 2.1.6 - The rglage du volume ("AF gain") Ce rglage change le volume des bips ou des clics de sondeur mis par la carte son. Notez que le priphrique de mixage de votre ordinateur n'est pas utilis pour rgler le volume : CWirc gnre simplement des signaux sonores de moindre amplitude en interne. 2.1.7 - Le rglage du manipulateur ("Key") Ce bouton indique CWirc d'interprter les clics souris dans la zone de manipulation, ou un vrai manipulateur connect un port srie (voir plus bas), comme une pioche (straight) ou un manipulateur double contact utilisant le gnrateur iambic interne ("iambic"). L'image affiche dans la zone de manipulation par la souris change en consquence, soit l'image d'une pioche, ou bien celle d'un manipulateur double contact. 2.1.8 - Le rglage de vitesse du gnrateur iambic ("keyer") Si vous choisissez "iambic" dans le rglage "Key", vous pouvez rgler la vitesse du gnrateur iambic en mots par minute ("WPM"). Le gnrateur fonctionnera alors cette vitesse, en accord avec les rglages de la page "Keyer settings" (voir plus bas). 2.1.9 - La zone de manipulation par la souris Si vous avez activ la souris comme mode de manipulation (voir plus bas), vous pouvez manipuler avec la souris en plaant le pointeur dans l'icne reprsentant un manipulateur morse et en utilisant les boutons de la souris comme pioche ou manipulateur double contact. Si vous dfinissez le manipulateur comme tant de type double contact (iambic), les boutons gauche et droits de la souris mulent les deux contacts. Si vous dfinissez le manipulateur comme tant de type pioche, l'un ou l'autre bouton de la souris mule le contact unique du manipulateur. 2.1.10 - The dcodeur de morse automatique En bas du panneau de contrle, il y a une ligne de texte contenant les caractres dcods en provenance du signal morse en cours de rception. Le dcodeur de morse qui gnre ces caractres simule un dcodeur automatique rel, connect la sortie audio d'un transceiver radio rel. Par consquent, it ne fonctionnera que si une seule personne transmet la fois. Si plusieurs personnes envoient du morse en mme temps sur le mme canal CW, comme dans un pileup, ou bien si vous transmettez par dessus le signal de quelque'un, le dcodeur sera perdu et dcodera n'importe quoi. Si vous avez vraiment besoin de dcoder une personne en particulier dans un pileup avec le dcodeur, vous pouvez utiliser la commande IRC "/IGNORE" pour faire taire tous les autres metteurs. Si vous utilisez la simulation de force du signal ou la simulation de couche E sporadique, le dcodeur ne fonctionnera pas si le signal reu est trop faible ou fluctuant, ou ne dcodera pas correctement. De la mme manire, si un signal fort arrive en mme temps qu'un signal faible, seul le signal fort sera dcod. Si plus d'un signal fort arrive en mme temps, le dcodeur sera perdu. Le dcoder a galement besoin "d'entendre" un peu de signal avant de pouvoir se synchroniser correctement avec l'metteur, ou avec vous. Par consquent, le ou les premiers caractres seront errons le temps que le dcodeur devine le timing du code morse. Il se re-synchronisera de la mme faon si l'metteur change brutalement sa vitesse de transmission de manire consquente, ou si vous-mme ne rpondez pas une vitesse proche de celle de votre correspondant. Enfin, bien que le dcodeur tolre des timings morse lgrement incorrects et des vitesses de transmission qui drivent, il a tout de mme besoin de recevoir du code morse "propre" pour fonctionner correctement. Vous ferez aussi bien d'utiliser vos oreilles pour copier un mauvais oprateur, ou un oprateur qui utilise un rapport de dure dit/silence trs atypique. Le dcodeur est aussi utile en mose "sidetone" (voir plus haut) pour s'entraner a manipuler du code morse clair avec un timing correct. NOTE: Si vous faites un QSO dans un code autre que le code morse moderne ou le code DOT, comme par exemple en code morse amricain, le dcodeur ne comprendra pas et produira n'importe quoi. 2.1.11 - L'indicateur de vitesse du dcodeur, et bouton de remise zero L'indicateur de vitesse du morse reu par le dcoder la droite du texte dcod, en mots par minutes, est une mesure de la vitesse de manipulation de votre correspondant. La vitesse est dtermine directement partir du signal reu ou envoy, et donc peut tre assez approximative. Si le dcodeur est perdu cause de deux signaux simultans, ou cause d'un signal fluctuant, l'indicateur de vitesse se met varier tout le temps et ne veut plus rien dire. Si le code morse n'utilise pas un rapport de dure dit/silence de 50%, l'indicateur de vitesse sera aussi fauss. Cet indicateur sert aussi de bouton de remise zro du dcodeur. en cliquant dessus, le tampon de caractres dcods est effac et l'tat interne du dcodeur est remis zro. 2.1.12 - Le slecteur de langue du dcodeur de morse automatique A droite de l'indicateur de vitesse, vous pouvez slectionner quelle langue ou quel code vous souhaitez que le dcodeur utilise. Le morse Anglais (international), Franais, Russe et Japonais (katakana), ainsi que le code DOT (qui est un code historique distinct du morse) sont supports. Afin de voir les caractres dcods dans une langue autre que l'Anglais (morse ou DOT), vous devez avoir un jeu de fontes Unicode/ISO-10646 install sur votre systme. Si vous tes intress par un code morse different de l'Anglais, il y a de bonnes chances que votre machine soit dj configure correctement. Sinon, un bon document lire pour configurer vos fontes correctement sous X est le document "XFree86 Font De-uglification HOWTO" (en Anglais, pas de VF disponible ma connaissance), disponible sur : http://www.tldp.org/HOWTO/FDU/index.html Si vous trouvez le dcodeur gnant, ou que vous ne pouvez pas vous empcher de le regarder lorsque vous vous entranez la copie, slectionnez "No decoder" pour l'arrter. 2.2 - La page de rglage du gnrateur iambic ("Keyer settings") Cette page vous permet d'ajuster le gnrateur iambic votre got. Les caractristiques et rglages d'un gnrateur iambic sont une affaire trs personnelle : des gnrateurs de diffrents fabricants (ou des ralisations personnelles), et mme quelquefois des modles diffrents d'un mme fabricant, ont tous des rponses lgrement diffrentes la mme manipulation d'un oprateur, et presque tous les oprateurs ont tendance prfrer les caractristiques du gnrateur avec lequel ils ont appris l'iambic. Le gnrateur interne de CWirc peut tre ajust pour reproduire les caractristiques de presque tous les gnrateurs qui existent. 2.2.1 - Le slecteur de mode iambic Slectionnez le mode iambic que vous voulez que le gnrateur utilise (mode A ou B). Le mode iambic change seulement le comportement du gnrateur lorsque les deux contacts sont relchs aprs avoir t mis en oeuvre les deux la fois (c'est la dfinition du mode iambic) : en mode A, quand les deux contacts sont relchs au milieu d'un lment en cours d'mission (dit ou dah), l'lment est complt, puis le gnrateur s'arrte. En mode B, l'lment est complt, puis le gnrateur ajoute automatiquement un lment oppos, puis s'arrte. Si, quand vous manipulez, vos Cs se transforment rgulirement en Ks, vous utilisez probablement le mode A alors que vous tes habitu au mode B. A l'inverse, si vos Ks se transforment en Cs, vous tes probablement habitu au mode A. 2.2.2 - La mmoire de dit et la mmoire de dah ("dit memory", "dah memory") Si vous activez la mmoire de dit, quand le gnrateur dtecte le contact des dits se fermer durant l'mission d'un dah, mme brievement, il s'en "souvient" et met un dit ds que le timing morse le permet. de la mme manire, la mmoire de dah autorise l'insertion automatique d'un dah quand le contact des dahs est ferm brievement durant l'mission d'un dit. Typiquement, la mmoire de dit et de dah sont utilises pour gnrer des Ns et des As en fermant rapidement les deux contacts successivement, l'un aprs l'autre (mais sans fermer les deux contacts la fois, ce qui ferait entrer le gnrateur en mode iambic). Elles sont aussi trs utiles pour gnrer des lettres telles que Y, Q, L ou F en envoyant un flot de dahs ou de dits, et en insrant un dit ou un dah en fermant rapidement le contact oppos au moment adquat. 2.2.3 - Le mode B de demi-lment ("mid-element mode-B") La plupart des gnrateurs en mode B ajoutent automatiquement un lment oppos lorsque les deux contacts sont relchs n'importe quel moment durant l'lment en cours d'mission, en mode iambic. Cependant, certains gnrateurs semblent faire la distinction entre le cas o les deux contacts sont relchs avant le milieu de l'lment en cours d'mission, et le cas o ils sont relchs aprs. Dans le second cas, ces gnrateurs n'envoient pas un lment oppos supplmentaire, alors qu'ils le font dans le premier cas. Ces gnrateurs semblent tre assez rare cependant. Si vos As se transforment rgulirement en Rs, et vos Us en Fs, mais que votre manipulation est correcte le reste du temps en mode B, peut-tre tes-vous habitu ce "demi mode B" et que cette option pourra corriger le problme. 2.2.4 - L'espacement de caractres automatique ("auto character spacing") Quand cette option est active, le gnrateur vous force attendre la dure correcte entre les lettres. Essayez cette option si vous avez du mal bien sparer les lettres. 2.2.5 - L'espacement de mots automatique ("auto word spacing") En plus de l'espacement de caractres automatique, vous pouvez utiliser cette option pour forcer le gnrateur vous faire attendre la dure correcte entre les mots et vous aider formater votre transmission de faon parfaite. Essayez d'utiliser cette option si vous avez constament des difficults laisser assez d'espace entre les mots. Sachez cependant que cette option requiert une bonne matrise gnrale de la technique de manipulation pour tre utilise efficacement, car elle vous force attendre une dure de pause entre mots complte chaque fois que vous hsitez sur une lettre. 2.2.6 - L'option d'inversement des contacts ("invert paddles") Si vous tes gaucher, ou si vous tes habitu manipuler avec le contact de gauche a droite et celui de droite gauche, activez cette option. 2.2.7 - Le rglage du rapport de dure dit/silence ("dit weight") A l'poque o les radios avaient souvent un peu de retard entre le moment o le manipulateur tait activ et le moment o elles commenaient mettre, il tait souvent utile d'augmenter artificiellement la longueur des lments mis par le gnrateur iambic, afin que le signal qui tait transmis au final par la radio se retrouve avec un timing correct. De nos jours, la plupart des transceivers n'ont plus besoin de cette astuce pour envoyer de la CW au format correct, mais certains oprateurs ont gard leurs rapports de dure dit/silence inhabituels car ils pensent que cel "sonne" mieux, ou pour "personnaliser" leurs signaux. Le gnrateur interne de CWirc vous permet galement de changer le rapport de dure dit/silence, bien que cel soit totalement inutile pour faire de la CW sur le net. La valeur correspondant au timing normal du code morse est 50%. NOTE: n'exagrez pas le rglage : si vous rglez le rapport trop loign de 50%, la plupart des oprateur ne vous copieront pas confortablement, et certains peuvent ne pas vous copier du tout. 2.3 - La page de simulation Cette page vous permet de rgler CWirc afin d'obtenir une approximation du son que peut produire un vritable poste radio, pour vous entraner la copie de signaux qui ne sont pas parfait, et qui sont moins "artificiels" qu'avec les rglages de base. 2.3.1 - La simulation de QRN Activez "simulate QRN" pour ajouter du bruit et de la statique aux signaux reus. Utilisez la rglette "QRN level" pour ajuster le niveau de statique que vous souhaitez. Le niveau de QRN que vous avez choisi se traduit par une monte de l'aiguille du S-mtre correspondante dans le panneau principal. 2.3.2 - La simulation de propagation Activez "simulate signal strength for signals with grid squares" pour associer aux signaux reus une force de signal simule, calcule partir de votre locator et de ceux des metteurs des signaux en question, pour les metteurs qui ont choisi d'envoyer leur locator dans leur signal. Pour que cette option fonctionne, vous devez entrer votre locator dans la page de gestion des informations personnelles (voir ci-dessous) : CWirc dtermine la force simule d'un signal en calculant la distance entre vous et la personne qui met le signal, donc il doit connatre votre position sur Terre, ainsi que celle de l'metteur. La personne qui met a cependant le choix de ne pas divulger son locator : si le locator n'est pas envoy avec un signal, ce signal se verra attribuer une force de signal simule par dfaut, que vous pouvez ajuster avec la rglette intitule "default signal strength for signals without grid squares". En plus de la simulation de force de signal, vous pouvez y ajouter la simulation de couche E sporadique en activant "simulate sporadic-E for weak signals". Le vritable phnomne de couche E sporadique est un type de rflection des ondes radios sur la couche ionosphrique E, caus par des zones d'ionisation inhabituellement denses dans l'atmosphre, qui permet de faire de nombreux contacts longue-distance en VHF. Ces signaux rflchis on tendance a fluctuer lors des mouvements des zones d'ionisation dans l'atmosphre, ce qui rend ces contacts longue-distance difficile tablir et maintenir. Avec la simulation de couche E sporadique active, CWirc fait fluctuer la force de tous les signaux faibles qu'il reoit (environ en dessous de S3) comme s'ils venaient d'une rflexion sur la couche ionosphrique E. 2.4 - La page de gestion des informations personnelles ("Personal info") 2.4.1 - L'indicatif ("Callsign") Si vous tes radioamateur, vous pouvez entrer votre indicatif pour que les autres utilisateurs le voient dans vos messages morses, ou lorsqu'ils interrogent votre client CWirc avec la commande /CTCP CWIRC (voir plus bas). 2.4.2 - Le locator ("Grid square") Entrez le locator correspondant votre position physique sur Terre. Si vous voulez pouvoir utiliser la simulation de force de signal et la simulation de couche E sporadique. Si vous ne connaissez pas votre position sur la grille, vous pouvez la dterminer sur la page suivante, l'aide de la carte, ou si vous connaissez votre latitude et longitude : http://www4.plala.or.jp/nomrax/GL/index.html CWirc accepte les locators au format de base 4 caractres ("AB12"), ou au format plus prcis 6 caractres ("AB12CD"). 2.4.3 - L'envoi de l'indicatif avec le signal ("send callsign with CW") Si vous slectionnez cette option, CWirc enverra votre indicatif en parallle avec votre signal CW, et les autres utilisateurs de CWirc pourront le voir lorsqu'ils recevront votre signal. Si vous choisissez de diffuser votre indicatif, il sera transmis sous forme code dans le message IRC, afin que seuls les autres utilisateurs de CWirc puissent le voir. C'est utile si vous voulez rester anonyme sur IRC aux yeux des chatteurs IRC normaux, mais vous souhaitez tre connu des autres utilisateurs de CWirc par votre indicatif en mme temps. 2.4.4 - L'envoi du locator avec le signal ("send grid square with CW") Si vous slectionnez cette option, votre locator sera transmis en parallle avec votre signal CW, ce qui permettra aux autres utilisateurs de CWirc d'utiliser la simulation de force de signal avec votre signal. Si vous choisissez de diffuser votre locator, il sera transmis sous forme code dans le message IRC. Si vous voulez rester vague sur votre position exacte, entrez votre locator sur 4 caractres seulement (de tels locators dfinissent une zone de 110 km x 160 km environ en Europe ou en Amerique du nord). 2.4.5 - Les options CTCP CWirc peut rpondre une requte CTCP spciale (CTCP CWIRC) pour annoncer quelle version vous utilisez, le canal sur lequel vous tes actuellement, votre indicatif et votre locator. Si vous ne voulez divulger aucune de ces informations, dsactivez l'option "reply to CTCP CWIRC queries". Si vous l'activez cependant, CWIRC donnera quiconque tapera "/CTCP CWIRC" la version de votre client CWirc. Vous pouvez galement activer "send callsign in CTCP reply" pour laisser CWirc divulger votre indicatif, "send grid square in CTCP reply" pour divulger votre locator, et "send current channel in CTCP reply" pour divulger le canal sur lequel vous tes actuellement. Additionally, you can also check "send callsign in CTCP reply", "send grid square in CTCP reply, or "send current channel in CTCP reply" to give those details along with the CWirc version. 2.5 - La page de configuration d'entres/sorties ("I/O configuration") Cette page vous permet de rgler les paramtres pour les priphriques l'entre et de sortie des signaux CW, et le rglage du tampon de rception. Les rglages dans cette page ne sont effectifs qu'aprs que vous aillez cliqu sur le bouton "Change/Save". Si un paramtre est erron, une bote d'erreur vous informera de la raison de l'erreur. 2.5.1 - Le priphrique d'entre de la CW ("CW input") Pour manipuler dans CWirc, vous pouvez utiliser la souris en cliquant dans la zone de manipulation souris dans le panneau principal (voir plus haut) en slectionnant "mouse", un vrai manipulateur connect un a port srie (voir plus bas) en slectionnant "real key", ou les deux en slectionnant "both". Si vous slectionnez un vrai manipulateur ou les deux mthodes, the port srie ("Serial device") doit tre dfini. 2.5.2 - Le priphrique de sortie de la CW ("CW output") Pour mettre le son du morse, CWirc peut utiliser une carte son en slectionnant "soundcard", un sondeur externe connect un port srie (voir plus bas) en slectionnant "sounder", ou les deux en slectionnant "both". Si vous slectionnez la carte son ou les deux, le priphrique son ("Sound device") doit tre dfini. Si vous slectionnez le sondeur ou les deux, le port srie ("Serial device") doit tre dfini. NOTE: Si vous utilisez la fois un vrai manipulateur et un sondeur, ils partageront le mme port srie. NOTE: Si vous utilisez un sondeur, vous devriez viter d'utiliser la simulation de force de signal. En effet, comme le sondeur n'a pas de concept de volume, des signaux faibles ne seraient tout simplement pas mis. NOTE: L'option "sounder" (c'est--dire un sondeur externe comme seul priphrique de sortie) n'est pas disponible sous FreeBSD ou NetBSD, car ces systmes d'exploitation n'ont pas d'implmentation correcte de l'interface /dev/rtc, par consquent CWirc a toujours besoin d'une carte son pour obtenir un timing en temps rel. 2.5.3 - L'option du son de la CW ("CW sound") Si le priphrique de sortie de la CW est une carte son ou les deux, vous pouvez choisir d'mettre le son du code morse entrant ou sortant comme des bips traditionnels, ou comme des clics de sondeur. La plupart des radioamateurs "modernes" choisira l'option "beeps". Les clics de sondeur ("sounder clicks") sont une option destine ceux qui s'intressent l'histoire du tlgraphe, ceux qui veulent faire l'exprience du son de la tlgraphie d'une poque rvolue qu'on pouvait entendre dans les stations de tlgraphie des les gares de chemin de fer de la conqute de l'ouest, ou qui veulent s'essayer au code morse Amricain originel (qui est diffrent du code morse international que tout le monde connait aujourd'hui). Notez que les clics de sondeur mis par CWirc proviennent d'un vritable sondeur Vail, et que les timings du bras du sondeur qui vont de haut en bas ont t reproduits fidlement. 2.5.4 - L'anti-rebond pour les contacts du manipulateur ("Key debounce") Quand un manipulateur connect un port srie est utilis, le ou les contact(s) du manipulateur sont lus intervalles rguliers pour dterminer leur(s) tat(s). Si vous constatez que des dits ou des dahs parasites se produisent quand vous manipulez, il est trs possible que le ou les contact(s) prsente(nt) un phnomne de "rebond" qui se produit lorsque un contact lectrique est coup. Le "rebond" est un phnomne lectrique courant qui se produit avec presque tous les contacts lectriques. Pour remdier au problme, augmentez la valeur de l'anti- rebond ("Key debounce") jusqu' ce que le problme disparaisse. NOTE: plus la valeur de l'anti-rebond est faible, meilleure sera la prcision du timing, ce qui est important surtout si vous tes un oprateur rapide. Si vous trouvez le manipulateur "mou" et/ou si vous ratez des lments quand vous manipulez vite, essayez de diminuer l'anti-rebond. 2.5.5 - Le rglage du tampon de rception ("Recv buffering") Ce rglage indique CWirc pendant combien de temps (en millisecondes) il doit stocker le dbut d'un signal morse reu. Sur des serveurs IRC raisonnablement responsifs, 1000 ms (1 s) est en gnral suffisant. Si vous tes connect un server IRC charg et lent, essayez d'augmenter la valeur pour augmenter la quantit de signal morse dans le tampon de rception. Si vous tes connect un serveur IRC local, ou si vous recevez un signal d'un oprateur avec lequel vous tes en DCC CHAT (voir plus bas), vous pouvez diminuer la valeur. Plus vous augmenter la valeur du tampon de rception, moins votre client CWirc sera sujet des coupures de signal dues un retard des donnes entrantes, mais plus le temps de latence en rception augmentera. 2.5.6 - Le priphrique son ("Sound device") Si le priphrique de sortie de la CW est la carte son ou les deux, ce rglage indique CWirc quel fichier de priphrique son utiliser pour accder la carte son. En gnral, il s'agit de "/dev/dsp" sous Linux, "/dev/dsp0.0" sous FreeBSD, ou "/dev/audio0" sous NetBSD, si vous n'avez qu'une seule carte son. NOTE: si vous voulez utiliser the dmon aRts avec CWirc, vous pouvez grce au convertisseur artsdsp et avec un peu de bricolage, au dpend de la latence audio : - En tant que root, renommez l'excutable "cwirc_frontend" (d'habitude install dans /usr/bin ou /usr/local/bin) en "cwirc_frontend.REAL" - En tant que root, ditez un nouveau script shell dnomm "cwirc_frontend" la place du vrai excutable, contenant les lignes suivantes : #!/bin/sh artsdsp cwirc_frontend.REAL $* et rendez-le excutable en invoquant chmod +x cwirc_frontend - Redmarrez CWirc et assurez-vous que le priphrique son est "/dev/dsp". Le son devrait alors tre redirig vers le dmon aRts. 2.5.7 - Le port srie ("Serial device") Si le priphrique d'entre de la CW est un vrai manipulateur ou les deux, ou bien si le priphrique de sortie de la CW est un sondeur ou les deux, ce rglage indique CWirc sur quel port srie sont connects le manipulateur et/ou le sondeur. En gnral, utilisez /dev/ttyS0 pour COM1, /dev/ttyS1 pour COM2 ... sous Linux, /dev/cuaa0 pour COM1, /dev/cuaa1 pour COM2 ... sous FreeBSD, ou /dev/tty00 pour COM1, /dev/tty01 pour COM2 ... sous NETBSD. 2.6 - Faire des QSOs sur un canal IRC Une fois que CWirc est configur comme vous le souhaitez, connectez-vous un server IRC et rejoignez un canal IRC o l'on trouve du trafic morse. N'oubliez pas de rgler le canal CW sur le mme que celui des autres participants (gnralement 1000 est le canal de CQ). Le morse que vous manipulez sera envoy sur le canal IRC sous forme de lignes de texte codes toutes les 2 secondes. De la mme manire, votre client CWirc recevra des signaux morse envoys sous forme de lignes codes. Notez que le morse reu sur les canaux autres que celui sur lequel vous tes sera ignor. IMPORTANT: CWirc utilise un protocole qui ressemble beaucoup des caractres alatoires envoys grande vitesse, aux yeux des chatteurs IRC qui n'utilisent pas CWirc. Soyez vigilants et n'utilisez pas CWirc sur des canaux IRC de chat gnraux (c'est--dire non-ddis au trafic morse) moins que vous ne connaissiez les chatteurs et que vous ne les prveniez l'avance. 2.7 - Faire des QSOs hors d'un canal IRC Il est possible que vous ne souhaitiez pas discuter de certaines choses sur un canal IRC public, afin que n'importe qui sur votre canal CW n'entende pas ce que vous dites. Il est possible de discuter en priv avec une autre personne en utilisant la commande IRC /QUERY, en morse, comme vous le feriez pour envoyer des messages IRC normaux en priv. Toutefois, vous est votre correspondant devez tout de mme rester sur le mme canal CW. Vous pouvez aussi chatter en DCC CHAT avec l'autre correspondant : dans ce cas, la connection entre vous et l'autre correspondant est directe, se passe compltement du server IRC, ce qui a pour avantage de rduire le dlai entre les 2 clients IRC, et vous assure de ne pas vous faire "sortir" du canal IRC pour raison de flooding. 2.8 - Bloquer CWirc sur un canal IRC Normalement, CWirc reoit et envoie du morse sur le canal IRC courant. Si vous ne faites que du morse, c'est gnralement suffisant. Cependant, il est possible que vous vouliez faire du morse sur un canal IRC, tout en chattant normalement sur un autre. Typiquement, la situation se prsente quand vous attendez que quelqu'un lance l'appel sur un canal IRC ddi au morse, et que vous vouliez chatter avec des amis sur un autre canal IRC en attendant. Vous pouvez ordonner CWirc de ne pas suivre le canal courant. Pour faire cel, allez sur le canal IRC sur lequel vous voulez faire du morse et tapez la commande "/CWLOCK" : CWirc vous dit alors qu'il est maintenant bloqu sur ce canal IRC. Vous pouvez alors aller faire ce que vous voulez sur d'autres canaux IRC, CWirc restera sur le canal sur lequel vous l'avez bloqu. Si vous voulez bloquer CWirc sur un autre canal, allez sur ce nouveau canal et tapez la commande "/CWLOCK" nouveau. Si vous voulez revenir au mode par dfaut qui est de suivre le canal IRC courant, tapez la commande "/CWUNLOCK". Notez que vous pouvez galement bloquer et dbloquer CWirc sur des fentres de chat priv et de chat en DCC CHAT. 2.9 - Notes sur l'utilisation de la simulation Si vous utilisez la simulation de force de signal, et particulirement si vous y ajoutez la simulation de couche E sporadique, il est trs possible de ne pas entendre un signal du tout malgr que CWirc dit le recevoir, s'il est trop faible (si l'oprateur qui envoie le signal est trop loign de vous physiquement) ou s'il est trop attnu par la simulation de couche E sporadique. De plus, bien que cel soit possible, n'est pas une trs bonne ide d'utiliser la simulation de force de signal ou de couche E sporadique avec un sondeur : si le signal est trop faible, le son du sondeur s'arrtera tout bonnement, puisque il s'agit d'un priphrique tout-ou-rien. Enfin, bien que cel soit possible galement, notez qu'utiliser des sons de clics de sondeur avec du QRN simul, ou avec la simulation de force de signal ou de couche E sporadique, n'a aucun sens : les sondeurs taient utiliss pour la tlgraphie filaire, et donc ne gnraient jamais de statiques ou de signaux faibles. 3 - Connecter un vrai manipulateur Manipuler la souris est acceptable quand aucune autre solution n'existe, mais n'est vraiment pas idal. Si vous avez un vrai manipulateur, vous pouvez l'utiliser avec CWirc en le connectant votre ordinateur avec un simple cble srie : 3.1 - Utiliser une pioche En supposant que votre port srie utilise un connecteur DB9, le schma de cblage est le suivant : No. du fil DB9 Manipulateur ===== 6 (ligne DSR) --------------------+-------------| 4 (ligne DTR) --------------------+-------------O Une fois que le manipulateur est connect, configurez CWirc en rglant l'entre de la CW sur "real key" ou "both" et le type de manipulateur sur "straight" dans le panneau principal. 3.2 - Utiliser un manipulateur double contact En supposant que votre port srie utilise un connecteur DB9, le schma de cblage est le suivant : No. du fil DB9 Manipulateur 8 (ligne CTS) --------------------+--------O--===== Contact de droite 4 (ligne DTR) --------------------+--------| Commun 6 (ligne DSR) --------------------+--------O--===== Contact de gauche Une fois que le manipulateur est connect, configurez CWirc en rglant l'entre de la CW sur "real key" ou "both" et le type de manipulateur sur "iambic" dans le panneau principal. 4 - Connecter un sondeur externe CWirc peut contrler un sondeur, un gnrateur de bips, ou mme la ligne PTT de votre transceiver, au travers de la ligne RTS du port srie. Il est possible de faire en sorte que cette ligne change d'tat en fonction du code morse reu ou mis, en parallle avec la carte son, ou la place de la carte son. C'est une fonction utile pour diffrents types d'utilisateurs : - Ceux dont la carte son ne peut tre utilise par plus d'un processus la fois et qui veulent couter quelque chose en mme temps qu'ils font de la CW - Les gens qui veulent faire l'exprience du son originel du tlgraphe (c'est--dire le son du sondeur), qui taient non pas des bips mais des clics - Les radioamateurs qui veulent retransmettre un QSO CW internet sur les ondes - Les utilisateurs qui ont un problme d'audition et qui ont besoin d'une indication visuelle des dits et des dahs Bien entendu, on ne peut pas trouver d'appareils pour faire du morse contrls par une ligne RTS de port RS232 tout faits dans le commerce, donc il vous faudra probablement dpoussirer votre fer souder et le faire vous- mme. Le plus simple est probablement de fabriquer une petite interface relai contrl par la ligne RTS, avec un optocoupleur pour protger votre port srie, puis d'utiliser le relai pour injecter une tension dans un oscillateur d'entranement tout fait, un buzzer, une ampoule ou une bobine de sondeur. En supposant que votre port srie utilise un connecteur DB9, le schma de cblage est le suivant : No. du fil DB9 7 (ligne RTS) --------------------+-------- Sortie sondeur 5 (ligne GND) --------------------+-------- Masse logique Une fois que le sondeur est connect, configurez CWirc en rglant la sortie de la CW sur "sounder" ou "both". Avec un sondeur, si plusieurs oprateurs envoient du morse sur le mme canal CW en mme temps, il n'est pas possible de discerner entre eux grce la hauteur du son, vu que la seule information disponible avec une ligne de donne unique est la prsence ou l'absence de signal. NOTE: si vous rglez la sortie de la CW sur "sounder" (option disponible seulement sous Linux), CWirc ne pourra pas utiliser la carte son pour obtenir son timing en temps rel. Donc, il essayera d'utiliser l'horloge en temps rel de l'ordinateur la place, travers l'interface /dev/rtc. Vous devez cependant configurer certains choses pour autoriser un programme utilisateur accder /dev/rtc : - Activez l'option "Enhanced Real Time Clock Support" dans le noyau Linux, soit en tant que module, soit compil dans le noyau - Changez les permissions du fichier /dev/rtc pour qu'il soit accessible par un utilisateur normal - Autorisez CWirc demander au noyaux de gnrer 1024 interruptions par seconde en tapant la commande suivante, en tant root : echo 1024 > /proc/sys/dev/rtc/max-user-freq (Le plus simple est de mettre cette ligne dans un script de dmarrage afin que l'horloge en temps rel soit toujours configure correctement chaque redmarrage de la machine.) Si vous utilisez la sortie CW par la carte son et par le sondeur en mme temps, vous n'avez pas besoin de faire la configuration ci-dessus. En effet, CWirc utilise automatiquement la carte son pour se synchroniser chaque fois que c'est possible. 5 - Programmes d'extensions pour CWirc Depuis la version 1.7.0, CWirc supporte des programmes externes pour tendre ses fonctionnalits. Une interface de programmation simple permet un programme conu ou modifi pour fonctionner avec CWirc de recevoir l'audio de CWirc de faon synchrone, et de manipuler comme si vous manipuliez vous-mme. Si vous avez un programme d'extension install, une page supplmentaire apparatra dans le menu afin de vous permettre de le dmarrer. Notez qu'un seul programme d'extension peut fonctionner la fois. 6 - Note sur l'interfaage de CWirc et de CWCom Le type d'interfaage de priphriques externes par le port srie utilis par CWirc est strictement identique celui utilis par le programme CWCom pour Windows, de MRX Software (http://www.mrx.com.au/d_cwcom.htm). Donc, si vous utilisez dj CWCom dans Windows avec un manipulateur et/ou un sondeur connect au port srie, vous n'aurez pas besoin de modifier quoi que ce soit votre installation matrielle pour utiliser CWirc sous Unix. 7 - Rsoudre le problme de son hach Sur certaines machines quipes de cartes sons bas-de-gamme (typiquement les chipsets SiS, i8x0 ou VIA), il est possible que CWirc produise un son dsagrable et hach quand le systme est charg, mme modrment. Si vous entendez un tel son hach, essayez d'installer le programme d'interface graphique (gnralement le fichier /usr/bin/cwirc_frontend ou /usr/local/bin/cwirc_frontend) avec l'attribut suid root, en tapant les commandes suivantes en tant root : chown root /cwirc_frontend chmod u+s /cwirc_frontend puis en redmarrant CWirc. Cel devrait supprimer le problme, ou au moins l'amliorer. Quand CWirc est excut avec l'attribut suid root, il demande au systme de donner sa routine d'entres/sorties une priorit d'excution suprieure la plupart des autres processus du systme, ce qui contribue liminer le retard de transfer de donnes vers la carte son l'origine du son hach. CWirc ne peut demander ce traitement de faveur au systme que s'il a les mmes droits que le superutilisateur (root), d'o la ncessit d'installer le programme suid root. CWirc est normalement install sans l'attribut suid root par dfault, car bien qu'il renonce aux droits du superutilisateur immdiatement aprs avoir chang sa propre priorit systme, presque au tout dbut du programme, et par consquent devrait tre trs sr, les programmes avec l'attribut suid root sont en gnral considrs comme un risque pour la scurit du systme, et de toute faon la plupart des utilisateurs n'auront aucun problme de son avec CWirc tournant avec une priorit systme normale. C'est la raison pour laquelle il vous est laiss le soin de changer l'attribut suid root du fichier de l'interface graphique la main, seulement si vous en avez besoin. Si le problme semble persister, vous pouvez vrifier que CWirc a effectivement russi changer la priorit de sa routine d'entre/sorties avec les droits du superutilisateur. Pour cel, invoquez : ps x | grep cwirc_frontend alors que CWirc tourne, et vrifiez que l'un des deux processus appels "cwirc_frontend" a un "<" marqu devant son nom, ce qui signifie que le processus possde une priorit leve. 8 - FAQ Q: Quand je rgle "CW output" sur "sounder", quand je dmarre le plugin, il dit "Error : cannot open /dev/rtc." mais je suis sr que mon noyau a le support pour l'horloge en temps rel, qu'il est configur correctement et que le fichier /dev/rtc a les permissions correctes. R: Des programmes qui utilisent /dev/rtc comme VMware ou mplayer ont le contrle exclusif de l'horloge en temps rel et doivent tre arrts avant de pouvoir utiliser CWirc. Tapez "lsof /dev/rtc" pour voir quel est le processus actuellement en train d'utiliser /dev/rtc. Q: Quand je rgle "CW output" sur "sounder", quand je dmarre le plugin, il dit "cannot set /dev/rtc to generate 1024 interrupts per second." R: Par dfaut, le noyau Linux ne laisse pas les programme non-root demander plus de 64 interruptions par seconde l'horloge en temps rel. CWirc en a besoin de 1024, donc il faut que vous leviez cette barrire de scurit dans le noyau. Voir la section traitant de l'utilisation d'un sondeur plus haut pour les details. Si vous ne pouvez pas changer les paramtres du noyau parce que vous n'avez pas l'accs au systme en tant que superutilisateur, vous devrez utiliser la carte son en mme temps. Q: Quand j'essaye de dmarrer CWirc, X-Chat me dit "CWirc : error : cannot execute cwirc_frontend" ". R: cwirc_frontend est l'excutable pour l'interface graphique de CWirc. Il doit tre dans votre chemin de recherche "PATH" pour que le plugin puisse le dmarrer. Q: Quand je manipule, aprs un moment, le serveur IRC me "sort" R: Quand vous transmettez, beaucoup de donnes sont envoyes au server IRC trs rapidement. La plupart des serveurs IRC autorisent jusqu' une ligne de taille raisonnable toutes les 2 secondes, mais certain serveurs peuvent interprter vos messages comme du "flooding" et vous dconnecter. De plus, si vous manipulez trs vite, les lignes envoyes au server IRC peuvent devenir assez longues et dclencher le mcanisme de protection anti-flood du serveur. Essayez d'utiliser un serveur plus permissif, de manipuler moins vite, ou de faire des QSOs privs en DCC CHAT. Q: Le plugin dmarre correctement, mais rien ne se passe quand je manipule avec un vrai manipulateur R: Assurez-vous que le fichier du port srie que vous avez configur correspond bien au port srie sur lequel vous avez connect votre manipulateur. Le plugin ne peut pas dtecter votre manipulateur morse. Q: Quand quelqu'un transmet, le flot de CW est coup de temps en temps R: C'est trs probablement d au retard entre la machine de la personne et le serveur IRC, ou entre votre machine et le serveur IRC. Essayez d'augmenter la valeur du tampon de rception, essayer de vous connecter un serveur plus responsif et moins charg, ou bien initiez une session en DCC CHAT avec l'autre personne pour communiquer directement sans passer par le server IRC. Q: J'ai augment la valeur du tampon de rception mais le son est toujours hach, ou bien le son est hach lorsque je fais tourner beaucoup de programmes dans mon systme R: Voir la section "Rsoudre le problme de son hach" plus haut Q: Un ami a CWirc install, je peux voir des trames encodes qui proviennent de son client, et il peut voir les miennes, et aucun de nous ne peut entendre l'autre, ou alors seulement partiellement R: Le format des trames a chang la version 0.3.0, puis de nouveau la version 0.8.0, et encore une fois la version 1.7.0 de CWirc. Les trames gnres par les versions prcdentes de CWirc sont ignores et considres comme des messages IRC normaux. Installez la dernire version pour rsoudre le problme. Q: J'ai rejoint mon canal favori sur mon server IRC favori, j'ai envoy un ou deux CQs pour voir si je pouvais faire un contact avec un autre utilisateur de CWirc, et le rsultat a t que j'ai t "ject" du canal / banni / insult. Que se passe-t-il ? R: Quand CWirc est charg, il filtre les trames CW entrantes ou sortantes et affiche seulement "sending" ou "receiving" (ou rien du tout) pour vous viter d'avoir lire du texte encod. Cependant, les autres chatteurs qui n'utilisent pas CWirc verront le texte et vous prendront trs rapidement pour un mauvais plaisantin qui s'amuse casser leurs conversations, et vous classeront dans la catgorie "nuisance". Demandez toujours s'il y a d'autres utilisateurs de CWirc sur un canal avant d'mettre, et ensuite, soit initiez une conversation en priv avec eux avec la commande "/QUERY" ou en DCC CHAT, soit crez un nouveau canal IRC pour faire du morse avec les gens intresss, afin que les autres ne soient pas ennuys. Q: Pourquoi l'option "sounder" n'est-elle pas disponible sous FreeBSD ou NetBSD, dans le rglage de la sortie de la CW ? R: Normalement, CWirc utilise la carte son comme horloge en temps rel, c'est--dire qu'il tire avantage du fait qu'il faut la carte son un temps trs prcis pour mettre un fragment audio. Avec l'option "sounder", la carte son n'est pas utilise du tout. Donc, CWirc doit se rabattre sur une autre source de timings prcis. Sous Linux, il est possible d'utiliser l'interface /dev/rtc dans ce but. Sous FreeBSD ou NetBSD, il n'y a pas de telle interface, et le module rtc disponible avec l'mulation Linux n'est pas complet et il lui manque certaines des fonctions utilises par CWirc. Par consquent, l'option "sounder" est simplement dsactive sous ces systmes d'exploitation. Q: Que signifie l'option "DOT" dans le slecteur de langue du dcodeur ? R: Le code DOT n'est pas une langue mais un ancien code tlgraphique driv directement d'un code fanions. Il tait utilis par l'arme U.S. pendant la guerre civile Amricaine. Le code DOT n'est pas un code morse, et n'est plus utilis, sauf durant les prsentations et les reconstitutions historiques. Si l'histoire du tlgraphe vous intresse et que vous voudriez reconstituer une station tlgraphique de cette poque, vous pouvez utiliser les sons de clics de sondeur et passer le dcodeur en code DOT pour vous aider copier ce vieux code. Q: Je manipule, mais apparement personne ne m'entend R: Vrifiez que vous n'tes pas en mode "sidetone". Dans ce mode, CWirc fonctionne exactement comme en mode normal, sauf qu'il ne transmet rien. 9 - Contributions Si vous pensez pouvoir amliorer le plugin, n'hsitez pas m'envoyer vos modifications, je les incorporerai avec plaisir. Aussi, si vous administrez un serveur IRC et vous voulez ddier un canal pour faire du morse, faites-le moi savoir afin que je poste l'adresse de votre serveur. Personnellement, j'utilise le server irc.freenode.net, qui est un serveur assez performant et permissif. 10 - Crdits Un grand merci aux personnes suivantes : - Patrick Maille pour avoir test CWirc sur de nombreuses distributions Linux, et pour ses suggestions. - Juha Nygard pour son aide avec FreeBSD, et pour le compte sur sa machine FreeBSD. - Bill Meahan pour les patchs NetBSD, et son aide pour le testage et le dboguage. - Ted Wagner & David T. Bock pour leur aide concernant le code DOT dans le dcodeur automatique. - Mac WA4CAW, pour son temps, son aide et la documentation afin de bien comprendre les gnrateurs iambic. - Ted WA0EIR, pour son aide et sa capacit dnicher des bogues obscurs. - Joop Stakenborg PG4I pour maintainir le paquetage Debian and pour les corrections de bogues. 11 - Mentions lgale Ce logiciel est distribu sous les termes de la License Publique Gnrale GNU (GPL). Voir le fichier "COPYING" pour plus de dtails. Ah oui, j'oubliais : AVERTISSEMENT : Je ne suis pas responsable des dommages que ce logiciel pourrait causer votre ordinateur, votre manipulateur morse, ou bien s'il efface votre disque dur, ou s'il dclenche une bombe atomique, etc ... cwirc-2.0.0.orig/RELEASE_NOTES0000644000175000017500000003451010433705700014024 0ustar pg4ipg4i2.0.0: The previous version has been used for nearly two years without any reported bugs, so it can be considered quite stable. Only a minor function was added at users' request in this release, so it is now pretty much feature-complete. Hence the jump in major version number. 1.8.8: This release fixes a rather blatant bug corruption bug that somehow managed to surface only now. It would occur when a serie of backlogged CWirc frames would arrive from the IRC server all at once, right after the receiving client's buffer had underrun, during the fadeout period. This bug would cause a bunch of "Receiving cw from ..." lines to be dumped in the X-Chat window, but with no CW signal for several seconds, and would be triggered by a high buffering value and a lagged IRC server. 1.8.7: 1.8.6: CWirc now filters out Morse frames even when the plugin is disabled. That means there's always some CWirc code running all the time in X-Chat, whereas until now, when the plugin was disabled, it was truly inactive. 1.8.5: The CWirc Debian package is now maintained by Joop Stakenborg PG4I. 1.8.4: The CWirc frontend now tries to renice itself when it starts. If it can (because the binary was installed suid root), the performances for the I/O process are improved, which helps solve the bad sound problem on system with low-end sound chips. A less kludgy solution would have been to increase the sound buffering, but this would have increased the lag between local keying and beeping, which rapidly becomes disconcerting for high-speed keyers. Right now, the lag is 30ms and that is already quite enough to make a noticeable difference between keying a real rig and CWirc. 1.8.3: 1.8.2: The size of the CWirc frontend binary was reduced dramatically by very simply tricks, like re-working and optimizing the XPM icons. Also, the code was cleaned up, resulting in some improvenemts in memory usage. 1.8.1: An obscure double-to-int rounding bug has been squashed. So obscure in fact that nobody ever hit it, but it was there nonetheless. 1.8.0: The keyer has been totally revamped. Now it proposes truly correct modes, and many options to fine-tune it just right. 1.7.7: A number of people were unhappy with the Curtis mode-B keyer setting, as it isn't like a conventional dit memory, or a Super CMOS mode-B. Also, the simple "mode-B" toggle button wasn't a very clear way to set the keyer's mode. Therefore, 2 new keyer modes have been added and a menu is now used to select them. 1.7.6: 1.7.5: The sidetone mode and the decoder decoding the local key was something many people have wanted for a long time. Now it's possible to see what you key, without sending anything on the channel, which is good for training to key. 1.7.1: The addition of the Hellschreiber extension, and the intolerance of the Hellschreiber mode for timing errors, has revealed bad inaccuracies in the sent and received event values, mainly due to rounding floats into ints when sending, and ints back to floats when receiving, with no correction for the timing drift this introduces. Timing drifts are now handled correctly, making Hellschreiber transmissions almost perfect. 1.7.0: The frame format has been extended to conserve bandwidth when transmitting many keyups/keydowns per frames. The base frame format is entirely compatible with the previous formats used so far. The extended frame format, however, isn't. Consequently, newer CWirc version will be able to receive transmissions from clients up to version 1.6.1, but older clients won't be able to receive all the frames from the newer versions. The new CWirc extension mechanism allows external programs to interact with CWirc : they can receive the sound CWirc generates using a ring buffer and 2 semaphores to transfer audio data, and to synchronize themselves with CWirc, and a flag to key CWirc. Extension programs (or synlinks to them) must be installed in the directory specified in the Makefile for CWirc to see them and list them in the extensions tab. When CWirc starts an extension program, it passes it "--cwirc" followed by the shared memory id of the extensions API. Only one extension program can run at any given time. The extensions API was made specifically to interface gMFSK and CWirc, in order to do FeldHell-over-IP : Feldhell is the only digital mode that's slow enough and close enough to CW to work over IRC. 1.6.1: NetBSD has its own sound API that is not OSS, the API used by CWirc. However, it has an OSS emulation library (libossaudio) that allows Linux programs to be compiled without modification. Therefore, in order to build and use CWirc under NetBSD, the "-lossaudio" flag must be passed to the linker. 1.6.0: 1.5.0: FreeBSD doesn't seem to have a native RTC mechanism to provide real-time periodic interrupts. The only thing it seems to have is a Linux /dev/rtc emulator that only has ioctls to start the periodic interrupts, but none to stop them, which makes it unsuitable for CWirc. Therefore, the soundcard-less operation for FreeBSD has been disabled. Also, FreeBSD has different dsp and tty device names, so these are reflected in the default CWirc settings. Finally, this release has been tested under FreeBSD 5.1. I am told FreeBSD 4.x boxes have slight differences in the naming of devices nodes in /dev, but the initial FreeBSD port was done on one of these boxes, so I believe it works. I'm a FreeBSD newbie though, so don't take my word for it. You might have to hack around to get it to go. 1.4.2: 1.4.1: 1.4.0: 1.3.0: The new signal strength simulation is based on the physical distance between stations. If the signal strength is completely artificial and made up, the algorithm to calculate the distance between two stations on the planet is accurate. The QRM generator generates pseudo pink noise by downsampling white noise and upsampling it back. It's not an accurate radio noise but it's much less CPU-intensive than "proper" sound generation with FFTs. 1.2.3: The automatic decoder now has a real "inertia" built-in, i.e. it tends to resist changing decoding speed. As a result, transient timing errors are more easily ironed out. Also, to decode bad straight keying better, it now works on the assumption that beginners follow the "music" even when they key dits or dahs way too short, resulting in spaces that are too long and would normally trigger the decoding of the current character. The decoder now silently allows longer spaces if it sees characters that it thinks are too short. This feature is on all the time as it doesn't impact the decoding of good keying by definition. 1.2.2: 1.2.1: CWirc is now more conservative with CPU, so it's possible to use it on slower computers, and faster computers with a high load, without sound breakup. This was done mainly by replacing trigonometry function calls by precalculated tables in tight loops, and by reducing the amount of GTK pixmap redraws in the S-meter drawing code. 1.2.0: This version can now generate sounder clicks as well as regular morse beeps. The sounder click samples come from an actual sounder, and the timing of its arm going down and up as the coil is energized and de-energized is reproduced accurately in CWirc. In the process of extending the sound routines, the regular beeping sound has also been cleanup up to fade in and out softly, removing the annoying clicks at the end of each beep. 1.1.0: The CW frame protocol has been extended to pass an explicit callsign along IRC message. The feature is of little value alone, but it will allow single repeater bots to forward message from multiple callsigns on non-CWirc morse networks. Note that the explicit callsign is scrambled in the IRC message, so casual IRC chatters don't immediately see who it is from. 1.0.1: Just a few minor cosmetic changes in this release. 1.0.0: This is a major code change. The user interface has been recoded as a GTK+ gui, which meant splitting the X-Chat plugin part of CWirc from the rest, so as to avoid problems between the X-Chat GTK+ session and the CWirc GTK+ one. Also, in this new version, the I/O process has been recoded to never stop and be reconfigurable on the fly. Therefore, even if it doesn't perform because of some error, the gui stays up and can reconfigure it. As a result, it's now possible to configure CWirc entirely from the gui. (no more editing ~/.cwircrc). 0.9.2: 0.9.1: In the previous version, if the sounder was activated when the plugin was disabled, it would continue beeping. This has been fixed by making the I/O process terminate gracefully and turn off the sounder before exiting. The main process doesn't abruptly kill the I/O and user interface processes anymore, it now asks them to terminate and waits for them to die, which is cleaner anyway. Also, previous versions used up nearly 2M of memory in one shared memory block, due to over-generous buffering and way to many concurrent senders which was ridiculous. The shared memory usage has been brought down to less than 50K. 0.9.0: It is now possible to output the received or sent morse code on an external sounder, or CW oscillator, throught the RTS line on a serial port. It's also possible to do without a soundcard altogether, but in this case, CWirc needs to use /dev/rtc to get its timing. Since it uses the periodic interrupt at 512Hz, it'll need special privileges set in /proc/sys/dev/rtc/max-user-freq. Since multiple inputs and outputs where getting confusing, 2 new variables have been added to the configuration file (cwinput and cwoutput) to clarify things. 0.8.2: 0.8.1: The details of exactly what iambic timings are implemented in CWirc are now included. 0.8.0: The new morse frame format uses 1/3rd less bandwidth than the previous one. The tests I've run show that one can send a continuous stream of dits at 30wpm without being throttled or kicked on the most common IRC servers, which means that in a real QSO, sustained speeds of 40/45 wpm can be expected. That should be more than enough for most operators. 0.7.0: The sound device is now used at 44.1KHz / 16 bit / stereo, in order to increase the sound fragment size to 256 bytes and still maintain a timing precision in the order of one millisecond. As a result, since 44100 Hz isn't 1000 times a power of 2 like 8000 Hz, the entire I/O, encoding and decoding sections have been adapted to cope with timing durations that aren't exactly one millisecond. This was necessary for broken or cheap sound cards that can't cope with very small sound fragments. Since it's usually admitted that all sound devices should be able to cope at least with 256 byte fragments, that's why CWirc now uses the most common sound format that consumes as many bytes per seconds as possible. The Makefile has been modified to ask the user to set the paths to xchat-plugin.h and the base installation directory for X-Chat. I've just noticed that the Debian install package I use installs X-Chat in /usr, while the X-Chat tarball installs in /usr/local and doesn't copy the .h file into the install directory. So the user has to set the correct path for his/her machine first, and the Makefile now makes sure of that. 0.6.0: An automatic morse decoder has been added. It decodes from the overall signal received, so it's useless in a pile-up, but it works rather well when receiving cw from a single sender who keys cleanly and regularly. Some people have asked for this, to help them copy fast iambic keyers. 0.5.1: 0.5.0: I finally modularized the code. The single "cwirc.c" file was quickly becoming spaghetti code. That gave me the occasion to review all the code, interactions between processes, and clean/simplify/better the whole thing. A fake S-meter has been added to the control panel : it's basically cosmetic, as there isn't much use for RST reports on IRC obviously, but it helps feel in front of a real trx, while the static panel doesn't. 0.4.2: 0.4.1: There's now a delay between the moment a cw frame is received and the moment it starts being played on the sound card. This allows for some lag in the connection to the IRC server. Before that, IRC servers had to be nearly flawlessly snappy to sustain the morse rate without choppiness. It does increase the lag between keying a frame on one end and hearing it on the other though. 0.4.0: CWirc can now be used solely with a mouse, without a real key connected to a serial port. Many people have asked for this. 0.3.0: The bug fixes in 0.2.1 didn't quite do it. After much experimenting, I determined that X-Chat just isn't thread-safe. Even spawning a thread that does nothing but sleep in a loop makes X-Chat segfault randomly after a while. So I turned the threads into normal heavy-weight processes and it appears rock-stable now. It's not as efficient in terms of memory or CPU, but at least it works well. The frame format is now more compact and many IRC servers that would kick the client when keying fast don't anymore as a result. 0.2.1: The cleanup code in the standalone version of CWirc was always followed by the termination of the program. In the plugin, it may be called again and again. As a result, the code that left variables hanging was causing the plugin and X-Chat to segfault regularly when doing /CWENABLE several times. This is fixed. 0.2.0: CWirc is now an X-Chat plugin. It makes much more sense than creating a brand new standalone IRC client, since X-Chat is full-featured, has a fairly complete plugin interface and allows plugins to do pretty much whatever they wants in terms of threads and file accesses. Corrected the iambic code, so that even a light tap on one paddle while the other is actuated ends up sending a single inverted element in the morse stream. 0.1.0: Added support for iambic keyers in mode A or B. Mode-A implemetation is straightforward, and I implemented mode-B timing as I believe it should correctly be, which is that the extra dit or dah sent after releasing squeezed paddles is sent only if the paddles are released after the first half of the last element has been sent. 0.0.2: The code was broken in the first release : users couldn't set the serial port the morse key is connected to in the config file. This is corrected. 0.0.1: First release of CWirc. The user interface is minimalistic, the code is still very unpolished and the buffering and timing code isn't very robust. The basics work though. cwirc-2.0.0.orig/schematics/0000755000175000017500000000000010433707212014171 5ustar pg4ipg4icwirc-2.0.0.orig/schematics/rs232_key_connection.jpg0000644000175000017500000004360107712325061020645 0ustar pg4ipg4iJFIFddC   '!%"."%()+,+ /3/*2'*+*C  ***************************************************"V !1AVQTUa"245Sqst67BWfu#3R$Cbr% ?):M5:23!.fFg3$6LFH@%!*[*VLDF|X_eA<5uE~m6J3$%J"5c\?.8RZPMJ<?,HbS{gyƳj%~r#K޲Wnk%c1.Kiye6j"Rb@|R)5(Ȉ&gRVZJJ$dy#!'\Rf᪚[õ,g(R,-QiJ>h9 *u!SfY整A̯Pr]Q Fy=~ڱiiLy3ri{8y]Vg*$IdR8d{33>TKAXlَ2y,dfMZ#:k0$2-&D $Dx"bZ̔"2^U'"qBiTi)4rcIj\ZU,Kfgg]#;I&"JTx%)*#<m<kVmh\UG*5 Y"%!5ߖIvdrwz\ s&Iɂ2Kǿrcͷ#2|hFٌh- mXJU}tqpih'rR*W"%#)h5X"״pAf 1S6r"ћoجgaEd۔Kt!u6Mdy%`a^]nΥ5MJam?-&zڬ0WeyYU]=W N7j^ZJ0[TYۜq q\t@`򐵡z'5ZƣWpe[N)i>oM%eIQg ,ۑ6 EMQx֔M`F~|l1Mg#5 Նg?6GBf zҥѥFI"HͰ!jmBR݇ #jV"RPADpIEb±-9ݤC8Q7dfM,;rYWm@:8)inBPF2"2-cfY!NW{_Tg1-TfJR`2L-ʃ0F gzETˋ<]nN4x}㤍U)cW%ɍ6cL R "4Xk&d)IpM*'agd2vD%%\);=)Ve.Q4lڈQ<<[`Nfͥ쇣Wfk5|2ZU.:W}ح'Iv6MbMa1NM'8B|$Jv먪h-eķG-sNcu+e[([jmֲ.3$^`yRn6/|))%c[)=@7FGo TJ`fDJJI3ۃ-᫖5K7Hc>F7u7'sǾ8ǚEP_EUh.vBcEoy*JJYV4ۧhCkuYrFeJrY;P,U&y'S;f•\uΘJVDIlSa{KDSJn͒}љ93<IVmf+Qf2h}ƖH{8ŏRȋ\[F,Vz[QAD'Kv9)Eˋ;P~5&19k5s1ף(M 2R3D^82V~"g?x_if'7Hؕ鵉Ap}P)%FQyC9ruRX'7NXp'U,szꥇ9ruRX'7NXp'U,c3*:ؒi[n$ƕ.ޣqE.$$;bXe(%-rB#$j5|iQe?u5&ڌ&e<#KszꥀHhH*d<یIq2>]cs [ Fa1TJу"NM833#Kszꥀ"",'7NXp'U,szꥇ9ruRX'7NXp'U,szꥇ9ruRX'7NXۗt C63 S#+NaHw@g)VsLgF`E? >-Z+"GٟVdX *^.TtڇuMF඘>ծـ7FhipRҞCrƲRdJ25_hm~4oo?bF_ s|m ؐJtI2~DC""I--t3udiqFQtuC5z۸^گu(VP7̎tj$\R)U2%1VP$j_Y"ٓ=᣸{npF.iTw2efy\[XN8R)Gfi-Κz2v5XiY:G{ r9ħnjj6ZKf.<@gm~4oo?bF_ Y՜|?ѧ+?Occ##W%R)ZUJܩhZs*.l?!diW&%#: Of8 ujUJmM#:rRj3ghw%1d8URRjb!?+dd.7-yO`T"vyg[T~b1дڶ`oڼn Ӆsė$Stk}mtyi)Hb~Ǯ4F@:wSTv{ZV3sdk[Fə2?0aV W﻾HP(&ۨDeFFFFG=`yR[KTɎ!t'a$jX#3B*%$##,(J9&3O0V~"g?x_iff~߭[`#Ҳ,po[fӕQ_ZQKh#k(cNٰVeI "TϼIqSi.VZT4LOC(pq*RKϨJǟTZƩSK%6N4x?stg6k%J*u~4;"ٵ:+/h֟S2- 4,f<|ڭUCIK"n:-x9H%U4wU*A6I .e*ÿ|ʹ:2=Eu!M!sf@iϭQ"BTm?U$oI(|D|E*4}FfHcqOiKQ5(iiJ!ojj})jCo:bwR4$ғ=Œ#JI%$$e*ohn{-̎I%S8a-{K\F2/W'Fo jLh.XD*sJ[\j3Jau4͚/[|ʹ:2=_2Nl;.lz}wSH\٢;̫#VΑo[*E2A7R=ꖣ#\Ij#-&T䱔!Ť@ *S ?pY՜|?ѧ}[{~oVE? oo֭JȰ~e[m!Z3v:2#>]\dY5%k)܎ۺǴȍfEL֟/LѤS]R*GCym $=.D~0/E ˆʧק3SmʼtQGI_p ?sP%RBST}l2KX4 JPcNzK=V-<6`H[}5O{kQ|#*{M>qf߶ݩcąW8`zCDҥ#QO==Vn$c#, F7P(a)u&g(h@7@a4Ʒ)}=GPJ/=RފMi<""""F_䘲F&iV~"g?x_i S ?p #Ҳ,}[{~oVEEZӷ믡 Q.>T/LJ,X7 eI%)/q NidwDY n#L!\=hyU'CsPi6ҡƷJA-J4)Zdx<|=MimP$%D\#mƍLYk{~d9Mfi3[{?>w:姽~0ToΩyi@ߨjS ?p?H&3;Zxu0l2MM!!$Ϙ"h̡5F)q+FB ~@6H{?w?}!d7}#E6H{ H#m􇽑`#}#Cw?}!dXH#m􇽐6H{?w?}!d7}#E6H{ H#m􇽑`#}#Cw?}!dXH#m􇽐6H{?w?}!d7}#E6H{ H#m􇽑`#}#Cw?}!dXH#m􇽐6H{?w?}!ddhUb)~q[)(&ij"=!Xϑ'Gv>T6T=/QBDi?۪E.H[r⭶FxJyqrՙTB*aq-ҥjr^qDF,Ң.,렩ާͮӪ.XkTe.0MiuԅTn;>RLr =tN~V~_ur$JR2j$KI)x2'ik&i""IK8,ڥU)"M^/SfDwTђ]KJk:D`h t%r5D\eo|Ȳj<ٍLnLy0&Eɶ*2di3z ʮkSgT!:R ZCJ7L$D^Ȉq-*!5IѪju)ns˧\:J $>sɀ˹kB)o",%0ˈmכmnlBT#W\cJQޕ-眀Pi5)G""qaO](MsLGf< G#3,3K-U,}?hW.;~V_KtT25{<(\m)f;׭jj#,둒|8]KZjIqJL&ZWW?>"Tca$gT̈2ښҘ!$imk,8,NDNWyFW%Cq!;gE\zŞ]GBM6ܺov}UtH1V)a$д+'u, tI4]24jT]B$J&EﱌbDC. q֟Pnu$SESfIkHM2) &\eQ!6jd2Q#"]mN&G9~ZDv~ B2ʤf) -ZؔD{8bFj]Z6ʙ~ᑾRaj%fOV$#|˞Hz4{C9sFh;*Ka*IJ6ӰiF֗JyJ5+?Oc-Z+"(&1:Hc9(41I6 oIqՒR_Ɨ|tO,@HՉS=JL *&]J~|rGe6V ’##dpQZPZ R(33m~4oo?bF_ yK.|7G2'IRAN'imµ$Ñ:>M.[(SM;)[:үtht֩s 7Ӟ沒Qj-U[#mRE6&[T}KYC-! 3LffgNY3r-aU7PqHܐ)&xVߵm-wMvo܇%[R $mp^ %4Y% i4j~)sb]KrWOf !vSS(tIH-<゚-oQ=ED%fKèÈVY4){Xd 4rω2T; YyGUa&7TKGWm.Gܙe[NEݞdUZ]:Aw6}*e֤9Qdky4PbFv,K:l5-F,Y=>NRltUz*O%6TҲ‰RD~3!ZbZ7/s5`|dDLLf*\σQJ%gZ>vKSoBݘcqKFSYX>SSG}Y>7 T21V6h߸$Ő70@J9&3O0V~"g?x_iff~߭[`#Ҳ,xTiJhdQ[T:rb^[ypdx6J*rIuiYi A9e Ti"P6%6॓k61ѤjVGeV]6UƣSE*,6ty"Q$w{@@#{1.jĸ>{@Kgd71.jI{j!γnijY Vfx # J'T2Ry/:eoqܪ f|IfBTfr k{~YF&G۶)4ZôLy2NUpĨ\F${mQy0S6YK\$#WsW&T{VT5*M&SjL5%ſnUe\WDȯv:bbMFhj2#V)G3=6CҕwH]>FN 5$w5齬fn6v\s;U]F{!m>wtqj_ -Wv >Go=CޝŪ|.;Ӻ8^؀mF{#zwONzbCnGo=쏝?ZWC;U]F{!m>wtqj_ -Wv 8={HtT(e #ʕ5T#"3:kuLkHvDMU'K"ǘiWtsT2_S%ʂenT(ovG6J|p owGJ$0]Zj4wIFr\ŸӏH'JFhQqrCѬ;MHjW!DH^ )JTf$)NyqzwOw}#G"HBB{d^I`uӺ8^؎Z OQSUM-Tz%?齤c, lx{*^wNѲԽ'u26*mˣg^z^'YizP՗ȚuL}_֣膫MD*۵%ڶ{4}į[Ըu&N\G8L%/<^a-r.ਝJ4 .l$tHk&Dj#"Q(^%ZT*vsRmF- ,)J\X񯛝 w]&d$Cw$.kk'4^.qU)T*2n=usM"g%89ŢԖu5TMLBFt"x޷UPms%Ž 䑑deY1?O>qǯִ-sˎ)GIժg"hT&ffm*6wKONXwf(>+ټإtTzv;KONXwf(>+ټإtTzv;KONXwf(>+ټإtTzv;KONXwf(>+ټإtTzv;KONXwf(>+ټإtTzv;KONXwf(>+ټإtTzv;KONXwf(>+ټإtTzv;KONXwf(>+ټإtTzv;KONXwf(>+ټإtTzv;KONXwf(>+ټإtTzrl9]ό]QI-bKh]ze.Tfꒇj2IgY!;ՓsH7J$ɴvadhΟL69}6N$ųr6jZ. f bLpn"jH̋+V0fg˝zݝV+Tm.=Ԓ]ZKi5' #۴hQԶ(>|4%ɍ ,$)dEGU;m>$UD1$^t7Rs$n &NE7>gjlǃ jI$9O27 zoKq8D+r4Q]J+mD(#O\!(qI UDx"yFeA3xذlDR˰Ia'StВjţȺJ Դ*t΢Ik-[vi=޼FXmT܎鶽E:D%*7If[2yMԑQx@r$袅6:>!{ݪ:FcAV})z'yRԝFσl_B]^Ӥǒ{RJTdK%%Xd~fiCM*Q초lkXRk)X-RQopFu}rD:ԘKud൏i1=f۳m|T5:TqY6Fl$ #mƍLYk{~d4?Oc-Z+"6h߸$Ő70@ 5j5*>L';Lozt@sLozøWJS ?pUKZM+JI j22GE)$$`}"ėڕJuT}y/< k \e{A??^/dWZ{!`#̯s"Ae{A??^/dWZ{!`#̯s"Ae{A??^/dWZ{!`#̯s"Ae{A??^/dWZ{!`#̯s"Ae{A??^/dWZ{!`#̯s"Ae{A??^/dWZ{!`#̯s"Ae{A??^/d7L)*FѼ'M)"$$cwirc-2.0.0.orig/schematics/cw_oscillator.jpg0000644000175000017500000006166007712325061017554 0ustar pg4ipg4iJFIFddC   %# , #&')*)-0-(0%()(C   ((((((((((((((((((((((((((((((((((((((((((((((((((("b !17AQVu"25Saqs34Tt#6BWr$RUbvC%'8DEd&ce ?RM]bsYԙ2B,M=QQN]-uTstռCѷnTt(M̗dkoԧ-L ?/ G;"GdJ]^}13tMdj]EP(fjhU_5]bY";޷nMɬJrSMS-3;+x 廷+O.@Ca!P~Y3VMӭ6𧃬aN 7rZKvaG,E"9Dw ipڻOi4(ٟq25MeMxg5ۂg9btGGӵRPNuXH3YXddңUX9<(st08$f tOXѨúmuƗZ݊sĒĝ"jZnqOI|wG}Uvw>(,wW=\>~/C]WWjL=bW Z 2]tF7wEDFxw]ëw%>>v̽tS|n kۥVvzgܕ6_StޔӒ+,KMOr/^0ҫKIcOۦ̶EMOZprﲢQ~ F~۷[$$E;gum0>K㱯pD9DFG˱ ;cX*;xbDMrHOuѹsXM8H۴)w9/59i=wĉWꝲn Qgk4&;bl5X<;moi"cHDڏG97kU;ʻȽ{FH<Ը`]fb$j]GOz?9B:,Y,ȩ Q7w6Dn;W|-|G#];mӿ:@ ۤz-aR6)jϏ|fMEN1}Q9_>ѫeoWG ZQ;wE,ԛ~&WBj;_dץW:7n9Tb.ܓQ g:0Mg[>wNWCn›kUWto]s8ي]'+g5lUbx®G;vyE]ҧʘi\U.8,{׶MaY-c1fc1ہbtn[[ܼ uE 'F͆l0 Y,ErwD}UO@zoOWVЇ!^۩̿&܋n98ȨbʯT]v]ΞOaר>>tK*ƛTۑ0ԘQW챮G,vKsR>8dl24ǽ*"IꕟN|@/}[t`ҭ[mx.Uw~?Ef¤ˉjAb$uuS޻g"˺^2j:F~ŢK]IՂndF=xSo@ #Zh=IIKb6Z?F5"wQ}v'IZ3աlVi٭$k8x#WgDDN{o05?G:-sڕhjLcB'Ϩu>vM]vkM? [fUW#ZDwc~OtNF>:PҚ*%kSb#Uwߟ2}yTS3iƬGʀW?9W512U';F#SRxU $ljDuG{y8/-C[œ17)HNOAfԬWGkRԪ.c{d9TTP<)Js]k0ԆNkUJcSw.țY"V/oXS+T{ xDz*>!^¿OWppGS+T{ xDz*>!^¿OWppGS+T{ xgW5zKBƆWoo@J;.H}ފOWp-]A5ϳ8#V U|B["=j|_EZ+8WŸ#V U|B["=j|_EZ+8WŸ#V U|B[3OHܳm ~De% #g'7sϿV :#V U|B["=j|_EZ+8WŸ#V U|B["=j|_EZ+8WŸ#V U|B[3=S)ϡ/xϋ#U|Byj:߽-@U|B=j|_EZ+8WV nU|B=j|_EZ+8WV nU|B=j|_EZ+8WV nU|B=j|_EZ+8WV nU|BUjh+ x8z)cukl>xkISvG%k8ܛ[x CT׎^V"Uj<O8SR`(zU _ ϵlxzV*-G$dc2".<'zaZG7w憤4<0K*K/>#\5"2}OFGƹQK]:d=)־FZrH;ڼ׽e5%{x*1,nYkvtHjpn]ߘEZ+8WV eQaI\Nr"*Q9"Ǵ w$°e\ȪYݻ%ۨNM&B{R"9/MӅ9נqq:/brJ=q5fTUM VڪƱz67V U|B["=j|_EZ+8WŸ#V U|B["=j|_fvrx|"hG9Uwb*Ȫ2@"V/oXZ]+{7,VٜZz?t5^wDtYSP][~T~Ej:߽-HW'Brn+I^1V9k6:8KZ7go6eoS=xRے >ۜ 'w~qi|(f*1>F4N%b7yyw 6bȩͭvH R#Ƣ"{USoRКeiwg5ρkR&waZKS]\9Z)*oUd<[Un VDZ]+{7,-Hjy dCvhڕ;+W=h?g55:@~:ҥ}Ib+%z&@:":,.d-}t/{(ZZN~ PIb|nDTsUn mZ=nڎudbHWZsr#zTDD ;nKqH?yUn VD[FC8WJ|K R+ob>_Zך]7ԨVj1DFr1ɾ//JEIG:_ax^Fu"7UϋmnwrC+{eETTQ|(>-&5gAS~}ې>SOy5 T~26+dbMtɶ"HrG^ -]'lzGٚć^>=nT4/J }{I:O#tW9UU>Z7 JF dW/ewgc\UTFrD y:Gre,ûclh׫bI詳~i9(2kGe6t+=S'Y_IYR4s$W[0Ƒķb|"l" ?PiHXvfm*v6/ii.C9 ؍b/ Q?I8U\ Fr*m_xzG7 {>ZݥTK9M 4HsZc("M^TUJNT׮'?12I;s~5j/H_\?vܯ.5կ|D_" ӶǜK"Y 7.ȭO#aq3HD.kQӼ{{VE Gh/m#aqvh Z@2+ ^ەƽڵ/kD_vܯ.;A{nWj"կ|D! rH_\kݫ_";VE Gh/m#aqvh Z@?>gwїu@ǭΫMȩ#Fd)vܯ.5-VkClDvNj{;VE Gh/m2Xʓd{j͂$.ɺSZCAz61WVg# ,jz/Z9=TE戆5WG ,NG, Q2(\^͗.g7hmCo5u \<5X* ,cdUwٻ&NtoÀ݂%FnG{Ɗ?C֑׍=b6sWt_f71brSɝibUUhɺ~Dcjb1c^ (f=>Ci/>YyyK@2@R*v+}p-@WJ|Kh?gVٜZ|Y ?X׮'?22wrVyBd1O47/3iO ݣ! h"why'[ؼiajEt^ߴ PhBI<5"'[?,EtZ[5tblruTݮENJv=.Ww~=1Uf?,p.Ww~^'ߛ!w|]WG˪^'ߛ!Ex~lu_ozc.' Ex~lK~^Sn77o;+??k}hԙ[4*1ʊ|"<ɨ$h~"'LSY쎦*Snv(ѭU;uж)ηdMl Wօ}cW;*s]~%+a1TGeC.Qnգݕw^'#S""""l<~ϥbho?E^g6*v+}rԊݣ! h P+ob>_ҷx/~-@>LB'b+@{܍W*"{@ÕTDNRjƴB+ՠLw̓+cw]櫶5i4쉭Rd򅟬bho?E^gk1O47/3hX[FC9jEVѐoNҷx/~Ԋ[ؼi`˕*#x_5SϨkOfqcTiz¯U9Gq"+{o̥ԙ6poo'v|W9vWv!GŃbtnE_Xy-Hb}s6NtsS7jV.SҶ;J*d%x "W75:;.a]}xg-o"Zw9 A~]Nwd>d򅟬bho?E^gk1O47/3hX[FC9jEVѐoNҷx/~Ԋ[ؼi`"wtM>Ԋ=uϳw9 A~]Nwd>d򅟬z*%dQ[j~=;UNJ_ )4m'7G5wE'kzZȈ~d/kK;]DۘȼdzI!kZPmP;U}cc̒V=ҵ/!Uzs4Gؾzx3܊3;ZDjvTN{@o7!OO֑V3#z{w`fho//sݕ\I2#lp=#zzGGYӠd{4^rw׍}I7KI~ ?r\ryxA:_ i?O #EwrWm֋l  eU3H^ū˶r9~j C7HᴾJ|~C+ycY! 5vn@?9zSt&ǗFxLҐ>2m}x'>| Ci/>YyyK@2@R*v+}p-@WJ|Kl~lק_}$F7}_q67!S'Qb]ʨ"r9_4>gq-ԎH;vvDw>K9˝ĥy,.J`&;3xZ*\R*"SQcfb^Z-M5g|ft\;SގݾF&ByݐDTZ.ޱ=J䯤t5̊iW=@(oJI|2Ց$X*z"ZOu %d,NFT 5lc.%25$cj mNQ7*:]G,Q65T숀}=7;+׼2KUsUUNCݪtqgr=QleLlG.ɾۺȨmпн3kLޗյk`2teX܉¨_p<Ӛ_,ri0VD߄kʉԈW`)zBX]dmJ\/A^z2ѧKјm1jXB6znW*ȭ着Ztr|8kQbS!w]Y+6.Uȋ)_HڿL^GƋbj}KN`fp=$G&:+6n DNU7TDeD]Qy)@i:PVt1ff:.rvW֮Yd*I^tQ܇=Jʜ]Qk>SFtCNjtupwbGǖtUQS&"#eOЛ7C\/fP{5Ȝ/z#M +HDZDqS֥g+w3Ak5{s]FyWjf°+Smt7UObho?E^gk1O47/3hXTڋ d+5߰wۋ_C݊PKt-2X8v+Wg"쨨t',ךnh"G"wmjxz춄[\lck+l=cTn#'5+SRD=J}gdV<ٱ3fbe{&Y$z' *".׹Nݣ! h"why'zޔk%923ixX|/8x$XD 9c1+M׉m䅯߇\ꈪ#3v;lK1طew#{ r=#Vpq^>/ׇUnCZ%| %gTE)cc\ڻpmystf7r'],TYխXڊ^K0j.@m:NsZD^KS:v:z5$XZ|~ڨ=6r *u/Qړ14.z9jud[=_ jq*횼K 2z#IbTƤd};cm%G%#jrH#j;wr5W*ji|e|LsF(YadO5Ȋ]+{7,-HjrumzW3FZi HbssS;c3NZ=cdUY 6&+EN&lKշ-8V^fӹm%5ytlrU=JVȨ^ijK5Ț{;QQ?GZ-W֙-?,oGDTv6&JFUs\ܕhC5nX'FuҵK29USusc\)S*ZEr{tҹJz֣Msʻ1n"GMzU*J#oT?{Bѣd򅟬k;+Q'frBPyV{;{-{DvgO/c'.pC^b?ћAxsFiΏo۹fE'lM~\Dk4 b>Sz.TߧszO%B6K7^(*ʱhW+x7NWnw~:;+6r RF?͘߿}Bl}(jQ:aj28o X"Un VD[FC89߸bl#H k+:`gV<.Zx偶qad6$z5DUʧTgeLҷx/~Ԋ[ؼi`"wtM>κK%6ٯVo[,Duvp_6?[4k]Lu1N.d}jj{ 0M챶N;_to|;z@c<͏hp_6?ސ :RW[s|GW4L~Yy7~wɠMu_ozc.'$h<%@<<]WG˪}?+;I_=1Uf?,yOJ&W4L~YċO#JLf r3.ҵvD׬M)Uf3 wQvtrL~Y+؆V#z%C9\"cX&&h?gVٜZ/ҟsmOxqzSm?SUzn'?22wrVyB5뿉n ̝ܕPuHb=dKO;}~>\u8cZM(kSD֬`sp1yb.tXs"E^{Ms^j}/UR՘٭RijgJ޶9<<өvԺ{C9J;ux'SCiMҍ0XV}EUsM{UQ<OS ZcNV7&ʛsDE$*c~$zgX3|e,@Z*t%ݴz}QM*"Ȇ'gPՌԏvOXbECZEVѐoNZUd<[jfI0EGy;{$DlOiYH="Qۢ{^ZZqشYjlw^&Ҕ z9_.ļUP"zGu-1vhc&AݒvQ6庢둧Gs15F>/K5p>Ęgj+_wEMۚL] ӂG G5v䧫 ભl5 `Wq+ _ ֠EdQ;j>v:}Gtpw1Y*ֺ4ٝlnXv9YG󸾱1U7\Jb͗Ɲ=;$OK ߒxnZd#ᬻ{R= [M۶c㢩ysNOO3i`njIk\nVջoG/Mia5{-t/7a{%cTkUDc6UN"Ekt})`5W=U(ΰRRvzU[V7a?}e-%]Zw<]_ȴv?};7S(ܽjcFT#cD^Zwb+_A?[ؼiajEt^ߴ S_5Tb|4`PZ&kfqjEj}Ũ_~wKePؤVH'&2nzDN ܑFVݎ{&]"/Hi/(v^"_Qj"EkzEI~cEܽ"vTݏd)#~߱5n ̝ܕP֚,^Pm="dw%SyNp8ϒ'uDF:UDMj""'ԽiMM;vGdWoI}ӡJTF mOS ZxX_<,~OCzZ`6nRĎw)b3W)Æz݃dk7sUw_R"~V5EV2:Xj1$݉\'Vj2{Z:YV,tJl+ &FGwH+vujؒ.1ŒʐFǻtFsGlh=U&K5aZD^k#o7ޔ/v>H-X޸aDif9nlWHZ*!ֵ"'GB"MK"UUbzr=iGKD@ZUd<[Un VDZgeLgeLf>_-~Cs4yk^=-qXemڭU}J*Eߨ +_&!?GWWXXbq9tkSªr0}:j=bڮG笿+U"k[7?=莜VոM ='lRY^˴HCoWrkF.%I6׺W gD?d򅟬k;+WԶ'oI2j~Viz?OZh̫$Ȍ+뚉}SeN| kV㑪ZlM ϦF]֊tsYUUq8;yStWDʰ&꨻5_Рkj5֢#Q6DN"kO!?=kO!?fRl^:U+FeQWMvN}DzQҎj9+U7EL]OղMAz2I2eX.Fsi8?a1P L+U,Z}_W6l'nc֛) XȒ=jUT]&My*O銡_EVM&'SZ!);/}V4D[FC9jEVѐoNf{Q/tf{Q/tic=,66C)f*jIdv>|ic=ZMaE6TюV?"Wò/0#tj,ZZZ'$R"Kj[ ֍V]*unqc.W^jȝNbT'ҳE+|wSAyoMVK^s#HTjsL4޳lpfUqE'>n΋4S'f+$н$OݎNE䥪&ȈHFp6c%6'v뺽{\wۗ1ZCUhOq5*ƛ2(p-cS$uf/fO]ҁd kZ{\rg133aI[6;=U.[h|M Ab&jTNI BOG Җj Hf,Td~& Tn%G{}riTlg-FlAO0zJ/zqW%X{;J.UQ{/htêr^?0'~2/JVOzߡ9NfŻ .Yl+)DױbS.߼5N%٬$╰̯X5ݩqYyyK@ \RK{QVjZlT_qb]OiDžIUFѷ;OʙN>{pޤj;pțyWu|=3|e,:F5I[*.+/Ѱ;(wƭ%otwUA4l{Uj\v'i&IdruV*WF_geyqΑpb&bۧeOlI;u֜IkX'"o*^h^yOb IXڬFnsy?Ō?vUnܹ >,dDvgz(RJE^IQ5֧:xh2"n"'?0?8 IrFږn ֪9ۢsCzzxe?=U_m O)ꯒA W1?O gKS3_%<2ឪ/OU|` gOW_nJS:Mk18omԻ/=ޞOU|~뺗t~S3_%)ꯒClb~OU|O gK xe?=U_=<2ឪ/6' W#5Vk-_Ye,aUo 9mh<,~Oy?'WGۣLnBO)bGt; AiֵҮS۔[V?4}?^Vc+rZS2G QzQ=^7Z_+S≬vE舞hGW|J! r梎ϚL\ѻGuvyk2V֪ʪF;DԎC Xh:#^ɸ_jzlDV4Dt:=KqKuRN_Xx_}R{C;/}jEVѐoNZUd<[j4zoVwY} b]uH$dIDUjr*5%KPe)ѯ Z۰vs^ f!iٱm\ԎEbV'}[yVcSh 3b3Pݏ݋T%V¬s#QdFγZ*QWXjGqZ6Y:^/YYG󸾱+55?Yj wMO,z㦧xZ3%)U5f֬7fܦzo:mI wMO,b={Qla6M3܊T]QO> M wMO,i-9j,ڷ%~ 9SZ~i'-H9SZ~i'%:ZNzlrE^ Os6rbf6'FVj'_UU G8ƢzX T_]5Wn6z*sM€B7\gr10݋Ν{ρ}Yn]j7j>?h2]i٤zuU7VN$jCv"\kQ9%TOn=K3 g 7Gz$; W Aam".v>(ݿݛխAWHi{ ]E.a#a챢#6EF9oEzEضfJlKѵwFX#=*Ud<[Un VDZgeLgeLҷx/~Ԋ[ؼi`"wtM>Ԋ4\3P"u/yR+wR.לxX_<,~OCYK;x_+NwT֟cR+NwT֟c>nꛧ4w3Щa5tR5咴rTj.nCccYe]nq"I9͎Ӻ^S}r'[yNrٙrH,:5bvLnDETr5UO l ~{t_+q6cQN$Drlz9KtTLc܎45;*'ݕO Un VD[FC89I#v*'Glt6l03:^Mt6l06<-(DltnG7Y芝KP[ؼiajEt^ߴ P02u+ZZkkQTvj*TOΟfcM7Bv̘رdY9z'^ɹu{L_~2c~Tzfh1*UA{L_~2c~Tzfh1*UA{L_~2c~Tzfh1*UA{L_~2c~Tzfh1*UA{L_~2c~Tzfh1*UA{L_~2c~Tzfh1*UA{L_~2c~Tzfh1*UA{L_~2c~Tzfh1*UA{L_ZJGv~[Rlu8d.s_2|)ğ~2c~Th=/")院d~2c~Th=/")院d~2c~Th=/")院d~2c~Th=/")院d~2c~Th=/")院d~2c~Th=/")院d~2c~Th=/")院d~2c~Th=/")院d~2c~Th=/")院d~2c~Th=/")院d7Iz1aRcUUݭv@2z@Ҙ/gf(x_^%B3EɍR"փbf3EɍR"փbf3EɍR"փbf3EɍR"փbf7Ae)fB9M}zx\ԛ|)o{{L_8dilkS *v+}rԊݣ! h P+ob>_%tYaIH]oaWP/}'Ĩ%,vcM՛i=r4Yqֹ+bH!2GXne"U=)+ͩ'ucM1UENEeZŃ:kJщΥ*Seԝ|W"סo!, &/bs+ZčN"/U|=/oD',_ƴ>oAi1̺nqy"nHuO&w .Lvjbf1( /R9*i]=CKb;Ney_G.^4Q$dr,t=/ĉkVr9sRG"uoЙ k)qMbV#ӱ#grkSrky'>&GYqk{"29^]KpQOj)-=U`Պl"f* ;^GwK$VFhլll]܈sN/5lcS>J.ܭ|tVȫUr/ YvNnu]ԚL|'j1kI1Qx퓙N4S8~::x>KU*Zz#R]~{lhM"why'-H2@&RV%bVđ{|յ!}lI=DsU#ۍwN\M:WJrȤMK'}X+?[PdUZBi,588m?nnm~2O-8$ ksdF;nh7ò5=\骹 TL@nĺ?=R51w!%K+3r lǣeIP1o(F\~\xGQO7I+sli&jkJ࿑ ˭d5$ѴZTErfvO݈>le( |pM+z*]:zFzs;0W~NV%W0i`zV9ZEM*sEP?uljt~{O8[Xn$bh6sG#{,dI:N[q]Cq]GDž|> VU{ n˷jW45jo&p??cwirc-2.0.0.orig/cwdecoder.c0000644000175000017500000002431610433703560014161 0ustar pg4ipg4i/* CWirc - X-Chat plugin for sending and receiving raw morse code over IRC (c) Pierre-Philippe Coupard - 18/06/2003 Morse decoder This program is distributed under the terms of the GNU General Public License See the COPYING file for details */ #include #include #include "types.h" #include "cwdecoder.h" #include "morsecodes.h" #include "cwirc.h" /* Definitions */ #define CW_BUF_MAX_SIZE CW_SEQUENCE_MAX+2 /* Max. dits or dahs we buffer*/ #define DECODER_INERTIA 4 /* How slowly the decoder adapts to a new keying speed */ /* Global variables */ struct cwcodeset cwirc_cw_table[NB_CW_CODE_SETS]=MORSE_CODES; /* Prototypes */ static void decode_morse_code(T_BOOL key,double ticklen,int cwcodeset, T_BOOL reset_decoder); static void decode_dot_code(T_BOOL key,double ticklen,int cwcodeset, T_BOOL reset_decoder); static char *decode_cw_sequence(int cwcodeset,char *cwbuf,char *decoded_char); static void insert_character_in_decoder_buffer(char *c,T_BOOL delete_spaces); /* Functions */ void cwirc_decode_cw(T_BOOL key,double ticklen,int cwcodeset) { /* Is the decoder disabled ? */ if(cwirc_cw_table[sharedmem->cwcodeset].cwcodetype==NOCODE) if(sharedmem->decoded_msg_wpm!=WPM_DECODER_DISABLED) sharedmem->reset_decoder=1; else return; else if(sharedmem->decoded_msg_wpm==WPM_DECODER_DISABLED) sharedmem->decoded_msg_wpm=WPM_UNKNOWN_WPM; /* Have we been asked to reset the decoder ? */ if(sharedmem->reset_decoder) { decode_morse_code(key,ticklen,cwcodeset,1); decode_dot_code(key,ticklen,cwcodeset,1); sharedmem->decoded_msg_buf[0]=0; sharedmem->decoded_msg_buf_char_markers[0]=0; sharedmem->decoded_msg_wpm=cwirc_cw_table[sharedmem->cwcodeset].cwcodetype ==NOCODE?WPM_DECODER_DISABLED:WPM_UNKNOWN_WPM; sharedmem->decoded_msg_updated=1; sharedmem->reset_decoder=0; } /* Is the chosen code set in Morse code ? */ if(cwirc_cw_table[cwcodeset].cwcodetype==MORSE) { decode_morse_code(key,ticklen,cwcodeset,0); return; } /* Is the chosen code set in DOT code ? */ if(cwirc_cw_table[cwcodeset].cwcodetype==DOT) { decode_dot_code(key,ticklen,cwcodeset,0); return; } } /* Decode international Morse code */ void decode_morse_code(T_BOOL key,double ticklen,int cwcodeset, T_BOOL reset_decoder) { static double evtlen=0; static double beeplenprev=0,lastshortbeeplen=0,lastlongbeeplen=0; static double lastbeep_too_short_by=0; /* in ms */ static double ditlen=0; static T_BOOL keyprev=0; static char cwbuf[CW_BUF_MAX_SIZE]=""; static T_BOOL wait_for_end_of_word=0; static char newbeep=0; char decoded_char[CW_SYMBOL_MAX+1]=""; int i; /* Should we reset the decoder's internal states? */ if(reset_decoder) { evtlen=0; beeplenprev=0; lastshortbeeplen=0; lastlongbeeplen=0; lastbeep_too_short_by=0; ditlen=0; keyprev=0; cwbuf[0]=0; wait_for_end_of_word=0; newbeep=0; decoded_char[0]=0; return; } /* Did the key change state ? */ if(key!=keyprev) { wait_for_end_of_word=0; if(!key) /* Was the key released ? */ { if(evtlenbeeplenprev*2) newbeep='-'; if((i=strlen(cwbuf))evtlen?ditlen-evtlen:0; else lastbeep_too_short_by=ditlen*3>evtlen?ditlen*3-evtlen:0; beeplenprev=evtlen; } evtlen=0; } /* If the key has been released for over a dit length * 2, decode the character. Allow for timing imprecision if the last beep was too short */ if(!key && !keyprev && (evtlen-lastbeep_too_short_by)>ditlen*2 && cwbuf[0]) { /* Decode the cw character */ decode_cw_sequence(cwcodeset,cwbuf,decoded_char); /* Empty the buffer */ cwbuf[0]=0; wait_for_end_of_word=1; } /* If the key has been released for over a dit length * 4, send a space. Allow for timing imprecision if the last beep was too short */ if((evtlen-lastbeep_too_short_by)>ditlen*4 && wait_for_end_of_word) { strcpy(decoded_char," "); wait_for_end_of_word=0; } /* Is there a new decoded character ? */ if(decoded_char[0]) { /* Add the character in the buffer, or remove the last character */ insert_character_in_decoder_buffer(decoded_char,1); decoded_char[0]=0; /* Report the current decoder's speed */ if(ditlen>0) sharedmem->decoded_msg_wpm=1200/ditlen; else sharedmem->decoded_msg_wpm=WPM_UNKNOWN_WPM; /* Assert this for the display routine */ sharedmem->decoded_msg_updated=1; } keyprev=key; evtlen+=ticklen; } /* Decode DOT code */ void decode_dot_code(T_BOOL key,double ticklen,int cwcodeset, T_BOOL reset_decoder) { static double evtlen=0; static double ditlen=0; static T_BOOL keyprev=0; static int dotcount=0; static char cwbuf[CW_BUF_MAX_SIZE]=""; char decoded_char[CW_SYMBOL_MAX+1]=""; int i; /* Should we reset the decoder's internal states? */ if(reset_decoder) { evtlen=0; ditlen=0; keyprev=0; dotcount=0; cwbuf[0]=0; decoded_char[0]=0; return; } /* Did the key change state ? */ if(key!=keyprev) { if(!key) /* Was the key released ? */ { if(dotcount<9) dotcount++; /* Count dots in the current character element */ /* Progressively deviate the "official" dit length toward the last short beep length, so the decoder isn't thrown off track immediately when the operator made a temporary timing mistake */ ditlen=(ditlen*(DECODER_INERTIA-1)+evtlen)/DECODER_INERTIA; } evtlen=0; } /* If the key has been released for over a dit length * 2 and there were dots counted, add the current character element to the buffer. */ if(!key && !keyprev && evtlen>ditlen*2 && dotcount && (i=strlen(cwbuf))ditlen*5 && cwbuf[0]) { /* Decode the cw character */ decode_cw_sequence(cwcodeset,cwbuf,decoded_char); /* Empty the buffer */ cwbuf[0]=0; } /* Is there a new decoded character ? */ if(decoded_char[0]) { /* Add the character in the buffer, or remove the last character */ insert_character_in_decoder_buffer(decoded_char,0); decoded_char[0]=0; /* Report the current decoder's speed */ if(ditlen>0) sharedmem->decoded_msg_wpm=600/ditlen; /* Calculated on the basis of 100 dits per PARIS word in DOT code */ else sharedmem->decoded_msg_wpm=WPM_UNKNOWN_WPM; /* Assert this for the display routine */ sharedmem->decoded_msg_updated=1; } keyprev=key; evtlen+=ticklen; } /* Find a CW sequence in the right table and return it */ static char *decode_cw_sequence(int cwcodeset,char *cwbuf,char *decoded_char) { int i; /* Look for a matching sequence */ for(i=0;cwirc_cw_table[cwcodeset].cwcode[i].sequence[0] && strcmp(cwbuf,cwirc_cw_table[cwcodeset].cwcode[i].sequence);i++); /* Did we find a sequence ? */ if(cwirc_cw_table[cwcodeset].cwcode[i].sequence[0]) strcpy(decoded_char,cwirc_cw_table[cwcodeset].cwcode[i].symbol); else { /* Is it a continuous stream of dits ? */ if(strchr(cwbuf,'-')==NULL) strcpy(decoded_char,"\b"); /* It's an "error" morse code */ else strcpy(decoded_char,UNKNOWN_CHARACTER_SIGN);/* We don't know what it is */ } return(decoded_char); } /* Insert a decoded character in the decoder buffer, or remove the last one if the character is a backspace */ static void insert_character_in_decoder_buffer(char *c,T_BOOL delete_spaces) { int i,j,k; k=strlen(sharedmem->decoded_msg_buf); /* Is the character a BACKSPACE ? */ if(c[0]=='\b') { if(delete_spaces) { /* Zap the last spaces in the decoded message line */ while(k && sharedmem->decoded_msg_buf[k-1]==' ') { sharedmem->decoded_msg_buf[--k]=0; sharedmem->decoded_msg_buf_char_markers[k]=0; } } /* Zap the last character in the decoded message line */ while(k && sharedmem->decoded_msg_buf_char_markers[k-1]==' ') { sharedmem->decoded_msg_buf[--k]=0; sharedmem->decoded_msg_buf_char_markers[k]=0; } if(k) { sharedmem->decoded_msg_buf[--k]=0; sharedmem->decoded_msg_buf_char_markers[k]=0; } } else { /* Do we need to make room in the decoded message buffer for the new character ? */ j=strlen(c); if(j+k>=DECODED_MSG_SIZE) { /* Find out the position of the character that'll become the new leading character of the decoded message buffer */ for(i=j+k+1-DECODED_MSG_SIZE; sharedmem->decoded_msg_buf_char_markers[i]==' ';i++); /* Shift the decoded message left accordingly */ for(k=i;sharedmem->decoded_msg_buf[k];k++) { sharedmem->decoded_msg_buf[k-i]=sharedmem->decoded_msg_buf[k]; sharedmem->decoded_msg_buf_char_markers[k-i]= sharedmem->decoded_msg_buf_char_markers[k]; } sharedmem->decoded_msg_buf[k-i]=0; sharedmem->decoded_msg_buf_char_markers[k-i]=0; } /* Append the new character in the buffer */ strcat(sharedmem->decoded_msg_buf,c); /* Append the new character's start marker in the markers buffer */ for(i=0;idecoded_msg_buf_char_markers,i?" ":"|"); } } cwirc-2.0.0.orig/cwframe.c0000644000175000017500000003751710104260247013650 0ustar pg4ipg4i/* CWirc - X-Chat plugin for sending and receiving raw morse code over IRC (c) Pierre-Philippe Coupard - 18/06/2003 CW frames encoding/decoding routines This program is distributed under the terms of the GNU General Public License See the COPYING file for details */ #include #include #include #include #include "types.h" #include "cwframe.h" #include "cwirc.h" #include "grid.h" #include "propagation.h" #include "io.h" #include "ipc.h" /* Prototypes */ static void rot46_enc_dec(char *msg); static int decoded_number_basefmt(char **buf); static int decoded_number_xfmt(char **buf); static char *encoded_number_basefmt(int number); static char *encoded_number_xfmt(int number); /* Encode a cw frame. A frame has the following format : [de=,][at= ... - The channel is a positive integer. I suggest using 1000 a general CQ channel. - Each delay is a positive or negative number. If it's positive, the sender's key is down (beeping). If it's negative, the key is up (silence). The absolute value of the number is the number of ms the event lasts The channel is always encoded in base format (2-letter block of printable characters, see below). If the format is the base format ("cw=" header), subsequent event delay values are also encoded in base format. If the format is the extended format ("cx=" header), subsequent event delay values are encoded in extended format (1- or 3-letter blocks of printable characters, see below). Return value : NULL --> the frame wasn't encoded pointer to the encoded frame */ char *cwirc_encode_cw_frame(void) { static char cwframe[3+MAX_NICK_SIZE+1+3+MAX_GRIDSQUARE_SIZE+1+3+2+ XMIT_BUF_MAX_SIZE*3+1]; char encoded_callsign[MAX_NICK_SIZE]; char encoded_gridsquare[MAX_GRIDSQUARE_SIZE]; T_BOOL send_callsign; T_BOOL send_gridsquare; char enc_evts_basefmt[XMIT_BUF_MAX_SIZE*2+1]; char enc_evts_xfmt[XMIT_BUF_MAX_SIZE*3+1]; T_U8 evts_fmt; /* 0 -> evts in base fmt, 1 --> evts in extended fmt */ int i; if(!sharedmem->xmit_buf_flush_nb_evts) return(NULL); send_callsign=sharedmem->send_callsign_with_cw && sharedmem->callsign[0]; send_gridsquare=sharedmem->send_gridsquare_with_cw &&sharedmem->gridsquare[0]; if(send_callsign) { strcpy(encoded_callsign,sharedmem->callsign); rot46_enc_dec(encoded_callsign); } if(send_gridsquare) { strcpy(encoded_gridsquare,sharedmem->gridsquare); rot46_enc_dec(encoded_gridsquare); } /* Create a list of events encoded in base format */ enc_evts_basefmt[0]=0; for(i=0;ixmit_buf_flush_nb_evts;i++) strcat(enc_evts_basefmt,encoded_number_basefmt(sharedmem->xmit_buf[i])); /* Create a list of events encoded in extended format */ enc_evts_xfmt[0]=0; for(i=0;ixmit_buf_flush_nb_evts;i++) strcat(enc_evts_xfmt,encoded_number_xfmt(sharedmem->xmit_buf[i])); /* Use whatever format makes a shorter frame */ evts_fmt=(strlen(enc_evts_xfmt)cwchannel[sharedmem-> currcwchannel]), evts_fmt==0?enc_evts_basefmt:enc_evts_xfmt); return(cwframe); } /* Decode a cw frame and insert it in the senders table. A frame has the following format : [de=,][at= ... - The channel is a positive integer. - Each delay is a positive or negative number. If it's positive, the sender's key is down (beeping). If it's negative, the key is up (silence). The absolute value of the number is the number of ms the event lasts The channel is always encoded in base format (2-letter block of printable characters, see below). If the format is the base format ("cw=" header), subsequent event delay values are also encoded in base format. If the format is the extended format ("cx=" header), subsequent event delay values are encoded in extended format (1- or 3-letter blocks of printable characters, see below). Return value : 0 --> frame is cw frame, but not on our cw chan, or we drop it 1 --> frame is a cw frame on our channel from a new sender, and is decoded 2 --> frame is a cw frame on our channel from an already known sender and is decoded If a callsign was found in the frame, callsign points to it. Otherwise, callsign is NULL. */ int cwirc_decode_cw_frame(char *sender_name,char *frame,char **callsign) { static char decoded_callsign[MAX_NICK_SIZE]; static char decoded_gridsquare[MAX_GRIDSQUARE_SIZE]; int distance_from_receiver; /* In Km */ int i,j; char *ptr,*ptr2; int new_sender; T_U8 evts_fmt; /* 0 -> evts in base fmt, 1 --> evts in extended fmt */ new_sender=0; ptr=frame; /* Does the message start with the explicit callsign header ? */ *callsign=NULL; if(!strncmp(ptr,EXPLICIT_CALLSIGN_HEADER,strlen(EXPLICIT_CALLSIGN_HEADER))) { /* Extract and decrypt the callsign */ ptr+=strlen(EXPLICIT_CALLSIGN_HEADER); ptr2=strchr(ptr,','); i=ptr2-ptr; i=i>=MAX_NICK_SIZE?MAX_NICK_SIZE-1:i; strncpy(decoded_callsign,ptr,i); decoded_callsign[i]=0; rot46_enc_dec(decoded_callsign); if(decoded_callsign[0]) { *callsign=decoded_callsign; sender_name=decoded_callsign; } ptr=ptr2+1; } /* Is there a grid square header next ? */ decoded_gridsquare[0]=0; if(!strncmp(ptr,GRID_SQUARE_HEADER,strlen(GRID_SQUARE_HEADER))) { /* Extract and decrypt the grid square */ ptr+=strlen(GRID_SQUARE_HEADER); ptr2=strchr(ptr,','); i=ptr2-ptr; i=i>=MAX_GRIDSQUARE_SIZE?MAX_GRIDSQUARE_SIZE-1:i; strncpy(decoded_gridsquare,ptr,i); decoded_gridsquare[i]=0; rot46_enc_dec(decoded_gridsquare); ptr=ptr2+1; } /* Are events in extended format ?*/ if(ptr[1]=='w') { evts_fmt=0; ptr+=strlen(CW_FRAME_HEADER_BASEFMT); } else { evts_fmt=1; ptr+=strlen(CW_FRAME_HEADER_XFMT); } /* Is the sender on our channel ? */ if(decoded_number_basefmt(&ptr)!=sharedmem->cwchannel[sharedmem-> currcwchannel]) return(0); /* Not our channel : ignore the frame */ /* Acquire the semaphore */ if(!cwirc_sem_P(sharedmem->semid,SEM_ST)) { /* Check if we already know the sender */ for(i=0;isender[i].name);i++); /* If the sender isn't known, or is known but is currently being timed out for removal, treat it as a new sender */ if(i==MAX_SENDERS || (sharedmem->sender[i].playback_stop_timeout>0 && sharedmem->sender[i].playback_start_timeout<=0)) { new_sender=1; /* Find a free slot if the sender is new */ if(i==MAX_SENDERS) { for(i=0;isender[i].name[0];i++); if(i==MAX_SENDERS) /* No free slot : */ return(0); /* just drop the frame */ sharedmem->sender[i].playback_stop_timeout=0; } /* Initialize the slot for the sender */ for(j=0;jsender[i].kcdelay[j]=0; sharedmem->sender[i].keystate[j]=0; } sharedmem->sender[i].buf_head=0; sharedmem->sender[i].keyup_tickcnt=0; sharedmem->sender[i].keydown_tickcnt=0; sharedmem->sender[i].keystate_prev=0; strncpy(sharedmem->sender[i].name,sender_name,MAX_NICK_SIZE); sharedmem->sender[i].name[MAX_NICK_SIZE-1]=0; /* Give sender a chance to send more events before our buffer underruns */ sharedmem->sender[i].playback_start_timeout=sharedmem->recv_buffering; } /* Append the frame events to the sender's ring buffer */ j=sharedmem->sender[i].buf_head; do { if(sharedmem->sender[i].kcdelay[j]<=0) { sharedmem->sender[i].kcdelay[j]=evts_fmt==0? decoded_number_basefmt(&ptr):decoded_number_xfmt(&ptr); if(sharedmem->sender[i].kcdelay[j]>0) sharedmem->sender[i].keystate[j]=1; else { sharedmem->sender[i].keystate[j]=0; sharedmem->sender[i].kcdelay[j]=-sharedmem->sender[i].kcdelay[j]; } } if((++j)==MAX_EVT_BUFFER) j=0; } while(j!=sharedmem->sender[i].buf_head && ptr[0]); /* If the sender has sent a grid square and ours is defined too, calculate how far the sender is from us and make up a signal strength*/ if(sharedmem->gridsquare[0] && decoded_gridsquare[0]) { distance_from_receiver=cwirc_great_circle_path( sharedmem->gridsquare,decoded_gridsquare); sharedmem->sender[i].signal_strength=cwirc_determine_signal_strength( distance_from_receiver); } else sharedmem->sender[i].signal_strength=-1; /* Release the semaphore */ cwirc_sem_V(sharedmem->semid,SEM_ST); } return(new_sender?1:2); } /* Check that a string looks like a valid cw frame */ int cwirc_is_cw_frame(char *frame) { char *ptr,*ptr2; char buf[7]; T_U8 evts_fmt; /* 0 -> evts in base fmt, 1 --> evts in extended fmt */ int i,j,k; ptr=frame; /* Is there an explicit header ? */ if(!strncmp(ptr,EXPLICIT_CALLSIGN_HEADER,strlen(EXPLICIT_CALLSIGN_HEADER))) { /* Yes: can we find a ',' after the header ? */ if((ptr=strchr(ptr,','))==NULL) return(0); /* No ','. Drop the frame */ else ptr++; } /* Is there a grid square header ? */ if(!strncmp(ptr,GRID_SQUARE_HEADER,strlen(GRID_SQUARE_HEADER))) { /* Yes: can we find a ',' after the header ? */ if((ptr2=strchr(ptr,','))==NULL) return(0); /* No ','. Drop the frame */ else { ptr+=strlen(GRID_SQUARE_HEADER); /* Check that the grid square is 4 or 6 characters long */ if(ptr2-ptr!=4 && ptr2-ptr!=6) /* Invalid grid square. Drop the frame */ return(0); /* Check that the grid square is valid */ strncpy(buf,ptr,ptr2-ptr); buf[ptr2-ptr]=0; rot46_enc_dec(buf); if(!cwirc_is_grid_square(buf)) /* Invalid grid square. Drop the frame */ return(0); ptr=ptr2+1; } } /* Is there a morse frame header ? */ if(strncmp(ptr,CW_FRAME_HEADER_BASEFMT,strlen(CW_FRAME_HEADER_BASEFMT)) && strncmp(ptr,CW_FRAME_HEADER_XFMT,strlen(CW_FRAME_HEADER_XFMT))) return(0); /* Header not found. Drop the frame */ /* Are events in extended format ?*/ if(ptr[1]=='w') { evts_fmt=0; ptr+=strlen(CW_FRAME_HEADER_BASEFMT); /* Are there are least 4 chars (channel number+one delay) and is the number of chars a multiple of 2 after the morse header ? */ if(strlen(ptr)<4 || strlen(ptr)%2) return(0); /* Not a valid frame length. Drop the frame */ } else { evts_fmt=1; ptr+=strlen(CW_FRAME_HEADER_XFMT); /* Are there are least 3 chars (channel number+one delay) ? */ if(strlen(ptr)<3) return(0); /* Not a valid frame length. Drop the frame */ } /* Are the characters only composed of printable characters between '!' (33) and '~' (126) included ? */ for(i=0;i'~') return(0);/* Impossible character in an encoded delay. Drop the frame */ /* Check that all the delays following the channel number have reasonable values individually, i.e. less than 1.5x our own xmit delay and not null, and the sum of all delays is less than 1.5x our own xmit delay.*/ ptr+=2; k=0; while(k=XMIT_BUF_DELAY*1.5) return(0); /* Suspicious delay. Drop the frame */ k+=j<0?-j:j; } if(k>=XMIT_BUF_DELAY*1.5) return(0); /* Suspicious sum of delays. Drop the frame */ return(1); } /* Encrypt/decrypt a string with ROT46, using printable characters between '!' (33) and '}' (125) included, but excluding ','. Any character outside this set is silently discarded. This isn't much of an encryption, but it's good enough to scramble things so they're not too easily readable. */ static void rot46_enc_dec(char *msg) { int i,j,k; unsigned char c; k=strlen(msg); /* Remove unwanted characters from the string */ i=0; while(i'}') { for(j=i;j=','?msg[i]-1:msg[i])+46; if(c>'}'-1) c='!'+c-'}'; msg[i]=c>=','?c+1:c; } } /* Decode a signed number encoded into a string of 2 characters composed only of printable characters between '!' (33) and '~' (126) included, and do so in an endian-independant fashion. If an invalid character (including the string terminator) is encountered in the 2 characters needed, the function returns -32768 and *buf points to the offending character. If the call is successful, *buf points to the next character after the encoded number. */ static int decoded_number_basefmt(char **buf) { unsigned char c1,c2; c1=(*buf)[0]; if(c1<'!' || c1>'~') return(-32768); (*buf)++; c2=(*buf)[0]; if(c2<'!' || c2>'~') return(-32768); (*buf)++; return(((c1-'!')*94 + (c2-'!'))-4418); } /* Decode a signed number encoded into a string of 1 or 3 characters composed only of printable characters between '!' (33) and '~' (126) included, and do so in an endian-independant fashion. The format is as follow: - If a character is between '!' and '~' excluded, it directly encodes the number. - If a character is '~', the 2 characters that follow encode the number in base format fashion (see above). If an invalid character (including the string terminator) is encountered in the 1 or 3 characters needed, or if the format is invalid, the function returns -32768 and *buf points to the offending character. If the call is successful, *buf points to the next character after the encoded number. */ static int decoded_number_xfmt(char **buf) { unsigned char c1; c1=(*buf)[0]; if(c1<'!' || c1>'~') return(-32768); (*buf)++; return(c1=='~'?decoded_number_basefmt(buf):(c1-'!')-46); } /* Encode a signed number into a string of 2 characters composed only of printable characters between '!' (33) and '~' (126) included, and do so in an endian-independant fashion */ static char *encoded_number_basefmt(int number) { static char buf[3]={0,0,0}; if(number<-4418) number=-4418; if(number>4417) number=4417; number+=4418; buf[0]='!'+number/94; buf[1]='!'+number%94; return(buf); } /* Encode a signed number into a string of 1, 2 or 3 characters composed only of printable characters between '!' (33) and '~' (126) included, and do so in an endian-independant fashion. The format is as follow: - If a number is between -46 and 46 included, it encodes into a single characters. - If a number is between -92 and -47 included, or between 47 and 92 included, it is encoded into 2 characters, which, decoded and summed up, reconstitute the number. - If a number is less than -92 or greater than 92, it is encoded into 3 characters, the first one being '~' and the 2 others being the number encoded in base format (see above). */ static char *encoded_number_xfmt(int number) { static char buf[4]; if(number>=-46 && number<=46) { buf[0]='!'+number+46; buf[1]=0; return(buf); } if(number>=-92 && number<=92) { buf[0]=number<0?'!':'}'; buf[1]='!'+(number<0?number+92:number); buf[2]=0; return(buf); } buf[0]='~'; strcpy(buf+1,encoded_number_basefmt(number)); return(buf); } cwirc-2.0.0.orig/cwsound.c0000644000175000017500000001356210063136371013704 0ustar pg4ipg4i/* CWirc - X-Chat plugin for sending and receiving raw morse code over IRC (c) Pierre-Philippe Coupard - 18/06/2003 CW sound generation routines This program is distributed under the terms of the GNU General Public License See the COPYING file for details */ #include #include #include "types.h" #include "cwsound.h" #include "sounder_down.h" #include "sounder_up.h" /* Definitions */ #define SOUNDER_UP_TO_DOWN_DELAY 10 /* ms */ #define SOUNDER_DOWN_TO_UP_DELAY 60 /* ms */ #define QRN_AMPLIFICATION 2 #define QRN_CRACKLING_DURATION 2 /* ms */ #define QRN_CRACKLING_OCCUR_PROB .005 #define SQUELCH_TIMEOUT 3000 /* ms */ /* Generate a sound fragment that is "nbsamples" long at an audio frequency "freq", at an amplitude "amplitude" (between 0 and 100), in the form of a serie of samples betweem -1 and 1, at a sampling rate of "samplerate", at an offset of "offset_keyup" or "offset_keydown" sample ticks, corresponding to a morse key state that is either up or down. There are 2 types of sounds: 0 --> beep : simple sine wave at "freq" Hz that's either present or absent depending on the state of the key. 1 --> sounder clicks : 2 sounds, one is a sharp click when the key goes up and the other is a duller click when the key goes down. In this case, "freq" is ignored. Also, make sure the sound changes "softly" when the key changes state, so it doesn't make nasty clicks. Return code: 0 --> all samples are null, 1 --> sound was generated */ int generate_cw_sound_fragment(int sndtype,int keystate_prev,int keystate, int samplerate,int nbsamples,int freq,int amplitude, unsigned long long offset_keyup,unsigned long long offset_keydown, double *samplebuf) { static T_BOOL firstcall=1; static double sinetable[1000]; unsigned long long sine_i; int retcode; int i; retcode=0; switch(sndtype) { case 0: /* beeping sound */ if(keystate || keystate_prev) { /* Is it the first time we're called ? */ if(firstcall) { /* Generate the sine table. The 1000 samples contain exactly one period. All sine values are pre-divided by 100 so we can multiply by the amplitude in the sample generation code blow without having to do an extra division. */ for(i=0;i<1000;i++) sinetable[i]=sin(((double)i*M_PI*2)/1000)/100; firstcall=0; } /* Make sure the sound frequency is above 75Hz so it's always audible */ if(freq<75) freq=75; /* Generate the samples */ for(i=0;i=0) samplebuf[i]=(double)amplitude*sinetable[sine_i%1000]; else samplebuf[i]=(double)amplitude*-sinetable[(-sine_i)%1000]; /* Make the beeps fade in and out so they don't generate nasty clicks */ if(!keystate_prev) samplebuf[i]*=(double)i/(double)nbsamples; else if(!keystate) samplebuf[i]*=(double)(nbsamples-i)/(double)nbsamples; if(samplebuf[i]!=0) retcode=1; } } else for(i=0;i=0 && offset_keydown+i=0 && offset_keyup+i1) sample=1; else if(sample<-1) sample=-1; if(cracklingcnt) { cracklingcnt--; samplebuf[i]=(((double)rand()/RAND_MAX-1)*amplitude)/100; } else samplebuf[i]=sample; getrndval_cnt=(getrndval_cnt+1)%div; } } /* Squelch sounds under a certain threshold */ void squelch(int squelch_level,double *sndbuf,int nbsamples,double ticklen) { static double squelch_timeout=0; static int fadecnt=0; int sample; int i; for(i=0;isquelch_level || sample<-squelch_level) squelch_timeout=SQUELCH_TIMEOUT; /* Squelch the sound, do a fadeout */ fadecnt+=fadecnt0) squelch_timeout-=ticklen; } cwirc-2.0.0.orig/frontend.c0000644000175000017500000001607410065334036014042 0ustar pg4ipg4i/* CWirc - X-Chat plugin for sending and receiving raw morse code over IRC (c) Pierre-Philippe Coupard - 18/06/2003 Frontend application. This program is distributed under the terms of the GNU General Public License See the COPYING file for details */ #include #include #include #include #include #include #include #include #include #include #include #include "types.h" #include "cwirc.h" #include "common.h" #include "rcfile.h" #include "io.h" #include "gui.h" #include "extension.h" #include "ipc.h" /* Global variables */ struct cwirc_shm_block *sharedmem; int shmid; int ext_shmid; /* Extension API's shared memory id */ struct cwirc_extension_api *ext_sharedmem; int io_process_pid=-1; /* Prototypes */ static void sigchld_hdlr(int nothing); static void clean_exit_hdlr(int nothing); /* Main Function */ int main(int argc,char *argv[]) { char *errmsg; int caught_sigs_not_sigchld[]={SIGHUP,SIGINT,SIGKILL,SIGPIPE,SIGIO, \ SIGPROF,SIGTERM,SIGUSR1,SIGUSR2,SIGVTALRM,SIGURG,-1}; struct sigaction sigact; int normal_priority; int i; /* Find out our current priority */ errno=0; normal_priority=getpriority(PRIO_PROCESS,0); if(errno) /* Error finding out the priority ? */ normal_priority=-99; /* Forget about the whole priority thing */ /* Try to renice ourselves, then immediately drop root privileges. If this fails, it's not an error as the user would only install the frontend binary suid root to allow it to renice itself, to cure "scratchy" sound with low-end soundcards. If the user is happy with I/O performances without renicing, so much the better. */ if(normal_priority!=-99) setpriority(PRIO_PROCESS,0,-20); setreuid(getuid(),getuid()); setregid(getgid(),getgid()); /* We need one argument only, and it needs to be the shared memory id */ if(argc!=2 || (shmid=strtol(argv[1],NULL,0))==0) { printf("Error: %s is a frontend for the CWirc X-Chat plugin.\n",argv[0]); printf(" It cannot be used as a standalone application.\n"); usleep(250000); return(-1); } /* Attach to the shared memory block */ if((sharedmem=(struct cwirc_shm_block *)cwirc_shm_attach(shmid)) ==(struct cwirc_shm_block *)-1) { printf("CWirc (frontend) : error : can't attach to the shared memory.\n"); usleep(250000); return(-1); } /* Check the plugin's version number against ours */ if(strncmp(sharedmem->version,VERSION,strlen(VERSION))) { printf("CWirc (frontend) : error : plugin/frontend version mismatch.\n"); usleep(250000); return(-1); } sharedmem->mouseinputbutton0=0; sharedmem->mouseinputbutton1=0; sharedmem->cwcodeset=0; sharedmem->decoded_msg_buf[0]=0; sharedmem->decoded_msg_buf_char_markers[0]=0; sharedmem->decoded_msg_wpm=-1; sharedmem->decoded_msg_updated=0; sharedmem->reset_decoder=0; sharedmem->sidetone_mode=0; /* Read/check the config file */ if((errmsg=cwirc_parse_rcfile(RCFILE))!=NULL) { printf("CWirc : error : %s",errmsg); cwirc_shm_detach(sharedmem); usleep(250000); return(-1); } /* Seed the RNG with something vaguely random */ srand(time(NULL)); /* Create a shared memory block for the extension API */ while((i=rand())==shmid); if((ext_shmid=cwirc_shm_alloc(i,sizeof(struct cwirc_extension_api)))==-1) { printf("CWirc : error : can't create shared memory for the extension API"); cwirc_shm_detach(sharedmem); usleep(250000); return(-1); } /* Attach to the extension API's shared memory block */ if((ext_sharedmem=(struct cwirc_extension_api *)cwirc_shm_attach(ext_shmid)) ==(struct cwirc_extension_api *)-1) { printf("CWirc (frontend) : error : can't attach to the extension API's " "shared memory\n"); cwirc_shm_free(ext_shmid); cwirc_shm_detach(sharedmem); usleep(250000); return(-1); } /* Create 2 semaphores to sync an extension program and allow it to safely get audio out of the extension API's audio buffer */ while((i=rand())==sharedmem->semid); if((ext_sharedmem->semid=cwirc_sem_create(i,2))==-1) { printf("CWirc (frontend) : error : can't create sync semaphores for the " "extension API\n"); cwirc_shm_detach(ext_sharedmem); cwirc_shm_free(ext_shmid); cwirc_shm_detach(sharedmem); usleep(250000); return(-1); } /* Acquire the 2 semaphores before any extension program has a chance to start */ for(i=0;i<2;i++) if(cwirc_sem_P(ext_sharedmem->semid,i)!=0) { printf("CWirc (frontend) : error : can't acquire sync semaphore #%d for " "the extension API\n",i); cwirc_shm_detach(ext_sharedmem); cwirc_shm_free(ext_shmid); cwirc_shm_detach(sharedmem); usleep(250000); return(-1); } /* Initialize the extension API */ ext_sharedmem->out_audiobuf_start=0; ext_sharedmem->out_audiobuf_end=0; ext_sharedmem->in_key=0; ext_sharedmem->pid=-1; /* Make sure we catch all signals other than SIGCHLD to exit cleanly */ for(i=0;caught_sigs_not_sigchld[i]!=-1;i++) signal(caught_sigs_not_sigchld[i],&clean_exit_hdlr); /* Make sure we catch the I/O process' death (but not its stopping) */ sigact.sa_handler=sigchld_hdlr; sigemptyset(&sigact.sa_mask); sigact.sa_flags=SA_NOCLDSTOP; sigaction(SIGCHLD,&sigact,NULL); /* Spawn the I/O process */ if((io_process_pid=cwirc_spawn_io_process(shmid,ext_shmid))==-1) { printf("CWirc : error : can't spawn I/O process.\n"); cwirc_sem_destroy(ext_sharedmem->semid); cwirc_shm_detach(ext_sharedmem); cwirc_shm_free(ext_shmid); cwirc_shm_detach(sharedmem); usleep(250000); return(-1); } /* The I/O process is running, possibly with nicer priority. The user interface doesn't need that however, so renice ourselves down now. */ if(normal_priority!=-99) setpriority(PRIO_PROCESS,0,normal_priority); printf("CWirc enabled!\n"); fflush(stdout); /* Run the user interface */ cwirc_ui(ext_shmid); /* If an extension program is running, kill it */ if(ext_sharedmem->pid!=-1) { /* Try nicely at first */ kill(ext_sharedmem->pid,SIGHUP); sleep(1); /* If the process still isn't dead and reaped by now, be a little more persuasive */ if(ext_sharedmem->pid!=-1) { kill(ext_sharedmem->pid,SIGKILL); sleep(1); } } /* Clean things up */ cwirc_sem_destroy(ext_sharedmem->semid); cwirc_shm_detach(ext_sharedmem); cwirc_shm_free(ext_shmid); cwirc_shm_detach(sharedmem); return(0); } /* SIGCHLD signal handler */ static void sigchld_hdlr(int nothing) { int pid; /* Reap the child process that died */ pid=wait(NULL); if(pid==io_process_pid) /* I/O process died */ sharedmem->stop_frontend=1; /* Terminate the entire frontend. */ else if(pid==ext_sharedmem->pid) /* Extension process died */ ext_sharedmem->pid=-1; } /* Signal handler to make sure we reap the I/O process before dying. */ static void clean_exit_hdlr(int nothing) { /* Terminate the I/O process. */ sharedmem->stop_frontend=1; } cwirc-2.0.0.orig/extension.c0000644000175000017500000000647110062715643014243 0ustar pg4ipg4i/* CWirc - X-Chat plugin for sending and receiving raw morse code over IRC (c) Pierre-Philippe Coupard - 18/06/2003 CWirc extensions routines This program is distributed under the terms of the GNU General Public License See the COPYING file for details */ #include #include #include #include #include #include #include "types.h" #include "cwirc.h" #include "extension.h" #include "ipc.h" #include "common.h" /* Variables */ char cwirc_extensions[MAX_CWIRC_EXTENSIONS][FILENAME_MAX]; /* Browse the CWirc extensions directory and store filenames present there */ void get_available_cwirc_extensions(void) { DIR *extdir; struct dirent *dirent; struct stat statbuf; char fullpathname[FILENAME_MAX]; int i; /* Initialize the extensions table */ for(i=0;id_name); if(stat(fullpathname,&statbuf)!=-1 && S_ISREG(statbuf.st_mode) && !access(fullpathname,X_OK)) { strncpy(cwirc_extensions[i],dirent->d_name,FILENAME_MAX-1); cwirc_extensions[i][FILENAME_MAX-1]=0; i++; } } /* Close the directory */ closedir(extdir); } /* Execute an extension program, passing it "--cwirc" as first argument, and the extension API's shared memory id as second argument. Return NULL or an error message. */ char *exec_extension_program(char *fname,int ext_shmid) { static char errmsg[64]; struct cwirc_extension_api *ext_sharedmem; char fullpathname[FILENAME_MAX]; int pid; /* Attach to the extension API's shared memory block */ if((ext_sharedmem=(struct cwirc_extension_api *)cwirc_shm_attach(ext_shmid)) ==(struct cwirc_extension_api *)-1) { strcpy(errmsg,"Error : can't attach to the extension API's shared memory."); return(errmsg); } /* If an extension process is already running, abort */ if(ext_sharedmem->pid!=-1) { cwirc_shm_detach(ext_sharedmem); strcpy(errmsg,"An extension program is already running."); return(errmsg); } /* Spawn the extension program */ switch((pid=fork())) { case -1: strcpy(errmsg,"Error : fork() : Cannot spawn the extension process."); return(errmsg); break; case 0: /* I'm the child */ /* Close the extension program's stdout so it doesn't trickle down to the X-Chat window */ close(1); /* Detach from the extension API's shared memory block */ cwirc_shm_detach(ext_sharedmem); /* Execute the extension program */ sprintf(errmsg,"0x%0x",ext_shmid); /* Reuse errmsg to store the shm id */ sprintf(fullpathname,"%s/%s",EXTENSIONS_DIR,fname); execl(fullpathname,fname,"--cwirc",errmsg,NULL); fprintf(stderr,"Error : cannot execute \"%s\".\n",fullpathname); fflush(stderr); sleep(1); /* Give the parent a change to catch us dying prematurely */ _exit(0); break; } ext_sharedmem->pid=pid; /* Detach from the extension API's shared memory block */ cwirc_shm_detach(ext_sharedmem); return(NULL); } cwirc-2.0.0.orig/grid.c0000644000175000017500000000455210062721335013145 0ustar pg4ipg4i/* CWirc - X-Chat plugin for sending and receiving raw morse code over IRC (c) Pierre-Philippe Coupard - 18/06/2003 Grid squares distance routines This program is distributed under the terms of the GNU General Public License See the COPYING file for details */ #include #include #include #include "grid.h" /* Definitions */ #define EARTH_RADIUS 6367 /* km, average */ /* Prototypes */ static void gridsquare_to_latlon(char *gs,double *lat,double *lon); /* Check if a string is a valid 4- or 6-character grid square */ int cwirc_is_grid_square(char *gs) { int i; /* Test the length of the string */ i=strlen(gs); if(i!=4 && i!=6) return(0); /* Test its format */ if(toupper(gs[0])<'A' || toupper(gs[0])>'R' || toupper(gs[1])<'A' || toupper(gs[1])>'R' || !isdigit(gs[2]) || !isdigit(gs[3]) || (i==6 && (toupper(gs[4])<'A' || toupper(gs[4])>'X' || toupper(gs[5])<'A' || toupper(gs[5])>'X'))) return(0); return(1); } /* Calculate the great circle path between 2 grid squares' centers in Km */ int cwirc_great_circle_path(char *gs1,char *gs2) { double lat1,lon1; double lat2,lon2; double a,d; /* Convert the grid squares to latitude/longitude */ gridsquare_to_latlon(gs1,&lat1,&lon1); gridsquare_to_latlon(gs2,&lat2,&lon2); /* Calculate the great circle path */ a=pow(sin((lat2-lat1)/2),2) + cos(lat1)*cos(lat2)*pow(sin((lon2-lon1)/2),2); d=EARTH_RADIUS * 2*atan2(sqrt(a),sqrt(1-a)); return(d); } /* Calculate the latitude/longitude (in rads) of the center of a grid square */ static void gridsquare_to_latlon(char *gs,double *lat,double *lon) { /* Calculate the base coordinates of the corner of the grid square */ *lon=-M_PI +(toupper(gs[0])-'A')*((M_PI/180)*20)+(gs[2]-'0')*((M_PI/180)*2); *lat=-M_PI/2 +(toupper(gs[1])-'A')*((M_PI/180)*10)+(gs[3]-'0')*((M_PI/180)*1); /* Is it a short (4 character) or long (6 character) grid square ? */ if(strlen(gs)==4) { /* Calculate the center of the grid square */ *lon+=(M_PI/180)*1; *lat+=(M_PI/180)*.5; } else { /* Increase precision of the coordinates of the corner of the grid square */ *lon+=(toupper(gs[4])-'A')*(((M_PI/180)/60)*5); *lat+=(toupper(gs[5])-'A')*(((M_PI/180)/60)*2.5); /* Calculate the center of the grid square */ *lon+=((M_PI/180)/60)*2.5; *lat+=((M_PI/180)/60)*1.25; } } cwirc-2.0.0.orig/gui.c0000644000175000017500000021633110433707136013011 0ustar pg4ipg4i/* CWirc - X-Chat plugin for sending and receiving raw morse code over IRC (c) Pierre-Philippe Coupard - 18/06/2003 Graphical user interface This program is distributed under the terms of the GNU General Public License See the COPYING file for details */ #include #include #include #include #include #include #include #include #include "types.h" #include "gui.h" #include "common.h" #include "cwirc.h" #include "rcfile.h" #include "grid.h" #include "io.h" #include "cwdecoder.h" #include "extension.h" #include "keyer.h" #include "ipc.h" #include "smeter.xpm" #include "sidetone.xpm" #include "straightkey.xpm" #include "iambickey.xpm" /* Definitions */ #define SMETER_NEEDLE_RANGE 83 /* degrees */ #define SMETER_NEEDLE_COLOR "black" #define SMETER_ARC_DOWN_OFFSET 14 /* Pixels */ #define IAMBIC_RADIO_BUTTON 1 #define MODEB_TOGGLE_BUTTON 2 #define DECODER_RESET_BUTTON 3 #define DITMEMORY_TOGGLE_BUTTON 4 #define DAHMEMORY_TOGGLE_BUTTON 5 #define MIDELEMENTMODEB_TOGGLE_BUTTON 6 #define AUTOCHARSPACING_TOGGLE_BUTTON 7 #define AUTOWORDSPACING_TOGGLE_BUTTON 8 #define INVERTPADDLES_TOGGLE_BUTTON 9 #define MOUSEINPUT_TOGGLE_BUTTON 10 #define KEYINPUT_TOGGLE_BUTTON 11 #define BOTHINPUT_TOGGLE_BUTTON 12 #define SNDDEVOUTPUT_TOGGLE_BUTTON 13 #define SOUNDEROUTPUT_TOGGLE_BUTTON 14 #define BOTHOUTPUT_TOGGLE_BUTTON 15 #define CWSOUND_BEEPS_RADIO_BUTTON 16 #define IO_CONFIG_SAVE_BUTTON 17 #define REPLY_TO_CTCP_TOGGLE_BUTTON 18 #define GIVE_CALLSIGN_IN_CTCP_REPLY_TOGGLE_BUTTON 19 #define GIVE_GRIDSQUARE_IN_CTCP_REPLY_TOGGLE_BUTTON 20 #define GIVE_CWCHANNEL_IN_CTCP_REPLY_TOGGLE_BUTTON 21 #define SEND_CALLSIGN_WITH_CW_TOGGLE_BUTTON 22 #define SEND_GRIDSQUARE_WITH_CW_TOGGLE_BUTTON 23 #define SIMULATE_QRN_TOGGLE_BUTTON 24 #define SIMULATE_SIGNAL_STRENGTH_TOGGLE_BUTTON 25 #define SIMULATE_SPORADICE_TOGGLE_BUTTON 26 #define PERSONAL_INFO_SAVE_BUTTON 27 #define SMETER 1 #define MORSEKEY 2 /* Global variables */ static GtkWidget *wd; static GtkWidget *popup_wd; static GdkColormap *colormap; static GtkWidget *notebook; static GtkWidget *table; static GtkWidget *table2; static GtkWidget *frame; static GtkWidget *align_wdg; static GtkWidget *hbox; static GtkWidget *vbox,*vbox2; static GtkWidget *label; static GtkWidget *optionmenu; static GtkWidget *menu; static GtkWidget *menuitem; static GtkWidget *iambic_keyer_zone; static GtkWidget *keyer_settings_zone; static GtkWidget *cwsound_zone; static GtkWidget *key_debounce_zone; static GtkWidget *sound_device_zone; static GtkWidget *serial_device_zone; static GtkWidget *ctcp_params_zone; static GtkWidget *callsign_zone; static GtkWidget *propag_sim_zone; static GtkWidget *simulate_sporadicE_zone; static GtkWidget *default_signal_strength_zone1; static GtkWidget *default_signal_strength_zone2; static GtkAdjustment *adj; static GtkAdjustment *channel_spinner_adj; static GtkWidget *spinner; static GtkWidget *scrollbar; static GtkWidget *button; static GtkWidget *midelementmodeB_button; static GtkWidget *autowordspacing_button; static GtkWidget *decoder_text_entry; static GtkWidget *decoder_wpm_label; static GtkWidget *snddev_text_entry; static GtkWidget *serialdev_text_entry; static GtkWidget *callsign_text_entry; static GtkWidget *gridsquare_text_entry; static GdkGC *smeter_gc; static GdkGC *morsekey_gc; static GdkColor smeter_needle_color; static GdkPixmap *smeter_bg_pixmap; static GdkPixmap *sidetone_bg_pixmap; static GdkPixmap *straightkey_bg_pixmap; static GdkPixmap *iambickey_bg_pixmap; static GtkWidget *smeter_drawingarea; static GtkWidget *morsekey_drawingarea; static gint smeter_width; static gint smeter_height; static gint morsekey_width; static gint morsekey_height; static int signal_strength_prev=0; static int signal_strength=0; static T_BOOL local_do_mouse_input; static T_BOOL local_do_key_input; static T_BOOL local_do_snddev_output; static T_BOOL local_do_sounder_output; static int local_cwsound; static int local_debounce; static int local_recv_buffering; static T_BOOL local_send_callsign_with_cw; static T_BOOL local_send_gridsquare_with_cw; static T_BOOL local_reply_to_ctcp; static T_BOOL local_give_callsign_in_ctcp_reply; static T_BOOL local_give_gridsquare_in_ctcp_reply; static T_BOOL local_give_cwchannel_in_ctcp_reply; /* Prototypes */ static gboolean gtk_delete_event(GtkWidget *wdg,GdkEvent *ev,gpointer data); static void gtk_destroy(GtkWidget *wdg,GdkEvent *ev,gpointer data); static void current_preset_channel_changed(GtkWidget *wd,gpointer data); static void channel_changed(GtkWidget *wd,GtkSpinButton *spinner); static void rxpitch_changed(GtkWidget *wd,GtkRange *scrollbar); static void txpitch_changed(GtkWidget *wd,GtkRange *scrollbar); static void squelch_changed(GtkWidget *wd,GtkRange *scrollbar); static void volume_changed(GtkWidget *wd,GtkRange *scrollbar); static void qrnlevel_changed(GtkWidget *wd,GtkRange *scrollbar); static void default_signal_strength_changed(GtkWidget *wd,GtkRange *scrollbar); static void wpm_changed(GtkWidget *wd,GtkSpinButton *spinner); static void cw_decoder_language_changed(GtkWidget *wd,gpointer data); static void dit_weight_changed(GtkWidget *wd,GtkSpinButton *spinner); static void extension_program_button_clicked(GtkWidget *wd,gpointer data); static void debounce_changed(GtkWidget *wd,GtkSpinButton *spinner); static void recv_buffering_changed(GtkWidget *wd,GtkSpinButton *spinner); static void button_changed(GtkWidget *wd,gpointer button); static gboolean smeter_configure_event(GtkWidget *wdg,GdkEventConfigure *ev); static gboolean smeter_expose_event(GtkWidget *wdg,GdkEventExpose *ev); static gboolean smeter_pressed_event(GtkWidget *wdg,GdkEventButton *ev); static gboolean morsekey_configure_event(GtkWidget *wdg,GdkEventConfigure *ev); static gboolean morsekey_expose_event(GtkWidget *wdg,GdkEventExpose *ev); static gboolean morsekey_pressed_event(GtkWidget *wdg,GdkEventButton *ev); static gboolean morsekey_released_event(GtkWidget *wdg,GdkEventButton *ev); static void draw_smeter(int value,T_BOOL full_refresh); static void calculate_smeter_needle_coordinates(int value,T_U8 *x1,T_U8 *y1, T_U8 *x2,T_U8 *y2); static void error_popup(char *message); static gint gtk_timeout(gpointer data); static int extension_shmid; /* User interface. The function is passed the id of the extension API's shared memory block, to pass to an extension program. */ int cwirc_ui(int ext_shmid) { gint argc; gchar **argv; char buf[10]; int i; extension_shmid=ext_shmid; /* Find out the list of available CWirc extensions */ get_available_cwirc_extensions(); /* Save some internal values locally, so we can control when they change */ local_do_mouse_input=sharedmem->do_mouse_input; local_do_key_input=sharedmem->do_key_input; local_do_snddev_output=sharedmem->do_snddev_output; local_do_sounder_output=sharedmem->do_sounder_output; local_cwsound=sharedmem->cwsound; local_debounce=sharedmem->debounce; local_recv_buffering=sharedmem->recv_buffering; local_send_callsign_with_cw=sharedmem->send_callsign_with_cw; local_send_gridsquare_with_cw=sharedmem->send_gridsquare_with_cw; local_reply_to_ctcp=sharedmem->reply_to_ctcp; local_give_callsign_in_ctcp_reply=sharedmem->give_callsign_in_ctcp_reply; local_give_gridsquare_in_ctcp_reply=sharedmem->give_gridsquare_in_ctcp_reply; local_give_cwchannel_in_ctcp_reply=sharedmem->give_cwchannel_in_ctcp_reply; /* Initialize GTK */ argc=1; argv=g_new(gchar *,1); argv[0]=g_strdup("CWirc"); gtk_init(&argc,(char ***)&argv); /* Create the window for the control panel */ wd=gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(G_OBJECT(wd),"delete_event",G_CALLBACK(gtk_delete_event), NULL); g_signal_connect(G_OBJECT(wd),"destroy",G_CALLBACK(gtk_destroy),NULL); gtk_window_set_title(GTK_WINDOW(wd),"CWirc"); colormap=gtk_widget_get_colormap(wd); /* Create the S-meter and "sidetone" GDK pixmap */ smeter_bg_pixmap=gdk_pixmap_colormap_create_from_xpm_d(NULL,colormap, NULL,NULL,smeter_xpm); sidetone_bg_pixmap=gdk_pixmap_colormap_create_from_xpm_d(NULL,colormap, NULL,NULL,sidetone_xpm); gdk_window_get_size(smeter_bg_pixmap,&smeter_width,&smeter_height); /* Create a GC for the S-meter */ smeter_gc=gdk_gc_new(smeter_bg_pixmap); gdk_colormap_alloc_color(colormap,&smeter_needle_color,TRUE,TRUE); gdk_color_parse(SMETER_NEEDLE_COLOR,&smeter_needle_color); gdk_gc_set_foreground(smeter_gc,&smeter_needle_color); /* Create the "straight key icon" and "iambic key icon" GDK pixmaps */ straightkey_bg_pixmap=gdk_pixmap_colormap_create_from_xpm_d(NULL,colormap, NULL,NULL,straightkey_xpm); iambickey_bg_pixmap=gdk_pixmap_colormap_create_from_xpm_d(NULL,colormap, NULL,NULL,iambickey_xpm); gdk_window_get_size(straightkey_bg_pixmap,&morsekey_width,&morsekey_height); /* Create a GC for the morse key icon */ morsekey_gc=gdk_gc_new(straightkey_bg_pixmap); /* Create the notebook for the tabbed pages inside the window */ notebook=gtk_notebook_new(); gtk_notebook_set_tab_pos (GTK_NOTEBOOK(notebook),GTK_POS_TOP); gtk_container_add(GTK_CONTAINER(wd),notebook); /* Create the first page of the notebook with a table inside */ label=gtk_label_new("Main"); table=gtk_table_new(6,2,FALSE); gtk_notebook_append_page(GTK_NOTEBOOK(notebook),table,label); /* Create the S-meter drawing area inside an alignment widget, inside a frame, inside the table */ frame=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_ETCHED_OUT); gtk_table_attach(GTK_TABLE(table),frame,0,1,0,1,GTK_SHRINK,GTK_SHRINK, 7,7); align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_container_add(GTK_CONTAINER(frame),align_wdg); smeter_drawingarea=gtk_drawing_area_new(); gtk_drawing_area_size(GTK_DRAWING_AREA(smeter_drawingarea), smeter_width,smeter_height); gtk_signal_connect(GTK_OBJECT (smeter_drawingarea),"expose_event", (GtkSignalFunc)smeter_expose_event,NULL); gtk_signal_connect(GTK_OBJECT(smeter_drawingarea),"configure_event", (GtkSignalFunc)smeter_configure_event,NULL); gtk_signal_connect(GTK_OBJECT(smeter_drawingarea),"button_press_event", (GtkSignalFunc)smeter_pressed_event,NULL); gtk_widget_set_events(smeter_drawingarea,GDK_BUTTON_PRESS_MASK); gtk_container_add(GTK_CONTAINER(align_wdg),smeter_drawingarea); /* Create a vbox to contain the preset channel selector and the channel spinner, inside a labeled frame, inside the table */ frame=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_ETCHED_OUT); gtk_frame_set_label(GTK_FRAME(frame),"Channel"); gtk_frame_set_label_align(GTK_FRAME(frame),0,.5); gtk_table_attach(GTK_TABLE(table),frame,1,2,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(frame),vbox); /* Create the preset channel selector inside an alignment widget, inside the vbox */ align_wdg=gtk_alignment_new(.5,.75,1,0); gtk_box_pack_start(GTK_BOX(vbox),align_wdg,TRUE,TRUE,0); optionmenu=gtk_option_menu_new(); menu=gtk_menu_new(); strcpy(buf,"PR x"); for(i=0;i<5;i++) { buf[3]='1'+i; menuitem=gtk_menu_item_new_with_label(buf); g_signal_connect(G_OBJECT(menuitem),"activate", G_CALLBACK(current_preset_channel_changed),(gpointer)i); gtk_menu_shell_append(GTK_MENU_SHELL(menu),menuitem); } gtk_option_menu_set_menu(GTK_OPTION_MENU(optionmenu),menu); gtk_option_menu_set_history(GTK_OPTION_MENU(optionmenu), sharedmem->currcwchannel); gtk_container_add(GTK_CONTAINER(align_wdg),optionmenu); /* Create the "Channel" spinner inside an alignment widget, inside the vbox */ align_wdg=gtk_alignment_new(.5,.25,1,0); gtk_box_pack_start(GTK_BOX(vbox),align_wdg,TRUE,TRUE,0); channel_spinner_adj=(GtkAdjustment *)gtk_adjustment_new(sharedmem->cwchannel[ sharedmem->currcwchannel],0,3999,1,10,0); spinner=gtk_spin_button_new(channel_spinner_adj,0.1,0); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinner),TRUE); g_signal_connect(G_OBJECT(channel_spinner_adj),"value_changed", G_CALLBACK(channel_changed),(gpointer)spinner); gtk_container_add(GTK_CONTAINER(align_wdg),spinner); /* Create a second table to contain the sound settings inside a frame, inside the first table */ frame=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_ETCHED_OUT); gtk_table_attach(GTK_TABLE(table),frame,2,3,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); table2=gtk_table_new(2,4,FALSE); gtk_container_add(GTK_CONTAINER(frame),table2); /* Create the "RX pitch", "TX pitch", "Squelch" and "AF gain" scrollbars inside alignment widgets, inside the second table */ for(i=0;i<4;i++) { align_wdg=gtk_alignment_new(.5,.5,1,0); gtk_table_attach(GTK_TABLE(table2),align_wdg,0,1,i,i+1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,3,0); adj=(GtkAdjustment *)gtk_adjustment_new(i==0?sharedmem->cwrxpitch: i==1?sharedmem->cwtxpitch:i==2?sharedmem->squelch:sharedmem->volume, (i<2?-50:0),(i<2?50:100), 1,5,0); scrollbar=gtk_hscrollbar_new(adj); gtk_widget_set_size_request(GTK_WIDGET(scrollbar),100,-1); gtk_range_set_update_policy(GTK_RANGE(scrollbar),GTK_UPDATE_CONTINUOUS); g_signal_connect(G_OBJECT(adj),"value_changed",G_CALLBACK( i==0?rxpitch_changed:i==1?txpitch_changed: i==2?squelch_changed:volume_changed), (gpointer)scrollbar); gtk_container_add(GTK_CONTAINER(align_wdg),scrollbar); align_wdg=gtk_alignment_new(.5,.5,1,0); gtk_table_attach(GTK_TABLE(table2),align_wdg,1,2,i,i+1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,3,0); label=gtk_label_new(i==0?"RX pitch":i==1?"TX pitch": i==2?"Squelch":"AF gain"); gtk_misc_set_alignment(GTK_MISC(label),0,0.5); gtk_container_add(GTK_CONTAINER(align_wdg),label); } /* Create the straight/iambic radio buttons inside an vbox, inside an alignment widget, inside a labelled frame, inside the table. */ frame=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_ETCHED_OUT); gtk_frame_set_label(GTK_FRAME(frame),"Key"); gtk_frame_set_label_align(GTK_FRAME(frame),0,.5); gtk_table_attach(GTK_TABLE(table),frame,3,4,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_container_add(GTK_CONTAINER(frame),align_wdg); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox); button=gtk_radio_button_new_with_label(NULL,"straight"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), sharedmem->doiambic?FALSE:TRUE); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); button=gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(button),"iambic"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), sharedmem->doiambic?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed),(gpointer)IAMBIC_RADIO_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); /* Create the WPM spinner inside an alignment widget, inside an hbox, inside a labelled frame, inside the table */ iambic_keyer_zone=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(iambic_keyer_zone),GTK_SHADOW_ETCHED_OUT); gtk_frame_set_label(GTK_FRAME(iambic_keyer_zone),"Keyer"); gtk_frame_set_label_align(GTK_FRAME(iambic_keyer_zone),0,.5); gtk_widget_set_sensitive(iambic_keyer_zone,sharedmem->doiambic?TRUE:FALSE); gtk_table_attach(GTK_TABLE(table),iambic_keyer_zone,4,5,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); hbox=gtk_hbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(iambic_keyer_zone),hbox); align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_box_pack_start(GTK_BOX(hbox),align_wdg,TRUE,TRUE,5); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox); label=gtk_label_new("WPM"); gtk_misc_set_alignment(GTK_MISC(label),0,0.5); gtk_box_pack_start(GTK_BOX(vbox),label,FALSE,TRUE,0); adj=(GtkAdjustment *)gtk_adjustment_new(sharedmem->wpm,1,60,1,5,0); spinner=gtk_spin_button_new(adj,0.1,0); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinner),FALSE); g_signal_connect(G_OBJECT(adj),"value_changed", G_CALLBACK(wpm_changed),(gpointer)spinner); gtk_box_pack_start(GTK_BOX(vbox),spinner,FALSE,TRUE,0); /* Create the "morse key icon" drawing area inside an alignment widget, inside a frame, inside the table */ frame=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_ETCHED_OUT); gtk_table_attach(GTK_TABLE(table),frame,5,6,0,1,GTK_SHRINK,GTK_SHRINK, 7,7); align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_container_add(GTK_CONTAINER(frame),align_wdg); morsekey_drawingarea=gtk_drawing_area_new(); gtk_drawing_area_size(GTK_DRAWING_AREA(morsekey_drawingarea), morsekey_width,morsekey_height); gtk_signal_connect (GTK_OBJECT (morsekey_drawingarea),"expose_event", (GtkSignalFunc)morsekey_expose_event,NULL); gtk_signal_connect(GTK_OBJECT(morsekey_drawingarea),"configure_event", (GtkSignalFunc)morsekey_configure_event,NULL); gtk_signal_connect(GTK_OBJECT(morsekey_drawingarea),"button_press_event", (GtkSignalFunc)morsekey_pressed_event,NULL); gtk_signal_connect(GTK_OBJECT(morsekey_drawingarea),"button_release_event", (GtkSignalFunc)morsekey_released_event,NULL); gtk_widget_set_events(morsekey_drawingarea,GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); gtk_container_add(GTK_CONTAINER(align_wdg),morsekey_drawingarea); /* Create the decoder text entry and speedo/reset button inside an hbox, inside a frame, inside the table */ frame=gtk_frame_new(NULL); gtk_table_attach(GTK_TABLE(table),frame,0,5,1,2, GTK_FILL|GTK_SHRINK,GTK_FILL|GTK_SHRINK,7,7); hbox=gtk_hbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(frame),hbox); decoder_text_entry=gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(decoder_text_entry),FALSE); gtk_box_pack_start(GTK_BOX(hbox),decoder_text_entry,TRUE,TRUE,0); button=gtk_button_new(); decoder_wpm_label=gtk_label_new("? WPM"); gtk_container_add(GTK_CONTAINER(button),decoder_wpm_label); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed),(gpointer)DECODER_RESET_BUTTON); gtk_box_pack_start(GTK_BOX(hbox),button,FALSE,TRUE,0); /* Create the morse decoder language selector inside the table */ optionmenu=gtk_option_menu_new(); menu=gtk_menu_new(); for(i=0;icwcodeset); gtk_table_attach(GTK_TABLE(table),optionmenu,5,6,1,2, GTK_FILL|GTK_SHRINK,GTK_FILL|GTK_SHRINK,7,7); /* Create the second page of the notebook with a table inside */ label=gtk_label_new("Keyer settings"); keyer_settings_zone=gtk_table_new(4,1,FALSE); gtk_widget_set_sensitive(keyer_settings_zone,sharedmem->doiambic?TRUE:FALSE); gtk_notebook_append_page(GTK_NOTEBOOK(notebook),keyer_settings_zone,label); /* Create the "Iambic mode" radio buttons inside an vbox, inside an alignment widget, inside a labelled frame, inside the table */ frame=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_ETCHED_OUT); gtk_frame_set_label(GTK_FRAME(frame),"Iambic mode"); gtk_frame_set_label_align(GTK_FRAME(frame),0,.5); gtk_table_attach(GTK_TABLE(keyer_settings_zone),frame,0,1,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_container_add(GTK_CONTAINER(frame),align_wdg); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox); button=gtk_radio_button_new_with_label(NULL,"mode-A"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), sharedmem->iambicmode==0?TRUE:FALSE); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); button=gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(button),"mode-B"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), sharedmem->iambicmode==1?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed),(gpointer)MODEB_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); /* Create the "Memory" check buttons inside an vbox, inside an alignment widget, inside a labelled frame, inside the table */ frame=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_ETCHED_OUT); gtk_frame_set_label(GTK_FRAME(frame),"Memory"); gtk_frame_set_label_align(GTK_FRAME(frame),0,.5); gtk_table_attach(GTK_TABLE(keyer_settings_zone),frame,1,2,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_container_add(GTK_CONTAINER(frame),align_wdg); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox); button=gtk_check_button_new_with_label("dit memory"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), sharedmem->do_ditmemory?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed),(gpointer)DITMEMORY_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); button=gtk_check_button_new_with_label("dah memory"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), sharedmem->do_dahmemory?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed),(gpointer)DAHMEMORY_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); /* Create the "Options" check buttons inside an vbox, inside an alignment widget, inside a labelled frame, inside the table */ frame=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_ETCHED_OUT); gtk_frame_set_label(GTK_FRAME(frame),"Options"); gtk_frame_set_label_align(GTK_FRAME(frame),0,.5); gtk_widget_set_sensitive(frame,local_do_snddev_output?TRUE:FALSE); gtk_table_attach(GTK_TABLE(keyer_settings_zone),frame,2,3,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_container_add(GTK_CONTAINER(frame),align_wdg); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox); midelementmodeB_button=gtk_check_button_new_with_label("mid-element mode-B"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(midelementmodeB_button), sharedmem->do_midelementmodeB?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(midelementmodeB_button),"clicked", G_CALLBACK(button_changed), (gpointer)MIDELEMENTMODEB_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),midelementmodeB_button,FALSE,TRUE,0); gtk_widget_set_sensitive(midelementmodeB_button,sharedmem->iambicmode==1? TRUE:FALSE); button=gtk_check_button_new_with_label("auto character spacing"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), sharedmem->do_autocharspacing?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed), (gpointer)AUTOCHARSPACING_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); autowordspacing_button=gtk_check_button_new_with_label("auto word spacing"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autowordspacing_button), sharedmem->do_autowordspacing?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(autowordspacing_button),"clicked", G_CALLBACK(button_changed), (gpointer)AUTOWORDSPACING_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),autowordspacing_button,FALSE,TRUE,0); gtk_widget_set_sensitive(autowordspacing_button,sharedmem->do_autocharspacing? TRUE:FALSE); button=gtk_check_button_new_with_label("invert paddles"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), sharedmem->invertpaddles?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed), (gpointer)INVERTPADDLES_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); /* Create a vbox to contain the "dit weight" spinner, inside an alignment widget, inside the table */ align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_table_attach(GTK_TABLE(keyer_settings_zone),align_wdg,3,4,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox); /* Create the "dit weight" spinner inside an alignment widget inside the vbox */ align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_box_pack_start(GTK_BOX(vbox),align_wdg,TRUE,TRUE,5); vbox2=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox2); label=gtk_label_new("Dit weight (%)"); gtk_misc_set_alignment(GTK_MISC(label),0,0.5); gtk_box_pack_start(GTK_BOX(vbox2),label,FALSE,TRUE,0); adj=(GtkAdjustment *)gtk_adjustment_new(sharedmem->dit_weight,15,85,1,5,0); spinner=gtk_spin_button_new(adj,0.1,0); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinner),FALSE); g_signal_connect(G_OBJECT(adj),"value_changed", G_CALLBACK(dit_weight_changed),(gpointer)spinner); gtk_box_pack_start(GTK_BOX(vbox2),spinner,FALSE,TRUE,0); /* Are there one or more CWirc extensions available ? */ if(cwirc_extensions[0][0]) { /* Create a third, intersticial page to run them */ label=gtk_label_new("Extensions"); table=gtk_table_new(1,1,FALSE); gtk_notebook_append_page(GTK_NOTEBOOK(notebook),table,label); /* Create an hbox to contain the extensions start buttons inside an vbox, inside an alignment widget, inside a labelled frame, inside the table */ frame=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_ETCHED_OUT); gtk_frame_set_label(GTK_FRAME(frame),"Available extensions"); gtk_frame_set_label_align(GTK_FRAME(frame),0,.5); gtk_table_attach(GTK_TABLE(table),frame,0,1,0,2, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_container_add(GTK_CONTAINER(frame),align_wdg); hbox=gtk_hbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),hbox); /* Populate the hbox with extension program names */ for(i=0;isimulate_qrn?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed), (gpointer)SIMULATE_QRN_TOGGLE_BUTTON); gtk_container_add(GTK_CONTAINER(align_wdg),button); /* Create the "QRN level" scrollbar inside an alignment widget inside the second table */ align_wdg=gtk_alignment_new(.5,.5,1,0); gtk_table_attach(GTK_TABLE(table2),align_wdg,0,1,1,2, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,3,0); adj=(GtkAdjustment *)gtk_adjustment_new(sharedmem->qrnlevel,0,100,1,5,0); scrollbar=gtk_hscrollbar_new(adj); gtk_widget_set_size_request(GTK_WIDGET(scrollbar),100,-1); gtk_range_set_update_policy(GTK_RANGE(scrollbar),GTK_UPDATE_CONTINUOUS); g_signal_connect(G_OBJECT(adj),"value_changed", G_CALLBACK(qrnlevel_changed),(gpointer)scrollbar); gtk_container_add(GTK_CONTAINER(align_wdg),scrollbar); align_wdg=gtk_alignment_new(.5,.5,1,0); gtk_table_attach(GTK_TABLE(table2),align_wdg,1,2,1,2, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,3,0); label=gtk_label_new("QRN level"); gtk_misc_set_alignment(GTK_MISC(label),0,0.5); gtk_container_add(GTK_CONTAINER(align_wdg),label); /* Create a second table containing the propagation simulation settings inside an alignment widget, inside a labelled frame, inside the table */ propag_sim_zone=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(propag_sim_zone),GTK_SHADOW_ETCHED_OUT); gtk_frame_set_label(GTK_FRAME(propag_sim_zone),sharedmem->gridsquare[0]? "Propagation simulation": "Propagation simulation [needs the grid square to be set]"); gtk_frame_set_label_align(GTK_FRAME(propag_sim_zone),0,.5); gtk_widget_set_sensitive(propag_sim_zone,sharedmem->gridsquare[0]?TRUE:FALSE); gtk_table_attach(GTK_TABLE(table),propag_sim_zone,1,2,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); align_wdg=gtk_alignment_new(.5,.5,0,.5); gtk_container_add(GTK_CONTAINER(propag_sim_zone),align_wdg); table2=gtk_table_new(2,3,FALSE); gtk_container_add(GTK_CONTAINER(align_wdg),table2); /* Create the "simulate signal strength ..." check button inside an alignment widget inside the second table */ align_wdg=gtk_alignment_new(.5,.5,1,0); gtk_table_attach(GTK_TABLE(table2),align_wdg,0,2,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,3,0); button=gtk_check_button_new_with_label( "simulate signal strength for signals with grid squares"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), sharedmem->simulate_signal_strength?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed), (gpointer)SIMULATE_SIGNAL_STRENGTH_TOGGLE_BUTTON); gtk_container_add(GTK_CONTAINER(align_wdg),button); /* Create the "simulate sporadic-E ..." check button inside an alignment widget inside the second table */ simulate_sporadicE_zone=gtk_alignment_new(.5,.5,1,0); gtk_widget_set_sensitive(simulate_sporadicE_zone, sharedmem->simulate_signal_strength?TRUE:FALSE); gtk_table_attach(GTK_TABLE(table2),simulate_sporadicE_zone,0,2,1,2, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,3,0); button=gtk_check_button_new_with_label( "simulate sporadic-E for weak signals"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), sharedmem->simulate_sporadicE?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed), (gpointer)SIMULATE_SPORADICE_TOGGLE_BUTTON); gtk_container_add(GTK_CONTAINER(simulate_sporadicE_zone),button); /* Create the "default signal strength ..." scrollbar inside an alignment widget inside the second table */ default_signal_strength_zone1=gtk_alignment_new(.5,.5,1,0); gtk_widget_set_sensitive(default_signal_strength_zone1, sharedmem->simulate_signal_strength?TRUE:FALSE); gtk_table_attach(GTK_TABLE(table2),default_signal_strength_zone1,0,1,2,3, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,3,0); adj=(GtkAdjustment *)gtk_adjustment_new(sharedmem->default_signal_strength, 0,100,1,5,0); scrollbar=gtk_hscrollbar_new(adj); gtk_widget_set_size_request(GTK_WIDGET(scrollbar),100,-1); gtk_range_set_update_policy(GTK_RANGE(scrollbar),GTK_UPDATE_CONTINUOUS); g_signal_connect(G_OBJECT(adj),"value_changed", G_CALLBACK(default_signal_strength_changed),(gpointer)scrollbar); gtk_container_add(GTK_CONTAINER(default_signal_strength_zone1),scrollbar); default_signal_strength_zone2=gtk_alignment_new(.5,.5,1,0); gtk_widget_set_sensitive(default_signal_strength_zone2, sharedmem->simulate_signal_strength?TRUE:FALSE); gtk_table_attach(GTK_TABLE(table2),default_signal_strength_zone2,1,2,2,3, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,3,0); label=gtk_label_new( "default signal strength for signals without grid squares"); gtk_misc_set_alignment(GTK_MISC(label),0,0.5); gtk_container_add(GTK_CONTAINER(default_signal_strength_zone2),label); /* Create the fourth (or fifth) page of the notebook with a table inside */ label=gtk_label_new("Personal info"); table=gtk_table_new(4,1,FALSE); gtk_notebook_append_page(GTK_NOTEBOOK(notebook),table,label); /* Create a zone to contain the CTCP buttons inside an vbox, inside an alignment widget, inside a labelled frame, inside the table */ frame=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_ETCHED_OUT); gtk_frame_set_label(GTK_FRAME(frame),"CTCP"); gtk_frame_set_label_align(GTK_FRAME(frame),0,.5); gtk_table_attach(GTK_TABLE(table),frame,0,1,0,2, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_container_add(GTK_CONTAINER(frame),align_wdg); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox); /* Create the "reply to CTCP CWIRC queries" check button inside the vbox */ button=gtk_check_button_new_with_label("reply to CTCP CWIRC queries"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), local_reply_to_ctcp?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed), (gpointer)REPLY_TO_CTCP_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); /* Create the "send callsign in CTCP reply", "send grid square in CTCP reply" and "send current channel in CTCP reply" check buttons inside a second vbox, inside the vbox */ ctcp_params_zone=gtk_vbox_new(FALSE,0); gtk_widget_set_sensitive(ctcp_params_zone,local_reply_to_ctcp?TRUE:FALSE); gtk_box_pack_start(GTK_BOX(vbox),ctcp_params_zone,FALSE,TRUE,0); button=gtk_check_button_new_with_label("send callsign in CTCP reply"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), local_give_callsign_in_ctcp_reply?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed), (gpointer)GIVE_CALLSIGN_IN_CTCP_REPLY_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(ctcp_params_zone),button,FALSE,TRUE,0); button=gtk_check_button_new_with_label("send grid square in CTCP reply"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), local_give_gridsquare_in_ctcp_reply?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed), (gpointer)GIVE_GRIDSQUARE_IN_CTCP_REPLY_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(ctcp_params_zone),button,FALSE,TRUE,0); button=gtk_check_button_new_with_label("send current channel in CTCP reply"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), local_give_cwchannel_in_ctcp_reply?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed), (gpointer)GIVE_CWCHANNEL_IN_CTCP_REPLY_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(ctcp_params_zone),button,FALSE,TRUE,0); /* Create a zone to contain the "send [..] with CW" buttons inside an vbox, inside an alignment widget, inside a labelled frame, inside the table */ frame=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_ETCHED_OUT); gtk_frame_set_label(GTK_FRAME(frame),"Additional info in signal"); gtk_frame_set_label_align(GTK_FRAME(frame),0,.5); gtk_table_attach(GTK_TABLE(table),frame,1,2,0,2, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_container_add(GTK_CONTAINER(frame),align_wdg); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox); /* Create the "send callsign with CW" check button inside the vbox */ button=gtk_check_button_new_with_label("send callsign with CW"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), local_send_callsign_with_cw?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed), (gpointer)SEND_CALLSIGN_WITH_CW_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); /* Create the "send grid square with CW" check button inside the vbox */ button=gtk_check_button_new_with_label("send grid square with CW"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), local_send_gridsquare_with_cw?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed), (gpointer)SEND_GRIDSQUARE_WITH_CW_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); /* Create a vbox to contain the callsign and grid square text entries, inside an alignment widget, inside the table */ align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_table_attach(GTK_TABLE(table),align_wdg,2,3,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox); /* Create the callsign entry, inside an alignment widget, inside the vbox */ callsign_zone=gtk_alignment_new(.5,.5,0,0); gtk_widget_set_sensitive(callsign_zone,local_send_callsign_with_cw || local_give_callsign_in_ctcp_reply?TRUE:FALSE); gtk_box_pack_start(GTK_BOX(vbox),callsign_zone,TRUE,TRUE,5); vbox2=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(callsign_zone),vbox2); label=gtk_label_new("Callsign"); gtk_misc_set_alignment(GTK_MISC(label),0,0.5); gtk_box_pack_start(GTK_BOX(vbox2),label,FALSE,TRUE,0); callsign_text_entry=gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(callsign_text_entry),TRUE); gtk_entry_set_max_length(GTK_ENTRY(callsign_text_entry),MAX_NICK_SIZE-1); gtk_entry_set_text(GTK_ENTRY(callsign_text_entry),sharedmem->callsign); gtk_box_pack_start(GTK_BOX(vbox2),callsign_text_entry,FALSE,TRUE,0); /* Create the grid square entry, inside an alignment widget, inside the vbox*/ align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_box_pack_start(GTK_BOX(vbox),align_wdg,TRUE,TRUE,5); vbox2=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox2); label=gtk_label_new("Grid square"); gtk_misc_set_alignment(GTK_MISC(label),0,0.5); gtk_box_pack_start(GTK_BOX(vbox2),label,FALSE,TRUE,0); gridsquare_text_entry=gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(gridsquare_text_entry),TRUE); gtk_entry_set_max_length(GTK_ENTRY(gridsquare_text_entry), MAX_GRIDSQUARE_SIZE-1); gtk_entry_set_text(GTK_ENTRY(gridsquare_text_entry),sharedmem->gridsquare); gtk_box_pack_start(GTK_BOX(vbox2),gridsquare_text_entry,FALSE,TRUE,0); /* Create a save/change button inside an alignment widget, inside the table */ align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_table_attach(GTK_TABLE(table),align_wdg,3,4,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); button=gtk_button_new_with_label("Change/Save"); g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(button_changed),(gpointer)PERSONAL_INFO_SAVE_BUTTON); gtk_container_add(GTK_CONTAINER(align_wdg),button); /* Create the fifth (sixth) page of the notebook with a table inside */ label=gtk_label_new("I/O configuration"); table=gtk_table_new(6,1,FALSE); gtk_notebook_append_page(GTK_NOTEBOOK(notebook),table,label); /* Create the "CW input" radio buttons inside an vbox, inside an alignment widget, inside a labelled frame, inside the table */ frame=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_ETCHED_OUT); gtk_frame_set_label(GTK_FRAME(frame),"CW input"); gtk_frame_set_label_align(GTK_FRAME(frame),0,.5); gtk_table_attach(GTK_TABLE(table),frame,0,1,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_container_add(GTK_CONTAINER(frame),align_wdg); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox); button=gtk_radio_button_new_with_label(NULL,"mouse"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), local_do_mouse_input && !local_do_key_input?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed),(gpointer)MOUSEINPUT_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); button=gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(button),"real key"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), !local_do_mouse_input && local_do_key_input?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed),(gpointer)KEYINPUT_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); button=gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(button),"both"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), local_do_mouse_input && local_do_key_input?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed),(gpointer)BOTHINPUT_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); /* Create the "CW output" radio buttons inside an vbox, inside an alignment widget, inside a labelled frame, inside the table */ frame=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_ETCHED_OUT); gtk_frame_set_label(GTK_FRAME(frame),"CW output"); gtk_frame_set_label_align(GTK_FRAME(frame),0,.5); gtk_table_attach(GTK_TABLE(table),frame,1,2,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_container_add(GTK_CONTAINER(frame),align_wdg); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox); button=gtk_radio_button_new_with_label(NULL,"soundcard"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), local_do_snddev_output && !local_do_sounder_output?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed), (gpointer)SNDDEVOUTPUT_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); button=gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(button),"sounder"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), !local_do_snddev_output && local_do_sounder_output?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed), (gpointer)SOUNDEROUTPUT_TOGGLE_BUTTON); #ifndef LINUX gtk_widget_set_sensitive(button,FALSE); #endif gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); button=gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(button),"both"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), local_do_snddev_output && local_do_sounder_output?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed),(gpointer)BOTHOUTPUT_TOGGLE_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); /* Create the "CW sound" radio buttons inside an vbox, inside an alignment widget, inside a labelled frame, inside the table */ cwsound_zone=gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(cwsound_zone),GTK_SHADOW_ETCHED_OUT); gtk_frame_set_label(GTK_FRAME(cwsound_zone),"CW sound"); gtk_frame_set_label_align(GTK_FRAME(cwsound_zone),0,.5); gtk_widget_set_sensitive(cwsound_zone,local_do_snddev_output?TRUE:FALSE); gtk_table_attach(GTK_TABLE(table),cwsound_zone,2,3,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_container_add(GTK_CONTAINER(cwsound_zone),align_wdg); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox); button=gtk_radio_button_new_with_label(NULL,"beeps"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), local_cwsound==0?TRUE:FALSE); gtk_signal_connect(GTK_OBJECT(button),"clicked", G_CALLBACK(button_changed), (gpointer)CWSOUND_BEEPS_RADIO_BUTTON); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); button=gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(button),"sounder clicks"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), local_cwsound==1?TRUE:FALSE); gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,TRUE,0); /* Create a vbox to contain the "debounce" and "recv_buffering" spinners, inside an alignment widget, inside the table */ align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_table_attach(GTK_TABLE(table),align_wdg,3,4,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox); /* Create the "debounce" spinner inside an alignment widget inside the vbox */ key_debounce_zone=gtk_alignment_new(.5,.5,0,0); gtk_widget_set_sensitive(key_debounce_zone,local_do_key_input?TRUE:FALSE); gtk_box_pack_start(GTK_BOX(vbox),key_debounce_zone,TRUE,TRUE,5); vbox2=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(key_debounce_zone),vbox2); label=gtk_label_new("Key debounce"); gtk_misc_set_alignment(GTK_MISC(label),0,0.5); gtk_box_pack_start(GTK_BOX(vbox2),label,FALSE,TRUE,0); adj=(GtkAdjustment *)gtk_adjustment_new(local_debounce,1,15,1,1,0); spinner=gtk_spin_button_new(adj,0.1,0); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinner),FALSE); g_signal_connect(G_OBJECT(adj),"value_changed", G_CALLBACK(debounce_changed),(gpointer)spinner); gtk_box_pack_start(GTK_BOX(vbox2),spinner,FALSE,TRUE,0); /* Create the "recv buffering" spinner inside an alignment widget inside the vbox */ align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_box_pack_start(GTK_BOX(vbox),align_wdg,TRUE,TRUE,5); vbox2=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox2); label=gtk_label_new("Recv buffering"); gtk_misc_set_alignment(GTK_MISC(label),0,0.5); gtk_box_pack_start(GTK_BOX(vbox2),label,FALSE,TRUE,0); adj=(GtkAdjustment *)gtk_adjustment_new(local_recv_buffering, 100,3000,100,500,0); spinner=gtk_spin_button_new(adj,0.1,0); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinner),FALSE); g_signal_connect(G_OBJECT(adj),"value_changed", G_CALLBACK(recv_buffering_changed),(gpointer)spinner); gtk_box_pack_start(GTK_BOX(vbox2),spinner,FALSE,TRUE,0); /* Create a vbox to contain the sound device and serial device lines, inside an alignment widget, inside the table */ align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_table_attach(GTK_TABLE(table),align_wdg,4,5,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(align_wdg),vbox); /* Create the sound device entry, inside an alignment widget, inside the vbox */ sound_device_zone=gtk_alignment_new(.5,.5,0,0); gtk_widget_set_sensitive(sound_device_zone,local_do_snddev_output? TRUE:FALSE); gtk_box_pack_start(GTK_BOX(vbox),sound_device_zone,TRUE,TRUE,5); vbox2=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(sound_device_zone),vbox2); label=gtk_label_new("Sound device"); gtk_misc_set_alignment(GTK_MISC(label),0,0.5); gtk_box_pack_start(GTK_BOX(vbox2),label,FALSE,TRUE,0); snddev_text_entry=gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(snddev_text_entry),TRUE); gtk_entry_set_max_length(GTK_ENTRY(snddev_text_entry),FILENAME_MAX-1); gtk_entry_set_text(GTK_ENTRY(snddev_text_entry),sharedmem->snddev); gtk_box_pack_start(GTK_BOX(vbox2),snddev_text_entry,FALSE,TRUE,0); /* Create the serial device entry, inside an alignment widget, inside the vbox */ serial_device_zone=gtk_alignment_new(.5,.5,0,0); gtk_widget_set_sensitive(serial_device_zone,local_do_key_input || local_do_sounder_output?TRUE:FALSE); gtk_box_pack_start(GTK_BOX(vbox),serial_device_zone,TRUE,TRUE,5); vbox2=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(serial_device_zone),vbox2); label=gtk_label_new("Serial device"); gtk_misc_set_alignment(GTK_MISC(label),0,0.5); gtk_box_pack_start(GTK_BOX(vbox2),label,FALSE,TRUE,0); serialdev_text_entry=gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(serialdev_text_entry),TRUE); gtk_entry_set_max_length(GTK_ENTRY(serialdev_text_entry),FILENAME_MAX-1); gtk_entry_set_text(GTK_ENTRY(serialdev_text_entry),sharedmem->serialdev); gtk_box_pack_start(GTK_BOX(vbox2),serialdev_text_entry,FALSE,TRUE,0); /* Create a save/change button inside an alignment widget, inside the table */ align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_table_attach(GTK_TABLE(table),align_wdg,5,6,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); button=gtk_button_new_with_label("Change/Save"); g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(button_changed),(gpointer)IO_CONFIG_SAVE_BUTTON); gtk_container_add(GTK_CONTAINER(align_wdg),button); /* Create the sixth (or seventh) page of the notebook with a table inside */ label=gtk_label_new("About"); table=gtk_table_new(2,1,FALSE); gtk_notebook_append_page(GTK_NOTEBOOK(notebook),table,label); /* Create the title/author label inside the table */ label=gtk_label_new("CWirc " VERSION "\n" "by F8EJF"); gtk_label_set_use_markup(GTK_LABEL(label),TRUE); gtk_table_attach(GTK_TABLE(table),label,1,2,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); /* Create the general information label inside the table */ label=gtk_label_new("CWirc - IRC Morse code chat application\n" "Version: " VERSION ", build date: " __DATE__ "\n" "(c) Pierre-Philippe Coupard \n\n" "This program is distributed under the terms of the GNU " "General Public License"); gtk_table_attach(GTK_TABLE(table),label,0,1,0,1, GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,7,7); /* Make the window non-resizable */ gtk_window_set_policy(GTK_WINDOW(wd),FALSE,FALSE,FALSE); /* Show all the widgets and the window */ gtk_widget_show_all(wd); /* Add the periodic timeout */ gtk_timeout_add(20,gtk_timeout,0); /* Enter the main GTK loop */ gtk_main(); /* Save the current settings in the configuration file */ cwirc_save_rcfile(RCFILE); return(0); } /* GTK callback to handle the "delete_event" signals */ static gboolean gtk_delete_event(GtkWidget *wdg,GdkEvent *ev,gpointer data) { /* Stop the frontend */ sharedmem->stop_frontend=1; return(FALSE); } /* GTK callback to handle the "destroy" signals */ static void gtk_destroy(GtkWidget *wdg,GdkEvent *ev,gpointer data) { /* Stop the frontend */ sharedmem->stop_frontend=1; gtk_main_quit(); } /* GTK callback for when a new preset channel is selected. */ static void current_preset_channel_changed(GtkWidget *wd,gpointer data) { int i; /* Did the user select another preset channel ? */ if((int)data!=sharedmem->currcwchannel) { /* Acquire the semaphore */ if(!cwirc_sem_P(sharedmem->semid,SEM_ST)) { /* If the actual channel changed, clear the reception buffer */ if(sharedmem->cwchannel[(int)data]!=sharedmem->cwchannel[ sharedmem->currcwchannel]) { for(i=0;isender[i].name[0]=0; } /* Change the current preset channel and update the spinner's value */ sharedmem->currcwchannel=(int)data; gtk_adjustment_set_value(GTK_ADJUSTMENT(channel_spinner_adj), sharedmem->cwchannel[sharedmem->currcwchannel]); /* Release the semaphore */ cwirc_sem_V(sharedmem->semid,SEM_ST); } } } /* GTK callback for when the value of the "Channel" spinner changes */ static void channel_changed(GtkWidget *wd,GtkSpinButton *spinner) { int new_chan; int i; new_chan=gtk_spin_button_get_value_as_int(spinner); /* If the channel has changed, clear the reception buffer */ if(new_chan!=sharedmem->cwchannel[sharedmem->currcwchannel]) { /* Acquire the semaphore */ if(!cwirc_sem_P(sharedmem->semid,SEM_ST)) { for(i=0;isender[i].name[0]=0; /* Change the channel */ sharedmem->cwchannel[sharedmem->currcwchannel]=new_chan; /* Release the semaphore */ cwirc_sem_V(sharedmem->semid,SEM_ST); } } } /* GTK callback for when the value of the "RX pitch" scrollbar changes */ static void rxpitch_changed(GtkWidget *wd,GtkRange *scrollbar) { sharedmem->cwrxpitch=gtk_adjustment_get_value( gtk_range_get_adjustment(scrollbar)); } /* GTK callback for when the value of the "TX pitch" scrollbar changes */ static void txpitch_changed(GtkWidget *wd,GtkRange *scrollbar) { sharedmem->cwtxpitch=gtk_adjustment_get_value( gtk_range_get_adjustment(scrollbar)); } /* GTK callback for when the value of the "Squelch" scrollbar changes */ static void squelch_changed(GtkWidget *wd,GtkRange *scrollbar) { sharedmem->squelch=gtk_adjustment_get_value( gtk_range_get_adjustment(scrollbar)); } /* GTK callback for when the value of the "Volume" scrollbar changes */ static void volume_changed(GtkWidget *wd,GtkRange *scrollbar) { sharedmem->volume=gtk_adjustment_get_value( gtk_range_get_adjustment(scrollbar)); } /* GTK callback for when the value of the "QRN level" scrollbar changes */ static void qrnlevel_changed(GtkWidget *wd,GtkRange *scrollbar) { sharedmem->qrnlevel=gtk_adjustment_get_value( gtk_range_get_adjustment(scrollbar)); } /* GTK callback for when the value of the "default signal strength ..." scrollbar changes */ static void default_signal_strength_changed(GtkWidget *wd,GtkRange *scrollbar) { sharedmem->default_signal_strength=gtk_adjustment_get_value( gtk_range_get_adjustment(scrollbar)); } /* GTK callback for when the value of the "WPM" spinner changes */ static void wpm_changed(GtkWidget *wd,GtkSpinButton *spinner) { sharedmem->wpm=gtk_spin_button_get_value_as_int(spinner); } /* GTK callback for when another CW decoder language is selected. */ static void cw_decoder_language_changed(GtkWidget *wd,gpointer data) { if((int)data!=sharedmem->cwcodeset) sharedmem->cwcodeset=(int)data; } /* GTK callback for when the value of the "dit weight" spinner changes */ static void dit_weight_changed(GtkWidget *wd,GtkSpinButton *spinner) { sharedmem->dit_weight=gtk_spin_button_get_value_as_int(spinner); } /* GTK callback for when an extension program has been selected */ static void extension_program_button_clicked(GtkWidget *wd,gpointer data) { char *errmsg; if((errmsg=exec_extension_program(cwirc_extensions[(int)data], extension_shmid))!=NULL) error_popup(errmsg); } /* GTK callback for when the value of the "debounce" spinner changes */ static void debounce_changed(GtkWidget *wd,GtkSpinButton *spinner) { local_debounce=gtk_spin_button_get_value_as_int(spinner); } /* GTK callback for when the value of the "recv_buffering" spinner changes */ static void recv_buffering_changed(GtkWidget *wd,GtkSpinButton *spinner) { local_recv_buffering=gtk_spin_button_get_value_as_int(spinner); } /* GTK callback when any of the panel's simple, toggle or radio button change */ static void button_changed(GtkWidget *wd,gpointer button) { char buf[MAX_NICK_SIZE]; int i,j,k; T_BOOL button_active=0; /* Get the button's state */ if((int)button!=IO_CONFIG_SAVE_BUTTON && (int)button!=PERSONAL_INFO_SAVE_BUTTON && (int)button!=DECODER_RESET_BUTTON) button_active=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wd))?1:0; /* What button was clicked ? */ switch((int)button) { case IAMBIC_RADIO_BUTTON: /* The "iambic" toggle changed state. Since "iambic" is the negation of "straight" in our toggle buttons pair, we don't watch "straight". */ sharedmem->doiambic=button_active; gtk_widget_set_sensitive(iambic_keyer_zone,button_active?TRUE:FALSE); gtk_widget_set_sensitive(keyer_settings_zone,button_active?TRUE:FALSE); gdk_draw_drawable(morsekey_drawingarea->window,morsekey_gc, button_active?iambickey_bg_pixmap:straightkey_bg_pixmap, 0,0,0,0,morsekey_width,morsekey_height); break; case DECODER_RESET_BUTTON: sharedmem->reset_decoder=1; break; case MODEB_TOGGLE_BUTTON: /* The "mode-B" radio button changes state. Since "mode-A" is the negation of "mode-B" in our toggle buttons pair, we don't watch "mode-A" */ sharedmem->iambicmode=button_active?1:0; gtk_widget_set_sensitive(midelementmodeB_button,button_active?TRUE:FALSE); break; case DITMEMORY_TOGGLE_BUTTON: /* The "dit memory" toggle changed state */ sharedmem->do_ditmemory=button_active; break; case DAHMEMORY_TOGGLE_BUTTON: /* The "dah memory" toggle changed state */ sharedmem->do_dahmemory=button_active; break; case MIDELEMENTMODEB_TOGGLE_BUTTON: /* The "mid-element mode-B" toggle changed state */ sharedmem->do_midelementmodeB=button_active; break; case AUTOCHARSPACING_TOGGLE_BUTTON: /* The "auto character spacing" toggle changed state. */ sharedmem->do_autocharspacing=button_active; gtk_widget_set_sensitive(autowordspacing_button,button_active?TRUE:FALSE); break; case AUTOWORDSPACING_TOGGLE_BUTTON: /* The "auto word spacing" toggle changed state. */ sharedmem->do_autowordspacing=button_active; break; case INVERTPADDLES_TOGGLE_BUTTON: /* The "invert paddles" toggle changed state. */ sharedmem->invertpaddles=button_active; break; case MOUSEINPUT_TOGGLE_BUTTON: /* The "mouse" toggle changed state. */ if(button_active) { local_do_mouse_input=1; local_do_key_input=0; gtk_widget_set_sensitive(key_debounce_zone,FALSE); gtk_widget_set_sensitive(serial_device_zone,local_do_sounder_output? TRUE:FALSE); } break; case KEYINPUT_TOGGLE_BUTTON: /* The "real key" toggle changed state. */ if(button_active) { local_do_mouse_input=0; local_do_key_input=1; gtk_widget_set_sensitive(key_debounce_zone,TRUE); gtk_widget_set_sensitive(serial_device_zone,TRUE); } break; case BOTHINPUT_TOGGLE_BUTTON: /* The "both" (input) toggle changed state. */ if(button_active) { local_do_mouse_input=1; local_do_key_input=1; gtk_widget_set_sensitive(key_debounce_zone,TRUE); gtk_widget_set_sensitive(serial_device_zone,TRUE); } break; case SNDDEVOUTPUT_TOGGLE_BUTTON: /* The "soundcard" toggle changed state. */ if(button_active) { local_do_snddev_output=1; local_do_sounder_output=0; gtk_widget_set_sensitive(sound_device_zone,TRUE); gtk_widget_set_sensitive(serial_device_zone,local_do_key_input? TRUE:FALSE); gtk_widget_set_sensitive(cwsound_zone,TRUE); } break; case SOUNDEROUTPUT_TOGGLE_BUTTON: /* The "sounder" toggle changed state. */ if(button_active) { local_do_snddev_output=0; local_do_sounder_output=1; gtk_widget_set_sensitive(sound_device_zone,FALSE); gtk_widget_set_sensitive(serial_device_zone,TRUE); gtk_widget_set_sensitive(cwsound_zone,FALSE); } break; case BOTHOUTPUT_TOGGLE_BUTTON: /* The "both" (output) toggle changed state. */ if(button_active) { local_do_snddev_output=1; local_do_sounder_output=1; gtk_widget_set_sensitive(sound_device_zone,TRUE); gtk_widget_set_sensitive(serial_device_zone,TRUE); gtk_widget_set_sensitive(cwsound_zone,TRUE); } break; case CWSOUND_BEEPS_RADIO_BUTTON: /* The "beeps" toggle changed state. Since "sounder clicks" is the negation of "beeps" in our toggle buttons pair, we don't watch "sounder clicks".*/ local_cwsound=button_active?0:1; break; case IO_CONFIG_SAVE_BUTTON: /* The "Save/Change" button (I/O config) was pressed : */ /* Acquire semaphore to prevent reconfiguring I/O process while it works*/ cwirc_sem_P(sharedmem->semid,SEM_IO_PROCESS_WORKING); /* Install the new settings "live" */ sharedmem->do_mouse_input=local_do_mouse_input; sharedmem->do_key_input=local_do_key_input; sharedmem->do_snddev_output=local_do_snddev_output; sharedmem->cwsound=local_cwsound; sharedmem->do_sounder_output=local_do_sounder_output; sharedmem->debounce=local_debounce; sharedmem->recv_buffering=local_recv_buffering; strncpy(sharedmem->snddev, gtk_entry_get_text(GTK_ENTRY(snddev_text_entry)),FILENAME_MAX); sharedmem->snddev[FILENAME_MAX-1]=0; strncpy(sharedmem->serialdev, gtk_entry_get_text(GTK_ENTRY(serialdev_text_entry)),FILENAME_MAX); sharedmem->serialdev[FILENAME_MAX-1]=0; /* Tell the I/O process to reconfigure itself */ sharedmem->reconfigure_io_process=1; /* Release semaphore to prevent reconfiguring I/O process while it works*/ cwirc_sem_V(sharedmem->semid,SEM_IO_PROCESS_WORKING); /* Save the settings in the configuration file */ cwirc_save_rcfile(RCFILE); break; case REPLY_TO_CTCP_TOGGLE_BUTTON: /* The "reply to CTCP queries" button was pressed */ local_reply_to_ctcp=button_active; gtk_widget_set_sensitive(ctcp_params_zone,button_active?TRUE:FALSE); if(button_active) gtk_widget_set_sensitive(callsign_zone,local_give_callsign_in_ctcp_reply? TRUE:local_send_callsign_with_cw?TRUE:FALSE); else gtk_widget_set_sensitive(callsign_zone,local_send_callsign_with_cw? TRUE:FALSE); break; case GIVE_CALLSIGN_IN_CTCP_REPLY_TOGGLE_BUTTON: /* The "send callsign in CTCP reply" toggle changed state */ local_give_callsign_in_ctcp_reply=button_active; if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wd))) gtk_widget_set_sensitive(callsign_zone,TRUE); else gtk_widget_set_sensitive(callsign_zone,local_send_callsign_with_cw? TRUE:FALSE); break; case GIVE_GRIDSQUARE_IN_CTCP_REPLY_TOGGLE_BUTTON: /* The "send grid square in CTCP reply" toggle changed state */ local_give_gridsquare_in_ctcp_reply=button_active; break; case GIVE_CWCHANNEL_IN_CTCP_REPLY_TOGGLE_BUTTON: /* The "send current channel in CTCP reply" toggle changed state */ local_give_cwchannel_in_ctcp_reply=button_active; break; case SEND_CALLSIGN_WITH_CW_TOGGLE_BUTTON: /* The "send callsign with CW" toggle changed state */ local_send_callsign_with_cw=button_active; if(button_active) gtk_widget_set_sensitive(callsign_zone,TRUE); else gtk_widget_set_sensitive(callsign_zone,local_reply_to_ctcp && local_give_callsign_in_ctcp_reply?TRUE:FALSE); break; case SEND_GRIDSQUARE_WITH_CW_TOGGLE_BUTTON: /* The "send grid square with CW" toggle changed state */ local_send_gridsquare_with_cw=button_active; break; case SIMULATE_QRN_TOGGLE_BUTTON: /* The "simulate QRN" button changed state */ sharedmem->simulate_qrn=button_active; break; case SIMULATE_SIGNAL_STRENGTH_TOGGLE_BUTTON: /* The "simulate signal strength ..." toggle changed state */ sharedmem->simulate_signal_strength=button_active; gtk_widget_set_sensitive(simulate_sporadicE_zone,button_active?TRUE:FALSE); gtk_widget_set_sensitive(default_signal_strength_zone1,button_active? TRUE:FALSE); gtk_widget_set_sensitive(default_signal_strength_zone2,button_active? TRUE:FALSE); break; case SIMULATE_SPORADICE_TOGGLE_BUTTON: /* The "simulate sporadic-E ..." toggle changed state */ sharedmem->simulate_sporadicE=button_active; break; case PERSONAL_INFO_SAVE_BUTTON: /* The "Save/Change" button (personal info) was pressed : */ /* Install the new settings "live" */ sharedmem->reply_to_ctcp=local_reply_to_ctcp; sharedmem->give_callsign_in_ctcp_reply=local_give_callsign_in_ctcp_reply; sharedmem->give_gridsquare_in_ctcp_reply= local_give_gridsquare_in_ctcp_reply; sharedmem->give_cwchannel_in_ctcp_reply=local_give_cwchannel_in_ctcp_reply; sharedmem->send_callsign_with_cw=local_send_callsign_with_cw; sharedmem->send_gridsquare_with_cw=local_send_gridsquare_with_cw; /* Acquire semaphore to access the personal info */ cwirc_sem_P(sharedmem->semid,SEM_PERSONAL_INFO); /* Force callsign to be upper-case and containing only approved characters*/ strncpy(buf,gtk_entry_get_text(GTK_ENTRY(callsign_text_entry)), MAX_NICK_SIZE); buf[MAX_NICK_SIZE-1]=0; k=strlen(buf); sharedmem->callsign[0]=0; for(i=j=0;i='!' && buf[i]!=',' && buf[i]<='}') { sharedmem->callsign[j++]=toupper(buf[i]); sharedmem->callsign[j]=0; } /* Force the formatted callsign back to the text entry */ gtk_entry_set_text(GTK_ENTRY(callsign_text_entry),sharedmem->callsign); /* Check the grid square */ strncpy(buf,gtk_entry_get_text(GTK_ENTRY(gridsquare_text_entry)), MAX_GRIDSQUARE_SIZE); if(!buf[0] || cwirc_is_grid_square(buf)) { /* Force the grid square to be upper-case */ k=strlen(buf); for(i=0;igridsquare[i]=toupper(buf[i]); sharedmem->gridsquare[i]=0; } /* Force the formatted grid square back to the text entry */ gtk_entry_set_text(GTK_ENTRY(gridsquare_text_entry),sharedmem->gridsquare); /* Release semaphore to prevent reconfiguring I/O process while it works*/ cwirc_sem_V(sharedmem->semid,SEM_PERSONAL_INFO); /* Save the settings in the configuration file */ cwirc_save_rcfile(RCFILE); /* Change the sensitivity and title of the propagation simulation zone in case a valid grid square was given */ gtk_widget_set_sensitive(propag_sim_zone,sharedmem->gridsquare[0]? TRUE:FALSE); gtk_frame_set_label(GTK_FRAME(propag_sim_zone),sharedmem->gridsquare[0]? "Propagation simulation": "Propagation simulation [needs the grid square to be set]"); break; } } /* Configure event callback for the S-meter */ static gboolean smeter_configure_event(GtkWidget *wdg,GdkEventConfigure *ev) { draw_smeter(signal_strength,1); return(TRUE); } /* Expose event callback for the S-meter */ static gboolean smeter_expose_event(GtkWidget *wdg,GdkEventExpose *ev) { return(smeter_configure_event(wdg,(GdkEventConfigure *)ev)); } /* Mouse button press event callback for the S-meter */ static gboolean smeter_pressed_event(GtkWidget *wdg,GdkEventButton *ev) { if(ev->type==GDK_BUTTON_PRESS) /* Filter out double-clicks here */ { sharedmem->sidetone_mode=!sharedmem->sidetone_mode; draw_smeter(signal_strength,1); } return(TRUE); } /* Configure event callback for the "morse key icon" */ static gboolean morsekey_configure_event(GtkWidget *wdg,GdkEventConfigure *ev) { gdk_draw_drawable(morsekey_drawingarea->window,morsekey_gc, sharedmem->doiambic?iambickey_bg_pixmap:straightkey_bg_pixmap, 0,0,0,0,morsekey_width,morsekey_height); return(TRUE); } /* Expose event callback for the "morse key icon" */ static gboolean morsekey_expose_event(GtkWidget *wdg,GdkEventExpose *ev) { return(morsekey_configure_event(wdg,(GdkEventConfigure *)ev)); } /* Mouse button press event callback for the "morse key icon" */ static gboolean morsekey_pressed_event(GtkWidget *wdg,GdkEventButton *ev) { if(ev->type==GDK_BUTTON_PRESS) /* Filter out double-clicks here */ { if(ev->button==1) sharedmem->mouseinputbutton0=1; else sharedmem->mouseinputbutton1=1; } return(TRUE); } /* Mouse button release event callback for the "morse key icon" */ static gboolean morsekey_released_event(GtkWidget *wdg,GdkEventButton *ev) { if(ev->button==1) sharedmem->mouseinputbutton0=0; else sharedmem->mouseinputbutton1=0; return(TRUE); } /* Draw the S-meter (value is 0 -> 100). If full_refresh is asserted, the entire S-meter area is redrawn. Otherwise, only the space occupied by the previous needle is redrawn. */ static void draw_smeter(int value,T_BOOL full_refresh) { static int pn_x,pn_y,pn_w,pn_h; static T_U8 x1[101],y1[101],x2[101],y2[101]; static int i=1; /* Is this the first call to this function ? */ if(i) { full_refresh=1; /* Make sure we start off by drawing everything */ /* Precalculate the needle line coordinates for all possible meter values */ for(i=0;i<=100;i++) calculate_smeter_needle_coordinates(i,&x1[i],&y1[i],&x2[i],&y2[i]); i=0; } /* Do we do a full refresh, or is it the first time we're called ? */ if(full_refresh) { pn_x=0; pn_y=0; pn_w=smeter_width; pn_h=smeter_height; } /* Make sure the value is bound */ if(value>100) value=100; /* Draw the background image first, or the part of it necessary to cover the previous needle */ gdk_draw_drawable(smeter_drawingarea->window,smeter_gc, sharedmem->sidetone_mode?sidetone_bg_pixmap:smeter_bg_pixmap, pn_x,pn_y,pn_x,pn_y,pn_w,pn_h); /* Draw the new needle on top of the background image */ gdk_draw_line(smeter_drawingarea->window,smeter_gc,x1[value],y1[value], x2[value],y2[value]); /* Calculate the coordinates of the smallest box that covers the line */ if(x1[value]<=x2[value]) { pn_x=x1[value]-1; pn_w=x2[value]-x1[value]+3; } else if(x1[value]>x2[value]) { pn_x=x2[value]-1; pn_w=x1[value]-x2[value]+3; } pn_y=y2[value]; pn_h=y1[value]-y2[value]; } /* Calculate the coordinates of the S-meter's needle within the S-meter box given the meter's value */ static void calculate_smeter_needle_coordinates(int value,T_U8 *x1,T_U8 *y1, T_U8 *x2,T_U8 *y2) { double nr_rad; double angle; int nl; int ncx,ncy,ntx,nty; int x,y,w,h; w=smeter_width; h=smeter_height; x=w/2; y=(h+SMETER_ARC_DOWN_OFFSET)/2; /* Calculate the needle range in radians */ nr_rad=(SMETER_NEEDLE_RANGE*M_PI)/180; /* Calculate the needle's length in the S-meter rectangle */ nl=w/(2*tan(nr_rad/2)*cos(nr_rad/2)); /* Calculate the angle of the needle with the given value */ angle=((50-value)*nr_rad)/100+M_PI_2; /* Calculate the coordinates of the needle's ends in the S-meter rectangle */ ncx=0; ncy=h-nl; ntx=nl*cos(angle); nty=ncy+nl*sin(angle); /* Calculate where the needle intersects with the absissa in the rectangle box, so we clip what's below it and that's not supposed to be visible */ if(nl>h) { ncx=((ncx+ntx)*(nl-h))/nl; ncy=0; } /* Calculate the final line's endpoints' coordinates */ *x1=x+ncx; *y1=y+h/2-ncy; *x2=x+(ntx*.8); *y2=y+h/2-(nty*.8); } /* Make an error popup with a message and an OK button */ static void error_popup(char *message) { /* Create the popup window */ popup_wd=gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(popup_wd),"Error"); label=gtk_label_new(message); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(popup_wd)->vbox),label,TRUE,TRUE,0); align_wdg=gtk_alignment_new(.5,.5,0,0); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(popup_wd)->action_area),align_wdg, TRUE,TRUE,0); button=gtk_button_new_with_label("Okay"); gtk_signal_connect_object(GTK_OBJECT(button),"clicked", G_CALLBACK(gtk_widget_destroy),GTK_OBJECT(popup_wd)); gtk_container_add(GTK_CONTAINER(align_wdg),button); gtk_widget_show_all(popup_wd); } /* GTK timeout callback : this is were we update the S-meter, the automatic decoder line and watch for external orders to stop the frontend. */ static gint gtk_timeout(gpointer data) { char wpm[9]; /* Check if we have a message from the I/O process */ if(!cwirc_sem_P(sharedmem->semid,SEM_IO_PROCESS_MSG)) /* Acquire semaphore */ { if(sharedmem->io_process_msg[0]) { error_popup(sharedmem->io_process_msg); sharedmem->io_process_msg[0]=0; } /* Release the semaphore */ cwirc_sem_V(sharedmem->semid,SEM_IO_PROCESS_MSG); } /* Do we need to stop the gui ? */ if(sharedmem->stop_frontend) { gtk_main_quit(); return(FALSE); } /* Emulate the S-meter */ signal_strength_prev=signal_strength; signal_strength=(signal_strength+sharedmem->recv_signal)/2; if(signal_strength!=signal_strength_prev) draw_smeter(signal_strength,0); /* Has the decoded morse line been updated ? */ if(sharedmem->decoded_msg_updated) { /* Update the decoded morse line */ gtk_entry_set_text(GTK_ENTRY(decoder_text_entry), sharedmem->decoded_msg_buf); gtk_editable_set_position(GTK_EDITABLE(decoder_text_entry),-1); /* Update the WPM label */ if(sharedmem->decoded_msg_wpm>-1) sprintf(wpm,"%.0f WPM",sharedmem->decoded_msg_wpm); else sprintf(wpm,"? WPM"); gtk_label_set_text(GTK_LABEL(decoder_wpm_label),wpm); sharedmem->decoded_msg_updated=0; } return(TRUE); } cwirc-2.0.0.orig/keyer.c0000644000175000017500000001245210062722444013337 0ustar pg4ipg4i/* CWirc - X-Chat plugin for sending and receiving raw morse code over IRC (c) Pierre-Philippe Coupard - 18/06/2003 Iambic keyer implementation This program is distributed under the terms of the GNU General Public License See the COPYING file for details */ #include "types.h" #include "keyer.h" /* Definitions */ #define NO_TIMEOUTS_SCHED -2 #define NO_ELEMENT -1 #define DIT 0 #define DAH 1 #define MODE_A 0 #define MODE_B 1 #define NO_PADDLE_SQUEEZE 0 #define PADDLES_SQUEEZED 1 #define PADDLES_RELEASED 2 #define NO_DELAY 0 #define CHAR_SPACING_DELAY 1 #define WORD_SPACING_DELAY 2 /* Implement the keyer. Ticklen is the time interval in ms between 2 calls to the function. Return the state of the keyer-generated "straight key" */ T_BOOL cwirc_run_keyer(struct cwirc_keyer_state *is,T_BOOL dit,T_BOOL dah, int wpm,int iambicmode,T_BOOL midelementmodeB,T_BOOL ditmemory, T_BOOL dahmemory,T_BOOL autocharspacing,T_BOOL autowordspacing, int weight,double ticklen) { double ditlen=1200/(double)wpm; int set_element_timeouts=NO_TIMEOUTS_SCHED; /* Do we need to initialize the keyer ? */ if(!is->keyer_initialized) { is->prev_dit=dit; is->prev_dah=dah; is->last_element=is->current_element=NO_ELEMENT; is->iambic_in_element=NO_PADDLE_SQUEEZE; is->paddles_squeezed_after_mid_element=0; is->insert_inverted_element=0; is->mid_element_timeout=is->beep_timeout=is->element_timeout=0; is->delay_timeout=0; is->delay_type=NO_DELAY; is->keyer_initialized=1; } /* Decrement the timeouts */ is->delay_timeout-=is->delay_timeout>0?ticklen:0; if(is->delay_timeout<=0) { /* If nothing is scheduled to play, and we just did a character spacing delay, and we do auto word spacing, wait for a word spacing delay, otherwise resume the normal element timeout countdowns */ if(is->element_timeout<=0 && is->delay_type==CHAR_SPACING_DELAY && autowordspacing) { is->delay_timeout=ditlen*4; is->delay_type=WORD_SPACING_DELAY; } else { is->delay_type=NO_DELAY; is->mid_element_timeout-=is->mid_element_timeout>0?ticklen:0; is->beep_timeout-=is->beep_timeout>0?ticklen:0; is->element_timeout-=is->element_timeout>0?ticklen:0; } } /* Are both paddles squeezed ? */ if(dit && dah) { is->iambic_in_element=PADDLES_SQUEEZED; /* Are the paddles squeezed past the middle of the element ? */ if(is->mid_element_timeout<=0) is->paddles_squeezed_after_mid_element=1; } else /* Are both paddles released and we had gotten a squeeze in this element ?*/ if(!dit && !dah && is->iambic_in_element==PADDLES_SQUEEZED) is->iambic_in_element=PADDLES_RELEASED; /* Is the current element finished ? */ if(is->element_timeout<=0 && is->current_element!=NO_ELEMENT) { is->last_element=is->current_element; /* Should we insert an inverted element ? */ if(((dit && dah) || (is->insert_inverted_element && is->iambic_in_element!= PADDLES_RELEASED) || (is->iambic_in_element==PADDLES_RELEASED && iambicmode==MODE_B && (!midelementmodeB || is->paddles_squeezed_after_mid_element)) ) ) { if(is->last_element==DAH) set_element_timeouts=is->current_element=DIT; else set_element_timeouts=is->current_element=DAH; } else { /* No more element */ is->current_element=NO_ELEMENT; /* Do we do automatic character spacing ? */ if(autocharspacing && !dit && !dah) { is->delay_timeout=ditlen*2; is->delay_type=CHAR_SPACING_DELAY; } } is->insert_inverted_element=0; is->iambic_in_element=NO_PADDLE_SQUEEZE; is->paddles_squeezed_after_mid_element=0; } /* Is an element currently being played ? */ if(is->current_element==NO_ELEMENT) { if(dah) /* Dah paddle down ? */ set_element_timeouts=is->current_element=DAH; else if(dit) /* Dit paddle down ? */ set_element_timeouts=is->current_element=DIT; } /* Do the dah memory */ if(is->current_element==DIT && !is->prev_dah && dah && dahmemory) is->insert_inverted_element=1; /* Do the dit memory */ if(is->current_element==DAH && !is->prev_dit && dit && ditmemory) is->insert_inverted_element=1; /* If we had a dit (or dah) scheduled to be played after a delay, and the operator lifted both paddles before the end of the delay, and we have no dit (or dah) memory, forget it */ if(is->delay_timeout>0 && !dit && !dah && ( (is->current_element==DIT && !ditmemory) || (is->current_element==DAH && !dahmemory) )) set_element_timeouts=is->current_element=NO_ELEMENT; /* Do we need to set the playing timeouts of an element? */ switch(set_element_timeouts) { case NO_ELEMENT: /* Cancel any dit or dah */ is->beep_timeout=0; is->mid_element_timeout=0; is->element_timeout=0; break; case DIT: /* Schedule a dit ? */ is->beep_timeout=(ditlen*(double)weight)/50; is->mid_element_timeout=is->beep_timeout/2; is->element_timeout=ditlen*2; break; case DAH: /* Schedule a dah ? */ is->beep_timeout=(ditlen*(double)weight)/50 + ditlen*2; is->mid_element_timeout=is->beep_timeout/2; is->element_timeout=ditlen*4; break; } is->prev_dit=dit; is->prev_dah=dah; return(is->beep_timeout>0 && is->delay_timeout<=0?1:0); } cwirc-2.0.0.orig/io.c0000644000175000017500000007663410100602032012622 0ustar pg4ipg4i/* CWirc - X-Chat plugin for sending and receiving raw morse code over IRC (c) Pierre-Philippe Coupard - 18/06/2003 I/O routines This program is distributed under the terms of the GNU General Public License See the COPYING file for details */ #include #include #include #include #include #include #include #include #include #ifdef NETBSD #include #else #include #endif #ifdef LINUX #include #endif #include "types.h" #include "io.h" #include "cwirc.h" #include "keyer.h" #include "cwsound.h" #include "cwdecoder.h" #include "propagation.h" #include "extension.h" #include "ipc.h" /* Definitions */ #define DSR_LINE_CLOSED_KEY 1 #define CTS_LINE_CLOSED_KEY 1 #define DTR_LINE_SET 0 #define RTS_LINE_SET 0 #define BASE_BEEP_FREQ 1100 /* Hz */ #define DSP_SAMPLE_FREQ 44100 #define DSP_STEREO 1 #define DSP_16BITS 1 #define DSP_FRAG_SIZE 8 /* bytes, in power of 2 */ #define DSP_FRAG_BUFFER 25 /* Prebuffered fradments */ #define BYTES_PER_FRAG (1<stop_frontend) { /* If we're in error, twiddle our thumbs until we're told to reconfigure */ if(process_in_error && !sharedmem->reconfigure_io_process) { /* Clear the reception buffer (don't allow it to fill up since we're not emptying it) */ if(!cwirc_sem_P(sharedmem->semid,SEM_ST)) /* Acquire the semaphore */ { for(i=0;isender[i].name[0]=0; /* Release the semaphore */ cwirc_sem_V(sharedmem->semid,SEM_ST); } usleep(200000); continue; } process_in_error=0; sharedmem->reconfigure_io_process=0; /* Do we output to a sound device ? */ if(sharedmem->do_snddev_output) { /* Open the sound device */ if((errormsg=open_snd_dev(sharedmem->snddev))!=NULL) { send_errmsg("Error : %s\n",errormsg); cleanup(); process_in_error=1; continue; } ticklen=((double)1000*(double)SAMPLES_PER_TICK)/(double)DSP_SAMPLE_FREQ; samples_per_tick=SAMPLES_PER_TICK; } else { /* Open the rtc instead, to give us a nice fast timing device */ if((errormsg=open_rtc_dev())!=NULL) { send_errmsg("Error : %s\n",errormsg); cleanup(); process_in_error=1; continue; } /* Enable the RTC periodic interrupt */ if(!sharedmem->do_snddev_output && enable_rtc_interrupts()) { close_rtc_dev(); send_errmsg("Error enabling real-time clock periodic interrupts.\n"); process_in_error=1; continue; } ticklen=(double)1000/(double)RTC_RATE; real_samples_per_tick=(double)DSP_SAMPLE_FREQ/(double)RTC_RATE; rounded_samples_per_tick=real_samples_per_tick; samples_per_tick_fraction=real_samples_per_tick- (double)rounded_samples_per_tick; samples_per_tick_drift=0; } /* Open the serial port if we need to */ if((sharedmem->do_key_input || sharedmem->do_sounder_output) && (errormsg=open_serial_dev(sharedmem->serialdev))!=NULL) { send_errmsg("Error : %s\n",errormsg); cleanup(); process_in_error=1; continue; } /* Main loop */ while(!sharedmem->reconfigure_io_process && !process_in_error && !sharedmem->stop_frontend) { /* Are we paced only by the RTC device ? */ if(!sharedmem->do_snddev_output) { /* Recalculate the apparent samples per tick value to compensate for the fact that the real number of samples per tick isn't exact, so that we generate sound samples for an extension program that doesn't lag over time */ if(samples_per_tick_drift>=1) { samples_per_tick_drift-=1; samples_per_tick=rounded_samples_per_tick+1; } else samples_per_tick=rounded_samples_per_tick; samples_per_tick_drift+=samples_per_tick_fraction; } /* Initialize the sound buffer */ remote_signals_snd_total_weight=0; for(i=0;isemid,SEM_IO_PROCESS_WORKING)) { /* Acquire the semaphore to access the senders table */ if(!cwirc_sem_P(sharedmem->semid,SEM_ST)) { for(i=0;isender[i].name[0]) { /* Calculate the sender's signal strength */ sender_signal_strength=(sharedmem->simulate_signal_strength && sharedmem->gridsquare[0])? (sharedmem->sender[i].signal_strength>=0? sharedmem->sender[i].signal_strength: (double)sharedmem->default_signal_strength/100):1; /* Simulate sporadic-E */ if(sharedmem->simulate_sporadicE) cwirc_simulate_sporadicE(&sender_signal_strength,ticklen); /* If playback start timeout hasn't reached 0 yet, decrease it. */ if(sharedmem->sender[i].playback_start_timeout>0) { sharedmem->sender[i].playback_start_timeout-=ticklen; if(sharedmem->sender[i].playback_start_timeout>0) { /* Maintain the sender's signal strength to 0 or whatever it was when it started to fade out so we don't get a sudden rise of background signal if we have a short buffer underrun for that sender */ remote_signals_snd_total_weight+=sender_signal_strength * (sharedmem->sender[i].playback_stop_timeout/ SENDER_SIGNAL_FADEOUT_DELAY); } else sharedmem->sender[i].playback_stop_timeout=0; } /* If the playback stop timeout hasn't reached 0 yet, decrease it, fade out the sender's signal and remove the sender when the timeout reaches 0 */ else if(sharedmem->sender[i].playback_stop_timeout>0) { sharedmem->sender[i].playback_stop_timeout-=ticklen; if(sharedmem->sender[i].playback_stop_timeout<=0) sharedmem->sender[i].name[0]=0; /* Remove sender */ remote_signals_snd_total_weight+=sender_signal_strength * (sharedmem->sender[i].playback_stop_timeout/ SENDER_SIGNAL_FADEOUT_DELAY); } else /* We can consume this sender's events */ { /* Bias the beep frequency according to the RX pitch, and the sender's name and so the listener can discriminate between several senders.*/ for(j=k=0;jsender[i].name);j++) k+=sharedmem->sender[i].name[j]; k/=strlen(sharedmem->sender[i].name); beep_freq=BASE_BEEP_FREQ+(sharedmem->cwrxpitch*20)- (((signed int)sharedmem->sender[i].name[0])-80)*5; /* If the sender's key changed state, reset the current keyup or keydown tick counter */ if(sharedmem->sender[i].keystate[sharedmem->sender[i]. buf_head] && !sharedmem->sender[i].keystate_prev) sharedmem->sender[i].keydown_tickcnt=0; if(!sharedmem->sender[i].keystate[sharedmem->sender[i]. buf_head] && sharedmem->sender[i].keystate_prev) sharedmem->sender[i].keyup_tickcnt=0; /* Add the sender's signal to the existing ones */ generate_cw_sound_fragment(sharedmem->cwsound, sharedmem->sender[i].keystate_prev,sharedmem-> sender[i].keystate[sharedmem->sender[i].buf_head], DSP_SAMPLE_FREQ,samples_per_tick,beep_freq, sender_signal_strength*100,sharedmem->sender[i]. keyup_tickcnt,sharedmem->sender[i].keydown_tickcnt, sndbuf); for(j=0;jsender[i].keyup_tickcnt+=samples_per_tick; sharedmem->sender[i].keydown_tickcnt+=samples_per_tick; sharedmem->sender[i].keystate_prev=sharedmem->sender[i]. keystate[sharedmem->sender[i].buf_head]; /* If the sender's key if down, add the sender's signal strength to the total signal strength */ if(sharedmem->sender[i].keystate[sharedmem->sender[i].buf_head]) { total_signal_strength+=sender_signal_strength; /* Only register this remote key if the sender's signal is at least S+1 above S0 or the QRN floor */ if(sender_signal_strength*100-(sharedmem->simulate_qrn? sharedmem->qrnlevel:0) > 5) remote_keys=1; } /* Decrease the delay counter of the sender */ sharedmem->sender[i].kcdelay[sharedmem->sender[i].buf_head]-= ticklen; while(sharedmem->sender[i].kcdelay[sharedmem->sender[i]. buf_head]<=0) { /* Move the sender's buffer head to the next delay counter*/ j=sharedmem->sender[i].buf_head; if((++sharedmem->sender[i].buf_head)==MAX_EVT_BUFFER) sharedmem->sender[i].buf_head=0; /* If buffer is empty, start sender playback stop timeout */ if(sharedmem->sender[i].kcdelay[sharedmem->sender[i]. buf_head]<=0) { sharedmem->sender[i].playback_stop_timeout= SENDER_SIGNAL_FADEOUT_DELAY; break; } else /* Compensate the time drift between the sender and us */ sharedmem->sender[i].kcdelay[sharedmem->sender[i]. buf_head]+=sharedmem->sender[i].kcdelay[j]; } } } } /* Release the semaphore to access the senders table */ cwirc_sem_V(sharedmem->semid,SEM_ST); } /* Cap the total received signal strength */ if(total_signal_strength>1) total_signal_strength=1; /* Read the key connected to the serial port if we need to */ if(sharedmem->do_key_input) serialkey=sharedmem->doiambic?read_iambic_key_serial(ticklen): read_straight_key_serial(); /* Read the mouse "key" if we need to */ if(sharedmem->do_mouse_input) mousekey=sharedmem->doiambic?read_iambic_key_mouse(ticklen): read_straight_key_mouse(); /* Combine all the key inputs and the "key" from the extension API */ key_prev=key; key=serialkey || mousekey || ext_sharedmem->in_key; /* If we're in sidetone mode, silence the key input flags used to determine the events to send. Otherwise, make them follow the real key input states */ key_evts_send_prev=key_evts_send; key_evts_send=sharedmem->sidetone_mode?0:key; /* Send the remote keys and local key states to the morse decoder */ cwirc_decode_cw(remote_keys || key,ticklen,sharedmem->cwcodeset); /* If the local key is down, its signal drowns out all the incoming signal */ if(key) total_signal_strength=1; /* If the local key changed state, reset the current keyup or keydown tick counter */ if(key && !key_prev) local_keydown_tickcnt=0; if(!key && key_prev) local_keyup_tickcnt=0; /* Bias the beep frequency according to the TX pitch */ beep_freq=BASE_BEEP_FREQ+(sharedmem->cwtxpitch*20); /* generate the local signal */ local_signal_present_prev=local_signal_present; local_signal_present=generate_cw_sound_fragment( sharedmem->cwsound,key_prev,key,DSP_SAMPLE_FREQ, samples_per_tick,beep_freq,100,local_keyup_tickcnt, local_keydown_tickcnt,local_signal_sndbuf); /* Increment the keyup and keydown tick counters */ local_keyup_tickcnt+=samples_per_tick; local_keydown_tickcnt+=samples_per_tick; /* If we have no countdown going and the key goes down, start counter and enable transmission to the irc server. Save current cw channel so we don't end up emitting on another one if user changes channel before we flush the buffer. */ if(xmit_ms_count<=0 && xmit_ms_count_prev<=0 && key_evts_send && !key_evts_send_prev) { xmit_ms_count=xmit_ms_count_prev=XMIT_BUF_DELAY; xmit_drift=0; key_evts_send_prev=key_evts_send; do_xmit=1; } /* Detect changes of the key, store then in the buffer. If the countdown has reached 0 and the key still hasn't changed, artificially close the event */ if((key_evts_send_prev!=key_evts_send || (xmit_ms_count<=0 && xmit_ms_count_prev>0 && key_evts_send_prev==key_evts_send)) && xmit_buf_i integer conversion */ if(xmit_drift>=1) { local_xmit_buf[xmit_buf_i]++; xmit_drift-=1; } /* Key up or down ? */ if(!key_evts_send_prev) local_xmit_buf[xmit_buf_i]=-local_xmit_buf[xmit_buf_i]; /* Only store the event if its duration isn't zero (case when we have a sub-millisecond event, rounded to int, without a drift compensation added afterward) */ if(local_xmit_buf[xmit_buf_i]) xmit_buf_i++; xmit_ms_count_prev=xmit_ms_count; } /* Do we need to transmit the buffer to the irc server ? */ if(do_xmit && xmit_ms_count<=0) { /* If there's nothing to transmit or just a single silence, disable the transmission */ if(!xmit_buf_i || (xmit_buf_i==1 && local_xmit_buf[0]<0)) { do_xmit=0; xmit_ms_count=xmit_ms_count_prev=0; } else { /* Transmit all the timings to the IRC server : */ /* Acquire the semaphore to acess the xmit buffer */ if(!cwirc_sem_P(sharedmem->semid,SEM_XMIT_BUF)) { /* Copy the local xmit buffer to the shared memory block */ for(i=0;ixmit_buf[i]=local_xmit_buf[i]; /* Indicate how many events have to be flushed */ sharedmem->xmit_buf_flush_nb_evts=xmit_buf_i; /* Release the semaphore */ cwirc_sem_V(sharedmem->semid,SEM_XMIT_BUF); } /* Restart the counter */ xmit_ms_count+=XMIT_BUF_DELAY; xmit_ms_count_prev+=XMIT_BUF_DELAY; } xmit_buf_i=0; } /* Do the xmit buffer timeout countdown */ xmit_ms_count-=xmit_ms_count>0?ticklen:0; /* Add QRN to the local signal */ if(sharedmem->simulate_qrn) { generate_qrn_sound_fragment(DSP_SAMPLE_FREQ,samples_per_tick,100, sndbuf); for(i=0;iqrnlevel) + (sndbuf[i]*sharedmem->qrnlevel))/100; } /* Finish mixing all the incoming signals, if we have no local signal */ if(!local_signal_present || !local_signal_present_prev) for(i=0;isquelch,sndbuf,samples_per_tick,ticklen); /* Append the sound fragment to the extension API's audio ring buffer */ for(i=0;iout_audiobuf[ext_sharedmem->out_audiobuf_end++]= sndbuf[i]*32767; if(ext_sharedmem->out_audiobuf_end>=AUDIOBUF_SIZE) ext_sharedmem->out_audiobuf_end-=AUDIOBUF_SIZE; if(ext_sharedmem->out_audiobuf_end==ext_sharedmem->out_audiobuf_start) if(++ext_sharedmem->out_audiobuf_start>=AUDIOBUF_SIZE) ext_sharedmem->out_audiobuf_start-=AUDIOBUF_SIZE; } /* Release one of the extension API's semaphores */ cwirc_sem_V(ext_sharedmem->semid,ext_lock_semno); /* Apply the volume */ for(i=0;ivolume)/100; /* Create the final sound fragment */ for(i=0;isimulate_qrn && sharedmem->qrnlevel>total_signal_strength*100) total_signal_strength=(double)sharedmem->qrnlevel/100; /* Assert this for the gui's S-meter */ sharedmem->recv_signal=total_signal_strength*100; /* Play the morse code on the external sounder if we need to */ if(sharedmem->do_sounder_output) set_sounder_line(remote_keys | key); /* Do we output to a sound device ? */ if(sharedmem->do_snddev_output) { /* Release the semaphore to prevent being reconfigured while we work*/ cwirc_sem_V(sharedmem->semid,SEM_IO_PROCESS_WORKING); /* Write the sound fragment through the sound device */ i=0; j=bytes_per_frag; do { i=write(fddsp,frag+i,j); j-=i; } while(i>0 && j>0); /* Did we encounter a write error ? */ if(i<=0) { send_errmsg("Error writing to the sound device.\n"); process_in_error=1; cleanup(); /* Re-acquire the extension API's semaphore and switch semaphore */ cwirc_sem_P(ext_sharedmem->semid,ext_lock_semno); ext_lock_semno=ext_lock_semno?0:1; continue; } } else /* No sound card to sync us : get our timing from the rtc */ { /* Release the semaphore to prevent being reconfigured while we work*/ cwirc_sem_V(sharedmem->semid,SEM_IO_PROCESS_WORKING); /* Wait for the next periodic interrupt */ if(read(fdrtc,&rtc_data,sizeof(rtc_data))==-1) { process_in_error=1; cleanup(); /* Re-acquire the extension API's semaphore and switch semaphore */ cwirc_sem_P(ext_sharedmem->semid,ext_lock_semno); ext_lock_semno=ext_lock_semno?0:1; continue; } } /* Re-acquire the extension API's semaphore and switch semaphore */ cwirc_sem_P(ext_sharedmem->semid,ext_lock_semno); ext_lock_semno=ext_lock_semno?0:1; } } /* Make sure the sounder is inactive */ if(sharedmem->do_sounder_output) set_sounder_line(0); cleanup(); } cwirc_shm_detach(ext_sharedmem); cwirc_shm_detach(sharedmem); return(0); } /* Read a straight key connected to a serial port, do debouncing, then return the key state */ static T_BOOL read_straight_key_serial(void) { int serstatus; static int debounce_buf_i=0; static int debounce_buf[DEBOUNCE_BUF_MAX_SIZE]; static T_BOOL keystate=0; int i,j; /* Read the key state */ if(ioctl(fdser,TIOCMGET,&serstatus)!=-1) { debounce_buf[debounce_buf_i]=(serstatus & (TIOCM_DSR|TIOCM_CTS))? DSR_LINE_CLOSED_KEY:!DSR_LINE_CLOSED_KEY; debounce_buf_i++; } /* If the debounce buffer is full, determine the state of the key */ if(debounce_buf_i>=sharedmem->debounce) { debounce_buf_i=0; j=0; for(i=0;idebounce;i++) if(debounce_buf[i]) j++; keystate=(j>sharedmem->debounce/2)?1:0; } return(keystate); } /* Read an iambic key connected to a serial port, do debouncing, emulate a straight key, then return the emulated key state */ static T_BOOL read_iambic_key_serial(double ticklen) { int serstatus; static T_BOOL dah_debounce_buf[DEBOUNCE_BUF_MAX_SIZE]; static T_BOOL dit_debounce_buf[DEBOUNCE_BUF_MAX_SIZE]; static int debounce_buf_i=0; static int dah=0,dit=0; static struct cwirc_keyer_state is={0}; int i,j; /* Read the key states */ if(ioctl(fdser,TIOCMGET,&serstatus)!=-1) { if(sharedmem->invertpaddles) { dah_debounce_buf[debounce_buf_i]= (serstatus & TIOCM_DSR)?DSR_LINE_CLOSED_KEY:!DSR_LINE_CLOSED_KEY; dit_debounce_buf[debounce_buf_i]= (serstatus & TIOCM_CTS)?CTS_LINE_CLOSED_KEY:!CTS_LINE_CLOSED_KEY; } else { dit_debounce_buf[debounce_buf_i]= (serstatus & TIOCM_DSR)?DSR_LINE_CLOSED_KEY:!DSR_LINE_CLOSED_KEY; dah_debounce_buf[debounce_buf_i]= (serstatus & TIOCM_CTS)?CTS_LINE_CLOSED_KEY:!CTS_LINE_CLOSED_KEY; } debounce_buf_i++; } /* If the debounce buffer is full, determine the state of the keys */ if(debounce_buf_i>=sharedmem->debounce) { debounce_buf_i=0; j=0; for(i=0;idebounce;i++) if(dah_debounce_buf[i]) j++; dah=(j>sharedmem->debounce/2)?1:0; j=0; for(i=0;idebounce;i++) if(dit_debounce_buf[i]) j++; dit=(j>sharedmem->debounce/2)?1:0; } return(cwirc_run_keyer(&is,dit,dah,sharedmem->wpm,sharedmem->iambicmode, sharedmem->do_midelementmodeB,sharedmem->do_ditmemory, sharedmem->do_dahmemory,sharedmem->do_autocharspacing, sharedmem->do_autowordspacing,sharedmem->dit_weight,ticklen)); } /* Read the mouse buttons as a straight key */ static T_BOOL read_straight_key_mouse(void) { return(sharedmem->mouseinputbutton0 || sharedmem->mouseinputbutton1); } /* Read the mouse buttons as an iambic key, emulate a straight key, then return the emulated key state */ static T_BOOL read_iambic_key_mouse(double ticklen) { static int dah=0,dit=0; static struct cwirc_keyer_state is={0}; if(sharedmem->invertpaddles) { dah=sharedmem->mouseinputbutton0; dit=sharedmem->mouseinputbutton1; } else { dit=sharedmem->mouseinputbutton0; dah=sharedmem->mouseinputbutton1; } return(cwirc_run_keyer(&is,dit,dah,sharedmem->wpm,sharedmem->iambicmode, sharedmem->do_midelementmodeB,sharedmem->do_ditmemory, sharedmem->do_dahmemory,sharedmem->do_autocharspacing, sharedmem->do_autowordspacing,sharedmem->dit_weight,ticklen)); } /* Open the sound device. Return codes : NULL : no error error message */ char *open_snd_dev(char *snddev) { int i; int little_endian=0; /* Do the endianness test here, so we don't have to force the user to change compilation options */ i=1; if(((char *)&i)[0]) little_endian=1; /* Open the sound device */ if((fddsp=open(snddev,O_WRONLY | O_NONBLOCK))==-1) { sprintf(errmsg,"cannot open sound device %s",snddev); return(errmsg); } /* Remove the non-blocking flag */ if(fcntl(fddsp,F_SETFL,0)==-1) { sprintf(errmsg,"cannot make sound device %s blocking",snddev); return(errmsg); } /* Configure the sound device */ i=DSP_FRAG_SIZE+(DSP_FRAG_BUFFER<<16); if(ioctl(fddsp,SNDCTL_DSP_SETFRAGMENT,&i)<0) { close(fddsp); fddsp=-1; sprintf(errmsg,"cannot configure buffer in sound device %s",snddev); return(errmsg); } i=DSP_STEREO; if(ioctl(fddsp,SNDCTL_DSP_STEREO,&i)<0) { close(fddsp); fddsp=-1; sprintf(errmsg,"cannot configure sound device %s in %s.",snddev, i?"stereo":"mono"); return(errmsg); } i=DSP_16BITS?(little_endian?AFMT_S16_LE:AFMT_S16_BE):AFMT_S8; if(ioctl(fddsp,SNDCTL_DSP_SETFMT,&i)<0) { close(fddsp); fddsp=-1; sprintf(errmsg,"cannot configure sound device %s in signed %d bits.",snddev, i==AFMT_S8?8:16); return(errmsg); } i=DSP_SAMPLE_FREQ; if(ioctl(fddsp,SNDCTL_DSP_SPEED,&i)<0) { close(fddsp); fddsp=-1; sprintf(errmsg,"cannot configure sound device %s at %dHz.",snddev,i); return(errmsg); } return(NULL); } /* Open the serial device and perform initial setup. */ char *open_serial_dev(char *serialdev) { int serstatus; if((fdser=open(serialdev,O_WRONLY))==-1) { sprintf(errmsg,"cannot open serial device %s",serialdev); return(errmsg); } /* Ensure DTR is down, so we can read the key's contact(s) */ if(ioctl(fdser,TIOCMGET,&serstatus)==-1) { close(fdser); fdser=-1; sprintf(errmsg,"cannot get serial device status"); return(errmsg); } if(DTR_LINE_SET) serstatus&=~TIOCM_DTR; else serstatus|=TIOCM_DTR; if(ioctl(fdser,TIOCMSET,&serstatus)==-1) { close(fdser); fdser=-1; sprintf(errmsg,"cannot set serial device status"); return(errmsg); } return(NULL); } /* Open and set /dev/rtc */ char *open_rtc_dev(void) { #ifdef LINUX /* Open the rtc device */ if((fdrtc=open("/dev/rtc",O_RDONLY))==-1) { sprintf(errmsg,"cannot open /dev/rtc."); return(errmsg); } /* Configure the rtc for periodic interrupts */ if(ioctl(fdrtc,RTC_IRQP_SET,RTC_RATE)==-1) { close(fdrtc); fdrtc=-1; sprintf(errmsg,"cannot set /dev/rtc to generate %d interupts per second.", RTC_RATE); return(errmsg); } return(NULL); #else sprintf(errmsg,"operation without a sound device isn't implemented."); return(errmsg); #endif } /* Enable periodic interrupts from /dev/rtc */ static int enable_rtc_interrupts(void) { #ifdef LINUX return(ioctl(fdrtc,RTC_PIE_ON,0)==-1?-1:0); #else return(-1); #endif } /* Close the sound device */ void close_snd_dev(void) { /* Make sure the sound device is closed */ if(fddsp!=-1) { close(fddsp); fddsp=-1; } } /* Close the serial device */ void close_serial_dev(void) { /* Make sure the sound device is closed */ if(fdser!=-1) { close(fdser); fdser=-1; } } /* Reset and close /dev/rtc */ void close_rtc_dev(void) { #ifdef LINUX /* Make sure the rtc device file is closed */ if(fdrtc!=-1) { /* Disable the periodic interrupt */ ioctl(fdrtc,RTC_PIE_OFF,0); close(fdrtc); fdrtc=-1; } #endif } /* Set the external sounder line */ static int set_sounder_line(T_BOOL state) { int serstatus; if(ioctl(fdser,TIOCMGET,&serstatus)==-1) return(-1); if(RTS_LINE_SET) serstatus=state?serstatus | TIOCM_RTS:serstatus & (~TIOCM_RTS); else serstatus=state?serstatus & (~TIOCM_RTS):serstatus | TIOCM_RTS; if(ioctl(fdser,TIOCMSET,&serstatus)==-1) return(-1); return(0); } /* Send an error message to the gui */ static void send_errmsg(char const *fmt,...) { va_list ap; va_start(ap,fmt); /* Acquire the semaphore */ if(!cwirc_sem_P(sharedmem->semid,SEM_IO_PROCESS_MSG)) { vsprintf(sharedmem->io_process_msg,fmt,ap); /* Release the semaphore */ cwirc_sem_V(sharedmem->semid,SEM_IO_PROCESS_MSG); } va_end(ap); } /* Clean up our stuff : close files, free memory ... */ static void cleanup(void) { close_rtc_dev(); close_snd_dev(); close_serial_dev(); } cwirc-2.0.0.orig/ipc.c0000644000175000017500000000426607752566656013026 0ustar pg4ipg4i/* CWirc - X-Chat plugin for sending and receiving raw morse code over IRC (c) Pierre-Philippe Coupard - 18/06/2003 IPC routines This program is distributed under the terms of the GNU General Public License See the COPYING file for details */ #include #include #include #include #include "ipc.h" /* Create a semaphore set. */ int cwirc_sem_create(int key,int nb_sems) { struct sembuf sops; int semid; int i; /* Create the semaphore set */ if((semid=semget(key,nb_sems,IPC_CREAT | 0600))==-1) return(-1); /* Wait for the semaphore to reach 1 */ for(i=0;i #include "types.h" /* Main program */ int main(int argc,char *argv[]) { T_BOOL little_endian=0; T_U8 c1,c2; T_S16 sample; T_U8 *sptr; long sampleno=0; int i; sptr=(T_U8 *)&sample; /* Do the endianness test */ i=1; if(((char *)&i)[0]) little_endian=1; /* Read and ignore 44 bytes (the header) */ for(i=0;i<44;i++) getc(stdin); printf("static const T_S16 %s[]={\n",argv[1]); /* Read and convert the samples */ while(!feof(stdin)) { c1=getc(stdin); c2=getc(stdin); if(little_endian) { sptr[0]=c1; sptr[1]=c2; } else { sptr[0]=c2; sptr[1]=c1; } if(sampleno>0) { printf(","); if(sampleno%8==0) printf("\n"); } printf("%d",sample); sampleno++; } printf("};\n\n"); printf("static const long %s_nbsamples=%ld;\n",argv[1],sampleno); return(0); } cwirc-2.0.0.orig/plugin.c0000644000175000017500000005320310076625436013525 0ustar pg4ipg4i/* CWirc - X-Chat plugin for sending and receiving raw morse code over IRC (c) Pierre-Philippe Coupard - 18/06/2003 X-Chat plugin stub. This program is distributed under the terms of the GNU General Public License See the COPYING file for details */ #include #include #include #include #include #include #include #include #include #include #include "types.h" #include "common.h" #include "cwirc.h" #include "cwframe.h" #include "ipc.h" /* Global variables */ struct cwirc_shm_block *sharedmem; static xchat_plugin *ph; /* plugin handle */ static xchat_hook *xc_hook[12]; static T_BOOL plugin_enabled=0; static pid_t watchdog_pid; static pid_t frontend_pid; static char ctcp_reply[128+MAX_NICK_SIZE]=""; static char locked_channel[MAX_CHANNEL_NAME_SIZE]=""; static char locked_server[MAX_SERVER_NAME_SIZE]=""; static int shmid=-1; /* Prototypes */ int xchat_plugin_init(xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg); int xchat_plugin_deinit(void); static int enable_cb(char *word[], char *word_eol[], void *userdata); static void disable_plugin(void); static int msg_receive_cb(char *word[], void *userdata); static int msg_send_cb(void *userdata); static int ctcp_query_cb(char *word[],void *userdata); static int sent_msgs_filter_cb(char *word[],void *userdata); static int sent_notices_filter_cb(char *word[],void *userdata); static int cwlock_cb(char *word[], char *word_eol[], void *userdata); static int cwunlock_cb(char *word[], char *word_eol[], void *userdata); static void clean_exit_hdlr(int nothing); /* Register the plugin */ int xchat_plugin_init(xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg) { plugin_enabled=0; /* we need to save this for use with any xchat_* functions */ ph=plugin_handle; *plugin_name="CWirc"; *plugin_desc="Send and receive raw morse code over IRC"; *plugin_version=VERSION; /* Hook the message receive callback that'll filter out incoming cwirc frames even when the plugin is disabled */ xc_hook[1]=xchat_hook_print(ph,"Channel Message",XCHAT_PRI_NORM, msg_receive_cb,0); xc_hook[2]=xchat_hook_print(ph,"Private Message",XCHAT_PRI_NORM, msg_receive_cb,0); xc_hook[3]=xchat_hook_print(ph,"Private Message to Dialog",XCHAT_PRI_NORM, msg_receive_cb,0); xc_hook[4]=xchat_hook_print(ph,"Notice",XCHAT_PRI_NORM, msg_receive_cb,0); /* Add the "/CW" command */ xc_hook[0]=xchat_hook_command(ph,"CW",XCHAT_PRI_NORM,enable_cb, "Usage: CW, Turns ON/OFF morse coding/decoding",0); /* Add a "CWirc" button */ xchat_commandf(ph,"ADDBUTTON CWirc CW"); /* Inform the user we're loaded */ xchat_printf(ph,"CWirc loaded successfully!\n"); /* Seed the RNG with something vaguely random */ srand(time(NULL)); return(1); } /* Deregister the plugin */ int xchat_plugin_deinit(void) { int i; /* Disable the plugin if it's already enabled */ if(plugin_enabled) { /* Stop the frontend */ sharedmem->stop_frontend=1; /* Disable the plugin */ disable_plugin(); } /* Remove the "CWirc" button */ xchat_commandf(ph,"DELBUTTON CWirc CW"); /* Unhook all the remaining callbacks */ for(i=0;i<5;i++) xchat_unhook(ph,xc_hook[i]); xchat_printf(ph, "CWirc unloaded successfully!\n"); return(1); } /* Enable the plugin */ static int enable_cb(char *word[], char *word_eol[], void *userdata) { char shmid_string[32]; char frontend_msg[FRONTEND_MSG_SIZE]; int frontend_stdout_pipe[2]; FILE *frontend_stdout; int caught_sigs_not_sigchld[]={SIGHUP,SIGINT,SIGKILL,SIGPIPE,SIGIO, \ SIGPROF,SIGTERM,SIGUSR1,SIGUSR2,SIGVTALRM,SIGURG,-1}; struct sigaction sigact; int i; /* Disable the plugin if it's already enabled */ if(plugin_enabled) { /* Stop the frontend */ sharedmem->stop_frontend=1; return(XCHAT_EAT_ALL); } /* Enable the plugin : */ /* Create the shared memory block */ if((shmid=cwirc_shm_alloc(rand(),sizeof(struct cwirc_shm_block)))==-1) { xchat_printf(ph,"CWirc : error : can't create shared memory.\n"); return(XCHAT_EAT_ALL); } /* Attach to the shared memory block */ if((sharedmem=(struct cwirc_shm_block *)cwirc_shm_attach(shmid)) ==(struct cwirc_shm_block *)-1) { cwirc_shm_detach(sharedmem); cwirc_shm_free(shmid); xchat_printf(ph,"CWirc : error : can't attach to the shared memory.\n"); return(XCHAT_EAT_ALL); } /* Store the version number known to us (the plugin) in the shared memory block, so the frontend will be able to detect a version mismatch */ strcpy(sharedmem->version,VERSION); /* Initialize the senders table */ for(i=0;isender[i].name[0]=0; /* Zero the xmit buffer */ for(i=0;ixmit_buf[i]=0; sharedmem->xmit_buf_flush_nb_evts=0; /* Make sure we have some values set up now because the config file isn't loaded yet by the frontend, but we start using the value within the plugin before spawning the frontend */ sharedmem->recv_buffering=1000; for(i=0;i<5;i++) sharedmem->cwchannel[i]=1000; sharedmem->currcwchannel=0; sharedmem->reply_to_ctcp=0; sharedmem->give_callsign_in_ctcp_reply=0; sharedmem->give_gridsquare_in_ctcp_reply=0; sharedmem->give_cwchannel_in_ctcp_reply=0; /* Make sure the plugin isn't locked on any channel */ locked_channel[0]=0; /* Create the semaphore */ if((sharedmem->semid=cwirc_sem_create(rand(),NB_SEMAPHORES))==-1) { xchat_printf(ph,"CWirc : error : can't create semaphore.\n"); cwirc_shm_detach(sharedmem); cwirc_shm_free(shmid); return(XCHAT_EAT_ALL); } /* Spawn the frontend */ sharedmem->stop_frontend=0; sharedmem->frontend_stopped=0; switch((watchdog_pid=fork())) /* Escape from the X-Chat execution context */ { case -1: /* Error fork()ing */ cwirc_sem_destroy(sharedmem->semid); cwirc_shm_detach(sharedmem); cwirc_shm_free(shmid); xchat_printf(ph,"CWirc : error : can't spawn frontend watchdog process.\n"); return(XCHAT_EAT_ALL); break; case 0: /* I'm the 1st child */ /* Make sure we catch all signals other than SIGCHLD to exit cleanly */ for(i=0;caught_sigs_not_sigchld[i]!=-1;i++) signal(caught_sigs_not_sigchld[i],&clean_exit_hdlr); /* Make sure we catch the frontend process' death (but not its stopping) */ sigact.sa_handler=clean_exit_hdlr; sigemptyset(&sigact.sa_mask); sigact.sa_flags=SA_NOCLDSTOP; sigaction(SIGCHLD,&sigact,NULL); /* Make a pipe to catch the frontend's stdout */ if(pipe(frontend_stdout_pipe)) { printf("CWirc : error : cannot create unnamed pipe.\n"); fflush(stdout); _exit(0); } switch((frontend_pid=fork())) /* Spawn the frontend process proper */ { case -1: /* Error fork()ing */ printf("CWirc : error : cannot spawn frontend process.\n"); fflush(stdout); _exit(0); break; case 0: /* I'm the 2nd child */ /* Connect my stdout to the pipe and close the reading end of the pipe */ close(1); dup(frontend_stdout_pipe[1]); close(frontend_stdout_pipe[0]); /* Spawn the frontend and pass it the id of the shared memory block */ sprintf(shmid_string,"0x%0x",shmid); execlp(FRONTEND,FRONTEND,shmid_string,NULL); printf("CWirc : error : cannot execute \"%s\".\n",FRONTEND); fflush(stdout); sharedmem->frontend_stopped=1; _exit(0); break; default: /* Close the writing end of the pipe */ close(frontend_stdout_pipe[1]); frontend_stdout=fdopen(frontend_stdout_pipe[0],"r"); /* Capture what the frontend says. If the pipe closes, the frontend has died. */ while(fgets(frontend_msg,FRONTEND_MSG_SIZE,frontend_stdout)!=NULL) { /* Zap trailing CR or LFs */ i=strlen(frontend_msg); while(i && (frontend_msg[i-1]=='\n' || frontend_msg[i-1]=='\r')) frontend_msg[--i]=0; /* Send the message for display in the X-Chat window : */ i=1; do { if(!cwirc_sem_P(sharedmem->semid,SEM_FRONTEND_MSG)) /* Acquire sem*/ { if(!sharedmem->frontend_msg[0]) { strncpy(sharedmem->frontend_msg,frontend_msg,FRONTEND_MSG_SIZE); sharedmem->frontend_msg[FRONTEND_MSG_SIZE-1]=0; i=0; } /* Release the semaphore */ cwirc_sem_V(sharedmem->semid,SEM_FRONTEND_MSG); } /* If we couldn't send the message, sleep a bit */ if(i) usleep(10000); } while(i); } sharedmem->stop_frontend=1; /* Reap the frontend's process */ waitpid(frontend_pid,NULL,0); /* Mark the frontend as stopped */ sharedmem->frontend_stopped=1; _exit(0); break; } break; } /* Hook the additional callbacks we need when the plugin is enabled */ xc_hook[5]=xchat_hook_timer(ph,10,msg_send_cb,NULL); xc_hook[6]=xchat_hook_print(ph,"Your Message",XCHAT_PRI_NORM, sent_msgs_filter_cb,0); xc_hook[7]=xchat_hook_print(ph,"CTCP Generic",XCHAT_PRI_NORM, ctcp_query_cb,0); xc_hook[8]=xchat_hook_print(ph,"CTCP Generic to Channel",XCHAT_PRI_NORM, ctcp_query_cb,0); xc_hook[9]=xchat_hook_print(ph,"Notice Send",XCHAT_PRI_NORM, sent_notices_filter_cb,0); xc_hook[10]=xchat_hook_command(ph,"CWLOCK",XCHAT_PRI_NORM,cwlock_cb, "Usage: CWLOCK, Locks CWirc onto the current chat window",0); xc_hook[11]=xchat_hook_command(ph,"CWUNLOCK",XCHAT_PRI_NORM,cwunlock_cb, "Usage: CWUNLOCK, Release CWirc from any chat window lock.",0); /* All good */ plugin_enabled=1; return(XCHAT_EAT_ALL); } /* Disable the plugin */ void disable_plugin(void) { int i; /* Reap the frontend watchdog process */ waitpid(watchdog_pid,NULL,0); /* Unhook the callbacks we don't need when the plugin is disabled */ for(i=5;i<12;i++) xchat_unhook(ph,xc_hook[i]); plugin_enabled=0; /* Detach/free the shared memory block, destroy the semaphore */ cwirc_sem_destroy(sharedmem->semid); cwirc_shm_detach(sharedmem); cwirc_shm_free(shmid); xchat_printf(ph, "CWirc disabled!\n"); } /* Receive messages from the IRC channel */ static int msg_receive_cb(char *word[],void *userdata) { xchat_context *curr_ctx,*ctx; const char *ircchannel,*ircserver; char src_ircchannel[MAX_CHANNEL_NAME_SIZE]; char src_ircserver[MAX_SERVER_NAME_SIZE]; char cmp_ircchannel[MAX_CHANNEL_NAME_SIZE]; char *nickptr; char *callsign; /* Is the line a cw frame ? */ if(cwirc_is_cw_frame(word[2])) { /* Is the plugin enabled ? */ if(plugin_enabled) { /* Find the originating channel namee */ if((ircchannel=xchat_get_info(ph,"channel"))==NULL) return(XCHAT_EAT_ALL); strncpy(src_ircchannel,ircchannel,MAX_CHANNEL_NAME_SIZE); src_ircchannel[MAX_CHANNEL_NAME_SIZE-1]=0; /* Find the originating server namee */ if((ircserver=xchat_get_info(ph,"server"))==NULL) return(XCHAT_EAT_ALL); strncpy(src_ircserver,ircserver,MAX_SERVER_NAME_SIZE); src_ircserver[MAX_SERVER_NAME_SIZE-1]=0; /* Are we not locked on a particular channel/server ? */ if(!locked_channel[0]) { /* Save the current xchat context */ if((curr_ctx=xchat_get_context(ph))==NULL) return(XCHAT_EAT_ALL); /* Find the context of the window currently in focus and switch to it */ if((ctx=xchat_find_context(ph,NULL,NULL))==NULL) return(XCHAT_EAT_ALL); if(!xchat_set_context(ph,ctx)) return(XCHAT_EAT_ALL); /* Find the current channel name */ if((ircchannel=xchat_get_info(ph,"channel"))==NULL) return(XCHAT_EAT_ALL); strncpy(cmp_ircchannel,ircchannel,MAX_CHANNEL_NAME_SIZE); cmp_ircchannel[MAX_CHANNEL_NAME_SIZE-1]=0; ircchannel=cmp_ircchannel; /* Find the current server name */ if((ircserver=xchat_get_info(ph,"server"))==NULL) return(XCHAT_EAT_ALL); /* Restore the current context (source channel context) */ if(!xchat_set_context(ph,curr_ctx)) return(XCHAT_EAT_ALL); } else { ircchannel=locked_channel; ircserver=locked_server; } /* Remove possible X-Chat color codes from the nick */ nickptr=word[1]; if(nickptr[0]==3) /* CTRL-C indicates a color code follows */ while(isdigit((++nickptr)[0])); /* Did the line come from the channel currently in focus or the one we're locked on ? */ if(!strcmp(src_ircchannel,ircchannel) && !strcmp(src_ircserver,ircserver)) { /* Decode the frame */ if(cwirc_decode_cw_frame(nickptr,word[2],&callsign)==1) { if(callsign!=NULL) xchat_printf(ph, "Receiving cw from %s [from %s] ...\n",callsign, nickptr); else xchat_printf(ph, "Receiving cw from %s ...\n",nickptr); } } } /* Filter out the cw frame from the channel window */ return(XCHAT_EAT_ALL); } return(XCHAT_EAT_NONE); } /* This routine gets called regularly by xchat to poll and check if a message needs to be sent, and also take care of disabling the plugin if the frontend has terminated. It's butt-ugly but there's no other mechanism. */ static int msg_send_cb(void *userdata) { const char *dst; xchat_context *curr_ctx=NULL,*ctx; xchat_list *dcclist; T_BOOL do_dccchat; char *msgptr; static time_t last_error_tstamp=0,curtime; int i; /* Check if we have a message from the frontend */ if(!cwirc_sem_P(sharedmem->semid,SEM_FRONTEND_MSG)) /* Acquire semaphore */ { /* Any error message from the frontend ? */ if(sharedmem->frontend_msg[0]) { xchat_printf(ph,"%s\n",sharedmem->frontend_msg); sharedmem->frontend_msg[0]=0; } /* Release the semaphore */ cwirc_sem_V(sharedmem->semid,SEM_FRONTEND_MSG); /* Release semaphore */ } /* Check if we have a morse message to send to the irc server */ if(!cwirc_sem_P(sharedmem->semid,SEM_XMIT_BUF)) /* Acquire semaphore */ { /* Any CW message to transmit ? */ if(sharedmem->xmit_buf_flush_nb_evts) { dst=NULL; /* Save the current xchat context */ if((curr_ctx=xchat_get_context(ph))!=NULL) { /* Find the context of the window currently in focus, or the locked channel/server */ if((ctx=xchat_find_context(ph,locked_channel[0]?locked_server:NULL, locked_channel[0]?locked_channel:NULL))!=NULL) { /* Switch to that context */ if(xchat_set_context(ph,ctx)) { /* If we're not locked on a channel/server, find the current channel name */ if(locked_channel[0]) dst=locked_channel; else dst=xchat_get_info(ph,"channel"); } } else /* We failed to find the context */ { /* Is the channel/server locked ? */ if(locked_channel[0]) { /* If it is more than 3s since we last sent the following error msg, change context to the window currently in focus and send it again */ curtime=time(NULL); if(curtime-last_error_tstamp>3 && (ctx=xchat_find_context(ph,NULL,NULL))!=NULL && xchat_set_context(ph,ctx)) xchat_printf(ph,"WARNING: can't send cw to \"%s\" (%s) : stale " "lock.\n",locked_channel,locked_server); last_error_tstamp=curtime; } } } /* Do we have something to send to ? */ if(dst!=NULL) { /* Check if we have a DCC CHAT connection to destination if it's a nick */ do_dccchat=0; if(dst[0]!='#' && (dcclist=xchat_list_get(ph,"dcc"))) { while(!do_dccchat && xchat_list_next(ph,dcclist)) { i=xchat_list_int(ph,dcclist,"type"); if(!strcmp(dst,xchat_list_str(ph,dcclist,"nick")) && xchat_list_int(ph,dcclist,"status")==1 && (i==2 || i==3)) do_dccchat=1; } } /* Acquire the semaphore to access the personal information */ if(!cwirc_sem_P(sharedmem->semid,SEM_PERSONAL_INFO)) { if((msgptr=cwirc_encode_cw_frame())!=NULL) xchat_commandf(ph,"MSG %s%s %s",do_dccchat?"=":"",dst,msgptr); /* Release the semaphore */ cwirc_sem_V(sharedmem->semid,SEM_PERSONAL_INFO); } } sharedmem->xmit_buf_flush_nb_evts=0; } /* Restore the current context */ if(curr_ctx!=NULL) xchat_set_context(ph,curr_ctx); /* Release the semaphore */ cwirc_sem_V(sharedmem->semid,SEM_XMIT_BUF); } /* Do we need to disable the plugin because the frontend has stopped ? */ if(sharedmem->frontend_stopped) disable_plugin(); return(1); } /* Watch incoming CTCP queries, intercept "CTCP CWIRC" and repy, or not. */ static int ctcp_query_cb(char *word[],void *userdata) { T_BOOL report_callsign,report_gridsquare; /* Do we reply to CTCP CWIRC queries, and is this one ? */ if(sharedmem->reply_to_ctcp && !strcasecmp(word[1],"CWIRC")) { sprintf(ctcp_reply,"CWIRC CWirc version %s",VERSION); if(sharedmem->give_callsign_in_ctcp_reply || sharedmem->give_gridsquare_in_ctcp_reply || sharedmem->give_cwchannel_in_ctcp_reply) { strcat(ctcp_reply," ("); /* Should we give the callsign or the grid square in the reply ? */ report_callsign=sharedmem->give_callsign_in_ctcp_reply && sharedmem->callsign[0]; report_gridsquare=sharedmem->give_gridsquare_in_ctcp_reply && sharedmem->gridsquare[0]; if(report_callsign || report_gridsquare) { /* Acquire the semaphore to access the personal information */ if(!cwirc_sem_P(sharedmem->semid,SEM_PERSONAL_INFO)) { sprintf(ctcp_reply+strlen(ctcp_reply),"user "); if(report_callsign) sprintf(ctcp_reply+strlen(ctcp_reply),"callsign \"%s\"%s", sharedmem->callsign,report_gridsquare || sharedmem->give_cwchannel_in_ctcp_reply?", ":")"); if(report_gridsquare) sprintf(ctcp_reply+strlen(ctcp_reply),"grid location \"%s\"%s", sharedmem->gridsquare, sharedmem->give_cwchannel_in_ctcp_reply?", ":")"); /* Release the semaphore */ cwirc_sem_V(sharedmem->semid,SEM_PERSONAL_INFO); } } /* Should we give the current CW channel in the reply ? */ if(sharedmem->give_cwchannel_in_ctcp_reply) sprintf(ctcp_reply+strlen(ctcp_reply),"currently on channel %d)", sharedmem->cwchannel[sharedmem->currcwchannel]); } /* Send the reply */ xchat_commandf(ph,"NOTICE %s %s",word[2],ctcp_reply); } return(XCHAT_EAT_NONE); } /* Watch what we send to the server and trap our own cw frames */ static int sent_msgs_filter_cb(char *word[],void *userdata) { static time_t last_send_tstamp=0,curtime; /* Is the message one of our cw frames ? */ if(cwirc_is_cw_frame(word[2])) { /* Is it more than 3s since we sent the last cw frame ? */ curtime=time(NULL); if(curtime-last_send_tstamp>3) xchat_printf(ph,"%s sending cw ...\n",word[1]); last_send_tstamp=curtime; return(XCHAT_EAT_ALL); } return(XCHAT_EAT_NONE); } /* Watch the notices we send to the server and trap our own CTCP replies */ static int sent_notices_filter_cb(char *word[],void *userdata) { if(!strcmp(word[2],ctcp_reply)) return(XCHAT_EAT_ALL); return(XCHAT_EAT_NONE); } /* Locks CWirc onto the current chat window, i.e. make sure it'll always send and receive from the corresponding channel/nick from now on, even if the user changes chat window afterward */ static int cwlock_cb(char *word[], char *word_eol[], void *userdata) { xchat_context *curr_ctx,*ctx; const char *irc_info; /* Save the current xchat context */ if((curr_ctx=xchat_get_context(ph))==NULL) return(XCHAT_EAT_ALL); /* Find the context of the window currently in focus and switch to it */ if((ctx=xchat_find_context(ph,NULL,NULL))==NULL) return(XCHAT_EAT_ALL); if(!xchat_set_context(ph,ctx)) return(XCHAT_EAT_ALL); /* Find the current channel name */ if((irc_info=xchat_get_info(ph,"channel"))==NULL || !irc_info[0]) { locked_channel[0]=locked_server[0]=0; return(XCHAT_EAT_ALL); } strncpy(locked_channel,irc_info,MAX_CHANNEL_NAME_SIZE); locked_channel[MAX_CHANNEL_NAME_SIZE-1]=0; /* Find the current server name */ if((irc_info=xchat_get_info(ph,"server"))==NULL || !irc_info[0]) { locked_channel[0]=locked_server[0]=0; return(XCHAT_EAT_ALL); } strncpy(locked_server,irc_info,MAX_SERVER_NAME_SIZE); locked_server[MAX_SERVER_NAME_SIZE-1]=0; /* Restore the current context */ if(!xchat_set_context(ph,curr_ctx)) { locked_channel[0]=locked_server[0]=0; return(XCHAT_EAT_ALL); } /* Tell the user what CWirc is locked on now */ xchat_printf(ph, "CWirc locked onto \"%s\" (%s).\n",locked_channel, locked_server); return(XCHAT_EAT_ALL); } /* Release CWirc from any chat window it might be locked onto. */ static int cwunlock_cb(char *word[], char *word_eol[], void *userdata) { /* Tell the user what CWirc has been unlocked from if we can. */ if(locked_channel[0]) xchat_printf(ph, "CWirc released from \"%s\" (%s).\n",locked_channel, locked_server); else xchat_printf(ph, "CWirc is not locked.\n"); locked_channel[0]=locked_server[0]=0; return(XCHAT_EAT_ALL); } /* Signal handler to make sure we terminate the frontend if we get any signal in the frontend watch process . */ static void clean_exit_hdlr(int nothing) { /* Terminate the frontend. */ sharedmem->stop_frontend=1; } cwirc-2.0.0.orig/propagation.c0000644000175000017500000000247010062724714014544 0ustar pg4ipg4i/* CWirc - X-Chat plugin for sending and receiving raw morse code over IRC (c) Pierre-Philippe Coupard - 18/06/2003 Simulated propagation / signal strength evaluation routines This program is distributed under the terms of the GNU General Public License See the COPYING file for details */ #include #include "propagation.h" /* Definitions */ #define HALF_SIGNAL_DROP_DISTANCE 200 /* km */ #define SPORADICE_UPDATE_PERIOD 500 /* ms */ /* Make up a signal strength (0 -> 100) from the distance in Km between sender and receiver. The current simulation doesn't correspond to anything real but allows us to not really exclude anybody anywhere in the world from being received. */ double cwirc_determine_signal_strength(int distance) { return(1/(1+((double)distance/HALF_SIGNAL_DROP_DISTANCE))); } /* Simulate sporadic-E. Here, we do it solely by attenuating the signal at random */ void cwirc_simulate_sporadicE(double *signal_strength,double ticklen) { static double rnd_update_timeout=0; static double dir=1; static double attn=1; if(rnd_update_timeout<=0) { dir=rand()>RAND_MAX/2?ticklen/300:0; rnd_update_timeout=SPORADICE_UPDATE_PERIOD; } rnd_update_timeout-=ticklen; attn=(attn+dir)/(1+ticklen/300); if(*signal_strength<0.2) *signal_strength*=attn; } cwirc-2.0.0.orig/rcfile.c0000644000175000017500000005631110063141227013461 0ustar pg4ipg4i/* CWirc - X-Chat plugin for sending and receiving raw morse code over IRC (c) Pierre-Philippe Coupard - 18/06/2003 Configuration file reading, parsing and checking routines This program is distributed under the terms of the GNU General Public License See the COPYING file for details */ #include #include #include #include #include #include "types.h" #include "rcfile.h" #include "cwirc.h" #include "grid.h" #include "io.h" #include "cwdecoder.h" /* Definitions */ #define LINE_MAX_SIZE 256 #define DEFAULT_CWINPUT "mouse" #define DEFAULT_CWOUTPUT "soundcard" #define DEFAULT_CWSOUND "beeps" #ifdef LINUX #define DEFAULT_SNDDEV "/dev/dsp" #define DEFAULT_SERIALDEV "/dev/ttyS0" #endif #ifdef FREEBSD #define DEFAULT_SNDDEV "/dev/dsp0.0" #define DEFAULT_SERIALDEV "/dev/cuaa0" #endif #ifdef NETBSD #define DEFAULT_SNDDEV "/dev/audio0" #define DEFAULT_SERIALDEV "/dev/tty00" #endif #define DEFAULT_KEYTYPE "straight" #define DEFAULT_IAMBICMODE "B" #define DEFAULT_MIDELEMENTMODEB 0 #define DEFAULT_DITMEMORY 1 #define DEFAULT_DAHMEMORY 1 #define DEFAULT_AUTOCHARSPACING 0 #define DEFAULT_AUTOWORDSPACING 0 #define DEFAULT_INVERTPADDLES 0 #define DEFAULT_DITWEIGHT 50 #define DEFAULT_SIDETONE_MODE 0 #define DEFAULT_CWCHANNEL1 1000 #define DEFAULT_CWCHANNEL2 1000 #define DEFAULT_CWCHANNEL3 1000 #define DEFAULT_CWCHANNEL4 1000 #define DEFAULT_CWCHANNEL5 1000 #define DEFAULT_CURRENTCWCHANNEL 1 #define DEFAULT_CWRXPITCH 0 #define DEFAULT_CWTXPITCH 0 #define DEFAULT_SQUELCH 0 #define DEFAULT_VOLUME 100 #define DEFAULT_WPM 10 #define DEFAULT_DEBOUNCE 1 #define DEFAULT_RECV_BUFFERING 1000 #define DEFAULT_CALLSIGN "" #define DEFAULT_GRIDSQUARE "" #define DEFAULT_SEND_CALLSIGN_WITH_CW 0 #define DEFAULT_SEND_GRIDSQUARE_WITH_CW 0 #define DEFAULT_REPLY_TO_CTCP 1 #define DEFAULT_GIVE_CALLSIGN_IN_CTCP_REPLY 0 #define DEFAULT_GIVE_GRIDSQUARE_IN_CTCP_REPLY 0 #define DEFAULT_GIVE_CWCHANNEL_IN_CTCP_REPLY 1 #define DEFAULT_SIMULATE_QRN 0 #define DEFAULT_QRNLEVEL 10 #define DEFAULT_SIMULATE_SIGNAL_STRENGTH 0 #define DEFAULT_SIMULATE_SPORADICE 0 #define DEFAULT_DEFAULT_SIGNAL_STRENGTH 50 #define DEFAULT_CW_DECODER_LANGUAGE "english" /* Global variables */ static char errmsg[LINE_MAX_SIZE]; static char cwinput[LINE_MAX_SIZE]; static char cwoutput[LINE_MAX_SIZE]; static char cwsound[LINE_MAX_SIZE]; static char snddev[LINE_MAX_SIZE]; static char serialdev[LINE_MAX_SIZE]; static char keytype[LINE_MAX_SIZE]; static char iambicmode[LINE_MAX_SIZE]; static int midelementmodeB; static int ditmemory; static int dahmemory; static int autocharspacing; static int autowordspacing; static int invertpaddles; static int ditweight; static int sidetone_mode; static int cwrxpitch; static int cwtxpitch; static int squelch; static int volume; static int cwchannel[5]; static int currentcwchannel; static int wpm; static int debounce; static int recv_buffering; static char callsign[LINE_MAX_SIZE]; static char gridsquare[LINE_MAX_SIZE]; static int send_callsign_with_cw; static int send_gridsquare_with_cw; static int reply_to_ctcp; static int give_callsign_in_ctcp_reply; static int give_gridsquare_in_ctcp_reply; static int give_cwchannel_in_ctcp_reply; static int simulate_qrn; static int qrnlevel; static int simulate_signal_strength; static int simulate_sporadicE; static int default_signal_strength; static char cw_decoder_language[LINE_MAX_SIZE]; /* Prototypes */ void restore_default(void); static char *check_parameters(void); void load_internal_vars_from_rcfile_values(void); /* Load default values into the variables */ void restore_default_settings(void) { strcpy(cwinput,DEFAULT_CWINPUT); strcpy(cwoutput,DEFAULT_CWOUTPUT); strcpy(cwsound,DEFAULT_CWSOUND); strcpy(snddev,DEFAULT_SNDDEV); strcpy(serialdev,DEFAULT_SERIALDEV); strcpy(keytype,DEFAULT_KEYTYPE); strcpy(iambicmode,DEFAULT_IAMBICMODE); midelementmodeB=DEFAULT_MIDELEMENTMODEB; ditmemory=DEFAULT_DITMEMORY; dahmemory=DEFAULT_DAHMEMORY; autocharspacing=DEFAULT_AUTOCHARSPACING; autowordspacing=DEFAULT_AUTOWORDSPACING; invertpaddles=DEFAULT_INVERTPADDLES; ditweight=DEFAULT_DITWEIGHT; sidetone_mode=DEFAULT_SIDETONE_MODE; cwrxpitch=DEFAULT_CWRXPITCH; cwtxpitch=DEFAULT_CWTXPITCH; squelch=DEFAULT_SQUELCH; volume=DEFAULT_VOLUME; cwchannel[0]=DEFAULT_CWCHANNEL1; cwchannel[1]=DEFAULT_CWCHANNEL2; cwchannel[2]=DEFAULT_CWCHANNEL3; cwchannel[3]=DEFAULT_CWCHANNEL4; cwchannel[4]=DEFAULT_CWCHANNEL5; currentcwchannel=DEFAULT_CURRENTCWCHANNEL; wpm=DEFAULT_WPM; debounce=DEFAULT_DEBOUNCE; recv_buffering=DEFAULT_RECV_BUFFERING; strcpy(callsign,DEFAULT_CALLSIGN); strcpy(gridsquare,DEFAULT_GRIDSQUARE); send_callsign_with_cw=DEFAULT_SEND_CALLSIGN_WITH_CW; send_gridsquare_with_cw=DEFAULT_SEND_GRIDSQUARE_WITH_CW; reply_to_ctcp=DEFAULT_REPLY_TO_CTCP; give_callsign_in_ctcp_reply=DEFAULT_GIVE_CALLSIGN_IN_CTCP_REPLY; give_gridsquare_in_ctcp_reply=DEFAULT_GIVE_GRIDSQUARE_IN_CTCP_REPLY; give_cwchannel_in_ctcp_reply=DEFAULT_GIVE_CWCHANNEL_IN_CTCP_REPLY; simulate_qrn=DEFAULT_SIMULATE_QRN; qrnlevel=DEFAULT_QRNLEVEL; simulate_signal_strength=DEFAULT_SIMULATE_SIGNAL_STRENGTH; simulate_sporadicE=DEFAULT_SIMULATE_SPORADICE; default_signal_strength=DEFAULT_DEFAULT_SIGNAL_STRENGTH; strcpy(cw_decoder_language,DEFAULT_CW_DECODER_LANGUAGE); load_internal_vars_from_rcfile_values(); } /* Read the config file and set options accordingly. The config files is composed of "var=val" lines. Return codes : NULL --> no error error message */ char *cwirc_parse_rcfile(char *rcfile) { char filename[FILENAME_MAX]; char *homedir; FILE *fd; char buf[LINE_MAX_SIZE]; char *var,*val; char *strptr; int *intptr; int lineno; int i,j; strncpy(filename,rcfile,FILENAME_MAX); filename[FILENAME_MAX-1]=0; /* Expand tildas by the HOME variable */ homedir=getenv("HOME"); for(i=0;ii;j--) filename[j+strlen(homedir)-1]=filename[j]; for(j=0;j no error error message */ static char *check_parameters(void) { int i; /* Check that the variables have correct values */ if(strcmp(cwinput,"key") && strcmp(cwinput,"mouse") && strcmp(cwinput,"both")) { sprintf(errmsg,"invalid CW input source \"%s\".",cwinput); return(errmsg); } if(strcmp(cwoutput,"soundcard") && strcmp(cwoutput,"sounder") && strcmp(cwoutput,"both")) { sprintf(errmsg,"invalid CW output source \"%s\".",cwoutput); return(errmsg); } if((!strcmp(cwinput,"key") || !strcmp(cwinput,"both") || !strcmp(cwoutput,"sounder") || !strcmp(cwoutput,"both")) && !serialdev[0]) { sprintf(errmsg,"serial device not defined."); return(errmsg); } if((!strcmp(cwoutput,"soundcard") || !strcmp(cwoutput,"both")) && !snddev[0]) { sprintf(errmsg,"sound device not defined."); return(errmsg); } if(strcmp(cwsound,"beeps") && strcmp(cwsound,"sounder_clicks")) { sprintf(errmsg,"invalid CW sound type \"%s\".",cwsound); return(errmsg); } if(cwrxpitch<-50 || cwrxpitch>50) { sprintf(errmsg,"invalid CW RX pitch setting %d.",cwrxpitch); return(errmsg); } if(cwtxpitch<-50 || cwtxpitch>50) { sprintf(errmsg,"invalid CW TX pitch setting %d.",cwtxpitch); return(errmsg); } if(squelch<0 || squelch>100) { sprintf(errmsg,"invalid squelch setting %d.",squelch); return(errmsg); } if(volume<0 || volume>100) { sprintf(errmsg,"invalid volume setting %d.",volume); return(errmsg); } for(i=0;i<5;i++) if(cwchannel[i]<0 || cwchannel[i]>3999) { sprintf(errmsg,"invalid morse channel #%d %d.",i+1,cwchannel[i]); return(errmsg); } if(currentcwchannel<1 || currentcwchannel>5) { sprintf(errmsg,"invalid current morse channel %d.",currentcwchannel); return(errmsg); } if(wpm<1 || wpm>60) { sprintf(errmsg,"%d wpm is invalid.",wpm); return(errmsg); } if(debounce<1 || debounce>DEBOUNCE_BUF_MAX_SIZE) { sprintf(errmsg,"debounce value of %d is invalid.",debounce); return(errmsg); } if(strcmp(keytype,"straight") && strcmp(keytype,"iambic")) { sprintf(errmsg,"invalid key type \"%s\".",keytype); return(errmsg); } if(strcmp(iambicmode,"A") && strcmp(iambicmode,"B")) { sprintf(errmsg,"iambic mode must be A or B."); return(errmsg); } if(midelementmodeB!=0 && midelementmodeB!=1) { sprintf(errmsg,"midelementmodeB must be 0 or 1."); return(errmsg); } if(ditmemory!=0 && ditmemory!=1) { sprintf(errmsg,"ditmemory must be 0 or 1."); return(errmsg); } if(dahmemory!=0 && dahmemory!=1) { sprintf(errmsg,"dahmemory must be 0 or 1."); return(errmsg); } if(autocharspacing!=0 && autocharspacing!=1) { sprintf(errmsg,"autocharspacing must be 0 or 1."); return(errmsg); } if(autowordspacing!=0 && autowordspacing!=1) { sprintf(errmsg,"autowordspacing must be 0 or 1."); return(errmsg); } if(invertpaddles!=0 && invertpaddles!=1) { sprintf(errmsg,"invertpaddles must be 0 or 1."); return(errmsg); } if(ditweight<15 || ditweight>85) { sprintf(errmsg,"invalid dit weight \"%d\".",ditweight); return(errmsg); } if(sidetone_mode!=0 && sidetone_mode!=1) { sprintf(errmsg,"sidetone_mode must be 0 or 1."); return(errmsg); } if(recv_buffering<100 || recv_buffering>3000) { sprintf(errmsg,"invalid receive buffering %d ms.",recv_buffering); return(errmsg); } for(i=0;i'}') { sprintf(errmsg,"invalid character \"%c\" in callsign \"%s\".", callsign[i],callsign); return(errmsg); } if(gridsquare[0] && !cwirc_is_grid_square(gridsquare)) { sprintf(errmsg,"invalid grid square \"%s\".",gridsquare); return(errmsg); } if(send_callsign_with_cw!=0 && send_callsign_with_cw!=1) { sprintf(errmsg,"send_callsign_with_cw must be 0 or 1."); return(errmsg); } if(send_gridsquare_with_cw!=0 && send_gridsquare_with_cw!=1) { sprintf(errmsg,"send_gridsquare_with_cw must be 0 or 1."); return(errmsg); } if(reply_to_ctcp!=0 && reply_to_ctcp!=1) { sprintf(errmsg,"reply_to_ctcp must be 0 or 1."); return(errmsg); } if(give_callsign_in_ctcp_reply!=0 && give_callsign_in_ctcp_reply!=1) { sprintf(errmsg,"give_callsign_in_ctcp_reply must be 0 or 1."); return(errmsg); } if(give_gridsquare_in_ctcp_reply!=0 && give_gridsquare_in_ctcp_reply!=1) { sprintf(errmsg,"give_gridsquare_in_ctcp_reply must be 0 or 1."); return(errmsg); } if(give_cwchannel_in_ctcp_reply!=0 && give_cwchannel_in_ctcp_reply!=1) { sprintf(errmsg,"give_cwchannel_in_ctcp_reply must be 0 or 1."); return(errmsg); } if(simulate_qrn!=0 && simulate_qrn!=1) { sprintf(errmsg,"simulate_qrn must be 0 or 1."); return(errmsg); } if(qrnlevel<0 || qrnlevel>100) { sprintf(errmsg,"invalid qrn level %d.",qrnlevel); return(errmsg); } if(simulate_signal_strength!=0 && simulate_signal_strength!=1) { sprintf(errmsg,"simulate_signal_strength must be 0 or 1."); return(errmsg); } if(simulate_sporadicE!=0 && simulate_sporadicE!=1) { sprintf(errmsg,"simulate_sporadicE must be 0 or 1."); return(errmsg); } if(default_signal_strength<0 || default_signal_strength>100) { sprintf(errmsg,"invalid default signal strength %d.", default_signal_strength); return(errmsg); } for(i=0;ido_mouse_input=!strcmp(cwinput,"mouse") || !strcmp(cwinput,"both"); sharedmem->do_key_input=!strcmp(cwinput,"key") || !strcmp(cwinput,"both"); sharedmem->do_snddev_output=!strcmp(cwoutput,"soundcard") || !strcmp(cwoutput,"both"); sharedmem->do_sounder_output=!strcmp(cwoutput,"sounder") || !strcmp(cwoutput,"both"); sharedmem->cwsound=!strcmp(cwsound,"beeps")?0:1; strncpy(sharedmem->snddev,snddev,FILENAME_MAX); sharedmem->snddev[FILENAME_MAX-1]=0; strncpy(sharedmem->serialdev,serialdev,FILENAME_MAX); sharedmem->serialdev[FILENAME_MAX-1]=0; sharedmem->doiambic=(keytype[0]=='i'); sharedmem->iambicmode=(iambicmode[0]=='A'?0:iambicmode[0]=='B'?1: iambicmode[3]=='m'?2:3); sharedmem->do_midelementmodeB=midelementmodeB; sharedmem->do_ditmemory=ditmemory; sharedmem->do_dahmemory=dahmemory; sharedmem->do_autocharspacing=autocharspacing; sharedmem->do_autowordspacing=autowordspacing; sharedmem->invertpaddles=invertpaddles; sharedmem->dit_weight=ditweight; sharedmem->sidetone_mode=sidetone_mode; sharedmem->cwrxpitch=cwrxpitch; sharedmem->cwtxpitch=cwtxpitch; sharedmem->squelch=squelch; sharedmem->volume=volume; for(i=0;i<5;i++) sharedmem->cwchannel[i]=cwchannel[i]; sharedmem->currcwchannel=currentcwchannel-1; sharedmem->wpm=wpm; sharedmem->debounce=debounce; sharedmem->recv_buffering=recv_buffering; strncpy(sharedmem->callsign,callsign,MAX_NICK_SIZE); sharedmem->callsign[MAX_NICK_SIZE-1]=0; strncpy(sharedmem->gridsquare,gridsquare,MAX_GRIDSQUARE_SIZE); sharedmem->gridsquare[MAX_GRIDSQUARE_SIZE-1]=0; sharedmem->send_callsign_with_cw=send_callsign_with_cw; sharedmem->send_gridsquare_with_cw=send_gridsquare_with_cw; sharedmem->reply_to_ctcp=reply_to_ctcp; sharedmem->give_callsign_in_ctcp_reply=give_callsign_in_ctcp_reply; sharedmem->give_gridsquare_in_ctcp_reply=give_gridsquare_in_ctcp_reply; sharedmem->give_cwchannel_in_ctcp_reply=give_cwchannel_in_ctcp_reply; sharedmem->simulate_qrn=simulate_qrn; sharedmem->qrnlevel=qrnlevel; sharedmem->simulate_signal_strength=simulate_signal_strength; sharedmem->simulate_sporadicE=simulate_sporadicE; sharedmem->default_signal_strength=default_signal_strength; for(sharedmem->cwcodeset=0;strcmp(cw_decoder_language, cwirc_cw_table[sharedmem->cwcodeset].lang); sharedmem->cwcodeset++); } /* Save the internal parameters into a config file */ char *cwirc_save_rcfile(char *rcfile) { char filename[FILENAME_MAX]; char *homedir; FILE *fd; int i,j; strncpy(filename,rcfile,FILENAME_MAX); filename[FILENAME_MAX-1]=0; /* Expand tildas by the HOME variable */ homedir=getenv("HOME"); for(i=0;ii;j--) filename[j+strlen(homedir)-1]=filename[j]; for(j=0;jdo_key_input? sharedmem->do_mouse_input?"both":"key":"mouse"); fprintf(fd,"cwoutput=%s\n",sharedmem->do_snddev_output? sharedmem->do_sounder_output?"both":"soundcard":"sounder"); fprintf(fd,"cwsound=%s\n",sharedmem->cwsound==0?"beeps":"sounder_clicks"); fprintf(fd,"snddev=%s\n",sharedmem->snddev); fprintf(fd,"serialdev=%s\n",sharedmem->serialdev); fprintf(fd,"debounce=%d\n",sharedmem->debounce); fprintf(fd,"keytype=%s\n",sharedmem->doiambic?"iambic":"straight"); fprintf(fd,"iambicmode=%s\n",sharedmem->iambicmode==0?"A": sharedmem->iambicmode==1?"B":sharedmem->iambicmode==2?"ditmem": "ditdahmem"); fprintf(fd,"midelementmodeB=%d\n",sharedmem->do_midelementmodeB?1:0); fprintf(fd,"ditmemory=%d\n",sharedmem->do_ditmemory?1:0); fprintf(fd,"dahmemory=%d\n",sharedmem->do_dahmemory?1:0); fprintf(fd,"autocharspacing=%d\n",sharedmem->do_autocharspacing?1:0); fprintf(fd,"autowordspacing=%d\n",sharedmem->do_autowordspacing?1:0); fprintf(fd,"invertpaddles=%d\n",sharedmem->invertpaddles?1:0); fprintf(fd,"ditweight=%d\n",sharedmem->dit_weight); fprintf(fd,"sidetone_mode=%d\n",sharedmem->sidetone_mode); fprintf(fd,"wpm=%d\n",sharedmem->wpm); fprintf(fd,"cwrxpitch=%d\n",sharedmem->cwrxpitch); fprintf(fd,"cwtxpitch=%d\n",sharedmem->cwtxpitch); fprintf(fd,"squelch=%d\n",sharedmem->squelch); fprintf(fd,"volume=%d\n",sharedmem->volume); for(i=0;i<5;i++) fprintf(fd,"cwchannel%d=%d\n",i+1,sharedmem->cwchannel[i]); fprintf(fd,"currentcwchannel=%d\n",sharedmem->currcwchannel+1); fprintf(fd,"recv_buffering=%d\n",sharedmem->recv_buffering); fprintf(fd,"callsign=%s\n",sharedmem->callsign); fprintf(fd,"gridsquare=%s\n",sharedmem->gridsquare); fprintf(fd,"send_callsign_with_cw=%d\n",sharedmem->send_callsign_with_cw); fprintf(fd,"send_gridsquare_with_cw=%d\n",sharedmem->send_gridsquare_with_cw); fprintf(fd,"reply_to_ctcp=%d\n",sharedmem->reply_to_ctcp); fprintf(fd,"give_callsign_in_ctcp_reply=%d\n", sharedmem->give_callsign_in_ctcp_reply); fprintf(fd,"give_gridsquare_in_ctcp_reply=%d\n", sharedmem->give_gridsquare_in_ctcp_reply); fprintf(fd,"give_cwchannel_in_ctcp_reply=%d\n", sharedmem->give_cwchannel_in_ctcp_reply); fprintf(fd,"simulate_qrn=%d\n",sharedmem->simulate_qrn); fprintf(fd,"qrnlevel=%d\n",sharedmem->qrnlevel); fprintf(fd,"simulate_signal_strength=%d\n", sharedmem->simulate_signal_strength); fprintf(fd,"simulate_sporadicE=%d\n",sharedmem->simulate_sporadicE); fprintf(fd,"default_signal_strength=%d\n",sharedmem->default_signal_strength); fprintf(fd,"cw_decoder_language=%s\n", cwirc_cw_table[sharedmem->cwcodeset].lang); fclose(fd); return(NULL); } cwirc-2.0.0.orig/cwdecoder.h0000644000175000017500000000150110433700443014152 0ustar pg4ipg4i/* Definitions */ #define UNKNOWN_CHARACTER_SIGN "_" #define NB_CW_CODE_SETS 6 #define CW_CODESET_SIZE_MAX 94 #define CW_SEQUENCE_MAX 9 #define CW_SYMBOL_MAX 5 #define LANG_NAME_SIZE_MAX 8 #define MENU_ENTRY_SIZE_MAX 14 /* Code types */ #define NOCODE 0 #define MORSE 1 #define DOT 2 /* Special meanings of the decoded_msg_wpm variable */ #define WPM_UNKNOWN_WPM -1 #define WPM_DECODER_DISABLED -2 /* Types */ struct cwsymbol { char sequence[CW_SEQUENCE_MAX+1]; char symbol[CW_SYMBOL_MAX+1]; }; struct cwcodeset { char lang[LANG_NAME_SIZE_MAX+1]; char lang_menu_entry[MENU_ENTRY_SIZE_MAX+1]; char cwcodetype; struct cwsymbol cwcode[CW_CODESET_SIZE_MAX]; }; /* Global variables */ extern struct cwcodeset cwirc_cw_table[]; /* Prototypes */ void cwirc_decode_cw(T_BOOL key,double ticklen,int cwcodeset); cwirc-2.0.0.orig/cwframe.h0000644000175000017500000000062307752340644013660 0ustar pg4ipg4i/* Definitions */ #define EXPLICIT_CALLSIGN_HEADER "de=" #define GRID_SQUARE_HEADER "at=" #define CW_FRAME_HEADER_BASEFMT "cw=" #define CW_FRAME_HEADER_XFMT "cx=" /* Prototypes */ char *cwirc_encode_cw_frame(void); int cwirc_decode_cw_frame(char *sender_name,char *frame,char **callsign); int cwirc_is_cw_frame(char *frame); int cwirc_decode_encrypted_callsign_in_msg(char **callsign,char **msg); cwirc-2.0.0.orig/cwirc.h0000644000175000017500000000652310076555372013347 0ustar pg4ipg4i/* Definitions */ #define RCFILE "~/.cwircrc" #define MAX_NICK_SIZE 64 /* That should be more than enough */ #define MAX_GRIDSQUARE_SIZE 7 #define MAX_CHANNEL_NAME_SIZE 128 /* That should be more than enough */ #define MAX_SERVER_NAME_SIZE 256 /* That should be more than enough */ #define MAX_EVT_BUFFER 500 /* Nb events we buffer per sender */ #define MAX_SENDERS 10 /* Max. senders we listen to */ #define XMIT_BUF_MAX_SIZE 2048 /* Max. events we send to irc server */ #define DECODED_MSG_SIZE 256 /* Max. chars in the cw decoder buf */ #define FRONTEND_MSG_SIZE 512 /* Max. chars in a frontend err msg */ /* Types */ struct cwirc_cw_sender { char name[MAX_NICK_SIZE]; double kcdelay[MAX_EVT_BUFFER]; T_BOOL keystate[MAX_EVT_BUFFER]; T_BOOL keystate_prev; unsigned long long keyup_tickcnt; unsigned long long keydown_tickcnt; double playback_start_timeout; double playback_stop_timeout; T_U16 buf_head; double signal_strength; /* 0 -> 1. <1 == undefined */ }; struct cwirc_shm_block { char version[10]; /* Used to detect plugin/frontend mismatch */ int semid; T_BOOL stop_frontend; T_BOOL frontend_stopped; char frontend_msg[FRONTEND_MSG_SIZE]; T_BOOL reconfigure_io_process; char io_process_msg[FRONTEND_MSG_SIZE]; char snddev[FILENAME_MAX]; char serialdev[FILENAME_MAX]; T_BOOL sidetone_mode; /* 0==send cw normally, 1==sidetone mode */ T_BOOL do_mouse_input; T_BOOL do_key_input; T_BOOL do_snddev_output; T_BOOL do_sounder_output; T_U8 cwsound; /* 0==beeps, 1==sounder clicks */ T_U16 cwchannel[5]; /* The preset channels */ T_U8 currcwchannel; /* The currently active preset channel (0->4)*/ T_S8 cwrxpitch; /* Received CW sound pitch */ T_S8 cwtxpitch; /* Transmitted CW sound pitch */ T_U8 squelch; /* Squelch level */ T_U8 volume; /* Sound volume */ T_U8 wpm; /* Words per minute for the iambic keyer */ T_BOOL doiambic; /* Iambic or straight key mode */ T_U8 iambicmode; /* 0 -> mode-A, 1 -> mode-B */ T_BOOL do_midelementmodeB; T_BOOL do_ditmemory; T_BOOL do_dahmemory; T_BOOL do_autocharspacing; T_BOOL do_autowordspacing; T_U8 dit_weight; /* 15 -> 85 % */ T_BOOL invertpaddles; /* 0 = left paddle is dit, right paddle is dah*/ T_U8 debounce; /* nb samples to take to read paddles */ T_S16 recv_buffering; /* Number of millisec. we buffer incoming cw */ char callsign[MAX_NICK_SIZE]; /* Operator's callsign */ char gridsquare[MAX_GRIDSQUARE_SIZE]; /* Operator's location */ T_BOOL send_callsign_with_cw; /* 1 = send the callsign along with cw frames */ T_BOOL send_gridsquare_with_cw;/* 1 = send the location along with cw frames*/ struct cwirc_cw_sender sender[MAX_SENDERS]; T_S16 xmit_buf[XMIT_BUF_MAX_SIZE]; T_U16 xmit_buf_flush_nb_evts; T_BOOL mouseinputbutton0; T_BOOL mouseinputbutton1; T_U8 recv_signal; T_U8 cwcodeset; char decoded_msg_buf[DECODED_MSG_SIZE]; char decoded_msg_buf_char_markers[DECODED_MSG_SIZE]; double decoded_msg_wpm; T_BOOL decoded_msg_updated; T_BOOL reset_decoder; T_BOOL reply_to_ctcp; T_BOOL give_callsign_in_ctcp_reply; T_BOOL give_gridsquare_in_ctcp_reply; T_BOOL give_cwchannel_in_ctcp_reply; T_BOOL simulate_qrn; T_U8 qrnlevel; T_BOOL simulate_signal_strength; T_BOOL simulate_sporadicE; T_U8 default_signal_strength; }; /* Variables */ extern struct cwirc_shm_block *sharedmem; cwirc-2.0.0.orig/cwsound.h0000644000175000017500000000063510063136375013712 0ustar pg4ipg4i/* Prototypes */ int generate_cw_sound_fragment(int sndtype,int keystate_prev,int keystate, int samplerate,int nbsamples,int freq,int amplitude, unsigned long long offset_keyup,unsigned long long offset_keydown, double *samplebuf); void generate_qrn_sound_fragment(int samplerate,int nbsamples,int amplitude, double *samplebuf); void squelch(int squelch_level,double *sndbuf,int nbsamples,double ticklen); cwirc-2.0.0.orig/extension.h0000644000175000017500000000307110062704457014242 0ustar pg4ipg4i/* CWirc extension API */ /* Definitions */ #define MAX_CWIRC_EXTENSIONS 10 #define AUDIOBUF_SIZE 22050 /* Samples */ /* Types */ /* Extension programs must use the API as follows : - An extension program synchronizes itself with CWirc by getting audio samples from the it. Audio samples are always 44100Hz/16bit/mono. - To get audio samples, the program acquires one of the 2 semaphores in the semphore set alternatively, read audio samples from the ring buffer, adjust the ring buffer's pointers accordingly, then release the semaphore it had acquired as quickly as possible. The ring buffer can contain up to .5s worth of audio. Once a semaphore is acquired, the extension program is guaranteed to have samples to read : CWirc won't release any of the 2 semaphore unless there's something in the buffer. - To provoke a key-down in CWirc, the extension sets in_key to 1. To provoke a key-up, the extension sets in_key to 0. - The extension may be killed at any time with SIGHUP. */ struct cwirc_extension_api { int semid; /* 2-semaphore set to synchronize extension */ T_S16 out_audiobuf[AUDIOBUF_SIZE];/* Audio buffer */ int out_audiobuf_start; int out_audiobuf_end; int in_key; /* Input source for extension to key CWirc*/ int pid; /* Pid of the extension process. For internal use only. */ }; /* Variables */ extern char cwirc_extensions[MAX_CWIRC_EXTENSIONS][FILENAME_MAX]; /* Prototypes */ void get_available_cwirc_extensions(void); char *exec_extension_program(char *fname,int ext_shmid); cwirc-2.0.0.orig/grid.h0000644000175000017500000000014707726216412013156 0ustar pg4ipg4i/* Prototypes */ int cwirc_is_grid_square(char *gs); int cwirc_great_circle_path(char *gs1,char *gs2); cwirc-2.0.0.orig/gui.h0000644000175000017500000000005607753267732013027 0ustar pg4ipg4i/* Prototypes */ int cwirc_ui(int ext_shmid); cwirc-2.0.0.orig/keyer.h0000644000175000017500000000166410062722072013344 0ustar pg4ipg4i/* Types */ struct cwirc_keyer_state { T_BOOL keyer_initialized; /* Put 0 here for the first call to the keyer */ T_BOOL prev_dit; T_BOOL prev_dah; int last_element; /* -1 -> nothing, 0 -> dit, 1 -> dah */ int current_element; /* -1 -> nothing, 0 -> dit, 1 -> dah */ T_BOOL insert_inverted_element; int iambic_in_element; /* 0 -> none, 1 -> squeezed, 2 -> released */ T_BOOL paddles_squeezed_after_mid_element; double beep_timeout; double mid_element_timeout; double element_timeout; double delay_timeout; int delay_type; /* 0 -> none, 1 -> inter-char spacing, 2 -> inter-word spacing */ }; /* Variables */ extern char cwirc_available_iambic_modes[][10]; /* Prototypes */ T_BOOL cwirc_run_keyer(struct cwirc_keyer_state *is,T_BOOL dit,T_BOOL dah, int wpm,int iambicmode,T_BOOL midelementmodeB,T_BOOL ditmemory, T_BOOL dahmemory,T_BOOL autocharspacing,T_BOOL autowordspacing, int weight,double ticklen); cwirc-2.0.0.orig/io.h0000644000175000017500000000024207753267732012647 0ustar pg4ipg4i/* Definitions */ #define XMIT_BUF_DELAY 2000 /* ms */ #define DEBOUNCE_BUF_MAX_SIZE 30 /* Prototypes */ int cwirc_spawn_io_process(int shmid,int ext_shmid); cwirc-2.0.0.orig/ipc.h0000644000175000017500000000147307752566656013030 0ustar pg4ipg4i/* Definitions */ #define SEM_ST 0 /* To access the senders table */ #define SEM_FRONTEND_MSG 1 /* To access the frontend message */ #define SEM_XMIT_BUF 2 /* To access the xmit buffer */ #define SEM_IO_PROCESS_MSG 3 /* To access the I/O process message */ #define SEM_IO_PROCESS_WORKING 4 /* To reconfigure the I/O process safely */ #define SEM_PERSONAL_INFO 5 /* To access the pers. info settings */ #define NB_SEMAPHORES 6 #define cwirc_sem_P cwirc_sem_dec #define cwirc_sem_V cwirc_sem_inc /* Prototypes */ int cwirc_sem_create(int key,int nb_sems); int cwirc_sem_dec(int semid,int semnum); int cwirc_sem_inc(int semid,int semnum); int cwirc_sem_destroy(int semid); int cwirc_shm_alloc(int key,int size); void *cwirc_shm_attach(int shmid); int cwirc_shm_detach(void *shm); int cwirc_shm_free(int shmid); cwirc-2.0.0.orig/morsecodes.h0000644000175000017500000003464210433704273014377 0ustar pg4ipg4i/* Definitions */ #define MORSE_CODES \ { \ DECODER_DISABLED, \ ENGLISH_MORSE_CODE, \ FRENCH_MORSE_CODE, \ RUSSIAN_MORSE_CODE, \ JAPANESE_MORSE_CODE, \ DOT_CODE \ } #define DECODER_DISABLED \ { \ "none", /* Language */ \ "No decoder", /* Language selection menu item */ \ NOCODE, /* Code type */ \ \ /* Empty symbol table : */ \ { \ {"" ,"" }/* Terminator entry */ \ } \ } #define ENGLISH_MORSE_CODE \ { \ "english", /* Language */ \ "English morse", /* Language selection menu item */ \ MORSE, /* Code type */ \ \ /* Morse-to-UTF8 latin symbols table : */ \ { \ {".-" ,"A" }, \ {"-..." ,"B" }, \ {"-.-." ,"C" }, \ {"-.." ,"D" }, \ {"." ,"E" }, \ {"..-." ,"F" }, \ {"--." ,"G" }, \ {"...." ,"H" }, \ {".." ,"I" }, \ {".---" ,"J" }, \ {"-.-" ,"K" }, \ {".-.." ,"L" }, \ {"--" ,"M" }, \ {"-." ,"N" }, \ {"---" ,"O" }, \ {".--." ,"P" }, \ {"--.-" ,"Q" }, \ {".-." ,"R" }, \ {"..." ,"S" }, \ {"-" ,"T" }, \ {"..-" ,"U" }, \ {"...-" ,"V" }, \ {".--" ,"W" }, \ {"-..-" ,"X" }, \ {"-.--" ,"Y" }, \ {"--.." ,"Z" }, \ {".----" ,"1" }, \ {"..---" ,"2" }, \ {"...--" ,"3" }, \ {"....-" ,"4" }, \ {"....." ,"5" }, \ {"-...." ,"6" }, \ {"--..." ,"7" }, \ {"---.." ,"8" }, \ {"----." ,"9" }, \ {"-----" ,"0" }, \ {"-...-" ,"=" }, \ {"-..-." ,"/" }, \ {"..--.." ,"?" }, \ {"--..--" ,"," }, \ {".-.-.-" ,"." }, \ {"---..." ,":" }, \ {".----." ,"'" }, \ {".-..-." ,"\"" }, \ {"..--.-" ,"_" }, \ {"-.--." ,"(" }, \ {"-.--.-" ,")" }, \ {"-.---" ,"#" }, \ {"-....-" ,"-" }, \ {"...-.." ,"|" }, \ {"-....." ,"\\" }, \ {"-----." ,"*" }, \ {"-.-.-." ,";" }, \ {".--.-." ,"@" /* Commat */ }, \ {"....--.-." ,"^" }, \ {"...-..-" ,"$" }, \ {"....-." ,"!" }, \ {"....---." ,">" }, \ {"....-...." ,"]" }, \ {"....-.." ,"[" }, \ {"....-.-.." ,"<" }, \ {"....--." ,"&" }, \ {"....-.--." ,"%" }, \ {"....--" ,"~" }, \ {".-.-." ,"+" }, \ {"....-.--" ,"{" }, \ {"....--..-" ,"}" }, \ {".-.-." ,"[AR]" }, \ {".-..." ,"[AS]" }, \ {"-...-.-" ,"[BK]" }, \ {"-...-" ,"[BT]" }, \ {"-.-.-" ,"[KA]" }, \ {"-.-..-.." ,"[CL]" }, \ {"-.--." ,"[KN]" }, \ {"...-.-" ,"[VA]" }, \ {"...-." ,"[VE]" }, \ {"--..-." ,"[GR]" }, \ {"....--" ,"[HM]" }, \ {"..-..-" ,"[IX]" }, \ {"..--.." ,"[IMI]" }, \ {"..-.-" ,"[INT]" }, \ {"...---..." ,"[SOS]" }, \ {"" ,"" }/* Terminator entry */ \ } \ } #define FRENCH_MORSE_CODE \ { \ "french", /* Language */ \ "French morse", /* Language selection menu item */ \ MORSE, /* Code type */ \ \ /* Morse-to-UTF8 latin symbols table : */ \ { \ {".-" ,"A" }, \ {"-..." ,"B" }, \ {"-.-." ,"C" }, \ {"-.." ,"D" }, \ {"." ,"E" }, \ {"..-." ,"F" }, \ {"--." ,"G" }, \ {"...." ,"H" }, \ {".." ,"I" }, \ {".---" ,"J" }, \ {"-.-" ,"K" }, \ {".-.." ,"L" }, \ {"--" ,"M" }, \ {"-." ,"N" }, \ {"---" ,"O" }, \ {".--." ,"P" }, \ {"--.-" ,"Q" }, \ {".-." ,"R" }, \ {"..." ,"S" }, \ {"-" ,"T" }, \ {"..-" ,"U" }, \ {"...-" ,"V" }, \ {".--" ,"W" }, \ {"-..-" ,"X" }, \ {"-.--" ,"Y" }, \ {"--.." ,"Z" }, \ {".--.-" ,"\303\200" /* A grave*/}, \ {".-.-" ,"\303\204" /* A diae.*/}, \ {"-.-.." ,"\303\207" /* C cedi.*/}, \ {".-..-" ,"\303\210" /* E grave*/}, \ {"..-.." ,"\303\211" /* E acute*/}, \ {"--.--" ,"\303\221" /* N tilde*/}, \ {"---." ,"\303\226" /* O diae.*/}, \ {"..--" ,"\303\234" /* U diae.*/}, \ {"----" ,"CH" }, \ {".----" ,"1" }, \ {"..---" ,"2" }, \ {"...--" ,"3" }, \ {"....-" ,"4" }, \ {"....." ,"5" }, \ {"-...." ,"6" }, \ {"--..." ,"7" }, \ {"---.." ,"8" }, \ {"----." ,"9" }, \ {"-----" ,"0" }, \ {"-...-" ,"=" }, \ {"-..-." ,"/" }, \ {"..--.." ,"?" }, \ {"--..--" ,"," }, \ {".-.-.-" ,"." }, \ {"---..." ,":" }, \ {".----." ,"'" }, \ {".-..-." ,"\"" }, \ {"..--.-" ,"_" }, \ {"-.--." ,"(" }, \ {"-.--.-" ,")" }, \ {"-.---" ,"#" }, \ {"-....-" ,"-" }, \ {"...-.." ,"|" }, \ {"-....." ,"\\" }, \ {"-----." ,"*" }, \ {"-.-.-." ,";" }, \ {".--.-." ,"@" /* Commat */ }, \ {"....--.-." ,"^" }, \ {"...-..-" ,"$" }, \ {"....-." ,"!" }, \ {"....---." ,">" }, \ {"....-...." ,"]" }, \ {"....-.." ,"[" }, \ {"....-.-.." ,"<" }, \ {"....--." ,"&" }, \ {"....-.--." ,"%" }, \ {"....--" ,"~" }, \ {".-.-." ,"+" }, \ {"....-.--" ,"{" }, \ {"....--..-" ,"}" }, \ {".-.-." ,"[AR]" }, \ {".-..." ,"[AS]" }, \ {"-...-.-" ,"[BK]" }, \ {"-...-" ,"[BT]" }, \ {"-.-.-" ,"[KA]" }, \ {"-.-..-.." ,"[CL]" }, \ {"-.--." ,"[KN]" }, \ {"...-.-" ,"[VA]" }, \ {"...-." ,"[VE]" }, \ {"--..-." ,"[GR]" }, \ {"....--" ,"[HM]" }, \ {"..-..-" ,"[IX]" }, \ {"..--.." ,"[IMI]" }, \ {"..-.-" ,"[INT]" }, \ {"...---..." ,"[SOS]" }, \ {"" ,"" }/* Terminator entry */ \ } \ } #define RUSSIAN_MORSE_CODE \ { \ "russian", /* Language */ \ "Russian morse", /* Language selection menu item */ \ MORSE, /* Code type */ \ \ /* Morse-to-UTF8 cyrillic symbols table : */ \ { \ {".-" ,"\320\220" /* A */ }, \ {"-..." ,"\320\221" /* Be */ }, \ {".--" ,"\320\222" /* Ve */ }, \ {"--." ,"\320\223" /* Ghe */ }, \ {"-.." ,"\320\224" /* De */ }, \ {"." ,"\320\225" /* Ie */ }, \ {"...-" ,"\320\226" /* Zhe */ }, \ {"--.." ,"\320\227" /* Ze */ }, \ {".." ,"\320\230" /* I */ }, \ {".---" ,"\320\231" /* Short I*/}, \ {"-.-" ,"\320\232" /* Ka */ }, \ {".-.." ,"\320\233" /* El */ }, \ {"--" ,"\320\234" /* Em */ }, \ {"-." ,"\320\235" /* En */ }, \ {"---" ,"\320\236" /* O */ }, \ {".--." ,"\320\237" /* Pe */ }, \ {".-." ,"\320\240" /* Er */ }, \ {"..." ,"\320\241" /* Es */ }, \ {"-" ,"\320\242" /* Te */ }, \ {"..-" ,"\320\243" /* U */ }, \ {"..-." ,"\320\244" /* Ef */ }, \ {"...." ,"\320\245" /* Ha */ }, \ {"-.-." ,"\320\246" /* Tse */ }, \ {"---." ,"\320\247" /* Che */ }, \ {"----" ,"\320\250" /* Sha */ }, \ {"--.-" ,"\320\251" /* ShCha */ }, \ {"-..-" ,"\320\254" /* Soft b */}, \ {"-.--" ,"\320\253" /* Yeru */ }, \ {"..-.." ,"\320\255" /* E */ }, \ {"..--" ,"\320\256" /* Yu */ }, \ {".-.-" ,"\320\257" /* Ya */ }, \ {".----" ,"1" }, \ {"..---" ,"2" }, \ {"...--" ,"3" }, \ {"....-" ,"4" }, \ {"....." ,"5" }, \ {"-...." ,"6" }, \ {"--..." ,"7" }, \ {"---.." ,"8" }, \ {"----." ,"9" }, \ {"-----" ,"0" }, \ {"-...-" ,"=" }, \ {"-..-." ,"/" }, \ {"..--.." ,"?" }, \ {"--..--" ,"," }, \ {".-.-.-" ,"." }, \ {"---..." ,":" }, \ {".----." ,"'" }, \ {".-..-." ,"\"" }, \ {"..--.-" ,"_" }, \ {"-.--." ,"(" }, \ {"-.--.-" ,")" }, \ {"-.---" ,"#" }, \ {"-....-" ,"-" }, \ {"...-.." ,"|" }, \ {"-....." ,"\\" }, \ {"-----." ,"*" }, \ {"-.-.-." ,";" }, \ {".--.-." ,"@" /* Commat */ }, \ {"....--.-." ,"^" }, \ {"...-..-" ,"$" }, \ {"....-." ,"!" }, \ {"....---." ,">" }, \ {"....-...." ,"]" }, \ {"....-.." ,"[" }, \ {"....-.-.." ,"<" }, \ {"....--." ,"&" }, \ {"....-.--." ,"%" }, \ {"....--" ,"~" }, \ {".-.-." ,"+" }, \ {"....-.--" ,"{" }, \ {"....--..-" ,"}" }, \ {".-..." ,"[AS]" }, \ {"-...-.-" ,"[BK]" }, \ {"-.-.-" ,"[KA]" }, \ {"-.-..-.." ,"[CL]" }, \ {"...-.-" ,"[VA]" }, \ {"...-." ,"[VE]" }, \ {"--..-." ,"[GR]" }, \ {"..-..-" ,"[IX]" }, \ {"..-.-" ,"[INT]" }, \ {"...---..." ,"[SOS]" }, \ {"" ,"" }/* Terminator entry */ \ } \ } #define JAPANESE_MORSE_CODE \ { \ "japanese", /* Language */ \ "Japanese morse", /* Language selection menu item */ \ MORSE, /* Code type */ \ \ /* Morse-to-UTF8 katakana symbols table : */ \ { \ {".-" ,"\343\202\244" /* i */ }, \ {".-.-" ,"\343\203\255" /* ro */}, \ {"-..." ,"\343\203\217" /* ha */}, \ {"-.-." ,"\343\203\213" /* hi */}, \ {"-.." ,"\343\203\233" /* ho */}, \ {"." ,"\343\203\230" /* he */}, \ {"..-.." ,"\343\203\210" /* to */}, \ {"..-." ,"\343\203\201" /* chi*/}, \ {"--." ,"\343\203\252" /* ri */}, \ {"...." ,"\343\203\214" /* nu */}, \ {"-.--." ,"\343\203\253" /* ru */}, \ {".---" ,"\343\203\262" /* wo */}, \ {"-.-" ,"\343\203\257" /* wa */}, \ {".-.." ,"\343\202\253" /* ka */}, \ {"--" ,"\343\203\250" /* yo */}, \ {"-." ,"\343\202\277" /* ta */}, \ {"---" ,"\343\203\254" /* re */}, \ {"---." ,"\343\202\275" /* so */}, \ {".--." ,"\343\203\204" /* tsu*/}, \ {"--.-" ,"\343\203\215" /* ne */}, \ {".-." ,"\343\203\212" /* na */}, \ {"..." ,"\343\203\251" /* ra */}, \ {"-" ,"\343\203\240" /* mu */}, \ {"..-" ,"\343\202\246" /* u */ }, \ {".-..-" ,"\343\203\260" /* i */ }, \ {"..--" ,"\343\203\216" /* no */}, \ {".-..." ,"\343\202\252" /* o */ }, \ {"...-" ,"\343\202\257" /* ku */}, \ {".--" ,"\343\203\244" /* ya */}, \ {"-..-" ,"\343\203\236" /* ma */}, \ {"-.--" ,"\343\202\261" /* ke */}, \ {"--.." ,"\343\203\225" /* fu */}, \ {"----" ,"\343\202\263" /* ko */}, \ {"-.---" ,"\343\202\250" /* e */ }, \ {".-.--" ,"\343\203\206" /* te */}, \ {"--.--" ,"\343\202\242" /* a */ }, \ {"-.-.-" ,"\343\202\265" /* sa */}, \ {"-.-.." ,"\343\202\255" /* ki */}, \ {"-..--" ,"\343\203\246" /* yu */}, \ {"-...-" ,"\343\203\241" /* me */}, \ {"..-.-" ,"\343\203\237" /* mi */}, \ {"--.-." ,"\343\202\267" /* shi*/}, \ {".--.." ,"\343\203\261" /* e */ }, \ {"--..-" ,"\343\203\222" /* hi */}, \ {"-..-." ,"\343\203\242" /* mo */}, \ {".---." ,"\343\202\273" /* se */}, \ {"---.-" ,"\343\202\271" /* su */}, \ {".-.-." ,"\343\203\263" /* nn */}, \ {".." ,"\343\202\233" /* `` */}, \ {"..--." ,"\343\202\234" /* ^o */}, \ {".--.-" ,"\343\203\274" /* - */ }, \ {"...-." ,"\b" }, \ {".----" ,"1" }, \ {"..---" ,"2" }, \ {"...--" ,"3" }, \ {"....-" ,"4" }, \ {"....." ,"5" }, \ {"-...." ,"6" }, \ {"--..." ,"7" }, \ {"---.." ,"8" }, \ {"----." ,"9" }, \ {"-----" ,"0" }, \ {"..--.." ,"?" }, \ {"--..--" ,"," }, \ {".-.-.-" ,"." }, \ {"---..." ,":" }, \ {".----." ,"'" }, \ {".-..-." ,"\"" }, \ {"..--.-" ,"_" }, \ {"-....-" ,"-" }, \ {"...-.." ,"|" }, \ {"-....." ,"\\" }, \ {"-----." ,"*" }, \ {"-.-.-." ,";" }, \ {".--.-." ,"@" /* Commat */ }, \ {"....--.-." ,"^" }, \ {"...-..-" ,"$" }, \ {"....-." ,"!" }, \ {"....---." ,">" }, \ {"....-...." ,"]" }, \ {"....-.." ,"[" }, \ {"....-.-.." ,"<" }, \ {"....--." ,"&" }, \ {"....-.--." ,"%" }, \ {"....--" ,"~" }, \ {"....-.--" ,"{" }, \ {"....--..-" ,"}" }, \ {"-...-.-" ,"[BK]" }, \ {"-.-..-.." ,"[CL]" }, \ {"...-.-" ,"[VA]" }, \ {"--..-." ,"[GR]" }, \ {"..-..-" ,"[IX]" }, \ {"...---..." ,"[SOS]" }, \ {"" ,"" }/* Terminator entry */ \ } \ } #define DOT_CODE \ { \ "DOT", /* Language */ \ "DOT", /* Language selection menu item */ \ DOT, /* Code type */ \ \ /* DOT-to-UTF8 latin symbols table : */ \ { \ {"11" ,"A" }, \ {"1221" ,"B" }, \ {"212" ,"C" }, \ {"111" ,"D" }, \ {"21" ,"E" }, \ {"1112" ,"F" }, \ {"1122" ,"G" }, \ {"211" ,"H" }, \ {"2" ,"I" }, \ {"2211" ,"J" }, \ {"1212" ,"K" }, \ {"112" ,"L" }, \ {"2112" ,"M" }, \ {"22" ,"N" }, \ {"12" ,"O" }, \ {"2121" ,"P" }, \ {"2122" ,"Q" }, \ {"122" ,"R" }, \ {"121" ,"S" }, \ {"1" ,"T" }, \ {"221" ,"U" }, \ {"2111" ,"V" }, \ {"2212" ,"W" }, \ {"1211" ,"X" }, \ {"222" ,"Y" }, \ {"1111" ,"Z" }, \ {"12221" ,"1" }, \ {"21112" ,"2" }, \ {"11211" ,"3" }, \ {"11121" ,"4" }, \ {"11112" ,"5" }, \ {"21111" ,"6" }, \ {"22111" ,"7" }, \ {"22221" ,"8" }, \ {"22122" ,"9" }, \ {"11111" ,"0" }, \ {"2222" ,"&" }, \ {"2221" ,"TION" }, \ {"1121" ,"ING" }, \ {"1222" ,"ED" }, \ {"3" ," " }, \ {"33" ,". " }, \ {"333" ,"[EOM]" }, \ {"6" ,"\b" /* Error */ }, \ {"7" ,"\b" /* Error */ }, \ {"8" ,"\b" /* Error */ }, \ {"9" ,"\b" /* Error */ }, \ {"121212" ,"\b" /* Error */ }, \ {"" ,"" }/* Terminator entry */ \ } \ } cwirc-2.0.0.orig/propagation.h0000644000175000017500000000021607726216412014551 0ustar pg4ipg4i/* Prototypes */ double cwirc_determine_signal_strength(int distance); void cwirc_simulate_sporadicE(double *signal_strength,double ticklen); cwirc-2.0.0.orig/rcfile.h0000644000175000017500000000014007714157145013472 0ustar pg4ipg4i/* Prototypes */ char *cwirc_parse_rcfile(char *rcfile); char *cwirc_save_rcfile(char *rcfile); cwirc-2.0.0.orig/types.h0000644000175000017500000000037610062704434013372 0ustar pg4ipg4i/* Common types. Define for your platform */ typedef unsigned char T_BOOL; typedef unsigned char T_U8; typedef signed char T_S8; typedef unsigned short int T_U16; typedef signed short int T_S16; typedef unsigned int T_U32; typedef signed int T_S32; cwirc-2.0.0.orig/xchat/0000755000175000017500000000000010433707212013155 5ustar pg4ipg4icwirc-2.0.0.orig/xchat/xchat-plugin.h0000644000175000017500000001701407743102315015737 0ustar pg4ipg4i/* You can distribute this header with your plugins for easy compilation */ #ifndef XCHAT_PLUGIN_H #define XCHAT_PLUGIN_H #define XCHAT_IFACE_MAJOR 1 #define XCHAT_IFACE_MINOR 9 #define XCHAT_IFACE_MICRO 9 #define XCHAT_IFACE_VERSION ((XCHAT_IFACE_MAJOR * 10000) + \ (XCHAT_IFACE_MINOR * 100) + \ (XCHAT_IFACE_MICRO)) #define XCHAT_PRI_HIGHEST 127 #define XCHAT_PRI_HIGH 64 #define XCHAT_PRI_NORM 0 #define XCHAT_PRI_LOW (-64) #define XCHAT_PRI_LOWEST (-128) #define XCHAT_FD_READ 1 #define XCHAT_FD_WRITE 2 #define XCHAT_FD_EXCEPTION 4 #define XCHAT_FD_NOTSOCKET 8 #define XCHAT_EAT_NONE 0 /* pass it on through! */ #define XCHAT_EAT_XCHAT 1 /* don't let xchat see this event */ #define XCHAT_EAT_PLUGIN 2 /* don't let other plugins see this event */ #define XCHAT_EAT_ALL (XCHAT_EAT_XCHAT|XCHAT_EAT_PLUGIN) /* don't let anything see this event */ #ifdef __cplusplus extern "C" { #endif typedef struct _xchat_plugin xchat_plugin; typedef struct _xchat_list xchat_list; typedef struct _xchat_hook xchat_hook; #ifndef PLUGIN_C typedef struct _xchat_context xchat_context; #endif #ifndef PLUGIN_C struct _xchat_plugin { /* these are only used on win32 */ xchat_hook *(*xchat_hook_command) (xchat_plugin *ph, char *name, int pri, int (*callback) (char *word[], char *word_eol[], void *user_data), char *help_text, void *userdata); xchat_hook *(*xchat_hook_server) (xchat_plugin *ph, char *name, int pri, int (*callback) (char *word[], char *word_eol[], void *user_data), void *userdata); xchat_hook *(*xchat_hook_print) (xchat_plugin *ph, char *name, int pri, int (*callback) (char *word[], void *user_data), void *userdata); xchat_hook *(*xchat_hook_timer) (xchat_plugin *ph, int timeout, int (*callback) (void *user_data), void *userdata); xchat_hook *(*xchat_hook_fd) (xchat_plugin *ph, int fd, int flags, int (*callback) (int fd, int flags, void *user_data), void *userdata); void *(*xchat_unhook) (xchat_plugin *ph, xchat_hook *hook); void (*xchat_print) (xchat_plugin *ph, char *text); void (*xchat_printf) (xchat_plugin *ph, char *format, ...); void (*xchat_command) (xchat_plugin *ph, char *command); void (*xchat_commandf) (xchat_plugin *ph, char *format, ...); int (*xchat_nickcmp) (xchat_plugin *ph, char *s1, char *s2); int (*xchat_set_context) (xchat_plugin *ph, xchat_context *ctx); xchat_context *(*xchat_find_context) (xchat_plugin *ph, char *servname, char *channel); xchat_context *(*xchat_get_context) (xchat_plugin *ph); const char *(*xchat_get_info) (xchat_plugin *ph, const char *id); int (*xchat_get_prefs) (xchat_plugin *ph, const char *name, const char **string, int *integer); xchat_list * (*xchat_list_get) (xchat_plugin *ph, const char *name); void (*xchat_list_free) (xchat_plugin *ph, xchat_list *xlist); const char ** (*xchat_list_fields) (xchat_plugin *ph, const char *name); int (*xchat_list_next) (xchat_plugin *ph, xchat_list *xlist); const char * (*xchat_list_str) (xchat_plugin *ph, xchat_list *xlist, const char *name); int (*xchat_list_int) (xchat_plugin *ph, xchat_list *xlist, const char *name); void * (*xchat_plugingui_add) (xchat_plugin *ph, char *filename, char *name, char *desc, char *version, char *reserved); void (*xchat_plugingui_remove) (xchat_plugin *ph, void *handle); int (*xchat_emit_print) (xchat_plugin *ph, char *event_name, ...); }; #endif xchat_hook * xchat_hook_command (xchat_plugin *ph, char *name, int pri, int (*callback) (char *word[], char *word_eol[], void *user_data), char *help_text, void *userdata); xchat_hook * xchat_hook_server (xchat_plugin *ph, char *name, int pri, int (*callback) (char *word[], char *word_eol[], void *user_data), void *userdata); xchat_hook * xchat_hook_print (xchat_plugin *ph, char *name, int pri, int (*callback) (char *word[], void *user_data), void *userdata); xchat_hook * xchat_hook_timer (xchat_plugin *ph, int timeout, int (*callback) (void *user_data), void *userdata); xchat_hook * xchat_hook_fd (xchat_plugin *ph, int fd, int flags, int (*callback) (int fd, int flags, void *user_data), void *userdata); void * xchat_unhook (xchat_plugin *ph, xchat_hook *hook); void xchat_print (xchat_plugin *ph, char *text); void xchat_printf (xchat_plugin *ph, char *format, ...); void xchat_command (xchat_plugin *ph, char *command); void xchat_commandf (xchat_plugin *ph, char *format, ...); int xchat_nickcmp (xchat_plugin *ph, char *s1, char *s2); int xchat_set_context (xchat_plugin *ph, xchat_context *ctx); xchat_context * xchat_find_context (xchat_plugin *ph, char *servname, char *channel); xchat_context * xchat_get_context (xchat_plugin *ph); const char * xchat_get_info (xchat_plugin *ph, const char *id); int xchat_get_prefs (xchat_plugin *ph, const char *name, const char **string, int *integer); xchat_list * xchat_list_get (xchat_plugin *ph, const char *name); void xchat_list_free (xchat_plugin *ph, xchat_list *xlist); const char ** xchat_list_fields (xchat_plugin *ph, const char *name); int xchat_list_next (xchat_plugin *ph, xchat_list *xlist); const char * xchat_list_str (xchat_plugin *ph, xchat_list *xlist, const char *name); int xchat_list_int (xchat_plugin *ph, xchat_list *xlist, const char *name); void * xchat_plugingui_add (xchat_plugin *ph, char *filename, char *name, char *desc, char *version, char *reserved); void xchat_plugingui_remove (xchat_plugin *ph, void *handle); int xchat_emit_print (xchat_plugin *ph, char *event_name, ...); #if !defined(PLUGIN_C) && defined(WIN32) #ifndef XCHAT_PLUGIN_HANDLE #define XCHAT_PLUGIN_HANDLE (ph) #endif #define xchat_hook_command ((XCHAT_PLUGIN_HANDLE)->xchat_hook_command) #define xchat_hook_server ((XCHAT_PLUGIN_HANDLE)->xchat_hook_server) #define xchat_hook_print ((XCHAT_PLUGIN_HANDLE)->xchat_hook_print) #define xchat_hook_timer ((XCHAT_PLUGIN_HANDLE)->xchat_hook_timer) #define xchat_hook_fd ((XCHAT_PLUGIN_HANDLE)->xchat_hook_fd) #define xchat_unhook ((XCHAT_PLUGIN_HANDLE)->xchat_unhook) #define xchat_print ((XCHAT_PLUGIN_HANDLE)->xchat_print) #define xchat_printf ((XCHAT_PLUGIN_HANDLE)->xchat_printf) #define xchat_command ((XCHAT_PLUGIN_HANDLE)->xchat_command) #define xchat_commandf ((XCHAT_PLUGIN_HANDLE)->xchat_commandf) #define xchat_nickcmp ((XCHAT_PLUGIN_HANDLE)->xchat_nickcmp) #define xchat_set_context ((XCHAT_PLUGIN_HANDLE)->xchat_set_context) #define xchat_find_context ((XCHAT_PLUGIN_HANDLE)->xchat_find_context) #define xchat_get_context ((XCHAT_PLUGIN_HANDLE)->xchat_get_context) #define xchat_get_info ((XCHAT_PLUGIN_HANDLE)->xchat_get_info) #define xchat_get_prefs ((XCHAT_PLUGIN_HANDLE)->xchat_get_prefs) #define xchat_list_get ((XCHAT_PLUGIN_HANDLE)->xchat_list_get) #define xchat_list_free ((XCHAT_PLUGIN_HANDLE)->xchat_list_free) #define xchat_list_fields ((XCHAT_PLUGIN_HANDLE)->xchat_list_fields) #define xchat_list_str ((XCHAT_PLUGIN_HANDLE)->xchat_list_str) #define xchat_list_int ((XCHAT_PLUGIN_HANDLE)->xchat_list_int) #define xchat_list_next ((XCHAT_PLUGIN_HANDLE)->xchat_list_next) #define xchat_plugingui_add ((XCHAT_PLUGIN_HANDLE)->xchat_plugingui_add) #define xchat_plugingui_remove ((XCHAT_PLUGIN_HANDLE)->xchat_plugingui_remove) #define xchat_emit_print ((XCHAT_PLUGIN_HANDLE)->xchat_emit_print) #endif #ifdef __cplusplus } #endif #endif cwirc-2.0.0.orig/xchat/README.xchat_include_file0000644000175000017500000000055407743102315017654 0ustar pg4ipg4iThis include file is provided here for convenience's sake, so people don't have to download the entire X-Chat source tree if their distribution's X-Chat package doesn't provide it. This should be okay as xchat-plugin.h doesn't seem to change much from one release of xchat2 to the next, and the author suggests including the file in plugins distributions anyway. cwirc-2.0.0.orig/straightkey.xpm0000644000175000017500000003432010062565650015142 0ustar pg4ipg4i/* XPM */ static char * straightkey_xpm[] = { "160 80 91 1", " c None", ". c #241D1B", "+ c #44423A", "@ c #788280", "# c #B6A88A", "$ c #CEE2E8", "% c #BCCED3", "& c #ADBABA", "* c #5D5D53", "= c #918A71", "- c #AF8D58", "; c #F8F8F5", "> c #D0C19C", ", c #987049", "' c #B6C6C9", ") c #DED3B0", "! c #838D8B", "~ c #CBAE71", "{ c #393730", "] c #78776B", "^ c #F0EEE7", "/ c #B7AC94", "( c #CAC0A9", "_ c #5C422B", ": c #856442", "< c #C6BEA7", "[ c #343028", "} c #EAE8DE", "| c #A1957C", "1 c #968262", "2 c #D5D1C2", "3 c #BEB39B", "4 c #B79964", "5 c #B2C2C4", "6 c #C9DCE1", "7 c #77705D", "8 c #E6E4D9", "9 c #A2A8A4", "0 c #92948D", "a c #C2BCA6", "b c #7A5431", "c c #302A23", "d c #B8B1A0", "e c #5A4F3E", "f c #7B5E3E", "g c #A8B2B1", "h c #CAC7B5", "i c #B3A285", "j c #A49D8C", "k c #29241F", "l c #8F9DA0", "m c #BBBBAB", "n c #AEBEBE", "o c #E2E3D8", "p c #E1DED2", "q c #6E6A5A", "r c #A7814E", "s c #67523A", "t c #CDD0C0", "u c #AC9676", "v c #CFBEA7", "w c #AAB6B4", "x c #523923", "y c #C1D3D9", "z c #C5AE82", "A c #6C5D46", "B c #B8CACE", "C c #DAD1C1", "D c #4F321F", "E c #9C9D94", "F c #A38D6B", "G c #9B7852", "H c #AC906C", "I c #886E4E", "J c #706652", "K c #B09C7D", "L c #86785F", "M c #92A2A2", "N c #DDD8CC", "O c #4D4F4A", "P c #89826E", "Q c #B2BEBF", "R c #46392A", "S c #79684F", "T c #47301F", "U c #908C7D", "V c #C5B498", "W c #2F2620", "X c #D1C8B6", "Y c #BDC2B9", "Z c #A3835F", "BBBB%BBBBBBBBBBBBBBBBBBBBBBBBBBB'''''''''''''''''''''5''5'''5555555555555555555555555555555555nnnnnnnnnnnnnnnnQnnnnnnn&nnn&&&&&g9l00llEg&&&&&&&&&&&&&&&&&&&&&&&w", "%%BBBBBBBBBBBBBBBBBBBB''''''''''BBBB'B''''''''5555555'55'555''55'''5555555QQQ5nnnnnnnn5nnnnnnn55Q5QQQQnnQQQnnnnQn&&&&&n&&&nw!qO{[c[[cc[[O@M&&&&&&w&&w&w&wwwwwww&", "B%BBBBBBBBB'B''B'''''BBBBBB''''''''B'''''''''''55'''5''555555''5555555555555n555555QQn5Q555QQnn5n555nQQnnnQ&QnnnQnnnn&nn&g7{[[{{{[ckcc[[[[[*lwwwwwwwwwwwwwwwwwww", "BBBBBBBBBBBB'BB'BBBBB''''''BB'''''''''''''''''5''555555''''55555Q5555555n5nn555QQQn555n5QQn5nQQnnnnn5nnnnnnn&Q&&n&&&&n&&!+k[{+{c..k......[ccc]w&&nw&w&&w&w&&ww&&", "BBBBBBB''BBBBBBBBB''BBBB'''''B''''''''''''55''5'''''5'5555''5555Q5n5Q555555QQQ5555nnQ5nQnQn55nQQnnnnQQQQnnQnnnQ&nnnQ&nw]cc{{{kk.k..k......k[ccOM&wnwwwwnwwwwnwww", "BBBBB'BBB'BB'BBB''BB'''''B''B''B'''''5'5'5'''5'55555'5''5555'555555Q5n555nn5555nnn555Q5555QQn5nnQQQnnnnnQ&nn&Qnnn&&&&g*kk{{kk.kkkc{[{{kk....kcc+Mnwnwnngnwnww&w&", "B'B'B'B'B''B'''BB'''B''B'''''''''''''5'5'555'55''''5555''5555555Q5555n555Qn5nnQQQnnn5nnnnn5QnQQnnnQnnnQnQnQnnnn&QQnnw*ck{[...kc*{ln5!q{ck....kkc{M&wwgngngwwwgw&", "BBBBBB'B'BB'BB'''''B'B'''BB'''''5'5'''''''''55'5555'55'5555555555555555Q555n555555QQn55QQQnnQn55QQnnnnn&n&nQ&&nQn&&n!{c{{[k.kk{O*{@@]+[kk.k.kkkkc*wnnwgngnwwww&w", "B'BB'B'B''B''B''B''''B'''''''5''5'555555555''5''555'555555Q55QQ55QnQ5n55nQ5nnnnQQQnQQnnnQQQnnnQnnnQQQnQnQ&nnQ&n&n&&gOOO@{kckkk.kkkkkckk........kkklwwngngnwwwwww", "BBB'B'B''B'''''''''''''B'''''''''5'''5'55''55555'55555555Q555555Q555Q5Qn55Q5QQQnn55nnQ5QnnnQQQ&Q&&n&n&Q&nQ&n&Q&n&nn!+OO*+k.k...k{[{OO{kk......k...qwngwwwwwwww&&", "B'B'B'BB''''''''''''''''5'5''555'555'5'555'55555'555Q55555555nQ55555Q5QQnnQQ5Q5Qnn5QnnnQQQnnnQnQQnn&Q&Q&&Q&Q&Q&Q&nn@{{{+[kc....{+kk[[ck...........*&wwnwnwwnwwgw", "'B'B'B''''BB''''B5''5''''5'55'5'55'555555555555555555555555QQ55555nn5n5n5Qn5nnQQQQnnQQQnnnQQQn&nn&nQnn&Qn&Q&&&Q&&&&!{+{k[kkkkk..................kk*nwngwgwwgww&&", "'B'''''''''''''5'''''555'5''5'55'55555555Q55555Q5555Q55555555n5QQ55nQnQQ5QnQQnnnnQnnnnQQQnn&QQQnQQ&&&n&&&&QQ&&&&&&n9++[ckk...kkkkk............kckclwwwwnwwwwwgww", "B''B'''''''''''''5''5'''5'5555''55'''55555555555555Q5QQ55Q55Q555QQQ55QQnQQQnnQQQQnQQQnn&&QQQnQ&&n&QQ&&&Q&&&&Q&&&&&&nqO{[k...k.kk[k[[[kkkkk.kckcc[Ogwwnwgwwwwwwww", "BB'''''''''''5'''5'''55'55'''5555555555555555Q55Q55n55QQ5nnQQQnnQnQnnnQnnnQQnnnnQnn&QnQn&&nQ&QQQ&&&Q&&&&&&&&&&&w&w&&MO+[k..k.kk{{[q**[.kkkkkkc[[{lwwgwwwwwwwwwww", "'''''''''''''''5''55555555555555'55555555Q5QQ5555QQ5nQ55QQQ5QnQQnQQQQQQ&QQQnQQQQ&QQQ&QnQnnn&QQ&&Q&n&&Q&Q&Q&&&&w&&&&wn!O{kk....kO+{qq*{.kkkkkcc[{@gwwwwwwwwwwwwww", "'''''B'''''''5'5'''5''5''55555'555555Q555Q5555QQ5555nQnnQQnnQnnQQnnQnnQnn&Q&n&&Q&&nQ&&&QQ&Q&&Q&&Q&&&Q&&&&&&&&&&&&&&&wg]+{k..k..{O{7]+[kkkkcck[{*wwgwwwwwgwwgwwww", "''B'''''''''5'''555'55'555'5555555Q555Qn5555QQ55QnQQ55Q5n5Q5nQQnnQ&&QQnQ&n&Q&nQ&&n&&QQQ&&Q&n&&Q&&Q&&&&&&&&&&&&&ww&&wnnMO+kk...k[*{J]+kkkkkkc[{OMgwwgwwwwwgwwwwgg", "''''''''''5'555555555555'5''555555555555QQQ55QQ55QQnnnQ5nnnQQQQQnQQn&Q&QQ&&Q&&Q&Q&&&&&&&&&&Q&&Q&&&&&&&&&&&&&&w&&w&&wwnnl+{k....c_+*7+kkkkkkc[{lwwwwwwgwwgwgwgwww", "''''''''55'5'''5''55''55555555Q55555555n555QQ55nn55QQ5nnQQQnnnnnQn&&QnQ&&QQ&Q&&Q&&Q&&&&&Q&&&&&&&&&&&&&&&&g&&&&w&&w&wwgww*{[...k.[c{+c.kkkkkc{qgwwgwwwwgwwwwgwggg", "'''''55'55'555'55''55'555555Q55Q555555555555QnQQnnQnQQQQnnQQQQQ&QQQn&nQQ&&&&&&&&&&Q&&w&&&&&Q&&&&&&&&&&&&&&&g&www&w&wwwnw!+{k...kkkkkk.kkkkk[{M&wwwgwggwgwgggwwww", "'''5'''5'555555'555'555555Q55'555555555n5QQn5Q5QQQn5nQQnQQnnnnnQnQQ&Q&n&QnQQ&&&&&w9U|h1]9&&&&&&&&&&&g&&&&g&&w&&&wwwwwwgwg+{k...kkkk.....kkk[qwgwgwgwgwgwgggwgggg", "'''''''5'''5'55'55555''5555'55555Q55555n555n5n55n5QQnQQnnQQnQQQ&nnQ&Q&n&&&&Q&&Q&QwZrrZ,b]&&&&&&&&g&&&&g&&&w&wwww&&&wwwwww*+k...kkk.......kk[!wwgwgwgwgggwggwgggw", "'''5''''555'5'555'5'555555555gg9g9gQQ555nQQ5Q5nn5nn5Qnn5QnnQnnnQ&&&Q&Q&&&&&&&&&&w&-rr,,f7&&&&&g&&&&&w&&&w&&&&wwwwwwwwwwwn@{...kk.........kc{gwwgwgwgwgwgggggwwwg", "''''5'5'''''5'''5'5'55'555559uHzuIAgQQ5555QnQQQnQQnnQQQnQQQQQQQQQQ&Q&Q&&Q&&Q&&QQ&wZGr,,bS&&&g&&w&&w&w&g&g&ggw&&www&wwwwgg!+c..kk.........kk*ggwgwgwgwggwgwgggggw", "''''''''''''''55'5'5'55'55559HHZ-G_g55Q55555555QQQQQQQnQQQnnQnnQ&&Q&Q&QQ&&&&Q&&&&&F:,-bb0&&&&&&w&w&&w&&&&&w&&wwwwwwwwwwwgl+[k.k..........kk]wgwgwgggwggwgggggggg", "'B'B'''''''''''''''5''5''5559-4rZGbgQ5QQQ55Q5Q555nQnnQQQnQQnQQQQQnQ&Q&&&QQ&&&&&&&Q&Zb,xE&&w&&&&wmwww&g&g&wwwwwww&wwwwwwggl+[k.k............!gwgwgggggwggwggggggg", "B''''B''''''''B''''''5'5Q'55irrrr,bg55555QQ5Q5QnnQ55QQn5QQnQQQnQQ&&Q&Q&Q&&&&&Q&Q&&&ub:D0&&w&w&&w&&&d&&&&w&wwwwwwgwwwwwwwwl+{k.............klwgwgggwggwggggggwwgw", "BBBBBBBBBBB'BB'B'''''''''''''g,4Gbg55'5555Q5QQQQ5nQ5QQnQnQQQ&QQQQQ&QQQ&Q&Q&&Q&&&&&&Fb,D|w&&mw&g&wgQ&g&g&gwwwwwwwwwwwwwgwwM+{kk............kMwggwgggwgggggggggggg", "%%%%BBBBBBBB%BBBBBB''''B'''''YGGbeQ'55'5555Q5555QQQQQQQnQQQnQQnQQQQ&&&Q&Q&Q&Q&&Q&&&Hb,DE&&&&&&&&&&g&&&&w&w&wwwwwwwwwgwwwgg{{kk............[Mgwggwggggwgggggggggg", "%B%%%%%BBB%B%BBBBBBBB%BBB'B''Y,,:bQ''''''''5555555Qn5QQQQnQQQQnnnnQQQ&Q&Q&Q&&Q&&&&&Ub,D0&&&&w&&&&&&g&g&g&wwwwwwwwwwwwgwwg9{[c[..[k........[gwggwgggwgggggggggggg", "%y%%%%%%%%%%%%%B%%B%%B%B%B%B%Y,r,e5'''''''''''555555Q5555QQ5QQQQQQQQQQ&Q&Q&QwQQQ&&&Gb,D0&w&&&&d&&&g&&&&&wwwwwwwwwwwgwwwww9{[ck..{k........[Mggwggwggwgwggggggggg", "%%yyyyyyy%%%%%%%%%%B%%%&i#P=PFH~V,L7L]L]E'BB'B''''''5''5'555555QQQQQQ5Q5QQQQ&9|||jEGG-:UjE0PPE&&g&&g&gwwwwwwwwwwwwgwwgwgwl[[k...{c..k.....cggwgwwwwwgggwgggggggg", "yyyyyy%yyyyyyyy%y%%%%%%|4iKHHuzVzHZG1::bfBB'B''BB'''B'''wgdhhdgQ55'''55Q5QQQjrFZG,Z4#zuG:bbs__9&&d&w&&wwwwwwwwwwwwwwwwwgw!{+ck..{{OOk.....kMggwgggggwgggggggggwg", "6yyyyyyyyyyyyyyyyyyyyy%uHzz4H-4HFG1Z1:SbAB%B%B%'BBB'''Yj#t2X))>KE555Y''Y'5'5EGrZZG,rZGGG,I:s_xgQ&&&&&&wwwwwwwwwwwwwwwgwwg][{k...[{{Ok.....klwggggggggwgggggggggg", "y6666666y6y6y6yy6yyyyy%FHz~iZ4H-FGZZGIIff%%%%%%B%%%B5Ed))}^)~#~~F15B''''5'Y'jGGGG,rG,,,,,:fs__g&QQ&&&wm&&wwwwgwgwwwggwgwwq{ckc..{k..k.....k!gnwwwwwggggggggggggg", "66y6y66666y6y66y66y666y|Hzi~-H4i-rG1G:fsS%y%%%%%%%'9#h)ppoptVFI44:L'''5'''5'jGGG,,,,G,,G,::b__&QQQQQQ&&&&&&&&w&wwwwwgMMl!+++kk..[[+{k......]Mgggwwggwggggggggggg", "66$6$666666666666666y666d1ZFH44Vz##ii|||9mmYmmYmmdiVppo^}}p)>VKf|9/gwmgdgg/g/u-,:,,-4~4r::::10dwdmwd9QQ&QQnn&&&&wnw0*+eO+{kcckkkc{+ck....kk+OO*@Mwggwgwggggggggg", "$6$6$666$66666666666666yQK#VvXC)Np8}^^;;;;;;;;;^;2>po^}}}}p)hh>uS3hhN2222thhhYX)p}^^^^;;;;;;;;;;8>pp^}}88})X>h>a113(tC)pp8^^^^;^;;;^^^X)p^^}8)>>4i>hhazSK)o^o)>X)~r,G3tt<11d)}})V#>)4:bs|h)t#IKatthYaaV3333#i||uuuFuid3dmd33dddd3/33uU9Qggwwwwq[cck.kk.k.kkkc{{k....k.kkc[{*Mnww&wwwwwwgwww", "6$$$$$$$6$$$6$$$6$$$$$$65/m<(CCp8^^^^^;^;;;;;;;)>)oo)4t>>>Gb_=mNtmfFmhhh(p)~>o))>-f_ihNt>A13hhhYamm3dd/#iju||ujiji##########3/V3V33##i#//##uFrGLIII:I:S:ffffAfJflnn5nnnnnnnn&n&&wnnw&&&", "6$$$$$$$6$6$6$$6$6$$$$$6%#VX)NN88}^^;;;;;;;;^^})#>)h~>^8))4bS>tpt>fFmthh(aa3//#/#iu||u|ijii#i#iiii##33V333V3z##z/z##K-FrZ-ZrGGLGLGIII:::,l55555nnnnnnnnnnnw&n&&&", "$$$$$$$$$$$$$6$$$6$6$6$$'#/vX)p}}^^^;;;;;;;;;^^84t)t>4)}))1Ga)NppzIuahYhamammzd//#j4|u|uiiji#iiii#//Vath~4>>4F>)ooop11dYhhhhtt>#~a)ooopohLmYBBY'YYYYYmmmm&m9111ddwdwdg/w3g/#dmm3mm3dd3//uH4Zu/iijiiKu|uK|1ZFZjuj|wBBBBBB''B'''5'5555n555", "$$$$$N$$$N$$N$$$$$$$$6$$$$yZZGs+R[fI:Abbbss966666M>>httt>$}}}}op1y66666666y66666666wD_]6666y666y66y6yyy6yy6y6y6yLbrx!yyyyyyyyy%%%B%%B%%ByB%BBBBB%'BB''BBB'5''555", "$$$$$$$$$$$$$$$$6$6$$$$$$$yFFZART[_sbsbbbs_/$$6$66j>>htt$o^^}ooF7y666666666y6y6y6y6MJPAq9y66y66yy6y666y6yyyy6yyyLb-_Uyyyyyyyyyyyyy%y%y%%y%%%%%BBB%BB%'BBBB''''5'", "$$$$$$$$$$$$6$6$$$6$6$$6$6yFHF1s_sb_ssfbbbs966$666yM~B))$}}o})rS]6666666y6666y666BU]=0J*066y66y66y6yyy6y66y6y6y67brx0yyyyyyyyyyy%yy%y%y%%y%y%y%%%%%%%BBBBBBBBBB'", "$6$$$$$$$$$$$$$$$$$6yYwgg9j1F1G:f:S::bbbbbsg$6666$6%t#ah))$)~F1L]66666y66y6y66y6y%0qS0gBy666y6y66y666yyyy6yyyyyy0I,AQyy6yyyyyyyyyyyyyyyyyyyyy%yy%%y%%%B%B%BBBBBB", "$$$$$p$$$$$$$$6$6$$QFi1LL1ui>3u|111GI:__sL966$6$66$Boot>m~>a/44LLy666666666666666666y'E]0yyy666yy6yyy6666y666yEJAS]AA@%yyyyyyyyyyyyyyyyy%y%yy%y%y%%y%y%%%%%%%%%%", "$6$$$$$$$$$6$$$6$$$iFKHuFuza#4SsLLP=P=P====!P=P]RRs==AA7L]L]]]]77777qqqqqqSJARD_:bxWW_A*AsAAAsAssAsss*s****lB%yyyy%yy%yyy%%%y%y", "$$$$$$$$$$$$N$$$$66|HKKz4|KuFLG1GLGIs_x_e7LL@PPPPPP|o}}opN6ta#4SsPPPPPPPP@P@P]]]]7AAfSA*7777777L777S777S77qSqARD_bsxTW_*sAeses*es*e**esessss*J9y%yy%y%y%yyyy%y%y", "$$$$$$$$$6$$$$6$6'EFuiu#H-44FGI1,I1Ibs__sAJS7q77777=oo^^op)t>~#beAJAJJJJJJJfAJAss*AfAJf__sAAAAAsAAsAsAsAssAssexx_bbxTWRse*sesesseeseeseseeseeee@ny%yy%yy%%y%y%%%", "$$$$N$$$$$$$$$6%j00==FI::,Fi4-:fbesbAJJJLLLP==P==PP=)op)6)>(zK4b7L=PPPPPPPPPPPLJAA3KeJSA**AASqSJS77SJJJqSJAJAs+x_bbxT[esJ0jeeeee_e_eeeeeeeessssAJM%%yyy%y%yy%yy%", "$6$$$6$$$$$$$%9U!UUU=Ls_xTxbb_TcWWc_bIILILLP=====PP1t)XaV##i4-rsfLLP=P=====UFU==SIzIs1AesSqqJJL77I7P7LJS]LPP7JeesIfeRRsqs:G_ebAAAsAsAsssAsAAAAAAAJ@&%yyyyy%%y%%y", "$$$$$$$N$$6y9UU!=P!P]Js_DxsG:_DTWTTR_SG1LIILP==P=P==>>>~V###i4HISLLLPLPPPPPPPP1Pse1i|ij|U|j||||j|#j#||0|jE|=U=1U=FUP1PUPIGS_eAAAAAAAAAAAAs**A*s*AAAq0'y%%yyyyy%y", "$$$$6$$$$6gUUUUPPPPPLLfAsssISbb_seAASI1G11LP=======-ahh>>VVVzi4L7PLPPPPPLPPP1PP17ff4~~~~>~V~4----444-r---rrGGGGGr,rr-4444r__sfAAJAAAAAAAAAAs*AAAAAAAAq9%y%y%%yy%", "$$6$$$$$Y///dd#/g//d//#ii##///##ii//#/3m3aaaa>>h>)ttpp8o888op)))X)t))2tX)tX)t)t222XCCXX)X))))CC)C)XX))X)X2XXX)XXX>>vvvvvVzKujjj|||FF=F1=111111LLLILIII7Pn%yy%y%y", "$p$$$6$wiVhXX>>>vvvVVVVVV#iHF19%%y%y%", "$$$$$$mFd3Vd3Vmth))N))pN)N)N))N)222hh((a(ah>>aVaVVVVVVvVVVVVzVzzzzzVVzVV>VvVVVVvVVVVvvv>vvvvvvvvvvvVzzzizi4u4HH-Hu44-Z-rrZZGG,IQy%%%", "$$N$$6iKKKiiii#dd3aXXtX2Npo}}}^}8}8}8o)h22222)NNoo888pN2NCN2((a333//###ii##ii4KKiKi4K4KKuHu|HHHuHHuuKHHHH4uK4uHHHKiiKK4KKKi4KK4uKHHHZ-ZZZGZGrZZrrrZGGGG,,I:&yyyy", "$$$$$6KKKiiii////3V<(X222CNppppoo}}opN2XXXX2hX2)p88p8888ppN2(Yd3d/########i###iiiii#iKKKKKuuH||HuHHFHHHFFFZFHHHHHHu4uuuHHHHHHHHHFZHZFZZZZZZGZGrrrrrGG,G,,,Iwy%%%", "$$$$$$uuKKiii//#d33m c #97BBCE", ", c #D6E2E8", "' c #4F4C48", ") c #3D3E3B", "! c #897C71", "~ c #D1DEE3", "{ c #BCC1C2", "] c #213825", "^ c #7C888A", "/ c #939087", "( c #FADA86", "_ c #535C5B", ": c #363C3D", "< c #F3D687", "[ c #EEC371", "} c #767066", "| c #323A39", "1 c #191E18", "2 c #BDC8CA", "3 c #716558", "4 c #BDA990", "5 c #C8D6DB", "6 c #9D9180", "7 c #C2C9CC", "8 c #2E4D34", "9 c #C6CED1", "0 c #2E3736", "a c #536563", "b c #FAF0B8", "c c #ABB3B4", "d c #6B7F85", "e c #A29B8E", "f c #B4C7CE", "g c #9DA6A6", "h c #809AB3", "i c #ACBBBF", "j c #1A3E1A", "k c #3F5F47", "l c #767875", "m c #825332", "n c #C8D2D5", "o c #212524", "p c #D9CFB6", "q c #656E6E", "r c #CEDADE", "s c #929B9A", "t c #404949", "u c #606455", "v c #2B302F", "w c #F4F6EF", "x c #E4C080", "y c #9E886F", "z c #B4C2C6", "A c #697677", "B c #405648", "C c #DAE6EA", "D c #859193", "E c #8E877C", "F c #ECDAAB", "G c #ACA69C", "H c #C6CACE", "I c #6B523D", "J c #BBB2AB", "K c #CFD4D6", "L c #66422C", "M c #505553", "N c #1C421C", "O c #645D55", "P c #252A2A", "Q c #78807F", "R c #E6F3F7", "S c #435250", "T c #B4BCBE", "U c #F5E6C3", "V c #889B9F", "W c #FCFBF3", "X c #CEC8BA", "Y c #CACED2", "Z c #5F6768", "2727H77H77H7777777H9H77H9HHHHHHH9Y9HH9HHYHHYHY99H9YYYH999HHHHH7H9YYHYHYYY9HH9999HHH9H7H99Y99YYY9HHHHHYYYYH797999997999YnYYYnnnnn9nn9Y999n997%72727222222{{{2{{T{", "7{777{77H7777{X{77HHH7HHH9777HH9H9HH%HHH7HY99HHYHHYHHHHHHH79Y7H9H779HHHH9%99H77H9H777HHHHHHHHHHH999H9YHYH997%2777H9HY99Yn99YYYY999n99H9n97%%H%72777{22{{z2zz2f{2", "7{7{H7{777{H{HHHH7H7777YHHHH7HHHHH9HHHHH777HHHHYYHH79HHYHHH7H77HHHH799HH97HYYY9HYYHH77HH9YH999YHHH7H%999HH9HY9777779Y999n99Y99999YYn99999HY77777%2722{f2{22{{2T{", "{{{7{7HH{7H{7HH777HH77H7HHHHH9YHYYHY9HH7HHXH9YH9H979HH77HHH7777HHHHHYYH999Y9Y7H99H7277HHYH%99HHHHY92HHHHH77H%77H77779YnnY9Y99YH9H9nYn97n9n7277%72{f{{z*$>izf2f22", "HH{7{H{HHH{77H77777HX7777777HHYH9YHH97HH979H99H9HH777H77HHHH7X79HH77HY99H7YnnnY99n977797YH9H977H77977HHH97777H77H7777H999nnY9nYnYH9YYn%n95n%%9772{fiDa8+=k#>2f{{", "77H{77H{H{7H77H{777H777777777H7HHY9HHHH9H7H7HHHHHHHH9Y77HHH777HH77%%HYHH9YHYY999%nHHH799HHH7H99H7HHH9HHHHH77%7%H72HH99H%9HH99999%%%nn99%n979H%7{2c#k88=---+@*2f2", "{H{H{{H77{H{H{H7{X2HH77X777H7H9Y9HHH77HHH99HHHY99HHH9HH77HH7HHH9H7Y9HYHH9HHHH99H99HHH799H797H9HH7H7H99%HH%772H77H77HH%HHH77%Y9HH999H%nY%7nn9H22c#B===+Nj]--]@T{z", "H{7777{7{7HHX7{777H7HH{7{77HHHHHHYYHHH79H77HH9HHHYHY97HH7H7HHH9HH77%7HY9Y9HY99HHHH9999777H799H97HHHYY7H%nHH7777HH727%H%H%H%HH9H7HH%%H9%Hn%92fcdB===++NjNN+j-8${2", "77{H{7X77{{777{HH7H7HHHH777HY99Y99HHH77HHHHYYYYY7H7HHH7H9HH772ceyEEscH97HH9H77YH9HHH7997H77997H9n99nn7H79%7777277277H%%7HH%%H7%H77%%HHn%%%7cdB==++NN+NjNN++]NdT2", "H{H7H77H{HH7HH77HHHHHHHH7HHH7H79YHYYYYHYYHHHYY9HHHHH7HHHHH77{GesceDE}/7999YYHHYHHHH99%77HHHH997779n99n%9777%777f2772n9%7%7HH%%7%77HH77H77gA8==+NNjNNjjNNNNN+8a2z", "H77{7777HH7H7{7HHHHHH777X7YHHY9HYYH9YYYYHYYH9HYYYYYHH7HYHHH2nr2{cscsV}iHHHHYY99HYY%7H7777999YYYY9HH79Y99H77%7777{272HH%7H7777%H%H7%%%%f*@8=+NjjjjjN++NNNNN++=az2", "7H7H{7H7H{77HH7HHHH77X77HHHH99H9H9YY9YHHYYKn9YHH999YHH7HYHHHn57n2$sD^qcHHYHHHHH9YY977777777%99H9HYH7Hnn979H77H77H22HHHH2777H%7%H%%27zV@==+NNNNjjj+++NNNNjN++=azz", "7{X7HH7{H7HX7{7HHHHHHHH7H9YHHHHHY9YYY9YYYYHKYYHHYHH9HY9HH7H79r2%TsgDQ}THH9Y99HHHHY%H997HH9H%%9H9H9n%9H99H797%H7H777H7HH77%%7%HH7H%fVa=N++NNNNNNNN+NN+NNNjj++=az2", "7H77X7HH{H{77H77HHHH77777H9Y9HYYYHHYnYY9nnYYYnKYYYYYYHHHHHH79n2T*g*sQZTH9YYYHHH9%9n%77977799H%%H9%9H9999%HH%HHHf72f7H7HH%997HH%7zDk=+NNNNNjNjjjNN+++NNNNNN++=azz", "{777HH7H777{77779YYH7HHHH7HHH99YY9YYYHHY%nY9YYYYK9YY9H9H7H7772T2zc*g^qz9YHYY7HHH9997HH%9H9H9HH%7H7n7%99H7%H%%H2HH7%7%7%HHH%H%2i^SNNjjjjjjjjjjjjNN+N+NjNNNjN+=@T2", "H7777HHHHH7H777HHYHHHHHHHH9H9HY9Y9HH9nY9Y99YYKnY9Y9nY9HY7HHH%nr2Tgcs^qT999999HH79n99HHY9Y9n999999999H7777HH77H7777H777H%%777*A8j+NjjjjjNjjjNj]+++N+NjNjNjjNN=af{", "77HH7777777777HHH9HHHHHHHHYHYYY9H9n9YnY9999YYYnKn979YHYH999Hz2{n%gDgQu{9997Y9H9%9H9Y9HH999nn9n9999999%77%H777%7%H7%77%HH%%*Z0-jj]jjjjjjjNjjjjj+++N+NNNNNjjjN=a22", "H7HHHHHH{7HHH7777HYHH99999HYY9Yn9nYnnYX99nYYYYK99n99YY9YYHn97%%2csc^lu2Yn9999nHH99nn9YY99nnYnYnnn9n977%%7%%%%727H%7%7H%7*@0-]NNjNjN]jjjjjjjjNjN+++N++NNNjjjN=af{", "HH7H9YY9777XH7YYYHYYHY9YXnYnK9nY9nKY5Knnnnnnn9Yn9nY99YYYn9H9%ci2T*D^Qu{9HH9999999999nY{ee6e66///gHnn%7772H7H7%H27%7%%H$_vojNN+NNjjNjjjjjNjjjNN++++NN+NNNjjjN=@f2", "HHH799n9HH777HH7H9YHHYYHnY9TE!yGe6!}333sTT2nKY9KnnYKYn9nY99%T$5Ww*gz^q%9%%979799%9Y9ce!m3eJTe!3')}7{ic{29%7H7HH%%9%fV_--jNj+++NjjjjjjjjjjNNNNNj+N+++NNNNNNNj+@22", "HH9H99nHHHHHH7Y99999H9YYK9nG3}WWW!3G!X)lge'g5nnYYnYnn5nnnnH{D$&WCgDDgZl999n959H99%n{lE}IKWWG'}EXOODD{{{*H%%n%7%HHzDSP-jNjNjNN++NjjjjjjjjjjN++++NNNN+N+NNNNNN+a22", "Y97HH99n%77H799Y9HHYnYcTJc{^Ou{WU')O!'v^YGMs5KnKKK5Ynnnnn952gQu^Q_t|tDDn9%9nnY79T{Hc^^AI}TJ''Hcu^SQ/KYKcn%nn%nHi^t|jjj-j-jjjj]]jjjjNjjjjjN+NNNNNNNNNNNNjjjNN+@2{", "HY9H997Y9%9n9nnYn9YH99c{{cGZQMl{G'qzevOZAuADnK555K5K{2{2{{22{cDizneDQTTT{cT{s2{l{{HJQ'sMMie)'HTqTM_g,H~eD^tS_aktPoo1.1.1.....1..1jjjjjjjjj+N+NNNNjjjNjjNNNNN+a%z", "YH{{7T2TT{TG*cz2z2T2TYc77Y^qcMQ$/S}2/)ZtaQZ^n5K5KKK5'))::0||:)t'^/uvPvvPvovPoP')H%Yi0|iZOhstM2cqYq0VKYrsv01P=k8]1...11111P-=-.1.1j-jjjjjjjjNNNNNjjNNjjjjjjN++@22", "nc{{T{{{{ccccsz5%f%fg%z5~CqOgZA#lMqz#t'v:|v}nYX2Kn5CvvPoPPPvPPPPQ}_'oo1ov1ovo1MOKr52vvsqZ$$t'TGQ2gvT,YncPv0tojM_:P..11..-@_uqN1.1NjjjjjjjjjNNNNNjjjNNjjjjjN++@f2", "{gKYTKT*TggGcs}Vggggls%2nKT|ZqdzQ)ufEtlO)MulE6EEeyenvPPPPoPoPPPP^/uO|P1o)1o'voQs&nCrZ'#qAhhSMcs#cXM&~YKc)tM_qul!uM]...11a}_o)Z-.1NjjjjNjjjNjNNNNNjNNjjjjNjjN+@2f", "cT2~ccHgcsggg^QsD^/sg{r%%7,)ZZd>D)Z%^'sGlcJ2cURYX{{pPoPPvPPPoooo/gqE'1ooOoo'Po!Y~CKKeEZd@h*a'gEqsJ6r&K~T}Dg*{{22l}B....-@e2v0OB..jjjjjjNjjjNNjNjjjjjNjjjjjN+N@22", "eJ&J{{G%gggcYEXK2{%rC&n2nge)ad^9D)u2^_!^ecTcgJ44pWbCPPoooPPovPov/gO3L1.1)1P)ov'Zrnn9Za_AA**_M*E@QQesrY7cl^sc22X{Euk....1u/2||B+..jjjjjjjjNjNNjNjNjjNNNjjjNjjN@z2", "Vc{2{G2cgG/c{QE/QQ^DVsiT2s_0Z^hfD'Z%^S}qqlQlZ/sec~,KvPPPoPPPPvoP/gq_v..ovo)PP:t'72nTlM_AA>$_MzGAAq_DrKKcAQQ^$g$V}u:....1kuu)tu]..jjjjjjjjNjjNNjNjjjjjjNjjjjjN@22", "sDcTgTgsc^$eg^lu___O_ZcTi$qod#^$^)q2DMqt:ttS_O33644KPPPPooPoPoovssqOP..1P.vPovv'2zT*)PBdd$*a_zcqd30^,HKc'MMB__u@uB......-BBt_]..1jjjjjjNjjNNNjjNjjjjjjjjjjjj+@2{", "T^*D$s^sD/QQsQ_q}qAA^**GcVtPQ^hhh_q2DZuv0vvZn%T{G_39vPPPPPPooPPPes})o...o11ooP1)c{isPPMAd>>Z_zcqQuo}nr7goo1:o]Bu8o........-]P....jjjjjjjjNjNNNjjjjjjjjjjjjjjN@f2", "n/lQlQQlQqAAAq*ziT{29HDgsD0v^Ah$DtZ%DqMP|:vunr~r~r~&:vPPPPoPvPovs}qo...11.11ov1:Vgg^oP_Ad>>@_zcZ#_PZHYH^PP.]-Po0-...............1-jjjjjjjNNN+NjjjjjjjjjjjjjjN@22", "97sssssss/ssgG%K55nKK9^sD^AtqAhhhtqHDAS1)aMd9KrrrKK~|0vvvvvvvvvvsM_PooPv)v)tt''_Q^^dt0Mahff@_i*_#_|q7ccg^DE/gg^u]]------------jjjjjjjjjjjN+NNNjjjjjjjjjjjjNjN@22", "n999799nn9Y9Knn5nKKn5KQ^^lDSaqh$hMq9sl@SBZaQKrrrrr~T3qqAAAAlqv|vMAZ!'EKKKKKK55rH/DDDd__@hff@uTgasatdgGecH7%%%7%H*A+-jjjjjNN++NNjjjjjjjjjjj++++jjNNNjjNjjjNjj+a{2", "nYHn9YYY99nYnnYKYYKKnKs/D/{ZZ@hhh_a2slQZSAaQnKrK~KK~r~KrKK97c|vPovvM:^KKK~KrKK55rKrTdZ_@hf~#Ac*qc_l^ssE*Y%9Y9X29%2idN-jjNNNN+N+jjjjjjjjjNNNN++Nj++NNNNNjjjj]+@z2", "YYn9H999%nnnYYKnYKYYKKKrrnndaq#$^MuHD^Q@M^Z^K,KrKr~KrHD}ZOqZqZM)||)MtMl/Q^Qq*KrrKYKTA__ahf~dZTc@caDc/Ds{nHHHH999H%%9T^8--NNN+NNNNjjjjjNjNjNNNN+j+NN+NNNNjjNN]a2{", "YH99HHHHHY9nYYYn9Y9YKYYYYYnQaZhh^Sq7DsQAMsqQYKKrKr~rKKsq_MqD^,CcQqq^^A%,*ldAcKrnKrKiAAaah>>@_2cAcag9YKHH9H7YHH%9HH%%7H{DB--NNNNNjjjjjjjjjjjjjN+N+NN++N+NjNNN-az{", "Y9HYHYnYHY9YnHHHH9nn9YKKYnK^aqh>^Mq%/D^AMgA^Y~KKrr~Kr5rgqt)Mgq&Gu:'A)V&QM_QKrrrr5KniAA_dh5z@_2cdzZgnYYKHY99H9YH7H999%%2%zVB--NjjjjjjjjjNjjjjjNN++NNNNNNNNN++]_22", "YY99YHY9YYHH9HYYYHYn5YnnKYn^Z@hhhqq2Ds^@_il^7rKrKKrKKK{DOt:tA_r6M))S:Zc_t|_cn5KrKKrTAZ_Ah>$aM2cAi@gnY9YHHHH2HHHHHH79997%2%2$kNNNNjjjjjjNNjjjNNN+++jNNjNjjN+N-a{{", "HHHH9YHH9HHYH9HHHY99nYHHYn9^_Ah$h_A7sg^Aq2A^YKKKKrKKK9slO'3HQ2iAS_ZgA_g,*@_Acr~rnKKiAd_ad>*__cgAiQgKKKnYHH9XH9H7H99HH%%7777H7*@=NNjjjjjjjjjjjjNN++++NNNNNNNNjZ22", "HH77H9HH7H7H79999YYH%YY9KY9^adhhh'q{Dc^A@zA^HrKrKKK55Y^Z_3^2^wWC$lAs*@,W%#AqTKrKn5riADM@d>*__sg#T^gnKKYYYH99H9H2X2HHH722%777797*d8++NjNNjjNjNNjNNNNNNNNNNNjN]@z{", "77{799X777H772HHHHH9HHYYH9H^_dhh^SZz^c#q_ilQHKrKKKrKKKcE_')Z^gCcAZuuZZT$_tS^KrrrKKYiAAS@d>*a_sgDfQgKnYYnY7HHHH9HHH97%%777%7%77279i#B++N+NNNNNjjNN+N+NNNjjjNj]@2z", "HH7HY9HHHH9HHHY7H9H7HHHYYYn^_dhh^MZ{Dc#q@zdQnKKKKKrKKK5cl')OnVWXqt_A_V&qS_DrrrrKKrKTAQSAd>$a_/ssf^gYnnYn9HHH9H9HH2HX79X7277227727%%z#k=++NNjN+jjN+NNNNNNNNNjjq2z", "YY7YYYnH79H99H77HHHYHYYnYYYdZh#hd)Z{^{^Zu2AQ7~~rrKKKrrTG3'tZ*^,g_SMutlcAtt^srr~rKr5iAqSAh>$_uegDfAgnnKnnY7HHHHH9Y7227277HHH722%22222%fVa=+++jjjjjN+NNNN+NNNNNd{2", "9HYYYY9HHnKY9YH9Y9999YKYnKKQqhh$^SZTD2#ZA2q^9KKKrrrrrnVA_'}K,&RTqZ3g^aTR$@Zq{r~~KrKTqDSd#%>aaG*sf@G5nKKn999779HHHX22X7H99%X7727222222%ff$@==++j+jjN+j+jNNNN+8Df{", "HYKnnY9YYYnnnYKnnYnnnYKYKYrdA$$>Dt_TD7#ZuA_QY~~rKrrrK9Q_''}7$WWwsaZQgA&wgd_ZHK~~~K,cZ^S#$5>dagg*z_*KK59nnH979H9H7H7727HH9H77H7H2222222{2%f*A8++NNN+N+jNNNN+N=V{z", "YYYYKKnKKYKYnYYKKKKn5KKKYKrQd>f>hMacQ9DZOI)'Hrr~K~K~Kr2Q_))_d$,eq___Ma$l::as,~~~~~~TZZMh$>$a_s/iz_*rKKnK5Yn9nHHHHHXHH2HY2H72X77{{2{2{2{{{22f*d8==++N+NjNN+N-Bcz{", "YYYKYKKKKKnKKnKKK5KKKYKKrYK^#5C~$MZg^2#q!mLLX~rK~KKKrnT/}))MQD,zZtMZBgr_tSAfK,~~Kr,c_lMV$f$aus^TzaerK5K5KKn9Hn9HYH777X7%X2H7H{{XH{2{{{{{{T{{{fcdB=++NNNjj]-|dT{T", "YKYKYnKKKrKKKKKKrKK5Kn5YHzz^h,WR9^^Ts2qa!mL'G{7{772{2*Q_t'!T*&wKAaqQDd~~hZZq${{2{{z^tQMh>>*a_E#czAszTzTTTTz2nnn9YHH9HHH%H72X27{72X{2{2{{{{{{{zTzc#k8==jP-oN@*2{T", "Y9YKnKKKrr~KKKKrKrrK~5zziTTGGHwwU{Ge64lImIL)*z{TTT{zTgQ')tQ{*WWRDqq^$dr&*AaZsiTTiiTsMAMlf>*aBEQc*A/iTiiciicTTnnn9n9Y9HH9nH7277722{2X2X22{{z{T{TTTTi#k8N]j=#*2TTT", "YnYKKKKpKKKKKKKrKKKK{TTiiTT<<;bbU([[44ym3mL)cTfzzz{fTcQMvv_lqK,XZS_qQq25DkSSsTTTTTT$_AS_r%*aMDlGc^sccciccccicc75nYYY999YnYHHH27X7{{2{{{2{{T{{{{TTTTTTgD#V*>iTT{T", "XYYnnnKKKKKKKKKKK52TzTi{TT{<;Ubbb(<[[yy}Iu'McfTTzzzTzgq'|)q*DWW,QMuADAfrh@__VzzzTTisqqS_iwCQBQQgqBDTTiciiciccicT9nnn999nY9HHHH772H{{{2{{{{{{{TT{TTTTTTTicTTTTTTT", "KKYKKKKKnKYKKKKKHTiTTTTiiiTx[******c>i>iiiiiiiifff%fff%ff%%f%%f%%f%f5%%%%%5%5%5555n%%%n%nnn5n%%%%%%n%%%2%%%%fffffff>fff>f>f>zfff%555555555rrr55r5rrrr~5~~5~r~5~~~~~~~~~,5,~,~", "7777{{{H77HY9HHYnn55r~~~,CCCCC&&&C&C&&RR&RRRRRRRRRRRRRRRRRRRRRRRRRR&RRRRRRRRRRRRRRRRRRRRRRRRR&RRRRR&&&&&C&&&&&&C&C&&&RRRRRRRRR&&CCCC,C~~~~r~~5~5~5~~5~~5~5~5~r~r", "{{{{7772{7{72{7z{f777%%7nnn55%55rrrr~,,,,~~~,C,~~,,,C,C,C,CC,,CCCCCCCCCCCC&&CC&CC&C&&CCCC&&&&&CCC&C&R&&&&&C&&C&&C&&&&CCC&&&&&&&R&RR&&&&CC,,,,~,~~~~555555555rrrr"}; cwirc-2.0.0.orig/smeter.xpm0000644000175000017500000003254510062601222014074 0ustar pg4ipg4i/* XPM */ static char * smeter_xpm[] = { "160 80 33 1", " c None", ". c #3E2D11", "+ c #655940", "@ c #67925C", "# c #7DA477", "$ c #9FB69A", "% c #B7C5B2", "& c #B62025", "* c #D5D2C8", "= c #DBDAD2", "- c #B22A23", "; c #C46465", "> c #CE8B89", ", c #BE5D54", "' c #AAA695", ") c #877A63", "! c #BA5D58", "~ c #DEDED4", "{ c #AE2F1F", "] c #C2B8AA", "^ c #D8A9A6", "/ c #C67B75", "( c #776D59", "_ c #4E4024", ": c #E3E4DD", "< c #98907B", "[ c #B65253", "} c #B73B39", "| c #D1C6BB", "1 c #DFBCB8", "2 c #AA2612", "3 c #D2A299", "4 c #F2F2EE", "444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444|*44444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444441|1*4444444444444444444444444444444/}-34444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444412-&;444444444444444444444444444444~-3/,4444444444444444444444444444444444444444444444444", "444444444444444444444444444444444444444444444444444444444444444444444444**}^4444444444444444444444444444444-[[/4444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444~[444444444444444444444444444444441,&^4444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444^,4444444444444444444444444444444/1^}44444444444444444444444444444444444444444444444444", "444444444444444444444444444444444444444444444=>/4444444444444444444444444>/4444444444444444444444444444444;}}^44444444444444444444444444444444444444444444444444", "444444444444444444444444444444444444444444441-}>4444444444444444444444444//444444444444444444444444444444441*444444444444444444444444444444444444444444444444444", "444444444444444444444444444444444444444444441&^=4444444444444444444444444=*4444444444444444444444444444444444444444444444444444444444444%$~444444444444444444444", "444444444444444444444444444444444444444444444}{{,:44444444444444444444444444444444444444444444444444444444444444444444444444444444444444@@#=44444444444444444444", "4444444444444444444444444444444444444444444443[1[>44444444444444444444444*14444444444444444444444444444441/4444444444444444444444444444$@%##:4444444444444444444", "444444444444444444444444444444444444444444444444/;4444444444441:444444444},4444444444444~,=44444444444444;^444444444444444444444444444~@$4*@~4444444444444444444", "4444444444444444444444444444444444444444444444^[-344444444444:&/4444444443^4444444444444*}144444444444444}*4444444444$444%*44444444444##44%@:4444444444444444444", "4444444444444444444444444444444444444444444444:314444444444444^:44444444444444444444444444444444444444441,444444444$##44:@%4::4444444%#%4:#$4444$%44444444444444", "444444444444444444444444444444444444444444444444114444444444444444444:**||]''']'||**~:444444444444444444[>444444444=@@$4*#:%##$444444$#44$@=444*@@#4444444444444", "4444444444444444444444441>*444444444444444444444[[44444444444:|]')(__.....____..__...___+)<'|~4444444444;~4444444444#=:4#$~#%*#44444:@@$$@$444~@#$#%444444444444", "444444444444444444444441-}[:44444444444444444444^14444444|'(_..._(<3]||):4444*+*4444*](]<)+_.__(<]=44444444444444444~44~#~$#4*#444444:#@#$4444#@::#$444444444444", "444444444444444444444443/=-1444444444444444444444444:]<+_._)'|*+]444444<44444=+~44444:'44444:_)<(___)'~4444444444444444##4#%4$$44444444444444%#@##@=444444444444", "4444444444444444444444444>-}144444444:>4444444444~'+_.+)(~44444+'444444'44444=_*44444*]444444+|444*'(._+)|4444444444444%:4@%%#=4444444444444:##$@@%4444444444444", "444444444444444444444444444>;444444443&1444444~<+__<|444<444444)<444444<44444*+~44444*|44444*+=44444]]*'+__)]4444444444444#@@%44444444444444##:4$#44444444444444", "444444444444444444444444411;/44444444414444:'+.+_)444444'*44444'(444444'44444*+*44444]%44444](444444':4444%(..)|44444444%~4==444444444444444#@##@$44444444444444", "44444444444444444444444443},~444444444444|(__<=4'+444444|]44444$+4~*]'<+)(+++_.++())<('*~444')444444<444444'+](_+<:4444~@$4444444444444444444%###:44444444444444", "44444444444444444444444444444444444444:'+.+|4444=_|44444:'44~]'+....__++()<<<<<)<)((+__.__+(_(*44444'444444(<44='__)%444*444444444444444444444444444444444444444", "4444444444444444444444444444;,444444=<__<''444444(<4444='++_._+(']*~4444444444444444444:=]<)+___(<|'*44444:+*44444$__+$44444444444444444444444444444444444444444", "4444444444444444444444444444/;4444=).+]444<444444'+~|<+__)'|44444:]444444444444444444444444444=]<+_.+<|:44$(444444$]=<_+#444444444444444444444444444444444444444", "44444444444444444444444444444444*(.+]44444<|44444'._.(3*444444444<_=44444444444444444444444*(+|4444|'+__(]+'444444<4444'__$4444444444444444444444444444444444444", "444444444444444444444444444444:).+++444444=<4:|)+.)]4444444444444_.|44444444444444444444444+((_44444444|)_.(]:444*$444444(.+$44444444444444444444444444444444444", "4444444444444444444444444444:<.+|4=_'444444))+.+]~44444444444444$._]4444444444444444444444%_]*]44444444444*)+_)%4'4444444+<'_+%444444~=4444444444444444444444444", "4:444*;444444444444=>444444]__]4444)+4444|+_+'~44444444444444444()('4444444444444444444444<.._*44444444444444](__(~44444'+444'_(%4444@#4444444444444444444444444", "44444*-/44444444444>{:444*+.+444444~_'4]+.)144444444444444444444_+__'444444444444444444444((*+'4444444444444444*'+_<=444_]4444*)_#444%%4444444444444444444444444", "444444|[/44444444444=444<.)*<]444444<___<~444444444444444444444~+++.|444444444444444444444(<4+'4444444444444444444]+_)*<(4444444+_+%4444444444444444444444444444", "4444444*}^444444444444|+_]44:(44444'__'444444444444444444444444444~'4444444444444444444444<___*444444444444444444444|+..$444444$$4<_@444444444444=$%$44444444444", "444444441}14444444444'.)44444]'44]__'4|+_'4444444444444444444444444444444444444444444444444%'*444444444444444444444444%+_<~444~'444%_+*44444444444@@%444~4444444", "4444444443^44444444:+.)4444444<'(_<444++<+:4444444444444444444444%++|444444444444444444444*]:4444444444444444444444444*:]+_'44'*44444(_$444444444~##$44##$444444", "44444444444~144444]_(#_]444444).(=4444(]*_~4444444444444444444444+((+44444444444444444444|..+~4444444444444444444444|_.(:4'_+<]4444444+.)444444444%4~444%#:44444", "44444444444,}4444<.<44)_:444%_+]44444444]+44444444444444444444444):'(44444444444444444444|<=+]4444444444444444444444))|+|44~<.<444444#_$++=444444444444$##444444", "4444444444413444(_]4444+)4:)_<4444444444()4444444444444444444444444+<444444444444444444444*(_*4444444444444444444444(+<_%4444|++%444|_%44@_]44444444#%4@$:=##%44", "44444444444444|_+=44444*_)_+|44444444444+)<(4444444444444444444444<(4444444444444444444444%_(4444444444444444444444+__.'4444444<_<4:+<4444'_'4444444#$*#%%@%%#44", "4444444444444|__)4444444(.'4444444444444+._]4444444444444444444444_'~4444444444444444444444]+:44444444444444444444%(*'+444444444|+++(444444%_<444444=@@#%#%4%#44", "4444441>4444].<4''4444=+_|44444444444444$]44444444444444444444444%...'444444444444444444*_'<+444444444444444444444%_%))44444444444).'4444444(_)444444444#$4~#$44", "444444>{~44'_'444<]44]_)444444444444444444%<444444444444444444444~)<]:4444444444444444444(..'4444444444444444444444)._*444444444444$_<44444)%~+)4444#$44@%=@$444", "4444444~44<.]44444<]<.<4444444444444444444<_~444444444444444444444444444444444444444444444|:444444444444444444444444~444444444444444|+(~44<]444+(:44##44$@#$4444", "444444444]_%444444=__]44444444444444444444~()444444444444444444444444444444444444444444444444444444444444444444444$<44444444444444444:)+%]$44444(+~444444~:44444", "444444444$.'44444=+_*4444444444444444444444|_:444444444444444444444444444444444444444444444444444444444444444444*(.(4444444444444444444<_<4444444+(4444444444444", "4444444444'.]444|_(:444444444444444444444444(<44444444444444444444444444444444444444444444444444444444444444444'.__%44444444444444444444'_'44444*_@4444444444444", "44444444444<.$4*_)44444444444444444444444444%_~444444444444444444444444444444444444444444444444444444444444444).$)(4444444444444444444444]_'444%+<44444444444444", "444444444444'.)_<4444444444444444444444444444<*444444444444444444444444444444444444444444444444444444444444444'___$44444444444444444444444%_<4*_'444444444444444", "4444444444444'.<:*:44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444=_.]444444444444444444444444%_(_'4444444444444444", "44444444444444~:(..'44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444)$44444444444444444444444]<4=+<44444444444444444", "444444444444444$_*'_'4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444*_<444444444444444444444", "444444444444444]_*4'_]444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444()44~4444444444444444444", "4444444444444444++:4<(44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444(+:'__<444444444444444444", "4444444444444444*_+*$+4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444)+~<_'$_*44444444444444444", "44444444444444444~_._]444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444$+*'_]4%+~44444444444444444", "4444444444444444444]*4<_+%444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444==+':~+)444444444444444444", "444444444444444444444*_').'444444444444444444444444444444*:4444444444444444444444444444444444444444444444444444444444444444444444444444%_**+(4444444444444444444", "444444444444444444444|_~4'.]4444444444444444444444444444;&}^44444444=,*4~;=41^44~>44~3443;/;/^4441>*44444444444444444444444444444444](~:+..(44444444444444444444", "4444444444444444444444_(:4'+4444444444444444444444444443&[[}44444444^&143&14,&143-~4>{~4;&&&{>44>&&}1444444444444444444444444444444'__+~4$%444444444444444444444", "4444444444444444444444|_+==+*44444444444444444444444444/&3~344444444^&14^&14[&[43-~43&:441-[=444-,^{;44444444444444444444444444444].(*(]444444444444444444444444", "44444444444444444444444*_._+4444444444444444444444444441&&3444444444^&14>&*4;&-^>}:4>}4444}/444:{}=||4444444444444444444444444444%|<_$44444444444444444444444444", "4444444444444444444444444'<:4444444444444444444444444444^}&/44444444^&14>&*4,&&}[}443}4444}/4444/&}344444444444444444444444444444+*:(<44444444444444444444444444", "4444444444444444444444444444444444444444444444444444444:~:/&|4444444^&14>&*4,-;&&}44>}4444}/44444^}&>4444444444444444444444444444+))_|44444444444444444444444444", "4444444444444444444444444444444444444444444444444444444;}11&144444441->4;}44,}4,&}44>}4444}>444:;1:-;4444444444444444444444444444]++%444444444444444444444444444", "44444444444444444444444444444444444444444444444444444443&-&;444444444[&}&>44,}4*-}44/}4444}/444~-}/&/44444444444444444444444444444444444444444444444444444444444", "44444444444444444444444444444444444444444444444444444444^;>~444444444:/;34443/44^/44^>4444;344443&&[=44444444444444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444~14444444444444444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444"}; cwirc-2.0.0.orig/sidetone.xpm0000644000175000017500000003254710062564720014424 0ustar pg4ipg4i/* XPM */ static char * sidetone_xpm[] = { "160 80 33 1", " c None", ". c #2A1F0C", "+ c #3A301C", "@ c #585140", "# c #4E714A", "$ c #7D8777", "% c #A1A29B", "& c #32220D", "* c #F2F2EE", "= c #E2524E", "- c #8E4243", "; c #86191C", "> c #DF6B6A", ", c #873532", "' c #EBA7A3", ") c #E68682", "! c #757565", "~ c #935C5B", "{ c #822B2A", "] c #8E5350", "^ c #93877E", "/ c #D60303", "( c #9C7875", "_ c #EED6D2", ": c #82544A", "< c #9A978F", "[ c #49402E", "} c #676452", "| c #B2B2AE", "1 c #7E1B18", "2 c #93716A", "3 c #722F1D", "4 c #DE3636", "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||<<||||||||||||||||||||||||||||||||||||||||||||||||||", "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||^<^<|||||||||||||||||||||||||||||||~;;2|||||||||||||||||||||||||||||||||||||||||||||||||", "|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||^;;;-||||||||||||||||||||||||||||||<1(~-|||||||||||||||||||||||||||||||||||||||||||||||||", "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||<<{(|||||||||||||||||||||||||||||||{-,]%||||||||||||||||||||||||||||||||||||||||||||||||", "|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||%,%|||||||||||||||||||||||||||||||^-;(|||||||||||||||||||||||||||||||||||||||||||||||||", "|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||^-|||||||||||||||||||||||||||||||]^(,%|||||||||||||||||||||||||||||||||||||||||||||||||", "||||||||||||||||||||||||||||||||||||||||||||%<~:%||||||||||||||||||||||||~]|||||||||||||||||||||||||||||||]{{(||||||||||||||||||||||||||||||||||||||||||||||||||", "||||||||||||||||||||||||||||||||||||||||||||^;{~|||||||||||||||||||||||||~]||||||||||||||||||||||||||||||||<<|||||||||||||||||||||||||||||||||||||||||||||||||||", "||||||||||||||||||||||||||||||||||||||||||||^;^<|||||||||||||||||||||||||<<|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||$#%|||||||||||||||||||||", "|||||||||||||||||||||||||||||||||||||||||||||,;1,%|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||%###$||||||||||||||||||||", "|||||||||||||||||||||||||||||||||||||||||||||~-<,~|||||||||||||||||||||||^<|||||||||||||%||||||||||||||||(]||||||||||||||||||||||||||||$#$##||||||||||||||||||||", "||||||||||||||||||||||||||||||||||||||||||||||||~-||||||||||||(<%||||||||{{|||||||||||||<,<||||||||||||||-2|||||||||||||||||||||||||||<#$|<#<|||||||||||||||||||", "||||||||||||||||||||||||||||||||||||||||||||||2,12|||||||||||<;~|||||||||((|||||||||||||<{^||||||||||||||{<||||||||||!%||$$|||||||||||##||$#%|||||||||||||||||||", "||||||||||||||||||||||||||||||||||||||||||||||%(^|||||||||||||(<||||||||||||||||||||||||||||||||||||||||(-|||||||||!##||%#$|%<|||||||<#<||#!||||!$%|||||||||||||", "||||||||||||||||||||||||||||||||||||||||||||||||^^||||||||||||||||||%%<<^^$!!!!!^^^<<%||||||||||||||||||,2|||||||||%##!|<#%$!#$||||||#$%|$#<|||$###|||||||||||||", "||||||||||||||||||||||||(~<|||||||||||||||||||||,{|||||||||||%^^}:@++&..&&&&+&&&++&&&&&+[@}!^<||||||||||-^||||||||||#<%|!$%#$<#<||||%##$##$|||%##$#$||||||||||||", "|||||||||||||||||||||||^;{{%||||||||||||||||||||^(||||||%^!@+&..+@}2^^^}%||||%[<||||<$@(!:[[.&+[}!<||%||||||||||||||%||%#%$$|<#||||||<###$||||##%%#$||||||||||||", "|||||||||||||||||||||||(~<{^||||||||||||||||||||||||%^@[&&+@2<<+^||||||!|||||<[%||||||!|||||%+@}@+&+@!<||||||||||||||||!#|#$|$$||||||||||||||<#####<||||||||||||", "|||||||||||||||||||||||||~;{^||||||||%~%|||||||||//=****''****=//)**_>///**4//=*=/*****//", "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||//>*')*)/*'/'*=)**'/=*)==44=*'=4/__>=)*'//**_//=*=/*'===//", "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||//'*//=4/*'/'*///_*4=*=/////*'//__4///=*>/***>/=*=/*'/////", "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||//>*_>///*'/'*///4*)=*=/////*'/4*)/////__/*''_/=*=/*'/////", "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||///>_*_=/*'/'*////*'=****=//*'/=*=/////'*/*'4*)=*=/****'//", "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||/////>*_/*'/'*////*'=*)==///*'/4*>/////'_/*'/)*>*=/*'==4//", "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||//>>//'*/*'/'*///'*4=*=/////*'//__////=*)/*'//__*=/*'/////", "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||//)*>>*'/*'/'*=>_*'/=*)==4//*'//4*_>=)*_//*'//>**=/*'===//", "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||///)**)//*'/'***'>//=****'//*'///4'**_)///*'///'*=/*****//", "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||//////////////////////////////////////////////////////////", "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||//////////////////////////////////////////////////////////"}; cwirc-2.0.0.orig/sounder_down.wav0000644000175000017500000001546007717245724015321 0ustar pg4ipg4iRIFF(WAVEfmt DXdata FRR 1 9 ۔$ދY=!#]OSѴSN $6%6 Px!j r -V0&fϙZ㾍 Bf|0o*M,Д^讖1x:JYL>%ZAʾB\[3Yr.ziptV0=Ǧš\g" .JZ\O57Ű un0HSO<װg>N4D7IB1qI.fd{3 [kB"n q+,#dVѢ2cjr݆2(BEKAs:W* c 1L/>gC<^,إתHm "YkB 6_,3:hxeV c %ZL]zGVT m\yH;1l < 6bzSk޴LZivWo \=(ތbY<.fEFH} -x$Cv;4AS,K ).p.(EiW s)E(*A^22B? (,A,' '792C0   " =HC ]mmW vT / (nnSZlA>X)c"i{dx-X`s[,cd`;~Ek0 Z,8x8< E '  J2~3< p (u  J ;[C B Q3F @4`w/ e  `q{K>de$l#Lae>j%ORdCV_oN{_-Ox Df`_2GB(v x Wej 9 O[A/*8D~4w9VB9hK*R [L'T_4ux{QF,R* S#z2X!QD|q\VKww>5q0mMWjNz<aV;sr$ #jQTg#/{OJM=_w<);%`6NWA`=N\iCXp\C&}K*cq7,&yH`&mxFt3u;b}J-#!7Bo$Z%L.5!R^9l=f+|`ic3 Y;\UYa8 wp``E9yMW^pc~o"$R&-MZKA-c$?8 O2i}/%V/:SmK=q8Q'0~@[JlRY[t jdMJa%IUTF/ 8LXU: J(?ocwMZ&fv|VCym 4 ?,sU%p`>kmc!vDzaMn[x^V!v8+\61]JrqB\*$Bf~{jg{\9$` ZgO]7DE%GG l{{/>x|Ns?!8\Vj8Pb7:>O6 *JJNTsAdo ER^ATGKo5 3t/P=$cF-vZ`%c=t@l((;ko_\a<0]Yj_tn@? )TEEM8EN/_rpb,(abN$T `{=Wa jL*+ CX9=9.&2#]|@^ +AJ.O8qa~)!>ka4x:Vmm[Re[)w1tS'dwj; - $KUqW`,ay,ek~F:,B)6\IA)/q Gdsq4N_"cQAu7Rd#f>t0V8~\OIK8t1$$;[4'bJ*)~lOG0>(vX'qnD^!6Rjd>9*|&oCF?h"H4;f^`? 3fQ-R[dCZ X&a6J|." V$_Vt7$g%\P$S YY0%`;!;= J IS9ddq^b&NSGdKVe:Z<H~v sop:ooEH6fO}V/{9M~`o q@?_OPw~x|jAk* 0Nn 5f|> -NY^B!^',>mZlqzw!I>u$EX**:/#!4*v@4(yA?K7f&%e'B;FYIM/U6[0 bona;ayLb<BlMI[!\qCyedm^5b((gdelz9n *0NQE.vTs` +]@5g=<7 k#xTR?^MT{*"c.B-k/Qcsp1.V ">LZK.g\v:iqK@'GIA,{(iY >Kcw>g;)3V gz"4A5%42+ cwirc-2.0.0.orig/sounder_up.wav0000644000175000017500000000631607717245724014776 0ustar pg4ipg4iRIFF WAVEfmt DXdata xn`W 4;<"% %  54 |m @ ӣϼ܌1%&!c 0Fwh ; q?G &(!WP{."%9! ,mCɕkcQ##5|[" o yGוL!.4k ih ! 2L};T J*oe o4 Mk8^g t z% be#N^6l"t,%>Zp[ ,^EC[L69(:u4[/a##u, + ;.5 WF&sjV I[ Rd< w0',-d) N zWf+eb kE ,9_.M25["&`: ; Z<(dUc'l K  l5ٰݞ 1iSI  * S{C!ؔԋ6M}97uP$$XQpI4 7h"((k< gD  >r V]m)G-_Z"wK PL/e XP"G B Z b < 'ps: e-]No 5 7 HC. aV e Y_w"? \ $ ' m!B*GAJ`r0ye-rWVociZ3aphZ|+vPm 8h8j bzYm}S /Z J+Hp^ B|Cc{ * "  x n O h y H  3  T PT- 78)6', 8 ~ UJbh ,  g  ]r9>z(koP7' :uy|kBP$YNZU ]0:qX3!1+51"SamsYS)wAMD1Rp{ n=O[tGN]"!T`,. $kL>T;#ThwI\&> V 0?QQBo6 K    y?  3 WKB%ave|]e]IUz_7Ivxm%bQ FXX`N83|1: p#j}y ?r-$xHYamKbo!fa)c.b,,7@?*r9 Tg#!E{Ji4Y 228y? ;P\WD)6x'{VDp{!lTf:q^|GydJ*}3[*XE~eR`mr`NIUdqn# UpRcn5 Zx!U1b 'dd F@ p$G`)KDM>jN0L*)o>{xCF&Wq/$X^xsF*C^X6 EZZEcwirc-2.0.0.orig/rpm/0000755000175000017500000000000010433707212012644 5ustar pg4ipg4icwirc-2.0.0.orig/rpm/cwirc.spec0000644000175000017500000000245610433706626014646 0ustar pg4ipg4i%define name cwirc %define version 2.0.0 %define release 1 Summary: X-Chat Morse plugin Name: %{name} Version: %{version} Release: %{release} Source: http://users.skynet.be/ppc/cwirc/download/%{name}-%{version}.tar.gz License: GPL Group: Networking/IRC BuildRoot: %{_builddir}/%{name}-buildroot Prefix: %{_prefix} BuildRequires: libgtk+2.0_0-devel Requires: xchat >= 2.0.2 %description X-Chat plugin for sending and receiving raw morse code over IRC. %prep %setup -q %build make TARGET_OS=LINUX PLUGIN_INSTALL_DIRECTORY=dummy \ FRONTEND_INSTALL_DIRECTORY=dummy \ CWIRC_EXTENSIONS_DIRECTORY=%{_prefix}/lib/cwirc/extensions %install rm -rf $RPM_BUILD_ROOT mkdir $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/%{_prefix}/lib/xchat/plugins mkdir -p $RPM_BUILD_ROOT/%{_prefix}/bin mkdir -p $RPM_BUILD_ROOT/%{_prefix}/lib/cwirc/extensions cp cwirc.so $RPM_BUILD_ROOT/%{_prefix}/lib/xchat/plugins cp cwirc_frontend $RPM_BUILD_ROOT/%{_prefix}/bin %clean rm -rf $RPM_BUILD_ROOT %post %postun %files %defattr(-,root,root) %{_prefix}/lib/xchat/plugins/cwirc.so %{_prefix}/bin/cwirc_frontend %{_prefix}/lib/cwirc/extensions %doc README LISEZMOI Changelog COPYING schematics/cw_oscillator.jpg schematics/rs232_key_connection.jpg %changelog * Mon Jan 12 2004 P.P. Coupard - First draft of the spec file cwirc-2.0.0.orig/rpm/rpmmacros0000644000175000017500000000010010433706651014567 0ustar pg4ipg4i%packager P.P. Coupard %distribution CWirc