From c16ca054a5c251e8ab7e32f3a856d82724bbae46 Mon Sep 17 00:00:00 2001 From: MelwareDE Date: Thu, 2 Jun 2005 18:47:35 +0000 Subject: [PATCH] Initial import of new chan_capi. --- INSTALL | 28 + LICENSE | 341 +++++ Makefile | 79 ++ README | 149 +++ app_capiCD.c | 187 +++ app_capiECT.c | 216 ++++ app_capiHOLD.c | 134 ++ app_capiMCID.c | 124 ++ app_capiNoES.c | 99 ++ app_capiRETRIEVE.c | 137 ++ capi.conf | 44 + chan_capi.c | 3062 ++++++++++++++++++++++++++++++++++++++++++++ chan_capi_app.h | 35 + chan_capi_pvt.h | 303 +++++ create_config.sh | 76 ++ xlaw.h | 1660 ++++++++++++++++++++++++ 16 files changed, 6674 insertions(+) create mode 100644 INSTALL create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README create mode 100644 app_capiCD.c create mode 100644 app_capiECT.c create mode 100644 app_capiHOLD.c create mode 100644 app_capiMCID.c create mode 100644 app_capiNoES.c create mode 100644 app_capiRETRIEVE.c create mode 100644 capi.conf create mode 100644 chan_capi.c create mode 100644 chan_capi_app.h create mode 100644 chan_capi_pvt.h create mode 100755 create_config.sh create mode 100644 xlaw.h diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..2da9d5d --- /dev/null +++ b/INSTALL @@ -0,0 +1,28 @@ +Modify the Makefile to fit your system, especially the path to the Asterisk include files. + +Currently there are some buildtime configuration parameters. You can enable early B3 connects +if you want the capi channels to come up very soon and hear the indications from your +local exchange (native capi indications). +You can also force software dtmf detection/generation to be used. + +To build the driver you will need an installed capi system, including header files. + +to build the channel driver type: +make + +to install: +make install + +to install a sample configuration: +make config + + +in /etc/asterisk/modules.conf insert the line: + load => chan_capi.so + + and in the [global] section: + chan_capi.so=yes + + +HEY, dont forget a trailing newline at the end of modules.conf!!! + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a52b16e --- /dev/null +++ b/LICENSE @@ -0,0 +1,341 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..16ce7e8 --- /dev/null +++ b/Makefile @@ -0,0 +1,79 @@ +# +# (CAPI*) +# +# An implementation of Common ISDN API 2.0 for Asterisk +# +# Makefile, based on the Asterisk Makefile, Coypright (C) 1999, Mark Spencer +# +# Copyright (C) 2005 Cytronics & Melware +# +# Armin Schindler +# +# Reworked, but based on the work of +# Copyright (C) 2002-2005 Junghanns.NET GmbH +# +# Klaus-Peter Junghanns +# +# This program is free software and may be modified and +# distributed under the terms of the GNU Public License. +# + +.EXPORT_ALL_VARIABLES: + +INSTALL_PREFIX= +ASTERISK_HEADER_DIR=$(INSTALL_PREFIX)/usr/include +ASTERISKVERSION=$(shell if [ -f .version ]; then cat .version; else if [ -d CVS ]; then if [ -f CVS/Tag ] ; then echo "CVS-`sed 's/^T//g' CVS/Tag`-`date +"%D-%T"`"; else echo "CVS-HEAD-`date +"%D-%T"`"; fi; fi; fi) + + +MODULES_DIR=$(INSTALL_PREFIX)/usr/lib/asterisk/modules + +PROC=$(shell uname -m) + +DEBUG=-g #-pg +INCLUDE=-I$(ASTERISK_HEADER_DIR) +CFLAGS=-pipe -Wall -Wmissing-prototypes -Wmissing-declarations $(DEBUG) $(INCLUDE) -D_REENTRANT -D_GNU_SOURCE +CFLAGS+=-O6 +CFLAGS+=$(shell if $(CC) -march=$(PROC) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=$(PROC)"; fi) +CFLAGS+=$(shell if uname -m | grep -q ppc; then echo "-fsigned-char"; fi) + +# uncomment the next line if you are in the ulaw world +#CFLAGS+=-DCAPI_ULAW + +# audio sync +CFLAGS+=-DCAPI_SYNC + +CFLAGS+=-DASTERISKVERSION=\"$(ASTERISKVERSION)\" + +LIBS=-ldl -lpthread -lm +CC=gcc +INSTALL=install + +SHAREDOS=chan_capi.so app_capiCD.so app_capiHOLD.so app_capiRETRIEVE.so app_capiECT.so app_capiMCID.so app_capiNoES.so + +CFLAGS+=-Wno-missing-prototypes -Wno-missing-declarations + +CFLAGS+=-DCRYPTO + +all: config.h $(SHAREDOS) + +clean: + rm -f config.h + rm -f *.so *.o + +%.so : %.o + $(CC) -shared -Xlinker -x -o $@ $< + +config.h: + ./create_config.sh "$(ASTERISK_HEADER_DIR)" + +chan_capi.so: chan_capi.o + $(CC) -shared -Xlinker -x -o $@ chan_capi.o -lcapi20 + +install: all + for x in $(SHAREDOS); do $(INSTALL) -m 755 $$x $(MODULES_DIR) ; done + +config: all + cp capi.conf $(INSTALL_PREFIX)/etc/asterisk/ + +samples: config + diff --git a/README b/README new file mode 100644 index 0000000..4ecbaec --- /dev/null +++ b/README @@ -0,0 +1,149 @@ +(CAPI*) chan_capi a Common ISDN API 2.0 implementation for Asterisk + + Copyright (C) 2005 Cytronics & Melware + Armin Schindler + + Reworked, but based on the work of + Copyright (C) 2002-2005 Junghanns.NET GmbH + Klaus-Peter Junghanns + +This program is free software and may be modified and distributed under +the terms of the GNU Public License. There is _NO_ warranty for this! + +Thanks go to the debuggers and bugfixers (listed in chronological order) :) +=========================================================================== +Lele Forzani +Florian Overkamp +Gareth Watts +Jeff Noxon +Petr Michalek +Jan Stocker +(...and all the others that i forgot..) :-) + +This chan_capi version includes: +================================ + +- multiple controller support +- CID,DNID (callling party, called party) +- CLIR/CLIP +- supplementary services, CD,HOLD,RETRIEVE,ECT +- DTMF (dependend on card) + software DTMF support +- early B3 connects (always,success,never) +- digital audio (what did you think?) +- incoming/outgoing calls +- overlap sending (dialtone) +- E(xplicit) C(all) T(ransfer) (...although it's done implicit .. but dont tell!) +- tuneable latency ;) you can configure the size of B3 blocks at compile time + (in chan_capi_pvt.h, AST_CAPI_MAX_B3_BLOCK_SIZE) + the default is 160 samples, for non-VoIP use you can tune it down to 130 +- use asterisk's internal dsp functions for dtmf +- alaw support +- ulaw support! +- Eicon CAPI echo cancelation (echocancel=1) +- reject call waiting (ACO) +- DID for Point to Point mode (a.k.a overlap receiving) +- experimental echo squelching (echosquelch=1) +- call progress, no need to add ||r to your dialstring anymore +- rx/tx gains (rxgain=1.0) +- call deflection on circuitbusy (makefile option) (deflect=12345678) +- (inter)national dialing prefix (for callerid) configurable in capi.conf +- CLI command "capi info" shows B channel status +- capiECT will announce the callerID since it gets lost on most isdn pbxes + the called party can press # to drop the call +- audio syncing (timing outgoing dataB3 on incoming dataB3), supposed to fix + the DATA_B3_REQ (error = 0x1103) problem +- catch all MSN (incomingmsn=*) +- some configuration enhancements (msn=123,124,125 and controller=1,2,3,4) +- accountcode= added. +- finally the echo squelching works! +- callgroup support +- fixed pipe leak +- updated to support the new frame->delivery field +- compiles with latest cvs with a makefile option (LOOK AT THE MAKEFILE) +- fixed channel name bug in p2p mode +- added app_capiNoES for disabling the primitive echo suppressor, use this before + you start recording voicemail or your files may get choppy +- fixed for latest cvs (AST_MUTEX_DEFINE_STATIC) +- fixed for latest cvs (asterisk/parking.h -> asterisk/features.h) +- fixed for latest cvs ast_pthread_create + +- ATTENTION! the dialstring syntax now uses the zaptel dialstring syntax + it used to be: Dial(CAPI/[@]:[b|B]) + + now it is: Dial(CAPI/g/[b|B]) + or: Dial(CAPI/contr/[b|B]) + + CLIP/CLIR is now uses the calling presentation of the calling channel, this can + be modified using the CallingPres() application. Use CallinPres(32) for CLIR. + That is why the msn= param in capi.conf is now obsolete. The callerID is also + taken from the calling channel. + +- fixes for BSD (Jan Stocker) + +Helper applications +=================== +kapejod says: "No No No, dont use those yet....!" (except maybe HOLD,ECT...) + +app_capiCD.c forwards an unanswered call to another phone (does not rely on sservice CD) + example: + exten => s,1,Wait,1 + exten => s,2,capiCD,12345678 + +app_capiHOLD.c puts an answered call on hold, this has nothing to do with asterisk's onhold thingie (music et al) + after putting a call onhold, never use the Wait application! + +app_capiRETRIEVE.c gets the holded call back + +app_capiECT.c explicit call transfer of the holded call (must put call on hold first!) + example: + exten => s,1,Answer + exten => s,2,capiHOLD + exten => s,3,capiECT,55:50 + will ECT the call to 50 using 55 as the callerid/outgoing msn + + +Using CLIR +========== +Use the CallingPres() application before you dial: +exten => _X.,1,CallingPres(32) +exten => _X.,2,Dial(CAPI/contr1/${EXTEN}) + +Enjoying early B3 connects (inband call progress, tones and announcements) +========================================================================== +early B3 is now configurable in the dialstring :) +if you prefix the destination number with a 'b' early B3 will always be used, also if the call fails +because the number is unprovisioned, etc ... +if you prefix it with a 'B' early B3 will only be used on successful calls, giving you ring indication,etc... + +dont use indications in the Dial command, your local exchange will do that for you: +exten => _X.,1,Dial(CAPI/contr1/B${EXTEN},30) (early B3 on success) +exten => _X.,1,Dial(CAPI/contr1/b${EXTEN},30) (always early B3) +exten => _X.,1,Dial(CAPI/contr1/${EXTEN},30,r) (no early B3, fake ring indication) + +exten => _X.,1,Dial(CAPI/contr1/b${EXTEN},30,r) (always early B3, fake indicatons if the exchange + does not give us indications) +exten => _X.,1,Dial(CAPI/contr1/B${EXTEN},30,r) (early B3 on success, fake indicatons if the exchange + does not give us indications) + +For normal PBX usage you would use the "b" option, always early B3. + +Overlap sending (a.k.a. real dialtone) +====================================== +when you dial an empty number, and have early B3 enabled, with: + Dial(CAPI/g1/b) +the channel will come up at once and give you the dialtone it gets from the local exchange. +at this point the channel is like a legacy phone, now you can send dtmf digits to dial. + +Example context for incoming calls on MSN 12345678: +=================================================== + +[capi-in] +exten => 12345678,1,Dial(SIP/phone1) +exten => 12345678,2,Hangup + + +More information/documentation and commercial support can be found at: + http://www.junghanns.net/asterisk/ + + + diff --git a/app_capiCD.c b/app_capiCD.c new file mode 100644 index 0000000..6c6c787 --- /dev/null +++ b/app_capiCD.c @@ -0,0 +1,187 @@ +/* + * (CAPI*) + * + * An implementation of Common ISDN API 2.0 for Asterisk + * + * Call Deflection, inspired by capircvd by Alexander Brickwedde + * + * Copyright (C) 2005 Cytronics & Melware + * + * Armin Schindler + * + * Reworked, but based on the work of + * Copyright (C) 2002-2005 Junghanns.NET GmbH + * + * Klaus-Peter Junghanns + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#include "config.h" + +#include +#include +#include +#ifndef CC_AST_HAVE_TECH_PVT +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "chan_capi_pvt.h" +#include "chan_capi_app.h" + + +static char *tdesc = "(CAPI*) Call Deflection, the magic thing."; +static char *app = "capiCD"; +static char *synopsis = "call deflection"; + +STANDARD_LOCAL_USER; + +LOCAL_USER_DECL; + +static int capiCD_exec(struct ast_channel *chan, void *data) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(chan); + MESSAGE_EXCHANGE_ERROR Info; + _cmsg CMSG; + char bchaninfo[1]; + char fac[60]; + int res = 0; + int ms = 3000; + struct localuser *u; + + if (!data) { + ast_log(LOG_WARNING, "cd requires an argument (destination phone number)\n"); + return -1; + } + + LOCAL_USER_ADD(u); + + /* Do our thing here */ + + if ((i->state == CAPI_STATE_CONNECTED) || + (i->state == CAPI_STATE_BCONNECTED)) { + ast_log(LOG_ERROR, "call deflection does not work with calls that are already connected!\n"); + LOCAL_USER_REMOVE(u); + return -1; + } + + /* wait until the channel is alerting, so we dont drop the call and interfer with msgs */ + while ((ms > 0) && (i->state != CAPI_STATE_ALERTING)) { + sleep(100); + ms -= 100; + } + + /* make sure we hang up correctly */ + i->state = CAPI_STATE_CONNECTPENDING; + + fac[0] = 0; /* len */ + fac[1] = 0; /* len */ + fac[2] = 0x01; /* Use D-Chan */ + fac[3] = 0; /* Keypad len */ + fac[4] = 31; /* user user data? len = 31 = 29 + 2 */ + fac[5] = 0x1c; /* magic? */ + fac[6] = 0x1d; /* strlen destination + 18 = 29 */ + fac[7] = 0x91; /* .. */ + fac[8] = 0xA1; + fac[9] = 0x1A; /* strlen destination + 15 = 26 */ + fac[10] = 0x02; + fac[11] = 0x01; + fac[12] = 0x70; + fac[13] = 0x02; + fac[14] = 0x01; + fac[15] = 0x0d; + fac[16] = 0x30; + fac[17] = 0x12; /* strlen destination + 7 = 18 */ + fac[18] = 0x30; /* ...hm 0x30 */ + fac[19] = 0x0d; /* strlen destination + 2 */ + fac[20] = 0x80; /* CLIP */ + fac[21] = 0x0b; /* strlen destination */ + fac[22] = 0x01; /* destination start */ + fac[23] = 0x01; /* */ + fac[24] = 0x01; /* */ + fac[25] = 0x01; /* */ + fac[26] = 0x01; /* */ + fac[27] = 0x01; /* */ + fac[28] = 0x01; /* */ + fac[29] = 0x01; /* */ + fac[30] = 0x01; /* */ + fac[31] = 0x01; /* */ + fac[32] = 0x01; /* */ + fac[33] = 0x01; /* 0x01 = sending complete */ + fac[34] = 0x01; + fac[35] = 0x01; + + memcpy((unsigned char *)fac + 22, data, strlen(data)); + + fac[22 + strlen(data)] = 0x01; /* fill with 0x01 if number is only 6 numbers (local call) */ + fac[23 + strlen(data)] = 0x01; + fac[24 + strlen(data)] = 0x01; + fac[25 + strlen(data)] = 0x01; + fac[26 + strlen(data)] = 0x01; + + fac[6] = 18 + strlen(data); + fac[9] = 15 + strlen(data); + fac[17] = 7 + strlen(data); + fac[19] = 2 + strlen(data); + fac[21] = strlen(data); + + bchaninfo[0] = 0x1; + + INFO_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + INFO_REQ_CONTROLLER(&CMSG) = i->controller; + INFO_REQ_PLCI(&CMSG) = i->PLCI; + INFO_REQ_BCHANNELINFORMATION(&CMSG) = (unsigned char*)bchaninfo; /* use D-Channel */ + INFO_REQ_KEYPADFACILITY(&CMSG) = 0; + INFO_REQ_USERUSERDATA(&CMSG) = 0; + INFO_REQ_FACILITYDATAARRAY(&CMSG) = (unsigned char*)fac + 4; + + if ((Info = _capi_put_cmsg(&CMSG)) != 0) { + res = (int)Info; + } else { + if (capidebug) { + ast_log(LOG_NOTICE, "sent INFO_REQ PLCI = %#x\n", + i->PLCI); + } + } + + LOCAL_USER_REMOVE(u); + return res; +} + +int unload_module(void) +{ + STANDARD_HANGUP_LOCALUSERS; + return ast_unregister_application(app); +} + +int load_module(void) +{ + return ast_register_application(app, capiCD_exec, synopsis, tdesc); +} + +char *description(void) +{ + return tdesc; +} + +int usecount(void) +{ + int res; + STANDARD_USECOUNT(res); + return res; +} + +char *key() +{ + return ASTERISK_GPL_KEY; +} diff --git a/app_capiECT.c b/app_capiECT.c new file mode 100644 index 0000000..62b4cff --- /dev/null +++ b/app_capiECT.c @@ -0,0 +1,216 @@ +/* + * (CAPI*) + * + * An implementation of Common ISDN API 2.0 for Asterisk + * + * ECT transfer the held call + * + * Copyright (C) 2005 Cytronics & Melware + * + * Armin Schindler + * + * Reworked, but based on the work of + * Copyright (C) 2002-2005 Junghanns.NET GmbH + * + * Klaus-Peter Junghanns + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#include "config.h" + +#include +#include +#include +#ifndef CC_AST_HAVE_TECH_PVT +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "chan_capi_pvt.h" +#include "chan_capi_app.h" + + +static char *tdesc = "(CAPI*) ECT"; +static char *app = "capiECT"; +static char *synopsis = "transfer the call that is on hold"; + +STANDARD_LOCAL_USER; + +LOCAL_USER_DECL; + + +static int capiECT_exec(struct ast_channel *chan, void *data) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(chan); + MESSAGE_EXCHANGE_ERROR Info; + _cmsg CMSG; + char fac[8]; + int res = 0; + struct localuser *u; + char *ecodes = "*#"; + + if (!data) { + ast_log(LOG_WARNING, "ECT requires an argument (destination phone number)\n"); + return -1; + } + + if (i->onholdPLCI <= 0) { + ast_log(LOG_WARNING, "no call on hold that could be transfered\n"); + return -1; + } + + LOCAL_USER_ADD(u); + + /* Do our thing here */ + + ast_log(LOG_NOTICE, "ECT to %s\n", (char *)data); + capi_call(chan, data, 0); + + while ((i->state != CAPI_STATE_BCONNECTED) && (i->onholdPLCI != 0)) { + usleep(10000); + } + + if (i->state == CAPI_STATE_BCONNECTED) { + ast_log(LOG_NOTICE,"call was answered\n"); + + capi_detect_dtmf(chan, 1); + + /* put the stuff to play announcement message here ---> <----- */ + res = ast_say_digit_str(chan, i->cid, ecodes, chan->language); + if ( res == '#') { + ast_log(LOG_NOTICE, "res = %d\n", res); + /* user pressed #, hangup */ + /* first the holded user */ + /* ast_exec("capi RETRIEVE",chan); */ + + DISCONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + DISCONNECT_REQ_PLCI(&CMSG) = i->onholdPLCI; + + if ((Info = _capi_put_cmsg(&CMSG)) == 0) { + ast_log(LOG_NOTICE, "sent DISCONNECT_REQ PLCI=%#x\n", + i->onholdPLCI); + } + + /* then the destination */ + + DISCONNECT_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI; + + if ((Info = _capi_put_cmsg(&CMSG)) == 0) { + ast_log(LOG_NOTICE, "sent DISCONNECT_B3_REQ NCCI=%#x\n", + i->NCCI); + } + + /* wait for the B3 layer to go down */ + while (i->state != CAPI_STATE_CONNECTED) { + usleep(10000); + } + + DISCONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + DISCONNECT_REQ_PLCI(&CMSG) = i->PLCI; + + if ((Info = _capi_put_cmsg(&CMSG)) == 0) { + ast_log(LOG_NOTICE, "sent DISCONNECT_REQ PLCI=%#x\n", + i->PLCI); + } + + LOCAL_USER_REMOVE(u); + return -1; + } else { + /* now drop the bchannel */ + DISCONNECT_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI; + + if ((Info = _capi_put_cmsg(&CMSG)) == 0) { + ast_log(LOG_NOTICE, "sent DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI); + } + + /* wait for the B3 layer to go down */ + while (i->state != CAPI_STATE_CONNECTED) { + usleep(10000); + } + } + } + + /* the caller onhold hungup or died away, drop the answered call */ + if (i->onholdPLCI == 0) { + DISCONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + DISCONNECT_REQ_PLCI(&CMSG) = i->PLCI; + + if ((Info = _capi_put_cmsg(&CMSG)) == 0) { + ast_log(LOG_NOTICE, "sent DISCONNECT_REQ PLCI=%#x\n", + i->PLCI); + } + return -1; + } + + ast_log(LOG_NOTICE, "onholdPLCI = %d\n", i->onholdPLCI); + + fac[0] = 7; /* len */ + fac[1] = 0x06; /* ECT (function) */ + fac[2] = 0x00; + fac[3] = 4; /* len / sservice specific parameter , cstruct */ + fac[4] = (i->onholdPLCI << 8 ) >> 8; + fac[5] = i->onholdPLCI >> 8; + fac[6] = 0; + fac[7] = 0; + + FACILITY_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(),0); + FACILITY_REQ_CONTROLLER(&CMSG) = i->controller; + FACILITY_REQ_PLCI(&CMSG) = i->onholdPLCI; + FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 0x0003; /* sservices */ + FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (char *)&fac; + + if ((Info = _capi_put_cmsg(&CMSG)) != 0) { + res = (int)Info; + } else { + ast_log(LOG_NOTICE, "sent FACILITY_REQ PLCI = %#x (%#x %#x) onholdPLCI = %#x\n ", + i->PLCI, fac[4], fac[5], i->onholdPLCI); + ast_log(LOG_NOTICE,"%s\n",capi_cmsg2str(&CMSG)); + } + + /* i->outgoing = -1; / incoming + outgoing, this is a magic channel :) */ + + LOCAL_USER_REMOVE(u); + return res; +} + +int unload_module(void) +{ + STANDARD_HANGUP_LOCALUSERS; + return ast_unregister_application(app); +} + +int load_module(void) +{ + return ast_register_application(app, capiECT_exec, synopsis, tdesc); +} + +char *description(void) +{ + return tdesc; +} + +int usecount(void) +{ + int res; + STANDARD_USECOUNT(res); + return res; +} + +char *key() +{ + return ASTERISK_GPL_KEY; +} + diff --git a/app_capiHOLD.c b/app_capiHOLD.c new file mode 100644 index 0000000..f63194d --- /dev/null +++ b/app_capiHOLD.c @@ -0,0 +1,134 @@ +/* + * (CAPI*) + * + * An implementation of Common ISDN API 2.0 for Asterisk + * + * HOLD ... stop right there...that's close enough + * + * Copyright (C) 2005 Cytronics & Melware + * + * Armin Schindler + * + * Reworked, but based on the work of + * Copyright (C) 2002-2005 Junghanns.NET GmbH + * + * Klaus-Peter Junghanns + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#include "config.h" + +#include +#include +#include +#ifndef CC_AST_HAVE_TECH_PVT +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "chan_capi_pvt.h" +#include "chan_capi_app.h" + + + +static char *tdesc = "(CAPI*) HOLD"; +static char *app = "capiHOLD"; +static char *synopsis = "put the call on hold"; + +STANDARD_LOCAL_USER; + +LOCAL_USER_DECL; + +static int capiHOLD_exec(struct ast_channel *chan, void *data) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(chan); + MESSAGE_EXCHANGE_ERROR Info; + _cmsg CMSG; + char fac[4]; + int res = 0; + struct localuser *u; + + LOCAL_USER_ADD(u); + + /* Do our thing here */ + + while (i->state != CAPI_STATE_BCONNECTED) { + usleep(10000); + } + + fac[0] = 3; /* len */ + fac[1] = 0x02; /* this is a HOLD up */ + fac[2] = 0; + fac[3] = 0; + + FACILITY_REQ_HEADER(&CMSG,ast_capi_ApplID, get_ast_capi_MessageNumber(),0); + FACILITY_REQ_PLCI(&CMSG) = i->PLCI; + FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 0x0003; /* sservices */ + FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (char *)&fac; + + if ((Info = _capi_put_cmsg(&CMSG)) != 0) { + LOCAL_USER_REMOVE(u); + return Info; + } else { + ast_log(LOG_NOTICE,"sent FACILITY_REQ PLCI = %#x\n", + i->PLCI); + } + + i->state = CAPI_STATE_PUTTINGONHOLD; + i->onholdPLCI= i->PLCI; + + while (i->state == CAPI_STATE_PUTTINGONHOLD) { + usleep(10000); + } + + if (i->onholdPLCI != 0) { + ast_log(LOG_NOTICE,"PLCI = %#x is on hold now\n", + i->onholdPLCI); + } else { + i->state = CAPI_STATE_BCONNECTED; + ast_log(LOG_NOTICE,"PLCI = %#x did not go on hold. going on!\n", + i->PLCI); + } + + LOCAL_USER_REMOVE(u); + return res; +} + +int unload_module(void) +{ + STANDARD_HANGUP_LOCALUSERS; + return ast_unregister_application(app); +} + +int load_module(void) +{ + return ast_register_application(app, capiHOLD_exec, synopsis, tdesc); +} + +char *description(void) +{ + return tdesc; +} + +int usecount(void) +{ + int res; + STANDARD_USECOUNT(res); + return res; +} + +char *key() +{ + return ASTERISK_GPL_KEY; +} + diff --git a/app_capiMCID.c b/app_capiMCID.c new file mode 100644 index 0000000..af4143f --- /dev/null +++ b/app_capiMCID.c @@ -0,0 +1,124 @@ +/* + * (CAPI*) + * + * An implementation of Common ISDN API 2.0 for Asterisk + * + * Malicious Caller ID + * + * Copyright (C) 2005 Cytronics & Melware + * + * Armin Schindler + * + * Reworked, but based on the work of + * Copyright (C) 2002-2005 Junghanns.NET GmbH + * + * Klaus-Peter Junghanns + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#include "config.h" + +#include +#include +#include +#ifndef CC_AST_HAVE_TECH_PVT +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "chan_capi_pvt.h" +#include "chan_capi_app.h" + + + +static char *tdesc = "(CAPI*) Malicious Caller ID, the evil thing."; +static char *app = "capiMCID"; +static char *synopsis = "malicious caller id"; + +STANDARD_LOCAL_USER; + +LOCAL_USER_DECL; + +static int capiMCID_exec(struct ast_channel *chan, void *data) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(chan); + MESSAGE_EXCHANGE_ERROR Info; + _cmsg CMSG; + char fac[4]; + int res = 0; + struct localuser *u; + + LOCAL_USER_ADD(u); + + /* Do our thing here */ + +/* + if ((i->state != CAPI_STATE_CONNECTED) && (i->state != CAPI_STATE_BCONNECTED)) { + ast_log(LOG_ERROR, "need to accept the call first to MCID!\n"); + LOCAL_USER_REMOVE(u); + return -1; + } +*/ + + fac[0] = 3; /* len */ + fac[1] = 0x0d; + fac[2] = 0x00; + fac[3] = 0; + + FACILITY_REQ_HEADER(&CMSG,ast_capi_ApplID, get_ast_capi_MessageNumber(),0); + FACILITY_REQ_PLCI(&CMSG) = i->PLCI; + FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 0x0003; /* sservices */ + FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (char *)&fac; + + if ((Info = _capi_put_cmsg(&CMSG)) != 0) { + LOCAL_USER_REMOVE(u); + return Info; + } else { + if (capidebug) { + ast_log(LOG_NOTICE,"sent FACILITY_REQ PLCI = %#x\n", + i->PLCI); + } + } + + LOCAL_USER_REMOVE(u); + return res; +} + +int unload_module(void) +{ + STANDARD_HANGUP_LOCALUSERS; + return ast_unregister_application(app); +} + +int load_module(void) +{ + return ast_register_application(app, capiMCID_exec, synopsis, tdesc); +} + +char *description(void) +{ + return tdesc; +} + +int usecount(void) +{ + int res; + STANDARD_USECOUNT(res); + return res; +} + +char *key() +{ + return ASTERISK_GPL_KEY; +} + diff --git a/app_capiNoES.c b/app_capiNoES.c new file mode 100644 index 0000000..02c173f --- /dev/null +++ b/app_capiNoES.c @@ -0,0 +1,99 @@ +/* + * (CAPI*) + * + * An implementation of Common ISDN API 2.0 for Asterisk + * + * Disable echo suppression (useful for fax and voicemail!) + * + * Copyright (C) 2005 Cytronics & Melware + * + * Armin Schindler + * + * Reworked, but based on the work of + * Copyright (C) 2002-2005 Junghanns.NET GmbH + * + * Klaus-Peter Junghanns + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#include "config.h" + +#include +#include +#include +#ifndef CC_AST_HAVE_TECH_PVT +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "chan_capi_pvt.h" +#include "chan_capi_app.h" + + + +static char *tdesc = "(CAPI*) No Echo Suppression."; +static char *app = "capiNoES"; +static char *synopsis = "Disable Echo Suppression"; + +STANDARD_LOCAL_USER; + +LOCAL_USER_DECL; + +static int capiNoES_exec(struct ast_channel *chan, void *data) +{ + int res=0; + struct localuser *u; + + LOCAL_USER_ADD(u); + + if (strcasecmp("CAPI", chan->type) == 0) { + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(chan); + if (i->doES == 1) { + i->doES = 0; + } + } else { + ast_log(LOG_WARNING, "capiNoES only works on CAPI channels, check your extensions.conf!\n"); + } + + LOCAL_USER_REMOVE(u); + return res; +} + +int unload_module(void) +{ + STANDARD_HANGUP_LOCALUSERS; + return ast_unregister_application(app); +} + +int load_module(void) +{ + return ast_register_application(app, capiNoES_exec, synopsis, tdesc); +} + +char *description(void) +{ + return tdesc; +} + +int usecount(void) +{ + int res; + STANDARD_USECOUNT(res); + return res; +} + +char *key() +{ + return ASTERISK_GPL_KEY; +} + diff --git a/app_capiRETRIEVE.c b/app_capiRETRIEVE.c new file mode 100644 index 0000000..6218756 --- /dev/null +++ b/app_capiRETRIEVE.c @@ -0,0 +1,137 @@ +/* + * (CAPI*) + * + * An implementation of Common ISDN API 2.0 for Asterisk + * + * RETRIEVE + * + * Copyright (C) 2005 Cytronics & Melware + * + * Armin Schindler + * + * Reworked, but based on the work of + * Copyright (C) 2002-2005 Junghanns.NET GmbH + * + * Klaus-Peter Junghanns + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#include "config.h" + +#include +#include +#include +#ifndef CC_AST_HAVE_TECH_PVT +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "chan_capi_pvt.h" +#include "chan_capi_app.h" + + + +static char *tdesc = "(CAPI*) RETRIEVE"; +static char *app = "capiRETRIEVE"; +static char *synopsis = "retrieve the call that is on hold"; + +STANDARD_LOCAL_USER; + +LOCAL_USER_DECL; + +static int capiRETRIEVE_exec(struct ast_channel *chan, void *data) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(chan); + MESSAGE_EXCHANGE_ERROR Info; + _cmsg CMSG; + char fac[4]; + int res = 0; + struct localuser *u; + + if (i->onholdPLCI <= 0) { + ast_log(LOG_WARNING, "no call on hold to retrieve!\n"); + return -1; + } + + LOCAL_USER_ADD(u); + + /* Do our thing here */ + + fac[0] = 3; /* len */ + fac[1] = 0x03; /* retrieve */ + fac[2] = 0x00; + fac[3] = 0; + + FACILITY_REQ_HEADER(&CMSG,ast_capi_ApplID, get_ast_capi_MessageNumber(),0); + FACILITY_REQ_PLCI(&CMSG) = i->onholdPLCI; + FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 0x0003; /* sservices */ + FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (char *)&fac; + + if ((Info = _capi_put_cmsg(&CMSG)) != 0) { + LOCAL_USER_REMOVE(u); + return Info; + } else { + i->state = CAPI_STATE_RETRIEVING; + ast_log(LOG_NOTICE,"sent FACILITY_REQ PLCI = %#x\n",i->onholdPLCI); + } + + while (i->state == CAPI_STATE_RETRIEVING) { + usleep(10000); + } + + /* send a CONNECT_B3_REQ */ + memset(&CMSG, 0, sizeof(_cmsg)); + CONNECT_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(),0); + CONNECT_B3_REQ_PLCI(&CMSG) = i->PLCI; + if ((Info = _capi_put_cmsg(&CMSG)) == 0) { + ast_log(LOG_NOTICE,"sent CONNECT_B3_REQ (PLCI=%#x)\n", + i->PLCI); + } + + while (i->state == CAPI_STATE_CONNECTED) { + usleep(10000); + } + ast_log(LOG_NOTICE,"retrieved PLCI = %#x\n", i->PLCI); + + LOCAL_USER_REMOVE(u); + return res; +} + +int unload_module(void) +{ + STANDARD_HANGUP_LOCALUSERS; + return ast_unregister_application(app); +} + +int load_module(void) +{ + return ast_register_application(app, capiRETRIEVE_exec, synopsis, tdesc); +} + +char *description(void) +{ + return tdesc; +} + +int usecount(void) +{ + int res; + STANDARD_USECOUNT(res); + return res; +} + +char *key() +{ + return ASTERISK_GPL_KEY; +} + diff --git a/capi.conf b/capi.conf new file mode 100644 index 0000000..88920f2 --- /dev/null +++ b/capi.conf @@ -0,0 +1,44 @@ +; +; CAPI config +; +; +[general] +nationalprefix=0 +internationalprefix=00 +rxgain=0.8 +txgain=0.8 + +[interfaces] + +; mode: ptmp (point-to-multipoint) or ptp (point-to-point) +isdnmode=ptmp +; allow incoming calls to this list of MSNs, * == any +incomingmsn=* +; capi controller number +controller=1 +; dialout group +group=1 +; enable/disable software dtmf detection, recommended for AVM cards +softdtmf=1 +; accountcode to use in CDRs +accountcode= +; context for incoming calls +context=capi-in +; _VERY_PRIMITIVE_ echo suppression +;echosquelch=1 +; EICON DIVA SERVER echo cancelation +;echocancel=yes +;echotail=64 +; call group +;callgroup=1 +; deflect incoming calls to 12345678 if all B channels are busy +;deflect=12345678 +; number of concurrent calls on this controller (2 makes sense for single BRI) +devices => 2 + + +;PointToPoint (55512-0) +;isdnmode=ptp +;msn=55512 +;controller=2 +;devices => 30 diff --git a/chan_capi.c b/chan_capi.c new file mode 100644 index 0000000..9a51740 --- /dev/null +++ b/chan_capi.c @@ -0,0 +1,3062 @@ +/* + * (CAPI*) + * + * An implementation of Common ISDN API 2.0 for Asterisk + * + * Copyright (C) 2005 Cytronics & Melware + * + * Armin Schindler + * + * Reworked, but based on the work of + * Copyright (C) 2002-2005 Junghanns.NET GmbH + * + * Klaus-Peter Junghanns + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#include "config.h" + +#include +#include +#include +#ifndef CC_AST_HAVE_TECH_PVT +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) +#include +#else +#include +#endif +#include +#include +#include "xlaw.h" +#include "chan_capi_app.h" +#include "chan_capi_pvt.h" + + +/* + * personal stuff + */ +unsigned ast_capi_ApplID; + +static _cword ast_capi_MessageNumber = 1; +static char *desc = "Common ISDN API for Asterisk"; +#ifdef CC_AST_HAVE_TECH_PVT +#ifdef CAPI_ULAW +static const char tdesc[] = "Common ISDN API Driver (0.4.0) muLaw "ASTERISKVERSION; +#else +static const char tdesc[] = "Common ISDN API Driver (0.4.0) aLaw "ASTERISKVERSION; +#endif +static const char type[] = "CAPI"; +#else +#ifdef CAPI_ULAW +static char *tdesc = "Common ISDN API Driver (0.4.0) muLaw "ASTERISKVERSION; +#else +static char *tdesc = "Common ISDN API Driver (0.4.0) aLaw "ASTERISKVERSION; +#endif +static char *type = "CAPI"; +#endif + +static int usecnt; + +AST_MUTEX_DEFINE_STATIC(messagenumber_lock); +AST_MUTEX_DEFINE_STATIC(usecnt_lock); +AST_MUTEX_DEFINE_STATIC(iflock); +AST_MUTEX_DEFINE_STATIC(pipelock); +AST_MUTEX_DEFINE_STATIC(monlock); +AST_MUTEX_DEFINE_STATIC(contrlock); +AST_MUTEX_DEFINE_STATIC(capi_send_buffer_lock); +AST_MUTEX_DEFINE_STATIC(capi_put_lock); + +#ifdef CAPI_ULAW +static int capi_capability = AST_FORMAT_ULAW; +#else +static int capi_capability = AST_FORMAT_ALAW; +#endif + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) +static CAPIProfileBuffer_t profile; +#else +static struct ast_capi_profile profile; +#endif + +static pthread_t monitor_thread = -1; + +static struct ast_capi_pvt *iflist = NULL; +static struct capi_pipe *pipelist = NULL; +static struct ast_capi_controller *capi_controllers[AST_CAPI_MAX_CONTROLLERS]; +static int capi_num_controllers = 0; +static int capi_counter = 0; +static unsigned long capi_used_controllers=0; + +static char capi_send_buffer[AST_CAPI_MAX_B3_BLOCKS * AST_CAPI_MAX_B3_BLOCK_SIZE]; +static int capi_send_buffer_handle = 0; + +char capi_national_prefix[AST_MAX_EXTENSION]; +char capi_international_prefix[AST_MAX_EXTENSION]; + +int capidebug = 0; + +/* + * helper for ast_verbose with different verbose settings + */ +#define cc_ast_verbose(o_v, c_d, text...) \ + do { \ + if ((o_v == 0) || (option_verbose > o_v)) { \ + if ((!c_d) || ((c_d) && (capidebug))) { \ + ast_verbose(text); \ + } \ + } \ + } while(0) + +#define return_on_no_pipe(x) \ + if (!p) { \ + ast_log(LOG_ERROR, "CAPI: %s no pipe PLCI=%#x\n", x, PLCI); \ + return; \ + } + +/* + * get a new capi message number atomically + */ +_cword get_ast_capi_MessageNumber(void) +{ + _cword mn; + + ast_mutex_lock(&messagenumber_lock); + mn = ast_capi_MessageNumber; + ast_capi_MessageNumber++; + ast_mutex_unlock(&messagenumber_lock); + + return(mn); +} + +/* + * write a capi message to capi device + */ +MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG) +{ + MESSAGE_EXCHANGE_ERROR error; + + if (ast_mutex_lock(&capi_put_lock)) { + ast_log(LOG_WARNING, "Unable to lock capi put!\n"); + return -1; + } + + error = capi20_put_cmsg(CMSG); + + if (ast_mutex_unlock(&capi_put_lock)) { + ast_log(LOG_WARNING, "Unable to unlock capi put!\n"); + return -1; + } + + if (error) { + ast_log(LOG_ERROR, "CAPI error sending %s (NCCI=%#x) (error=%#x)\n", + capi_cmsg2str(CMSG), CMSG->adr.adrNCCI, error); + } + return error; +} + +/* + * wait some time for a new capi message + */ +MESSAGE_EXCHANGE_ERROR check_wait_get_cmsg(_cmsg *CMSG) +{ + MESSAGE_EXCHANGE_ERROR Info; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 10000; + + Info = capi20_waitformessage(ast_capi_ApplID, &tv); + if ((Info != 0x0000) && (Info != 0x1104)) { + if (capidebug) { + ast_log(LOG_DEBUG, "Error waiting for cmsg... INFO = %#x\n", Info); + } + return Info; + } + + if (Info == 0x0000) { + Info = capi_get_cmsg(CMSG,ast_capi_ApplID); + } + return Info; +} + +/* + * send Listen to specified controller + */ +static unsigned ListenOnController(unsigned long CIPmask, unsigned controller) +{ + MESSAGE_EXCHANGE_ERROR error; + _cmsg CMSG,CMSG2; + + LISTEN_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), controller); + + LISTEN_REQ_INFOMASK(&CMSG) = 0x03ff; /* lots of info ;) + early B3 connect */ + /* 0x00ff if no early B3 should be done */ + + LISTEN_REQ_CIPMASK(&CMSG) = CIPmask; + if ((error = _capi_put_cmsg(&CMSG)) != 0) { + return error; + } + while (!IS_LISTEN_CONF(&CMSG2)) { + error = check_wait_get_cmsg(&CMSG2); + } + return 0; +} + +/* + * Echo cancellation is for cards w/ integrated echo cancellation only + * (i.e. Eicon active cards support it) + */ + +#define EC_FUNCTION_ENABLE 1 +#define EC_FUNCTION_DISABLE 2 +#define EC_FUNCTION_FREEZE 3 +#define EC_FUNCTION_RESUME 4 +#define EC_FUNCTION_RESET 5 +#define EC_OPTION_DISABLE_NEVER 0 +#define EC_OPTION_DISABLE_G165 (1<<1) +#define EC_OPTION_DISABLE_G164_OR_G165 (1<<1 | 1<<2) +#define EC_DEFAULT_TAIL 64 + +static void capi_echo_canceller(struct ast_channel *c, int function) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); + _cmsg CMSG; + char buf[7]; + + /* If echo cancellation is not requested or supported, don't attempt to enable it */ + ast_mutex_lock(&contrlock); + if (!capi_controllers[i->controller]->echocancel || !i->doEC) { + ast_mutex_unlock(&contrlock); + return; + } + ast_mutex_unlock(&contrlock); + + cc_ast_verbose(2, 0, VERBOSE_PREFIX_3 "Setting up echo canceller (PLCI=%#x, function=%d, options=%d, tail=%d)\n", + i->PLCI, function, i->ecOption, i->ecTail); + + FACILITY_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + FACILITY_REQ_NCCI(&CMSG) = i->NCCI; + FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 6; /* Echo canceller */ + + memset(buf, 0, sizeof(buf)); + buf[0] = 6; /* msg size */ + write_capi_word(&buf[1], function); + if (function == EC_FUNCTION_ENABLE) { + write_capi_word(&buf[3], i->ecOption); /* bit field - ignore echo canceller disable tone */ + write_capi_word(&buf[5], i->ecTail); /* Tail length, ms */ + } + + FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = buf; + + if (_capi_put_cmsg(&CMSG) != 0) { + return; + } + + cc_ast_verbose(5, 0, VERBOSE_PREFIX_4 "sent FACILITY_REQ (PLCI=%#x)\n", i->PLCI); + + return; +} + +/* + * turn on/off DTMF detection + */ +int capi_detect_dtmf(struct ast_channel *c, int flag) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); + MESSAGE_EXCHANGE_ERROR error; + _cmsg CMSG; + char buf[9]; + + memset(buf, 0, sizeof(buf)); + + /* does the controller support dtmf? and do we want to use it? */ + + ast_mutex_lock(&contrlock); + + if ((capi_controllers[i->controller]->dtmf == 1) && (i->doDTMF == 0)) { + ast_mutex_unlock(&contrlock); + FACILITY_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + FACILITY_REQ_PLCI(&CMSG) = i->PLCI; + FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 1; + buf[0] = 8; /* msg length */ + if (flag == 1) { + write_capi_word(&buf[1], 1); /* start DTMF listen */ + } else { + write_capi_word(&buf[1], 2); /* stop DTMF listen */ + } + write_capi_word(&buf[3], AST_CAPI_DTMF_DURATION); + write_capi_word(&buf[5], AST_CAPI_DTMF_DURATION); + FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = buf; + + if ((error = _capi_put_cmsg(&CMSG)) != 0) { + return error; + } + cc_ast_verbose(5, 0, VERBOSE_PREFIX_4 "sent FACILITY_REQ (PLCI=%#x)\n", + i->PLCI); + } else { + ast_mutex_unlock(&contrlock); + /* do software dtmf detection */ + i->doDTMF = 1; /* just being paranoid again... */ + } + return 0; +} + +/* + * send a DTMF digit + */ +static int capi_send_digit(struct ast_channel *c, char digit) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); + MESSAGE_EXCHANGE_ERROR error; + _cmsg CMSG; + char buf[10]; + + if (i->state != CAPI_STATE_BCONNECTED) { + return 0; + } + + memset(buf, 0, sizeof(buf)); + + if (i->earlyB3 == 1) { + /* + * we should really test for the network saying the number is incomplete + * since i'm only doing a test and this is true at the right time + * i'm going with this + */ + + INFO_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + INFO_REQ_PLCI(&CMSG) = i->PLCI; + buf[0] = 2; + buf[1] = 0x80; + buf[2] = digit; + INFO_REQ_CALLEDPARTYNUMBER(&CMSG) = buf; + + if ((error = _capi_put_cmsg(&CMSG)) != 0) { + return error; + } + cc_ast_verbose(5, 0, VERBOSE_PREFIX_4 "sent CALLEDPARTYNUMBER INFO digit = %c (PLCI=%#x)\n", + digit, i->PLCI); + } else { + ast_mutex_lock(&contrlock); + if ((capi_controllers[i->controller]->dtmf == 0) || (i->doDTMF == 1)) { + /* let * fake it */ + ast_mutex_unlock(&contrlock); + return -1; + } + + ast_mutex_unlock(&contrlock); + + FACILITY_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + FACILITY_REQ_PLCI(&CMSG) = i->NCCI; + FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 1; + buf[0] = 8; + write_capi_word(&buf[1], 3); /* send DTMF digit */ + write_capi_word(&buf[3], AST_CAPI_DTMF_DURATION); + write_capi_word(&buf[5], AST_CAPI_DTMF_DURATION); + buf[7] = 1; + buf[8] = digit; + FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = buf; + + if ((error = _capi_put_cmsg(&CMSG)) != 0) { + return error; + } + cc_ast_verbose(4, 0, VERBOSE_PREFIX_3 "sent dtmf '%c'\n", digit); + } + return 0; +} + +/* + * send ALERT to ISDN line + */ +static int capi_alert(struct ast_channel *c) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); + _cmsg CMSG; + + ALERT_REQ_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0); + ALERT_REQ_PLCI(&CMSG) = i->PLCI; + + if (_capi_put_cmsg(&CMSG) != 0) { + return -1; + } + cc_ast_verbose(5, 0, VERBOSE_PREFIX_4 "sent ALERT_REQ PLCI = %#x\n", + i->PLCI); + + i->state = CAPI_STATE_ALERTING; + + return 0; +} + +/* + * deflect a call + */ +static int capi_deflect(struct ast_channel *chan, void *data) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(chan); + MESSAGE_EXCHANGE_ERROR Info; + _cmsg CMSG; + char bchaninfo[1]; + char fac[60]; + int res = 0; + int ms = 3000; + + if (!data) { + ast_log(LOG_WARNING, "cd requires an argument (destination phone number)\n"); + return -1; + } + + if ((i->state == CAPI_STATE_CONNECTED) || (i->state == CAPI_STATE_BCONNECTED)) { + ast_log(LOG_ERROR, "call deflection does not work with calls that are already connected!\n"); + return -1; + } + + /* wait until the channel is alerting, so we dont drop the call and interfer with msgs */ + while ((ms > 0) && (i->state != CAPI_STATE_ALERTING)) { + sleep(100); + ms -= 100; + } + + /* make sure we hang up correctly */ + i->state = CAPI_STATE_CONNECTPENDING; + + fac[0] = 0; /* len */ + fac[1] = 0; /* len */ + fac[2] = 0x01; /* Use D-Chan */ + fac[3] = 0; /* Keypad len */ + fac[4] = 31; /* user user data? len = 31 = 29 + 2 */ + fac[5] = 0x1c; /* magic? */ + fac[6] = 0x1d; /* strlen destination + 18 = 29 */ + fac[7] = 0x91; /* .. */ + fac[8] = 0xA1; + fac[9] = 0x1A; /* strlen destination + 15 = 26 */ + fac[10] = 0x02; + fac[11] = 0x01; + fac[12] = 0x70; + fac[13] = 0x02; + fac[14] = 0x01; + fac[15] = 0x0d; + fac[16] = 0x30; + fac[17] = 0x12; /* strlen destination + 7 = 18 */ + fac[18] = 0x30; /* ...hm 0x30 */ + fac[19] = 0x0d; /* strlen destination + 2 */ + fac[20] = 0x80; /* CLIP */ + fac[21] = 0x0b; /* strlen destination */ + fac[22] = 0x01; /* destination start */ + fac[23] = 0x01; + fac[24] = 0x01; + fac[25] = 0x01; + fac[26] = 0x01; + fac[27] = 0x01; + fac[28] = 0x01; + fac[29] = 0x01; + fac[30] = 0x01; + fac[31] = 0x01; + fac[32] = 0x01; + fac[33] = 0x01; /* 0x1 = sending complete */ + fac[34] = 0x01; + fac[35] = 0x01; + + memcpy((unsigned char *)fac + 22, data, strlen(data)); + fac[22 + strlen(data)] = 0x01; /* fill with 0x01 if number is only 6 numbers (local call) */ + fac[23 + strlen(data)] = 0x01; + fac[24 + strlen(data)] = 0x01; + fac[25 + strlen(data)] = 0x01; + fac[26 + strlen(data)] = 0x01; + + fac[6] = 18 + strlen(data); + fac[9] = 15 + strlen(data); + fac[17] = 7 + strlen(data); + fac[19] = 2 + strlen(data); + fac[21] = strlen(data); + + bchaninfo[0] = 0x1; + + INFO_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + INFO_REQ_CONTROLLER(&CMSG) = i->controller; + INFO_REQ_PLCI(&CMSG) = i->PLCI; + INFO_REQ_BCHANNELINFORMATION(&CMSG) = (unsigned char*)bchaninfo; /* use D-Channel */ + INFO_REQ_KEYPADFACILITY(&CMSG) = 0; + INFO_REQ_USERUSERDATA(&CMSG) = 0; + INFO_REQ_FACILITYDATAARRAY(&CMSG) = (unsigned char*) fac + 4; + + if ((Info = _capi_put_cmsg(&CMSG)) != 0) { + return Info; + } + if (capidebug) { + /* ast_log(LOG_NOTICE,"%s\n",capi_cmsg2str(&CMSG)); */ + ast_log(LOG_NOTICE,"sent INFO_REQ PLCI = %#x\n",i->PLCI); + } + + return res; +} + +/* + * remove a pipe from the list + */ +static void remove_pipe(unsigned int PLCI) +{ + struct capi_pipe *p,*ptmp; + + ast_mutex_lock(&pipelock); + p = pipelist; + ptmp = NULL; + + while (p) { + if (p->PLCI != PLCI) { + ptmp = p; + p = p->next; + continue; + } + if (ptmp == NULL) { + /* mypipe == head of pipelist */ + pipelist = p->next; + } else { + /* somehwere inbetween or at the end */ + ptmp->next = p->next; + } + if(p->fd > -1) + close(p->fd); + if(p->i != NULL && p->i->fd > -1) + close(p->i->fd); + free(p); + cc_ast_verbose(4, 0, VERBOSE_PREFIX_3 "removed pipe for PLCI = %#x\n", PLCI); + break; + } + ast_mutex_unlock(&pipelock); +} + +/* + * hangup a line (CAPI messages) + */ +static void capi_activehangup(struct ast_channel *c) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); + _cmsg CMSG; + + cc_ast_verbose(2, 1, VERBOSE_PREFIX_4 "activehangingup\n"); + + if (i == NULL) { + return; + } + + if (c->_state == AST_STATE_RING) { + CONNECT_RESP_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0); + CONNECT_RESP_PLCI(&CMSG) = i->PLCI; + CONNECT_RESP_REJECT(&CMSG) = 2; + if (_capi_put_cmsg(&CMSG) == 0) { + cc_ast_verbose(5, 0, VERBOSE_PREFIX_4 "sent CONNECT_RESP for PLCI = %#x\n", i->PLCI); + } + return; + } + + /* active disconnect */ + if (i->state == CAPI_STATE_BCONNECTED) { + DISCONNECT_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI; + + if (_capi_put_cmsg(&CMSG) == 0) { + cc_ast_verbose(5, 0, VERBOSE_PREFIX_4 "sent DISCONNECT_B3_REQ NCCI=%#x\n", i->NCCI); + } + return; + } + + if ((i->state == CAPI_STATE_CONNECTED) || (i->state == CAPI_STATE_CONNECTPENDING)) { + DISCONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + DISCONNECT_REQ_PLCI(&CMSG) = i->PLCI; + + if (_capi_put_cmsg(&CMSG) == 0) { + cc_ast_verbose(5, 0, VERBOSE_PREFIX_4 "sent DISCONNECT_REQ PLCI=%#x\n", + i->PLCI); + } + } + return; +} + +/* + * Asterisk tells us to hangup a line + */ +static int capi_hangup(struct ast_channel *c) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); + + /* + * hmm....ok...this is called to free the capi interface (passive disconnect) + * or to bring down the channel (active disconnect) + */ + + cc_ast_verbose(3, 0, VERBOSE_PREFIX_3 "CAPI Hangingup\n"); + + if (i == NULL) { + ast_log(LOG_ERROR,"channel has no interface!\n"); + return -1; + } + + /* are we down, yet? */ + if (i->state != CAPI_STATE_DISCONNECTED) { + /* no */ + capi_activehangup(c); + } + + i->state = CAPI_STATE_DISCONNECTING; + + if ((i->doDTMF == 1) && (i->vad != NULL)) { + ast_dsp_free(i->vad); + } + + ast_smoother_free(i->smoother); /* discard any frames left hanging */ + i->smoother = ast_smoother_new(AST_CAPI_MAX_B3_BLOCK_SIZE * 2); + memset(i->cid, 0, sizeof(i->cid)); + i->owner=NULL; + + ast_mutex_lock(&usecnt_lock); + usecnt--; + ast_mutex_unlock(&usecnt_lock); + + ast_update_use_count(); + + i->mypipe = NULL; + CC_AST_CHANNEL_PVT(c) = NULL; + ast_setstate(c, AST_STATE_DOWN); + + return 0; +} + +/* + * convert a number + */ +static char *capi_number(char *data, int strip) +{ + unsigned len = *data; + + /* XXX fix me */ + /* convert a capi struct to a \0 terminated string */ + if ((!len) || (len < (unsigned int) strip)) + return NULL; + + len = len - strip; + data = (char *)(data + 1 + strip); + + return strndup((char *)data, len); +} + +/* + * Asterisk tells us to make a call + */ +int capi_call(struct ast_channel *c, char *idest, int timeout) +{ + struct ast_capi_pvt *i; + struct capi_pipe *p = NULL; + char *dest, *interface; + char buffer[AST_MAX_EXTENSION]; + char called[AST_MAX_EXTENSION], calling[AST_MAX_EXTENSION]; + char bchaninfo[3]; + + _cmsg CMSG; + MESSAGE_EXCHANGE_ERROR error; + + strncpy(buffer, (char *)idest, sizeof(buffer) - 1); + interface = strtok(buffer, "/"); + dest = strtok(NULL, "/"); + + + if ((!dest) || (!dest[0])) { + ast_log(LOG_WARNING, "Destination %s requres a real destination\n", idest); + return -1; + } + + i = CC_AST_CHANNEL_PVT(c); + + /* first character of destination tells special treatment */ + switch(dest[0]) { + case 'b': /* always B3 */ + i->doB3 = AST_CAPI_B3_ALWAYS; + dest++; + break; + case 'B': /* only do B3 on successfull calls */ + i->doB3 = AST_CAPI_B3_ON_SUCCESS; + dest++; + break; + default: + i->doB3 = AST_CAPI_B3_DONT; + } + + cc_ast_verbose(1, 1, VERBOSE_PREFIX_2 "CAPI Call %s %s\n", c->name, i->doB3?"with B3":""); + +#ifdef CC_AST_CHANNEL_HAS_CID + switch (c->cid.cid_pres) { +#else + switch (c->callingpres) { +#endif + case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED: + case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN: + case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN: + case PRES_ALLOWED_NETWORK_NUMBER: + case PRES_NUMBER_NOT_AVAILABLE: + i->CLIR = 0; + break; + case PRES_PROHIB_USER_NUMBER_NOT_SCREENED: + case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: + case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN: + case PRES_PROHIB_NETWORK_NUMBER: + i->CLIR = 1; + break; + default: + i->CLIR = 0; + } + + p = malloc(sizeof(struct capi_pipe)); + if (!p) { + ast_log(LOG_ERROR, "Error allocating capi_pipe.\n"); + return -1; + } + memset(p, 0, sizeof(struct capi_pipe)); + + /* set pipe and FDs */ + p->fd = i->fd2; + c->fds[0] = i->fd; + p->i = i; + p->c = c; + i->mypipe = p; + + ast_mutex_lock(&pipelock); + p->next = pipelist; + pipelist = p; + ast_mutex_unlock(&pipelock); + + i->outgoing = 1; + + i->MessageNumber = get_ast_capi_MessageNumber(); + CONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, i->controller); + CONNECT_REQ_CONTROLLER(&CMSG) = i->controller; + CONNECT_REQ_CIPVALUE(&CMSG) = 0x10; /* Telephony, could also use 0x04 (3.1Khz audio) */ + called[0] = strlen(dest) + 1; + called[1] = 0x80; + strncpy(&called[2], dest, sizeof(called) - 2); + CONNECT_REQ_CALLEDPARTYNUMBER(&CMSG) = called; + CONNECT_REQ_CALLEDPARTYSUBADDRESS(&CMSG) = NULL; + +#ifdef CC_AST_CHANNEL_HAS_CID + calling[0] = strlen(c->cid.cid_num) + 2; +#else + calling[0] = strlen(c->callerid) + 2; +#endif + + calling[1] = 0x00; + if (i->CLIR == 1) { + calling[2] = 0xA0; /* CLIR */ + } else { + calling[2] = 0x80; /* CLIP */ + } +#ifdef CC_AST_CHANNEL_HAS_CID + strncpy(&calling[3], c->cid.cid_num, sizeof(calling) - 3); +#else + strncpy(&calling[3], c->callerid, sizeof(calling) - 3); +#endif + + CONNECT_REQ_CALLINGPARTYNUMBER(&CMSG) = calling; + CONNECT_REQ_CALLINGPARTYSUBADDRESS(&CMSG) = NULL; + + CONNECT_REQ_B1PROTOCOL(&CMSG) = 1; + CONNECT_REQ_B2PROTOCOL(&CMSG) = 1; + CONNECT_REQ_B3PROTOCOL(&CMSG) = 0; + + bchaninfo[0] = 2; + bchaninfo[1] = 0x0; + bchaninfo[2] = 0x0; + CONNECT_REQ_BCHANNELINFORMATION(&CMSG) = bchaninfo; /* 0 */ + + if ((error = _capi_put_cmsg(&CMSG))) { + return error; + } + cc_ast_verbose(5, 0, VERBOSE_PREFIX_4 "sent CONNECT_REQ MN =%#x\n", + CMSG.Messagenumber); + + i->state = CAPI_STATE_CONNECTPENDING; + + ast_setstate(c, AST_STATE_DIALING); + +#if 0 + /* XXX fixme, not nice: */ + if (i->controller > 0) { + capi_controllers[i->controller]->nfreebchannels--; + } +#endif + + /* now we shall return .... the rest has to be done by handle_msg */ + return 0; +} + +/* + * Asterisk tells us to answer a call + */ +static int capi_answer(struct ast_channel *c) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); + _cmsg CMSG; + char buf[AST_MAX_EXTENSION]; + char *dnid; + + if ((i->isdnmode == AST_CAPI_ISDNMODE_PTP) && + (strlen(i->incomingmsn) < strlen(i->dnid))) { + dnid = i->dnid + strlen(i->incomingmsn); + } else { + dnid = i->dnid; + } + + CONNECT_RESP_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0); + CONNECT_RESP_PLCI(&CMSG) = i->PLCI; + CONNECT_RESP_REJECT(&CMSG) = 0; + buf[0] = strlen(dnid) + 2; + buf[1] = 0x00; + buf[2] = 0x80; + strncpy(&buf[3], dnid, sizeof(buf) - 4); + CONNECT_RESP_CONNECTEDNUMBER(&CMSG) = buf; + CONNECT_RESP_CONNECTEDSUBADDRESS(&CMSG) = NULL; + CONNECT_RESP_LLC(&CMSG) = NULL; + CONNECT_RESP_B1PROTOCOL(&CMSG) = 1; + CONNECT_RESP_B2PROTOCOL(&CMSG) = 1; + CONNECT_RESP_B3PROTOCOL(&CMSG) = 0; + + cc_ast_verbose(3, 0, VERBOSE_PREFIX_3 "CAPI Answering for MSN %s\n", dnid); + + if (_capi_put_cmsg(&CMSG) != 0) { + return -1; + } + cc_ast_verbose(5, 1, VERBOSE_PREFIX_4 "sent CONNECT_RESP PLCI = %#x DNID = %s\n", + i->PLCI, i->dnid); + + i->state = CAPI_STATE_ANSWERING; + i->doB3 = AST_CAPI_B3_DONT; + i->outgoing = 0; + i->earlyB3 = -1; + + return 0; +} + +/* + * Asterisk tells us to read for a channel + */ +struct ast_frame *capi_read(struct ast_channel *c) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); + int readsize = 0; + + if (i == NULL) { + ast_log(LOG_ERROR, "channel has no interface\n"); + return NULL; + } + + if ((i->state == CAPI_STATE_REMOTE_HANGUP)) { + ast_log(LOG_ERROR, "this channel is not connected\n"); + return NULL; + } + + if (i->state == CAPI_STATE_ONHOLD) { + i->fr.frametype = AST_FRAME_NULL; + return &i->fr; + } + + i->fr.frametype = AST_FRAME_NULL; + i->fr.subclass = 0; +#ifdef CC_AST_FRAME_HAS_TIMEVAL + i->fr.delivery.tv_sec = 0; + i->fr.delivery.tv_usec = 0; +#endif + readsize = read(i->fd, &i->fr, sizeof(struct ast_frame)); + if (readsize != sizeof(struct ast_frame)) { + ast_log(LOG_ERROR, "did not read a whole frame\n"); + } + if (i->fr.frametype == AST_FRAME_VOICE) { + readsize = read(i->fd,i->fr.data,i->fr.datalen); + if (readsize != i->fr.datalen) { + ast_log(LOG_ERROR, "did not read whole frame data\n"); + } + } + + i->fr.mallocd = 0; + + if (i->fr.frametype == AST_FRAME_NULL) { + return NULL; + } + if ((i->fr.frametype == AST_FRAME_DTMF) && (i->fr.subclass == 'f')) { + if (strcmp(c->exten, "fax")) { +#ifdef CC_AST_CHANNEL_HAS_CID + if (ast_exists_extension(c, ast_strlen_zero(c->macrocontext) ? c->context : c->macrocontext, "fax", 1, c->cid.cid_num)) { +#else + if (ast_exists_extension(c, ast_strlen_zero(c->macrocontext) ? c->context : c->macrocontext, "fax", 1, c->callerid)) { +#endif + cc_ast_verbose(2, 0, VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", c->name); + /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ + pbx_builtin_setvar_helper(c, "FAXEXTEN", c->exten); + if (ast_async_goto(c, c->context, "fax", 1)) + ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", c->name, c->context); + } else { + ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n"); + } + } else { + ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n"); + } + } + return &i->fr; +} + +/* + * Asterisk tells us to write for a channel + */ +int capi_write(struct ast_channel *c, struct ast_frame *f) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); + _cmsg CMSG; + int j = 0; + char buf[1000]; + struct ast_frame *fsmooth; + int txavg=0; + + if (!i) { + ast_log(LOG_ERROR, "channel has no interface\n"); + return -1; + } + + /* dont send audio to the local exchange! */ + if ((i->earlyB3 == 1) || (!i->NCCI)) { + return 0; + } + + if (f->frametype == AST_FRAME_NULL) { + return 0; + } + if (f->frametype == AST_FRAME_DTMF) { + ast_log(LOG_ERROR, "dtmf frame should be written\n"); + return 0; + } + if (f->frametype != AST_FRAME_VOICE) { + ast_log(LOG_ERROR,"not a voice frame\n"); + return -1; + } + if (f->subclass != capi_capability) { + ast_log(LOG_ERROR, "dont know how to write subclass %d\n", f->subclass); + return -1; + } + /* ast_log(LOG_NOTICE,"writing frame %d %d\n",f->frametype,f->subclass); */ + + if (ast_smoother_feed(i->smoother, f) != 0) { + ast_log(LOG_ERROR, "failed to fill smoother\n"); + return -1; + } + + fsmooth = ast_smoother_read(i->smoother); + while(fsmooth != NULL) { + DATA_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + DATA_B3_REQ_NCCI(&CMSG) = i->NCCI; + DATA_B3_REQ_DATALENGTH(&CMSG) = fsmooth->datalen; + DATA_B3_REQ_FLAGS(&CMSG) = 0; + + if (ast_mutex_lock(&capi_send_buffer_lock)) { + ast_log(LOG_WARNING, "Unable to lock B3 send buffer!\n"); + return -1; + } + + if ((i->doES == 1)) { + for (j = 0; j < fsmooth->datalen; j++) { + buf[j] = reversebits[ ((unsigned char *)fsmooth->data)[j] ]; + txavg += abs( capiXLAW2INT(reversebits[ ((unsigned char*)fsmooth->data)[j]]) ); + } + txavg = txavg / j; + for(j = 0; j < ECHO_TX_COUNT - 1; j++) { + i->txavg[j] = i->txavg[j+1]; + } + i->txavg[ECHO_TX_COUNT - 1] = txavg; + + /* ast_log(LOG_NOTICE,"txavg = %d\n",txavg); */ + } else { + for (j = 0; j < fsmooth->datalen; j++) { + buf[j] = i->g.txgains[reversebits[((unsigned char *)fsmooth->data)[j]]]; + } + } + + DATA_B3_REQ_DATAHANDLE(&CMSG) = capi_send_buffer_handle; + memcpy((char *)&capi_send_buffer[(capi_send_buffer_handle % AST_CAPI_MAX_B3_BLOCKS) * AST_CAPI_MAX_B3_BLOCK_SIZE], + &buf, fsmooth->datalen); + DATA_B3_REQ_DATA(&CMSG) = (unsigned char *)&capi_send_buffer[(capi_send_buffer_handle % AST_CAPI_MAX_B3_BLOCKS) * AST_CAPI_MAX_B3_BLOCK_SIZE]; + capi_send_buffer_handle++; + + if (ast_mutex_unlock(&capi_send_buffer_lock)) { + ast_log(LOG_WARNING,"Unable to unlock B3 send buffer!\n"); + return -1; + } + + +#ifdef CAPI_SYNC + ast_mutex_lock(&i->lockB3in); + if ((i->B3in >= 1) && (i->B3in <= AST_CAPI_MAX_B3_BLOCKS)) { + i->B3in--; + ast_mutex_unlock(&i->lockB3in); + if (_capi_put_cmsg(&CMSG) == 0) { + cc_ast_verbose(7, 1, VERBOSE_PREFIX_4 "sent DATA_B3_REQ (NCCI=%#x) (%d bytes)\n", + i->NCCI, fsmooth->datalen); + } + } else { + if (i->B3in > 0) + i->B3in--; + ast_mutex_unlock(&i->lockB3in); + } +#else + if (_capi_put_cmsg(&CMSG) == 0) { + cc_ast_verbose(7, 1, VERBOSE_PREFIX_4 "sent DATA_B3_REQ (NCCI=%#x) (%d bytes)\n", + i->NCCI, fsmooth->datalen); + } +#endif + + /* ast_frfree(fsmooth); */ + fsmooth = ast_smoother_read(i->smoother); + } + return 0; +} + +/* + * new channel + */ +static int capi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) +{ + struct ast_capi_pvt *p = CC_AST_CHANNEL_PVT(newchan); + + p->owner = newchan; + return 0; +} + +/* + * we don't support own indications + */ +static int capi_indicate(struct ast_channel *c, int condition) +{ + return -1; +} + +/* + * native bridging: connect to channels directly + */ +static int capi_bridge(struct ast_channel *c0, struct ast_channel *c1, + int flags, struct ast_frame **fo, struct ast_channel **rc) +{ + return -1; +} + +/* + * a new channel is needed + */ +static struct ast_channel *capi_new(struct ast_capi_pvt *i, int state) +{ + struct ast_channel *tmp; + int fmt; + int fds[2]; + + tmp = ast_channel_alloc(1); + + if (tmp == NULL) { + ast_log(LOG_ERROR,"Unable to allocate channel!\n"); + return(NULL); + } + + /* ast_log(LOG_NOTICE,"allocated channel for PLCI=%#x!\n", i->PLCI); */ + snprintf(tmp->name, sizeof(tmp->name), "CAPI/contr%d/%s-%d", + i->controller, i->dnid, capi_counter++); + tmp->type = type; + + if (pipe(fds) != 0) { + ast_log(LOG_ERROR, "CAPI: unable to create pipe.\n"); + ast_channel_free(tmp); + return NULL; + } + + cc_ast_verbose(4, 0, VERBOSE_PREFIX_3 "creating pipe for PLCI=%#x\n", + i->PLCI); + + i->fd = fds[0]; + i->fd2 = fds[1]; +#if 0 + flags = fcntl(i->fd,F_GETFL); + fcntl(i->fd,F_SETFL,flags | O_SYNC | O_DIRECT); + flags = fcntl(i->fd2,F_GETFL); + fcntl(i->fd2,F_SETFL,flags | O_SYNC | O_DIRECT); +#endif + + ast_setstate(tmp, state); + tmp->fds[0] = i->fd; + i->smoother = ast_smoother_new(AST_CAPI_MAX_B3_BLOCK_SIZE); + if (i->smoother == NULL) { + ast_log(LOG_ERROR, "smoother NULL!\n"); + } + i->fr.frametype = 0; + i->fr.subclass = 0; +#ifdef CC_AST_FRAME_HAS_TIMEVAL + i->fr.delivery.tv_sec = 0; + i->fr.delivery.tv_usec = 0; +#endif + i->state = CAPI_STATE_DISCONNECTED; + i->CLIR = 0; + i->calledPartyIsISDN = 0; /* let's be pessimistic */ + i->earlyB3 = -1; + i->doB3 = AST_CAPI_B3_DONT; + i->outgoing = 0; + i->onholdPLCI = 0; +#ifdef CAPI_SYNC + i->B3in = 0; + ast_mutex_init(&i->lockB3in); +#endif + memset(i->txavg, 0, ECHO_TX_COUNT); + + if (i->doDTMF == 1) { + i->vad = ast_dsp_new(); + ast_dsp_set_features(i->vad, DSP_FEATURE_DTMF_DETECT); + } + + if (tmp->pvt == NULL) { + free(tmp); + return NULL; + } + + CC_AST_CHANNEL_PVT(tmp) = i; + + tmp->callgroup = i->callgroup; +#ifndef CC_AST_HAVE_TECH_PVT + tmp->pvt->call = capi_call; + tmp->pvt->fixup = capi_fixup; + tmp->pvt->indicate = capi_indicate; + tmp->pvt->bridge = capi_bridge; + tmp->pvt->answer = capi_answer; + tmp->pvt->hangup = capi_hangup; + tmp->pvt->read = capi_read; + tmp->pvt->write = capi_write; + tmp->pvt->send_digit = capi_send_digit; +#endif + tmp->nativeformats = capi_capability; + fmt = ast_best_codec(tmp->nativeformats); + /* fmt = capi_capability; */ + tmp->readformat = fmt; + tmp->writeformat = fmt; +#ifdef CC_AST_HAVE_TECH_PVT + tmp->rawreadformat = fmt; + tmp->rawwriteformat = fmt; +#else + tmp->pvt->rawreadformat = fmt; + tmp->pvt->rawwriteformat = fmt; +#endif + strncpy(tmp->context, i->context, sizeof(tmp->context) - 1); +#ifdef CC_AST_CHANNEL_HAS_CID + tmp->cid.cid_num = strdup(i->cid); + tmp->cid.cid_dnid = strdup(i->dnid); +#else + tmp->callerid = strdup(i->cid); +#endif + strncpy(tmp->exten, i->dnid, sizeof(tmp->exten) - 1); + strncpy(tmp->accountcode, i->accountcode, sizeof(tmp->accountcode) - 1); + i->owner = tmp; + ast_mutex_lock(&usecnt_lock); + usecnt++; + ast_mutex_unlock(&usecnt_lock); + ast_update_use_count(); + if (state != AST_STATE_DOWN) { + /* we are alerting (phones ringing) */ + if (state == AST_STATE_RING) + capi_alert(tmp); + if (ast_pbx_start(tmp)) { + ast_log(LOG_ERROR, "Unable to start pbx on channel!\n"); + ast_hangup(tmp); + tmp = NULL; + } else { + cc_ast_verbose(2, 0, VERBOSE_PREFIX_3 "started pbx on channel (callgroup=%d)!\n", + tmp->callgroup); + } + } + return tmp; +} + +/* + * Asterisk wants us to dial ... + */ +#ifdef CC_AST_HAVE_TECH_PVT +struct ast_channel *capi_request(const char *type, int format, void *data, int *cause) +#else +struct ast_channel *capi_request(char *type, int format, void *data) +#endif +{ + struct ast_capi_pvt *i; + struct ast_channel *tmp = NULL; + char *dest, *interface; + char buffer[AST_MAX_EXTENSION]; + unsigned int capigroup = 0, controller = 0; + unsigned int foundcontroller; + int notfound = 1; + + cc_ast_verbose(1, 1, VERBOSE_PREFIX_3 "data = %s\n", (char *)data); + + strncpy(buffer, (char *)data, sizeof(buffer) - 1); + + interface = strtok(buffer, "/"); + dest = strtok(NULL, "/"); + + if (((char *)interface)[0] == 'g') { + interface++; + capigroup = atoi(interface); + cc_ast_verbose(1, 1, VERBOSE_PREFIX_3 "capi request group = %d\n", + capigroup); + } else if (!strncmp(interface, "contr", 5)) { + interface += 5; + controller = atoi(interface); + cc_ast_verbose(1, 1, VERBOSE_PREFIX_3 "capi request controller = %d\n", + controller); + } else { + ast_log(LOG_ERROR,"Syntax error in dialstring. read the docs!\n"); + return NULL; + } + + ast_mutex_lock(&iflock); + + for (i = iflist; (i && notfound); i = i->next) { + if (i->owner) { + continue; + } + /* unused channel */ + ast_mutex_lock(&contrlock); + if (controller) { + /* DIAL(CAPI/contrX/...) */ + if ((!(i->controllers & (1 << controller))) || + (capi_controllers[controller]->nfreebchannels < 1)) { + /* keep on running! */ + ast_mutex_unlock(&contrlock); + continue; + } + foundcontroller = controller; + } else { + /* DIAL(CAPI/gX/...) */ + if (!(i->group & (1 << capigroup))) { + /* keep on running! */ + ast_mutex_unlock(&contrlock); + continue; + } + for (foundcontroller = 1; foundcontroller <= capi_num_controllers; foundcontroller++) { + if ((i->controllers & (1 << foundcontroller)) && + (capi_controllers[foundcontroller]->nfreebchannels > 0)) { + break; + } + } + if (foundcontroller > capi_num_controllers) { + /* keep on running! */ + ast_mutex_unlock(&contrlock); + continue; + } + } + /* when we come here, we found a free controller match */ + strncpy(i->dnid, dest, sizeof(i->dnid) - 1); + i->controller = foundcontroller; + tmp = capi_new(i, AST_STATE_DOWN); + i->PLCI = 0; + i->datahandle = 0; + i->outgoing = 1; /* this is an outgoing line */ + i->earlyB3 = -1; + ast_mutex_unlock(&contrlock); + ast_mutex_unlock(&iflock); + return tmp; + } + ast_mutex_unlock(&iflock); + ast_log(LOG_NOTICE, "didn't find capi device with controller = %d or group = %d.\n", + controller, capigroup); + return NULL; +} + +/* + * find a pipe in our pipe-list + */ +struct capi_pipe *find_pipe(_cmsg *CMSG) +{ + struct capi_pipe *p; + unsigned int NCCI = CMSG->adr.adrNCCI; + unsigned int PLCI = (NCCI & 0xffff); + int MN = CMSG->Messagenumber; + + /* find a pipe by PLCI or by MessageNumber (in case this is a CONNECT_CONF) */ + + ast_mutex_lock(&pipelock); + + p = pipelist; + while(p != NULL) { + if ((p->PLCI == PLCI) || + ((p->PLCI == 0) && (p->i->MessageNumber == MN))) { + ast_mutex_unlock(&pipelock); + return p; + } + p = p->next; + } + ast_mutex_unlock(&pipelock); + + cc_ast_verbose(5, 1, VERBOSE_PREFIX_3 + "CAPI: unable to find a pipe for PLCI = %#x MN = %#x\n%s\n", + PLCI, MN, capi_cmsg2str(CMSG)); + + return NULL; +} + +/* + * send a frame to Asterisk via pipe + */ +static int pipe_frame(struct capi_pipe *p, struct ast_frame *f) +{ + fd_set wfds; + int written = 0; + struct timeval tv; + + FD_ZERO(&wfds); + FD_SET(p->fd, &wfds); + tv.tv_sec = 0; + tv.tv_usec = 10; + + if ((f->frametype == AST_FRAME_VOICE) && + (p->i->doDTMF == 1) && + (p->i->vad != NULL)) { +#ifdef CC_AST_DSP_PROCESS_NEEDLOCK + f = ast_dsp_process(p->c, p->i->vad, f, 0); +#else + f = ast_dsp_process(p->c, p->i->vad, f); +#endif + if (f->frametype == AST_FRAME_NULL) { + return 0; + } + } + + /* we dont want the monitor thread to block */ + if (select(p->fd + 1, NULL, &wfds, NULL, &tv) == 1) { + written = write(p->fd, f, sizeof(struct ast_frame)); + if (written < (signed int) sizeof(struct ast_frame)) { + ast_log(LOG_ERROR, "wrote %d bytes instead of %d\n", + written, sizeof(struct ast_frame)); + return -1; + } + if (f->frametype == AST_FRAME_VOICE) { + written = write(p->fd,f->data,f->datalen); + if (written < f->datalen) { + ast_log(LOG_ERROR,"wrote %d bytes instead of %d\n", + written, f->datalen); + return -1; + } + } + return 0; + } + return -1; +} + +/* + * see if did matches + */ +static int search_did(struct ast_channel *c) +{ + /* + * Returns + * -1 = Failure + * 0 = Match + * 1 = possible match + */ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); + char *exten; + + if (strlen(i->dnid) < strlen(i->incomingmsn)) + return -1; + + /* exten = i->dnid + strlen(i->incomingmsn); */ + exten = i->dnid; + + if (ast_exists_extension(NULL, c->context, exten, 1, NULL)) { + c->priority = 1; + strncpy(c->exten, exten, sizeof(c->exten) - 1); + return 0; + } + + if (ast_canmatch_extension(NULL, c->context, exten, 1, NULL)) { + return 1; + } + + return -1; +} + +/* + * CAPI INFO_IND + */ +static void capi_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pipe *p) +{ + _cmsg CMSG2; + MESSAGE_EXCHANGE_ERROR error; + struct ast_frame fr; + + memset(&CMSG2,0,sizeof(_cmsg)); + error = INFO_RESP(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, PLCI); + if (error != 0) { + ast_log(LOG_ERROR,"error sending INFO_RESP (error=%#x)\n",error); + return; + } + + cc_ast_verbose(5, 1, VERBOSE_PREFIX_4 "sent INFO_RESP (PLCI=%#x)\n", + PLCI); + + return_on_no_pipe("INFO_IND"); + +#if 0 + if ((INFO_IND_INFONUMBER(CMSG) >> 8) == 0x00) { + ast_log(LOG_ERROR,"%#x\n",INFO_IND_INFOELEMENT(CMSG)[0]); + ast_log(LOG_ERROR,"%#x\n",INFO_IND_INFOELEMENT(CMSG)[1]); + ast_log(LOG_ERROR,"%#x\n",INFO_IND_INFOELEMENT(CMSG)[2]); + ast_log(LOG_ERROR,"%#x\n",INFO_IND_INFOELEMENT(CMSG)[3]); + } +#endif + if ((INFO_IND_INFONUMBER(CMSG) == 0x001e) && + (p->i->doB3 != AST_CAPI_B3_DONT) && + (p->i->earlyB3 == -1) && + (p->i->state != CAPI_STATE_BCONNECTED)) { + /* ETSI 300 102-1 Progress Indicator */ + /* we do early B3 Connect */ + if (INFO_IND_INFOELEMENT(CMSG)[0] >= 2) { + if (INFO_IND_INFOELEMENT(CMSG)[2] & 0x2) { + p->i->calledPartyIsISDN = 0; + /* ast_log(LOG_NOTICE,"A N A L O G \n"); */ + } else { + p->i->calledPartyIsISDN = 1; + /* ast_log(LOG_NOTICE,"I S D N\n"); */ + } + if (INFO_IND_INFOELEMENT(CMSG)[2] & 0x88) { + /* in-band info available */ + p->i->earlyB3 = 1; + memset(&CMSG2, 0, sizeof(_cmsg)); + CONNECT_B3_REQ_HEADER(&CMSG2, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + CONNECT_B3_REQ_PLCI(&CMSG2) = PLCI; + if (_capi_put_cmsg(&CMSG2) != 0) { + return; + } + cc_ast_verbose(1, 1, VERBOSE_PREFIX_4 "sent early CONNECT_B3_REQ (PLCI=%#x)\n", + PLCI); + } + } + return; + } + + /* DISCONNECT */ + if ((INFO_IND_INFONUMBER(CMSG) == 0x8045) && + (PLCI == p->i->onholdPLCI)) { + /* the caller onhold hung up (or ECTed away) */ + /* send a disconnect_req , we cannot hangup the channel here!!! */ + memset(&CMSG2, 0, sizeof(_cmsg)); + DISCONNECT_REQ_HEADER(&CMSG2, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + DISCONNECT_REQ_PLCI(&CMSG2) = p->i->onholdPLCI; + + if (_capi_put_cmsg(&CMSG2) == 0) { + cc_ast_verbose(1, 1, VERBOSE_PREFIX_4 "sent DISCONNECT_REQ for onholdPLCI=%#x\n", + PLCI); + } + return; + } + + /* case 1: B3 on success or no B3 at all */ + if ((INFO_IND_INFONUMBER(CMSG) == 0x8045) && + (p->i->doB3 != AST_CAPI_B3_ALWAYS) && + (p->i->outgoing == 1)) { + p->i->earlyB3 = 0; /* !!! */ + fr.frametype = AST_FRAME_NULL; + fr.datalen = 0; + pipe_frame(p, (struct ast_frame *)&fr); + return; + } + + /* case 2: we are doing B3, and receive the 0x8045 after a successful call */ + if ((INFO_IND_INFONUMBER(CMSG) == 0x8045) && + (p->i->doB3 != AST_CAPI_B3_DONT) && + (p->i->earlyB3 == 0) && + (p->i->outgoing == 1)) { + fr.frametype = AST_FRAME_NULL; + fr.datalen = 0; + pipe_frame(p, (struct ast_frame *)&fr); + return; + } + + /* + * case 3: this channel is an incoming channel! the user hung up! + * it is much better to hangup now instead of waiting for a timeout and + * network caused DISCONNECT_IND! + */ + if ((INFO_IND_INFONUMBER(CMSG) == 0x8045) && + (p->i->outgoing == 0)) { + /* ast_log(LOG_NOTICE,"case 3\n"); */ + fr.frametype = AST_FRAME_NULL; + fr.datalen = 0; + pipe_frame(p, (struct ast_frame *)&fr); + return; + } + + /* case 4 (a.k.a. the italian case): B3 always. call is unsuccessful */ + if ((INFO_IND_INFONUMBER(CMSG) == 0x8045) && + (p->i->doB3 == AST_CAPI_B3_ALWAYS) && + (p->i->earlyB3 == -1) && + (p->i->outgoing == 1)) { + /* wait for the 0x001e (PROGRESS), play audio and wait for a timeout from the network */ + return; + } + + /* Handle DID digits */ + if ((INFO_IND_INFONUMBER(CMSG) == 0x0070) && + (p->i->isdnmode == AST_CAPI_ISDNMODE_PTP) && + (p->c != NULL)) { + char name[AST_CHANNEL_NAME] = ""; + char *did; + + did = capi_number(INFO_IND_INFOELEMENT(CMSG), 1); + if (strcasecmp(p->i->dnid, did)) { + strncat(p->i->dnid, did, sizeof(p->i->dnid) - 1); + } + + snprintf(name, sizeof(name), "CAPI/contr%d/%s/-%d", + p->i->controller, p->i->dnid, capi_counter++); + ast_change_name(p->c, name); + + switch(search_did(p->c)) { + case 0: /* match */ + ast_setstate(p->c, AST_STATE_RING); + /* we are alerting (phones ringing) */ + capi_alert(p->c); /* Do this here after pbx_start the Channel can be destroyed */ + if (ast_pbx_start(p->c)) { + ast_log(LOG_ERROR, "Unable to start pbx on channel!\n"); + ast_hangup(p->c); + } else { + cc_ast_verbose(2, 1, VERBOSE_PREFIX_3 "started pbx on channel!\n"); + } + break; + case 1: + /* would possibly match */ + break; + case -1: + default: + /* doesn't match */ + ast_log(LOG_ERROR, "did not find device for msn = %s\n", + p->i->dnid); + CONNECT_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0); + CONNECT_RESP_PLCI(&CMSG2) = PLCI; + CONNECT_RESP_REJECT(&CMSG2) = 1; /* ignore */ + if (_capi_put_cmsg(&CMSG2) == 0) { + cc_ast_verbose(5, 1, VERBOSE_PREFIX_4 "sent CONNECT_RESP for PLCI = %#x\n", + PLCI); + } + } + return; + } + + if (INFO_IND_INFONUMBER(CMSG) == 0x8001) { + fr.frametype = AST_FRAME_CONTROL; + fr.subclass = AST_CONTROL_RINGING; + pipe_frame(p, (struct ast_frame *)&fr); + return; + } + + if (INFO_IND_INFONUMBER(CMSG) == 0x800d) { + fr.frametype = AST_FRAME_CONTROL; + fr.subclass = AST_CONTROL_PROGRESS; + pipe_frame(p, (struct ast_frame *)&fr); + return; + } + + if (INFO_IND_INFONUMBER(CMSG) == 0x74) { + strncpy(p->i->owner->exten, capi_number(INFO_IND_INFOELEMENT(CMSG), 3), + sizeof(p->i->owner->exten) - 1); + ast_log(LOG_NOTICE,"%s\n", capi_cmsg2str(CMSG)); + } + + if (INFO_IND_INFONUMBER(CMSG) == 0x28) { +#if 0 + struct ast_frame ft = { AST_FRAME_TEXT, capi_number(INFO_IND_INFOELEMENT(CMSG),0), }; + ast_sendtext(p->i->owner,capi_number(INFO_IND_INFOELEMENT(CMSG), 0)); + ast_queue_frame(p->i->owner, &ft); + ast_log(LOG_NOTICE,"%s\n",capi_number(INFO_IND_INFOELEMENT(CMSG),0)); +#endif + } +} + +/* + * CAPI FACILITY_IND + */ +static void capi_handle_facility_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pipe *p) +{ + _cmsg CMSG2; + MESSAGE_EXCHANGE_ERROR error; + struct ast_frame fr; + char dtmf; + unsigned dtmflen; + + error = FACILITY_RESP(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, + PLCI, FACILITY_IND_FACILITYSELECTOR(CMSG), + FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)); + if (error != 0) { + ast_log(LOG_ERROR,"error sending FACILITY_RESP (error=%#x)\n", + error); + } else { + cc_ast_verbose(5, 1, VERBOSE_PREFIX_4 "sent FACILITY_RESP (PLCI=%#x)\n", + PLCI); + } + + return_on_no_pipe("FACILITY_IND"); + + if (FACILITY_IND_FACILITYSELECTOR(CMSG) == 0x0001) { + /* DTMF received */ + if (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0] != (0xff)) { + dtmflen = FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0]; + FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG) += 1; + } else { + dtmflen = ((__u16 *) (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG) + 1))[0]; + FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG) += 3; + } + if (dtmflen == 1) { + dtmf = (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG))[0]; + fr.frametype = AST_FRAME_DTMF; + fr.subclass = dtmf; + cc_ast_verbose(1, 1, VERBOSE_PREFIX_3 "c_dtmf = %c\n", dtmf); + pipe_frame(p, (struct ast_frame *)&fr); + } + } + + if (FACILITY_IND_FACILITYSELECTOR(CMSG) == 0x0003) { + /* supplementary sservices */ +#if 0 + ast_log(LOG_NOTICE,"FACILITY_IND PLCI = %#x\n",PLCI); + ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0]); + ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1]); + ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[2]); + ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3]); + ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4]); + ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5]); +#endif + /* RETRIEVE */ + if ( (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x3) && + (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3] == 0x2) ) { + p->i->state = CAPI_STATE_CONNECTED; + p->i->PLCI = p->i->onholdPLCI; + p->i->onholdPLCI = 0; + } + + /* HOLD */ + if ( (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x2) && + (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3] == 0x2) ) { + if ((FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5] != 0) && + (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4] != 0)) { + /* reason != 0x0000 == problem */ + p->i->onholdPLCI = 0; + p->i->state = CAPI_STATE_ONHOLD; + ast_log(LOG_WARNING, "unable to put PLCI=%#x onhold, REASON = %#x%#x, maybe you need to subscribe for this...\n", + PLCI, FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5], + FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4]); + } else { + /* reason = 0x0000 == call on hold */ + p->i->state = CAPI_STATE_ONHOLD; + if (capidebug) + ast_log(LOG_NOTICE, "PLCI=%#x put onhold\n", PLCI); + } + } + } +} + +/* + * CAPI DATA_B3_IND + */ +static void capi_handle_data_b3_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pipe *p) +{ + _cmsg CMSG2; + struct ast_frame fr; + char b3buf[1024]; + int b3len = 0; + int j; + int rxavg = 0; + int txavg = 0; + + memcpy(&b3buf[AST_FRIENDLY_OFFSET], (char *)DATA_B3_IND_DATA(CMSG), DATA_B3_IND_DATALENGTH(CMSG)); + b3len = DATA_B3_IND_DATALENGTH(CMSG); + + /* send a DATA_B3_RESP very quickly to free the buffer in capi */ + DATA_B3_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0); + DATA_B3_RESP_NCCI(&CMSG2) = NCCI; + DATA_B3_RESP_DATAHANDLE(&CMSG2) = DATA_B3_IND_DATAHANDLE(CMSG); + if (_capi_put_cmsg(&CMSG2) == 0) { + cc_ast_verbose(6, 1, VERBOSE_PREFIX_4 "sent DATA_B3_RESP (NCCI=%#x)\n", + NCCI); + } + + return_on_no_pipe("DATA_B3_IND"); + +#ifdef CAPI_SYNC + ast_mutex_lock(&p->i->lockB3in); + p->i->B3in++; + if (p->i->B3in > AST_CAPI_MAX_B3_BLOCKS) + p->i->B3in = AST_CAPI_MAX_B3_BLOCKS; + ast_mutex_unlock(&p->i->lockB3in); +#endif + + if ((p->i->doES == 1)) { + for (j = 0; j < b3len; j++) { + b3buf[AST_FRIENDLY_OFFSET + j] = reversebits[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]]; + rxavg += abs(capiXLAW2INT( reversebits[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]])); + } + rxavg = rxavg / j; + for(j = 0; j < ECHO_EFFECTIVE_TX_COUNT; j++) { + txavg += p->i->txavg[j]; + } + txavg = txavg / j; + + if ( (txavg / ECHO_TXRX_RATIO) > rxavg) { +#ifdef CAPI_ULAW + memset(&b3buf[AST_FRIENDLY_OFFSET], 255, b3len); +#else + memset(&b3buf[AST_FRIENDLY_OFFSET], 84, b3len); +#endif + if (capidebug) { + ast_log(LOG_NOTICE, "SUPPRESSING ECHO rx=%d, tx=%d\n", + rxavg, txavg); + } + } + } else { + for (j = 0; j < b3len; j++) { + b3buf[AST_FRIENDLY_OFFSET + j] = reversebits[p->i->g.rxgains[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]]]; + } + } + + /* just being paranoid ... */ + /* + if (p->c->_state != AST_STATE_UP) { + ast_setstate(p->c,AST_STATE_UP); + } + */ + + fr.frametype = AST_FRAME_VOICE; + fr.subclass = capi_capability; + fr.data = (char *)&b3buf[AST_FRIENDLY_OFFSET]; + fr.datalen = b3len; + fr.samples = b3len; + fr.offset = AST_FRIENDLY_OFFSET; + fr.mallocd = 0; +#ifdef CC_AST_FRAME_HAS_TIMEVAL + fr.delivery.tv_sec = 0; + fr.delivery.tv_usec = 0; +#endif + fr.src = NULL; + cc_ast_verbose(8, 1, VERBOSE_PREFIX_3 "DATA_B3_IND (len=%d) fr.datalen=%d fr.subclass=%d\n", + (int)DATA_B3_IND_DATALENGTH(CMSG), fr.datalen, fr.subclass); + pipe_frame(p, (struct ast_frame *)&fr); +} + +/* + * CAPI CONNECT_ACTIVE_IND + */ +static void capi_handle_connect_active_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pipe *p) +{ + _cmsg CMSG2; + struct ast_frame fr; + + CONNECT_ACTIVE_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0); + CONNECT_ACTIVE_RESP_PLCI(&CMSG2) = PLCI; + + if (_capi_put_cmsg(&CMSG2) != 0) { + return; + } + + cc_ast_verbose(5, 1, VERBOSE_PREFIX_4 "sent CONNECT_ACTIVE_RESP (PLCI=%#x)\n", + PLCI); + + return_on_no_pipe("CONNECT_ACTIVE_IND"); + + /* normal processing */ + if (p->i->earlyB3 != 1) { + p->i->state = CAPI_STATE_CONNECTED; + + /* send a CONNECT_B3_REQ */ + if (p->i->outgoing == 1) { + /* outgoing call */ + memset(&CMSG2, 0, sizeof(_cmsg)); + CONNECT_B3_REQ_HEADER(&CMSG2, ast_capi_ApplID, get_ast_capi_MessageNumber(),0); + CONNECT_B3_REQ_PLCI(&CMSG2) = PLCI; + if (_capi_put_cmsg(&CMSG2) != 0) { + return; + } + cc_ast_verbose(1, 1, VERBOSE_PREFIX_3 "sent CONNECT_B3_REQ (PLCI=%#x)\n", + PLCI); + } else { + /* incoming call */ + /* RESP already sent ... wait for CONNECT_B3_IND */ + } + } else { + /* special treatment for early B3 connects */ + p->i->state = CAPI_STATE_BCONNECTED; + if (p->c->_state != AST_STATE_UP) { + ast_setstate(p->c,AST_STATE_UP); + } + p->i->earlyB3 = 0; /* not early anymore */ + fr.frametype = AST_FRAME_CONTROL; + fr.subclass = AST_CONTROL_ANSWER; + fr.datalen = 0; + pipe_frame(p,(struct ast_frame *)&fr); + } +} + +/* + * CAPI CONNECT_B3_ACTIVE_IND + */ +static void capi_handle_connect_b3_active_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pipe *p) +{ + _cmsg CMSG2; + struct ast_frame fr; + + /* then send a CONNECT_B3_ACTIVE_RESP */ + CONNECT_B3_ACTIVE_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0); + CONNECT_B3_ACTIVE_RESP_NCCI(&CMSG2) = NCCI; + + if (_capi_put_cmsg(&CMSG2) != 0) { + return; + } + + cc_ast_verbose(5, 1, VERBOSE_PREFIX_4 "sent CONNECT_B3_ACTIVE_RESP (NCCI=%#x)\n", + NCCI); + + return_on_no_pipe("CONNECT_ACTIVE_B3_IND"); + + ast_mutex_lock(&contrlock); + if (p->i->controller > 0) { + capi_controllers[p->i->controller]->nfreebchannels--; + } + ast_mutex_unlock(&contrlock); + + p->i->state = CAPI_STATE_BCONNECTED; + capi_echo_canceller(p->c, EC_FUNCTION_ENABLE); + capi_detect_dtmf(p->c, 1); + + if (p->i->earlyB3 != 1) { + ast_setstate(p->c, AST_STATE_UP); + fr.frametype = AST_FRAME_CONTROL; + fr.subclass = AST_CONTROL_ANSWER; + fr.datalen = 0; + pipe_frame(p, (struct ast_frame *)&fr); + } +} + +/* + * CAPI DISCONNECT_B3_IND + */ +static void capi_handle_disconnect_b3_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pipe *p) +{ + _cmsg CMSG2; + + DISCONNECT_B3_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0); + DISCONNECT_B3_RESP_NCCI(&CMSG2) = NCCI; + + if (_capi_put_cmsg(&CMSG2) == 0) { + cc_ast_verbose(5, 1, VERBOSE_PREFIX_4 "sent DISCONNECT_B3_RESP NCCI=%#x\n", + NCCI); + } + + return_on_no_pipe("DISCONNECT_B3_IND"); + + switch(p->i->state) { + case CAPI_STATE_BCONNECTED: + /* passive disconnect */ + p->i->state = CAPI_STATE_CONNECTED; + break; + case CAPI_STATE_DISCONNECTING: + /* active disconnect */ + memset(&CMSG2, 0, sizeof(_cmsg)); + DISCONNECT_REQ_HEADER(&CMSG2, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + DISCONNECT_REQ_PLCI(&CMSG2) = PLCI; + + if (_capi_put_cmsg(&CMSG2) == 0) { + cc_ast_verbose(5, 1, VERBOSE_PREFIX_4 "sent DISCONNECT_REQ PLCI=%#x\n", + PLCI); + } + break; + case CAPI_STATE_ONHOLD: + /* no hangup */ + break; + } + ast_mutex_lock(&contrlock); + if (p->i->controller > 0) { + capi_controllers[p->i->controller]->nfreebchannels++; + } + ast_mutex_unlock(&contrlock); +} + +/* + * CAPI CONNECT_B3_IND + */ +static void capi_handle_connect_b3_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pipe *p) +{ + _cmsg CMSG2; + + /* then send a CONNECT_B3_RESP */ + memset(&CMSG2, 0, sizeof(_cmsg)); + CONNECT_B3_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0); + CONNECT_B3_RESP_NCCI(&CMSG2) = NCCI; + CONNECT_B3_RESP_REJECT(&CMSG2) = 0; + + if (_capi_put_cmsg(&CMSG2) != 0) { + return; + } + + cc_ast_verbose(5, 1, VERBOSE_PREFIX_4 "sent CONNECT_B3_RESP (NCCI=%#x)\n", + NCCI); + + return_on_no_pipe("CONNECT_B3_IND"); + + p->i->NCCI = NCCI; + + /* + if (p->i->controller > 0) { + capi_controllers[p->i->controller]->nfreebchannels--; + } + */ +} + +/* + * CAPI DISCONNECT_IND + */ +static void capi_handle_disconnect_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pipe *p) +{ + _cmsg CMSG2; + struct ast_frame fr; + + DISCONNECT_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber , 0); + DISCONNECT_RESP_PLCI(&CMSG2) = PLCI; + + /* + if (p->i->controller > 0) { + capi_controllers[p->i->controller]->nfreebchannels++; + } + */ + + if (_capi_put_cmsg(&CMSG2) == 0) { + cc_ast_verbose(5, 1, VERBOSE_PREFIX_4 "sent DISCONNECT_RESP PLCI=%#x\n", + PLCI); + } + + return_on_no_pipe("DISCONNECT_IND"); + + if (p->c) { + p->c->hangupcause = DISCONNECT_IND_REASON(CMSG) - 0x3480; + } + + if (PLCI == p->i->onholdPLCI) { + /* the caller onhold hung up (or ECTed away) */ + p->i->onholdPLCI = 0; + remove_pipe(PLCI); + return; + } + + if (p->i->state == CAPI_STATE_DID) { + if ((p->c) != NULL) { + ast_hangup(p->c); + } else { + ast_log(LOG_WARNING, "unable to hangup channel on DID. Channel is NULL.\n"); + } + return; + } + + p->i->state = CAPI_STATE_DISCONNECTED; + + fr.frametype = AST_FRAME_CONTROL; + if (DISCONNECT_IND_REASON(CMSG) == 0x34a2) { + fr.subclass = AST_CONTROL_BUSY; + } else { + fr.frametype = AST_FRAME_NULL; + } + fr.datalen = 0; + + if (pipe_frame(p, (struct ast_frame *)&fr) == -1) { + /* + * in this case * did not read our hangup control frame + * so we must hangup the channel! + */ + if ( (p->i->state != CAPI_STATE_DISCONNECTED) && (ast_check_hangup(p->c) == 0)) { + cc_ast_verbose(1, 0, VERBOSE_PREFIX_3 "soft hangup by capi\n"); + ast_softhangup(p->c, AST_SOFTHANGUP_DEV); + } else { + /* dont ever hangup while hanging up! */ + /* ast_log(LOG_NOTICE,"no soft hangup by capi\n"); */ + } + } + p->i->PLCI = 0; + p->i->NCCI = 0; + remove_pipe(PLCI); +} + +/* + * CAPI CONNECT_IND + */ +static void capi_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI) +{ + struct ast_capi_pvt *i; + struct capi_pipe *p; + _cmsg CMSG2; + char *DNID; + char *CID; + int NPLAN=0; + int controller = 0; + char *msn; + char buffer[AST_MAX_EXTENSION]; + char *magicmsn = "*\0"; + char *emptyid = "\0"; + char *emptydnid = "s\0"; + int deflect = 0; + + DNID = capi_number(CONNECT_IND_CALLEDPARTYNUMBER(CMSG),1); + if ((DNID && *DNID == 0) || !DNID) { + DNID = emptydnid; + } + + NPLAN = (CONNECT_IND_CALLINGPARTYNUMBER(CMSG)[1] & 0x70); + CID = capi_number(CONNECT_IND_CALLINGPARTYNUMBER(CMSG), 2); + controller = PLCI & 0xff; + + cc_ast_verbose(1, 1, VERBOSE_PREFIX_2 "CONNECT_IND (PLCI=%#x,DID=%s,CID=%s,CIP=%#x,CONTROLLER=%#x)\n", + PLCI, DNID, CID, CONNECT_IND_CIPVALUE(CMSG), controller); + + if ((CONNECT_IND_BCHANNELINFORMATION(CMSG)) && + ((CONNECT_IND_BCHANNELINFORMATION(CMSG)[1] == 0x02) && + (capi_controllers[controller]->isdnmode != AST_CAPI_ISDNMODE_PTP))) { + /* + * this is a call waiting CONNECT_IND with BChannelinformation[1] == 0x02 + * meaning "no B or D channel for this call", since we can't do anything with call waiting now + * just reject it with "user busy" + * however...if we are a p2p BRI then the telco switch will allow us to choose the b channel + * so it will look like a callwaiting connect_ind to us + */ + ast_log(LOG_ERROR, "received a call waiting CONNECT_IND\n"); + deflect = 1; + } + + /* well...somebody is calling us. let's set up a channel */ + ast_mutex_lock(&iflock); + for (i = iflist; i; i = i->next) { + if ((i->owner) || (i->incomingmsn == NULL)) { + /* has already owner */ + continue; + } + if (!(i->controllers & (1 << controller))) { + continue; + } + strncpy(buffer, i->incomingmsn, sizeof(buffer) - 1); + for (msn = strtok(buffer, ","); msn; msn = strtok(buffer, ",")) { + if (!DNID) { + /* if no DNID, only accept if '*' was specified */ + if (strncasecmp(msn, magicmsn, strlen(msn))) { + continue; + } + strncpy(i->dnid, emptydnid, sizeof(i->dnid) - 1); + } else { + /* make sure the number match exactly or may match on ptp mode */ + if ((strcasecmp(msn, DNID)) && + ((i->isdnmode == AST_CAPI_ISDNMODE_PTMP) || + (strlen(msn) >= strlen(DNID)) || + (strncasecmp(msn, DNID, strlen(msn)))) && + (strncasecmp(msn, magicmsn, strlen(msn)))) { + continue; + } + strncpy(i->dnid,DNID,sizeof(i->dnid)-1); + } + if (CID != NULL) { + if (NPLAN == CAPI_ETSI_NPLAN_NATIONAL) + snprintf(i->cid, (sizeof(i->cid)-1), "%s%s%s", + i->prefix, capi_national_prefix, CID); + else if (NPLAN == CAPI_ETSI_NPLAN_INTERNAT) + snprintf(i->cid, (sizeof(i->cid)-1), "%s%s%s", + i->prefix, capi_international_prefix, CID); + else + snprintf(i->cid, (sizeof(i->cid)-1), "%s%s", + i->prefix, CID); + } else + strncpy(i->cid, emptyid, sizeof(i->cid) - 1); + + i->controller = controller; + i->PLCI = PLCI; + i->MessageNumber = CMSG->Messagenumber; + + p = malloc(sizeof(struct capi_pipe)); + if (!p) { + ast_log(LOG_ERROR, "couldn't alloc capi_pipe\n"); + i = NULL; + break; + } + memset(p, 0, sizeof(struct capi_pipe)); + p->PLCI = PLCI; + p->i = i; + + ast_pthread_mutex_init(&(p->lock),NULL); + i->mypipe = p; + + if (i->isdnmode == AST_CAPI_ISDNMODE_PTP) { + p->c = capi_new(i,AST_STATE_DOWN); + i->state = CAPI_STATE_DID; + } else { + p->c = capi_new(i,AST_STATE_RING); + } + p->fd = i->fd2; + + ast_mutex_lock(&pipelock); + p->next = pipelist; + pipelist = p; + ast_mutex_unlock(&pipelock); + + ast_mutex_unlock(&iflock); + + if (deflect == 1) { + if (i->deflect2) { + capi_deflect(p->c, i->deflect2); + } else + break; + } + return; + } + } + ast_mutex_unlock(&iflock); + + /* obviously we are not called...so tell capi to ignore this call */ + + if (capidebug) { + ast_log(LOG_ERROR, "did not find device for msn = %s\n", DNID); + } + + CONNECT_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0); + CONNECT_RESP_PLCI(&CMSG2) = CONNECT_IND_PLCI(CMSG); + CONNECT_RESP_REJECT(&CMSG2) = (deflect == 1) ? 3 : 1; /* busy : ignore */ + if (_capi_put_cmsg(&CMSG2) == 0) { + cc_ast_verbose(5, 1, VERBOSE_PREFIX_4 "sent CONNECT_RESP for PLCI = %#x\n", + PLCI); + } +} + +/* + * CAPI *_IND + */ +static void capi_handle_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI) +{ + struct capi_pipe *p; + + if (CMSG->Command == CAPI_CONNECT) { /* only connect_ind are global (not channel specific) */ + capi_handle_connect_indication(CMSG, PLCI, NCCI); + return; + } + + p = find_pipe(CMSG); + + switch (CMSG->Command) { + case CAPI_DATA_B3: + capi_handle_data_b3_indication(CMSG, PLCI, NCCI, p); + break; + case CAPI_CONNECT_B3: + capi_handle_connect_b3_indication(CMSG, PLCI, NCCI, p); + break; + case CAPI_CONNECT_B3_ACTIVE: + capi_handle_connect_b3_active_indication(CMSG, PLCI, NCCI, p); + break; + case CAPI_DISCONNECT_B3: + capi_handle_disconnect_b3_indication(CMSG, PLCI, NCCI, p); + break; + case CAPI_DISCONNECT: + capi_handle_disconnect_indication(CMSG, PLCI, NCCI, p); + break; + case CAPI_FACILITY: + capi_handle_facility_indication(CMSG, PLCI, NCCI, p); + break; + case CAPI_INFO: + capi_handle_info_indication(CMSG, PLCI, NCCI, p); + break; + case CAPI_CONNECT_ACTIVE: + capi_handle_connect_active_indication(CMSG, PLCI, NCCI, p); + break; + default: + ast_log(LOG_ERROR, "Command.Subcommand = %#x.%#x\n", + CMSG->Command, CMSG->Subcommand); + } +} + +/* + * CAPI FACILITY_IND + */ +static void capi_handle_facility_confirmation(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pipe *p) +{ + switch (FACILITY_CONF_FACILITYSELECTOR(CMSG)) { + case FACILITYSELECTOR_DTMF: + cc_ast_verbose(2, 1, VERBOSE_PREFIX_3 "DTMF conf(PLCI=%#x)\n", + PLCI); + break; + case FACILITYSELECTOR_ECHO_CANCEL: + if (FACILITY_CONF_INFO(CMSG)) { + cc_ast_verbose(2, 0, VERBOSE_PREFIX_3 "Error setting up echo canceller (PLCI=%#x, Info=%#04x)\n", + PLCI, FACILITY_CONF_INFO(CMSG)); + break; + } + cc_ast_verbose(2, 0, VERBOSE_PREFIX_3 "Echo canceller successfully set up (PLCI=%#x)\n", + PLCI); + break; + + case FACILITYSELECTOR_SUPPLEMENTARY: + /* HOLD */ + if ((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[1] == 0x2) && + (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[2] == 0x0) && + ((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[4] != 0x0) || + (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[5] != 0x0))) { + if (p) { + p->i->state = CAPI_STATE_BCONNECTED; + } + } + break; + default: + ast_log(LOG_ERROR, "CAPI: unhandled FACILITY_CONF 0x%x\n", + FACILITY_CONF_FACILITYSELECTOR(CMSG)); + } +} + +/* + * CAPI *_CONF + */ +static void capi_handle_confirmation(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI) +{ + struct capi_pipe *p; + + p = find_pipe(CMSG); + + switch (CMSG->Command) { + case CAPI_FACILITY: + capi_handle_facility_confirmation(CMSG, PLCI, NCCI, p); + break; + case CAPI_CONNECT: + cc_ast_verbose(1, 1, VERBOSE_PREFIX_2 "received CONNECT_CONF PLCI = %#x INFO = %#x\n", + PLCI, CONNECT_CONF_INFO(CMSG)); + if (!p) + break; + if (CONNECT_CONF_INFO(CMSG) == 0) { + p->i->PLCI = PLCI; + p->PLCI = PLCI; + ast_setstate(p->c, AST_STATE_DIALING); + } else { + /* here, something has to be done --> */ + struct ast_frame fr; + fr.frametype = AST_FRAME_CONTROL; + fr.subclass = AST_CONTROL_BUSY; + fr.datalen = 0; + pipe_frame(p, (struct ast_frame *)&fr); + } + break; + case CAPI_CONNECT_B3: + if (!p) + break; + if (CONNECT_B3_CONF_INFO(CMSG) == 0) { + p->i->NCCI = NCCI; + } else { + p->i->earlyB3 = -1; + p->i->doB3 = AST_CAPI_B3_DONT; + } + break; + case CAPI_ALERT: + if (!p) + break; + p->i->state = CAPI_STATE_ALERTING; + if (p->c->_state == AST_STATE_RING) { + p->c->rings = 1; + } + break; + case CAPI_DISCONNECT: + case CAPI_DISCONNECT_B3: + case CAPI_INFO: + case CAPI_DATA_B3: + /* we do nothing here */ + break; + default: + ast_log(LOG_ERROR,"CAPI: Command.Subcommand = %#x.%#x\n", + CMSG->Command, CMSG->Subcommand); + } +} + +/* + * handle CAPI msg + */ +static void capi_handle_msg(_cmsg *CMSG) +{ + unsigned int NCCI = CMSG->adr.adrNCCI; + unsigned int PLCI = (NCCI & 0xffff); + + if ((CMSG->Subcommand != CAPI_IND) && + (CMSG->Subcommand != CAPI_CONF)) { + ast_log(LOG_ERROR, "CAPI: unknown Command.Subcommand = %#x.%#x\n", + CMSG->Command, CMSG->Subcommand); + return; + } + + if (CMSG->Command == CAPI_DATA_B3) { + cc_ast_verbose(6, 1, VERBOSE_PREFIX_3 "%s\n", capi_cmsg2str(CMSG)); + } else { + cc_ast_verbose(3, 1, VERBOSE_PREFIX_3 "%s\n", capi_cmsg2str(CMSG)); + } + + switch (CMSG->Subcommand) { + case CAPI_IND: + capi_handle_indication(CMSG, PLCI, NCCI); + break; + case CAPI_CONF: + capi_handle_confirmation(CMSG, PLCI, NCCI); + break; + } +} + + +/* + * module stuff, monitor... + */ + +static void *do_monitor(void *data) +{ + unsigned int Info; + _cmsg monCMSG; + + for (/* for ever */;;) { +#if 0 + if (ast_mutex_lock(&monlock)) { + ast_log(LOG_ERROR, "Unable to get monitor lock!\n"); + return NULL; + } + /* do some nifty stuff */ + + ast_mutex_unlock(&monlock); +#endif + + memset(&monCMSG, 0, sizeof(_cmsg)); + + switch(Info = check_wait_get_cmsg(&monCMSG)) { + case 0x0000: + cc_ast_verbose(8, 1, VERBOSE_PREFIX_3 "%s\n", + capi_cmsg2str(&monCMSG)); + capi_handle_msg(&monCMSG); + break; + case 0x1104: + /* CAPI queue is empty */ + break; + default: + /* something is wrong! */ + break; + } /* switch */ + } /* for */ + + /* never reached */ + return NULL; +} + +/* + * start monitor thread + */ +static int restart_monitor(void) +{ + /* stay stopped if wanted */ + if (ast_mutex_lock(&monlock)) { + ast_log(LOG_WARNING, "Unable to get monitor lock!\n"); + return -1; + } + + if (monitor_thread == pthread_self()) { + ast_mutex_unlock(&monlock); + ast_log(LOG_WARNING, "Unable to kill myself!\n"); + return -1; + } + + /* restart */ + if (ast_pthread_create(&monitor_thread, NULL, do_monitor, NULL) < 0) { + ast_mutex_unlock(&monlock); + ast_log(LOG_ERROR, "Unable to start monitor thread!\n"); + return -1; + } + + return 0; +} + +/* + * GAIN + */ +static void capi_gains(struct ast_capi_gains *g, float rxgain, float txgain) +{ + int i=0; + int x=0; + + if (rxgain != 1.0) { + for (i = 0; i < 256; i++) { + x = (int)(((float)capiXLAW2INT(i)) * rxgain); + if (x > 32767) + x = 32767; + if (x < -32767) + x = -32767; + g->rxgains[i] = capiINT2XLAW(x); + } + } else { + for (i = 0; i < 256; i++) { + g->rxgains[i] = i; + } + } + + if (txgain != 1.0) { + for (i = 0; i < 256; i++) { + x = (int)(((float)capiXLAW2INT(i)) * txgain); + if (x > 32767) + x = 32767; + if (x < -32767) + x = -32767; + g->txgains[i] = capiINT2XLAW(x); + } + } else { + for (i = 0; i < 256; i++) { + g->txgains[i] = i; + } + } +} + +/* + * create new interface + */ +int mkif(char *incomingmsn, char *context, char *controllerstr, int devices, + int softdtmf, int echocancel, int ecoption, int ectail, char *prefix, + int isdnmode, int es, float rxgain, float txgain, char *deflect2, + char *accountcode, unsigned int callgroup, unsigned int group) +{ + struct ast_capi_pvt *tmp; + int i = 0; + char buffer[100]; + char *contr; + unsigned long contrmap = 0; + + for (i = 0; i < devices; i++) { + tmp = malloc(sizeof(struct ast_capi_pvt)); + if (!tmp) { + return -1; + } + memset(tmp, 0, sizeof(struct ast_capi_pvt)); + + ast_pthread_mutex_init(&(tmp->lock),NULL); + + strncpy(tmp->context, context, sizeof(tmp->context) - 1); + strncpy(tmp->incomingmsn, incomingmsn, sizeof(tmp->incomingmsn)-1); + strncpy(tmp->prefix, prefix, sizeof(tmp->prefix)-1); + strncpy(tmp->accountcode, accountcode, sizeof(tmp->accountcode)-1); + + strncpy(buffer, controllerstr, sizeof(buffer) - 1); + contr = strtok(buffer, ","); + while (contr != NULL) { + contrmap |= (1 << atoi(contr)); + if (capi_controllers[atoi(contr)]) { + capi_controllers[atoi(contr)]->isdnmode = isdnmode; + /* ast_log(LOG_NOTICE, "contr %d isdnmode %d\n", + atoi(contr), isdnmode); */ + } + contr = strtok(NULL,","); + } + + tmp->controllers = contrmap; + capi_used_controllers |= contrmap; + tmp->controller = 0; + tmp->CLIR = 0; + tmp->earlyB3 = -1; + tmp->onholdPLCI = 0; + tmp->doEC = echocancel; + tmp->ecOption = ecoption; + tmp->ecTail = ectail; + tmp->isdnmode = isdnmode; + tmp->doES = es; + tmp->callgroup = callgroup; + tmp->group = group; + + tmp->rxgain = rxgain; + tmp->txgain = txgain; + capi_gains(&tmp->g, rxgain, txgain); + + strncpy(tmp->deflect2, deflect2, sizeof(tmp->deflect2) - 1); + + if (softdtmf == 1) { + tmp->doDTMF = 1; + } else { + tmp->doDTMF = 0; + } + + tmp->next = iflist; /* prepend */ + iflist = tmp; + /* + ast_log(LOG_NOTICE, "ast_capi_pvt(%s,%s,%#x,%d) (%d,%d,%d) (%d)(%f/%f) %d\n", + tmp->incomingmsn, tmp->context, (int)tmp->controllers, devices, + tmp->doEC, tmp->ecOption, tmp->ecTail, tmp->doES, tmp->rxgain, + tmp->txgain, callgroup); + */ + cc_ast_verbose(2, 0, VERBOSE_PREFIX_2 "ast_capi_pvt(%s,%s,%d,%d) (%d,%d,%d)\n", + tmp->incomingmsn, tmp->context, tmp->controller, devices, tmp->doEC, + tmp->ecOption, tmp->ecTail); + } + return 0; +} + +/* + * eval supported services + */ +static void supported_sservices(struct ast_capi_controller *cp) +{ + MESSAGE_EXCHANGE_ERROR error; + _cmsg CMSG, CMSG2; + struct timeval tv; + char fac[20]; + + memset(fac, 0, sizeof(fac)); + FACILITY_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); + FACILITY_REQ_CONTROLLER(&CMSG) = cp->controller; + FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 0x0003; /* sservices */ + fac[0] = 3; + FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (char *)&fac; + + if ((error= _capi_put_cmsg(&CMSG)) != 0) { + ast_log(LOG_ERROR,"error sending FACILITY_REQ (error=%#x)\n", + error); + } else { + cc_ast_verbose(5, 0, VERBOSE_PREFIX_4 "sent FACILITY_REQ (CONTROLLER=%#x)\n", + cp->controller); + } + + tv.tv_sec = 1; + tv.tv_usec = 0; + + for (/* for ever */;;) { + error = capi20_waitformessage(ast_capi_ApplID, &tv); + error = capi_get_cmsg(&CMSG2, ast_capi_ApplID); + if (error == 0) { + if (IS_FACILITY_CONF(&CMSG2)) { + cc_ast_verbose(5, 0, VERBOSE_PREFIX_4 "FACILITY_CONF INFO = %#x\n", + FACILITY_CONF_INFO(&CMSG2)); + break; + } + } + } + + /* preset all zero */ + cp->holdretrieve = 0; + cp->terminalportability = 0; + cp->ECT = 0; + cp->threePTY = 0; + cp->CF = 0; + cp->CD = 0; + cp->MCID = 0; + cp->CCBS = 0; + cp->MWI = 0; + cp->CCNR = 0; + cp->CONF = 0; + + /* parse supported sservices */ + if (FACILITY_CONF_FACILITYSELECTOR(&CMSG2) != 0x0003) { + ast_log(LOG_NOTICE, "unexpected FACILITY_SELECTOR = %#x\n", + FACILITY_CONF_FACILITYSELECTOR(&CMSG2)); + return; + } + + if (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[4] != 0) { + ast_log(LOG_NOTICE, "supplementary services info = %#x\n", + (short)FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[1]); + return; + } + + /* success, so set the features we have */ + if ((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 1) == 1) { + cp->holdretrieve = 1; + cc_ast_verbose(3, 0, VERBOSE_PREFIX_4 "HOLD/RETRIEVE\n"); + } + if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 2) >> 1) == 1) { + cp->terminalportability = 1; + cc_ast_verbose(3, 0, VERBOSE_PREFIX_4 "TERMINAL PORTABILITY\n"); + } + if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 4) >> 2) == 1) { + cp->ECT = 1; + cc_ast_verbose(3, 0, VERBOSE_PREFIX_4 "ECT\n"); + } + if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 8) >> 3) == 1) { + cp->threePTY = 1; + cc_ast_verbose(3, 0, VERBOSE_PREFIX_4 "3PTY\n"); + } + if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 16) >> 4) == 1) { + cp->CF = 1; + cc_ast_verbose(3, 0, VERBOSE_PREFIX_4 "CF\n"); + } + if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 32) >> 5) == 1) { + cp->CD = 1; + cc_ast_verbose(3, 0, VERBOSE_PREFIX_4 "CD\n"); + } + if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 64) >> 6) == 1) { + cp->MCID = 1; + cc_ast_verbose(3, 0, VERBOSE_PREFIX_4 "MCID\n"); + } + if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 128) >> 7) == 1) { + cp->CCBS = 1; + cc_ast_verbose(3, 0, VERBOSE_PREFIX_4 "CCBS\n"); + } + if ((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[7] & 1) == 1) { + cp->MWI = 1; + cc_ast_verbose(3, 0, VERBOSE_PREFIX_4 "MWI\n"); + } + if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[7] & 2) >> 1) == 1) { + cp->CCNR = 1; + cc_ast_verbose(3, 0, VERBOSE_PREFIX_4 "CCNR\n"); + } + if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[7] & 4) >> 2) == 1) { + cp->CONF = 1; + cc_ast_verbose(3, 0, VERBOSE_PREFIX_4 "CONF\n"); + } +} + +/* + * do command capi info + */ +static int capi_info(int fd, int argc, char *argv[]) +{ + int i=0; + + if (argc != 2) + return RESULT_SHOWUSAGE; + + for (i = 1; i <= capi_num_controllers; i++) { + ast_mutex_lock(&contrlock); + if (capi_controllers[i] != NULL) { + ast_cli(fd, "Contr%d: %d B channels total, %d B channels free.\n", + i, capi_controllers[i]->nbchannels, capi_controllers[i]->nfreebchannels); + } + ast_mutex_unlock(&contrlock); + } + return RESULT_SUCCESS; +} + +/* + * enable debugging + */ +static int capi_do_debug(int fd, int argc, char *argv[]) +{ + if (argc != 2) + return RESULT_SHOWUSAGE; + + capidebug = 1; + ast_cli(fd, "CAPI Debugging Enabled\n"); + + return RESULT_SUCCESS; +} + +/* + * disable debugging + */ +static int capi_no_debug(int fd, int argc, char *argv[]) +{ + if (argc != 3) + return RESULT_SHOWUSAGE; + capidebug = 0; + ast_cli(fd, "CAPI Debugging Disabled\n"); + + return RESULT_SUCCESS; +} + +/* + * usages + */ +static char info_usage[] = +"Usage: capi info\n" +" Show info about B channels.\n"; + +static char debug_usage[] = +"Usage: capi debug\n" +" Enables dumping of CAPI packets for debugging purposes\n"; + +static char no_debug_usage[] = +"Usage: capi no debug\n" +" Disables dumping of CAPI packets for debugging purposes\n"; + +/* + * define commands + */ +static struct ast_cli_entry cli_info = + { { "capi", "info", NULL }, capi_info, "Show CAPI info", info_usage }; +static struct ast_cli_entry cli_debug = + { { "capi", "debug", NULL }, capi_do_debug, "Enable CAPI debugging", debug_usage }; +static struct ast_cli_entry cli_no_debug = + { { "capi", "no", "debug", NULL }, capi_no_debug, "Disable CAPI debugging", no_debug_usage }; + +/* + * calling pres + */ +static char *synopsis_callingpres = "Change the presentation for the callerid"; +static char *descrip_callingpres = "Callingpres(number): Changes the presentation for the callerid. Should be called before placing an outgoing call\n"; +static char *app_callingpres = "CallingPres"; + +static int change_callingpres(struct ast_channel *chan, void *data) +{ + int mode = 0; + + if (data) { + mode = atoi((char *)data); +#ifdef CC_AST_CHANNEL_HAS_CID + chan->cid.cid_pres = mode; +#else + chan->callingpres = mode; +#endif + } else { + ast_log(LOG_NOTICE, "Application %s requres an argument: %s(number)\n", + app_callingpres, app_callingpres); + } + return 0; +} + +#ifdef CC_AST_HAVE_TECH_PVT +static const struct ast_channel_tech capi_tech = { + .type = type, + .description = tdesc, +#ifdef CAPI_ULAW + .capabilities = AST_FORMAT_ULAW, +#else + .capabilities = AST_FORMAT_ALAW, +#endif + .requester = capi_request, + .send_digit = capi_send_digit, + .send_text = NULL, + .call = capi_call, + .hangup = capi_hangup, + .answer = capi_answer, + .read = capi_read, + .write = capi_write, + .bridge = capi_bridge, + .exception = NULL, + .indicate = capi_indicate, + .fixup = capi_fixup, + .setoption = NULL, +}; +#endif + +/* + * main: load the module + */ +int load_module(void) +{ + struct ast_config *cfg; + struct ast_variable *v; + char *config = "capi.conf"; + char incomingmsn[AST_MAX_EXTENSION] = ""; + char context[AST_MAX_EXTENSION] = ""; + char prefix[AST_MAX_EXTENSION] = ""; + char accountcode[20] = ""; + char *empty = "\0"; + char deflect2[AST_MAX_EXTENSION] = ""; + char controllerstr[AST_MAX_EXTENSION] = ""; + int res = 0; + int controller = 0; + int softdtmf = 0; + int echocancel = 1; + int ecoption = EC_OPTION_DISABLE_G165; + int ectail = EC_DEFAULT_TAIL; + int es = 0; + float rxgain = 1.0; + float txgain = 1.0; + int isdnmode = 0; + unsigned int callgroup = 0; + unsigned int group = 0; + struct ast_capi_controller *cp; + + cfg = ast_load(config); + + /* We *must* have a config file otherwise stop immediately, well no */ + if (!cfg) { + ast_log(LOG_ERROR, "Unable to load config %s, CAPI disabled\n", config); + return 0; + } + if (ast_mutex_lock(&iflock)) { + ast_log(LOG_ERROR, "Unable to lock interface list???\n"); + return -1; + } + + strncpy(capi_national_prefix, AST_CAPI_NATIONAL_PREF, sizeof(capi_national_prefix)-1); + strncpy(capi_international_prefix, AST_CAPI_NATIONAL_PREF, sizeof(capi_national_prefix)-1); + v = ast_variable_browse(cfg, "general"); + while(v) { + if (!strcasecmp(v->name, "nationalprefix")) { + strncpy(capi_national_prefix, v->value, sizeof(capi_national_prefix)-1); + } else if (!strcasecmp(v->name, "internationalprefix")) { + strncpy(capi_international_prefix, v->value, sizeof(capi_international_prefix)-1); + } else if (!strcasecmp(v->name, "rxgain")) { + if (sscanf(v->value,"%f",&rxgain) != 1) { + ast_log(LOG_ERROR,"invalid rxgain\n"); + } + } else if (!strcasecmp(v->name, "txgain")) { + if (sscanf(v->value,"%f",&txgain) != 1) { + ast_log(LOG_ERROR,"invalid txgain\n"); + } + } + v = v->next; + } + + if (capi20_isinstalled() != 0) { + ast_mutex_unlock(&iflock); + ast_log(LOG_WARNING, "CAPI not installed, CAPI disabled!\n"); + return 0; + } + + if (capi20_register(AST_CAPI_BCHANS,AST_CAPI_MAX_B3_BLOCKS, + AST_CAPI_MAX_B3_BLOCK_SIZE, &ast_capi_ApplID) != 0) { + ast_mutex_unlock(&iflock); + ast_log(LOG_NOTICE,"unable to register application at CAPI!\n"); + return -1; + } + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) + if (capi20_get_profile(0, &profile) != 0) { +#else + if (capi20_get_profile(0, (char *)&profile) != 0) { +#endif + ast_mutex_unlock(&iflock); + ast_log(LOG_NOTICE,"unable to get CAPI profile!\n"); + return -1; + } + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) + capi_num_controllers = profile.wCtlr; +#else + capi_num_controllers = profile.ncontrollers; +#endif + + cc_ast_verbose(3, 0, VERBOSE_PREFIX_3 "This box has %d capi controller(s).\n", + capi_num_controllers); + + for (controller = 1 ;controller <= capi_num_controllers; controller++) { + + memset(&profile, 0, sizeof(profile)); +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) + capi20_get_profile(controller, &profile); +#else + capi20_get_profile(controller, (char *)&profile); +#endif + cp = malloc(sizeof(struct ast_capi_controller)); + if (!cp) { + ast_mutex_unlock(&iflock); + ast_log(LOG_ERROR, "Error allocating memory for struct capi_controller\n"); + return -1; + } + memset(cp, 0, sizeof(struct ast_capi_controller)); + cp->controller = controller; +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) + cp->nbchannels = profile.wNumBChannels; + cp->nfreebchannels = profile.wNumBChannels; + if (profile.dwGlobalOptions & CAPI_PROFILE_DTMF_SUPPORT) { +#else + cp->nbchannels = profile.nbchannels; + cp->nfreebchannels = profile.nbchannels; + if ((profile.globaloptions & 8) >> 3 == 1) { +#endif + cc_ast_verbose(3, 0, VERBOSE_PREFIX_3 "CAPI/contr%d supports DTMF\n", + controller); + cp->dtmf = 1; + } + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) + if (profile.dwGlobalOptions & CAPI_PROFILE_ECHO_CANCELLATION) { +#else + if (profile.globaloptions2 & 1) { +#endif + cc_ast_verbose(3, 0, VERBOSE_PREFIX_3 "CAPI/contr%d supports echo cancellation\n", + controller); + cp->echocancel = 1; + } + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) + if (profile.dwGlobalOptions & CAPI_PROFILE_SUPPLEMENTARY_SERVICES) { +#else + if ((profile.globaloptions & 16) >> 4 == 1) { +#endif + cp->sservices = 1; + } + + if (cp->sservices == 1) { + cc_ast_verbose(3, 0, VERBOSE_PREFIX_3 "CAPI/contr%d supports supplementary services\n", + controller); + supported_sservices(cp); + } + + capi_controllers[controller] = cp; + } + + v = ast_variable_browse(cfg, "interfaces"); + while(v) { + /* Create the interface list */ + if (!strcasecmp(v->name, "devices")) { + if (mkif(incomingmsn, context, controllerstr, atoi(v->value), + softdtmf, echocancel, ecoption, ectail, prefix, isdnmode, + es, rxgain, txgain, deflect2, accountcode, callgroup, group)) { + ast_mutex_unlock(&iflock); + ast_log(LOG_ERROR,"Error creating interface list\n"); + return -1; + } + es = 0; + strncpy(deflect2, empty, sizeof(deflect2)-1); + } else if (!strcasecmp(v->name, "context")) { + strncpy(context, v->value, sizeof(context)-1); + } else if (!strcasecmp(v->name, "incomingmsn")) { + strncpy(incomingmsn, v->value, sizeof(incomingmsn)-1); + } else if (!strcasecmp(v->name, "controller")) { + strncpy(controllerstr, v->value, sizeof(controllerstr)-1); + } else if (!strcasecmp(v->name, "softdtmf")) { + softdtmf = atoi(v->value); + } else if (!strcasecmp(v->name, "echosquelch")) { + es = atoi(v->value); + } else if (!strcasecmp(v->name, "callgroup")) { + callgroup = ast_get_group(v->value); + } else if (!strcasecmp(v->name, "group")) { + group = ast_get_group(v->value); + } else if (!strcasecmp(v->name, "deflect")) { + strncpy(deflect2, v->value, sizeof(deflect2)-1); + } else if (!strcasecmp(v->name, "rxgain")) { + if (sscanf(v->value,"%f",&rxgain) != 1) { + ast_log(LOG_ERROR,"invalid rxgain\n"); + } + } else if (!strcasecmp(v->name, "txgain")) { + if (sscanf(v->value,"%f",&txgain) != 1) { + ast_log(LOG_ERROR,"invalid txgain\n"); + } + } else if (!strcasecmp(v->name, "echocancel")) { + if (!strcasecmp(v->value, "yes") || !strcasecmp(v->value, "1") || !strcasecmp(v->value, "on")) { + echocancel=1; + ecoption=EC_OPTION_DISABLE_G165; + } + else if (!strcasecmp(v->value, "no") || !strcasecmp(v->value, "0") || !strcasecmp(v->value, "off")) { + echocancel=0; + ecoption=0; + } + else if (!strcasecmp(v->value, "g165") || !strcasecmp(v->value, "g.165")) { + echocancel=1; + ecoption=EC_OPTION_DISABLE_G165; + } + else if (!strcasecmp(v->value, "g164") || !strcasecmp(v->value, "g.164")) { + echocancel=1; + ecoption=EC_OPTION_DISABLE_G164_OR_G165; + } + else if (!strcasecmp(v->value, "force")) { + echocancel=1; + ecoption=EC_OPTION_DISABLE_NEVER; + } + else { + ast_log(LOG_ERROR,"Unknown echocancel parameter \"%s\" -- ignoring\n",v->value); + } + } else if (!strcasecmp(v->name, "echotail")) { + ectail = atoi(v->value); + if (ectail > 255) + ectail = 255; + } else if (!strcasecmp(v->name, "prefix")) { + strncpy(prefix, v->value, sizeof(prefix)-1); + } else if (!strcasecmp(v->name, "accountcode")) { + strncpy(accountcode, v->value, sizeof(accountcode)-1); + } else if (!strcasecmp(v->name, "isdnmode")) { + if (!strcasecmp(v->value, "ptp") || !strcasecmp(v->value, "1")) + isdnmode = AST_CAPI_ISDNMODE_PTP; + else if (!strcasecmp(v->value, "ptm") || + !strcasecmp(v->value, "0") || + !strcasecmp(v->value, "ptmp")) + isdnmode = AST_CAPI_ISDNMODE_PTMP; + else + ast_log(LOG_ERROR,"Unknown isdnmode parameter \"%s\" -- ignoring\n", + v->value); + + } + v = v->next; + } + ast_destroy(cfg); + + for (controller = 1; controller <= capi_num_controllers; controller++) { + if (capi_used_controllers & (1 << controller)) { + if (ListenOnController(ALL_SERVICES, controller) != 0) { + ast_log(LOG_ERROR,"Unable to listen on contr%d\n", controller); + } else { + cc_ast_verbose(2, 0, VERBOSE_PREFIX_3 "listening on contr%d CIPmask = %#x\n", + controller, ALL_SERVICES); + } + } else { + ast_log(LOG_WARNING,"Unused contr%d\n",controller); + } + } + + ast_mutex_unlock(&iflock); + +#ifdef CC_AST_HAVE_TECH_PVT + if (ast_channel_register(&capi_tech)) { +#else + if (ast_channel_register(type, tdesc, capi_capability, capi_request)) { +#endif + ast_log(LOG_ERROR, "Unable to register channel class %s\n", type); + unload_module(); + return -1; + } + + ast_cli_register(&cli_info); + ast_cli_register(&cli_debug); + ast_cli_register(&cli_no_debug); + + ast_register_application(app_callingpres, change_callingpres, synopsis_callingpres, descrip_callingpres); + + restart_monitor(); + + return res; +} + +/* + * unload the module + */ +int unload_module() +{ + if (capi20_release(ast_capi_ApplID) != 0) + ast_log(LOG_WARNING,"Unable to unregister from CAPI!\n"); + + ast_unregister_application(app_callingpres); + +#ifdef CC_AST_HAVE_TECH_PVT + ast_channel_unregister(&capi_tech); +#else + ast_channel_unregister(type); +#endif + + return 0; +} + +int usecount() +{ + int res; + + ast_mutex_lock(&usecnt_lock); + res = usecnt; + ast_mutex_unlock(&usecnt_lock); + + return res; +} + +char *description() +{ + return desc; +} + + +char *key() +{ + return ASTERISK_GPL_KEY; +} + diff --git a/chan_capi_app.h b/chan_capi_app.h new file mode 100644 index 0000000..1a2bedf --- /dev/null +++ b/chan_capi_app.h @@ -0,0 +1,35 @@ +/* + * (CAPI*) + * + * An implementation of Common ISDN API 2.0 for Asterisk + * + * include file for helper applications + * + * Copyright (C) 2005 Cytronics & Melware + * + * Armin Schindler + * + * Reworked, but based on the work of + * Copyright (C) 2002-2005 Junghanns.NET GmbH + * + * Klaus-Peter Junghanns + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#ifndef _ASTERISK_CAPI_IF_H +#define _ASTERISK_CAPI_IF_H + +/* exported symbols from chan_capi */ + +/* important things we need */ +extern unsigned ast_capi_ApplID; +extern _cword get_ast_capi_MessageNumber(void); +extern int capidebug; + +extern int capi_call(struct ast_channel *c, char *idest, int timeout); +extern int capi_detect_dtmf(struct ast_channel *c, int flag); +extern MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG); + +#endif diff --git a/chan_capi_pvt.h b/chan_capi_pvt.h new file mode 100644 index 0000000..50adb5d --- /dev/null +++ b/chan_capi_pvt.h @@ -0,0 +1,303 @@ +/* + * (CAPI*) + * + * An implementation of Common ISDN API 2.0 for Asterisk + * + * Copyright (C) 2005 Cytronics & Melware + * + * Armin Schindler + * + * Reworked, but based on the work of + * Copyright (C) 2002-2005 Junghanns.NET GmbH + * + * Klaus-Peter Junghanns + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#ifndef _ASTERISK_CAPI_H +#define _ASTERISK_CAPI_H + +#define AST_CAPI_MAX_CONTROLLERS 16 +#define AST_CAPI_MAX_DEVICES 30 +#define AST_CAPI_MAX_BUF 160 + +#define AST_CAPI_MAX_B3_BLOCKS 7 + +/* was : 130 bytes Alaw = 16.25 ms audio not suitable for VoIP */ +/* now : 160 bytes Alaw = 20 ms audio */ +/* you can tune this to your need. higher value == more latency */ +#define AST_CAPI_MAX_B3_BLOCK_SIZE 160 + +#define AST_CAPI_BCHANS 120 +#define ALL_SERVICES 0x1FFF03FF + +#define AST_CAPI_ISDNMODE_PTMP 0 +#define AST_CAPI_ISDNMODE_PTP 1 + +/* some helper functions */ +static inline void write_capi_word(void *m, unsigned short val) +{ + ((unsigned char *)m)[0] = val & 0xff; + ((unsigned char *)m)[1] = (val >> 8) & 0xff; +} + +/* + * definitions for compatibility with older versions of ast* + */ +#ifdef CC_AST_HAVE_TECH_PVT +#define CC_AST_CHANNEL_PVT(c) c->tech_pvt +#else +#define CC_AST_CHANNEL_PVT(c) c->pvt->pvt +#endif + +#ifndef AST_MUTEX_DEFINE_STATIC +#define AST_MUTEX_DEFINE_STATIC(mutex) \ + static ast_mutex_t mutex = AST_MUTEX_INITIALIZER +#endif + + +/* duration in ms for sending and detecting dtmfs */ +#define AST_CAPI_DTMF_DURATION 0x40 + +#define AST_CAPI_NATIONAL_PREF "0" +#define AST_CAPI_INTERNAT_PREF "00" + +#define ECHO_TX_COUNT 5 // 5 x 20ms = 100ms +#define ECHO_EFFECTIVE_TX_COUNT 3 // 2 x 20ms = 40ms == 40-100ms ... ignore first 40ms +#define ECHO_TXRX_RATIO 2.3 // if( rx < (txavg/ECHO_TXRX_RATIO) ) rx=0; + +#define FACILITYSELECTOR_DTMF 1 +#define FACILITYSELECTOR_SUPPLEMENTARY 3 +#define FACILITYSELECTOR_ECHO_CANCEL 6 + +/* + * state combination for a normal incoming call: + * DIS -> ALERT -> CON -> BCON -> CON -> DIS + * + * outgoing call: + * DIS -> CONP -> BCONNECTED -> CON -> DIS + */ + +#define CAPI_STATE_ALERTING 1 +#define CAPI_STATE_CONNECTED 2 +#define CAPI_STATE_BCONNECTED 3 + +#define CAPI_STATE_DISCONNECTING 4 +#define CAPI_STATE_DISCONNECTED 5 +#define CAPI_STATE_REMOTE_HANGUP 6 + +#define CAPI_STATE_CONNECTPENDING 7 +#define CAPI_STATE_ONHOLD 8 +#define CAPI_STATE_NETWORKHANGUP 9 +#define CAPI_STATE_ANSWERING 10 +#define CAPI_STATE_PUTTINGONHOLD 11 +#define CAPI_STATE_RETRIEVING 12 + +#define CAPI_STATE_DID 13 + +#define AST_CAPI_B3_DONT 0 +#define AST_CAPI_B3_ALWAYS 1 +#define AST_CAPI_B3_ON_SUCCESS 2 + +struct ast_capi_gains { + unsigned char txgains[256]; + unsigned char rxgains[256]; +}; + +#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED 0x00 +#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN 0x01 +#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN 0x02 +#define PRES_ALLOWED_NETWORK_NUMBER 0x03 +#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED 0x20 +#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN 0x21 +#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN 0x22 +#define PRES_PROHIB_NETWORK_NUMBER 0x23 +#define PRES_NUMBER_NOT_AVAILABLE 0x43 + + +/* ! Private data for a capi device */ +struct ast_capi_pvt { + ast_mutex_t lock; + int fd; + int fd2; + + /*! Channel we belong to, possibly NULL */ + struct ast_channel *owner; + /*! Frame */ + struct ast_frame fr; + + char offset[AST_FRIENDLY_OFFSET]; + + /* capi message number */ + _cword MessageNumber; + unsigned int NCCI; + unsigned int PLCI; + /* on which controller we do live */ + int controller; + + /* we could live on those */ + unsigned long controllers; + + int datahandle; + + short buf[AST_CAPI_MAX_BUF]; + int buflen; + /*! Immediate, or wait for an answer */ + int mode; + /*! State of modem in miniature */ + int state; + /*! Digits to strip on outgoing numbers */ + int stripmsd; + /*! ringer timeout */ + int ringt; + /*! actual time of last ring */ + time_t lastring; + /*! dtmf receive state/data */ + char dtmfrx; + + char context[AST_MAX_EXTENSION]; + /*! Multiple Subscriber Number we listen to (, seperated list) */ + char incomingmsn[AST_MAX_EXTENSION]; + /*! Prefix to Build CID */ + char prefix[AST_MAX_EXTENSION]; + /*! Caller ID if available */ + char cid[AST_MAX_EXTENSION]; + /*! Dialed Number if available */ + char dnid[AST_MAX_EXTENSION]; + + char accountcode[20]; + + unsigned int callgroup; + unsigned int group; + + /*! default language */ + char language[MAX_LANGUAGE]; + /*! Static response buffer */ + char response[256]; + + int calledPartyIsISDN; + /* this is an outgoing channel */ + int outgoing; + /* use CLIR */ + int CLIR; + /* are we doing early B3 connect on this interface? */ + int earlyB3; + /* should we do early B3 on this interface? */ + int doB3; + /* store plci here for the call that is onhold */ + unsigned int onholdPLCI; + /* do software dtmf detection */ + int doDTMF; + /* CAPI echo cancellation */ + int doEC; + int ecOption; + int ecTail; + /* isdnmode ptp or ptm */ + int isdnmode; + + /* deflect on circuitbusy */ + char deflect2[AST_MAX_EXTENSION]; + + /* not all codecs supply frames in nice 320 byte chunks */ + struct ast_smoother *smoother; + /* ok, we stop to be nice and give them the lowest possible latency 130 samples * 2 = 260 bytes */ +#ifdef CAPI_SYNC + int B3in; + ast_mutex_t lockB3in; +#endif + + /* do ECHO SURPRESSION */ + int doES; + short txavg[ECHO_TX_COUNT]; + float rxmin; + float txmin; + + struct ast_capi_gains g; + + float txgain; + float rxgain; + struct ast_dsp *vad; + + + struct capi_pipe *mypipe; + /*! Next channel in list */ + struct ast_capi_pvt *next; +}; + + +struct ast_capi_profile { + unsigned short ncontrollers; + unsigned short nbchannels; + unsigned char globaloptions; + unsigned char globaloptions2; + unsigned char globaloptions3; + unsigned char globaloptions4; + unsigned int b1protocols; + unsigned int b2protocols; + unsigned int b3protocols; + unsigned int reserved3[6]; + unsigned int manufacturer[5]; +}; + +struct capi_pipe { + /* lock */ + ast_mutex_t lock; + + /* fd for writing to the channel */ + int fd; + + /* PLCI of the B3 CON */ + unsigned int PLCI; + /* pointer to the interface */ + struct ast_capi_pvt *i; + /* pointer to the channel */ + struct ast_channel *c; + /* next pipe */ + struct capi_pipe *next; +}; + +struct ast_capi_controller { + /* which controller is this? */ + int controller; + /* how many bchans? */ + int nbchannels; + /* free bchans */ + int nfreebchannels; + /* DID */ + int isdnmode; + /* features: */ + int dtmf; + int echocancel; + int sservices; /* supplementray services */ + /* supported sservices: */ + int holdretrieve; + int terminalportability; + int ECT; + int threePTY; + int CF; + int CD; + int MCID; + int CCBS; + int MWI; + int CCNR; + int CONF; +}; + + +/* ETSI 300 102-1 information element identifiers */ +#define CAPI_ETSI_IE_CAUSE 0x08; +#define CAPI_ETSI_IE_PROGRESS_INDICATOR 0x1e; +#define CAPI_ETSI_IE_CALLED_PARTY_NUMBER 0x70; + +/* ETIS 300 102-1 message types */ +#define CAPI_ETSI_ALERTING 0x01; +#define CAPI_ETSI_SETUP_ACKKNOWLEDGE 0x0d; +#define CAPI_ETSI_DISCONNECT 0x45; + +/* ETSI 300 102-1 Numbering Plans */ +#define CAPI_ETSI_NPLAN_NATIONAL 0x20 +#define CAPI_ETSI_NPLAN_INTERNAT 0x10 + +#endif diff --git a/create_config.sh b/create_config.sh new file mode 100755 index 0000000..4f93d97 --- /dev/null +++ b/create_config.sh @@ -0,0 +1,76 @@ +#!/bin/sh +# +# create_config.sh +# +# Script to create config.h for compatibility with +# different asterisk versions. +# +# (C) 2005 Cytronics & Melware +# Armin Schindler +# + +CONFIGFILE="config.h" +rm -f "$CONFIGFILE" + +if [ $# -lt 1 ]; then + echo >&2 "Missing argument" + exit 1 +fi + +INCLUDEDIR="$1/asterisk" + +if [ ! -d "$INCLUDEDIR" ]; then + echo >&2 "Include directory '$INCLUDEDIR' does not exist" + exit 1 +fi + +echo "Checking Asterisk version..." + +echo "/*" >$CONFIGFILE +echo " * automatically generated by $0 `date`" >>$CONFIGFILE +echo " */" >>$CONFIGFILE +echo >>$CONFIGFILE +echo "#ifndef CHAN_CAPI_CONFIG_H" >>$CONFIGFILE +echo "#define CHAN_CAPI_CONFIG_H" >>$CONFIGFILE +echo >>$CONFIGFILE + +if grep -q "struct ast_channel_tech" $INCLUDEDIR/channel.h; then + echo "#define CC_AST_HAVE_TECH_PVT" >>$CONFIGFILE + echo " * found 'struct ast_channel_tech'" +else + echo "#undef CC_AST_HAVE_TECH_PVT" >>$CONFIGFILE + echo " * no 'struct ast_channel_tech', using old pvt" +fi + +if grep -q "ast_dsp_process*needlock" $INCLUDEDIR/dsp.h; then + echo "#define CC_AST_DSP_PROCESS_NEEDLOCK" >>$CONFIGFILE + echo " * ast_dsp_process() needs 'needlock'" +else + echo "#undef CC_AST_DSP_PROCESS_NEEDLOCK" >>$CONFIGFILE + echo " * ast_dsp_process() without 'needlock'" +fi + +if grep -q "struct ast_callerid" $INCLUDEDIR/channel.h; then + echo "#define CC_AST_CHANNEL_HAS_CID" >>$CONFIGFILE + echo " * found 'struct ast_callerid'" +else + echo "#undef CC_AST_CHANNEL_HAS_CID" >>$CONFIGFILE + echo " * no 'struct ast_callerid'" +fi + +if grep -q "struct timeval delivery" $INCLUDEDIR/frame.h; then + echo "#define CC_AST_FRAME_HAS_TIMEVAL" >>$CONFIGFILE + echo " * found 'struct timeval delivery'" +else + echo "#undef CC_AST_FRAME_HAS_TIMEVAL" >>$CONFIGFILE + echo " * no 'struct timeval delivery'" +fi + + +echo "" >>$CONFIGFILE +echo "#endif /* CHAN_CAPI_CONFIG_H */" >>$CONFIGFILE +echo "" >>$CONFIGFILE + +echo "config.h complete." +exit 0 + diff --git a/xlaw.h b/xlaw.h new file mode 100644 index 0000000..594e0a0 --- /dev/null +++ b/xlaw.h @@ -0,0 +1,1660 @@ +#ifdef CAPI_ULAW +#define capiXLAW2INT(x) capiULAW2INT[x] +#define capiINT2XLAW(x) capiINT2ULAW[((unsigned short)x) >> 2] +#else +#define capiXLAW2INT(x) capiALAW2INT[x] +#define capiINT2XLAW(x) capiINT2ALAW[(x>>4)+4096] +#endif + +static unsigned char reversebits[256] = +{ +0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, +0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, +0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, +0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, +0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, +0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, +0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, +0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, +0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, +0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, +0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, +0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, +0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, +0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, +0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, +0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, +0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, +0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, +0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, +0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, +0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, +0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, +0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, +0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, +0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, +0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, +0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, +0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, +0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, +0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, +0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, +0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + +#ifdef CAPI_ULAW +static short capiULAW2INT[] = +{ +0x8284, 0x7d7c, 0xf8a4, 0x075c, 0xe104, 0x1efc, 0xfe8c, 0x0174, +0xc184, 0x3e7c, 0xfc94, 0x036c, 0xf0c4, 0x0f3c, 0xff88, 0x0078, +0xa284, 0x5d7c, 0xfaa4, 0x055c, 0xe904, 0x16fc, 0xff0c, 0x00f4, +0xd184, 0x2e7c, 0xfd94, 0x026c, 0xf4c4, 0x0b3c, 0xffc8, 0x0038, +0x9284, 0x6d7c, 0xf9a4, 0x065c, 0xe504, 0x1afc, 0xfecc, 0x0134, +0xc984, 0x367c, 0xfd14, 0x02ec, 0xf2c4, 0x0d3c, 0xffa8, 0x0058, +0xb284, 0x4d7c, 0xfba4, 0x045c, 0xed04, 0x12fc, 0xff4c, 0x00b4, +0xd984, 0x267c, 0xfe14, 0x01ec, 0xf6c4, 0x093c, 0xffe8, 0x0018, +0x8a84, 0x757c, 0xf924, 0x06dc, 0xe304, 0x1cfc, 0xfeac, 0x0154, +0xc584, 0x3a7c, 0xfcd4, 0x032c, 0xf1c4, 0x0e3c, 0xff98, 0x0068, +0xaa84, 0x557c, 0xfb24, 0x04dc, 0xeb04, 0x14fc, 0xff2c, 0x00d4, +0xd584, 0x2a7c, 0xfdd4, 0x022c, 0xf5c4, 0x0a3c, 0xffd8, 0x0028, +0x9a84, 0x657c, 0xfa24, 0x05dc, 0xe704, 0x18fc, 0xfeec, 0x0114, +0xcd84, 0x327c, 0xfd54, 0x02ac, 0xf3c4, 0x0c3c, 0xffb8, 0x0048, +0xba84, 0x457c, 0xfc24, 0x03dc, 0xef04, 0x10fc, 0xff6c, 0x0094, +0xdd84, 0x227c, 0xfe54, 0x01ac, 0xf7c4, 0x083c, 0xfff8, 0x0008, +0x8684, 0x797c, 0xf8e4, 0x071c, 0xe204, 0x1dfc, 0xfe9c, 0x0164, +0xc384, 0x3c7c, 0xfcb4, 0x034c, 0xf144, 0x0ebc, 0xff90, 0x0070, +0xa684, 0x597c, 0xfae4, 0x051c, 0xea04, 0x15fc, 0xff1c, 0x00e4, +0xd384, 0x2c7c, 0xfdb4, 0x024c, 0xf544, 0x0abc, 0xffd0, 0x0030, +0x9684, 0x697c, 0xf9e4, 0x061c, 0xe604, 0x19fc, 0xfedc, 0x0124, +0xcb84, 0x347c, 0xfd34, 0x02cc, 0xf344, 0x0cbc, 0xffb0, 0x0050, +0xb684, 0x497c, 0xfbe4, 0x041c, 0xee04, 0x11fc, 0xff5c, 0x00a4, +0xdb84, 0x247c, 0xfe34, 0x01cc, 0xf744, 0x08bc, 0xfff0, 0x0010, +0x8e84, 0x717c, 0xf964, 0x069c, 0xe404, 0x1bfc, 0xfebc, 0x0144, +0xc784, 0x387c, 0xfcf4, 0x030c, 0xf244, 0x0dbc, 0xffa0, 0x0060, +0xae84, 0x517c, 0xfb64, 0x049c, 0xec04, 0x13fc, 0xff3c, 0x00c4, +0xd784, 0x287c, 0xfdf4, 0x020c, 0xf644, 0x09bc, 0xffe0, 0x0020, +0x9e84, 0x617c, 0xfa64, 0x059c, 0xe804, 0x17fc, 0xfefc, 0x0104, +0xcf84, 0x307c, 0xfd74, 0x028c, 0xf444, 0x0bbc, 0xffc0, 0x0040, +0xbe84, 0x417c, 0xfc64, 0x039c, 0xf004, 0x0ffc, 0xff7c, 0x0084, +0xdf84, 0x207c, 0xfe74, 0x018c, 0xf844, 0x07bc, 0x0000, 0x0000 +}; + +const unsigned char capiINT2ULAW[16384] = { +255,127,127,191,191,63,63,223,223,95,95,159,159,31,31,239, +239,111,111,175,175,47,47,207,207,79,79,143,143,15,15,247, +247,247,247,119,119,119,119,183,183,183,183,55,55,55,55,215, +215,215,215,87,87,87,87,151,151,151,151,23,23,23,23,231, +231,231,231,103,103,103,103,167,167,167,167,39,39,39,39,199, +199,199,199,71,71,71,71,135,135,135,135,7,7,7,7,251, +251,251,251,251,251,251,251,123,123,123,123,123,123,123,123,187, +187,187,187,187,187,187,187,59,59,59,59,59,59,59,59,219, +219,219,219,219,219,219,219,91,91,91,91,91,91,91,91,155, +155,155,155,155,155,155,155,27,27,27,27,27,27,27,27,235, +235,235,235,235,235,235,235,107,107,107,107,107,107,107,107,171, +171,171,171,171,171,171,171,43,43,43,43,43,43,43,43,203, +203,203,203,203,203,203,203,75,75,75,75,75,75,75,75,139, +139,139,139,139,139,139,139,11,11,11,11,11,11,11,11,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,115, +115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,51, +51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,83, +83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,147, +147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,19, +19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,99, +99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,35, +35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,67, +67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,131, +131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,125, +125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, +125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,61, +61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, +61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,93, +93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93, +93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,29, +29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, +29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,109, +109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, +109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,45, +45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, +45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,77, +77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, +77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,141, +141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, +141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,13, +13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, +13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,117, +117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, +117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, +117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, +117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,53, +53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53, +53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53, +53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53, +53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,85, +85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, +85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, +85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, +85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,21, +21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, +21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, +21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, +21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,101, +101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, +101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, +101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, +101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,37, +37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, +37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, +37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, +37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,69, +69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, +69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, +69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, +69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,57, +57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, +57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, +57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, +57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, +57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, +57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, +57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, +57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,89, +89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, +89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, +89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, +89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, +89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, +89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, +89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, +89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,25, +25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, +25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, +25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, +25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, +25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, +25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, +25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, +25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,41, +41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41, +41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41, +41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41, +41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41, +41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41, +41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41, +41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41, +41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,73, +73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73, +73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73, +73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73, +73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73, +73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73, +73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73, +73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73, +73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,9, +9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, +9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, +9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, +9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, +9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, +9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, +9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, +9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +8,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, +72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, +72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, +72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, +72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, +72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, +72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, +72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, +72,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40, +40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40, +40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40, +40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40, +40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40, +40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40, +40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40, +40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40, +40,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88, +88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88, +88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88, +88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88, +88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88, +88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88, +88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88, +88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88, +88,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56, +56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56, +56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56, +56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56, +56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56, +56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56, +56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56, +56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56, +56,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +4,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, +68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, +68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, +68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, +68,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, +100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, +100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, +100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, +100,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, +20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, +20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, +20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, +20,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, +84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, +84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, +84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, +84,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52, +52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52, +52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52, +52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52, +52,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, +116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, +116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, +116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, +116,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, +12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, +12,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, +140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, +140,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +76,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, +44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, +44,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, +108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, +108,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, +28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, +28,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, +92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, +92,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60, +60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60, +60,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, +124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, +124,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, +130,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, +66,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34, +34,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98, +98,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, +18,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, +146,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82, +82,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, +50,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, +114,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,10,10,10,10,10,10,10,10,138,138,138,138,138,138,138, +138,74,74,74,74,74,74,74,74,202,202,202,202,202,202,202, +202,42,42,42,42,42,42,42,42,170,170,170,170,170,170,170, +170,106,106,106,106,106,106,106,106,234,234,234,234,234,234,234, +234,26,26,26,26,26,26,26,26,154,154,154,154,154,154,154, +154,90,90,90,90,90,90,90,90,218,218,218,218,218,218,218, +218,58,58,58,58,58,58,58,58,186,186,186,186,186,186,186, +186,122,122,122,122,122,122,122,122,250,250,250,250,250,250,250, +250,6,6,6,6,134,134,134,134,70,70,70,70,198,198,198, +198,38,38,38,38,166,166,166,166,102,102,102,102,230,230,230, +230,22,22,22,22,150,150,150,150,86,86,86,86,214,214,214, +214,54,54,54,54,182,182,182,182,118,118,118,118,246,246,246, +246,14,14,142,142,78,78,206,206,46,46,174,174,110,110,238, +238,30,30,158,158,94,94,222,222,62,62,190,190,126,126,254, +}; +#else +static short capiALAW2INT[] = +{ + 0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4, + 0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74, + 0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4, + 0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64, + 0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4, + 0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4, + 0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4, + 0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4, + 0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64, + 0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34, + 0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844, + 0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24, + 0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64, + 0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4, + 0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964, + 0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4, + 0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24, + 0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94, + 0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924, + 0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94, + 0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24, + 0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14, + 0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24, + 0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14, + 0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4, + 0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54, + 0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4, + 0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64, + 0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4, + 0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4, + 0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4, + 0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4 +}; + +const unsigned char capiINT2ALAW[8192] = { + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, + 212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, + 212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, + 212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, + 148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, + 148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, + 148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, + 116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, + 116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, + 116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, + 116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, + 244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, + 244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, + 244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, + 244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, + 52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52, + 52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52, + 52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52, + 52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52, + 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, + 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, + 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, + 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, + 68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, + 68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, + 68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, + 68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, + 196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, + 196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, + 196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, + 196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, + 132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, + 132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, + 132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, + 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, + 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, + 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, + 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, + 228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, + 228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, + 228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, + 228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, + 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, + 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, + 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, + 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, + 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, + 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, + 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, + 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, + 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, + 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, + 220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, + 220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, + 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, + 156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, + 124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, + 124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, + 252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, + 252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, + 60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60, + 60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60, + 188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, + 188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, + 76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, + 76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, + 204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, + 204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, + 140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, + 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, + 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, + 236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, + 236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, + 44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, + 44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, + 172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, + 172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, + 80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, + 208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, + 112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, + 240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, + 48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, + 176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, + 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, + 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, + 224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, + 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, + 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, + 88,88,88,88,88,88,88,88,216,216,216,216,216,216,216,216, + 24,24,24,24,24,24,24,24,152,152,152,152,152,152,152,152, + 120,120,120,120,120,120,120,120,248,248,248,248,248,248,248,248, + 56,56,56,56,56,56,56,56,184,184,184,184,184,184,184,184, + 72,72,72,72,72,72,72,72,200,200,200,200,200,200,200,200, + 8,8,8,8,8,8,8,8,136,136,136,136,136,136,136,136, + 104,104,104,104,104,104,104,104,232,232,232,232,232,232,232,232, + 40,40,40,40,40,40,40,40,168,168,168,168,168,168,168,168, + 86,86,86,86,214,214,214,214,22,22,22,22,150,150,150,150, + 118,118,118,118,246,246,246,246,54,54,54,54,182,182,182,182, + 70,70,70,70,198,198,198,198,6,6,6,6,134,134,134,134, + 102,102,102,102,230,230,230,230,38,38,38,38,166,166,166,166, + 94,94,222,222,30,30,158,158,126,126,254,254,62,62,190,190, + 78,78,206,206,14,14,142,142,110,110,238,238,46,46,174,174, + 82,210,18,146,114,242,50,178,66,194,2,130,98,226,34,162, + 90,218,26,154,122,250,58,186,74,202,10,138,106,234,42,170, + 171,43,235,107,139,11,203,75,187,59,251,123,155,27,219,91, + 163,35,227,99,131,3,195,67,179,51,243,115,147,19,211,83, + 175,175,47,47,239,239,111,111,143,143,15,15,207,207,79,79, + 191,191,63,63,255,255,127,127,159,159,31,31,223,223,95,95, + 167,167,167,167,39,39,39,39,231,231,231,231,103,103,103,103, + 135,135,135,135,7,7,7,7,199,199,199,199,71,71,71,71, + 183,183,183,183,55,55,55,55,247,247,247,247,119,119,119,119, + 151,151,151,151,23,23,23,23,215,215,215,215,87,87,87,87, + 169,169,169,169,169,169,169,169,41,41,41,41,41,41,41,41, + 233,233,233,233,233,233,233,233,105,105,105,105,105,105,105,105, + 137,137,137,137,137,137,137,137,9,9,9,9,9,9,9,9, + 201,201,201,201,201,201,201,201,73,73,73,73,73,73,73,73, + 185,185,185,185,185,185,185,185,57,57,57,57,57,57,57,57, + 249,249,249,249,249,249,249,249,121,121,121,121,121,121,121,121, + 153,153,153,153,153,153,153,153,25,25,25,25,25,25,25,25, + 217,217,217,217,217,217,217,217,89,89,89,89,89,89,89,89, + 161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, + 33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, + 225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, + 97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, + 65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, + 177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, + 49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, + 241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, + 113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, + 145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, + 81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, + 173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, + 173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, + 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, + 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, + 237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, + 237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, + 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, + 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, + 141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, + 141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, + 205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, + 189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, + 253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, + 125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, + 125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, + 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, + 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, + 221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, + 93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93, + 93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93, + 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, + 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, + 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, + 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, + 229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, + 229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, + 229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, + 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, + 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, + 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, + 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, + 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, + 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, + 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, + 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, + 197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, + 197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, + 197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, + 69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, + 69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, + 69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, + 69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, + 181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, + 181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, + 181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, + 181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, + 53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53, + 53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53, + 53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53, + 53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53, + 245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, + 245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, + 245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, + 245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, + 117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, + 117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, + 117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, + 117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, + 149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, + 149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, + 149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, + 149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, + 213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, + 213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, + 213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85 +}; + +#endif // CAPI_ULAW