From 3e3f121c771f7f4cc6ce6f152cd5566e258a26f3 Mon Sep 17 00:00:00 2001 From: MelwareDE Date: Thu, 27 Sep 2007 08:09:26 +0000 Subject: [PATCH] Merged current trunk to stable 1.0, prepare next release. --- CHANGES | 13 + Makefile | 30 +- README | 117 +- README.qsig | 60 +- c20msg.c | 335 ------ capi.conf | 4 +- chan_capi.c | 2341 +++++++++++++++--------------------- chan_capi.h | 136 ++- chan_capi_chat.c | 390 ++++++ chan_capi_chat.h | 23 + chan_capi_qsig.h | 50 +- chan_capi_qsig_asn197ade.c | 101 +- chan_capi_qsig_asn197ade.h | 15 +- chan_capi_qsig_asn197no.c | 7 +- chan_capi_qsig_asn197no.h | 3 +- chan_capi_qsig_core.c | 1244 +++++++++++++++++-- chan_capi_qsig_ecma.c | 580 ++++++++- chan_capi_qsig_ecma.h | 58 + chan_capi_rtp.c | 70 +- chan_capi_rtp.h | 5 +- chan_capi_supplementary.c | 845 +++++++++++++ chan_capi_supplementary.h | 32 + chan_capi_utils.c | 1252 +++++++++++++++++++ chan_capi_utils.h | 59 + create_config.sh | 11 +- openpbx.ctrl | 151 --- preparser | Bin 413028 -> 0 bytes xlaw.c | 1653 +++++++++++++++++++++++++ xlaw.h | 1657 +------------------------ 29 files changed, 7386 insertions(+), 3856 deletions(-) delete mode 100644 c20msg.c create mode 100644 chan_capi_chat.c create mode 100644 chan_capi_chat.h create mode 100644 chan_capi_qsig_ecma.h create mode 100644 chan_capi_supplementary.c create mode 100644 chan_capi_supplementary.h create mode 100644 chan_capi_utils.c create mode 100644 chan_capi_utils.h delete mode 100644 openpbx.ctrl delete mode 100755 preparser create mode 100644 xlaw.c diff --git a/CHANGES b/CHANGES index 4d7b15e..3d77faa 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,19 @@ CHANGES ======= +HEAD +------------------ +- possibly fixed ECT channel hang +- added 'x' option to capicommand(ect) to have real 'explicit call transfer' + (needed by some ISDN lines) +- support CCBS (call completion on busy subscriber) +- added capicommand(chat) for CAPI based MeetMe/Conference using onboard DSPs. +- fixed ton-display in 'show capi channels' on outgoing line. +- fix for 64bit support +- Asterisk 1.4.4 adaptions +- send 'In-band info available' for progress in NT-mode +- detect KEYPAD digits in NT-mode and send call to 'K...' extension + chan_capi-1.0.1 ------------------ diff --git a/Makefile b/Makefile index 587b272..a703f69 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,7 @@ # # (CAPI*) # -# An implementation of Common ISDN API 2.0 for -# Asterisk/OpenPBX.org +# An implementation of Common ISDN API 2.0 for Asterisk # # Makefile, based on the Asterisk Makefile, Coypright (C) 1999, Mark Spencer # @@ -23,8 +22,6 @@ OSNAME=${shell uname} .EXPORT_ALL_VARIABLES: -.PHONY: openpbx - V=0 INSTALL_PREFIX= @@ -93,7 +90,9 @@ INSTALL=install SHAREDOS=chan_capi.so -OBJECTS=chan_capi.o c20msg.o chan_capi_rtp.o chan_capi_qsig_core.o chan_capi_qsig_ecma.o chan_capi_qsig_asn197ade.o chan_capi_qsig_asn197no.o +OBJECTS=chan_capi.o chan_capi_utils.o chan_capi_rtp.o xlaw.o \ + chan_capi_qsig_core.o chan_capi_qsig_ecma.o chan_capi_qsig_asn197ade.o \ + chan_capi_qsig_asn197no.o chan_capi_supplementary.o chan_capi_chat.o CFLAGS+=-Wno-missing-prototypes -Wno-missing-declarations @@ -110,7 +109,6 @@ all: config.h $(SHAREDOS) clean: rm -f config.h rm -f *.so *.o - rm -rf openpbx config.h: ./create_config.sh "$(ASTERISK_HEADER_DIR)" @@ -141,23 +139,3 @@ install_config: capi.conf samples: install_config -openpbx: - @rm -rf openpbx - @mkdir -p openpbx/channels - @mkdir -p openpbx/include/openpbx - @mkdir -p openpbx/doc - @mkdir -p openpbx/configs - @( \ - ./preparser -c openpbx.ctrl chan_capi.c openpbx/channels/chan_capi.c; \ - ./preparser -c openpbx.ctrl chan_capi_rtp.c openpbx/channels/chan_capi_rtp.c; \ - ./preparser -c openpbx.ctrl c20msg.c openpbx/channels/c20msg.c; \ - ./preparser -c openpbx.ctrl chan_capi.h openpbx/include/openpbx/chan_capi.h; \ - ./preparser -c openpbx.ctrl chan_capi_rtp.h openpbx/include/openpbx/chan_capi_rtp.h; \ - ./preparser -c openpbx.ctrl chan_capi20.h openpbx/include/openpbx/chan_capi20.h; \ - ./preparser -c openpbx.ctrl xlaw.h openpbx/include/openpbx/xlaw.h; \ - ./preparser -c openpbx.ctrl README openpbx/doc/README.chan_capi; \ - ./preparser -c openpbx.ctrl capi.conf openpbx/configs/capi.conf.sample; \ - true; \ - ) - - diff --git a/README b/README index 9d48849..24217d1 100644 --- a/README +++ b/README @@ -1,5 +1,4 @@ -(CAPI*) chan_capi a Common ISDN API 2.0 implementation -for Asterisk/OpenPBX +(CAPI*) chan_capi a Common ISDN API 2.0 implementation for Asterisk Copyright (C) 2005-2007 Cytronics & Melware Armin Schindler @@ -8,9 +7,6 @@ for Asterisk/OpenPBX Copyright (C) 2002-2005 Junghanns.NET GmbH Klaus-Peter Junghanns - Ported to OpenPBX.org 22nd October 2004, - Rob Thomas, - 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! @@ -72,14 +68,10 @@ This chan_capi version includes: - CLI command "capi show channels" shows details on channel status. - Asterisk 1.4 jitterbuffer configuration. - some QSIG extensions (see README.qsig) +- CCBS (call completion on busy subscriber) +- CAPI CHAT (CAPI MeetMe using onboard DSPs) +- KEYPAD digits detection -Permissions -=========== - -OpenPBX.org, by default, runs as the non-root user/group -openpbx/openpbx. You must make sure that the /dev/capi* device files -are readable by OpenPBX.org either by changing the ownership or the -permissions of the the device files or by running OpenPBX.org as root. The Dial string =============== @@ -104,6 +96,10 @@ The Dial string (Useful if additional digits shall be send afterwards or together with 'b' to get dialtone and then send the number, e.g. if otherwise no progress tones are available) + 's' : activate 'stay-online': don't disconnect CAPI connection on Hangup. + This is needed to give additional commands like CCBS after Hangup. + To really hangup the CAPI connection, use either capicommand(hangup) + or wait for chan-capi/network timeout (about 20 seconds). If the is used in dialstring, be sure the name (specified in capi.conf) does not start with 'contr' or 'g'. @@ -114,6 +110,27 @@ The Dial string capi.conf has been removed. The callerID is also taken from the calling channel. +CLI commands +============ + +capi info: + Show chan-capi version info. + Show status of available B-channels. + +capi debug: + Enable CAPI message verbosity. + +capi no debug: + Disable CAPI message verbosity. + +capi show channels: + Display detailed information on CAPI B-channels. + (Description see below) + +capi chatinfo: + Show status of CAPI CHAT. + + CAPI command application ======================== chan_capi provides an additional Asterisk application @@ -201,6 +218,10 @@ ECT: exten => s,1,capicommand(hold) exten => s,2,Wait(1) exten => s,3,Dial(CAPI/contr1/1234,60,M(capiect)) + Note: Normaly a PBX needs 'implicit call transfer', which is done by default + with this command. But if the line needs real 'explicit call transfer', use + exten => s,1,capicommand(ect|x) + instead. 3PTY: Initiate a Three-Party Conference (must have one call on hold and one active call!). @@ -213,6 +234,58 @@ ECT: exten => s,1,capicommand(hold) exten => s,2,Dial(CAPI/contr1/1234,,M(capi3pty)) +Peer link creation: + Create a reference for chan-capi to know who is the calling channel on Dial(). + This is needed if you want to use CCBS/CCNR afterwards. + Example: + exten => s,1,capicommand(peerlink) + +Hangup in mode 'stay-online': + After hangup in 'stay-online' mode, the line isn't really disconnected + until timeout or command: + exten => s,1,capicommand(hangup) + This works after capicommand(peerlink) only. + +Set local party to 'busy' or 'free': + Set the local phone to status to 'busy' or 'free' when + awaiting a callback for CCBS/CCNR. If the network wants to + call you back for CCBS/CCNR, chan-capi normaly doesn't know + about the status of the extension who started the callback. + By default chan-capi assumes 'free', but you can change that + with: + exten => s,1,capicommand(ccpartybusy|${CCLINKAGEID}|yes) + or + exten => s,1,capicommand(ccpartybusy|${CCLINKAGEID}|no) + +Call completion on subscriber busy (CCBS): + To receive a callback when the dialed and busy party becomes free, aka + call completion on subscriber busy, you can do the following: + Example: + exten => s,1,capicommand(peerlink) ;to let chan-capi know who is the calling channel. + exten => s,2,Dial(CAPI/contr1/123456,60,g) ;'g' to go-on with the dialplan on busy. + exten => s,3,NoOp(${CCLINKAGEID}) ;if this variable now contains a number, CCBS is possible. + ;here you can ask the caller if CCBS shall be activated... + exten => s,4,capicommand(ccbs|${CCLINKAGEID}|||) + exten => s,5,NoOp(${CCBSSTATUS}) ;if CCBS was successfully enabled, it is set to "ACTIVATED". + If the remote party becomes 'non-busy', the network initiates the callback which will be + sent to the provided context/exten/priority. Of course, this only happens if your local + phone is set to 'free' with capicommand(ccpartybusy), which is the default. + In this context/exten/priority you should just setup a callfile to initiate an outgoing + call from your extension to + exten => s,1,Dial(CAPI/ccbs/${CCLINKAGEID}/) + +Deactivate CCBS: + To deactivate a previously activated CCBS, use following command: + Example: + exten => s,1,capicommand(ccbsstop|${CCLINKAGEID}) + +Chat (MeetMe/Conference): + If the CAPI card/driver supports it, the caller can be put into a chat-room: + (This uses the DSPs onboard a Dialogic DIVA Server Rev.2 card.) + exten => s,1,capicommand(chat|||controller) + Example: + exten => s,1,capicommand(chat|salesmeeting||1,3-6) + Using CLIR ========== @@ -250,6 +323,7 @@ you: 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: @@ -259,6 +333,7 @@ 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: =================================================== @@ -325,6 +400,11 @@ FAXFORMAT : 0 = SFF. FAXPAGES : Number of pages received. FAXID : The ID of the remote fax maschine. +KEYPAD digits in NT-mode +======================== +If the device connected to a NT-mode port sends KEYPAD digits +instead of normal digits, this call is then send to extension +'Kxxx'. Where 'xxx' stands for the KEYPAD digits sent. CLI command "capi show channels" ================================ @@ -347,6 +427,7 @@ Column description: ton : type of number value number : the caller-number and destination-number + Asterisk variables used/set by chan_capi ======================================== @@ -373,7 +454,17 @@ CALLINGSUBADDRESS CALLEDSUBADDRESS If set on dial(), the called subaddress will be set to the content. - + +CCBSSTATUS + When using capicommand(ccbs|....), this variable is set to either "ERROR" or + "ACTIVATED". + +CCLINKAGEID + If a Call-Linkage-Id is received for CCBS/CCNR, this variable contains this Id. + But you need to use capicommand(peerlink) before dialing a CAPI channel, because + of a design problem in Asterisk, chan-capi is not able to set channel variables + of the calling channel. + CONNECTEDNUMBER Can be set before answering and if set, the content is used for IE 'Connected Number' on answering. diff --git a/README.qsig b/README.qsig index 67a9148..1108dea 100644 --- a/README.qsig +++ b/README.qsig @@ -1,5 +1,4 @@ -(CAPI*) chan_capi a Common ISDN API 2.0 implementation -for Asterisk/OpenPBX +(CAPI*) chan_capi a Common ISDN API 2.0 implementation for Asterisk QSIG Extension for chan_capi @@ -36,7 +35,9 @@ To use Q.SIG with asterisk, you'll need a card like Eicon DIVA Server The QSIG support includes: ========================== + - Name presentation on Call SETUP incoming like outgoing + - ISDN LEG INFO2 field - a message which delivers informations about call diversions on incoming call to asterisk Data is stored in Asterisk variables: QSIG_LI2_DIVREASON Reason of divertion: 0 - unknown, 1 - unconditional, 2 - user busy, 3 - user no reply @@ -48,25 +49,56 @@ The QSIG support includes: QSIG_LI2_ODIVNAME original diverting name at the moment only incoming handling is supported + - Possibility to inform QSIG switch about call from public network If you set variable QSIG_SETUP=X then the QSIG switch on the other side will know, this call source is public network - you will get different ring tone, etc. In dialplan use: Set(__QSIG_SETUP=X) command. The leading "__" tells asterisk, to export this variable to the outgoing channel and its subchannels + - Simple Call Transfer With capicommand(qsig_ct|src-id|dst-id) you can transfer an inbound call back to the qsig switch. The B-Channel of this call will be relased, so that the line is free for a next call. Unfortunately the call will be completely released by the switch, if the target is busy. - I have to read the ECMA-300 standard, if there's a chance, to refuse the transfer in such a case. + If you want need to know, if your target is busy, you can use the call transfer feature below. + +- Call Transfer (outgoing) + You can do an outbound call transfer. + First you need the PLCI (logical channel id) of your first channel. You'll get it with capicommand(getplci). This + command returns the channel id in the variable QSIG_PLCI. Now you can enable the call transfer feature. + Simply add "Ct" to QSIG_SETUP (i.e. QSIG_SETUP="X/Ct${QSIG_PLCI}" ). On the next dial command the call will + be automatically transferred. The transfer occurs after the CONNECT. If you want an transfer early on ringing you + can use "Ctr". Then the target user will get the infos about the originating user, while his phone is ringing. + + If the external switch offers an path replacement propose, it will be taken automatically in account. + The B-Channels will be cleared by the switch after call connection. Your channels stay free. + +- Automatic Call Transfer and Path Replacement (if allowed/possible) on bridge/line interconnect + If an line interconnect is set up from asterisk, chan_capi sends an Call Transfer facility out and waits for an + Path Replacement Propose message - if no Path Replacement is received, the line interconnect will proceed. + The Call Transfer allows your connected extensions in every case (if the switch supports the Call Transfer feature) + to see the name and number of his connected peer. + This should be configurable in the next release. + +- decoding of incoming Call Transfer feature + Enables inbound Path Replacement. If received, an automatic Path Replacement with asterisk internal bridging will be fired. + +- Support for sending CalledName + If in dialplan a variable CALLEDNAME was set, it will be sent out to the switch, while the asterisk extension is ringing. + +- Support for sending ConnectedName + If in dialplan a variable CONNECTEDNAME was set, it will be sent out to the switch AFTER connection is answered by asterisk + Future Targets: =============== - check code for buffer overflows -- Call Transfer -- Path Replacement +- complete path replacement features +- Call Rerouting feature [ECMA-174] - CCBS - AOC +- sendtext implementation (e.g. display instructions on the connected set) - ... How to use: @@ -74,18 +106,6 @@ How to use: simply enable Q.SIG with following line in your capi.conf interface: -================================================================================ -********** deprecated ********************************************************** -#### qsig=on - -#### Take care that you enable this only for interfaces, where the other end -#### understands the Q.SIG protocoll. If not, then these switches may reject the -#### entire call, because of wrong facility contents. - -#### Later this will change to qsig=off or qsig=1..x where we can support some -#### pbx manufacturer specific operations. -================================================================================ - Here we go with new configuration Set qsig to one of the following values, which corresponds to your configuration. @@ -98,6 +118,6 @@ Set qsig to one of the following values, which corresponds to your configuration ToDo List: ========== -- Invoke Identifier handling - currently i use invoke id #1, will be corrected by capi (outgoing) -- Handle later facilities - i don't know what to do with most informations now, maybe they are useless in asterisk -- Outgoing calls support only qsig type 1 (Alcatel) - add support for others on outgoing +- Support for inbound rerouting +- Enhance ASN1-97 Addressing Data Elements support - will save much code +- Allow/Disallow Path Replacement within capi.conf - partially done diff --git a/c20msg.c b/c20msg.c deleted file mode 100644 index 4b05211..0000000 --- a/c20msg.c +++ /dev/null @@ -1,335 +0,0 @@ -#include - -/* - * decode capi 2.0 info word - */ -char *capi_info_string(unsigned int info) -{ - switch (info) { - /* informative values (corresponding message was processed) */ - case 0x0001: - return "NCPI not supported by current protocol, NCPI ignored"; - case 0x0002: - return "Flags not supported by current protocol, flags ignored"; - case 0x0003: - return "Alert already sent by another application"; - - /* error information concerning CAPI_REGISTER */ - case 0x1001: - return "Too many applications"; - case 0x1002: - return "Logical block size to small, must be at least 128 Bytes"; - case 0x1003: - return "Buffer exceeds 64 kByte"; - case 0x1004: - return "Message buffer size too small, must be at least 1024 Bytes"; - case 0x1005: - return "Max. number of logical connections not supported"; - case 0x1006: - return "Reserved"; - case 0x1007: - return "The message could not be accepted because of an internal busy condition"; - case 0x1008: - return "OS resource error (no memory ?)"; - case 0x1009: - return "CAPI not installed"; - case 0x100A: - return "Controller does not support external equipment"; - case 0x100B: - return "Controller does only support external equipment"; - - /* error information concerning message exchange functions */ - case 0x1101: - return "Illegal application number"; - case 0x1102: - return "Illegal command or subcommand or message length less than 12 bytes"; - case 0x1103: - return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI"; - case 0x1104: - return "Queue is empty"; - case 0x1105: - return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE"; - case 0x1106: - return "Unknown notification parameter"; - case 0x1107: - return "The Message could not be accepted because of an internal busy condition"; - case 0x1108: - return "OS Resource error (no memory ?)"; - case 0x1109: - return "CAPI not installed"; - case 0x110A: - return "Controller does not support external equipment"; - case 0x110B: - return "Controller does only support external equipment"; - - /* error information concerning resource / coding problems */ - case 0x2001: - return "Message not supported in current state"; - case 0x2002: - return "Illegal Controller / PLCI / NCCI"; - case 0x2003: - return "Out of PLCIs"; - case 0x2004: - return "Out of NCCIs"; - case 0x2005: - return "Out of LISTEN requests"; - case 0x2006: - return "Out of FAX resources (protocol T.30)"; - case 0x2007: - return "Illegal message parameter coding"; - - /* error information concerning requested services */ - case 0x3001: - return "B1 protocol not supported"; - case 0x3002: - return "B2 protocol not supported"; - case 0x3003: - return "B3 protocol not supported"; - case 0x3004: - return "B1 protocol parameter not supported"; - case 0x3005: - return "B2 protocol parameter not supported"; - case 0x3006: - return "B3 protocol parameter not supported"; - case 0x3007: - return "B protocol combination not supported"; - case 0x3008: - return "NCPI not supported"; - case 0x3009: - return "CIP Value unknown"; - case 0x300A: - return "Flags not supported (reserved bits)"; - case 0x300B: - return "Facility not supported"; - case 0x300C: - return "Data length not supported by current protocol"; - case 0x300D: - return "Reset procedure not supported by current protocol"; - case 0x300E: - return "TEI assignment failed or supplementary service not supported"; - case 0x3010: - return "Request not allowed in this state"; - - /* informations about the clearing of a physical connection */ - case 0x3301: - return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)"; - case 0x3302: - return "Protocol error layer 2"; - case 0x3303: - return "Protocol error layer 3"; - case 0x3304: - return "Another application got that call"; - - /* T.30 specific reasons */ - case 0x3311: - return "Connecting not successful (remote station is no FAX G3 machine)"; - case 0x3312: - return "Connecting not successful (training error)"; - case 0x3313: - return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)"; - case 0x3314: - return "Disconnected during transfer (remote abort)"; - case 0x3315: - return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)"; - case 0x3316: - return "Disconnected during transfer (local tx data underrun)"; - case 0x3317: - return "Disconnected during transfer (local rx data overflow)"; - case 0x3318: - return "Disconnected during transfer (local abort)"; - case 0x3319: - return "Illegal parameter coding (e.g. SFF coding error)"; - - /* disconnect causes from the network according to ETS 300 102-1/Q.931 */ - case 0x3481: - return "Unallocated (unassigned) number"; - case 0x3482: - return "No route to specified transit network"; - case 0x3483: - return "No route to destination"; - case 0x3486: - return "Channel unacceptable"; - case 0x3487: - return "Call awarded and being delivered in an established channel"; - case 0x3490: - return "Normal call clearing"; - case 0x3491: - return "User busy"; - case 0x3492: - return "No user responding"; - case 0x3493: - return "No answer from user (user alerted)"; - case 0x3495: - return "Call rejected"; - case 0x3496: - return "Number changed"; - case 0x349A: - return "Non-selected user clearing"; - case 0x349B: - return "Destination out of order"; - case 0x349C: - return "Invalid number format"; - case 0x349D: - return "Facility rejected"; - case 0x349E: - return "Response to STATUS ENQUIRY"; - case 0x349F: - return "Normal, unspecified"; - case 0x34A2: - return "No circuit / channel available"; - case 0x34A6: - return "Network out of order"; - case 0x34A9: - return "Temporary failure"; - case 0x34AA: - return "Switching equipment congestion"; - case 0x34AB: - return "Access information discarded"; - case 0x34AC: - return "Requested circuit / channel not available"; - case 0x34AF: - return "Resources unavailable, unspecified"; - case 0x34B1: - return "Quality of service unavailable"; - case 0x34B2: - return "Requested facility not subscribed"; - case 0x34B9: - return "Bearer capability not authorized"; - case 0x34BA: - return "Bearer capability not presently available"; - case 0x34BF: - return "Service or option not available, unspecified"; - case 0x34C1: - return "Bearer capability not implemented"; - case 0x34C2: - return "Channel type not implemented"; - case 0x34C5: - return "Requested facility not implemented"; - case 0x34C6: - return "Only restricted digital information bearer capability is available"; - case 0x34CF: - return "Service or option not implemented, unspecified"; - case 0x34D1: - return "Invalid call reference value"; - case 0x34D2: - return "Identified channel does not exist"; - case 0x34D3: - return "A suspended call exists, but this call identity does not"; - case 0x34D4: - return "Call identity in use"; - case 0x34D5: - return "No call suspended"; - case 0x34D6: - return "Call having the requested call identity has been cleared"; - case 0x34D8: - return "Incompatible destination"; - case 0x34DB: - return "Invalid transit network selection"; - case 0x34DF: - return "Invalid message, unspecified"; - case 0x34E0: - return "Mandatory information element is missing"; - case 0x34E1: - return "Message type non-existent or not implemented"; - case 0x34E2: - return "Message not compatible with call state or message type non-existent or not implemented"; - case 0x34E3: - return "Information element non-existent or not implemented"; - case 0x34E4: - return "Invalid information element contents"; - case 0x34E5: - return "Message not compatible with call state"; - case 0x34E6: - return "Recovery on timer expiry"; - case 0x34EF: - return "Protocol error, unspecified"; - case 0x34FF: - return "Interworking, unspecified"; - - /* B3 protocol 7 (Modem) */ - case 0x3500: - return "Normal end of connection"; - case 0x3501: - return "Carrier lost"; - case 0x3502: - return "Error on negotiation, i.e. no modem with error correction at other end"; - case 0x3503: - return "No answer to protocol request"; - case 0x3504: - return "Remote modem only works in synchronous mode"; - case 0x3505: - return "Framing fails"; - case 0x3506: - return "Protocol negotiation fails"; - case 0x3507: - return "Other modem sends wrong protocol request"; - case 0x3508: - return "Sync information (data or flags) missing"; - case 0x3509: - return "Normal end of connection from the other modem"; - case 0x350a: - return "No answer from other modem"; - case 0x350b: - return "Protocol error"; - case 0x350c: - return "Error on compression"; - case 0x350d: - return "No connect (timeout or wrong modulation)"; - case 0x350e: - return "No protocol fall-back allowed"; - case 0x350f: - return "No modem or fax at requested number"; - case 0x3510: - return "Handshake error"; - - /* error info concerning the requested supplementary service */ - case 0x3600: - return "Supplementary service not subscribed"; - case 0x3603: - return "Supplementary service not available"; - case 0x3604: - return "Supplementary service not implemented"; - case 0x3606: - return "Invalid served user number"; - case 0x3607: - return "Invalid call state"; - case 0x3608: - return "Basic service not provided"; - case 0x3609: - return "Supplementary service not requested for an incoming call"; - case 0x360a: - return "Supplementary service interaction not allowed"; - case 0x360b: - return "Resource unavailable"; - - /* error info concerning the context of a supplementary service request */ - case 0x3700: - return "Duplicate invocation"; - case 0x3701: - return "Unrecognized operation"; - case 0x3702: - return "Mistyped argument"; - case 0x3703: - return "Resource limitation"; - case 0x3704: - return "Initiator releasing"; - case 0x3705: - return "Unrecognized linked-ID"; - case 0x3706: - return "Linked response unexpected"; - case 0x3707: - return "Unexpected child operation"; - - /* Line Interconnect */ - case 0x3800: - return "PLCI has no B-channel"; - case 0x3801: - return "Lines not compatible"; - case 0x3802: - return "PLCI(s) is (are) not in any or not in the same interconnection"; - - default: - return NULL; - } -} - diff --git a/capi.conf b/capi.conf index 03a1bb2..9f5c981 100644 --- a/capi.conf +++ b/capi.conf @@ -67,5 +67,5 @@ devices=2 ;number of concurrent calls (b-channels) on this controller ;jb..... ;with Asterisk 1.4 you can configure jitterbuffer, ;see Asterisk documentation for all jb* setting available. ;mohinterpret=default ;Asterisk 1.4: default music on hold class when placed on hold. -;qsig=on ;enable use of Q.SIG extensions. - +;qsig=1 ;enable use of Q.SIG extensions. ECMA Variant +;qsig_prnum=1234 ;enable inbound bridging - this should be an QSIG-network-wide unique number diff --git a/chan_capi.c b/chan_capi.c index 7d4a5db..e7dca9e 100644 --- a/chan_capi.c +++ b/chan_capi.c @@ -1,8 +1,7 @@ /* * (CAPI*) * - * An implementation of Common ISDN API 2.0 for - * Asterisk / OpenPBX.org + * An implementation of Common ISDN API 2.0 for Asterisk * * Copyright (C) 2005-2007 Cytronics & Melware * @@ -16,11 +15,6 @@ * This program is free software and may be modified and * distributed under the terms of the GNU Public License. */ -#ifdef PBX_IS_OPBX -#ifdef HAVE_CONFIG_H -#include "confdefs.h" -#endif -#endif #include #include @@ -33,73 +27,20 @@ #include #include -#ifdef PBX_IS_OPBX -#include "openpbx.h" - -OPENPBX_FILE_VERSION("$HeadURL$", "$Revision$") - -#include "openpbx/lock.h" -#include "openpbx/frame.h" -#include "openpbx/channel.h" -#include "openpbx/logger.h" -#include "openpbx/module.h" -#include "openpbx/pbx.h" -#include "openpbx/config.h" -#include "openpbx/options.h" -#include "openpbx/features.h" -#include "openpbx/utils.h" -#include "openpbx/cli.h" -#include "openpbx/rtp.h" -#include "openpbx/causes.h" -#include "openpbx/strings.h" -#include "openpbx/devicestate.h" -#include "openpbx/dsp.h" -#include "openpbx/xlaw.h" -#include "openpbx/chan_capi20.h" -#include "openpbx/chan_capi.h" -#include "openpbx/chan_capi_rtp.h" -#else -#include "config.h" - -#ifdef CC_AST_HAS_VERSION_1_4 -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CC_AST_HAS_VERSION_1_4 -#include "asterisk/abstract_jb.h" -#include "asterisk/musiconhold.h" -#endif #include "xlaw.h" #include "chan_capi20.h" #include "chan_capi.h" #include "chan_capi_rtp.h" #include "chan_capi_qsig.h" +#include "chan_capi_qsig_ecma.h" #include "chan_capi_qsig_asn197ade.h" #include "chan_capi_qsig_asn197no.h" -#endif +#include "chan_capi_utils.h" +#include "chan_capi_supplementary.h" +#include "chan_capi_chat.h" -#ifdef PBX_IS_OPBX -#define CC_VERSION "cm-opbx-1.0" -#else /* #define CC_VERSION "x.y.z" */ #define CC_VERSION "$Revision$" -#endif /* * personal stuff @@ -108,19 +49,13 @@ OPENPBX_FILE_VERSION("$HeadURL$", "$Revision$") #define CAPI_APPLID_UNUSED 0xffffffff unsigned capi_ApplID = CAPI_APPLID_UNUSED; -static _cword capi_MessageNumber; static const char tdesc[] = "Common ISDN API Driver (" CC_VERSION ")"; static const char channeltype[] = "CAPI"; -static const struct ast_channel_tech capi_tech; #ifdef CC_AST_HAS_VERSION_1_4 #define AST_MODULE "chan_capi" #else -#ifdef PBX_IS_OPBX -static char *ccdesc = "Common ISDN API for OpenPBX"; -#else static char *ccdesc = "Common ISDN API for Asterisk"; #endif -#endif static char *commandtdesc = "CAPI command interface.\n" "The dial command:\n" @@ -145,7 +80,9 @@ static char *commandtdesc = "CAPI command interface.\n" "\"3pty_begin|${MYHOLDVAR})\" Three-Party-Conference (3PTY) with active and held call\n" "\"receivefax|filename|stationID|headline\" receive a CAPIfax\n" "\"sendfax|filename.sff|stationID|headline\" send a CAPIfax\n" -"\"qsig_ct|cidsrc|ciddst\" QSIG call transfer\n" +"\"qsig_ssct|cidsrc|ciddst\" QSIG single step call transfer\n" +"\"qsig_ct|cidsrc|ciddst|marker|waitconnect\" QSIG call transfer\n" +"\"qsig_callmark|marker\" marks a QSIG call for later identification\n" "Variables set after fax receive:\n" "FAXSTATUS :0=OK, 1=Error\n" "FAXREASON :B3 disconnect reason\n" @@ -197,24 +134,19 @@ static int usecnt; * this lock! */ -AST_MUTEX_DEFINE_STATIC(messagenumber_lock); #ifndef CC_AST_HAS_VERSION_1_4 AST_MUTEX_DEFINE_STATIC(usecnt_lock); #endif AST_MUTEX_DEFINE_STATIC(iflock); -AST_MUTEX_DEFINE_STATIC(capi_put_lock); -AST_MUTEX_DEFINE_STATIC(verbose_lock); - -static int capi_capability = AST_FORMAT_ALAW; static pthread_t monitor_thread = (pthread_t)(0-1); -static struct capi_pvt *iflist = NULL; +struct capi_pvt *capi_iflist = NULL; + static struct cc_capi_controller *capi_controllers[CAPI_MAX_CONTROLLERS + 1]; static int capi_num_controllers = 0; static unsigned int capi_counter = 0; static unsigned long capi_used_controllers = 0; -static char *emptyid = "\0"; static struct ast_channel *chan_for_task; static int channel_task; @@ -224,12 +156,17 @@ static int channel_task; #define CAPI_CHANNEL_TASK_PICKUP 3 #define CAPI_CHANNEL_TASK_GOTOFAX 4 +static struct capi_pvt *interface_for_task; +static int interface_task; +#define CAPI_INTERFACE_TASK_NONE 0 +#define CAPI_INTERFACE_TASK_NULLIFREMOVE 1 + static char capi_national_prefix[AST_MAX_EXTENSION]; static char capi_international_prefix[AST_MAX_EXTENSION]; static char default_language[MAX_LANGUAGE] = ""; -static int capidebug = 0; +int capi_capability = AST_FORMAT_ALAW; #ifdef CC_AST_HAS_VERSION_1_4 /* Global jitterbuffer configuration - by default, jb is disabled */ @@ -251,37 +188,6 @@ static int pbx_capi_indicate(struct ast_channel *c, int condition, const void *d static int pbx_capi_indicate(struct ast_channel *c, int condition); #endif -/* external prototypes */ -extern char *capi_info_string(unsigned int info); - -/* */ -#define return_on_no_interface(x) \ - if (!i) { \ - cc_verbose(4, 1, "CAPI: %s no interface for PLCI=%#x\n", x, PLCI); \ - return; \ - } - -/* - * helper for _verbose with different verbose settings - */ -void cc_verbose(int o_v, int c_d, char *text, ...) -{ - char line[4096]; - va_list ap; - - va_start(ap, text); - vsnprintf(line, sizeof(line), text, ap); - va_end(ap); - - if ((o_v == 0) || (option_verbose > o_v)) { - if ((!c_d) || ((c_d) && (capidebug))) { - cc_mutex_lock(&verbose_lock); - cc_pbx_verbose(line); - cc_mutex_unlock(&verbose_lock); - } - } -} - /* * B protocol settings */ @@ -312,7 +218,6 @@ static struct { } }; -#ifndef CC_HAVE_NO_GLOBALCONFIGURATION /* * set the global-configuration (b-channel operation) */ @@ -334,7 +239,6 @@ static _cstruct capi_set_global_configuration(struct capi_pvt *i) buf = NULL; return (_cstruct)buf; } -#endif /* * command to string function @@ -372,140 +276,13 @@ static const char * capi_command_to_string(unsigned short wCmd) return "UNDEFINED"; } -/* - * show the text for a CAPI message info value - */ -static void show_capi_info(struct capi_pvt *i, _cword info) -{ - char *p; - char *name = "?"; - - if (info == 0x0000) { - /* no error, do nothing */ - return; - } - - if (!(p = capi_info_string((unsigned int)info))) { - /* message not available */ - return; - } - - if (i) - name = i->vname; - - cc_verbose(3, 0, VERBOSE_PREFIX_4 "%s: CAPI INFO 0x%04x: %s\n", - name, info, p); - return; -} - -/* - * get a new capi message number automically - */ -_cword get_capi_MessageNumber(void) -{ - _cword mn; - - cc_mutex_lock(&messagenumber_lock); - - capi_MessageNumber++; - if (capi_MessageNumber == 0) { - /* avoid zero */ - capi_MessageNumber = 1; - } - - mn = capi_MessageNumber; - - cc_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 (cc_mutex_lock(&capi_put_lock)) { - cc_log(LOG_WARNING, "Unable to lock capi put!\n"); - return -1; - } - - error = capi20_put_cmsg(CMSG); - - if (cc_mutex_unlock(&capi_put_lock)) { - cc_log(LOG_WARNING, "Unable to unlock capi put!\n"); - return -1; - } - - if (error) { - cc_log(LOG_ERROR, "CAPI error sending %s (NCCI=%#x) (error=%#x %s)\n", - capi_cmsg2str(CMSG), (unsigned int)HEADER_CID(CMSG), - error, capi_info_string((unsigned int)error)); - } else { - unsigned short wCmd = HEADER_CMD(CMSG); - if ((wCmd == CAPI_P_REQ(DATA_B3)) || - (wCmd == CAPI_P_RESP(DATA_B3))) { - cc_verbose(7, 1, "%s\n", capi_cmsg2str(CMSG)); - } else { - cc_verbose(4, 1, "%s\n", capi_cmsg2str(CMSG)); - } - } - - return error; -} - -/* - * wait for a specific message - */ -static MESSAGE_EXCHANGE_ERROR capi_wait_conf(struct capi_pvt *i, unsigned short wCmd) -{ - MESSAGE_EXCHANGE_ERROR error = 0; - struct timespec abstime; - unsigned char command, subcommand; - - subcommand = wCmd & 0xff; - command = (wCmd & 0xff00) >> 8; - i->waitevent = (unsigned int)wCmd; - abstime.tv_sec = time(NULL) + 2; - abstime.tv_nsec = 0; - cc_verbose(4, 1, "%s: wait for %s (0x%x)\n", - i->vname, capi_cmd2str(command, subcommand), i->waitevent); - if (ast_cond_timedwait(&i->event_trigger, &i->lock, &abstime) != 0) { - error = -1; - cc_log(LOG_WARNING, "%s: timed out waiting for %s\n", - i->vname, capi_cmd2str(command, subcommand)); - } else { - cc_verbose(4, 1, "%s: cond signal received for %s\n", - i->vname, capi_cmd2str(command, subcommand)); - } - return error; -} - -/* - * write a capi message and wait for CONF - * i->lock must be held - */ -MESSAGE_EXCHANGE_ERROR _capi_put_cmsg_wait_conf(struct capi_pvt *i, _cmsg *CMSG) -{ - MESSAGE_EXCHANGE_ERROR error; - - error = _capi_put_cmsg(CMSG); - - if (!(error)) { - unsigned short wCmd = CAPICMD(CMSG->Command, CAPI_CONF); - error = capi_wait_conf(i, wCmd); - } - return error; -} - /* * wait for B3 up */ -static void capi_wait_for_b3_up(struct capi_pvt *i) +int capi_wait_for_b3_up(struct capi_pvt *i) { struct timespec abstime; + int ret = 1; cc_mutex_lock(&i->lock); if (!(i->isdnstate & CAPI_ISDN_STATE_B3_UP)) { @@ -517,18 +294,21 @@ static void capi_wait_for_b3_up(struct capi_pvt *i) if (ast_cond_timedwait(&i->event_trigger, &i->lock, &abstime) != 0) { cc_log(LOG_WARNING, "%s: timed out waiting for b3 up.\n", i->vname); + ret = 0; } else { cc_verbose(4, 1, "%s: cond signal received for b3 up.\n", i->vname); } } cc_mutex_unlock(&i->lock); + + return ret; } /* * wait for finishing answering state */ -static void capi_wait_for_answered(struct capi_pvt *i) +void capi_wait_for_answered(struct capi_pvt *i) { struct timespec abstime; @@ -564,123 +344,6 @@ static int capi_tell_fax_finish(void *data) return 0; } -/* - * wait some time for a new capi message - */ -static MESSAGE_EXCHANGE_ERROR capidev_check_wait_get_cmsg(_cmsg *CMSG) -{ - MESSAGE_EXCHANGE_ERROR Info; - struct timeval tv; - - repeat: - Info = capi_get_cmsg(CMSG, capi_ApplID); - -#if (CAPI_OS_HINT == 1) || (CAPI_OS_HINT == 2) - /* - * For BSD allow controller 0: - */ - if ((HEADER_CID(CMSG) & 0xFF) == 0) { - HEADER_CID(CMSG) += capi_num_controllers; - } -#endif - - /* if queue is empty */ - if (Info == 0x1104) { - /* try waiting a maximum of 0.100 seconds for a message */ - tv.tv_sec = 0; - tv.tv_usec = 10000; - - Info = capi20_waitformessage(capi_ApplID, &tv); - - if (Info == 0x0000) - goto repeat; - } - - if ((Info != 0x0000) && (Info != 0x1104)) { - if (capidebug) { - cc_log(LOG_DEBUG, "Error waiting for cmsg... INFO = %#x\n", Info); - } - } - - return Info; -} - -/* - * send Listen for supplementary to specified controller - */ -static void ListenOnSupplementary(unsigned controller) -{ - _cmsg CMSG; - char fac[8]; - MESSAGE_EXCHANGE_ERROR error; - int waitcount = 50; - - fac[0] = 7; /* len */ - fac[1] = 0x01; /* listen */ - fac[2] = 0x00; - fac[3] = 4; /* len / sservice specific parameter , cstruct */ - write_capi_dword(&(fac[4]), 0x0000079f); - - FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - FACILITY_REQ_CONTROLLER(&CMSG) = controller; - FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_SUPPLEMENTARY; - FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)&fac; - - error = _capi_put_cmsg(&CMSG); - - while (waitcount) { - error = capidev_check_wait_get_cmsg(&CMSG); - - if (IS_FACILITY_CONF(&CMSG)) { - break; - } - usleep(30000); - waitcount--; - } - if (!waitcount) { - cc_log(LOG_ERROR,"Unable to supplementary-listen on contr%d (error=0x%x)\n", - controller, error); - } -} - -/* - * send Listen to specified controller - */ -static unsigned ListenOnController(unsigned long CIPmask, unsigned controller) -{ - MESSAGE_EXCHANGE_ERROR error; - _cmsg CMSG; - int waitcount = 50; - - LISTEN_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), controller); - - LISTEN_REQ_INFOMASK(&CMSG) = 0xffff; /* lots of info ;) + early B3 connect */ - /* 0x00ff if no early B3 should be done */ - - LISTEN_REQ_CIPMASK(&CMSG) = CIPmask; - error = _capi_put_cmsg(&CMSG); - - if (error) - goto done; - - while (waitcount) { - error = capidev_check_wait_get_cmsg(&CMSG); - - if (IS_LISTEN_CONF(&CMSG)) { - error = LISTEN_CONF_INFO(&CMSG); - ListenOnSupplementary(controller); - break; - } - usleep(30000); - waitcount--; - } - if (!waitcount) - error = 0x100F; - - done: - return error; -} - /* * TCAP -> CIP Translation Table (TransferCapability->CommonIsdnProfile) */ @@ -708,7 +371,7 @@ static int tcap2cip(unsigned short tcap) return CAPI_CIPI_SPEECH; } -static unsigned char tcap_is_digital(unsigned short tcap) +unsigned char capi_tcap_is_digital(unsigned short tcap) { int x; @@ -784,6 +447,19 @@ static char *transfercapability2str(int transfercapability) } } +/* + * set task for an interface which need to be done out of lock + * ( after the capi thread loop ) + */ +static void capi_interface_task(struct capi_pvt *i, int task) +{ + interface_for_task = i; + interface_task = task; + + cc_verbose(4, 1, VERBOSE_PREFIX_4 "%s: set interface task to %d\n", + i->name, task); +} + /* * set task for a channel which need to be done out of lock * ( after the capi thread loop ) @@ -801,26 +477,17 @@ static void capi_channel_task(struct ast_channel *c, int task) * 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<<2) -#define EC_OPTION_DISABLE_G164_OR_G165 (1<<1 | 1<<2) -#define EC_DEFAULT_TAIL 0 /* maximum */ - -static void capi_echo_canceller(struct ast_channel *c, int function) +static void capi_echo_canceller(struct capi_pvt *i, int function) { - struct capi_pvt *i = CC_CHANNEL_PVT(c); - _cmsg CMSG; - char buf[10]; int ecAvail = 0; if ((i->isdnstate & CAPI_ISDN_STATE_DISCONNECT)) return; + if (i->channeltype == CAPI_CHANNELTYPE_NULL) { + return; + } + if (((function == EC_FUNCTION_ENABLE) && (i->isdnstate & CAPI_ISDN_STATE_EC)) || ((function != EC_FUNCTION_ENABLE) && (!(i->isdnstate & CAPI_ISDN_STATE_EC)))) { cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: echo canceller (PLCI=%#x, function=%d) unchanged\n", @@ -844,7 +511,7 @@ static void capi_echo_canceller(struct ast_channel *c, int function) return; } - if (tcap_is_digital(c->transfercapability)) { + if (capi_tcap_is_digital(i->transfercapability)) { cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: No echo canceller in digital mode (PLCI=%#x)\n", i->vname, i->PLCI); return; @@ -853,28 +520,20 @@ static void capi_echo_canceller(struct ast_channel *c, int function) cc_verbose(3, 0, VERBOSE_PREFIX_2 "%s: Setting up echo canceller (PLCI=%#x, function=%d, options=%d, tail=%d)\n", i->vname, i->PLCI, function, i->ecOption, i->ecTail); - FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - FACILITY_REQ_PLCI(&CMSG) = i->PLCI; - FACILITY_REQ_FACILITYSELECTOR(&CMSG) = i->ecSelector; - - memset(buf, 0, sizeof(buf)); - buf[0] = 9; /* msg size */ - write_capi_word(&buf[1], function); if (function == EC_FUNCTION_ENABLE) { - buf[3] = 6; /* echo cancel param struct size */ - write_capi_word(&buf[4], i->ecOption); /* bit field - ignore echo canceller disable tone */ - write_capi_word(&buf[6], i->ecTail); /* Tail length, ms */ - /* buf 8 and 9 are "pre-delay lenght ms" */ i->isdnstate |= CAPI_ISDN_STATE_EC; } else { i->isdnstate &= ~CAPI_ISDN_STATE_EC; } - FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)buf; - - if (_capi_put_cmsg(&CMSG) != 0) { - return; - } + capi_sendf(i, 0, CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(), + "w(w(www))", + i->ecSelector, + function, + i->ecOption, /* bit field - ignore echo canceller disable tone */ + i->ecTail, /* Tail length, ms */ + 0 + ); return; } @@ -882,17 +541,18 @@ static void capi_echo_canceller(struct ast_channel *c, int function) /* * turn on/off DTMF detection */ -static int capi_detect_dtmf(struct ast_channel *c, int flag) +static int capi_detect_dtmf(struct capi_pvt *i, int flag) { - struct capi_pvt *i = CC_CHANNEL_PVT(c); MESSAGE_EXCHANGE_ERROR error; - _cmsg CMSG; - char buf[9]; if ((i->isdnstate & CAPI_ISDN_STATE_DISCONNECT)) return 0; - if (tcap_is_digital(c->transfercapability)) { + if (i->channeltype == CAPI_CHANNELTYPE_NULL) { + return 0; + } + + if (capi_tcap_is_digital(i->transfercapability)) { cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: No dtmf-detect in digital mode (PLCI=%#x)\n", i->vname, i->PLCI); return 0; @@ -910,23 +570,18 @@ static int capi_detect_dtmf(struct ast_channel *c, int flag) if ((capi_controllers[i->controller]->dtmf != 1) || (i->doDTMF != 0)) return 0; - memset(buf, 0, sizeof(buf)); cc_verbose(3, 0, VERBOSE_PREFIX_2 "%s: Setting up DTMF detector (PLCI=%#x, flag=%d)\n", i->vname, i->PLCI, flag); - FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - FACILITY_REQ_PLCI(&CMSG) = i->PLCI; - FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_DTMF; - 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], CAPI_DTMF_DURATION); - write_capi_word(&buf[5], CAPI_DTMF_DURATION); - FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)buf; - - if ((error = _capi_put_cmsg(&CMSG)) != 0) { + + error = capi_sendf(i, 0, CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(), + "w(www()())", + FACILITYSELECTOR_DTMF, + (flag == 1) ? 1:2, /* start/stop DTMF listen */ + CAPI_DTMF_DURATION, + CAPI_DTMF_DURATION + ); + + if (error != 0) { return error; } if (flag == 1) { @@ -942,16 +597,9 @@ static int capi_detect_dtmf(struct ast_channel *c, int flag) */ static int local_queue_frame(struct capi_pvt *i, struct ast_frame *f) { - struct ast_channel *chan = i->owner; unsigned char *wbuf; int wbuflen; - if (chan == NULL) { - cc_log(LOG_ERROR, "No owner in local_queue_frame for %s\n", - i->vname); - return -1; - } - if (!(i->isdnstate & CAPI_ISDN_STATE_PBX)) { /* if there is no PBX running yet, we don't need any frames sent */ @@ -1004,7 +652,9 @@ static void update_channel_name(struct capi_pvt *i) snprintf(name, sizeof(name) - 1, "CAPI/%s/%s-%x", i->vname, i->dnid, capi_counter++); - ast_change_name(i->owner, name); + if (i->owner) { + ast_change_name(i->owner, name); + } cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: Updated channel name: %s\n", i->vname, name); } @@ -1015,15 +665,11 @@ static void update_channel_name(struct capi_pvt *i) static int capi_send_info_digits(struct capi_pvt *i, char *digits, int len) { MESSAGE_EXCHANGE_ERROR error; - _cmsg CMSG; char buf[64]; int a; memset(buf, 0, sizeof(buf)); - INFO_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - INFO_REQ_PLCI(&CMSG) = i->PLCI; - if (len > (sizeof(buf) - 2)) len = sizeof(buf) - 2; @@ -1032,9 +678,12 @@ static int capi_send_info_digits(struct capi_pvt *i, char *digits, int len) for (a = 0; a < len; a++) { buf[a + 2] = digits[a]; } - INFO_REQ_CALLEDPARTYNUMBER(&CMSG) = (_cstruct)buf; - if ((error = _capi_put_cmsg(&CMSG)) != 0) { + error = capi_sendf(NULL, 0, CAPI_INFO_REQ, i->PLCI, get_capi_MessageNumber(), + "s()", + buf + ); + if (error != 0) { return error; } cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: sent CALLEDPARTYNUMBER INFO digits = '%s' (PLCI=%#x)\n", @@ -1048,12 +697,60 @@ static int capi_send_info_digits(struct capi_pvt *i, char *digits, int len) */ static int pbx_capi_send_digit_begin(struct ast_channel *c, char digit) { - /* Not needed */ + struct capi_pvt *i = CC_CHANNEL_PVT(c); + + if ((i->state == CAPI_STATE_CONNECTED) && (i->isdnstate & CAPI_ISDN_STATE_B3_UP)) { + /* we have a real connection, so send real DTMF */ + if ((capi_controllers[i->controller]->dtmf == 0) || (i->doDTMF > 0)) { + /* let * fake it */ + return -1; + } + } + return 0; } #endif + /* - * send a DTMF digit + * send DTMF digit + */ +static int capi_send_dtmf_digits(struct capi_pvt *i, char digit) +{ + int ret; + + if (!(i->isdnstate & CAPI_ISDN_STATE_B3_UP)) { + cc_verbose(2, 1, VERBOSE_PREFIX_3 "%s: send DTMF: B-channel not connected.\n", + i->vname); + return -1; + } + + cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: send DTMF '%c'.\n", + i->vname, digit); + + if ((capi_controllers[i->controller]->dtmf == 0) || (i->doDTMF > 0)) { + /* let * fake it */ + cc_mutex_unlock(&i->lock); + return -1; + } + + ret = capi_sendf(i, 0, CAPI_FACILITY_REQ, i->NCCI, get_capi_MessageNumber(), + "w(www(b)())", + FACILITYSELECTOR_DTMF, + 3, /* send DTMF digit */ + CAPI_DTMF_DURATION, /* XXX: duration comes from asterisk in 1.4 */ + CAPI_DTMF_DURATION, + digit + ); + + if (ret == 0) { + cc_verbose(3, 0, VERBOSE_PREFIX_4 "%s: sent dtmf '%c'\n", + i->vname, digit); + } + return ret; +} + +/* + * send a digit */ #if defined(CC_AST_HAS_VERSION_1_4) && defined(CC_AST_HAS_SEND_DIGIT_END_DURATION) static int pbx_capi_send_digit(struct ast_channel *c, char digit, unsigned int duration) @@ -1062,8 +759,6 @@ static int pbx_capi_send_digit(struct ast_channel *c, char digit) #endif { struct capi_pvt *i = CC_CHANNEL_PVT(c); - _cmsg CMSG; - char buf[10]; char did[2]; int ret = 0; @@ -1072,52 +767,39 @@ static int pbx_capi_send_digit(struct ast_channel *c, char digit) return -1; } - memset(buf, 0, sizeof(buf)); + cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: send_digit '%c' in state %d(%d)\n", + i->vname, digit, i->state, c->_state); cc_mutex_lock(&i->lock); if ((c->_state == AST_STATE_DIALING) && (i->state != CAPI_STATE_DISCONNECTING)) { - did[0] = digit; - did[1] = 0; - strncat(i->dnid, did, sizeof(i->dnid) - 1); - update_channel_name(i); - if ((i->isdnstate & CAPI_ISDN_STATE_SETUP_ACK) && - (i->doOverlap == 0)) { - ret = capi_send_info_digits(i, &digit, 1); + if (!(i->isdnstate & CAPI_ISDN_STATE_ISDNPROGRESS)) { + did[0] = digit; + did[1] = 0; + strncat(i->dnid, did, sizeof(i->dnid) - 1); + update_channel_name(i); + if ((i->isdnstate & CAPI_ISDN_STATE_SETUP_ACK) && + (i->doOverlap == 0)) { + ret = capi_send_info_digits(i, &digit, 1); + } else { + /* if no SETUP-ACK yet, add it to the overlap list */ + strncat(i->overlapdigits, &digit, 1); + i->doOverlap = 1; + } + cc_mutex_unlock(&i->lock); + return ret; } else { - /* if no SETUP-ACK yet, add it to the overlap list */ - strncat(i->overlapdigits, &digit, 1); - i->doOverlap = 1; + /* if PROGRESS arrived, we sent as DTMF */ + ret = capi_send_dtmf_digits(i, digit); + cc_mutex_unlock(&i->lock); + return ret; } - cc_mutex_unlock(&i->lock); - return ret; } - if ((i->state == CAPI_STATE_CONNECTED) && (i->isdnstate & CAPI_ISDN_STATE_B3_UP)) { + if (i->state == CAPI_STATE_CONNECTED) { /* we have a real connection, so send real DTMF */ - if ((capi_controllers[i->controller]->dtmf == 0) || (i->doDTMF > 0)) { - /* let * fake it */ - cc_mutex_unlock(&i->lock); - return -1; - } - - FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - FACILITY_REQ_PLCI(&CMSG) = i->NCCI; - FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_DTMF; - buf[0] = 8; - write_capi_word(&buf[1], 3); /* send DTMF digit */ - /* XXX: duration comes from asterisk in 1.4 */ - write_capi_word(&buf[3], CAPI_DTMF_DURATION); - write_capi_word(&buf[5], CAPI_DTMF_DURATION); - buf[7] = 1; - buf[8] = digit; - FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)buf; - - if ((ret = _capi_put_cmsg(&CMSG)) == 0) { - cc_verbose(3, 0, VERBOSE_PREFIX_4 "%s: sent dtmf '%c'\n", - i->vname, digit); - } + ret = capi_send_dtmf_digits(i, digit); } cc_mutex_unlock(&i->lock); return ret; @@ -1129,7 +811,7 @@ static int pbx_capi_send_digit(struct ast_channel *c, char digit) static int pbx_capi_alert(struct ast_channel *c) { struct capi_pvt *i = CC_CHANNEL_PVT(c); - _cmsg CMSG; + unsigned char *facilityarray = NULL; if ((i->state != CAPI_STATE_INCALL) && (i->state != CAPI_STATE_DID)) { @@ -1137,11 +819,12 @@ static int pbx_capi_alert(struct ast_channel *c) i->vname, i->state); return -1; } - - ALERT_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - ALERT_REQ_PLCI(&CMSG) = i->PLCI; - if (_capi_put_cmsg(&CMSG) != 0) { + facilityarray = alloca(CAPI_MAX_FACILITYDATAARRAY_SIZE); + cc_qsig_add_call_alert_data(facilityarray, i, c); + + if (capi_sendf(NULL, 0, CAPI_ALERT_REQ, i->PLCI, get_capi_MessageNumber(), + "(()()()s())", facilityarray) != 0) { return -1; } @@ -1174,6 +857,9 @@ static void interface_cleanup(struct capi_pvt *i) i->isdnstate = 0; i->cause = 0; + i->whentohangup = 0; + i->whentoqueuehangup = 0; + i->FaxState &= ~CAPI_FAX_STATE_MASK; i->PLCI = 0; @@ -1181,6 +867,7 @@ static void interface_cleanup(struct capi_pvt *i) i->NCCI = 0; i->onholdPLCI = 0; i->doEC = i->doEC_global; + i->ccbsnrhandle = 0; memset(i->cid, 0, sizeof(i->cid)); memset(i->dnid, 0, sizeof(i->dnid)); @@ -1192,7 +879,16 @@ static void interface_cleanup(struct capi_pvt *i) i->rtp = NULL; } + interface_cleanup_qsig(i); + + i->peer = NULL; i->owner = NULL; + i->used = NULL; + + if (i->channeltype == CAPI_CHANNELTYPE_NULL) { + capi_interface_task(i, CAPI_INTERFACE_TASK_NULLIFREMOVE); + } + return; } @@ -1201,20 +897,16 @@ static void interface_cleanup(struct capi_pvt *i) */ static void cc_disconnect_b3(struct capi_pvt *i, int wait) { - _cmsg CMSG; struct timespec abstime; if (!(i->isdnstate & (CAPI_ISDN_STATE_B3_UP | CAPI_ISDN_STATE_B3_PEND))) return; - DISCONNECT_B3_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI; - if (wait) { cc_mutex_lock(&i->lock); - _capi_put_cmsg_wait_conf(i, &CMSG); + capi_sendf(i, 1, CAPI_DISCONNECT_B3_REQ, i->NCCI, get_capi_MessageNumber(), "()"); } else { - _capi_put_cmsg(&CMSG); + capi_sendf(NULL, 0, CAPI_DISCONNECT_B3_REQ, i->NCCI, get_capi_MessageNumber(), "()"); return; } @@ -1244,16 +936,12 @@ static void cc_disconnect_b3(struct capi_pvt *i, int wait) /* * send CONNECT_B3_REQ */ -static void cc_start_b3(struct capi_pvt *i) +void cc_start_b3(struct capi_pvt *i) { - _cmsg CMSG; - if (!(i->isdnstate & (CAPI_ISDN_STATE_B3_UP | CAPI_ISDN_STATE_B3_PEND))) { i->isdnstate |= CAPI_ISDN_STATE_B3_PEND; - CONNECT_B3_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - CONNECT_B3_REQ_PLCI(&CMSG) = i->PLCI; - CONNECT_B3_REQ_NCPI(&CMSG) = capi_rtp_ncpi(i); - _capi_put_cmsg(&CMSG); + capi_sendf(NULL, 0, CAPI_CONNECT_B3_REQ, i->PLCI, get_capi_MessageNumber(), + "s", capi_rtp_ncpi(i)); cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: sent CONNECT_B3_REQ PLCI=%#x\n", i->vname, i->PLCI); } @@ -1287,26 +975,40 @@ static void send_progress(struct capi_pvt *i) return; } +/* + * send disconnect_req + */ +static void capi_send_disconnect(unsigned int PLCI, struct capi_pvt *i) +{ + if (PLCI == 0) { + return; + } + if (i) { + capi_sendf(i, 1, CAPI_DISCONNECT_REQ, PLCI, get_capi_MessageNumber(), "()"); + } else { + capi_sendf(NULL, 0, CAPI_DISCONNECT_REQ, PLCI, get_capi_MessageNumber(), "()"); + } +} + /* * hangup a line (CAPI messages) * (this must be called with i->lock held) */ -static void capi_activehangup(struct ast_channel *c, int state) +void capi_activehangup(struct capi_pvt *i, int state) { - struct capi_pvt *i = CC_CHANNEL_PVT(c); - _cmsg CMSG; + struct ast_channel *c = i->owner; const char *cause; - i->cause = c->hangupcause; - if ((cause = pbx_builtin_getvar_helper(c, "PRI_CAUSE"))) { - i->cause = atoi(cause); - } + if (c) { + i->cause = c->hangupcause; + if ((cause = pbx_builtin_getvar_helper(c, "PRI_CAUSE"))) { + i->cause = atoi(cause); + } - if ((i->isdnstate & CAPI_ISDN_STATE_ECT)) { - cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: activehangup ECT call\n", - i->vname); - /* we do nothing, just wait for DISCONNECT_IND */ - return; + if ((i->isdnstate & CAPI_ISDN_STATE_ECT)) { + cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: activehangup ECT call\n", + i->vname); + } } cc_verbose(2, 1, VERBOSE_PREFIX_3 "%s: activehangingup (cause=%d) for PLCI=%#x\n", @@ -1315,10 +1017,18 @@ static void capi_activehangup(struct ast_channel *c, int state) if ((state == CAPI_STATE_ALERTING) || (state == CAPI_STATE_DID) || (state == CAPI_STATE_INCALL)) { - CONNECT_RESP_HEADER(&CMSG, capi_ApplID, i->MessageNumber, 0); - CONNECT_RESP_PLCI(&CMSG) = i->PLCI; - CONNECT_RESP_REJECT(&CMSG) = (i->cause) ? (0x3480 | (i->cause & 0x7f)) : 2; - _capi_put_cmsg(&CMSG); + capi_sendf(NULL, 0, CAPI_CONNECT_RESP, i->PLCI, i->MessageNumber, + "w()()()()()", + (i->cause) ? (0x3480 | (i->cause & 0x7f)) : 2); + return; + } + + if ((i->isdnstate & CAPI_ISDN_STATE_STAYONLINE)) { + /* user has requested to leave channel online for further actions + like CCBS */ + cc_verbose(2, 1, VERBOSE_PREFIX_4 "%s: disconnect deferred, stay-online mode PLCI=%#x\n", + i->vname, i->PLCI); + i->whentohangup = time(NULL) + 18; /* timeout 18 seconds */ return; } @@ -1327,6 +1037,13 @@ static void capi_activehangup(struct ast_channel *c, int state) cc_disconnect_b3(i, 0); return; } + + if (i->channeltype == CAPI_CHANNELTYPE_NULL) { + if (i->PLCI == 0) { + interface_cleanup(i); + return; + } + } if ((state == CAPI_STATE_CONNECTED) || (state == CAPI_STATE_CONNECTPENDING) || (state == CAPI_STATE_ANSWERING) || (state == CAPI_STATE_ONHOLD)) { @@ -1334,9 +1051,7 @@ static void capi_activehangup(struct ast_channel *c, int state) /* CONNECT_CONF not received yet? */ capi_wait_conf(i, CAPI_CONNECT_CONF); } - DISCONNECT_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - DISCONNECT_REQ_PLCI(&CMSG) = i->PLCI; - _capi_put_cmsg_wait_conf(i, &CMSG); + capi_send_disconnect(i->PLCI, i); } return; } @@ -1385,11 +1100,14 @@ static int pbx_capi_hangup(struct ast_channel *c) interface_cleanup(i); } else { /* not disconnected yet, we must actively do it */ - capi_activehangup(c, state); + capi_activehangup(i, state); } + + i->owner = NULL; + CC_CHANNEL_PVT(c) = NULL; + cc_mutex_unlock(&i->lock); - CC_CHANNEL_PVT(c) = NULL; ast_setstate(c, AST_STATE_DOWN); #ifdef CC_AST_HAS_VERSION_1_4 @@ -1404,82 +1122,6 @@ static int pbx_capi_hangup(struct ast_channel *c) return 0; } -/* - * convert a number - */ -static char *capi_number_func(unsigned char *data, unsigned int strip, char *buf) -{ - unsigned int len; - - if (data[0] == 0xff) { - len = read_capi_word(&data[1]); - data += 2; - } else { - len = data[0]; - data += 1; - } - if (len > (AST_MAX_EXTENSION - 1)) - len = (AST_MAX_EXTENSION - 1); - - /* convert a capi struct to a \0 terminated string */ - if ((!len) || (len < strip)) - return NULL; - - len = len - strip; - data += strip; - - memcpy(buf, data, len); - buf[len] = '\0'; - - return buf; -} -#define capi_number(data, strip) \ - capi_number_func(data, strip, alloca(AST_MAX_EXTENSION)) - -/* - * parse the dialstring - */ -static void parse_dialstring(char *buffer, char **interface, char **dest, char **param, char **ocid) -{ - int cp = 0; - char *buffer_p = buffer; - char *oc; - - /* interface is the first part of the string */ - *interface = buffer; - - *dest = emptyid; - *param = emptyid; - *ocid = NULL; - - while (*buffer_p) { - if (*buffer_p == '/') { - *buffer_p = 0; - buffer_p++; - if (cp == 0) { - *dest = buffer_p; - cp++; - } else if (cp == 1) { - *param = buffer_p; - cp++; - } else { - cc_log(LOG_WARNING, "Too many parts in dialstring '%s'\n", - buffer); - } - continue; - } - buffer_p++; - } - if ((oc = strchr(*dest, ':')) != NULL) { - *ocid = *dest; - *oc = '\0'; - *dest = oc + 1; - } - cc_verbose(3, 1, VERBOSE_PREFIX_4 "parsed dialstring: '%s' '%s' '%s' '%s'\n", - *interface, (*ocid) ? *ocid : "NULL", *dest, *param); - return; -} - /* * PBX tells us to make a call */ @@ -1490,7 +1132,6 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout) char buffer[AST_MAX_EXTENSION]; char called[AST_MAX_EXTENSION], calling[AST_MAX_EXTENSION]; char callerid[AST_MAX_EXTENSION]; - char bchaninfo[3]; int CLIR; int callernplan = 0; int use_defaultcid = 0; @@ -1500,12 +1141,12 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout) char callingsubaddress[AST_MAX_EXTENSION]; char calledsubaddress[AST_MAX_EXTENSION]; int doqsig; + unsigned char *facilityarray = NULL; - _cmsg CMSG; MESSAGE_EXCHANGE_ERROR error; cc_copy_string(buffer, idest, sizeof(buffer)); - parse_dialstring(buffer, &interface, &dest, ¶m, &ocid); + capi_parse_dialstring(buffer, &interface, &dest, ¶m, &ocid); /* init param settings */ i->doB3 = CAPI_B3_DONT; @@ -1536,6 +1177,11 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout) cc_log(LOG_WARNING, "Default CID already set in '%s'\n", idest); use_defaultcid = 1; break; + case 's': /* stay online */ + if ((i->isdnstate & CAPI_ISDN_STATE_STAYONLINE)) + cc_log(LOG_WARNING, "'stay-online' already set in '%s'\n", idest); + i->isdnstate |= CAPI_ISDN_STATE_STAYONLINE; + break; case 'q': /* disable QSIG */ cc_verbose(4, 0, VERBOSE_PREFIX_4 "%s: QSIG extensions for this call disabled\n", i->vname); @@ -1552,12 +1198,57 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout) return -1; } + i->peer = cc_get_peer_link_id(pbx_builtin_getvar_helper(c, "CAPIPEERLINKID")); + i->outgoing = 1; + i->transfercapability = c->transfercapability; + i->isdnstate |= CAPI_ISDN_STATE_PBX; + i->state = CAPI_STATE_CONNECTPENDING; + ast_setstate(c, AST_STATE_DIALING); + i->MessageNumber = get_capi_MessageNumber(); + + /* if this is a CCBS/CCNR callback call */ + if (i->ccbsnrhandle) { + _cword cip = (_cword)tcap2cip(i->transfercapability); + _cword rbref; + + i->doOverlap = 0; + rbref = capi_ccbsnr_take_ref(i->ccbsnrhandle); + + if ((rbref == 0xdead) || + ((capi_sendf(NULL, 0, CAPI_FACILITY_REQ, i->controller, i->MessageNumber, + "w(w(www(wwwsss())()()()()))", + FACILITYSELECTOR_SUPPLEMENTARY, + 0x0012, /* CCBS call */ + rbref, /* reference */ + cip, /* CIP */ + 0, /* reserved */ + /* B protocol */ + b_protocol_table[i->bproto].b1protocol, + b_protocol_table[i->bproto].b2protocol, + b_protocol_table[i->bproto].b3protocol, + b_protocol_table[i->bproto].b1configuration, + b_protocol_table[i->bproto].b2configuration, + b_protocol_table[i->bproto].b3configuration + /* */ /* BC */ + /* */ /* LLC */ + /* */ /* HLC */ + /* */ /* Additional Info */ + )))) { + i->state = CAPI_STATE_DISCONNECTED; + ast_setstate(c, AST_STATE_RESERVED); + return 1; + } + return 0; + } + CLIR = c->cid.cid_pres; callernplan = c->cid.cid_ton & 0x7f; if ((ton = pbx_builtin_getvar_helper(c, "CALLERTON"))) { callernplan = atoi(ton) & 0x7f; } + i->cid_ton = callernplan; + cc_verbose(1, 1, VERBOSE_PREFIX_2 "%s: Call %s %s%s (pres=0x%02x, ton=0x%02x)\n", i->vname, c->name, i->doB3 ? "with B3 ":" ", i->doOverlap ? "overlap":"", CLIR, callernplan); @@ -1575,11 +1266,7 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout) dsa = calledsubaddress; } - i->MessageNumber = get_capi_MessageNumber(); - CONNECT_REQ_HEADER(&CMSG, capi_ApplID, i->MessageNumber, i->controller); - CONNECT_REQ_CONTROLLER(&CMSG) = i->controller; - CONNECT_REQ_CIPVALUE(&CMSG) = tcap2cip(c->transfercapability); - if (tcap_is_digital(c->transfercapability)) { + if (capi_tcap_is_digital(i->transfercapability)) { i->bproto = CC_BPROTO_TRANSPARENT; cc_verbose(4, 0, VERBOSE_PREFIX_2 "%s: is digital call, set proto to TRANSPARENT\n", i->vname); @@ -1593,8 +1280,6 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout) } called[1] = 0x80; strncpy(&called[2], dest, sizeof(called) - 3); - CONNECT_REQ_CALLEDPARTYNUMBER(&CMSG) = (_cstruct)called; - CONNECT_REQ_CALLEDPARTYSUBADDRESS(&CMSG) = (_cstruct)dsa; if (c->cid.cid_num) { cc_copy_string(callerid, c->cid.cid_num, sizeof(callerid)); @@ -1614,41 +1299,40 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout) calling[2] = 0x80 | (CLIR & 0x63); strncpy(&calling[3], callerid, sizeof(calling) - 4); - CONNECT_REQ_CALLINGPARTYNUMBER(&CMSG) = (_cstruct)calling; - CONNECT_REQ_CALLINGPARTYSUBADDRESS(&CMSG) = (_cstruct)osa; - - CONNECT_REQ_B1PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b1protocol; - CONNECT_REQ_B2PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b2protocol; - CONNECT_REQ_B3PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b3protocol; - CONNECT_REQ_B1CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b1configuration; - CONNECT_REQ_B2CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b2configuration; - CONNECT_REQ_B3CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b3configuration; - - bchaninfo[0] = 2; - bchaninfo[1] = 0x0; - bchaninfo[2] = 0x0; - CONNECT_REQ_BCHANNELINFORMATION(&CMSG) = (_cstruct)bchaninfo; /* 0 */ - if (doqsig) { - unsigned char *facilityarray = alloca(CAPI_MAX_FACILITYDATAARRAY_SIZE); + facilityarray = alloca(CAPI_MAX_FACILITYDATAARRAY_SIZE); cc_qsig_add_call_setup_data(facilityarray, i, c); - CONNECT_REQ_FACILITYDATAARRAY(&CMSG) = facilityarray; } - cc_mutex_lock(&i->lock); + error = capi_sendf(NULL, 0, CAPI_CONNECT_REQ, i->controller, i->MessageNumber, + "wssss(wwwsss())()()()((w)()()s())", + tcap2cip(i->transfercapability), /* CIP value */ + called, /* called party number */ + calling, /* calling party number */ + dsa, /* called party subaddress */ + osa, /* calling party subaddress */ + /* B protocol */ + b_protocol_table[i->bproto].b1protocol, + b_protocol_table[i->bproto].b2protocol, + b_protocol_table[i->bproto].b3protocol, + b_protocol_table[i->bproto].b1configuration, + b_protocol_table[i->bproto].b2configuration, + b_protocol_table[i->bproto].b3configuration, + /* BC */ + /* LLC */ + /* HLC */ + /* Additional Info */ + 0x0000, /* B channel info */ + /* Keypad facility */ + /* User-User data */ + facilityarray /* Facility data array */ + ); - i->outgoing = 1; - i->isdnstate |= CAPI_ISDN_STATE_PBX; - i->state = CAPI_STATE_CONNECTPENDING; - ast_setstate(c, AST_STATE_DIALING); - - if ((error = _capi_put_cmsg(&CMSG))) { + if (error) { i->state = CAPI_STATE_DISCONNECTED; ast_setstate(c, AST_STATE_RESERVED); - cc_mutex_unlock(&i->lock); return error; } - cc_mutex_unlock(&i->lock); /* now we shall return .... the rest has to be done by handle_msg */ return 0; @@ -1660,11 +1344,17 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout) static int capi_send_answer(struct ast_channel *c, _cstruct b3conf) { struct capi_pvt *i = CC_CHANNEL_PVT(c); - _cmsg CMSG; char buf[CAPI_MAX_STRING]; const char *dnid; const char *connectednumber; + unsigned char *facilityarray = NULL; + if (i->state == CAPI_STATE_DISCONNECTED) { + cc_verbose(3, 0, VERBOSE_PREFIX_2 "%s: Not answering disconnected call.\n", + i->vname); + return -1; + } + if ((i->isdnmode == CAPI_ISDNMODE_DID) && ((strlen(i->incomingmsn) < strlen(i->dnid)) && (strcmp(i->incomingmsn, "*")))) { @@ -1676,32 +1366,41 @@ static int capi_send_answer(struct ast_channel *c, _cstruct b3conf) dnid = connectednumber; } - CONNECT_RESP_HEADER(&CMSG, capi_ApplID, i->MessageNumber, 0); - CONNECT_RESP_PLCI(&CMSG) = i->PLCI; - CONNECT_RESP_REJECT(&CMSG) = 0; if (strlen(dnid)) { buf[0] = strlen(dnid) + 2; buf[1] = 0x00; buf[2] = 0x80; strncpy(&buf[3], dnid, sizeof(buf) - 4); - CONNECT_RESP_CONNECTEDNUMBER(&CMSG) = (_cstruct)buf; + } else { + buf[0] = 0x00; } - CONNECT_RESP_B1PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b1protocol; - CONNECT_RESP_B2PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b2protocol; - CONNECT_RESP_B3PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b3protocol; - CONNECT_RESP_B1CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b1configuration; - CONNECT_RESP_B2CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b2configuration; - if (!b3conf) + if (!b3conf) { b3conf = b_protocol_table[i->bproto].b3configuration; - CONNECT_RESP_B3CONFIGURATION(&CMSG) = b3conf; -#ifndef CC_HAVE_NO_GLOBALCONFIGURATION - CONNECT_RESP_GLOBALCONFIGURATION(&CMSG) = capi_set_global_configuration(i); -#endif + } cc_verbose(3, 0, VERBOSE_PREFIX_2 "%s: Answering for %s\n", i->vname, dnid); - if (_capi_put_cmsg(&CMSG) != 0) { + facilityarray = alloca(CAPI_MAX_FACILITYDATAARRAY_SIZE); + cc_qsig_add_call_answer_data(facilityarray, i, c); + + if (capi_sendf(NULL, 0, CAPI_CONNECT_RESP, i->PLCI, i->MessageNumber, + "w(wwwssss)s()()(()()()s())", + 0, /* accept call */ + /* B protocol */ + b_protocol_table[i->bproto].b1protocol, + b_protocol_table[i->bproto].b2protocol, + b_protocol_table[i->bproto].b3protocol, + b_protocol_table[i->bproto].b1configuration, + b_protocol_table[i->bproto].b2configuration, + b3conf, + capi_set_global_configuration(i), + buf, /* connected number */ + /* connected subaddress */ + /* LLC */ + /* Additional info */ + facilityarray + ) != 0) { return -1; } @@ -1723,7 +1422,7 @@ static int pbx_capi_answer(struct ast_channel *c) i->bproto = CC_BPROTO_TRANSPARENT; if (i->rtp) { - if (!tcap_is_digital(c->transfercapability)) + if (!capi_tcap_is_digital(i->transfercapability)) i->bproto = CC_BPROTO_RTP; } @@ -1736,46 +1435,12 @@ static int pbx_capi_answer(struct ast_channel *c) */ static struct ast_frame *pbx_capi_read(struct ast_channel *c) { - struct capi_pvt *i = CC_CHANNEL_PVT(c); + struct capi_pvt *i = CC_CHANNEL_PVT(c); struct ast_frame *f; - int readsize; - if (i == NULL) { - cc_log(LOG_ERROR, "channel has no interface\n"); - return NULL; - } - if (i->readerfd == -1) { - cc_log(LOG_ERROR, "no readerfd\n"); - return NULL; - } + f = capi_read_pipeframe(i); - f = &i->f; - f->frametype = AST_FRAME_NULL; - f->subclass = 0; - - readsize = read(i->readerfd, f, sizeof(struct ast_frame)); - if (readsize != sizeof(struct ast_frame)) { - cc_log(LOG_ERROR, "did not read a whole frame\n"); - } - - f->mallocd = 0; - f->data = NULL; - - if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) { - return NULL; - } - - if ((f->frametype == AST_FRAME_VOICE) && (f->datalen > 0)) { - if (f->datalen > sizeof(i->frame_data)) { - cc_log(LOG_ERROR, "f.datalen(%d) greater than space of frame_data(%d)\n", - f->datalen, sizeof(i->frame_data)); - f->datalen = sizeof(i->frame_data); - } - readsize = read(i->readerfd, i->frame_data + AST_FRIENDLY_OFFSET, f->datalen); - if (readsize != f->datalen) { - cc_log(LOG_ERROR, "did not read whole frame data\n"); - } - f->data = i->frame_data + AST_FRIENDLY_OFFSET; + if ((f) && (f->frametype == AST_FRAME_VOICE) && (f->datalen > 0)) { if ((i->doDTMF > 0) && (i->vad != NULL) ) { f = ast_dsp_process(c, i->vad, f); } @@ -1789,125 +1454,10 @@ static struct ast_frame *pbx_capi_read(struct ast_channel *c) static int pbx_capi_write(struct ast_channel *c, struct ast_frame *f) { struct capi_pvt *i = CC_CHANNEL_PVT(c); - MESSAGE_EXCHANGE_ERROR error; - _cmsg CMSG; - int j = 0; - unsigned char *buf; - struct ast_frame *fsmooth; - int txavg=0; int ret = 0; - if (!i) { - cc_log(LOG_ERROR, "channel has no interface\n"); - return -1; - } - - if ((!(i->isdnstate & CAPI_ISDN_STATE_B3_UP)) || (!i->NCCI) || - ((i->isdnstate & (CAPI_ISDN_STATE_B3_CHANGE | CAPI_ISDN_STATE_LI)))) { - return 0; - } + ret = capi_write_frame(i, f); - if ((!(i->ntmode)) && (i->state != CAPI_STATE_CONNECTED)) { - return 0; - } - - if (f->frametype == AST_FRAME_NULL) { - return 0; - } - if (f->frametype == AST_FRAME_DTMF) { - cc_log(LOG_ERROR, "dtmf frame should be written\n"); - return 0; - } - if (f->frametype != AST_FRAME_VOICE) { - cc_log(LOG_ERROR,"not a voice frame\n"); - return 0; - } - if (i->FaxState & CAPI_FAX_STATE_ACTIVE) { - cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: write on fax activity?\n", - i->vname); - return 0; - } - if ((!f->data) || (!f->datalen)) { - cc_log(LOG_DEBUG, "No data for FRAME_VOICE %s\n", c->name); - return 0; - } - if (i->isdnstate & CAPI_ISDN_STATE_RTP) { - if ((!(f->subclass & i->codec)) && - (f->subclass != capi_capability)) { - cc_log(LOG_ERROR, "don't know how to write subclass %s(%d)\n", - ast_getformatname(f->subclass), f->subclass); - return 0; - } - return capi_write_rtp(c, f); - } - if (i->B3count >= CAPI_MAX_B3_BLOCKS) { - cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: B3count is full, dropping packet.\n", - i->vname); - return 0; - } - - if ((!i->smoother) || (ast_smoother_feed(i->smoother, f) != 0)) { - cc_log(LOG_ERROR, "%s: failed to fill smoother\n", i->vname); - return 0; - } - - for (fsmooth = ast_smoother_read(i->smoother); - fsmooth != NULL; - fsmooth = ast_smoother_read(i->smoother)) { - DATA_B3_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - DATA_B3_REQ_NCCI(&CMSG) = i->NCCI; - DATA_B3_REQ_DATALENGTH(&CMSG) = fsmooth->datalen; - DATA_B3_REQ_FLAGS(&CMSG) = 0; - - DATA_B3_REQ_DATAHANDLE(&CMSG) = i->send_buffer_handle; - buf = &(i->send_buffer[(i->send_buffer_handle % CAPI_MAX_B3_BLOCKS) * - (CAPI_MAX_B3_BLOCK_SIZE + AST_FRIENDLY_OFFSET)]); - DATA_B3_REQ_DATA(&CMSG) = buf; - i->send_buffer_handle++; - - if ((i->doES == 1) && (!tcap_is_digital(c->transfercapability))) { - for (j = 0; j < fsmooth->datalen; j++) { - buf[j] = reversebits[ ((unsigned char *)fsmooth->data)[j] ]; - if (capi_capability == AST_FORMAT_ULAW) { - txavg += abs( capiULAW2INT[reversebits[ ((unsigned char*)fsmooth->data)[j]]] ); - } else { - txavg += abs( capiALAW2INT[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; - } else { - if ((i->txgain == 1.0) || (tcap_is_digital(c->transfercapability))) { - for (j = 0; j < fsmooth->datalen; j++) { - buf[j] = reversebits[((unsigned char *)fsmooth->data)[j]]; - } - } else { - for (j = 0; j < fsmooth->datalen; j++) { - buf[j] = i->g.txgains[reversebits[((unsigned char *)fsmooth->data)[j]]]; - } - } - } - - error = 1; - if (i->B3q > 0) { - error = _capi_put_cmsg(&CMSG); - } else { - cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: too much voice to send for NCCI=%#x\n", - i->vname, i->NCCI); - } - - if (!error) { - cc_mutex_lock(&i->lock); - i->B3count++; - i->B3q -= fsmooth->datalen; - if (i->B3q < 0) - i->B3q = 0; - cc_mutex_unlock(&i->lock); - } - } return ret; } @@ -1932,23 +1482,20 @@ static int pbx_capi_fixup(struct ast_channel *oldchan, struct ast_channel *newch */ static void cc_select_b(struct capi_pvt *i, _cstruct b3conf) { - _cmsg CMSG; - - SELECT_B_PROTOCOL_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - SELECT_B_PROTOCOL_REQ_PLCI(&CMSG) = i->PLCI; - SELECT_B_PROTOCOL_REQ_B1PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b1protocol; - SELECT_B_PROTOCOL_REQ_B2PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b2protocol; - SELECT_B_PROTOCOL_REQ_B3PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b3protocol; - SELECT_B_PROTOCOL_REQ_B1CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b1configuration; - SELECT_B_PROTOCOL_REQ_B2CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b2configuration; - if (!b3conf) + if (!b3conf) { b3conf = b_protocol_table[i->bproto].b3configuration; - SELECT_B_PROTOCOL_REQ_B3CONFIGURATION(&CMSG) = b3conf; -#ifndef CC_HAVE_NO_GLOBALCONFIGURATION - SELECT_B_PROTOCOL_REQ_GLOBALCONFIGURATION(&CMSG) = capi_set_global_configuration(i); -#endif + } - _capi_put_cmsg(&CMSG); + capi_sendf(NULL, 0, CAPI_SELECT_B_PROTOCOL_REQ, i->PLCI, get_capi_MessageNumber(), + "(wwwssss)", + b_protocol_table[i->bproto].b1protocol, + b_protocol_table[i->bproto].b2protocol, + b_protocol_table[i->bproto].b3protocol, + b_protocol_table[i->bproto].b1configuration, + b_protocol_table[i->bproto].b2configuration, + b3conf, + capi_set_global_configuration(i) + ); } /* @@ -1956,9 +1503,6 @@ static void cc_select_b(struct capi_pvt *i, _cstruct b3conf) */ static int line_interconnect(struct capi_pvt *i0, struct capi_pvt *i1, int start) { - _cmsg CMSG; - char buf[20]; - if ((i0->isdnstate & CAPI_ISDN_STATE_DISCONNECT) || (i1->isdnstate & CAPI_ISDN_STATE_DISCONNECT)) return -1; @@ -1972,41 +1516,33 @@ static int line_interconnect(struct capi_pvt *i0, struct capi_pvt *i1, int start return -1; } - FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - FACILITY_REQ_PLCI(&CMSG) = i0->PLCI; - FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_LINE_INTERCONNECT; - - memset(buf, 0, sizeof(buf)); - if (start) { /* connect */ - buf[0] = 17; /* msg size */ - write_capi_word(&buf[1], 0x0001); - buf[3] = 14; /* struct size LI Request Parameter */ - write_capi_dword(&buf[4], 0x00000000); /* Data Path */ - buf[8] = 9; /* struct size */ - buf[9] = 8; /* struct size LI Request Connect Participant */ - write_capi_dword(&buf[10], i1->PLCI); - write_capi_dword(&buf[14], 0x00000003); /* Data Path Participant */ - } else { - /* disconnect */ - buf[0] = 7; /* msg size */ - write_capi_word(&buf[1], 0x0002); - buf[3] = 4; /* struct size */ - write_capi_dword(&buf[4], i1->PLCI); - } - - FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)buf; - - _capi_put_cmsg(&CMSG); - - if (start) { + capi_sendf(i1, 0, CAPI_FACILITY_REQ, i0->PLCI, get_capi_MessageNumber(), + "w(w(d((dd))))", + FACILITYSELECTOR_LINE_INTERCONNECT, + 0x0001, + /* struct LI Request Parameter */ + 0x00000000, /* Data Path */ + /* struct */ + /* struct LI Request Connect Participant */ + i1->PLCI, + 0x00000003 /* Data Path Participant */ + ); i0->isdnstate |= CAPI_ISDN_STATE_LI; i1->isdnstate |= CAPI_ISDN_STATE_LI; } else { + /* disconnect */ + capi_sendf(i1, 0, CAPI_FACILITY_REQ, i0->PLCI, get_capi_MessageNumber(), + "w(w(d))", + FACILITYSELECTOR_LINE_INTERCONNECT, + 0x0002, + i1->PLCI + ); i0->isdnstate &= ~CAPI_ISDN_STATE_LI; i1->isdnstate &= ~CAPI_ISDN_STATE_LI; } + return 0; } @@ -2096,21 +1632,36 @@ static CC_BRIDGE_RETURN pbx_capi_bridge(struct ast_channel *c0, } if ((i0->isdnstate & CAPI_ISDN_STATE_ECT) || - (i0->isdnstate & CAPI_ISDN_STATE_ECT)) { + (i1->isdnstate & CAPI_ISDN_STATE_ECT)) { return AST_BRIDGE_FAILED; } + + if ((i0->qsigfeat) && (i1->qsigfeat)) { + int br_status = pbx_capi_qsig_bridge(i0, i1); + + switch (br_status) { + case 1: /* successfull established Call Transfer with PR */ + return ret; + case 2: /* don't do bridge - call transfer is active */ + cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s:%s cancelled bridge (path replacement was sent) for %s and %s\n", + i0->vname, i1->vname, c0->name, c1->name); + return AST_BRIDGE_FAILED_NOWARN; + default: /* let's do line interconnect */ + break; + } + } capi_wait_for_b3_up(i0); capi_wait_for_b3_up(i1); - + if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0)) - capi_detect_dtmf(i0->owner, 0); + capi_detect_dtmf(i0, 0); if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1)) - capi_detect_dtmf(i1->owner, 0); + capi_detect_dtmf(i1, 0); - capi_echo_canceller(i0->owner, EC_FUNCTION_DISABLE); - capi_echo_canceller(i1->owner, EC_FUNCTION_DISABLE); + capi_echo_canceller(i0, EC_FUNCTION_DISABLE); + capi_echo_canceller(i1, EC_FUNCTION_DISABLE); if (line_interconnect(i0, i1, 1)) { ret = AST_BRIDGE_FAILED; @@ -2156,13 +1707,13 @@ static CC_BRIDGE_RETURN pbx_capi_bridge(struct ast_channel *c0, return_from_bridge: if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0)) - capi_detect_dtmf(i0->owner, 1); + capi_detect_dtmf(i0, 1); if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1)) - capi_detect_dtmf(i1->owner, 1); + capi_detect_dtmf(i1, 1); - capi_echo_canceller(i0->owner, EC_FUNCTION_ENABLE); - capi_echo_canceller(i1->owner, EC_FUNCTION_ENABLE); + capi_echo_canceller(i0, EC_FUNCTION_ENABLE); + capi_echo_canceller(i1, EC_FUNCTION_ENABLE); return ret; } @@ -2174,19 +1725,20 @@ static struct ast_channel *capi_new(struct capi_pvt *i, int state) { struct ast_channel *tmp; int fmt; - int fds[2]; - int flags; #ifdef CC_AST_HAS_EXT_CHAN_ALLOC tmp = ast_channel_alloc(0, state, i->cid, NULL, +#ifdef CC_AST_HAS_EXT2_CHAN_ALLOC + i->accountcode, i->dnid, i->context, i->amaflags, +#endif "CAPI/%s/%s-%x", i->vname, i->dnid, capi_counter++); #else tmp = ast_channel_alloc(0); #endif if (tmp == NULL) { - cc_log(LOG_ERROR,"Unable to allocate channel!\n"); - return(NULL); + cc_log(LOG_ERROR, "Unable to allocate channel!\n"); + return NULL; } #ifndef CC_AST_HAS_EXT_CHAN_ALLOC @@ -2202,19 +1754,10 @@ static struct ast_channel *capi_new(struct capi_pvt *i, int state) tmp->type = channeltype; #endif - if (pipe(fds) != 0) { - cc_log(LOG_ERROR, "%s: unable to create pipe.\n", - i->vname); + if (!(capi_create_reader_writer_pipe(i))) { ast_channel_free(tmp); return NULL; } - i->readerfd = fds[0]; - i->writerfd = fds[1]; - flags = fcntl(i->readerfd, F_GETFL); - fcntl(i->readerfd, F_SETFL, flags | O_NONBLOCK); - flags = fcntl(i->writerfd, F_GETFL); - fcntl(i->writerfd, F_SETFL, flags | O_NONBLOCK); - tmp->fds[0] = i->readerfd; if (i->smoother != NULL) { @@ -2270,7 +1813,6 @@ static struct ast_channel *capi_new(struct capi_pvt *i, int state) ast_getformatname_multiple(alloca(80), 80, tmp->nativeformats), (i->rtp) ? " (RTP)" : ""); - cc_copy_string(tmp->context, i->context, sizeof(tmp->context)); if (!ast_strlen_zero(i->cid)) { if (tmp->cid.cid_num) { @@ -2285,9 +1827,12 @@ static struct ast_channel *capi_new(struct capi_pvt *i, int state) tmp->cid.cid_dnid = strdup(i->dnid); } tmp->cid.cid_ton = i->cid_ton; + +#ifndef CC_AST_HAS_EXT2_CHAN_ALLOC if (i->amaflags) tmp->amaflags = i->amaflags; + cc_copy_string(tmp->context, i->context, sizeof(tmp->context)); cc_copy_string(tmp->exten, i->dnid, sizeof(tmp->exten)); #ifdef CC_AST_HAS_STRINGFIELD_IN_CHANNEL ast_string_field_set(tmp, accountcode, i->accountcode); @@ -2296,7 +1841,16 @@ static struct ast_channel *capi_new(struct capi_pvt *i, int state) cc_copy_string(tmp->accountcode, i->accountcode, sizeof(tmp->accountcode)); cc_copy_string(tmp->language, i->language, sizeof(tmp->language)); #endif +#endif + +#ifdef CC_AST_HAS_STRINGFIELD_IN_CHANNEL + ast_string_field_set(tmp, language, i->language); +#else + cc_copy_string(tmp->language, i->language, sizeof(tmp->language)); +#endif + i->owner = tmp; + i->used = tmp; #ifdef CC_AST_HAS_VERSION_1_4 ast_atomic_fetchadd_int(&usecnt, 1); @@ -2327,12 +1881,12 @@ pbx_capi_request(const char *type, int format, void *data, int *cause) char buffer[CAPI_MAX_STRING]; ast_group_t capigroup = 0; unsigned int controller = 0; - int notfound = 1; + unsigned int ccbsnrhandle = 0; cc_verbose(1, 1, VERBOSE_PREFIX_4 "data = %s format=%d\n", (char *)data, format); cc_copy_string(buffer, (char *)data, sizeof(buffer)); - parse_dialstring(buffer, &interface, &dest, ¶m, &ocid); + capi_parse_dialstring(buffer, &interface, &dest, ¶m, &ocid); if ((!interface) || (!dest)) { cc_log(LOG_ERROR, "Syntax error in dialstring. Read the docs!\n"); @@ -2348,6 +1902,16 @@ pbx_capi_request(const char *type, int format, void *data, int *cause) controller = atoi(interface + 5); cc_verbose(1, 1, VERBOSE_PREFIX_4 "capi request controller = %d\n", controller); + } else if (!strncmp(interface, "ccbs", 4)) { + ccbsnrhandle = (unsigned int)strtoul(dest, NULL, 0); + cc_verbose(1, 1, VERBOSE_PREFIX_4 "capi request ccbs handle = %u\n", + ccbsnrhandle); + if ((controller = capi_get_ccbsnrcontroller(ccbsnrhandle)) == 0) { + cc_verbose(2, 0, VERBOSE_PREFIX_3 "didn't find CCBS handle %u\n", + ccbsnrhandle); + *cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL; + return NULL; + } } else { cc_verbose(1, 1, VERBOSE_PREFIX_4 "capi request for interface '%s'\n", interface); @@ -2355,8 +1919,8 @@ pbx_capi_request(const char *type, int format, void *data, int *cause) cc_mutex_lock(&iflock); - for (i = iflist; (i && notfound); i = i->next) { - if ((i->owner) || (i->channeltype != CAPI_CHANNELTYPE_B)) { + for (i = capi_iflist; i; i = i->next) { + if ((i->used) || (i->channeltype != CAPI_CHANNELTYPE_B)) { /* if already in use or no real channel */ continue; } @@ -2388,6 +1952,7 @@ pbx_capi_request(const char *type, int format, void *data, int *cause) } i->PLCI = 0; i->outgoing = 1; /* this is an outgoing line */ + i->ccbsnrhandle = ccbsnrhandle; cc_mutex_unlock(&iflock); return tmp; } @@ -2651,7 +2216,7 @@ static void capi_handle_dtmf_fax(struct capi_pvt *i) struct ast_channel *c = i->owner; if (!c) { - cc_log(LOG_ERROR, "No channel!\n"); + /* no channel, ignore */ return; } @@ -2686,46 +2251,6 @@ static void capi_handle_dtmf_fax(struct capi_pvt *i) return; } -/* - * find the interface (pvt) the PLCI belongs to - */ -static struct capi_pvt *find_interface_by_plci(unsigned int plci) -{ - struct capi_pvt *i; - - if (plci == 0) - return NULL; - - cc_mutex_lock(&iflock); - for (i = iflist; i; i = i->next) { - if (i->PLCI == plci) - break; - } - cc_mutex_unlock(&iflock); - - return i; -} - -/* - * find the interface (pvt) the messagenumber belongs to - */ -static struct capi_pvt *find_interface_by_msgnum(unsigned short msgnum) -{ - struct capi_pvt *i; - - if (msgnum == 0x0000) - return NULL; - - cc_mutex_lock(&iflock); - for (i = iflist; i; i = i->next) { - if ((i->PLCI == 0) && (i->MessageNumber == msgnum)) - break; - } - cc_mutex_unlock(&iflock); - - return i; -} - /* * see if did matches */ @@ -2818,7 +2343,6 @@ static void handle_progress_indicator(_cmsg *CMSG, unsigned int PLCI, struct cap static void start_pbx_on_match(struct capi_pvt *i, unsigned int PLCI, _cword MessageNumber) { struct ast_channel *c; - _cmsg CMSG2; c = i->owner; @@ -2843,11 +2367,11 @@ static void start_pbx_on_match(struct capi_pvt *i, unsigned int PLCI, _cword Mes return; } - switch(search_did(i->owner)) { + switch(search_did(c)) { case 0: /* match */ i->isdnstate |= CAPI_ISDN_STATE_PBX; ast_setstate(c, AST_STATE_RING); - if (ast_pbx_start(i->owner)) { + if (ast_pbx_start(c)) { cc_log(LOG_ERROR, "%s: Unable to start pbx on channel!\n", i->vname); capi_channel_task(c, CAPI_CHANNEL_TASK_HANGUP); @@ -2867,10 +2391,8 @@ static void start_pbx_on_match(struct capi_pvt *i, unsigned int PLCI, _cword Mes i->isdnstate |= CAPI_ISDN_STATE_PBX_DONT; /* don't try again */ cc_log(LOG_NOTICE, "%s: did not find exten for '%s', ignoring call.\n", i->vname, i->dnid); - CONNECT_RESP_HEADER(&CMSG2, capi_ApplID, MessageNumber, 0); - CONNECT_RESP_PLCI(&CMSG2) = PLCI; - CONNECT_RESP_REJECT(&CMSG2) = 1; /* ignore */ - _capi_put_cmsg(&CMSG2); + capi_sendf(NULL, 0, CAPI_CONNECT_RESP, PLCI, MessageNumber, + "w()()()()()", 1 /* ignore */); } return; } @@ -2878,7 +2400,8 @@ static void start_pbx_on_match(struct capi_pvt *i, unsigned int PLCI, _cword Mes /* * Called Party Number via INFO_IND */ -static void capidev_handle_did_digits(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) +static void capidev_handle_did_digits(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, + struct capi_pvt *i, unsigned int skip) { char *did; struct ast_frame fr = { AST_FRAME_NULL, }; @@ -2895,15 +2418,20 @@ static void capidev_handle_did_digits(_cmsg *CMSG, unsigned int PLCI, unsigned i return; } - did = capi_number(INFO_IND_INFOELEMENT(CMSG), 1); + did = capi_number(INFO_IND_INFOELEMENT(CMSG), skip); if ((!(i->isdnstate & CAPI_ISDN_STATE_DID)) && (strlen(i->dnid) && !strcasecmp(i->dnid, did))) { did = NULL; } - if ((did) && (strlen(i->dnid) < (sizeof(i->dnid) - 1))) + if ((did) && (strlen(i->dnid) < (sizeof(i->dnid) - 1))) { + if ((!strlen(i->dnid)) && (INFO_IND_INFONUMBER(CMSG) = 0x002c)) { + /* start of keypad */ + strcat(i->dnid, "K"); + } strcat(i->dnid, did); + } i->isdnstate |= CAPI_ISDN_STATE_DID; @@ -2926,7 +2454,7 @@ static void capidev_handle_did_digits(_cmsg *CMSG, unsigned int PLCI, unsigned i /* * send control according to cause code */ -static void queue_cause_control(struct capi_pvt *i, int control) +void capi_queue_cause_control(struct capi_pvt *i, int control) { struct ast_frame fr = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, }; @@ -2949,25 +2477,14 @@ static void queue_cause_control(struct capi_pvt *i, int control) */ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) { - _cmsg CMSG2; - i->isdnstate |= CAPI_ISDN_STATE_DISCONNECT; - if ((i->isdnstate & CAPI_ISDN_STATE_ECT)) { - cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: Disconnect ECT call\n", - i->vname); - /* we do nothing, just wait for DISCONNECT_IND */ - return; - } - - if (PLCI == i->onholdPLCI) { - cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: Disconnect onhold call\n", + if ((PLCI == i->onholdPLCI) || (i->isdnstate & CAPI_ISDN_STATE_ECT)) { + cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: Disconnect onhold/ECT call\n", i->vname); /* the caller onhold hung up (or ECTed away) */ /* send a disconnect_req , we cannot hangup the channel here!!! */ - DISCONNECT_REQ_HEADER(&CMSG2, capi_ApplID, get_capi_MessageNumber(), 0); - DISCONNECT_REQ_PLCI(&CMSG2) = i->onholdPLCI; - _capi_put_cmsg(&CMSG2); + capi_send_disconnect(PLCI, NULL); return; } @@ -2975,10 +2492,17 @@ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsig if ((i->doB3 != CAPI_B3_ALWAYS) && (i->outgoing == 1)) { cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: Disconnect case 1\n", i->vname); - if (i->state == CAPI_STATE_CONNECTED) - queue_cause_control(i, 0); - else - queue_cause_control(i, 1); + if (i->state == CAPI_STATE_CONNECTED) { + capi_queue_cause_control(i, 0); + } else { + if ((i->isdnstate & CAPI_ISDN_STATE_STAYONLINE)) { + cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: stay-online hangup frame queued.\n", + i->vname); + i->whentoqueuehangup = time(NULL) + 1; + } else { + capi_queue_cause_control(i, 1); + } + } return; } @@ -2987,7 +2511,7 @@ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsig (i->state == CAPI_STATE_CONNECTED) && (i->outgoing == 1)) { cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: Disconnect case 2\n", i->vname); - queue_cause_control(i, 1); + capi_queue_cause_control(i, 1); return; } @@ -3001,12 +2525,10 @@ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsig i->vname); if (i->FaxState & CAPI_FAX_STATE_ACTIVE) { /* in fax mode, we just hangup */ - DISCONNECT_REQ_HEADER(&CMSG2, capi_ApplID, get_capi_MessageNumber(), 0); - DISCONNECT_REQ_PLCI(&CMSG2) = i->PLCI; - _capi_put_cmsg(&CMSG2); + capi_send_disconnect(i->PLCI, NULL); return; } - queue_cause_control(i, 0); + capi_queue_cause_control(i, 0); return; } @@ -3016,7 +2538,7 @@ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsig i->vname); if ((i->state == CAPI_STATE_CONNECTED) && (i->isdnstate & CAPI_ISDN_STATE_B3_UP)) { - queue_cause_control(i, 1); + capi_queue_cause_control(i, 1); return; } /* wait for the 0x001e (PROGRESS), play audio and wait for a timeout from the network */ @@ -3046,7 +2568,7 @@ static void capidev_handle_setup_element(_cmsg *CMSG, unsigned int PLCI, struct } if (i->isdnmode == CAPI_ISDNMODE_DID) { - if (!strlen(i->dnid) && (i->immediate)) { + if (strlen(i->dnid) || (i->immediate)) { start_pbx_on_match(i, PLCI, HEADER_MSGNUM(CMSG)); } } else { @@ -3055,19 +2577,50 @@ static void capidev_handle_setup_element(_cmsg *CMSG, unsigned int PLCI, struct return; } +/* + * Send info elements back to calling channel if in NT-mode + * (this works with peerlink only) + */ +static void capidev_sendback_info(struct capi_pvt *i, _cmsg *CMSG) +{ + struct capi_pvt *i2; + unsigned char fac[CAPI_MAX_FACILITYDATAARRAY_SIZE]; + unsigned char length; + + if (!(i->peer)) + return; + + if (i->peer->tech != &capi_tech) + return; + + i2 = CC_CHANNEL_PVT(i->peer); + + if (!(i2->ntmode)) + return; + + length = INFO_IND_INFOELEMENT(CMSG)[0]; + + fac[0] = length + 2; + fac[1] = (unsigned char) INFO_IND_INFONUMBER(CMSG) & 0xff; + memcpy(&fac[2], &INFO_IND_INFOELEMENT(CMSG)[0], length + 1); + + capi_sendf(NULL, 0, CAPI_INFO_REQ, i2->PLCI, get_capi_MessageNumber(), + "()(()()()s())", + fac + ); +} + /* * CAPI INFO_IND */ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) { - _cmsg CMSG2; struct ast_frame fr = { AST_FRAME_NULL, }; char *p = NULL; char *p2 = NULL; int val = 0; - INFO_RESP_HEADER(&CMSG2, capi_ApplID, HEADER_MSGNUM(CMSG), PLCI); - _capi_put_cmsg(&CMSG2); + capi_sendf(NULL, 0, CAPI_INFO_RESP, PLCI, HEADER_MSGNUM(CMSG), ""); return_on_no_interface("INFO_IND"); @@ -3078,14 +2631,20 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig if (i->owner) { i->owner->hangupcause = INFO_IND_INFOELEMENT(CMSG)[2] & 0x7f; } + capidev_sendback_info(i, CMSG); break; case 0x0014: /* Call State */ cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element CALL STATE %02x\n", i->vname, INFO_IND_INFOELEMENT(CMSG)[1]); + capidev_sendback_info(i, CMSG); break; case 0x0018: /* Channel Identification */ cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element CHANNEL IDENTIFICATION %02x\n", i->vname, INFO_IND_INFOELEMENT(CMSG)[1]); + if (i->doB3 == CAPI_B3_ON_SUCCESS) { + /* try early B3 Connect */ + cc_start_b3(i); + } break; case 0x001c: /* Facility Q.932 */ cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element FACILITY\n", @@ -3095,6 +2654,7 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element PI %02x %02x\n", i->vname, INFO_IND_INFOELEMENT(CMSG)[1], INFO_IND_INFOELEMENT(CMSG)[2]); handle_progress_indicator(CMSG, PLCI, i); + capidev_sendback_info(i, CMSG); break; case 0x0027: { /* Notification Indicator */ char *desc = "?"; @@ -3119,11 +2679,13 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig } cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element NOTIFICATION INDICATOR '%s' (0x%02x)\n", i->vname, desc, INFO_IND_INFOELEMENT(CMSG)[1]); + capidev_sendback_info(i, CMSG); break; } case 0x0028: /* DSP */ cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element DSP\n", i->vname); + capidev_sendback_info(i, CMSG); break; case 0x0029: /* Date/Time */ cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element Date/Time %02d/%02d/%02d %02d:%02d\n", @@ -3131,11 +2693,18 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig INFO_IND_INFOELEMENT(CMSG)[1], INFO_IND_INFOELEMENT(CMSG)[2], INFO_IND_INFOELEMENT(CMSG)[3], INFO_IND_INFOELEMENT(CMSG)[4], INFO_IND_INFOELEMENT(CMSG)[5]); + capidev_sendback_info(i, CMSG); + break; + case 0x002c: /* Keypad facility */ + cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element KEYPAD FACILITY\n", + i->vname); + /* we handle keypad digits as normal digits */ + capidev_handle_did_digits(CMSG, PLCI, NCCI, i, 0); break; case 0x0070: /* Called Party Number */ cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element CALLED PARTY NUMBER\n", i->vname); - capidev_handle_did_digits(CMSG, PLCI, NCCI, i); + capidev_handle_did_digits(CMSG, PLCI, NCCI, i, 1); break; case 0x0074: /* Redirecting Number */ p = capi_number(INFO_IND_INFOELEMENT(CMSG), 3); @@ -3154,6 +2723,7 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig } i->owner->cid.cid_rdnis = strdup(p); } + capidev_sendback_info(i, CMSG); break; case 0x0076: /* Redirection Number */ p = capi_number(INFO_IND_INFOELEMENT(CMSG), 2); @@ -3173,6 +2743,7 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig snprintf(numberbuf, sizeof(numberbuf) - 1, "%s%s", p2, p); pbx_builtin_setvar_helper(i->owner, "REDIRECTIONNUMBER", numberbuf); } + capidev_sendback_info(i, CMSG); break; case 0x00a1: /* Sending Complete */ cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element Sending Complete\n", @@ -3196,6 +2767,7 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig local_queue_frame(i, &fr); if (i->owner) ast_setstate(i->owner, AST_STATE_RINGING); + break; case 0x8002: /* CALL PROCEEDING */ cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element CALL PROCEEDING\n", @@ -3205,6 +2777,7 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig local_queue_frame(i, &fr); break; case 0x8003: /* PROGRESS */ + i->isdnstate |= CAPI_ISDN_STATE_ISDNPROGRESS; cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element PROGRESS\n", i->vname); /* @@ -3222,7 +2795,7 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig if (i->doB3 == CAPI_B3_DONT) { if ((i->owner) && (i->owner->hangupcause == AST_CAUSE_USER_BUSY)) { - queue_cause_control(i, 1); + capi_queue_cause_control(i, 1); break; } } @@ -3287,132 +2860,99 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig i->vname, INFO_IND_INFONUMBER(CMSG), PLCI); break; } + + /* QSIG worker - is only executed, if QSIG is enabled */ + pbx_capi_qsig_handle_info_indication(CMSG, PLCI, NCCI, i); + return; } +/* + * CAPI FACILITY_IND line interconnect + */ +static int handle_facility_indication_line_interconnect( + _cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) +{ + if ((FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x01) && + (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[2] == 0x00)) { + cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: Line Interconnect activated\n", + i->vname); + } + if ((FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x02) && + (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[2] == 0x00) && + (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0] > 8)) { + show_capi_info(i, read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[8])); + } + return 0; +} + +/* + * CAPI FACILITY_IND dtmf received + */ +static int handle_facility_indication_dtmf( + _cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) +{ + struct ast_frame fr = { AST_FRAME_NULL, }; + char dtmf; + unsigned dtmflen = 0; + unsigned dtmfpos = 0; + + if (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0] != (0xff)) { + dtmflen = FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0]; + FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG) += 1; + } else { + dtmflen = read_capi_word(FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG) + 1); + FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG) += 3; + } + while (dtmflen) { + dtmf = (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG))[dtmfpos]; + cc_verbose(1, 1, VERBOSE_PREFIX_4 "%s: c_dtmf = %c\n", + i->vname, dtmf); + if ((!(i->ntmode)) || (i->state == CAPI_STATE_CONNECTED)) { + if ((dtmf == 'X') || (dtmf == 'Y')) { + capi_handle_dtmf_fax(i); + } else { + fr.frametype = AST_FRAME_DTMF; + fr.subclass = dtmf; + local_queue_frame(i, &fr); + } + } + dtmflen--; + dtmfpos++; + } + return 0; +} + /* * CAPI FACILITY_IND */ static void capidev_handle_facility_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) { - _cmsg CMSG2; - struct ast_frame fr = { AST_FRAME_NULL, }; - char dtmf; - unsigned dtmflen; - unsigned dtmfpos = 0; + int resp_done = 0; - FACILITY_RESP_HEADER(&CMSG2, capi_ApplID, HEADER_MSGNUM(CMSG), PLCI); - FACILITY_RESP_FACILITYSELECTOR(&CMSG2) = FACILITY_IND_FACILITYSELECTOR(CMSG); - FACILITY_RESP_FACILITYRESPONSEPARAMETERS(&CMSG2) = FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG); - _capi_put_cmsg(&CMSG2); - - return_on_no_interface("FACILITY_IND"); - - if (FACILITY_IND_FACILITYSELECTOR(CMSG) == FACILITYSELECTOR_LINE_INTERCONNECT) { - /* line interconnect */ - if ((FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x01) && - (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[2] == 0x00)) { - cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: Line Interconnect activated\n", - i->vname); - } - if ((FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x02) && - (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[2] == 0x00) && - (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0] > 8)) { - show_capi_info(i, read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[8])); - } + switch (FACILITY_IND_FACILITYSELECTOR(CMSG)) { + case FACILITYSELECTOR_LINE_INTERCONNECT: + return_on_no_interface("FACILITY_IND LI"); + resp_done = handle_facility_indication_line_interconnect(CMSG, PLCI, NCCI, i); + break; + case FACILITYSELECTOR_DTMF: + return_on_no_interface("FACILITY_IND DTMF"); + resp_done = handle_facility_indication_dtmf(CMSG, PLCI, NCCI, i); + break; + case FACILITYSELECTOR_SUPPLEMENTARY: + resp_done = handle_facility_indication_supplementary(CMSG, PLCI, NCCI, i); + break; + default: + cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: unhandled FACILITY_IND selector %d\n", + (i) ? i->vname:"???", FACILITY_IND_FACILITYSELECTOR(CMSG)); } - - if (FACILITY_IND_FACILITYSELECTOR(CMSG) == FACILITYSELECTOR_DTMF) { - /* DTMF received */ - if (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0] != (0xff)) { - dtmflen = FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0]; - FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG) += 1; - } else { - dtmflen = read_capi_word(FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG) + 1); - FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG) += 3; - } - while (dtmflen) { - dtmf = (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG))[dtmfpos]; - cc_verbose(1, 1, VERBOSE_PREFIX_4 "%s: c_dtmf = %c\n", - i->vname, dtmf); - if ((!(i->ntmode)) || (i->state == CAPI_STATE_CONNECTED)) { - if ((dtmf == 'X') || (dtmf == 'Y')) { - capi_handle_dtmf_fax(i); - } else { - fr.frametype = AST_FRAME_DTMF; - fr.subclass = dtmf; - local_queue_frame(i, &fr); - } - } - dtmflen--; - dtmfpos++; - } - } - - if (FACILITY_IND_FACILITYSELECTOR(CMSG) == FACILITYSELECTOR_SUPPLEMENTARY) { - /* supplementary sservices */ - /* ECT */ - if ( (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x6) && - (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3] == 0x2) ) { - cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x ECT Reason=0x%02x%02x\n", - i->vname, PLCI, - FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5], - FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4]); - show_capi_info(i, read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4])); - } - /* 3PTY */ - if ( (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x7) && - (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3] == 0x2) ) { - cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x 3PTY Reason=0x%02x%02x\n", - i->vname, PLCI, - FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5], - FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4]); - show_capi_info(i, read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4])); - } - - /* RETRIEVE */ - if ( (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x3) && - (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3] == 0x2) ) { - if ((FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5] != 0) || - (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4] != 0)) { - cc_log(LOG_WARNING, "%s: unable to retrieve PLCI=%#x, REASON = 0x%02x%02x\n", - i->vname, PLCI, - FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5], - FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4]); - show_capi_info(i, read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4])); - } else { - /* reason != 0x0000 == problem */ - i->state = CAPI_STATE_CONNECTED; - i->PLCI = i->onholdPLCI; - i->onholdPLCI = 0; - cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x retrieved\n", - i->vname, PLCI); - cc_start_b3(i); - } - } - - /* 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 */ - i->onholdPLCI = 0; - cc_log(LOG_WARNING, "%s: unable to put PLCI=%#x onhold, REASON = 0x%02x%02x, maybe you need to subscribe for this...\n", - i->vname, PLCI, - FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5], - FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4]); - show_capi_info(i, read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4])); - } else { - /* reason = 0x0000 == call on hold */ - i->state = CAPI_STATE_ONHOLD; - cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x put onhold\n", - i->vname, PLCI); - } - } + if (!resp_done) { + capi_sendf(NULL, 0, CAPI_FACILITY_RESP, PLCI, HEADER_MSGNUM(CMSG), + "w()", + FACILITY_IND_FACILITYSELECTOR(CMSG) + ); } - return; } /* @@ -3420,8 +2960,6 @@ static void capidev_handle_facility_indication(_cmsg *CMSG, unsigned int PLCI, u */ static void capidev_handle_data_b3_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) { - _cmsg CMSG2; - struct ast_channel *chan; struct ast_frame fr = { AST_FRAME_NULL, }; unsigned char *b3buf = NULL; int b3len = 0; @@ -3438,15 +2976,11 @@ static void capidev_handle_data_b3_indication(_cmsg *CMSG, unsigned int PLCI, un } /* send a DATA_B3_RESP very quickly to free the buffer in capi */ - DATA_B3_RESP_HEADER(&CMSG2, capi_ApplID, HEADER_MSGNUM(CMSG), 0); - DATA_B3_RESP_NCCI(&CMSG2) = NCCI; - DATA_B3_RESP_DATAHANDLE(&CMSG2) = DATA_B3_IND_DATAHANDLE(CMSG); - _capi_put_cmsg(&CMSG2); + capi_sendf(NULL, 0, CAPI_DATA_B3_RESP, NCCI, HEADER_MSGNUM(CMSG), + "w", DATA_B3_IND_DATAHANDLE(CMSG)); return_on_no_interface("DATA_B3_IND"); - chan = i->owner; - if (i->fFax) { /* we are in fax mode and have a file open */ cc_verbose(6, 1, VERBOSE_PREFIX_3 "%s: DATA_B3_IND (len=%d) Fax\n", @@ -3483,13 +3017,13 @@ static void capidev_handle_data_b3_indication(_cmsg *CMSG, unsigned int PLCI, un i->B3q += b3len; } - if ((i->doES == 1) && (!tcap_is_digital(chan->transfercapability))) { + if ((i->doES == 1) && (!capi_tcap_is_digital(i->transfercapability))) { for (j = 0; j < b3len; j++) { - *(b3buf + j) = reversebits[*(b3buf + j)]; + *(b3buf + j) = capi_reversebits[*(b3buf + j)]; if (capi_capability == AST_FORMAT_ULAW) { - rxavg += abs(capiULAW2INT[ reversebits[*(b3buf + j)]]); + rxavg += abs(capiULAW2INT[ capi_reversebits[*(b3buf + j)]]); } else { - rxavg += abs(capiALAW2INT[ reversebits[*(b3buf + j)]]); + rxavg += abs(capiALAW2INT[ capi_reversebits[*(b3buf + j)]]); } } rxavg = rxavg / j; @@ -3508,13 +3042,13 @@ static void capidev_handle_data_b3_indication(_cmsg *CMSG, unsigned int PLCI, un i->vname, rxavg, txavg); } } else { - if ((i->rxgain == 1.0) || (tcap_is_digital(chan->transfercapability))) { + if ((i->rxgain == 1.0) || (capi_tcap_is_digital(i->transfercapability))) { for (j = 0; j < b3len; j++) { - *(b3buf + j) = reversebits[*(b3buf + j)]; + *(b3buf + j) = capi_reversebits[*(b3buf + j)]; } } else { for (j = 0; j < b3len; j++) { - *(b3buf + j) = reversebits[i->g.rxgains[*(b3buf + j)]]; + *(b3buf + j) = capi_reversebits[i->g.rxgains[*(b3buf + j)]]; } } } @@ -3556,7 +3090,6 @@ static void capidev_send_faxdata(struct capi_pvt *i) #endif unsigned char faxdata[CAPI_MAX_B3_BLOCK_SIZE]; size_t len; - _cmsg CMSG; if (i->NCCI == 0) { cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: send_faxdata on NCCI = 0.\n", @@ -3573,16 +3106,11 @@ static void capidev_send_faxdata(struct capi_pvt *i) if ((i->fFax) && (!(feof(i->fFax)))) { len = fread(faxdata, 1, CAPI_MAX_B3_BLOCK_SIZE, i->fFax); if (len > 0) { - DATA_B3_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - DATA_B3_REQ_NCCI(&CMSG) = i->NCCI; - DATA_B3_REQ_DATALENGTH(&CMSG) = len; - DATA_B3_REQ_FLAGS(&CMSG) = 0; - DATA_B3_REQ_DATAHANDLE(&CMSG) = i->send_buffer_handle; - DATA_B3_REQ_DATA(&CMSG) = faxdata; i->send_buffer_handle++; + capi_sendf(NULL, 0, CAPI_DATA_B3_REQ, i->NCCI, get_capi_MessageNumber(), + "dwww", faxdata, len, i->send_buffer_handle, 0); cc_verbose(5, 1, VERBOSE_PREFIX_3 "%s: send %d fax bytes.\n", i->vname, len); - _capi_put_cmsg(&CMSG); #ifndef CC_AST_HAS_VERSION_1_4 local_queue_frame(i, &fr); #endif @@ -3592,9 +3120,8 @@ static void capidev_send_faxdata(struct capi_pvt *i) /* finished send fax, so we hangup */ cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: completed faxsend.\n", i->vname); - DISCONNECT_B3_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI; - _capi_put_cmsg(&CMSG); + capi_sendf(NULL, 0, CAPI_DISCONNECT_B3_REQ, i->NCCI, get_capi_MessageNumber(), + "()"); } /* @@ -3602,12 +3129,8 @@ static void capidev_send_faxdata(struct capi_pvt *i) */ static void capidev_handle_manufacturer_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) { - _cmsg CMSG2; - - MANUFACTURER_RESP_HEADER(&CMSG2, capi_ApplID, HEADER_MSGNUM(CMSG), 0); - MANUFACTURER_RESP_CONTROLLER(&CMSG2) = MANUFACTURER_IND_CONTROLLER(CMSG); - MANUFACTURER_RESP_MANUID(&CMSG2) = MANUFACTURER_IND_MANUID(CMSG); - _capi_put_cmsg(&CMSG2); + capi_sendf(NULL, 0, CAPI_MANUFACTURER_RESP, MANUFACTURER_IND_CONTROLLER(CMSG), HEADER_MSGNUM(CMSG), + "d", MANUFACTURER_IND_MANUID(CMSG)); return_on_no_interface("MANUFACTURER_IND"); @@ -3622,11 +3145,7 @@ static void capidev_handle_manufacturer_indication(_cmsg *CMSG, unsigned int PLC */ static void capidev_handle_connect_active_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) { - _cmsg CMSG2; - - CONNECT_ACTIVE_RESP_HEADER(&CMSG2, capi_ApplID, HEADER_MSGNUM(CMSG), 0); - CONNECT_ACTIVE_RESP_PLCI(&CMSG2) = PLCI; - _capi_put_cmsg(&CMSG2); + capi_sendf(NULL, 0, CAPI_CONNECT_ACTIVE_RESP, PLCI, HEADER_MSGNUM(CMSG), ""); return_on_no_interface("CONNECT_ACTIVE_IND"); @@ -3656,6 +3175,15 @@ static void capidev_handle_connect_active_indication(_cmsg *CMSG, unsigned int P /* send a CONNECT_B3_REQ */ if (i->outgoing == 1) { /* outgoing call */ + if (i->channeltype == CAPI_CHANNELTYPE_NULL) { + /* NULL-PLCI needs a virtual connection */ + capi_sendf(NULL, 0, CAPI_FACILITY_REQ, PLCI, get_capi_MessageNumber(), + "w(w(d()))", + FACILITYSELECTOR_LINE_INTERCONNECT, + 0x0001, /* CONNECT */ + 0x0000000c /* mask */ + ); + } cc_start_b3(i); } else { /* incoming call */ @@ -3672,16 +3200,13 @@ static void capidev_handle_connect_active_indication(_cmsg *CMSG, unsigned int P */ static void capidev_handle_connect_b3_active_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) { - _cmsg CMSG2; - - /* then send a CONNECT_B3_ACTIVE_RESP */ - CONNECT_B3_ACTIVE_RESP_HEADER(&CMSG2, capi_ApplID, HEADER_MSGNUM(CMSG), 0); - CONNECT_B3_ACTIVE_RESP_NCCI(&CMSG2) = NCCI; - _capi_put_cmsg(&CMSG2); + capi_sendf(NULL, 0, CAPI_CONNECT_B3_ACTIVE_RESP, NCCI, HEADER_MSGNUM(CMSG), ""); return_on_no_interface("CONNECT_ACTIVE_B3_IND"); - capi_controllers[i->controller]->nfreebchannels--; + if (i->channeltype != CAPI_CHANNELTYPE_NULL) { + capi_controllers[i->controller]->nfreebchannels--; + } if (i->state == CAPI_STATE_DISCONNECTING) { cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: CONNECT_B3_ACTIVE_IND during disconnect for NCCI %#x\n", @@ -3713,19 +3238,13 @@ static void capidev_handle_connect_b3_active_indication(_cmsg *CMSG, unsigned in return; } - if (!i->owner) { - cc_log(LOG_ERROR, "%s: No channel for interface!\n", - i->vname); - return; - } - if (i->FaxState & CAPI_FAX_STATE_ACTIVE) { i->FaxState |= CAPI_FAX_STATE_CONN; cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: Fax connection, no EC/DTMF\n", i->vname); } else { - capi_echo_canceller(i->owner, EC_FUNCTION_ENABLE); - capi_detect_dtmf(i->owner, 1); + capi_echo_canceller(i, EC_FUNCTION_ENABLE); + capi_detect_dtmf(i, 1); } if (i->state == CAPI_STATE_CONNECTED) { @@ -3739,11 +3258,7 @@ static void capidev_handle_connect_b3_active_indication(_cmsg *CMSG, unsigned in */ static void capidev_handle_disconnect_b3_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) { - _cmsg CMSG2; - - DISCONNECT_B3_RESP_HEADER(&CMSG2, capi_ApplID, HEADER_MSGNUM(CMSG), 0); - DISCONNECT_B3_RESP_NCCI(&CMSG2) = NCCI; - _capi_put_cmsg(&CMSG2); + capi_sendf(NULL, 0, CAPI_DISCONNECT_B3_RESP, NCCI, HEADER_MSGNUM(CMSG), ""); return_on_no_interface("DISCONNECT_B3_IND"); @@ -3781,16 +3296,19 @@ static void capidev_handle_disconnect_b3_indication(_cmsg *CMSG, unsigned int PL } } - if ((i->state == CAPI_STATE_DISCONNECTING) || - ((!(i->isdnstate & CAPI_ISDN_STATE_B3_SELECT)) && - (i->FaxState & CAPI_FAX_STATE_SENDMODE))) { - /* active disconnect */ - DISCONNECT_REQ_HEADER(&CMSG2, capi_ApplID, get_capi_MessageNumber(), 0); - DISCONNECT_REQ_PLCI(&CMSG2) = PLCI; - _capi_put_cmsg(&CMSG2); + if ((i->state == CAPI_STATE_DISCONNECTING)) { + if (!(i->isdnstate & CAPI_ISDN_STATE_STAYONLINE)) { + /* active disconnect */ + capi_send_disconnect(PLCI, NULL); + } + } else if ((!(i->isdnstate & CAPI_ISDN_STATE_B3_SELECT)) && + (i->FaxState & CAPI_FAX_STATE_SENDMODE)) { + capi_send_disconnect(PLCI, NULL); } - capi_controllers[i->controller]->nfreebchannels++; + if (i->channeltype != CAPI_CHANNELTYPE_NULL) { + capi_controllers[i->controller]->nfreebchannels++; + } } /* @@ -3798,14 +3316,10 @@ static void capidev_handle_disconnect_b3_indication(_cmsg *CMSG, unsigned int PL */ static void capidev_handle_connect_b3_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) { - _cmsg CMSG2; - - /* then send a CONNECT_B3_RESP */ - CONNECT_B3_RESP_HEADER(&CMSG2, capi_ApplID, HEADER_MSGNUM(CMSG), 0); - CONNECT_B3_RESP_NCCI(&CMSG2) = NCCI; - CONNECT_B3_RESP_REJECT(&CMSG2) = 0; - CONNECT_B3_RESP_NCPI(&CMSG2) = capi_rtp_ncpi(i); - _capi_put_cmsg(&CMSG2); + capi_sendf(NULL, 0, CAPI_CONNECT_B3_RESP, NCCI, HEADER_MSGNUM(CMSG), + "ws", + 0x0000, /* accept */ + capi_rtp_ncpi(i)); return_on_no_interface("CONNECT_B3_IND"); @@ -3820,13 +3334,10 @@ static void capidev_handle_connect_b3_indication(_cmsg *CMSG, unsigned int PLCI, */ static void capidev_handle_disconnect_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) { - _cmsg CMSG2; struct ast_frame fr = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, }; int state; - DISCONNECT_RESP_HEADER(&CMSG2, capi_ApplID, HEADER_MSGNUM(CMSG) , 0); - DISCONNECT_RESP_PLCI(&CMSG2) = PLCI; - _capi_put_cmsg(&CMSG2); + capi_sendf(NULL, 0, CAPI_DISCONNECT_RESP, PLCI, HEADER_MSGNUM(CMSG), ""); show_capi_info(i, DISCONNECT_IND_REASON(CMSG)); @@ -3891,9 +3402,9 @@ static void capidev_handle_disconnect_indication(_cmsg *CMSG, unsigned int PLCI, static void capidev_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt **interface) { struct capi_pvt *i; - _cmsg CMSG2; char *DNID; char *CID; + char *KEYPAD = NULL; int callernplan = 0, callednplan = 0; int controller = 0; char *msn; @@ -3915,10 +3426,20 @@ static void capidev_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, un return; } + if (CONNECT_IND_KEYPADFACILITY(CMSG)) { + KEYPAD = capi_number(CONNECT_IND_KEYPADFACILITY(CMSG), 0); + } DNID = capi_number(CONNECT_IND_CALLEDPARTYNUMBER(CMSG), 1); if (!DNID) { - DNID = emptydnid; + if (!KEYPAD) { + DNID = emptydnid; + } else { + /* if keypad is signaled instead, use it as DID with 'K' */ + DNID = alloca(AST_MAX_EXTENSION); + snprintf(DNID, AST_MAX_EXTENSION -1, "K%s", KEYPAD); + } } + if (CONNECT_IND_CALLEDPARTYNUMBER(CMSG)[0] > 1) { callednplan = (CONNECT_IND_CALLEDPARTYNUMBER(CMSG)[1] & 0x7f); } @@ -3933,15 +3454,15 @@ static void capidev_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, un cc_verbose(1, 1, VERBOSE_PREFIX_3 "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)) { + if (CONNECT_IND_BCHANNELINFORMATION(CMSG) && (CONNECT_IND_BCHANNELINFORMATION(CMSG)[0] > 0)) { bchannelinfo[0] = CONNECT_IND_BCHANNELINFORMATION(CMSG)[1] + '0'; } /* well...somebody is calling us. let's set up a channel */ cc_mutex_lock(&iflock); - for (i = iflist; i; i = i->next) { - if (i->owner) { - /* has already owner */ + for (i = capi_iflist; i; i = i->next) { + if (i->used) { + /* is already used */ continue; } if (i->controller != controller) { @@ -4005,8 +3526,9 @@ static void capidev_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, un interface_cleanup(i); break; } - i->owner->transfercapability = cip2tcap(i->cip); - if (tcap_is_digital(i->owner->transfercapability)) { + i->transfercapability = cip2tcap(i->cip); + i->owner->transfercapability = i->transfercapability; + if (capi_tcap_is_digital(i->transfercapability)) { i->bproto = CC_BPROTO_TRANSPARENT; } i->owner->cid.cid_pres = callpres; @@ -4017,7 +3539,7 @@ static void capidev_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, un cc_mutex_unlock(&iflock); cc_mutex_lock(&i->lock); - pbx_builtin_setvar_helper(i->owner, "TRANSFERCAPABILITY", transfercapability2str(i->owner->transfercapability)); + pbx_builtin_setvar_helper(i->owner, "TRANSFERCAPABILITY", transfercapability2str(i->transfercapability)); pbx_builtin_setvar_helper(i->owner, "BCHANNELINFO", bchannelinfo); sprintf(buffer, "%d", callednplan); pbx_builtin_setvar_helper(i->owner, "CALLEDTON", buffer); @@ -4035,9 +3557,8 @@ static void capidev_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, un pbx_builtin_setvar_helper(i->owner, "SECONDCALLERID", buffer); */ - if (i->qsigfeat != QSIG_DISABLED) { - cc_qsig_handle_capiind(CONNECT_IND_FACILITYDATAARRAY(CMSG), i); - } + /* Handle QSIG informations, if any */ + cc_qsig_handle_capiind(CONNECT_IND_FACILITYDATAARRAY(CMSG), i); if ((i->isdnmode == CAPI_ISDNMODE_MSN) && (i->immediate)) { /* if we don't want to wait for SETUP/SENDING-COMPLETE in MSN mode */ @@ -4054,53 +3575,45 @@ static void capidev_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, un cc_log(LOG_WARNING, "did not find device for msn = %s\n", DNID); } - CONNECT_RESP_HEADER(&CMSG2, capi_ApplID, HEADER_MSGNUM(CMSG), 0); - CONNECT_RESP_PLCI(&CMSG2) = CONNECT_IND_PLCI(CMSG); - CONNECT_RESP_REJECT(&CMSG2) = 1; /* ignore */ - _capi_put_cmsg(&CMSG2); + capi_sendf(NULL, 0, CAPI_CONNECT_RESP, CONNECT_IND_PLCI(CMSG), HEADER_MSGNUM(CMSG), + "w()()()()()", 1 /* ignore */); return; } /* * CAPI FACILITY_CONF */ -static void capidev_handle_facility_confirmation(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) +static void capidev_handle_facility_confirmation(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt **i) { int selector; - if (i == NULL) - return; - selector = FACILITY_CONF_FACILITYSELECTOR(CMSG); + if (selector == FACILITYSELECTOR_SUPPLEMENTARY) { + handle_facility_confirmation_supplementary(CMSG, PLCI, NCCI, i); + return; + } + + if (*i == NULL) + return; + if (selector == FACILITYSELECTOR_DTMF) { cc_verbose(2, 1, VERBOSE_PREFIX_4 "%s: DTMF conf(PLCI=%#x)\n", - i->vname, PLCI); + (*i)->vname, PLCI); return; } - if (selector == i->ecSelector) { + if (selector == (*i)->ecSelector) { if (FACILITY_CONF_INFO(CMSG)) { cc_verbose(2, 0, VERBOSE_PREFIX_3 "%s: Error setting up echo canceller (PLCI=%#x)\n", - i->vname, PLCI); + (*i)->vname, PLCI); return; } if (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[1] == EC_FUNCTION_DISABLE) { cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: Echo canceller successfully disabled (PLCI=%#x)\n", - i->vname, PLCI); + (*i)->vname, PLCI); } else { cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: Echo canceller successfully set up (PLCI=%#x)\n", - i->vname, PLCI); - } - return; - } - if (selector == 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))) { - cc_verbose(2, 0, VERBOSE_PREFIX_3 "%s: Call on hold (PLCI=%#x)\n", - i->vname, PLCI); + (*i)->vname, PLCI); } return; } @@ -4109,18 +3622,18 @@ static void capidev_handle_facility_confirmation(_cmsg *CMSG, unsigned int PLCI, (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[2] == 0x0)) { /* enable */ if (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[0] > 12) { - show_capi_info(i, read_capi_word(&FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[12])); + show_capi_info(*i, read_capi_word(&FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[12])); } } else { /* disable */ if (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[0] > 12) { - show_capi_info(i, read_capi_word(&FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[12])); + show_capi_info(*i, read_capi_word(&FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[12])); } } return; } cc_log(LOG_ERROR, "%s: unhandled FACILITY_CONF 0x%x\n", - i->vname, FACILITY_CONF_FACILITYSELECTOR(CMSG)); + (*i)->vname, FACILITY_CONF_FACILITYSELECTOR(CMSG)); } /* @@ -4194,6 +3707,39 @@ static void capidev_post_handling(struct capi_pvt *i, _cmsg *CMSG) } } +/* + * handle CONNECT_CONF or FACILITY_CONF(CCBS call) + */ +void capidev_handle_connection_conf(struct capi_pvt **i, unsigned int PLCI, + unsigned short wInfo, unsigned short wMsgNum) +{ + struct capi_pvt *ii; + struct ast_frame fr = { AST_FRAME_CONTROL, AST_CONTROL_BUSY, }; + + if (*i) { + cc_log(LOG_ERROR, "CAPI: CONNECT_CONF for already " + "defined interface received\n"); + return; + } + *i = capi_find_interface_by_msgnum(wMsgNum); + ii = *i; + if (ii == NULL) { + return; + } + cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: received CONNECT_CONF PLCI = %#x\n", + ii->vname, PLCI); + cc_mutex_lock(&ii->lock); + if (wInfo == 0) { + ii->PLCI = PLCI; + } else { + /* error in connect, so set correct state and signal busy */ + ii->state = CAPI_STATE_DISCONNECTED; + if (ii->owner) { + local_queue_frame(ii, &fr); + } + } +} + /* * handle CAPI msg */ @@ -4204,7 +3750,7 @@ static void capidev_handle_msg(_cmsg *CMSG) unsigned short wCmd = HEADER_CMD(CMSG); unsigned short wMsgNum = HEADER_MSGNUM(CMSG); unsigned short wInfo = 0xffff; - struct capi_pvt *i = find_interface_by_plci(PLCI); + struct capi_pvt *i = capi_find_interface_by_plci(PLCI); if ((wCmd == CAPI_P_IND(DATA_B3)) || (wCmd == CAPI_P_CONF(DATA_B3))) { @@ -4260,28 +3806,11 @@ static void capidev_handle_msg(_cmsg *CMSG) case CAPI_P_CONF(FACILITY): wInfo = FACILITY_CONF_INFO(CMSG); - capidev_handle_facility_confirmation(CMSG, PLCI, NCCI, i); + capidev_handle_facility_confirmation(CMSG, PLCI, NCCI, &i); break; case CAPI_P_CONF(CONNECT): wInfo = CONNECT_CONF_INFO(CMSG); - if (i) { - cc_log(LOG_ERROR, "CAPI: CONNECT_CONF for already " - "defined interface received\n"); - break; - } - i = find_interface_by_msgnum(wMsgNum); - if ((i == NULL) || (!i->owner)) - break; - cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: received CONNECT_CONF PLCI = %#x\n", - i->vname, PLCI); - if (wInfo == 0) { - i->PLCI = PLCI; - } else { - /* error in connect, so set correct state and signal busy */ - i->state = CAPI_STATE_DISCONNECTED; - struct ast_frame fr = { AST_FRAME_CONTROL, AST_CONTROL_BUSY, }; - local_queue_frame(i, &fr); - } + capidev_handle_connection_conf(&i, PLCI, wInfo, wMsgNum); break; case CAPI_P_CONF(CONNECT_B3): wInfo = CONNECT_B3_CONF_INFO(CMSG); @@ -4314,8 +3843,8 @@ static void capidev_handle_msg(_cmsg *CMSG) cc_start_b3(i); } if ((i->owner) && (i->FaxState & CAPI_FAX_STATE_ACTIVE)) { - capi_echo_canceller(i->owner, EC_FUNCTION_DISABLE); - capi_detect_dtmf(i->owner, 0); + capi_echo_canceller(i, EC_FUNCTION_DISABLE); + capi_detect_dtmf(i, 0); } } else { i->isdnstate &= ~CAPI_ISDN_STATE_B3_PEND; @@ -4379,11 +3908,9 @@ static void capidev_handle_msg(_cmsg *CMSG) static int pbx_capi_call_deflect(struct ast_channel *c, char *param) { struct capi_pvt *i = CC_CHANNEL_PVT(c); - _cmsg CMSG; - char fac[64]; - int res = 0; char *number; int numberlen; + char facnumber[32]; if (!param) { cc_log(LOG_WARNING, "capi deflection requires an argument (destination phone number)\n"); @@ -4418,34 +3945,48 @@ static int pbx_capi_call_deflect(struct ast_channel *c, char *param) if (i->state != CAPI_STATE_ALERTING) { pbx_capi_alert(c); } - - fac[0] = 0x0a + numberlen; /* length */ - fac[1] = 0x0d; /* call deflection */ - fac[2] = 0x00; - fac[3] = 0x07 + numberlen; /* struct len */ - fac[4] = 0x01; /* display of own address allowed */ - fac[5] = 0x00; - fac[6] = 0x03 + numberlen; - fac[7] = 0x00; /* type of facility number */ - fac[8] = 0x00; /* number plan */ - fac[9] = 0x00; /* presentation allowed */ - fac[10 + numberlen] = 0x00; /* subaddress len */ - memcpy((unsigned char *)fac + 10, number, numberlen); - - FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(),0); - FACILITY_REQ_PLCI(&CMSG) = i->PLCI; - FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_SUPPLEMENTARY; - FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)&fac; + facnumber[0] = 0x03 + numberlen; + facnumber[1] = 0x00; /* type of facility number */ + facnumber[2] = 0x00; /* number plan */ + facnumber[3] = 0x00; /* presentation allowed */ + memcpy(&facnumber[4], number, numberlen); - _capi_put_cmsg_wait_conf(i, &CMSG); + capi_sendf(i, 1, CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(), + "w(w(ws()))", + FACILITYSELECTOR_SUPPLEMENTARY, + 0x000d, /* call deflection */ + 0x0001, /* display of own address allowed */ + &facnumber[0] + ); cc_mutex_unlock(&i->lock); cc_verbose(2, 1, VERBOSE_PREFIX_3 "%s: sent FACILITY_REQ for CD PLCI = %#x\n", i->vname, i->PLCI); - return(res); + return 0; +} + +/* + * store the peer for future actions + */ +static int pbx_capi_peer_link(struct ast_channel *c, char *param) +{ + char buffer[32]; + int id; + + id = cc_add_peer_link_id(c); + + if (id >= 0) { + snprintf(buffer, sizeof(buffer) - 1, "%d", id); + pbx_builtin_setvar_helper(c, "_CAPIPEERLINKID", buffer); + } + + cc_verbose(2, 1, VERBOSE_PREFIX_3 "Added %s as CAPI peer link.\n", + c->name); + + return 0; } /* @@ -4454,8 +3995,6 @@ static int pbx_capi_call_deflect(struct ast_channel *c, char *param) static int pbx_capi_retrieve(struct ast_channel *c, char *param) { struct capi_pvt *i = CC_CHANNEL_PVT(c); - _cmsg CMSG; - char fac[4]; unsigned int plci = 0; if (c->tech == &capi_tech) { @@ -4467,7 +4006,7 @@ static int pbx_capi_retrieve(struct ast_channel *c, char *param) if (param) { plci = (unsigned int)strtoul(param, NULL, 0); cc_mutex_lock(&iflock); - for (i = iflist; i; i = i->next) { + for (i = capi_iflist; i; i = i->next) { if (i->onholdPLCI == plci) break; } @@ -4506,21 +4045,23 @@ static int pbx_capi_retrieve(struct ast_channel *c, char *param) return -1; } - fac[0] = 3; /* len */ - fac[1] = 0x03; /* retrieve */ - fac[2] = 0x00; - fac[3] = 0; + if (param != NULL) + cc_mutex_lock(&i->lock); - FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(),0); - FACILITY_REQ_PLCI(&CMSG) = plci; - FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_SUPPLEMENTARY; - FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)&fac; + capi_sendf(i, (param == NULL) ? 0:1, CAPI_FACILITY_REQ, plci, get_capi_MessageNumber(), + "w(w())", + FACILITYSELECTOR_SUPPLEMENTARY, + 0x0003 /* retrieve */ + ); + + i->isdnstate &= ~CAPI_ISDN_STATE_HOLD; + + if (param != NULL) + cc_mutex_unlock(&i->lock); - _capi_put_cmsg(&CMSG); cc_verbose(2, 1, VERBOSE_PREFIX_4 "%s: sent RETRIEVE for PLCI=%#x\n", i->vname, plci); - i->isdnstate &= ~CAPI_ISDN_STATE_HOLD; pbx_builtin_setvar_helper(i->owner, "_CALLERHOLDID", NULL); return 0; @@ -4533,17 +4074,19 @@ static int pbx_capi_ect(struct ast_channel *c, char *param) { struct capi_pvt *i = CC_CHANNEL_PVT(c); struct capi_pvt *ii = NULL; - _cmsg CMSG; - char fac[8]; const char *id; unsigned int plci = 0; + unsigned int ectplci; + char *holdid; if ((id = pbx_builtin_getvar_helper(c, "CALLERHOLDID"))) { plci = (unsigned int)strtoul(id, NULL, 0); } - if (param) { - plci = (unsigned int)strtoul(param, NULL, 0); + holdid = strsep(¶m, "|"); + + if (holdid) { + plci = (unsigned int)strtoul(holdid, NULL, 0); } if (!plci) { @@ -4552,7 +4095,7 @@ static int pbx_capi_ect(struct ast_channel *c, char *param) } cc_mutex_lock(&iflock); - for (ii = iflist; ii; ii = ii->next) { + for (ii = capi_iflist; ii; ii = ii->next) { if (ii->onholdPLCI == plci) break; } @@ -4564,8 +4107,13 @@ static int pbx_capi_ect(struct ast_channel *c, char *param) return -1; } + ectplci = plci; + if ((param) && (*param == 'x')) { + ectplci = i->PLCI; + } + cc_verbose(2, 1, VERBOSE_PREFIX_4 "%s: using PLCI=%#x for ECT\n", - i->vname, plci); + i->vname, ectplci); if (!(capi_controllers[i->controller]->ECT)) { cc_log(LOG_WARNING, "%s: ECT for %s not supported by controller.\n", @@ -4587,21 +4135,16 @@ static int pbx_capi_ect(struct ast_channel *c, char *param) return -1; } - fac[0] = 7; /* len */ - fac[1] = 0x06; /* ECT (function) */ - fac[2] = 0x00; - fac[3] = 4; /* len / sservice specific parameter , cstruct */ - write_capi_dword(&(fac[4]), plci); - - FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - FACILITY_REQ_CONTROLLER(&CMSG) = i->controller; - FACILITY_REQ_PLCI(&CMSG) = plci; /* implicit ECT */ - FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_SUPPLEMENTARY; - FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)&fac; - cc_mutex_lock(&ii->lock); - _capi_put_cmsg_wait_conf(ii, &CMSG); - + + /* implicit ECT */ + capi_sendf(ii, 1, CAPI_FACILITY_REQ, ectplci, get_capi_MessageNumber(), + "w(w(d))", + FACILITYSELECTOR_SUPPLEMENTARY, + 0x0006, /* ECT */ + plci + ); + ii->isdnstate &= ~CAPI_ISDN_STATE_HOLD; ii->isdnstate |= CAPI_ISDN_STATE_ECT; i->isdnstate |= CAPI_ISDN_STATE_ECT; @@ -4609,7 +4152,7 @@ static int pbx_capi_ect(struct ast_channel *c, char *param) cc_mutex_unlock(&ii->lock); cc_verbose(2, 1, VERBOSE_PREFIX_4 "%s: sent ECT for PLCI=%#x to PLCI=%#x\n", - i->vname, plci, i->PLCI); + i->vname, plci, ectplci); return 0; } @@ -4620,9 +4163,7 @@ static int pbx_capi_ect(struct ast_channel *c, char *param) static int pbx_capi_hold(struct ast_channel *c, char *param) { struct capi_pvt *i = CC_CHANNEL_PVT(c); - _cmsg CMSG; char buffer[16]; - char fac[4]; /* TODO: support holdtype notify */ @@ -4643,23 +4184,22 @@ static int pbx_capi_hold(struct ast_channel *c, char *param) return 0; } - fac[0] = 3; /* len */ - fac[1] = 0x02; /* this is a HOLD up */ - fac[2] = 0x00; - fac[3] = 0; + cc_mutex_lock(&i->lock); - FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(),0); - FACILITY_REQ_PLCI(&CMSG) = i->PLCI; - FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_SUPPLEMENTARY; - FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)&fac; - - _capi_put_cmsg(&CMSG); - cc_verbose(2, 1, VERBOSE_PREFIX_4 "%s: sent HOLD for PLCI=%#x\n", - i->vname, i->PLCI); + capi_sendf(i, 1, CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(), + "w(w())", + FACILITYSELECTOR_SUPPLEMENTARY, + 0x0002 /* hold */ + ); i->onholdPLCI = i->PLCI; i->isdnstate |= CAPI_ISDN_STATE_HOLD; + cc_mutex_unlock(&i->lock); + + cc_verbose(2, 1, VERBOSE_PREFIX_4 "%s: sent HOLD for PLCI=%#x\n", + i->vname, i->PLCI); + snprintf(buffer, sizeof(buffer) - 1, "%d", i->PLCI); if (param) { pbx_builtin_setvar_helper(i->owner, param, buffer); @@ -4675,8 +4215,6 @@ static int pbx_capi_hold(struct ast_channel *c, char *param) static int pbx_capi_malicious(struct ast_channel *c, char *param) { struct capi_pvt *i = CC_CHANNEL_PVT(c); - _cmsg CMSG; - char fac[4]; if (!(capi_controllers[i->controller]->MCID)) { cc_log(LOG_NOTICE, "%s: MCID for %s not supported by controller.\n", @@ -4684,18 +4222,14 @@ static int pbx_capi_malicious(struct ast_channel *c, char *param) return -1; } - fac[0] = 3; /* len */ - fac[1] = 0x0e; /* MCID */ - fac[2] = 0x00; - fac[3] = 0; - - FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(),0); - FACILITY_REQ_PLCI(&CMSG) = i->PLCI; - FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_SUPPLEMENTARY; - FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)&fac; - cc_mutex_lock(&i->lock); - _capi_put_cmsg_wait_conf(i, &CMSG); + + capi_sendf(i, 1, CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(), + "w(w())", + FACILITYSELECTOR_SUPPLEMENTARY, + 0x000e /* MCID */ + ); + cc_mutex_unlock(&i->lock); cc_verbose(2, 1, VERBOSE_PREFIX_4 "%s: sent MCID for PLCI=%#x\n", @@ -4717,9 +4251,9 @@ static int pbx_capi_echocancel(struct ast_channel *c, char *param) } if (ast_true(param)) { i->doEC = 1; - capi_echo_canceller(c, EC_FUNCTION_ENABLE); + capi_echo_canceller(i, EC_FUNCTION_ENABLE); } else if (ast_false(param)) { - capi_echo_canceller(c, EC_FUNCTION_DISABLE); + capi_echo_canceller(i, EC_FUNCTION_DISABLE); i->doEC = 0; } else { cc_log(LOG_WARNING, "Parameter for echocancel invalid.\n"); @@ -4780,6 +4314,46 @@ static int pbx_capi_holdtype(struct ast_channel *c, char *param) return 0; } +/* + * send the disconnect commands to capi + */ +static void capi_disconnect(struct capi_pvt *i) +{ + cc_mutex_lock(&i->lock); + + i->isdnstate &= ~CAPI_ISDN_STATE_STAYONLINE; + if ((i->isdnstate & CAPI_ISDN_STATE_B3_UP)) { + cc_disconnect_b3(i, 0); + } else { + capi_send_disconnect(i->PLCI, NULL); + } + + cc_mutex_unlock(&i->lock); +} + +/* + * really hangup a channel if the stay-online mode was activated + */ +static int pbx_capi_realhangup(struct ast_channel *c, char *param) +{ + struct capi_pvt *i; + + cc_mutex_lock(&iflock); + for (i = capi_iflist; i; i = i->next) { + if (i->peer == c) + break; + } + cc_mutex_unlock(&iflock); + + if ((i) && (i->state == CAPI_STATE_DISCONNECTING)) { + cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: capi command hangup PLCI=0x%#x.\n", + i->vname, i->PLCI); + capi_disconnect(i); + } + + return 0; +} + /* * set early-B3 (progress) for incoming connections * (only for NT mode) @@ -4787,6 +4361,7 @@ static int pbx_capi_holdtype(struct ast_channel *c, char *param) static int pbx_capi_signal_progress(struct ast_channel *c, char *param) { struct capi_pvt *i = CC_CHANNEL_PVT(c); + unsigned char fac[] = "\x04\x1e\x02\x82\x88"; /* In-Band info available */ if ((i->state != CAPI_STATE_DID) && (i->state != CAPI_STATE_INCALL)) { cc_log(LOG_DEBUG, "wrong channel state to signal PROGRESS\n"); @@ -4810,6 +4385,12 @@ static int pbx_capi_signal_progress(struct ast_channel *c, char *param) cc_select_b(i, NULL); + /* send facility for Progress 'In-Band info available' */ + capi_sendf(NULL, 0, CAPI_INFO_REQ, i->PLCI, get_capi_MessageNumber(), + "()(()()()s())", + fac + ); + return 0; } @@ -4821,8 +4402,6 @@ static int pbx_capi_3pty_begin(struct ast_channel *c, char *param) { struct capi_pvt *i = CC_CHANNEL_PVT(c); struct capi_pvt *ii = NULL; - _cmsg CMSG; - char fac[8]; const char *id; unsigned int plci = 0; @@ -4840,7 +4419,7 @@ static int pbx_capi_3pty_begin(struct ast_channel *c, char *param) } cc_mutex_lock(&iflock); - for (ii = iflist; ii; ii = ii->next) { + for (ii = capi_iflist; ii; ii = ii->next) { if (ii->onholdPLCI == plci) break; } @@ -4871,20 +4450,14 @@ static int pbx_capi_3pty_begin(struct ast_channel *c, char *param) return 0; } - fac[0] = 7; /* len */ - fac[1] = 0x07; /* this is a 3PTY Begin */ - fac[2] = 0x00; - fac[3] = 4; /* length of PLCI parameter (DWORD) */ - write_capi_dword(&(fac[4]), plci); - - FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - FACILITY_REQ_CONTROLLER(&CMSG) = i->controller; - FACILITY_REQ_PLCI(&CMSG) = plci; /* implicit 3PTY */ - FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_SUPPLEMENTARY; - FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)&fac; - cc_mutex_lock(&ii->lock); - _capi_put_cmsg_wait_conf(ii, &CMSG); + + capi_sendf(ii, 1, CAPI_FACILITY_REQ, plci, get_capi_MessageNumber(), + "w(w(d))", + FACILITYSELECTOR_SUPPLEMENTARY, + 0x0007, /* 3PTY begin */ + plci + ); ii->isdnstate &= ~CAPI_ISDN_STATE_HOLD; ii->isdnstate |= CAPI_ISDN_STATE_3PTY; @@ -4898,33 +4471,6 @@ static int pbx_capi_3pty_begin(struct ast_channel *c, char *param) return 0; } -/* - * Initiate a QSIG Call Transfer - */ -static int pbx_capi_qsig_ct(struct ast_channel *c, char *param) -{ - unsigned char fac[CAPI_MAX_FACILITYDATAARRAY_SIZE]; - _cmsg CMSG; - struct capi_pvt *i = CC_CHANNEL_PVT(c); - - if (!param) { /* no data implies no Calling Number and Destination Number */ - cc_log(LOG_WARNING, "capi qsig_ct requires source number and destination number\n"); - return -1; - } - - cc_qsig_do_facility(fac, c, param, 99); - - INFO_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(),0); - INFO_REQ_PLCI(&CMSG) = i->PLCI; - // / *INFO_REQ_FACILITYSELECTOR(&CMSG) = 0;* / - INFO_REQ_FACILITYDATAARRAY(&CMSG) = fac; - - _capi_put_cmsg(&CMSG); - - - return 0; -} - /* * struct of capi commands */ @@ -4933,6 +4479,7 @@ static struct capicommands_s { int (*cmd)(struct ast_channel *, char *); int capionly; } capicommands[] = { + { "peerlink", pbx_capi_peer_link, 0 }, { "progress", pbx_capi_signal_progress, 1 }, { "deflect", pbx_capi_call_deflect, 1 }, { "receivefax", pbx_capi_receive_fax, 1 }, @@ -4945,8 +4492,16 @@ static struct capicommands_s { { "retrieve", pbx_capi_retrieve, 0 }, { "ect", pbx_capi_ect, 1 }, { "3pty_begin", pbx_capi_3pty_begin, 1 }, - { "qsig_ct", pbx_capi_qsig_ct, 1 }, - { NULL, NULL, 0 } + { "ccbs", pbx_capi_ccbs, 0 }, + { "ccbsstop", pbx_capi_ccbsstop, 0 }, + { "ccpartybusy", pbx_capi_ccpartybusy, 0 }, + { "chat", pbx_capi_chat, 0 }, + { "hangup", pbx_capi_realhangup, 0 }, + { "qsig_ssct", pbx_capi_qsig_ssct, 1 }, + { "qsig_ct", pbx_capi_qsig_ct, 1 }, + { "qsig_callmark",pbx_capi_qsig_callmark, 1 }, + { "qsig_getplci", pbx_capi_qsig_getplci, 1 }, + { NULL, NULL, 0 } }; /* @@ -5029,7 +4584,6 @@ static int pbx_capi_indicate(struct ast_channel *c, int condition) #endif { struct capi_pvt *i = CC_CHANNEL_PVT(c); - _cmsg CMSG; int ret = -1; if (i == NULL) { @@ -5062,10 +4616,8 @@ static int pbx_capi_indicate(struct ast_channel *c, int condition) i->vname, c->name); if ((i->state == CAPI_STATE_ALERTING) || (i->state == CAPI_STATE_DID) || (i->state == CAPI_STATE_INCALL)) { - CONNECT_RESP_HEADER(&CMSG, capi_ApplID, i->MessageNumber, 0); - CONNECT_RESP_PLCI(&CMSG) = i->PLCI; - CONNECT_RESP_REJECT(&CMSG) = 3; - _capi_put_cmsg(&CMSG); + capi_sendf(NULL, 0, CAPI_CONNECT_RESP, i->PLCI, i->MessageNumber, + "w()()()()()", 3); ret = 0; } if ((i->isdnstate & CAPI_ISDN_STATE_HOLD)) @@ -5076,10 +4628,8 @@ static int pbx_capi_indicate(struct ast_channel *c, int condition) i->vname, c->name); if ((i->state == CAPI_STATE_ALERTING) || (i->state == CAPI_STATE_DID) || (i->state == CAPI_STATE_INCALL)) { - CONNECT_RESP_HEADER(&CMSG, capi_ApplID, i->MessageNumber, 0); - CONNECT_RESP_PLCI(&CMSG) = i->PLCI; - CONNECT_RESP_REJECT(&CMSG) = 4; - _capi_put_cmsg(&CMSG); + capi_sendf(NULL, 0, CAPI_CONNECT_RESP, i->PLCI, i->MessageNumber, + "w()()()()()", 4); ret = 0; } if ((i->isdnstate & CAPI_ISDN_STATE_HOLD)) @@ -5152,12 +4702,31 @@ static int pbx_capi_devicestate(void *data) return res; } +static void capi_do_interface_task(void) +{ + if (interface_for_task == NULL) + return; + + switch (interface_task) { + case CAPI_INTERFACE_TASK_NULLIFREMOVE: + /* remove an old null-plci interface */ + capi_remove_nullif(interface_for_task); + break; + default: + /* nothing to do */ + break; + } + + interface_for_task = NULL; + interface_task = CAPI_INTERFACE_TASK_NONE; +} + static void capi_do_channel_task(void) { if (chan_for_task == NULL) return; - switch(channel_task) { + switch (channel_task) { case CAPI_CHANNEL_TASK_HANGUP: /* deferred (out of lock) hangup */ ast_hangup(chan_for_task); @@ -5191,6 +4760,35 @@ static void capi_do_channel_task(void) channel_task = CAPI_CHANNEL_TASK_NONE; } +/* + * check for tasks every second + */ +static void capidev_run_secondly(time_t now) +{ + struct capi_pvt *i; + + /* check for channels to hangup (timeout) */ + cc_mutex_lock(&iflock); + for (i = capi_iflist; i; i = i->next) { + if (i->used == NULL) { + continue; + } + if ((i->whentohangup) && (i->whentohangup < now)) { + cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: stay-online timeout, hanging up.\n", + i->vname); + i->whentohangup = 0; + capi_disconnect(i); + } + if ((i->whentoqueuehangup) && (i->whentoqueuehangup < now)) { + cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: stay-online queue-hangup.\n", + i->vname); + capi_queue_cause_control(i, 1); + i->whentoqueuehangup = 0; + } + } + cc_mutex_unlock(&iflock); +} + /* * module stuff, monitor... */ @@ -5198,12 +4796,17 @@ static void *capidev_loop(void *data) { unsigned int Info; _cmsg monCMSG; + time_t lastcall = 0; + time_t newtime; + cc_log(LOG_NOTICE, "Started CAPI monitor-thread.\n"); + for (/* for ever */;;) { switch(Info = capidev_check_wait_get_cmsg(&monCMSG)) { case 0x0000: capidev_handle_msg(&monCMSG); capi_do_channel_task(); + capi_do_interface_task(); break; case 0x1104: /* CAPI queue is empty */ @@ -5219,6 +4822,11 @@ static void *capidev_loop(void *data) /* something is wrong! */ break; } /* switch */ + newtime = time(NULL); + if (lastcall != newtime) { + lastcall = newtime; + capidev_run_secondly(newtime); + } } /* for */ /* never reached */ @@ -5228,7 +4836,7 @@ static void *capidev_loop(void *data) /* * GAIN */ -static void capi_gains(struct cc_capi_gains *g, float rxgain, float txgain) +void capi_gains(struct cc_capi_gains *g, float rxgain, float txgain) { int i = 0; int x = 0; @@ -5368,10 +4976,11 @@ int mkif(struct cc_capi_conf *conf) tmp->doDTMF = conf->softdtmf; tmp->capability = conf->capability; - tmp->qsigfeat = conf->qsigfeat; - - tmp->next = iflist; /* prepend */ - iflist = tmp; + /* Initialize QSIG code */ + cc_qsig_interface_init(conf, tmp); + + tmp->next = capi_iflist; /* prepend */ + capi_iflist = tmp; cc_verbose(2, 0, VERBOSE_PREFIX_3 "capi %c %s (%s:%s) contr=%d devs=%d EC=%d,opt=%d,tail=%d\n", (tmp->channeltype == CAPI_CHANNELTYPE_B)? 'B' : 'D', tmp->vname, tmp->incomingmsn, tmp->context, tmp->controller, @@ -5386,19 +4995,16 @@ int mkif(struct cc_capi_conf *conf) static void supported_sservices(struct cc_capi_controller *cp) { MESSAGE_EXCHANGE_ERROR error; - _cmsg CMSG, CMSG2; + _cmsg CMSG2; struct timeval tv; - unsigned char fac[20]; unsigned int services; - memset(fac, 0, sizeof(fac)); - FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - FACILITY_REQ_CONTROLLER(&CMSG) = cp->controller; - FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_SUPPLEMENTARY; - fac[0] = 3; - FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)&fac; - _capi_put_cmsg(&CMSG); - + capi_sendf(NULL, 0, CAPI_FACILITY_REQ, cp->controller, get_capi_MessageNumber(), + "w(w())", + FACILITYSELECTOR_SUPPLEMENTARY, + 0x0000 /* get supported services */ + ); + tv.tv_sec = 1; tv.tv_usec = 0; @@ -5564,7 +5170,7 @@ static int pbxcli_capi_show_channels(int fd, int argc, char *argv[]) cc_mutex_lock(&iflock); - for (i = iflist; i; i = i->next) { + for (i = capi_iflist; i; i = i->next) { if (i->channeltype != CAPI_CHANNELTYPE_B) continue; @@ -5611,6 +5217,8 @@ static int pbxcli_capi_info(int fd, int argc, char *argv[]) if (argc != 2) return RESULT_SHOWUSAGE; + + ast_cli(fd, "%s www.chan-capi.org\n", tdesc); for (i = 1; i <= capi_num_controllers; i++) { if (capi_controllers[i] != NULL) { @@ -5669,6 +5277,10 @@ static char no_debug_usage[] = "Usage: capi no debug\n" " Disables dumping of CAPI packets for debugging purposes\n"; +static char chatinfo_usage[] = +"Usage: capi chatinfo\n" +" Show info about chat status.\n"; + /* * define commands */ @@ -5680,8 +5292,10 @@ static struct ast_cli_entry cli_debug = { { "capi", "debug", NULL }, pbxcli_capi_do_debug, "Enable CAPI debugging", debug_usage }; static struct ast_cli_entry cli_no_debug = { { "capi", "no", "debug", NULL }, pbxcli_capi_no_debug, "Disable CAPI debugging", no_debug_usage }; +static struct ast_cli_entry cli_chatinfo = + { { "capi", "chatinfo", NULL }, pbxcli_capi_chatinfo, "Show CAPI chat info", chatinfo_usage }; -static const struct ast_channel_tech capi_tech = { +const struct ast_channel_tech capi_tech = { .type = channeltype, .description = tdesc, .capabilities = AST_FORMAT_ALAW, @@ -5692,7 +5306,7 @@ static const struct ast_channel_tech capi_tech = { #else .send_digit = pbx_capi_send_digit, #endif - .send_text = NULL, + .send_text = pbx_capi_qsig_sendtext, .call = pbx_capi_call, .hangup = pbx_capi_hangup, .answer = pbx_capi_answer, @@ -5882,7 +5496,7 @@ static int cc_post_init_capi(void) int rtp_ext_size = 0; unsigned needchannels = 0; - for (i = iflist; i && !rtp_ext_size; i = i->next) { + for (i = capi_iflist; i && !rtp_ext_size; i = i->next) { /* if at least one line wants RTP, we need to re-register with bigger block size for RTP-header */ if (capi_controllers[i->controller]->rtpcodec & i->capability) { @@ -5900,7 +5514,7 @@ static int cc_post_init_capi(void) for (controller = 1; controller <= capi_num_controllers; controller++) { if (capi_used_controllers & (1 << controller)) { - if ((error = ListenOnController(ALL_SERVICES, controller)) != 0) { + if ((error = capi_ListenOnController(ALL_SERVICES, controller)) != 0) { cc_log(LOG_ERROR,"Unable to listen on contr%d (error=0x%x)\n", controller, error); } else { @@ -5977,7 +5591,6 @@ static int conf_interface(struct cc_capi_conf *conf, struct ast_variable *v) CONF_TRUE(conf->es, "echosquelch", 1) CONF_TRUE(conf->bridge, "bridge", 1) CONF_TRUE(conf->ntmode, "ntmode", 1) - CONF_INTEGER(conf->qsigfeat, "qsig") if (!strcasecmp(v->name, "callgroup")) { conf->callgroup = ast_get_group(v->value); continue; @@ -6078,6 +5691,7 @@ static int conf_interface(struct cc_capi_conf *conf, struct ast_variable *v) if (!strcasecmp(v->name, "disallow")) { ast_parse_allow_disallow(&conf->prefs, &conf->capability, v->value, 0); } + cc_pbx_qsig_conf_interface_value(conf, v); } #undef CONF_STRING #undef CONF_INTEGER @@ -6202,6 +5816,7 @@ int unload_module(void) ast_cli_unregister(&cli_show_channels); ast_cli_unregister(&cli_debug); ast_cli_unregister(&cli_no_debug); + ast_cli_unregister(&cli_chatinfo); #ifdef CC_AST_HAS_VERSION_1_4 ast_module_user_hangup_all(); @@ -6227,12 +5842,15 @@ int unload_module(void) } } - i = iflist; + i = capi_iflist; while (i) { - if (i->owner) - cc_log(LOG_WARNING, "On unload, interface still has owner.\n"); + if ((i->owner) || (i->used)) + cc_log(LOG_WARNING, "On unload, interface still has owner or is used.\n"); if (i->smoother) ast_smoother_free(i->smoother); + + pbx_capi_qsig_unload_module(i); + cc_mutex_destroy(&i->lock); ast_cond_destroy(&i->event_trigger); itmp = i; @@ -6243,6 +5861,8 @@ int unload_module(void) cc_mutex_unlock(&iflock); ast_channel_unregister(&capi_tech); + + cleanup_ccbsnr(); return 0; } @@ -6303,6 +5923,7 @@ int load_module(void) ast_cli_register(&cli_show_channels); ast_cli_register(&cli_debug); ast_cli_register(&cli_no_debug); + ast_cli_register(&cli_chatinfo); ast_register_application(commandapp, pbx_capicommand_exec, commandsynopsis, commandtdesc); @@ -6338,10 +5959,8 @@ char *description() return ccdesc; } -#ifndef PBX_IS_OPBX char *key() { return ASTERISK_GPL_KEY; } -#endif #endif /* CC_AST_HAS_VERSION_1_4 */ diff --git a/chan_capi.h b/chan_capi.h index a777da8..8177f0d 100644 --- a/chan_capi.h +++ b/chan_capi.h @@ -1,8 +1,7 @@ /* * (CAPI*) * - * An implementation of Common ISDN API 2.0 for - * Asterisk / OpenPBX.org + * An implementation of Common ISDN API 2.0 for Asterisk * * Copyright (C) 2005-2007 Cytronics & Melware * @@ -16,6 +15,33 @@ * This program is free software and may be modified and * distributed under the terms of the GNU Public License. */ + +#include "config.h" + +#ifdef CC_AST_HAS_VERSION_1_4 +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CC_AST_HAS_VERSION_1_4 +#include "asterisk/abstract_jb.h" +#include "asterisk/musiconhold.h" +#endif #ifndef _PBX_CAPI_H #define _PBX_CAPI_H @@ -37,11 +63,6 @@ #define CAPI_MAX_FACILITYDATAARRAY_SIZE 300 -#ifndef CONNECT_RESP_GLOBALCONFIGURATION -#define CC_HAVE_NO_GLOBALCONFIGURATION -#warning If you dont update your libcapi20, some fax features are not available -#endif - /* some helper functions */ static inline void write_capi_word(void *m, unsigned short val) { @@ -83,11 +104,6 @@ static inline unsigned int read_capi_dword(void *m) #define cc_pbx_verbose(x...) ast_verbose(x) #define cc_copy_string(dst, src, size) ast_copy_string(dst, src, size) -#ifdef PBX_IS_OPBX -#define CC_CHANNEL_PVT(c) (c)->tech_pvt - -#else /* PBX_IS_OPBX */ - #ifndef AST_MUTEX_DEFINE_STATIC #define AST_MUTEX_DEFINE_STATIC(mutex) \ static cc_mutex_t mutex = AST_MUTEX_INITIALIZER @@ -99,15 +115,12 @@ static inline unsigned int read_capi_dword(void *m) #define CC_CHANNEL_PVT(c) (c)->tech_pvt #define CC_BRIDGE_RETURN enum ast_bridge_result -#endif /* PBX_IS_OPBX */ - -/* - * prototypes - */ -extern unsigned capi_ApplID; -extern MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG); -extern _cword get_capi_MessageNumber(void); -extern void cc_verbose(int o_v, int c_d, char *text, ...); +/* */ +#define return_on_no_interface(x) \ + if (!i) { \ + cc_verbose(4, 1, "CAPI: %s no interface for PLCI=%#x\n", x, PLCI); \ + return; \ + } /* * B protocol settings @@ -157,6 +170,16 @@ typedef struct fax3proto3 B3_PROTO_FAXG3; #define FACILITYSELECTOR_FAX_OVER_IP 0x00fd #define FACILITYSELECTOR_VOICE_OVER_IP 0x00fe +#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<<2) +#define EC_OPTION_DISABLE_G164_OR_G165 (1<<1 | 1<<2) +#define EC_DEFAULT_TAIL 0 /* maximum */ + #define CC_HOLDTYPE_LOCAL 0 #define CC_HOLDTYPE_HOLD 1 #define CC_HOLDTYPE_NOTIFY 2 @@ -218,19 +241,47 @@ struct cc_capi_gains { #define CAPI_ISDN_STATE_EC 0x00002000 #define CAPI_ISDN_STATE_DTMF 0x00004000 #define CAPI_ISDN_STATE_B3_SELECT 0x00008000 -#define CAPI_ISDN_STATE_3PTY 0x10000000 +#define CAPI_ISDN_STATE_STAYONLINE 0x00010000 +#define CAPI_ISDN_STATE_ISDNPROGRESS 0x00020000 +#define CAPI_ISDN_STATE_3PTY 0x10000000 #define CAPI_ISDN_STATE_PBX_DONT 0x40000000 #define CAPI_ISDN_STATE_PBX 0x80000000 #define CAPI_CHANNELTYPE_B 0 #define CAPI_CHANNELTYPE_D 1 -#define CAPI_CHANNELTYPE_NONE 2 +#define CAPI_CHANNELTYPE_NULL 2 /* the lower word is reserved for capi commands */ #define CAPI_WAITEVENT_B3_UP 0x00010000 #define CAPI_WAITEVENT_B3_DOWN 0x00020000 #define CAPI_WAITEVENT_ANSWER_FINISH 0x00030000 +/* Private qsig data for capi device */ +struct cc_qsig_data { + int calltransfer_active; + int calltransfer; + int calltransfer_onring; + unsigned int callmark; + + char *dnameid; + + /* Path Replacement */ + int pr_propose_sendback; /* send back an prior received PR PROPOSE on Connect */ + int pr_propose_sentback; /* set to 1 after sending an PR PROPOSE */ + int pr_propose_active; + int pr_propose_doinboundbridge; /* We have to to bridge a call back to asterisk */ + char *pr_propose_cid; /* Call identity */ + char *pr_propose_pn; /* Party Number */ + + char if_pr_propose_pn[AST_MAX_EXTENSION]; /* configured interface Party Number */ + + /* Partner Channel - needed for many features */ + struct capi_pvt *partner_ch; + unsigned int partner_plci; + ast_cond_t event_trigger; + unsigned int waitevent; +}; + /* ! Private data for a capi device */ struct capi_pvt { cc_mutex_t lock; @@ -247,8 +298,12 @@ struct capi_pvt { char vname[CAPI_MAX_STRING]; unsigned char tmpbuf[CAPI_MAX_STRING]; + /*! Channel who used us, possibly NULL */ + struct ast_channel *used; /*! Channel we belong to, possibly NULL */ struct ast_channel *owner; + /*! Channel who called us, possibly NULL */ + struct ast_channel *peer; /* capi message number */ _cword MessageNumber; @@ -274,7 +329,7 @@ struct capi_pvt { /* which b-protocol is active */ int bproto; - + char context[AST_MAX_EXTENSION]; /*! Multiple Subscriber Number we listen to (, seperated list) */ char incomingmsn[CAPI_MAX_STRING]; @@ -335,12 +390,16 @@ struct capi_pvt { /* Common ISDN Profile (CIP) */ int cip; + unsigned short transfercapability; /* if not null, receiving a fax */ FILE *fFax; /* Fax status */ unsigned int FaxState; + /* handle for CCBS/CCNR callback */ + unsigned int ccbsnrhandle; + /* not all codecs supply frames in nice 160 byte chunks */ struct ast_smoother *smoother; @@ -369,6 +428,10 @@ struct capi_pvt { unsigned int reason; unsigned int reasonb3; + /* deferred tasks */ + time_t whentohangup; + time_t whentoqueuehangup; + /* RTP */ struct ast_rtp *rtp; int capability; @@ -378,7 +441,8 @@ struct capi_pvt { /* Q.SIG features */ int qsigfeat; - + struct cc_qsig_data qsig_data; + /*! Next channel in list */ struct capi_pvt *next; }; @@ -397,6 +461,10 @@ struct cc_capi_profile { unsigned int manufacturer[5]; } __attribute__((__packed__)); +struct cc_capi_qsig_conf { + char if_pr_propose_pn[AST_MAX_EXTENSION]; +}; + struct cc_capi_conf { char name[CAPI_MAX_STRING]; char language[MAX_LANGUAGE]; @@ -421,6 +489,7 @@ struct cc_capi_conf { int bridge; int amaflags; int qsigfeat; + struct cc_capi_qsig_conf qsigconf; unsigned int faxsetting; ast_group_t callgroup; ast_group_t pickupgroup; @@ -512,4 +581,21 @@ struct cc_capi_controller { #define PRI_TRANS_CAP_DIGITAL_W_TONES 0x11 #define PRI_TRANS_CAP_VIDEO 0x18 +/* + * prototypes + */ +extern const struct ast_channel_tech capi_tech; +extern int capi_capability; +extern unsigned capi_ApplID; +extern struct capi_pvt *capi_iflist; +extern void cc_start_b3(struct capi_pvt *i); +extern unsigned char capi_tcap_is_digital(unsigned short tcap); +extern void capi_queue_cause_control(struct capi_pvt *i, int control); +extern void capidev_handle_connection_conf(struct capi_pvt **i, unsigned int PLCI, + unsigned short wInfo, unsigned short wMsgNum); +extern void capi_wait_for_answered(struct capi_pvt *i); +extern int capi_wait_for_b3_up(struct capi_pvt *i); +extern void capi_activehangup(struct capi_pvt *i, int state); +extern void capi_gains(struct cc_capi_gains *g, float rxgain, float txgain); + #endif diff --git a/chan_capi_chat.c b/chan_capi_chat.c new file mode 100644 index 0000000..df55fcc --- /dev/null +++ b/chan_capi_chat.c @@ -0,0 +1,390 @@ +/* + * (CAPI*) + * + * An implementation of Common ISDN API 2.0 for Asterisk + * + * Copyright (C) 2005-2007 Cytronics & Melware + * + * Armin Schindler + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#include +#include +#include +#include +#include + +#include "chan_capi20.h" +#include "chan_capi.h" +#include "chan_capi_chat.h" +#include "chan_capi_utils.h" + + +struct capichat_s { + char name[16]; + unsigned int number; + struct capi_pvt *i; + struct capichat_s *next; +}; + +static struct capichat_s *chat_list = NULL; +AST_MUTEX_DEFINE_STATIC(chat_lock); + +/* + * update the capi mixer for the given char room + */ +static void update_capi_mixer(int remove, unsigned int roomnumber, struct capi_pvt *i) +{ + struct capi_pvt *ii; + struct capichat_s *room; + unsigned char p_list[360]; + _cdword dest; + _cdword datapath; + capi_prestruct_t p_struct; + unsigned int found = 0; + _cword j = 0; + + if (i->PLCI == 0) { + cc_verbose(2, 0, VERBOSE_PREFIX_3 "capi mixer: %s: PLCI is unset, abort.\n", + i->vname); + return; + } + + cc_mutex_lock(&chat_lock); + room = chat_list; + while (room) { + if ((room->number == roomnumber) && + (room->i != i)) { + found++; + if (j + 9 > sizeof(p_list)) { + /* maybe we need to split capi messages here */ + break; + } + ii = room->i; + p_list[j++] = 8; + p_list[j++] = (_cbyte)(ii->PLCI); + p_list[j++] = (_cbyte)(ii->PLCI >> 8); + p_list[j++] = (_cbyte)(ii->PLCI >> 16); + p_list[j++] = (_cbyte)(ii->PLCI >> 24); + dest = (remove) ? 0x00000000 : 0x00000003; + if (ii->channeltype == CAPI_CHANNELTYPE_NULL) { + dest |= 0x00000030; + } + p_list[j++] = (_cbyte)(dest); + p_list[j++] = (_cbyte)(dest >> 8); + p_list[j++] = (_cbyte)(dest >> 16); + p_list[j++] = (_cbyte)(dest >> 24); + cc_verbose(3, 1, VERBOSE_PREFIX_3 "capi mixer: listed %s PLCI=0x%04x LI=0x%x\n", + ii->vname, ii->PLCI, dest); + } + room = room->next; + } + cc_mutex_unlock(&chat_lock); + + if (found) { + p_struct.wLen = j; + p_struct.info = p_list; + + /* don't send DATA_B3 to me */ + datapath = 0x00000000; + if (remove) { + /* now we need DATA_B3 again */ + datapath = 0x0000000c; + if (found == 1) { + /* only one left, enable DATA_B3 too */ + p_list[5] |= 0x0c; + } + } + if (i->channeltype == CAPI_CHANNELTYPE_NULL) { + if (!remove) { + datapath |= 0x00000030; + } + } + + cc_verbose(3, 1, VERBOSE_PREFIX_3 "capi mixer: %s PLCI=0x%04x LI=0x%x\n", + i->vname, i->PLCI, datapath); + + capi_sendf(NULL, 0, CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(), + "w(w(dc))", + FACILITYSELECTOR_LINE_INTERCONNECT, + 0x0001, /* CONNECT */ + datapath, + &p_struct + ); + } +} + +/* + * delete a chat member + */ +static void del_chat_member(struct capichat_s *room) +{ + struct capichat_s *tmproom; + struct capichat_s *tmproom2 = NULL; + unsigned int roomnumber = room->number; + struct capi_pvt *i = room->i; + + cc_mutex_lock(&chat_lock); + tmproom = chat_list; + while (tmproom) { + if (tmproom == room) { + if (!tmproom2) { + chat_list = tmproom->next; + } else { + tmproom2->next = tmproom->next; + } + cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: removed chat member from room '%s' (%d)\n", + room->i->vname, room->name, room->number); + free(room); + } + tmproom2 = tmproom; + tmproom = tmproom->next; + } + cc_mutex_unlock(&chat_lock); + + update_capi_mixer(1, roomnumber, i); +} + +/* + * add a new chat member + */ +static struct capichat_s *add_chat_member(char *roomname, struct capi_pvt *i) +{ + struct capichat_s *room = NULL; + struct capichat_s *tmproom; + unsigned int roomnumber = 1; + + room = malloc(sizeof(struct capichat_s)); + if (room == NULL) { + cc_log(LOG_ERROR, "Unable to allocate capi chat struct.\n"); + return NULL; + } + memset(room, 0, sizeof(struct capichat_s)); + + strncpy(room->name, roomname, sizeof(room->name)); + room->name[sizeof(room->name) - 1] = 0; + room->i = i; + + cc_mutex_lock(&chat_lock); + + tmproom = chat_list; + while (tmproom) { + if (!strcmp(tmproom->name, roomname)) { + roomnumber = tmproom->number; + break; + } else { + if (tmproom->number == roomnumber) { + roomnumber++; + } + } + tmproom = tmproom->next; + } + + room->number = roomnumber; + + room->next = chat_list; + chat_list = room; + + cc_mutex_unlock(&chat_lock); + + cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: added new chat member to room '%s' (%d)\n", + i->vname, roomname, roomnumber); + + update_capi_mixer(0, roomnumber, i); + + return room; +} + +/* + * loop during chat + */ +static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i) +{ + struct ast_frame *f; + int ms; + int exception; + int ready_fd; + int waitfd; + int nfds = 0; + struct ast_channel *rchan; + struct ast_channel *chan = c; + + waitfd = i->readerfd; + if (i->channeltype == CAPI_CHANNELTYPE_NULL) { + nfds = 1; + ast_indicate(chan, -1); + ast_set_read_format(chan, capi_capability); + ast_set_write_format(chan, capi_capability); + } + + while (1) { + ready_fd = 0; + ms = 100; + errno = 0; + exception = 0; + + rchan = ast_waitfor_nandfds(&chan, 1, &waitfd, nfds, &exception, &ready_fd, &ms); + + if (rchan) { + f = ast_read(chan); + if (!f) { + cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: chat: no frame, hangup.\n", + i->vname); + break; + } + if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) { + cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: chat: hangup frame.\n", + i->vname); + ast_frfree(f); + break; + } else if (f->frametype == AST_FRAME_VOICE) { + cc_verbose(5, 1, VERBOSE_PREFIX_3 "%s: chat: voice frame.\n", + i->vname); + if (i->channeltype == CAPI_CHANNELTYPE_NULL) { + capi_write_frame(i, f); + } + } else if (f->frametype == AST_FRAME_NULL) { + /* ignore NULL frame */ + cc_verbose(5, 1, VERBOSE_PREFIX_3 "%s: chat: NULL frame, ignoring.\n", + i->vname); + } else { + cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: chat: unhandled frame %d/%d.\n", + i->vname, f->frametype, f->subclass); + } + ast_frfree(f); + } else if (ready_fd == i->readerfd) { + if (exception) { + cc_verbose(1, 0, VERBOSE_PREFIX_3 "%s: chat: exception on readerfd\n", + i->vname); + break; + } + f = capi_read_pipeframe(i); + if (f->frametype == AST_FRAME_VOICE) { + ast_write(chan, f); + } + /* ignore other nullplci frames */ + } else { + if ((ready_fd < 0) && ms) { + if (errno == 0 || errno == EINTR) + continue; + cc_log(LOG_WARNING, "%s: Wait failed (%s).\n", + chan->name, strerror(errno)); + break; + } + } + } +} + +/* + * start the chat + */ +int pbx_capi_chat(struct ast_channel *c, char *param) +{ + struct capi_pvt *i = NULL; + char *roomname, *controller, *options; + char *p; + struct capichat_s *room; + ast_group_t tmpcntr; + unsigned long contr = 0; + + roomname = strsep(¶m, "|"); + options = strsep(¶m, "|"); + controller = param; + + if (!roomname) { + cc_log(LOG_WARNING, "capi chat requires room name.\n"); + return -1; + } + + if (controller) { + for (p = controller; p && *p; p++) { + if (*p == '|') *p = ','; + } + tmpcntr = ast_get_group(controller); + contr = (unsigned long)(tmpcntr >> 1); + } + + cc_verbose(3, 1, VERBOSE_PREFIX_3 "capi chat: %s: roomname=%s " + "options=%s controller=%s (0x%x)\n", + c->name, roomname, options, controller, contr); + + if (c->tech == &capi_tech) { + i = CC_CHANNEL_PVT(c); + } else { + /* virtual CAPI channel */ + i = capi_mknullif(c, contr); + if (!i) { + return -1; + } + } + + if (c->_state != AST_STATE_UP) + ast_answer(c); + + capi_wait_for_answered(i); + if (!(capi_wait_for_b3_up(i))) { + goto out; + } + + room = add_chat_member(roomname, i); + if (!room) { + cc_log(LOG_WARNING, "Unable to open capi chat room.\n"); + return -1; + } + + /* main loop */ + chat_handle_events(c, i); + + del_chat_member(room); + +out: + capi_remove_nullif(i); + + return 0; +} + +/* + * do command capi chatinfo + */ +int pbxcli_capi_chatinfo(int fd, int argc, char *argv[]) +{ + struct capichat_s *room = NULL; + struct ast_channel *c; + + if (argc != 2) + return RESULT_SHOWUSAGE; + + if (chat_list == NULL) { + ast_cli(fd, "There are no members in CAPI CHAT.\n"); + return RESULT_SUCCESS; + } + + ast_cli(fd, "CAPI CHAT\n"); + ast_cli(fd, "Room# Roomname Member Caller\n"); + + cc_mutex_lock(&chat_lock); + room = chat_list; + while (room) { + c = room->i->owner; + if (!c) { + c = room->i->used; + } + if (!c) { + ast_cli(fd, "%3d %-12s%-30s\"%s\" <%s>\n", + room->number, room->name, room->i->vname, + "?", "?"); + } else { + ast_cli(fd, "%3d %-12s%-30s\"%s\" <%s>\n", + room->number, room->name, c->name, + (c->cid.cid_name) ? c->cid.cid_name:"", c->cid.cid_num); + } + room = room->next; + } + cc_mutex_unlock(&chat_lock); + + return RESULT_SUCCESS; +} + diff --git a/chan_capi_chat.h b/chan_capi_chat.h new file mode 100644 index 0000000..4638f2f --- /dev/null +++ b/chan_capi_chat.h @@ -0,0 +1,23 @@ +/* + * (CAPI*) + * + * An implementation of Common ISDN API 2.0 for Asterisk + * + * Copyright (C) 2006-2007 Cytronics & Melware + * + * Armin Schindler + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#ifndef _PBX_CAPI_CHAT_H +#define _PBX_CAPI_CHAT_H + +/* + * prototypes + */ +extern int pbx_capi_chat(struct ast_channel *c, char *param); +extern int pbxcli_capi_chatinfo(int fd, int argc, char *argv[]); + +#endif diff --git a/chan_capi_qsig.h b/chan_capi_qsig.h index e371970..57c7f79 100644 --- a/chan_capi_qsig.h +++ b/chan_capi_qsig.h @@ -20,6 +20,9 @@ #define QSIG_TYPE_ALCATEL_ECMA 0x01 /* use additional Alcatel ECMA */ #define QSIG_TYPE_HICOM_ECMAV2 0x02 /* use additional Hicom ECMA V2 */ +#define CAPI_QSIG_WAITEVENT_PRPROPOSE 0x01000000 + + #define Q932_PROTOCOL_ROSE 0x11 /* X.219 & X.229 */ #define Q932_PROTOCOL_CMIP 0x12 /* Q.941 */ #define Q932_PROTOCOL_ACSE 0x13 /* X.217 & X.227 */ @@ -38,6 +41,9 @@ #define APDUINTERPRETATION_CLEARCALL 0x01 #define APDUINTERPRETATION_REJECT 0x02 +/* const char* APDU_STR[] = { "IGNORE APDU", "CLEARCALL-IF-UNKNOWN", "REJECT APDU" }; */ + + /* ASN.1 Identifier Octet - Data types */ #define ASN1_TYPE_MASK 0x1f #define ASN1_BOOLEAN 0x01 @@ -86,8 +92,20 @@ #define CNIP_NAMEUSERPROVIDED 0x00 /* Name is User-provided, unvalidated */ #define CNIP_NAMEUSERPROVIDEDV 0x01 /* Name is User-provided and validated */ +/* QSIG Operations += 1000 */ #define CCQSIG__ECMA__NAMEPRES 1000 /* Setting an own constant for ECMA Operation/Namepresentation, others will follow */ -#define CCQSIG__ECMA__LEGINFO2 1011 /* LEG INFORMATION2 */ +#define CCQSIG__ECMA__PRPROPOSE 1004 /* Path Replacement Propose */ +#define CCQSIG__ECMA__CTCOMPLETE 1012 /* Call Transfer Complete */ +#define CCQSIG__ECMA__LEGINFO2 1021 /* LEG INFORMATION2 */ +#define CCQSIG__ECMA__LEGINFO3 1022 /* LEG INFORMATION3 */ + + +#define CCQSIG_TIMER_WAIT_PRPROPOSE 1 /* Wait x seconds */ + + +#define free_null(x) { free(x); x = NULL; } + +/* Common QSIG structs */ /* * INVOKE Data struct, contains data for further operations @@ -125,7 +143,6 @@ struct cc_qsig_nfe { }; - /* * prototypes */ @@ -134,12 +151,12 @@ struct cc_qsig_nfe { *** QSIG Core Functions */ -extern int cc_qsig_build_facility_struct(unsigned char * buf, unsigned int *idx, int apdu_interpr, struct cc_qsig_nfe *nfe); -extern int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke); +extern int cc_qsig_build_facility_struct(unsigned char * buf, unsigned int *idx, int protocolvar, int apdu_interpr, struct cc_qsig_nfe *nfe); +extern int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i); extern unsigned int cc_qsig_asn1_get_string(unsigned char *buf, int buflen, unsigned char *data); extern unsigned int cc_qsig_asn1_get_integer(unsigned char *data, int *idx); -extern unsigned char cc_qsig_asn1_get_oid(unsigned char *data, int *idx); +extern unsigned char *cc_qsig_asn1_oid2str(unsigned char *data, int size); extern unsigned int cc_qsig_asn1_add_string(unsigned char *buf, int *idx, char *data, int datalen); extern unsigned int cc_qsig_asn1_add_integer(unsigned char *buf, int *idx, int value); @@ -149,23 +166,30 @@ extern signed int cc_qsig_check_invoke(unsigned char *data, int *idx); extern signed int cc_qsig_get_invokeid(unsigned char *data, int *idx, struct cc_qsig_invokedata *invoke); extern signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qsig_invokedata *invoke, int apduval); extern unsigned int cc_qsig_handle_capiind(unsigned char *data, struct capi_pvt *i); +extern unsigned int cc_qsig_handle_capi_facilityind(unsigned char *data, struct capi_pvt *i); extern unsigned int cc_qsig_add_call_setup_data(unsigned char *data, struct capi_pvt *i, struct ast_channel *c); +extern unsigned int cc_qsig_add_call_answer_data(unsigned char *data, struct capi_pvt *i, struct ast_channel *c); +extern unsigned int cc_qsig_add_call_alert_data(unsigned char *data, struct capi_pvt *i, struct ast_channel *c); extern unsigned int cc_qsig_add_call_facility_data(unsigned char *data, struct capi_pvt *i, int facility); extern signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protocol); extern unsigned int cc_qsig_handle_invokeoperation(int invokeident, struct cc_qsig_invokedata *invoke, struct capi_pvt *i); -extern unsigned int cc_qsig_do_facility(unsigned char *fac, struct ast_channel *c, char *param, unsigned int factype); +extern unsigned int cc_qsig_do_facility(unsigned char *fac, struct ast_channel *c, char *param, unsigned int factype, int info1); -/* - *** ECMA QSIG Functions - */ +extern int pbx_capi_qsig_getplci(struct ast_channel *c, char *param); +extern int pbx_capi_qsig_ssct(struct ast_channel *c, char *param); +extern int pbx_capi_qsig_ct(struct ast_channel *c, char *param); +extern int pbx_capi_qsig_callmark(struct ast_channel *c, char *param); +extern int pbx_capi_qsig_bridge(struct capi_pvt *i0, struct capi_pvt *i1); +extern int pbx_capi_qsig_sendtext(struct ast_channel *c, const char *text); -extern void cc_qsig_op_ecma_isdn_namepres(struct cc_qsig_invokedata *invoke, struct capi_pvt *i); -extern int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, int nametype); -extern void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct capi_pvt *i); +extern void cc_qsig_interface_init(struct cc_capi_conf *conf, struct capi_pvt *tmp); +extern void cc_pbx_qsig_conf_interface_value(struct cc_capi_conf *conf, struct ast_variable *v); +extern void interface_cleanup_qsig(struct capi_pvt *i); +extern void pbx_capi_qsig_unload_module(struct capi_pvt *i); +extern void pbx_capi_qsig_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i); -extern void cc_qsig_encode_ecma_sscalltransfer(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param); #endif diff --git a/chan_capi_qsig_asn197ade.c b/chan_capi_qsig_asn197ade.c index 57f1023..4db2cf8 100644 --- a/chan_capi_qsig_asn197ade.c +++ b/chan_capi_qsig_asn197ade.c @@ -1,8 +1,7 @@ /* * (CAPI*) * - * An implementation of Common ISDN API 2.0 for - * Asterisk / OpenPBX.org + * An implementation of Common ISDN API 2.0 for Asterisk * * Copyright (C) 2005-2007 Cytronics & Melware * Copyright (C) 2007 Mario Goegel @@ -26,7 +25,9 @@ #include #include "chan_capi20.h" #include "chan_capi.h" +#include "chan_capi_utils.h" #include "chan_capi_qsig.h" +#include "chan_capi_qsig_ecma.h" #include "chan_capi_qsig_asn197ade.h" /* @@ -49,12 +50,17 @@ unsigned int cc_qsig_asn197ade_get_partynumber(char *buf, int buflen, int *idx, numtype = (data[myidx++] & 0x0F); /* defines type of Number: numDigits, publicPartyNum, nsapEncNum, dataNumDigits */ - /* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * num type %i\n", numtype); */ + /* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * num type %i,%i\n", numtype, myidx); */ switch (numtype){ case 0: - if (data[myidx++] > 0) /* length of this context data */ - if (data[myidx++] == ASN1_TC_CONTEXTSPEC) - myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data) + 1; + if (data[myidx] > 0) { /* length of this context data */ + if (data[myidx+1] == ASN1_TC_CONTEXTSPEC) { + myidx += 2; + myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data); + } else { + myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data); + } + } break; case 1: /* publicPartyNumber (E.164) not supported yet */ return 0; @@ -63,11 +69,17 @@ unsigned int cc_qsig_asn197ade_get_partynumber(char *buf, int buflen, int *idx, return 0; break; case 3: - if (data[myidx++] > 0) /* length of this context data */ - if (data[myidx++] == ASN1_TC_CONTEXTSPEC) - myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data) + 1; + if (data[myidx++] > 0) { /* length of this context data */ + if (data[myidx+1] == ASN1_TC_CONTEXTSPEC) { + myidx += 2; + myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data); + } else { + myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data); + } + } break; }; + /* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * num type %i,%i\n", numtype, myidx); */ return myidx - *idx; } @@ -85,7 +97,7 @@ unsigned int cc_qsig_asn197ade_get_numdigits(char *buf, int buflen, int *idx, un memcpy(buf, &data[myidx], strsize); buf[strsize] = 0; -/* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * string length %i\n", strsize); */ + /* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * string length %i,%i\n", strsize, *idx); */ return strsize; } @@ -106,3 +118,72 @@ unsigned int cc_qsig_asn197ade_add_numdigits(char *buf, int buflen, int *idx, un myidx = 1 + strlen(buf); return myidx; } + +/* + * Returns an "PresentedNumberScreened" from an string, encoded as in addressing-data-elements-asn1-97 + * data is pointer to PresentedNumberScreened struct + * return: + * index counter + */ +unsigned int cc_qsig_asn197ade_get_pns(unsigned char *data, int *idx, struct asn197ade_numberscreened *ns) +{ /* sample data: a0 08 80 03>513<0a 01 00 */ + int myidx = *idx; + char buf[ASN197ADE_NUMDIGITS_STRSIZE+1]; + unsigned int buflen = sizeof(buf); + unsigned res; + + ns->partyNumber = NULL; + ns->screeningInd = userProvidedNotScreened; + int numtype; + + numtype = (data[myidx++] & 0x0F); /* defines type of Number */ + + /* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * num type %i,%i\n", numtype, myidx); */ + switch (numtype){ + case 0: + /* myidx points now to length */ + res = cc_qsig_asn197ade_get_partynumber(buf, buflen, &myidx, data); + /* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * res %i\n", numtype); */ + if (!res) + return 0; + + myidx += res; + if (strlen(buf)) { + ns->partyNumber = strdup(buf); + } + + /* get screening indicator */ + if (data[myidx] == ASN1_ENUMERATED) { /* HACK: this is not safe - check length of this parameter */ + myidx++; + ns->screeningInd = cc_qsig_asn1_get_integer(data, &myidx); + } + + break; + case 1: /* presentation restricted */ + myidx += data[myidx] + 1; /* this val should be zero */ + break; + case 2: /* number not available due to interworking */ + myidx += data[myidx] + 1; /* this val should be zero */ + break; + case 3: + /* myidx points now to length */ + res = cc_qsig_asn197ade_get_partynumber(buf, buflen, &myidx, data); + if (!res) + return 0; + + myidx += res; + if (strlen(buf)) { + ns->partyNumber = strdup(buf); + } + + /* get screening indicator */ + if (data[myidx] == ASN1_ENUMERATED) { /* HACK: this is not safe - check length of this parameter */ + myidx++; + ns->screeningInd = cc_qsig_asn1_get_integer(data, &myidx); + } + + break; + }; + + return myidx - *idx; +} diff --git a/chan_capi_qsig_asn197ade.h b/chan_capi_qsig_asn197ade.h index ca549bd..51af7ea 100644 --- a/chan_capi_qsig_asn197ade.h +++ b/chan_capi_qsig_asn197ade.h @@ -1,8 +1,7 @@ /* * (CAPI*) * - * An implementation of Common ISDN API 2.0 for - * Asterisk / OpenPBX.org + * An implementation of Common ISDN API 2.0 for Asterisk * * Copyright (C) 2005-2007 Cytronics & Melware * Copyright (C) 2007 Mario Goegel @@ -23,9 +22,21 @@ #define ASN197ADE_NUMDIGITS_STRSIZE 20 +struct asn197ade_numberscreened { + char *partyNumber; + enum { + userProvidedNotScreened, + userProvidedVerifiedAndPassed, + userProvidedVerifiedAndFailed, + networkProvided + } screeningInd; +}; + extern unsigned int cc_qsig_asn197ade_get_partynumber(char *buf, int buflen, int *idx, unsigned char *data); extern unsigned int cc_qsig_asn197ade_get_numdigits(char *buf, int buflen, int *idx, unsigned char *data); extern unsigned int cc_qsig_asn197ade_add_numdigits(char *buf, int buflen, int *idx, unsigned char *data); +extern unsigned int cc_qsig_asn197ade_get_pns(unsigned char *data, int *idx, struct asn197ade_numberscreened *ns); + #endif diff --git a/chan_capi_qsig_asn197no.c b/chan_capi_qsig_asn197no.c index 4ab6e9c..4bc989a 100644 --- a/chan_capi_qsig_asn197no.c +++ b/chan_capi_qsig_asn197no.c @@ -1,8 +1,7 @@ /* * (CAPI*) * - * An implementation of Common ISDN API 2.0 for - * Asterisk / OpenPBX.org + * An implementation of Common ISDN API 2.0 for Asterisk * * Copyright (C) 2005-2007 Cytronics & Melware * Copyright (C) 2007 Mario Goegel @@ -26,7 +25,9 @@ #include #include "chan_capi20.h" #include "chan_capi.h" +#include "chan_capi_utils.h" #include "chan_capi_qsig.h" +#include "chan_capi_qsig_ecma.h" #include "chan_capi_qsig_asn197no.h" /* @@ -73,7 +74,7 @@ unsigned int cc_qsig_asn197no_get_name(char *buf, int buflen, unsigned int *bufd if (data[myidx++] == ASN1_OCTETSTRING) { /* should be so */ namelength = cc_qsig_asn1_get_string((unsigned char *)buf, buflen, &data[myidx]); - myidx += data[myidx-1]; /* is this safe? */ + myidx += namelength + 1; } else { cc_verbose(1, 1, VERBOSE_PREFIX_4 " Namestruct not ECMA conform (String expected)\n"); break; diff --git a/chan_capi_qsig_asn197no.h b/chan_capi_qsig_asn197no.h index 9b0e7ee..52ef9b9 100644 --- a/chan_capi_qsig_asn197no.h +++ b/chan_capi_qsig_asn197no.h @@ -1,8 +1,7 @@ /* * (CAPI*) * - * An implementation of Common ISDN API 2.0 for - * Asterisk / OpenPBX.org + * An implementation of Common ISDN API 2.0 for Asterisk * * Copyright (C) 2005-2007 Cytronics & Melware * Copyright (C) 2007 Mario Goegel diff --git a/chan_capi_qsig_core.c b/chan_capi_qsig_core.c index ec1f6a7..841a009 100644 --- a/chan_capi_qsig_core.c +++ b/chan_capi_qsig_core.c @@ -1,8 +1,7 @@ /* * (CAPI*) * - * An implementation of Common ISDN API 2.0 for - * Asterisk / OpenPBX.org + * An implementation of Common ISDN API 2.0 for Asterisk * * Copyright (C) 2005-2007 Cytronics & Melware * Copyright (C) 2007 Mario Goegel @@ -23,12 +22,20 @@ #include #include "chan_capi20.h" #include "chan_capi.h" +#include "chan_capi_utils.h" #include "chan_capi_qsig.h" +#include "chan_capi_qsig_ecma.h" #include "chan_capi_qsig_asn197ade.h" #include "chan_capi_qsig_asn197no.h" -/* - * Encodes an ASN.1 string +/*! + * \brief Encodes an ASN.1 string + * + * \param buf destination pointer for string + * \param idx index points to string position in buffer + * \param data string + * \param datalen string length + * \return always zero */ unsigned int cc_qsig_asn1_add_string(unsigned char *buf, int *idx, char *data, int datalen) { @@ -60,7 +67,8 @@ unsigned int cc_qsig_asn1_get_string(unsigned char *buf, int buflen, unsigned ch strsize = buflen - 1; memcpy(buf, &data[myidx], strsize); buf[strsize] = 0; -/* cc_verbose(1, 1, VERBOSE_PREFIX_4 " get_string length %i\n", strsize); */ + /* don't increase strsize after closing zero - string ends at strsize ! */ + return strsize; } @@ -119,10 +127,44 @@ unsigned int cc_qsig_asn1_get_integer(unsigned char *data, int *idx) /* * Returns an Human Readable OID from ASN.1 Encoded OID */ -unsigned char cc_qsig_asn1_get_oid(unsigned char *data, int *idx) +unsigned char *cc_qsig_asn1_oid2str(unsigned char *data, int size) { - /* TODO: Add code */ - return 0; + unsigned char buf[1024]; + char numbuf[10]; + unsigned char *s; + int len, i; + unsigned long n; + + s = buf; + if (size < 3) { + cc_verbose(1, 1, VERBOSE_PREFIX_3 "OID2STR: Object identifier too small (%i).\n", size); + return NULL; + } + +#define N(n) \ + snprintf(numbuf, sizeof numbuf, "%lu", (unsigned long)n); \ + len = strlen(numbuf); \ + memcpy(s, numbuf, len); \ + s += len; + + N(data[0] / 40) + *s++ = '.'; + N(data[0] % 40) + n = 0; + for (i = 1; i < size; i++) { + n = n << 7 | (data[i] & 0x7f); + if ((data[i] & 0x80) == 0) { + *s++ = '.'; + N(n) + n = 0; + } + } + + *s++ = 0; + + s = buf; + return (unsigned char *) strdup((char*)s); + } @@ -150,13 +192,15 @@ void cc_qsig_update_facility_length(unsigned char * buf, unsigned int idx) /* * Create Invoke Struct */ -int cc_qsig_build_facility_struct(unsigned char * buf, unsigned int *idx, int apdu_interpr, struct cc_qsig_nfe *nfe) +int cc_qsig_build_facility_struct(unsigned char * buf, unsigned int *idx, int protocolvar, int apdu_interpr, struct cc_qsig_nfe *nfe) { - int myidx = 1; /* we start with Index 1 - Byte 0 is Length of Facilitydataarray */ + int myidx = *idx; /* we start with Index 1 - Byte 0 is Length of Facilitydataarray */ + if (!myidx) + myidx++; buf[myidx++] = 0x1c; buf[myidx++] = 0; /* Byte 2 length of Facilitydataarray */ - buf[myidx++] = COMP_TYPE_DISCR_SS; /* QSIG Facility */ + buf[myidx++] = 0x80 | protocolvar; /* QSIG Facility */ /* TODO: Outsource following struct to an separate function */ buf[myidx++] = COMP_TYPE_NFE; /* Network Facility Extension */ buf[myidx++] = 6; /* NFE Size hardcoded - not good */ @@ -179,8 +223,9 @@ int cc_qsig_build_facility_struct(unsigned char * buf, unsigned int *idx, int ap /* * Add invoke to buf */ -int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke) +int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i) { + unsigned char oid1[] = {0x2b,0x0c,0x09,0x00}; int myidx = *idx; int invlenidx; int result; @@ -195,11 +240,31 @@ int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_in return -1; } + if (invoke->descr_type == -1) { + switch (i->qsigfeat) { + case QSIG_TYPE_ALCATEL_ECMA: + invoke->descr_type = ASN1_OBJECTIDENTIFIER; + /* Set ECMA/ETSI OID */ + oid1[3] = (unsigned char)invoke->type; + invoke->oid_len = sizeof(oid1); + memcpy(invoke->oid_bin, oid1, sizeof(oid1)); + break; + case QSIG_TYPE_HICOM_ECMAV2: + invoke->descr_type = ASN1_INTEGER; + /* Leave type as it is */ + break; + default: + /* INVOKE is not encoded */ + break; + } + } + + switch (invoke->descr_type) { case ASN1_INTEGER: result = cc_qsig_asn1_add_integer(buf, &myidx, invoke->type); if (result) { - cc_log(LOG_ERROR, "QSIG: Cannot add invoke, identifier is not encoded!\n"); + cc_log(LOG_ERROR, "QSIG: Cannot add invoke, type is not encoded!\n"); return -1; } break; @@ -239,25 +304,32 @@ int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_in unsigned int cc_qsig_check_facility(unsigned char *data, int *idx, int *apduval, int protocol) { int myidx = *idx; + char *APDU_STR[] = {"IGNORE", "REJECT CALL", "CLEAR CALL"}; /* First byte after Facility Length */ - if (data[myidx] == (unsigned char)(0x80 | protocol)) { - myidx++; - cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Supplementary Services\n"); - if (data[myidx++] == (unsigned char)COMP_TYPE_NFE) { - /* Todo: Check Entities? */ - myidx = myidx + data[myidx] + 1; - /* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (idc #1 %i)\n",idx); */ - if ((data[myidx++] == (unsigned char)COMP_TYPE_APDU_INTERP)) { - myidx = myidx + data[myidx]; - *apduval = data[myidx]; - /* ToDo: implement real reject or clear call ? */ - *idx = ++myidx; - return 1; - } - } + if (data[myidx] != (unsigned char)(0x80 | protocol)) { + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: received protocol 0x%#x not configured!\n", (data[myidx] ^= 0x80)); + return 0; } - return 0; + + myidx++; + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Supplementary Services\n"); + if (data[myidx] == (unsigned char)COMP_TYPE_NFE) { + myidx++; + /* TODO: Check Entities? */ + myidx += data[myidx] + 1; + *idx = myidx; + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Facility has NFE struct\n"); + } + if ((data[myidx] == (unsigned char)COMP_TYPE_APDU_INTERP)) { + myidx++; + myidx += data[myidx]; + *apduval = data[myidx++]; + /* TODO: implement real reject or clear call ? */ + *idx = myidx; + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Facility has APDU - What to do if INVOKE is unknown: %s\n", APDU_STR[*apduval]); + } + return 1; } @@ -272,13 +344,12 @@ signed int cc_qsig_check_invoke(unsigned char *data, int *idx) { int myidx = *idx; - if (data[myidx] == (unsigned char)COMP_TYPE_INVOKE) { - /* is an INVOKE_IDENT */ - *idx = myidx + 1; /* Set index to length byte of component */ -/* cc_verbose(1, 1, VERBOSE_PREFIX_4 "CONNECT_IND (Invoke Length %i)\n", data[myidx+1]); */ + if (data[myidx++] == (unsigned char)COMP_TYPE_INVOKE) { + /* is an INVOKE */ + *idx = myidx; /* Set index to length byte of component */ return data[myidx + 1]; /* return component length */ } - *idx = ++myidx; + *idx += data[myidx]; /* we can end here, if it is an Invoke Result or Error */ return -1; /* what to do now? got no Invoke */ } @@ -343,7 +414,7 @@ signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qs invoke->datalen = datalen; memcpy(invoke->data, &data[myidx], datalen); /* copy data of Invoke Operation */ - myidx = myidx + datalen; /* points to next INVOKE component, if there's any */ + myidx += datalen; /* points to next INVOKE component, if there's any */ *idx = myidx; break; @@ -359,11 +430,16 @@ signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qs /* TODO: Maybe we decode the OID here and be verbose - have to write cc_qsig_asn1get_oid */ -/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (OID, Length %i)\n", temp); */ invoke->oid_len = temp; memcpy(invoke->oid_bin, &data[myidx], temp); /* Copy OID to separate array */ myidx = myidx + temp; /* Set index to next information */ + if (temp == 4) { /* even if we have an OID, set the numeric invoke type */ + invoke->type = (int) invoke->oid_bin[3]; + } else { + invoke->type = -1; + } + temp2 = (invoke->len) + (invoke->offset) + 1; /* Array End = Invoke Length + Invoke Offset +1 */ datalen = temp2 - myidx; @@ -372,10 +448,9 @@ signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qs datalen = 255; } -/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (OID, Datalength %i)\n",datalen); */ invoke->datalen = datalen; memcpy(invoke->data, &data[myidx], datalen); /* copy data of Invoke Operation */ - myidx = myidx + datalen; /* points to next INVOKE component, if there's any */ + myidx += datalen; /* points to next INVOKE component, if there's any */ *idx = myidx; break; @@ -391,7 +466,7 @@ signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qs datalen = 255; } - *idx = datalen; /* Set index to next INVOKE, if there's any */ + *idx = myidx + datalen; /* Set index to next INVOKE, if there's any */ return -1; break; } @@ -399,6 +474,26 @@ signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qs } +static int ident_qsig_invoke(int invoketype) +{ + switch (invoketype) { + case 0: + case 1: + case 2: + case 3: + return CCQSIG__ECMA__NAMEPRES; + case 4: + return CCQSIG__ECMA__PRPROPOSE; + case 12: + return CCQSIG__ECMA__CTCOMPLETE; + case 21: + return CCQSIG__ECMA__LEGINFO2; + default: + cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG: Unhandled QSIG INVOKE (%i)\n", invoketype); + return -1; + } +} + /* * Identify an INVOKE and return our own Ident Integer (CCQSIG__*) */ @@ -414,24 +509,28 @@ signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protoco switch (invoke->descr_type) { case ASN1_INTEGER: invokedescrtype = 1; + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%i)\n", invoke->type); + return ident_qsig_invoke(invoke->type); break; case ASN1_OBJECTIDENTIFIER: invokedescrtype = 2; datalen = invoke->oid_len; - if ((datalen) == 4) { - if (!cc_qsig_asn1_check_ecma_isdn_oid(invoke->oid_bin, datalen)) { - switch (invoke->oid_bin[3]) { - case 0: /* ECMA QSIG Name Presentation */ - return CCQSIG__ECMA__NAMEPRES; - case 21: - return CCQSIG__ECMA__LEGINFO2; - default: /* Unknown Operation */ - cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG: Unhandled ECMA-ISDN QSIG INVOKE (%i)\n", invoke->oid_bin[3]); - return 0; - } - } + + unsigned char *oidstr = NULL; + oidstr = cc_qsig_asn1_oid2str(invoke->oid_bin, invoke->oid_len); + if (oidstr) { + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%s)\n", oidstr); + free(oidstr); + } else { + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (unknown - OID not displayable)\n"); } + if ((datalen) == 4) { + if (!cc_qsig_asn1_check_ecma_isdn_oid(invoke->oid_bin, datalen)) { + return ident_qsig_invoke( (int)invoke->oid_bin[3]); + } + } + return -1; break; default: cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Unidentified INVOKE OP\n"); @@ -442,18 +541,27 @@ signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protoco switch (invoke->descr_type) { case ASN1_INTEGER: invokedescrtype = 1; - switch (invoke->type) { - case 0: - return CCQSIG__ECMA__NAMEPRES; - case 21: - return CCQSIG__ECMA__LEGINFO2; - default: - cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG: Unhandled QSIG INVOKE (%i)\n", invoke->type); - return 0; - } + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%i)\n", invoke->type); + return ident_qsig_invoke(invoke->type); break; case ASN1_OBJECTIDENTIFIER: invokedescrtype = 2; + datalen = invoke->oid_len; + + unsigned char *oidstr = NULL; + oidstr = cc_qsig_asn1_oid2str(invoke->oid_bin, invoke->oid_len); + if (oidstr) { + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%s)\n", oidstr); + free(oidstr); + } else { + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (unknown - OID not displayable)\n"); + } + + if ((datalen) == 4) { + if (!cc_qsig_asn1_check_ecma_isdn_oid(invoke->oid_bin, datalen)) { + return ident_qsig_invoke( (int)invoke->oid_bin[3]); + } + } break; default: cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Unidentified INVOKE OP\n"); @@ -463,13 +571,110 @@ signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protoco default: break; } - return 0; + return -1; } +/* + * find the interface (pvt) the PLCI belongs to + */ +static struct capi_pvt *capi_find_interface_bynumber(char * num) +{ + struct capi_pvt *i; + + if (!num) + return NULL; + + for (i = capi_iflist; i; i = i->next) { + if (strcmp(i->cid, num) == 0 || + strcmp(i->dnid, num) == 0) + return i; + } + +#if 0 + cc_mutex_lock(&nullif_lock); + for (i = nulliflist; i; i = i->next) { + if (strcmp(i->cid, num) == 0 || + strcmp(i->dnid, num) == 0) + break; + } + cc_mutex_unlock(&nullif_lock); +#endif + + return i; +} + +static void pbx_capi_qsig_handle_ctc(struct cc_qsig_invokedata *invoke, struct capi_pvt *i) +{ + struct cc_qsig_ctcomplete ctc; + struct capi_pvt *ii; + +#define CLEAR_CTC { if (ctc.redirectionNumber.partyNumber) free_null(ctc.redirectionNumber.partyNumber);\ + if (ctc.basicCallInfoElements) free_null(ctc.basicCallInfoElements); \ + if (ctc.redirectionName) free_null(ctc.redirectionName); \ + if (ctc.argumentExtension) free_null(ctc.argumentExtension); } + + int res = cc_qsig_decode_ecma_calltransfer(invoke, i, &ctc); + + if (!res) + return; + + if (ctc.redirectionNumber.partyNumber && (ctc.endDesignation == 0)) { + ii = capi_find_interface_bynumber(ctc.redirectionNumber.partyNumber); + if (ii) { + char *prpn = i->qsig_data.if_pr_propose_pn; + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Call Transfer partner channel for %s found at channel %s, bridging possible.\n", ctc.redirectionNumber.partyNumber, ii->vname); + + if (!(strlen(prpn))) { + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Path Replacement not configured, bridging not available!\n"); + } else { + unsigned char fac[CAPI_MAX_FACILITYDATAARRAY_SIZE]; + + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Trying to bridge with Path Replacement number %s...\n", prpn); + + switch (ii->state) { + case CAPI_STATE_ALERTING: + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: peer is in state ALERTING, PATH REPLACE follows after CONNECT...\n"); + ii->qsig_data.pr_propose_cid = strdup("123"); /* HACK: need an dynamic ID */ + ii->qsig_data.pr_propose_pn = strdup(i->qsig_data.if_pr_propose_pn); + ii->qsig_data.pr_propose_doinboundbridge = 1; + i->qsig_data.pr_propose_doinboundbridge = 1; + i->qsig_data.partner_plci = ii->PLCI; + break; + case CAPI_STATE_CONNECTED: + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: peer is CONNECTED...\n"); + i->qsig_data.pr_propose_cid = strdup("123"); /* HACK: need an dynamic ID */ + i->qsig_data.pr_propose_pn = strdup(i->qsig_data.if_pr_propose_pn); + ii->qsig_data.pr_propose_doinboundbridge = 1; + ii->qsig_data.partner_plci = i->PLCI; + + cc_qsig_do_facility(fac, i->owner, NULL, 4, 0); + + capi_sendf(NULL, 0, CAPI_INFO_REQ, i->PLCI, get_capi_MessageNumber(), + "()(()()()s)", fac ); + + i->qsig_data.pr_propose_cid = NULL; + i->qsig_data.pr_propose_pn = NULL; + break; + default: + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: peer's state is %i, which is not handled yet...\n", ii->state); + break; + } + + } + + CLEAR_CTC + + } + } + + CLEAR_CTC + + return ; +} /* - * + * Handle inbound INVOKEs */ unsigned int cc_qsig_handle_invokeoperation(int invokeident, struct cc_qsig_invokedata *invoke, struct capi_pvt *i) { @@ -477,6 +682,12 @@ unsigned int cc_qsig_handle_invokeoperation(int invokeident, struct cc_qsig_invo case CCQSIG__ECMA__NAMEPRES: cc_qsig_op_ecma_isdn_namepres(invoke, i); break; + case CCQSIG__ECMA__PRPROPOSE: + cc_qsig_op_ecma_isdn_prpropose(invoke, i); + break; + case CCQSIG__ECMA__CTCOMPLETE: + pbx_capi_qsig_handle_ctc(invoke, i); + break; case CCQSIG__ECMA__LEGINFO2: cc_qsig_op_ecma_isdn_leginfo2(invoke, i); break; @@ -486,69 +697,150 @@ unsigned int cc_qsig_handle_invokeoperation(int invokeident, struct cc_qsig_invo return 0; } +/** + * Handles incoming facilities + * + * @internal + * @param data facility buffer + * @param i points to capip_pvt struct + * @param idx index in facility buffer + * @param faclen facility length + * @param protocoltype Q932_PROTOCOL_ROSE | Q932_PROTOCOL_EXTENSIONS + * @return zero + */ +static int qsig_handle_q932facility(unsigned char *data, struct capi_pvt *i, int *idx, int faclen, int protocoltype) +{ + int facidx = *idx; + int action_unkn_apdu; /* What to do with unknown Invoke-APDUs (0=Ignore, 1=clear call, 2=reject APDU) */ + struct cc_qsig_invokedata invoke; + int invoke_len; + int invoketmp1; + unsigned int invoke_op = 0; /* Invoke Operation ID */ + + if (cc_qsig_check_facility(data, &facidx, &action_unkn_apdu, protocoltype)) { + while ((facidx) < faclen) { + cc_verbose(1, 1, VERBOSE_PREFIX_3 "Checking INVOKE at index %i (of %i)\n", facidx, faclen); + invoke_len = cc_qsig_check_invoke(data, &facidx); + if (invoke_len > 0) { + if (cc_qsig_get_invokeid(data, &facidx, &invoke) == 0) { + invoketmp1 = cc_qsig_fill_invokestruct(data, &facidx, &invoke, action_unkn_apdu); + invoke_op = cc_qsig_identifyinvoke(&invoke, i->qsigfeat); + if (invoke_op < 0) { + cc_verbose(1, 1, VERBOSE_PREFIX_3 "Invoke not identified!\n"); + } + cc_qsig_handle_invokeoperation(invoke_op, &invoke, i); + } + } else { + /* Not an Invoke */ + } + } + } else { /* kill endlessloop */ + facidx += faclen; + } + *idx = facidx; + return 0; +} + /* * Handles incoming Indications from CAPI */ unsigned int cc_qsig_handle_capiind(unsigned char *data, struct capi_pvt *i) { + int faclen0 = 0; int faclen = 0; int facidx = 2; - int action_unkn_apdu; /* What to do with unknown Invoke-APDUs (0=Ignore, 1=clear call, 2=reject APDU) */ - int invoke_len; /* Length of Invoke APDU */ - unsigned int invoke_op; /* Invoke Operation ID */ - struct cc_qsig_invokedata invoke; - int invoketmp1; + if (!i->qsigfeat) + return 0; - - if (data) { - faclen=data[facidx-2]; -/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (Got Facility IE, Length=%#x)\n", faclen); */ - facidx++; - while (facidx < faclen) { - cc_verbose(1, 1, VERBOSE_PREFIX_3 "Checking Facility at index %i\n", facidx); - switch (i->qsigfeat) { - case QSIG_TYPE_ALCATEL_ECMA: - if (cc_qsig_check_facility(data, &facidx, &action_unkn_apdu, Q932_PROTOCOL_ROSE)) { - /* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND ROSE Supplementary Services (APDU Interpretation: %i)\n", action_unkn_apdu); */ - while ((facidx-1)0) { - if (cc_qsig_get_invokeid(data, &facidx, &invoke)==0) { - invoketmp1=cc_qsig_fill_invokestruct(data, &facidx, &invoke, action_unkn_apdu); - invoke_op=cc_qsig_identifyinvoke(&invoke, i->qsigfeat); - cc_qsig_handle_invokeoperation(invoke_op, &invoke, i); - } - } else { - /* Not an Invoke */ - } - } - } - break; - case QSIG_TYPE_HICOM_ECMAV2: - if (cc_qsig_check_facility(data, &facidx, &action_unkn_apdu, Q932_PROTOCOL_EXTENSIONS)) { - /* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND ROSE Supplementary Services (APDU Interpretation: %i)\n", action_unkn_apdu); */ - while ((facidx-1)0) { - if (cc_qsig_get_invokeid(data, &facidx, &invoke)==0) { - invoketmp1=cc_qsig_fill_invokestruct(data, &facidx, &invoke, action_unkn_apdu); - invoke_op=cc_qsig_identifyinvoke(&invoke, i->qsigfeat); - cc_qsig_handle_invokeoperation(invoke_op, &invoke, i); - } - } else { - /* Not an Invoke */ - } - } - } - break; - default: - cc_verbose(1, 1, VERBOSE_PREFIX_3 "Unknown QSIG protocol configured (%i)\n", i->qsigfeat); - break; + if (!data) { + return 0; + } + + faclen0 = data[facidx-2]; /* Length of facility array - there may be more facilities encoded in this struct */ + faclen = data[facidx++]; + faclen += facidx; + while (facidx < faclen0) { + cc_verbose(1, 1, VERBOSE_PREFIX_3 "Checking Facility at index %i\n", facidx); + switch (i->qsigfeat) { + case QSIG_TYPE_ALCATEL_ECMA: + qsig_handle_q932facility(data, i, &facidx, faclen, Q932_PROTOCOL_ROSE); + break; + case QSIG_TYPE_HICOM_ECMAV2: + qsig_handle_q932facility(data, i, &facidx, faclen, Q932_PROTOCOL_EXTENSIONS); + break; + default: + cc_verbose(1, 1, VERBOSE_PREFIX_3 "Unknown QSIG protocol configured (%i)\n", i->qsigfeat); + break; + } + + if (facidx < faclen0) { /* there may follow a new facility */ + if (data[facidx] == 0x1c) { + cc_verbose(1, 1, VERBOSE_PREFIX_3 "Found another facility at index %i\n", facidx); + facidx++; + faclen = data[facidx++]; + faclen += facidx; + } else { + cc_verbose(1, 1, VERBOSE_PREFIX_3 "More data found in facility at index %i, but this is not an facility (%#x)\n", facidx, data[facidx]); + facidx++; /* don't start an endlessloop */ } } } cc_verbose(1, 1, VERBOSE_PREFIX_3 "Facility done at index %i from %i\n", facidx, faclen); + return 1; +} + +/* + * Handles incoming Facility Indications from CAPI + */ +unsigned int cc_qsig_handle_capi_facilityind(unsigned char *data, struct capi_pvt *i) +{ + int faclen = 0; + int facidx = 0; + + if (!data) { + return 0; + } + faclen = data[facidx++]; + /* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (Got Facility IE, Length=%#x)\n", faclen); */ + while (facidx < faclen) { + cc_verbose(1, 1, VERBOSE_PREFIX_3 "Checking Facility at index %i\n", facidx); + switch (i->qsigfeat) { + case QSIG_TYPE_ALCATEL_ECMA: + qsig_handle_q932facility(data, i, &facidx, faclen, Q932_PROTOCOL_ROSE); + break; + case QSIG_TYPE_HICOM_ECMAV2: + qsig_handle_q932facility(data, i, &facidx, faclen, Q932_PROTOCOL_EXTENSIONS); + break; + default: + cc_verbose(1, 1, VERBOSE_PREFIX_3 "Unknown QSIG protocol configured (%i)\n", i->qsigfeat); + /* kill endlessloop */ + facidx += faclen; + break; + } + } + cc_verbose(1, 1, VERBOSE_PREFIX_3 "Facility done at index %i from %i\n", facidx, faclen); + return 1; +} + +static int identify_qsig_setup_callfeature(char *param) +{ + char *p = param; + switch (*p) { + case 't': + cc_verbose(1, 1, "Call Transfer"); + p++; + if (*p == 'r') { + cc_verbose(1, 1, " on ALERT"); + return 2; + } else { + return 1; + } + default: + cc_verbose(1, 1, "unknown (%c)\n", *p); + break; + } + return 0; } @@ -561,63 +853,227 @@ unsigned int cc_qsig_add_call_setup_data(unsigned char *data, struct capi_pvt *i struct cc_qsig_invokedata invoke; struct cc_qsig_nfe nfe; unsigned int dataidx = 0; + int protocolvar = 0; const unsigned char xprogress[] = {0x1e,0x02,0xa0,0x90}; char *p = NULL; + char *pp = NULL; int add_externalinfo = 0; - if ((p = pbx_builtin_getvar_helper(c, "QSIG_SETUP"))) { + data[0] = 0; /* Initialize array length */ + + if ((p = (char *)pbx_builtin_getvar_helper(c, "QSIG_SETUP"))) { /* some special dial parameters */ /* parse the parameters */ while ((p) && (*p)) { switch (*p) { case 'X': /* add PROGRESS INDICATOR for external calls*/ - cc_verbose(1, 1, VERBOSE_PREFIX_4, "Sending QSIG external PROGRESS IE.\n"); + cc_verbose(1, 1, VERBOSE_PREFIX_4 "Sending QSIG external PROGRESS IE.\n"); add_externalinfo = 1; - while (((char)*p!=',')&&(*p)) /* Remove next values until separator (,), stop if zero */ - p++; + pp = strsep (&p, "/"); + pp = NULL; + break; + case 'C': + cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG Call Feature requested: "); + p++; + switch(identify_qsig_setup_callfeature(p)) { + case 1: /* Call transfer */ + p++; + pp = strsep(&p, "/"); + if (!pp) { + cc_log(LOG_WARNING, "QSIG Call Feature needs plci as parameter!\n"); + } else { + i->qsig_data.calltransfer = 1; + i->qsig_data.partner_plci = atoi(pp); + /* set the other channel as partner to me */ + struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci); + if (ii) + ii->qsig_data.partner_plci = i->PLCI; + + cc_verbose(1, 1, " for plci %#x\n", i->qsig_data.partner_plci); + } + break; + case 2: /* Call transfer on ring */ + p += 2; + pp = strsep(&p, "/"); + if (!pp) { + cc_log(LOG_WARNING, "QSIG Call Feature needs plci as parameter!\n"); + } else { + i->qsig_data.calltransfer_onring = 1; + i->qsig_data.partner_plci = atoi(pp); + /* set the other channel as partner to me */ + struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci); + if (ii) + ii->qsig_data.partner_plci = i->PLCI; + + cc_verbose(1, 1, " for plci %#x\n", i->qsig_data.partner_plci); + } + break; + default: + pp = strsep(&p, "/"); + break; + } + pp = NULL; break; default: cc_log(LOG_WARNING, "Unknown parameter '%c' in QSIG_SETUP, ignoring.\n", *p); - while (((char)*p!=',')&&(*p)) - p++; + p++; } - if (*p) /* this is not the end */ - p++; } } -/*mg:remember me switch (i->doqsig) {*/ - cc_qsig_build_facility_struct(data, &dataidx, APDUINTERPRETATION_IGNORE, &nfe); - cc_qsig_encode_ecma_name_invoke(data, &dataidx, &invoke, i, 0); - cc_qsig_add_invoke(data, &dataidx, &invoke); + switch (i->qsigfeat) { + case QSIG_TYPE_ALCATEL_ECMA: + protocolvar = Q932_PROTOCOL_ROSE; + break; + case QSIG_TYPE_HICOM_ECMAV2: + protocolvar = Q932_PROTOCOL_EXTENSIONS; + break; + default: + cc_log(LOG_WARNING, " Unknown QSIG variant configured.\n"); + return 0; + break; + } + + cc_qsig_build_facility_struct(data, &dataidx, protocolvar, APDUINTERPRETATION_IGNORE, &nfe); + cc_qsig_encode_ecma_name_invoke(data, &dataidx, &invoke, i, 0, i->owner->cid.cid_name); + cc_qsig_add_invoke(data, &dataidx, &invoke, i); if (add_externalinfo) { /* add PROGRESS INDICATOR for external calls*/ - memcpy(&data[dataidx], xprogress, sizeof(xprogress)); - data[0] += data[0] + sizeof(xprogress); + int progress_size = sizeof(xprogress); + memcpy(&data[dataidx], xprogress, progress_size); + data[0] += progress_size; + dataidx += progress_size; } -/* }*/ + return 0; } +/* + * Handles outgoing Facilies on Call Answer + */ +unsigned int cc_qsig_add_call_answer_data(unsigned char *data, struct capi_pvt *i, struct ast_channel *c) +{ + struct cc_qsig_invokedata invoke; + struct cc_qsig_nfe nfe; + unsigned int dataidx = 0; + int protocolvar = 0; + const char *connectedname; + + data[0] = 0; + + if (!i->qsigfeat) + return 0; + + if (!(connectedname = pbx_builtin_getvar_helper(c, "CONNECTEDNAME"))) + return 0; + + if (!strlen(connectedname)) + return 0; + + switch (i->qsigfeat) { + case QSIG_TYPE_ALCATEL_ECMA: + protocolvar = Q932_PROTOCOL_ROSE; + break; + case QSIG_TYPE_HICOM_ECMAV2: + protocolvar = Q932_PROTOCOL_EXTENSIONS; + break; + default: + cc_log(LOG_WARNING, " Unknown QSIG variant configured.\n"); + return 0; + break; + } + + cc_qsig_build_facility_struct(data, &dataidx, protocolvar, APDUINTERPRETATION_IGNORE, &nfe); + cc_qsig_encode_ecma_name_invoke(data, &dataidx, &invoke, i, 2, (char *)connectedname); + cc_qsig_add_invoke(data, &dataidx, &invoke, i); + + return 1; +} + +/* + * Handles outgoing Facilies on Call Alert + */ +unsigned int cc_qsig_add_call_alert_data(unsigned char *data, struct capi_pvt *i, struct ast_channel *c) +{ + struct cc_qsig_invokedata invoke; + struct cc_qsig_nfe nfe; + unsigned int dataidx = 0; + int protocolvar = 0; + const char *connectedname; + + data[0] = 0; + + if (!i->qsigfeat) + return 0; + + if (!(connectedname = pbx_builtin_getvar_helper(c, "CALLEDNAME"))) + return 0; + + if (!strlen(connectedname)) + return 0; + + switch (i->qsigfeat) { + case QSIG_TYPE_ALCATEL_ECMA: + protocolvar = Q932_PROTOCOL_ROSE; + break; + case QSIG_TYPE_HICOM_ECMAV2: + protocolvar = Q932_PROTOCOL_EXTENSIONS; + break; + default: + cc_log(LOG_WARNING, " Unknown QSIG variant configured.\n"); + return 0; + break; + } + + cc_qsig_build_facility_struct(data, &dataidx, protocolvar, APDUINTERPRETATION_IGNORE, &nfe); + cc_qsig_encode_ecma_name_invoke(data, &dataidx, &invoke, i, 1, (char *)connectedname); + cc_qsig_add_invoke(data, &dataidx, &invoke, i); + + return 1; +} /* * Handles outgoing Facilies on capicommand */ -unsigned int cc_qsig_do_facility(unsigned char *fac, struct ast_channel *c, char *param, unsigned int factype) +unsigned int cc_qsig_do_facility(unsigned char *fac, struct ast_channel *c, char *param, unsigned int factype, int info1) { struct cc_qsig_invokedata invoke; struct cc_qsig_nfe nfe; struct capi_pvt *i = CC_CHANNEL_PVT(c); /* struct capi_pvt *ii = NULL; */ unsigned int facidx = 0; + int protocolvar = 0; - cc_qsig_build_facility_struct(fac, &facidx, APDUINTERPRETATION_REJECT, &nfe); + switch (i->qsigfeat) { + case QSIG_TYPE_ALCATEL_ECMA: + protocolvar = Q932_PROTOCOL_ROSE; + break; + case QSIG_TYPE_HICOM_ECMAV2: + protocolvar = Q932_PROTOCOL_EXTENSIONS; + break; + default: + cc_log(LOG_WARNING, " Unknown QSIG variant configured.\n"); + return 0; + break; + } + + cc_qsig_build_facility_struct(fac, &facidx, protocolvar, APDUINTERPRETATION_IGNORE, &nfe); switch (factype) { + case 4: /* ECMA-xxx pathReplacementPropose */ + cc_qsig_encode_ecma_prpropose(fac, &facidx, &invoke, i, param); + cc_qsig_add_invoke(fac, &facidx, &invoke, i); + + break; + case 12: /* ECMA-178 callTransfer */ + cc_qsig_encode_ecma_calltransfer(fac, &facidx, &invoke, i, param, info1); + cc_qsig_add_invoke(fac, &facidx, &invoke, i); + + break; case 99: /* ECMA-300 simpleCallTransfer */ cc_qsig_encode_ecma_sscalltransfer(fac, &facidx, &invoke, i, param); - cc_qsig_add_invoke(fac, &facidx, &invoke); + cc_qsig_add_invoke(fac, &facidx, &invoke, i); break; default: break; @@ -625,3 +1081,531 @@ unsigned int cc_qsig_do_facility(unsigned char *fac, struct ast_channel *c, cha return 0; } + +/* + * capicommand getplci - needed for Call Transfer + */ +int pbx_capi_qsig_getplci(struct ast_channel *c, char *param) +{ + struct capi_pvt *i = CC_CHANNEL_PVT(c); + char buffer[10]; + + snprintf(buffer, sizeof(buffer)-1, "%d", i->PLCI); + cc_verbose(4, 1, VERBOSE_PREFIX_4 "QSIG_GETPLCI: %s\n", buffer); + pbx_builtin_setvar_helper(c, "QSIG_PLCI", buffer); + + return 0; +} + +/* + * Initiate a QSIG Single Step Call Transfer + */ +int pbx_capi_qsig_ssct(struct ast_channel *c, char *param) +{ + unsigned char fac[CAPI_MAX_FACILITYDATAARRAY_SIZE]; + struct capi_pvt *i = CC_CHANNEL_PVT(c); + + if (!param) { /* no data implies no Calling Number and Destination Number */ + cc_log(LOG_WARNING, "capi qsig_ssct requires source number and destination number\n"); + return -1; + } + + cc_qsig_do_facility(fac, c, param, 99, 0); + + capi_sendf(NULL, 0, CAPI_INFO_REQ, i->PLCI, get_capi_MessageNumber(), + "()(()()()s)", + fac + ); + + return 0; +} + +/* + * Initiate a QSIG Call Transfer + */ +int pbx_capi_qsig_ct(struct ast_channel *c, char *param) +{ + unsigned char fac[CAPI_MAX_FACILITYDATAARRAY_SIZE]; + struct capi_pvt *i = CC_CHANNEL_PVT(c); + struct capi_pvt *ii = NULL; + unsigned int callmark; + char *marker; + + if (!param) { /* no data implies no Calling Number and Destination Number */ + cc_log(LOG_WARNING, "capi qsig_ct requires call marker, source number, destination number and await_connect info\n"); + return -1; + } + + marker = strsep(¶m, "|"); + + callmark = atoi(marker); + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG_CT: using call marker %i(%s)\n", callmark, marker); + + for (ii = capi_iflist; ii; ii = ii->next) { + if (ii->qsig_data.callmark == callmark) + break; + } + + if (!ii) { + cc_log(LOG_WARNING, "capi qsig_ct call marker not found!\n"); + return -1; + } + + cc_qsig_do_facility(fac, c, param, 12, 1); + + capi_sendf(NULL, 0, CAPI_INFO_REQ, i->PLCI, get_capi_MessageNumber(), + "()(()()()s())", + fac + ); + + cc_qsig_do_facility(fac, c, param, 12, 0); + + capi_sendf(NULL, 0, CAPI_INFO_REQ, ii->PLCI, get_capi_MessageNumber(), + "()(()()()s())", + fac + ); + + + return 0; +} + +/* + * mark an call + */ +int pbx_capi_qsig_callmark(struct ast_channel *c, char *param) +{ + struct capi_pvt *i = CC_CHANNEL_PVT(c); + + if (!param) { /* no data implies no Calling Number and Destination Number */ + cc_log(LOG_WARNING, "capi qsig_callmark requires an call identifier\n"); + return -1; + } + + i->qsig_data.callmark = atoi(param); + + return 0; +} + + +static void send_feature_calltransfer(struct capi_pvt *i) +{ + unsigned char *fac = alloca(CAPI_MAX_FACILITYDATAARRAY_SIZE); + + struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci); + + /* needed for Path Replacement */ + ii->qsig_data.partner_plci = i->PLCI; + + if (ii) { + cc_qsig_do_facility(fac, i->owner, NULL, 12, 1); + + capi_sendf(NULL, 0, CAPI_INFO_REQ, i->PLCI, get_capi_MessageNumber(), "()(()()()s())", fac); + + cc_qsig_do_facility(fac, ii->owner, NULL, 12, 0); + + capi_sendf(NULL, 0, CAPI_INFO_REQ, ii->PLCI, get_capi_MessageNumber(), "()(()()()s())", fac); + } else { + cc_log(LOG_WARNING, "Call Transfer failed - second channel not found (PLCI %#x)!\n", i->qsig_data.partner_plci); + } + +} + +/* + * init QSIG data on new channel - will be called by mkif + */ +void cc_qsig_interface_init(struct cc_capi_conf *conf, struct capi_pvt *tmp) +{ + tmp->qsigfeat = conf->qsigfeat; + if (!conf->qsigfeat) + return; + + tmp->qsig_data.calltransfer_active = 0; + tmp->qsig_data.calltransfer = 0; + tmp->qsig_data.calltransfer_onring = 0; + tmp->qsig_data.callmark = 0; + tmp->qsig_data.dnameid = NULL; + + /* Path Replacement */ + tmp->qsig_data.pr_propose_active = 0; + tmp->qsig_data.pr_propose_sendback = 0; /* send back an prior received PR PROPOSE on Connect */ + tmp->qsig_data.pr_propose_sentback = 0; + tmp->qsig_data.pr_propose_doinboundbridge = 0; + tmp->qsig_data.pr_propose_cid = NULL; /* Call identity */ + tmp->qsig_data.pr_propose_pn = NULL; /* Party Number */ + + cc_copy_string(tmp->qsig_data.if_pr_propose_pn, conf->qsigconf.if_pr_propose_pn, sizeof(tmp->qsig_data.if_pr_propose_pn)); + + /* Partner Channel - needed for many features */ + tmp->qsig_data.partner_ch = NULL; + tmp->qsig_data.partner_plci = 0; + tmp->qsig_data.waitevent = 0; + + ast_cond_init(&tmp->qsig_data.event_trigger, NULL); +} + +/* + * build the qsig-interface according to configs + */ +void cc_pbx_qsig_conf_interface_value(struct cc_capi_conf *conf, struct ast_variable *v) +{ +#define CONF_STRING(var, token) \ + if (!strcasecmp(v->name, token)) { \ + cc_copy_string(var, v->value, sizeof(var)); \ + } +#define CONF_INTEGER(var, token) \ + if (!strcasecmp(v->name, token)) { \ + var = atoi(v->value); \ +} +#define CONF_TRUE(var, token, val) \ + if (!strcasecmp(v->name, token)) { \ + if (ast_true(v->value)) \ + var = val; \ +} + + CONF_INTEGER(conf->qsigfeat, "qsig") + CONF_STRING(conf->qsigconf.if_pr_propose_pn, "qsig_prnum") + + +#undef CONF_STRING +#undef CONF_INTEGER +#undef CONF_TRUE +} + +/* + * cleanup QSIG stuff on every (end of) call per interface + */ +static void qsig_cleanup_channel(struct capi_pvt *i) +{ + i->qsig_data.callmark = 0; + i->qsig_data.partner_ch = NULL; + i->qsig_data.calltransfer_active = 0; + i->qsig_data.calltransfer_onring = 0; + i->qsig_data.pr_propose_active = 0; + i->qsig_data.pr_propose_sentback = 0; + i->qsig_data.pr_propose_doinboundbridge = 0; + if (i->qsig_data.pr_propose_cid) { + free(i->qsig_data.pr_propose_cid); + i->qsig_data.pr_propose_cid = NULL; + } + if (i->qsig_data.pr_propose_pn) { + free(i->qsig_data.pr_propose_pn); + i->qsig_data.pr_propose_pn = NULL; + } + if (i->qsig_data.dnameid) { + free(i->qsig_data.dnameid); + i->qsig_data.dnameid = NULL; + } + +} + +/* + * cleanup QSIG stuff on interface + */ +void interface_cleanup_qsig(struct capi_pvt *i) +{ + if (i->qsigfeat) { + cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG: cleanup channel\n"); + qsig_cleanup_channel(i); + } +} + +/* + * cleanup QSIG stuff on module unload + */ +void pbx_capi_qsig_unload_module(struct capi_pvt *i) +{ + if (!i->qsigfeat) + return; + ast_cond_destroy(&i->qsig_data.event_trigger); +} + +/* + * wait for B3 up + */ +int pbx_capi_qsig_wait_for_prpropose(struct capi_pvt *i) +{ + struct timespec abstime; + int ret = 1; + + cc_mutex_lock(&i->lock); + if (!(i->qsig_data.pr_propose_sentback)) { + i->qsig_data.waitevent = CAPI_QSIG_WAITEVENT_PRPROPOSE; + abstime.tv_sec = time(NULL) + CCQSIG_TIMER_WAIT_PRPROPOSE; /* PR PROPOSE TIMER */ + abstime.tv_nsec = 0; + cc_verbose(4, 1, "%s: wait for PATH REPLACEMENT.\n", + i->vname); + if (ast_cond_timedwait(&i->qsig_data.event_trigger, &i->lock, &abstime) != 0) { + cc_log(LOG_WARNING, "%s: timed out waiting for PATH REPLACEMENT.\n", + i->vname); + ret = 0; + } else { + cc_verbose(4, 1, "%s: cond signal received for PATH REPLACEMENT.\n", + i->vname); + } + } + cc_mutex_unlock(&i->lock); + + return ret; +} + +/* + * check special conditions, wake waiting threads and send outstanding commands + * for the given interface + */ +static void pbx_capi_qsig_post_handling(struct capi_pvt *i) +{ + if ((i->qsig_data.waitevent == CAPI_QSIG_WAITEVENT_PRPROPOSE) && + (i->qsig_data.pr_propose_sentback == 1)) { + i->qsig_data.waitevent = 0; + ast_cond_signal(&i->qsig_data.event_trigger); + cc_verbose(4, 1, "%s: found and signal for PATH REPLACEMENT state.\n", + i->vname); + return; + } +} + +/* + * handle a bridge attempt - maybe we're allowed to make a path replacement + */ +int pbx_capi_qsig_bridge(struct capi_pvt *i0,struct capi_pvt *i1) +{ + if (i1->qsig_data.pr_propose_sentback) { + return 2; /* Path Replacement already sent out - call will be cleared in short */ + } + + i1->qsig_data.partner_plci = i0->PLCI; + send_feature_calltransfer(i1); + + if (pbx_capi_qsig_wait_for_prpropose(i1)) + return 1; /* Path Replacement successful */ + + /* No Path Replacement - allow line interconnect */ + return 0; + +} + +int pbx_capi_qsig_sendtext(struct ast_channel *c, const char *text) +{ + struct capi_pvt *i = CC_CHANNEL_PVT(c); + +#if 0 + /* suppress compiler warnings */ + unsigned char *data = alloca(CAPI_MAX_FACILITYDATAARRAY_SIZE); + unsigned int dataidx = 0; + struct cc_qsig_invokedata invoke; + struct cc_qsig_nfe nfe; +#endif + + int protocolvar = 0; + + if (!i->qsigfeat) + return 0; + + + if (!strlen(text)) + return 0; + + switch (i->qsigfeat) { + case QSIG_TYPE_ALCATEL_ECMA: + protocolvar = Q932_PROTOCOL_ROSE; + break; + case QSIG_TYPE_HICOM_ECMAV2: + protocolvar = Q932_PROTOCOL_EXTENSIONS; + break; + default: + cc_log(LOG_WARNING, " Unknown QSIG variant configured.\n"); + return 0; + break; + } + + /* TODO: implement something - QSIG_LEG_INFO3 doesn't work here */ + + return 0; +} + +/* + * CAPI INFO_IND (QSIG part) + */ +void pbx_capi_qsig_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) +{ + if (!i->qsigfeat) /* Run only, if QSIG enabled */ + return; + + switch(INFO_IND_INFONUMBER(CMSG)) { + case 0x0008: /* Cause */ + break; + case 0x0014: /* Call State */ + break; + case 0x0018: /* Channel Identification */ + break; + case 0x001c: /* Facility Q.932 */ + { + unsigned int qsiginvoke; + qsiginvoke = cc_qsig_handle_capi_facilityind( (unsigned char*) INFO_IND_INFOELEMENT(CMSG), i); + + /* got an Path Replacement */ + if ((i->qsig_data.pr_propose_cid && i->qsig_data.pr_propose_pn) &! i->qsig_data.pr_propose_sendback &! i->qsig_data.pr_propose_doinboundbridge) { + struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci); + + if (ii) { + if (ii->state == CAPI_STATE_CONNECTED) { /* second line is connected, we can proceed */ + unsigned char fac[CAPI_MAX_FACILITYDATAARRAY_SIZE]; + + cc_qsig_do_facility(fac, i->owner, NULL, 4, 0); + + capi_sendf(NULL, 0, CAPI_INFO_REQ, ii->PLCI, get_capi_MessageNumber(), + "()(()()()s)", + fac + ); + i->qsig_data.pr_propose_active = 1; + ii->qsig_data.pr_propose_sentback = 1; + } else { /* Path Replacement has to be sent back after Connect on second line */ + ii->qsig_data.pr_propose_sendback = 1; + ii->qsig_data.pr_propose_cid = strdup(i->qsig_data.pr_propose_cid); + ii->qsig_data.pr_propose_pn = strdup(i->qsig_data.pr_propose_pn); + ii->qsig_data.pr_propose_active = 1; + } + } else + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG_PATHREPLACEMENT_PROPOSE: no partner channel found (%#x)\n", i->qsig_data.partner_plci); + + + + free(i->qsig_data.pr_propose_cid); + i->qsig_data.pr_propose_cid = NULL; + free(i->qsig_data.pr_propose_pn); + i->qsig_data.pr_propose_pn = NULL; + } + + if ((i->qsig_data.pr_propose_cid && i->qsig_data.pr_propose_pn) && i->qsig_data.pr_propose_doinboundbridge) { + struct ast_channel *chanx; + struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci); + + if (ii) { + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG_PATHREPLACEMENT_PROPOSE: trying to complete bridge...\n"); + chanx = ast_bridged_channel(i->owner); + ast_channel_masquerade(ii->owner, chanx); + } + + free(i->qsig_data.pr_propose_cid); + i->qsig_data.pr_propose_cid = NULL; + free(i->qsig_data.pr_propose_pn); + i->qsig_data.pr_propose_pn = NULL; + } + + } + break; + case 0x001e: /* Progress Indicator */ + break; + case 0x0027: /* Notification Indicator */ + break; + case 0x0028: /* DSP */ + break; + case 0x0029: /* Date/Time */ + break; + case 0x0070: /* Called Party Number */ + break; + case 0x0074: /* Redirecting Number */ + break; + case 0x0076: /* Redirection Number */ + break; + case 0x00a1: /* Sending Complete */ + break; + case 0x4000: /* CHARGE in UNITS */ + break; + case 0x4001: /* CHARGE in CURRENCY */ + break; + case 0x8001: /* ALERTING */ + /* TODO: some checks, if there's any work here */ + if (i->qsig_data.calltransfer_onring) { + i->qsig_data.calltransfer_onring = 0; + send_feature_calltransfer(i); + } + break; + case 0x8002: /* CALL PROCEEDING */ + break; + case 0x8003: /* PROGRESS */ + break; + case 0x8005: /* SETUP */ + break; + case 0x8007: /* CONNECT */ + if (i->qsig_data.calltransfer) { + i->qsig_data.calltransfer = 0; + send_feature_calltransfer(i); + } + { + /* handle prior received Path Replacement */ + if ((i->qsig_data.pr_propose_cid && i->qsig_data.pr_propose_pn) && i->qsig_data.pr_propose_sendback) { + unsigned char fac[CAPI_MAX_FACILITYDATAARRAY_SIZE]; + + cc_qsig_do_facility(fac, i->owner, NULL, 4, 0); + + capi_sendf(NULL, 0, CAPI_INFO_REQ, i->PLCI, get_capi_MessageNumber(), + "()(()()()s)", + fac + ); + + i->qsig_data.pr_propose_sendback = 0; + free(i->qsig_data.pr_propose_cid); + i->qsig_data.pr_propose_cid = NULL; + free(i->qsig_data.pr_propose_pn); + i->qsig_data.pr_propose_pn = NULL; + + i->qsig_data.pr_propose_sentback = 1; + } + } + + break; + case 0x800d: /* SETUP ACK */ + break; + case 0x800f: /* CONNECT ACK */ + { + unsigned int qsiginvoke; + qsiginvoke = cc_qsig_handle_capi_facilityind( (unsigned char*) INFO_IND_INFOELEMENT(CMSG), i); + } + { + /* handle outbound Path Replacement */ + if ((i->qsig_data.pr_propose_cid && i->qsig_data.pr_propose_pn) && i->qsig_data.pr_propose_doinboundbridge) { + unsigned char fac[CAPI_MAX_FACILITYDATAARRAY_SIZE]; + + cc_qsig_do_facility(fac, i->owner, NULL, 4, 0); + + capi_sendf(NULL, 0, CAPI_INFO_REQ, i->PLCI, get_capi_MessageNumber(), + "()(()()()s)", fac ); + + i->qsig_data.pr_propose_sendback = 0; + free(i->qsig_data.pr_propose_cid); + i->qsig_data.pr_propose_cid = NULL; + free(i->qsig_data.pr_propose_pn); + i->qsig_data.pr_propose_pn = NULL; + + i->qsig_data.pr_propose_sentback = 1; + i->qsig_data.pr_propose_doinboundbridge = 0; + + } + } + break; + case 0x8045: /* DISCONNECT */ + qsig_cleanup_channel(i); + + break; + case 0x804d: /* RELEASE */ + break; + case 0x805a: /* RELEASE COMPLETE */ + qsig_cleanup_channel(i); + + break; + case 0x8062: /* FACILITY */ + break; + case 0x806e: /* NOTIFY */ + break; + case 0x807b: /* INFORMATION */ + break; + case 0x807d: /* STATUS */ + break; + default: + break; + } + pbx_capi_qsig_post_handling(i); + return; + +} diff --git a/chan_capi_qsig_ecma.c b/chan_capi_qsig_ecma.c index 8d17263..da53ec7 100644 --- a/chan_capi_qsig_ecma.c +++ b/chan_capi_qsig_ecma.c @@ -1,8 +1,7 @@ /* * (CAPI*) * - * An implementation of Common ISDN API 2.0 for - * Asterisk / OpenPBX.org + * An implementation of Common ISDN API 2.0 for Asterisk * * Copyright (C) 2005-2007 Cytronics & Melware * Copyright (C) 2007 Mario Goegel @@ -23,7 +22,9 @@ #include #include "chan_capi20.h" #include "chan_capi.h" +#include "chan_capi_utils.h" #include "chan_capi_qsig.h" +#include "chan_capi_qsig_ecma.h" #include "chan_capi_qsig_asn197ade.h" #include "chan_capi_qsig_asn197no.h" @@ -46,18 +47,55 @@ void cc_qsig_op_ecma_isdn_namepres(struct cc_qsig_invokedata *invoke, struct cap unsigned int namelength = 0; unsigned int datalength; int myidx = 0; + char *nametype = NULL; cc_verbose(1, 1, VERBOSE_PREFIX_4 "Handling Name Operation (id# %#x)\n", invoke->id); + callername[0] = 0; datalength = invoke->datalen; myidx = cc_qsig_asn197no_get_name(callername, ASN197NO_NAME_STRSIZE, &namelength, &myidx, invoke->data ); - if (namelength > 0) { - /* TODO: Maybe we do some charset conversions */ - i->owner->cid.cid_name = strdup(callername); - cc_verbose(1, 1, VERBOSE_PREFIX_4 " * received name (%i byte(s)): \"%s\"\n", namelength, callername); + if (namelength == 0) { + return; } + + /* TODO: Maybe we do some charset conversions */ + + switch (invoke->type) { + case 0: /* Calling Name */ + nametype = "CALLING NAME"; + break; + case 1: /* Called Name */ + nametype = "CALLED NAME"; + break; + case 2: /* Connected Name */ + nametype = "CONNECTED NAME"; + break; + case 3: /* Busy Name */ + nametype = "BUSY NAME"; + break; + } + + switch (invoke->type) { + case 0: /* Calling Name */ + i->owner->cid.cid_name = strdup(callername); /* Save name to callerid */ + break; + case 1: /* Called Name */ + case 2: /* Connected Name */ + case 3: /* Busy Name */ + if (i->qsig_data.dnameid) { /* this facility may come more than once - if so, then update this value */ + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * deleting previously received name.\n", nametype, namelength, callername); + free(i->qsig_data.dnameid); + } + i->qsig_data.dnameid = strdup(callername); /* save name as destination in qsig specific fields */ + /* there's no similarly field in asterisk */ + break; + default: + break; + } + + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * Got %s: \"%s\" (%i byte(s))\n", nametype, callername, namelength); /* if there was an sequence tag, we have more informations here, but we will ignore it at the moment */ @@ -78,17 +116,15 @@ void cc_qsig_op_ecma_isdn_namepres(struct cc_qsig_invokedata *invoke, struct cap * returns * always 0 */ -int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, int nametype) +int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, int nametype, char * name) { - const unsigned char oid[] = {0x2b,0x0c,0x09,0x00}; /* 1.3.12.9.0 */ - int oid_len = sizeof(oid); unsigned char namebuf[51]; unsigned char data[255]; int dataidx = 0; int namelen = 0; - if (i->owner->cid.cid_name) - namelen = strlen(i->owner->cid.cid_name); + if (name) + namelen = strlen(name); if (namelen < 1) { /* There's no name available, try to take Interface-Name */ if (i->name) { @@ -102,17 +138,12 @@ int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, stru } else { if (namelen > 50) namelen = 50; - memcpy(namebuf, i->owner->cid.cid_name, namelen); + memcpy(namebuf, name, namelen); } invoke->id = 1; - invoke->descr_type = ASN1_OBJECTIDENTIFIER; - invoke->oid_len = oid_len; - memcpy(invoke->oid_bin, oid, oid_len); - - /* HACK: */ - if (nametype) - invoke->oid_bin[3] = 2; + invoke->descr_type = -1; /* Let others do the work: qsig_add_invoke */ + invoke->type = (nametype % 4); /* Invoke Operation Number, if OID it's the last byte*/ if (namelen>0) { data[dataidx++] = 0x80; /* We send only simple Name, Namepresentation allowed */ @@ -127,8 +158,78 @@ int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, stru invoke->datalen = dataidx; memcpy(invoke->data, data, dataidx); -/* qsig_add_invoke(buf, idx, invoke); */ - + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * Sending \"%s\": (%i byte(s))\n", namebuf, namelen); + + return 0; +} + +/* + * Encode Operation: 1.3.12.9.22 ECMA/ISDN/LEG_INFO3 + * + * This function encodes the namepresentation facility + * The name will be copied from the cid.cid_name field of the asterisk channel struct. + * We create an invoke struct with the complete encoded invoke. + * + * parameters + * buf is pointer to facility array, not used now + * idx current idx in facility array, not used now + * invoke struct, which contains encoded data for facility + * i is pointer to capi channel + * returns + * always 0 + */ +int cc_qsig_encode_ecma_isdn_leginfo3_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *name) +{ + unsigned char namebuf[51]; + unsigned char data[255]; + + int dataidx = 0; + int namelen = 0; + + if (name) + namelen = strlen(name); + + if (namelen < 1) { /* There's no name available, try to take Interface-Name */ + if (i->name) { + if (strlen(i->name) >= 1) { + if (namelen > 50) + namelen = 50; + namelen = strlen(i->name); + memcpy(namebuf, i->name, namelen); + } + } + } else { + if (namelen > 50) + namelen = 50; + memcpy(namebuf, name, namelen); + } + + invoke->id = 1; + invoke->descr_type = -1; /* Let others do the work: qsig_add_invoke */ + invoke->type = 22; /* Invoke Operation Number, if OID it's the last byte*/ + + data[dataidx++] = ASN1_TF_CONSTRUCTED | ASN1_SEQUENCE; + data[dataidx++] = 5 + namelen; + + data[dataidx++] = ASN1_BOOLEAN; /* PresentationAllowedIndicator */ + data[dataidx++] = 1; + data[dataidx++] = 1; + + if (namelen>0) { + data[dataidx++] = 0x80; /* We send only simple Name, Namepresentation allowed */ + data[dataidx++] = namelen; + memcpy(&data[dataidx], namebuf, namelen); + dataidx += namelen; + } else { + data[dataidx++] = 0x84; /* Name not available */ + data[dataidx++] = 0; + } + + invoke->datalen = dataidx; + memcpy(invoke->data, data, dataidx); + + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * Sending QSIG_LEG_INFO3 \"%s\": (%i byte(s))\n", namebuf, namelen); + return 0; } @@ -159,6 +260,7 @@ void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct cap char tempstr[5]; char divertNum[ASN197ADE_NUMDIGITS_STRSIZE+1]; char origCalledNum[ASN197ADE_NUMDIGITS_STRSIZE+1]; + struct asn197ade_numberscreened divertPNS, origPNS; char divertName[ASN197NO_NAME_STRSIZE+1]; char origCalledName[ASN197NO_NAME_STRSIZE+1]; unsigned int temp = 0; @@ -202,49 +304,46 @@ void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct cap orgDivReason = cc_qsig_asn1_get_integer(invoke->data, &myidx); break; case 1: - temp = cc_qsig_asn197ade_get_partynumber(divertNum, ASN197ADE_NUMDIGITS_STRSIZE, &myidx, invoke->data); - if (temp) { - myidx += temp; - } + temp = invoke->data[myidx++]; /* keep the length of this info - maybe we don't get all data now */ + cc_qsig_asn197ade_get_pns(invoke->data, &myidx, &divertPNS); + myidx += temp; break; case 2: - temp = cc_qsig_asn197ade_get_partynumber(origCalledNum, ASN197ADE_NUMDIGITS_STRSIZE, &myidx, invoke->data); - if (temp) { - myidx += temp; - } + temp = invoke->data[myidx++]; /* keep the length of this info - maybe we don't get all data now */ + cc_qsig_asn197ade_get_pns(invoke->data, &myidx, &origPNS); + myidx += temp; break; case 3: /* Redirecting Name */ - myidx++; - temp = cc_qsig_asn197no_get_name(divertName, ASN197NO_NAME_STRSIZE, &temp2, &myidx, invoke->data); - if (temp) { - myidx += temp; - } + temp = invoke->data[myidx++]; /* keep the length of this info - maybe we don't get all data now */ + cc_qsig_asn197no_get_name(divertName, ASN197NO_NAME_STRSIZE, &temp2, &myidx, invoke->data); + myidx += temp; break; case 4: /* origCalled Name */ - myidx++; - temp = cc_qsig_asn197no_get_name(origCalledName, ASN197NO_NAME_STRSIZE, &temp2, &myidx, invoke->data); - if (temp) { - myidx += temp; - } + temp = invoke->data[myidx++]; /* keep the length of this info - maybe we don't get all data now */ + cc_qsig_asn197no_get_name(origCalledName, ASN197NO_NAME_STRSIZE, &temp2, &myidx, invoke->data); + myidx += temp; + break; + default: + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * unknown parameter %i\n", parameter); break; } } snprintf(tempstr, 5, "%i", divReason); - pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_DIVREASON", tempstr); + pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_DIVREASON", tempstr); snprintf(tempstr, 5, "%i", orgDivReason); - pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_ODIVREASON", tempstr); + pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_ODIVREASON", tempstr); snprintf(tempstr, 5, "%i", divCount); - pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_DIVCOUNT", tempstr); + pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_DIVCOUNT", tempstr); - pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_DIVNUM", divertNum); - pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_ODIVNUM", origCalledNum); - pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_DIVNAME", divertName); - pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_ODIVNAME", origCalledName); + pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_DIVNUM", divertPNS.partyNumber); + pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_ODIVNUM", origPNS.partyNumber); + pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_DIVNAME", divertName); + pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_ODIVNAME", origCalledName); - cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG_LEG_INFO2: %i(%i), %ix %s->%s, %s->%s\n", divReason, orgDivReason, divCount, origCalledNum, divertNum, origCalledName, divertName); + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * Got QSIG_LEG_INFO2: %i(%i), %ix %s->%s, %s->%s\n", divReason, orgDivReason, divCount, origPNS.partyNumber, divertPNS.partyNumber, origCalledName, divertName); return; @@ -252,9 +351,240 @@ void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct cap /* - * Encode Operation: 1.3.12.9.99 ECMA/ISDN/SIMPLECALLTRANSFER + * Encode Operation: 1.3.12.9.12 ECMA/ISDN/CALLTRANSFER * - * This function encodes the simple call transfer facility + * This function encodes the call transfer facility + * + * We create an invoke struct with the complete encoded invoke. + * + * parameters + * buf is pointer to facility array, not used now + * idx current idx in facility array, not used now + * invoke struct, which contains encoded data for facility + * i is pointer to capi channel + * param is parameter from capicommand + * info this facility is part of 2, 0 is facility 1, 1 is facility 2 + * returns + * always 0 + */ +void cc_qsig_encode_ecma_calltransfer(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param, int info) +{ + char *cid, *ccanswer; + char *name = NULL; + int icanswer = 0; + int cidlen = 0; + int namelength = 0; + int seqlen = 13; + char c[255]; + int ix = 0; + + if (param) { /* got Call Transfer Parameters */ + if (info) { + cid = strsep(¶m, "|"); + cidlen = strlen(cid); + if (cidlen > 20) /* HACK: stop action here, maybe we have invalid data */ + cidlen = 20; + } else { + char *tmp = strsep(¶m, "|"); + tmp = NULL; + cid = strsep(¶m, "|"); + cidlen = strlen(cid); + if (cidlen > 20) /* HACK: stop action here, maybe we have invalid data */ + cidlen = 20; + + ccanswer = strsep(¶m, "|"); + if (ccanswer[0]) + icanswer = ccanswer[0] - 0x30; + } + } else { +/* cid = strdup(i->owner->cid.cid_num);*/ /* Here we get the Asterisk extension */ + if (info) { /* info is >0 on outbound channel (second facility) */ + struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci); + + cid = strdup(i->cid); + cidlen = strlen(cid); + + if (ii) { + /* send callers name to user B */ + if (ii->owner->cid.cid_name) { + name = ast_strdupa(ii->owner->cid.cid_name); + namelength = strlen(name); + } + } + } else { /* have to build first facility - send destination number back to inbound channel */ + struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci); + cid = strdup(ii->dnid); + cidlen = strlen(cid); + + if (ii) { + /* send destination name to user A */ + if (ii->qsig_data.dnameid) { + name = ast_strdupa(ii->qsig_data.dnameid); + namelength = strlen(name); + } + } + } + + if (!info) + icanswer = i->qsig_data.calltransfer_onring % 1; + } + + seqlen += cidlen; + if (namelength) + seqlen += 4 + namelength; + + c[ix++] = ASN1_SEQUENCE | ASN1_TF_CONSTRUCTED; /* start of SEQUENCE */ + c[ix++] = seqlen; + + c[ix++] = ASN1_ENUMERATED; /* End Designation */ + c[ix++] = 1; /* length */ + c[ix++] = info; + + c[ix++] = (ASN1_TC_CONTEXTSPEC | ASN1_TF_CONSTRUCTED) + 0; /* val 0 - Source Caller ID struct */ + c[ix++] = 5 + cidlen; + c[ix++] = ASN1_TC_CONTEXTSPEC; /* CallerID */ + c[ix++] = cidlen; + memcpy(&c[ix], cid, cidlen); + ix += cidlen; + c[ix++] = ASN1_ENUMERATED; /* Screening Indicator */ + c[ix++] = 1; /* length */ + c[ix++] = 1; /* 01 = userProvidedVerifiedAndPassed ...we hope so */ + + { + if (namelength) { + c[ix++] = (ASN1_TC_CONTEXTSPEC | ASN1_TF_CONSTRUCTED) + 1; /* val 1 - Source Caller ID struct */ + c[ix++] = 2 + namelength; + c[ix++] = ASN1_OCTETSTRING; /* CallerID */ + c[ix++] = namelength; + memcpy(&c[ix], name, namelength); + ix += namelength; + } + } + + c[ix++] = ASN1_ENUMERATED; /* val 3 - wait for connect ? */ + c[ix++] = 1; + c[ix++] = icanswer; + + /* end of SEQUENCE */ + /* there are optional data possible here */ + + invoke->id = 12; + invoke->descr_type = -1; + invoke->type = 12; /* Invoke Operation Code */ + + invoke->datalen = ix; + memcpy(invoke->data, c, ix); + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * Sending QSIG_CT: %i->%s\n", info, cid); + + if (cid) + free(cid); + +} + +/* + * Decode Operation: 1.3.12.9.12 ECMA/ISDN/CALLTRANSFER + * + * This function decodes the call transfer facility + * + * We create an invoke struct with the complete encoded invoke. + * + * parameters + * buf is pointer to facility array, not used now + * idx current idx in facility array, not used now + * invoke struct, which contains encoded data from facility + * i is pointer to capi channel + * returns + * transfer to destination number + */ +unsigned int cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct capi_pvt *i, struct cc_qsig_ctcomplete *ctc) +{ + unsigned int datalength; + unsigned int seqlength = 0; + unsigned char *data = invoke->data; + int myidx = 0; + /* TODO: write more code */ + + char *ct_status_txt[] = { "ANSWERED", "ALERTING" }; + char ct_name[ASN197NO_NAME_STRSIZE+1] = { "EMPTY" }; + unsigned int namelength = 0; + int temp = 0; + + ctc->endDesignation = primaryEnd; + ctc->redirectionNumber.partyNumber = NULL; + ctc->redirectionNumber.screeningInd = userProvidedNotScreened; + ctc->basicCallInfoElements = NULL; + ctc->redirectionName = NULL; + ctc->callStatus = answered; + ctc->argumentExtension = NULL; /* unhandled yet */ + +#define ct_err(x...) { cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG CALL TRANSFER - "x); return 0; } + + cc_verbose(1, 1, VERBOSE_PREFIX_4 "Handling QSIG CALL TRANSFER (id# %#x)\n", invoke->id); + + if (data[myidx++] != (ASN1_SEQUENCE | ASN1_TC_UNIVERSAL | ASN1_TF_CONSTRUCTED)) { /* 0x30 */ + /* We do not handle this, because it should start with an sequence tag */ + ct_err("not a sequence\n"); + } + + /* This facility is encoded as SEQUENCE */ + seqlength = data[myidx++]; + datalength = invoke->datalen; + if (datalength < (seqlength+1)) { + ct_err("buffer error\n"); + } + + if (data[myidx++] == ASN1_ENUMERATED) { + ctc->endDesignation = cc_qsig_asn1_get_integer(data, &myidx); + } else { + ct_err("no endDesignation information.\n"); + } + + temp = cc_qsig_asn197ade_get_pns(data, &myidx, &ctc->redirectionNumber); + + if (!temp) { + ct_err("error on decoding PresentedNumberScreened value.\n"); + } + myidx += temp; + + if (myidx < datalength) { + if (data[myidx] == ASN1_TC_APPLICATION) { + myidx++; + /* TODO: check size -> could be bigger than 256 bytes - MSB is set then */ + ctc->basicCallInfoElements = malloc(data[myidx]); + if (ctc->basicCallInfoElements) { + memcpy(ctc->basicCallInfoElements, &data[myidx+1], data[myidx] ); + } else { + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG CALL TRANSFER - couldn't allocate memory for basicCallInfoElements.\n", (int)data[myidx]); + } + myidx += data[myidx] + 1; + } + } + + if (myidx < datalength) { + if (data[myidx] != ASN1_ENUMERATED) { /* Maybe we get an name (OPTIONAL) */ + myidx += cc_qsig_asn197no_get_name(ct_name, ASN197NO_NAME_STRSIZE+1, &namelength, &myidx, data ); + if (namelength) + ctc->redirectionName = strdup(ct_name); + } + } + + if (myidx < datalength) { + if (data[myidx++] == ASN1_ENUMERATED) { /* Call Status */ + ctc->callStatus = cc_qsig_asn1_get_integer(data, &myidx); + } + } + + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * Got QSIG CALL TRANSFER endDesignation: %i partyNumber: %s (ScreeningInd: %i), partyName: \"%s\", Call state: %s\n", + ctc->endDesignation, ctc->redirectionNumber.partyNumber, ctc->redirectionNumber.screeningInd, ctc->redirectionName, ct_status_txt[ctc->callStatus]); + + return 1; +#undef ct_err +} + +/* + * Encode Operation: 1.3.12.9.99 ECMA/ISDN/SINGLESTEPCALLTRANSFER + * + * This function encodes the single step call transfer facility * * We create an invoke struct with the complete encoded invoke. * @@ -269,7 +599,6 @@ void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct cap */ void cc_qsig_encode_ecma_sscalltransfer(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param) { - const unsigned char oid[] = {0x2b,0x0c,0x09,0x63}; /* 1.3.12.9.99 */ char *cidsrc, *ciddst; int srclen, dstlen; int seqlen = 12; @@ -311,16 +640,155 @@ void cc_qsig_encode_ecma_sscalltransfer(unsigned char * buf, unsigned int *idx, c[ix++] = 1; c[ix++] = 0; - /* end of SEQUENCE */ + /* end of SEQUENCE */ /* there are optional data possible here */ invoke->id = 99; - invoke->descr_type = ASN1_OBJECTIDENTIFIER; - invoke->oid_len = sizeof(oid); - memcpy(invoke->oid_bin, oid, sizeof(oid)); - + invoke->descr_type = -1; + invoke->type = 99; + invoke->datalen = ix; memcpy(invoke->data, c, ix); - cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG_CT: %s->%s\n", cidsrc, ciddst); + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * Sending QSIG_SSCT: %s->%s\n", cidsrc, ciddst); } + +/* + * Handle Operation: 1.3.12.9.19 ECMA/ISDN/PATH REPLACEMENT PROPOSE + * + * This function decodes the PATH REPLACEMENT PROPOSE facility + * The datas will be copied in the some capi_pvt channel variables + * + * parameters + * invoke struct, which contains encoded data from facility + * i is pointer to capi channel + * returns + * nothing + */ +void cc_qsig_op_ecma_isdn_prpropose(struct cc_qsig_invokedata *invoke, struct capi_pvt *i) +{ + + unsigned int datalength; + unsigned int seqlength = 0; + int myidx = 0; + /* TODO: write more code */ + + char callid[4+1]; + char reroutingnr[ASN197ADE_NUMDIGITS_STRSIZE+1]; + int temp = 0; + + callid[0] = 0; + reroutingnr[0] = 0; + + cc_verbose(1, 1, VERBOSE_PREFIX_4 "Handling QSIG PATH REPLACEMENT PROPOSE (id# %#x)\n", invoke->id); + + if (invoke->data[myidx++] != (ASN1_SEQUENCE | ASN1_TC_UNIVERSAL | ASN1_TF_CONSTRUCTED)) { /* 0x30 */ + /* We do not handle this, because it should start with an sequence tag */ + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG REPLACEMENT PROPOSE - not a sequence\n"); + return; + } + + /* This facility is encoded as SEQUENCE */ + seqlength = invoke->data[myidx++]; + datalength = invoke->datalen; + if (datalength < (seqlength+1)) { + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG REPLACEMENT PROPOSE - buffer error\n"); + return; + } + + if (invoke->data[myidx++] == ASN1_NUMERICSTRING) { + int strsize; + strsize = cc_qsig_asn1_get_string((unsigned char*)&callid, sizeof(callid), &invoke->data[myidx]); + myidx += strsize +1; + } else { + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG REPLACEMENT PROPOSE - NUMERICSTRING expected\n"); + return; + } + + if (invoke->data[myidx++] == ASN1_TC_CONTEXTSPEC) + temp = cc_qsig_asn1_get_string((unsigned char*)&reroutingnr, sizeof(reroutingnr), &invoke->data[myidx]); + + if (temp) { + myidx += temp; + } else { + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG REPLACEMENT PROPOSE - partyNumber expected (%i)\n", myidx); + return; + } + + + i->qsig_data.pr_propose_cid = strdup(callid); + i->qsig_data.pr_propose_pn = strdup(reroutingnr); + + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * Got QSIG_PATHREPLACEMENT_PROPOSE Call identity: %s, Party number: %s (%i)\n", callid, reroutingnr, temp); + + return; +} + +/* + * Encode Operation: 1.3.12.9.19 ECMA/ISDN/PATH REPLACEMENT PROPOSE + * + * This function encodes the path replacement propose + * + * We create an invoke struct with the complete encoded invoke. + * + * parameters + * buf is pointer to facility array, not used now + * idx current idx in facility array, not used now + * invoke struct, which contains encoded data for facility + * i is pointer to capi channel + * param is parameter from capicommand + * returns + * always 0 + */ +void cc_qsig_encode_ecma_prpropose(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param) +{ + /* TODO: write code */ + int invokeop = 4; + + char *callid, *reroutingnr; + int cidlen, rrnlen; + int seqlen = 4; + char c[255]; + int ix = 0; + + if (!i->qsig_data.pr_propose_cid) + return ; + + if (!i->qsig_data.pr_propose_pn) + return ; + + callid = i->qsig_data.pr_propose_cid; + reroutingnr = i->qsig_data.pr_propose_pn; + + cidlen = strlen(callid); + rrnlen = strlen(reroutingnr); + seqlen += cidlen + rrnlen; + + + c[ix++] = ASN1_SEQUENCE | ASN1_TF_CONSTRUCTED; /* start of SEQUENCE */ + c[ix++] = seqlen; + + c[ix++] = ASN1_NUMERICSTRING; /* val 1 - CallID */ + c[ix++] = cidlen; + memcpy(&c[ix], callid, cidlen); + ix += cidlen; + + c[ix++] = ASN1_TC_CONTEXTSPEC; /* val 2 - Rerouting number*/ + c[ix++] = rrnlen; + memcpy(&c[ix], reroutingnr, rrnlen); + ix += rrnlen; + + /* end of SEQUENCE */ + /* there are optional data possible here */ + + invoke->id = invokeop; + invoke->descr_type = -1; + invoke->type = invokeop; + + invoke->datalen = ix; + memcpy(invoke->data, c, ix); + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * Sending QSIG_PATHREPLACEMENT_PROPOSE: Call identity: %s, Party number: %s\n", callid, reroutingnr); + + + return; +} diff --git a/chan_capi_qsig_ecma.h b/chan_capi_qsig_ecma.h new file mode 100644 index 0000000..bc246d0 --- /dev/null +++ b/chan_capi_qsig_ecma.h @@ -0,0 +1,58 @@ +/* + * (QSIG) + * + * Implementation of QSIG extensions for CHAN_CAPI + * + * Copyright 2006-2007 (c) Mario Goegel + * + * Mario Goegel + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#include "chan_capi_qsig_asn197ade.h" + +#ifndef PBX_QSIG_ECMA_H +#define PBX_QSIG_ECMA_H + +/* ECMA Features structs */ + +/* Call Transfer Complete struct */ +struct cc_qsig_ctcomplete { + enum { + primaryEnd, /* 0 */ + secondaryEnd /* 1 */ + } endDesignation; + + struct asn197ade_numberscreened redirectionNumber; + char *basicCallInfoElements; /* OPTIONAL: ASN1_APPLICATION Type */ + char *redirectionName; /* OPTIONAL */ + enum { + answered, + alerting + } callStatus; /* DEFAULT: answered */ + char *argumentExtension; /* OPTIONAL: ASN1_SEQUENCE - manufacturer specific extension */ +}; + + +/* + *** ECMA QSIG Functions + */ + +extern void cc_qsig_op_ecma_isdn_namepres(struct cc_qsig_invokedata *invoke, struct capi_pvt *i); +extern int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, int nametype, char *name); + +extern int cc_qsig_encode_ecma_isdn_leginfo3_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *name); + +extern void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct capi_pvt *i); + +extern void cc_qsig_op_ecma_isdn_prpropose(struct cc_qsig_invokedata *invoke, struct capi_pvt *i); +extern void cc_qsig_encode_ecma_prpropose(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param); + +extern void cc_qsig_encode_ecma_sscalltransfer(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param); + +extern void cc_qsig_encode_ecma_calltransfer(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param, int info); +extern unsigned int cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct capi_pvt *i, struct cc_qsig_ctcomplete *ctc); + +#endif diff --git a/chan_capi_rtp.c b/chan_capi_rtp.c index acb3de0..d11bd18 100644 --- a/chan_capi_rtp.c +++ b/chan_capi_rtp.c @@ -1,8 +1,7 @@ /* * (CAPI*) * - * An implementation of Common ISDN API 2.0 for - * Asterisk / OpenPBX.org + * An implementation of Common ISDN API 2.0 for Asterisk * * Copyright (C) 2006-2007 Cytronics & Melware * @@ -11,11 +10,6 @@ * This program is free software and may be modified and * distributed under the terms of the GNU Public License. */ -#ifdef PBX_IS_OPBX -#ifdef HAVE_CONFIG_H -#include "confdefs.h" -#endif -#endif #include #include @@ -27,41 +21,10 @@ #include #include -#ifdef PBX_IS_OPBX -#include "openpbx/lock.h" -#include "openpbx/frame.h" -#include "openpbx/channel.h" -#include "openpbx/logger.h" -#include "openpbx/module.h" -#include "openpbx/pbx.h" -#include "openpbx/config.h" -#include "openpbx/options.h" -#include "openpbx/features.h" -#include "openpbx/utils.h" -#include "openpbx/rtp.h" -#include "openpbx/strings.h" -#include "openpbx/chan_capi20.h" -#include "openpbx/chan_capi.h" -#include "openpbx/chan_capi_rtp.h" -#else -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "chan_capi20.h" #include "chan_capi.h" #include "chan_capi_rtp.h" -#endif +#include "chan_capi_utils.h" /* RTP settings / NCPI RTP struct */ @@ -225,10 +188,8 @@ int capi_alloc_rtp(struct capi_pvt *i) /* * write rtp for a channel */ -int capi_write_rtp(struct ast_channel *c, struct ast_frame *f) +int capi_write_rtp(struct capi_pvt *i, struct ast_frame *f) { - struct capi_pvt *i = CC_CHANNEL_PVT(c); - _cmsg CMSG; struct sockaddr_in us; int len; socklen_t uslen; @@ -281,14 +242,13 @@ int capi_write_rtp(struct ast_channel *c, struct ast_frame *f) i->vname, i->NCCI, len, f->datalen, ast_getformatname(f->subclass), i->timestamp); - DATA_B3_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - DATA_B3_REQ_NCCI(&CMSG) = i->NCCI; - DATA_B3_REQ_FLAGS(&CMSG) = 0; - DATA_B3_REQ_DATAHANDLE(&CMSG) = i->send_buffer_handle; - DATA_B3_REQ_DATALENGTH(&CMSG) = len; - DATA_B3_REQ_DATA(&CMSG) = (buf); - - _capi_put_cmsg(&CMSG); + capi_sendf(NULL, 0, CAPI_DATA_B3_REQ, i->NCCI, get_capi_MessageNumber(), + "dwww", + buf, + len, + i->send_buffer_handle, + 0 + ); } return 0; @@ -352,11 +312,11 @@ void voice_over_ip_profile(struct cc_capi_controller *cp) unsigned short info = 0; unsigned int payload1, payload2; - FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0); - FACILITY_REQ_CONTROLLER(&CMSG) = cp->controller; - FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_VOICE_OVER_IP; - FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)&fac; - _capi_put_cmsg(&CMSG); + capi_sendf(NULL, 0, CAPI_FACILITY_REQ, cp->controller, get_capi_MessageNumber(), + "ws", + FACILITYSELECTOR_VOICE_OVER_IP, + &fac + ); tv.tv_sec = 1; tv.tv_usec = 0; diff --git a/chan_capi_rtp.h b/chan_capi_rtp.h index bea73af..6377679 100644 --- a/chan_capi_rtp.h +++ b/chan_capi_rtp.h @@ -1,8 +1,7 @@ /* * (CAPI*) * - * An implementation of Common ISDN API 2.0 for - * Asterisk / OpenPBX.org + * An implementation of Common ISDN API 2.0 for Asterisk * * Copyright (C) 2006-2007 Cytronics & Melware * @@ -20,7 +19,7 @@ */ extern int capi_alloc_rtp(struct capi_pvt *i); extern void voice_over_ip_profile(struct cc_capi_controller *cp); -extern int capi_write_rtp(struct ast_channel *c, struct ast_frame *f); +extern int capi_write_rtp(struct capi_pvt *i, struct ast_frame *f); extern struct ast_frame *capi_read_rtp(struct capi_pvt *i, unsigned char *buf, int len); extern _cstruct capi_rtp_ncpi(struct capi_pvt *i); diff --git a/chan_capi_supplementary.c b/chan_capi_supplementary.c new file mode 100644 index 0000000..c7f1777 --- /dev/null +++ b/chan_capi_supplementary.c @@ -0,0 +1,845 @@ +/* + * (CAPI*) + * + * An implementation of Common ISDN API 2.0 for Asterisk + * + * Copyright (C) 2005-2007 Cytronics & Melware + * + * Armin Schindler + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#include +#include +#include + +#include "chan_capi20.h" +#include "chan_capi.h" +#include "chan_capi_supplementary.h" +#include "chan_capi_utils.h" + + +#define CCBSNR_TYPE_CCBS 1 +#define CCBSNR_TYPE_CCNR 2 + +#define CCBSNR_AVAILABLE 1 +#define CCBSNR_REQUESTED 2 +#define CCBSNR_ACTIVATED 3 + +struct ccbsnr_s { + char type; + _cword id; + unsigned int plci; + unsigned int state; + unsigned int handle; + _cword mode; + _cword rbref; + char partybusy; + char context[AST_MAX_CONTEXT]; + char exten[AST_MAX_EXTENSION]; + int priority; + time_t age; + struct ccbsnr_s *next; +}; + +static struct ccbsnr_s *ccbsnr_list = NULL; +AST_MUTEX_DEFINE_STATIC(ccbsnr_lock); + +/* + * remove too old CCBS/CCNR entries + * (must be called with ccbsnr_lock held) + */ +static void del_old_ccbsnr(void) +{ + struct ccbsnr_s *ccbsnr; + struct ccbsnr_s *tmp = NULL; + + ccbsnr = ccbsnr_list; + while (ccbsnr) { + if ((ccbsnr->age + 86400) < time(NULL)) { + cc_verbose(1, 1, VERBOSE_PREFIX_3 "CAPI: CCBS/CCNR handle=%d timeout.\n", + ccbsnr->handle); + if (!tmp) { + ccbsnr_list = ccbsnr->next; + } else { + tmp->next = ccbsnr->next; + } + free(ccbsnr); + break; + } + tmp = ccbsnr; + ccbsnr = ccbsnr->next; + } +} + +/* + * cleanup CCBS/CCNR ids + */ +void cleanup_ccbsnr(void) +{ + struct ccbsnr_s *ccbsnr; + struct ccbsnr_s *tmp = NULL; + + cc_mutex_lock(&ccbsnr_lock); + ccbsnr = ccbsnr_list; + while (ccbsnr) { + tmp = ccbsnr; + ccbsnr = ccbsnr->next; + free(tmp); + } + cc_mutex_unlock(&ccbsnr_lock); +} + +/* + * return the controller of ccbsnr handle + */ +unsigned int capi_get_ccbsnrcontroller(unsigned int handle) +{ + unsigned int contr = 0; + struct ccbsnr_s *ccbsnr; + + cc_mutex_lock(&ccbsnr_lock); + ccbsnr = ccbsnr_list; + while (ccbsnr) { + if (ccbsnr->handle == handle) { + contr = (ccbsnr->plci & 0xff); + break; + } + ccbsnr = ccbsnr->next; + } + cc_mutex_unlock(&ccbsnr_lock); + + return contr; +} + +/* + * a new CCBS/CCNR id was received + */ +static void new_ccbsnr_id(char type, unsigned int plci, + _cword id, struct capi_pvt *i) +{ + char buffer[CAPI_MAX_STRING]; + struct ccbsnr_s *ccbsnr; + + ccbsnr = malloc(sizeof(struct ccbsnr_s)); + if (ccbsnr == NULL) { + cc_log(LOG_ERROR, "Unable to allocate CCBS/CCNR struct.\n"); + return; + } + memset(ccbsnr, 0, sizeof(struct ccbsnr_s)); + + ccbsnr->age = time(NULL); + ccbsnr->type = type; + ccbsnr->id = id; + ccbsnr->rbref = 0xdead; + ccbsnr->plci = plci; + ccbsnr->state = CCBSNR_AVAILABLE; + ccbsnr->handle = (id | ((plci & 0xff) << 16) | (type << 28)); + + if (i->peer) { + snprintf(buffer, CAPI_MAX_STRING-1, "%u", ccbsnr->handle); + pbx_builtin_setvar_helper(i->peer, "CCLINKAGEID", buffer); + } else { + cc_log(LOG_NOTICE, "No peerlink found to set CCBS/CCNR linkage ID.\n"); + } + + cc_mutex_lock(&ccbsnr_lock); + del_old_ccbsnr(); + ccbsnr->next = ccbsnr_list; + ccbsnr_list = ccbsnr; + cc_mutex_unlock(&ccbsnr_lock); + + cc_verbose(1, 1, VERBOSE_PREFIX_3 + "%s: PLCI=%#x CCBS/CCNR new id=0x%04x handle=%d\n", + i->vname, plci, id, ccbsnr->handle); + + /* if the hangup frame was deferred, it can be done now and here */ + if (i->whentoqueuehangup) { + i->whentoqueuehangup = 0; + capi_queue_cause_control(i, 1); + } +} + +/* + * return the pointer to ccbsnr structure by handle + */ +static struct ccbsnr_s *get_ccbsnr_link(char type, unsigned int plci, + unsigned int handle, _cword ref, unsigned int *state, char *busy) +{ + struct ccbsnr_s *ret; + + cc_mutex_lock(&ccbsnr_lock); + ret = ccbsnr_list; + while (ret) { + if (((handle) && (ret->handle == handle)) || + ((ref != 0xffff) && (ret->rbref == ref) && + (ret->type == type) && ((ret->plci & 0xff) == (plci & 0xff)))) { + if (state) { + *state = ret->state; + } + if (busy) { + *busy = ret->partybusy; + } + break; + } + ret = ret->next; + } + cc_mutex_unlock(&ccbsnr_lock); + + return ret; +} + +/* + * function to tell if CCBSNR is activated + */ +static int ccbsnr_tell_activated(void *data) +{ + unsigned int handle = (unsigned int)data; + int ret = 0; + unsigned int state; + + if (get_ccbsnr_link(0, 0, handle, 0xffff, &state, NULL) != NULL) { + if (state == CCBSNR_REQUESTED) { + ret = 1; + } + } + + return ret; +} + +/* + * select CCBS/CCNR id + */ +static unsigned int select_ccbsnr_id(unsigned int id, char type, + char *context, char *exten, int priority) +{ + struct ccbsnr_s *ccbsnr; + int ret = 0; + + cc_mutex_lock(&ccbsnr_lock); + ccbsnr = ccbsnr_list; + while (ccbsnr) { + if (((ccbsnr->plci & 0xff) == ((id >> 16) & 0xff)) && + (ccbsnr->id == (id & 0xffff)) && + (ccbsnr->type == type) && + (ccbsnr->state == CCBSNR_AVAILABLE)) { + strncpy(ccbsnr->context, context, sizeof(ccbsnr->context) - 1); + strncpy(ccbsnr->exten, exten, sizeof(ccbsnr->exten) - 1); + ccbsnr->priority = priority; + ccbsnr->state = CCBSNR_REQUESTED; + ret = ccbsnr->handle; + cc_verbose(1, 1, VERBOSE_PREFIX_3 "CAPI: request CCBS/NR id=0x%x handle=%d (%s,%s,%d)\n", + id, ret, context, exten, priority); + break; + } + ccbsnr = ccbsnr->next; + } + cc_mutex_unlock(&ccbsnr_lock); + + return ret; +} + +/* + * a CCBS/CCNR ref was removed + */ +static void del_ccbsnr_ref(unsigned int plci, _cword ref) +{ + struct ccbsnr_s *ccbsnr; + struct ccbsnr_s *tmp = NULL; + + cc_mutex_lock(&ccbsnr_lock); + ccbsnr = ccbsnr_list; + while (ccbsnr) { + if (((ccbsnr->plci & 0xff) == (plci & 0xff)) && + (ccbsnr->rbref == ref)) { + if (!tmp) { + ccbsnr_list = ccbsnr->next; + } else { + tmp->next = ccbsnr->next; + } + free(ccbsnr); + cc_verbose(1, 1, VERBOSE_PREFIX_3 "CAPI: PLCI=%#x CCBS/CCNR removed " + "ref=0x%04x\n", plci, ref); + break; + } + tmp = ccbsnr; + ccbsnr = ccbsnr->next; + } + cc_mutex_unlock(&ccbsnr_lock); +} + +/* + * return rbref of CCBS/CCNR and delete entry + */ +_cword capi_ccbsnr_take_ref(unsigned int handle) +{ + unsigned int plci = 0; + _cword rbref = 0xdead; + struct ccbsnr_s *ccbsnr; + + cc_mutex_lock(&ccbsnr_lock); + ccbsnr = ccbsnr_list; + while (ccbsnr) { + if (ccbsnr->handle == handle) { + plci = ccbsnr->plci; + rbref = ccbsnr->rbref; + break; + } + ccbsnr = ccbsnr->next; + } + cc_mutex_unlock(&ccbsnr_lock); + + if (rbref != 0xdead) { + del_ccbsnr_ref(plci, rbref); + } + + return rbref; +} + +/* + * a CCBS/CCNR id was removed + */ +static void del_ccbsnr_id(unsigned int plci, _cword id) +{ + struct ccbsnr_s *ccbsnr; + struct ccbsnr_s *tmp = NULL; + unsigned int oldstate; + + cc_mutex_lock(&ccbsnr_lock); + ccbsnr = ccbsnr_list; + while (ccbsnr) { + if (((ccbsnr->plci & 0xff) == (plci & 0xff)) && + (ccbsnr->id == id)) { + oldstate = ccbsnr->state; + if (ccbsnr->state == CCBSNR_AVAILABLE) { + if (!tmp) { + ccbsnr_list = ccbsnr->next; + } else { + tmp->next = ccbsnr->next; + } + free(ccbsnr); + cc_verbose(1, 1, VERBOSE_PREFIX_3 "CAPI: PLCI=%#x CCBS/CCNR removed " + "id=0x%04x state=%d\n", plci, id, oldstate); + } else { + /* just deactivate the linkage id */ + ccbsnr->id = 0xdead; + cc_verbose(1, 1, VERBOSE_PREFIX_3 "CAPI: PLCI=%#x CCBS/CCNR erase-only " + "id=0x%04x state=%d\n", plci, id, ccbsnr->state); + } + break; + } + tmp = ccbsnr; + ccbsnr = ccbsnr->next; + } + cc_mutex_unlock(&ccbsnr_lock); +} + +/* + * on an activated CCBS, the remote party is now free + */ +static void ccbsnr_remote_user_free(_cmsg *CMSG, char type, unsigned int PLCI, _cword rbref) +{ + struct ast_channel *c; + struct ccbsnr_s *ccbsnr; + char handlename[CAPI_MAX_STRING]; + int state = AST_STATE_DOWN; + + /* XXX start alerting , when answered use CCBS call */ + cc_mutex_lock(&ccbsnr_lock); + ccbsnr = ccbsnr_list; + while (ccbsnr) { + if ((ccbsnr->type == type) && + ((ccbsnr->plci & 0xff) == (PLCI & 0xff)) && + (ccbsnr->rbref == rbref)) { + break; + } + ccbsnr = ccbsnr->next; + } + cc_mutex_unlock(&ccbsnr_lock); + + if (!(ccbsnr)) { + cc_log(LOG_ERROR, "CAPI CCBS/CCBR reference not found!\n"); + return; + } + + snprintf(handlename, CAPI_MAX_STRING-1, "%u", ccbsnr->handle); + +#ifdef CC_AST_HAS_EXT_CHAN_ALLOC + c = ast_channel_alloc(0, state, handlename, NULL, +#ifdef CC_AST_HAS_EXT2_CHAN_ALLOC + 0, ccbsnr->exten, ccbsnr->context, 0, +#endif + "CCBSNR/%x", ccbsnr->handle); +#else + c = ast_channel_alloc(0); +#endif + + if (c == NULL) { + cc_log(LOG_ERROR, "Unable to allocate channel!\n"); + return; + } + +#ifndef CC_AST_HAS_EXT_CHAN_ALLOC +#ifdef CC_AST_HAS_STRINGFIELD_IN_CHANNEL + ast_string_field_build(c, name, "CCBSNR/%x", ccbsnr->handle); +#else + snprintf(c->name, sizeof(c->name) - 1, "CCBSNR/%x", + ccbsnr->handle); +#endif +#endif +#ifndef CC_AST_HAS_VERSION_1_4 + c->type = "CCBS/CCNR"; +#endif + + c->priority = ccbsnr->priority; + + if (c->cid.cid_num) { + free(c->cid.cid_num); + } + c->cid.cid_num = strdup(handlename); + if (c->cid.cid_dnid) { + free(c->cid.cid_dnid); + } + c->cid.cid_dnid = strdup(ccbsnr->exten); + +#ifndef CC_AST_HAS_EXT2_CHAN_ALLOC + cc_copy_string(c->context, ccbsnr->context, sizeof(c->context)); + cc_copy_string(c->exten, ccbsnr->exten, sizeof(c->exten)); +#endif + +#ifndef CC_AST_HAS_EXT_CHAN_ALLOC + ast_setstate(c, state); +#endif + + if (ast_pbx_start(c)) { + cc_log(LOG_ERROR, "capi CCBS/CCNR: Unable to start pbx!\n"); + } else { + cc_verbose(2, 1, VERBOSE_PREFIX_2 "contr%d: started PBX for CCBS/CCNR callback (%s/%s/%d)\n", + PLCI & 0xff, ccbsnr->context, ccbsnr->exten, ccbsnr->priority); + } +} + +/* + * send Listen for supplementary to specified controller + */ +void ListenOnSupplementary(unsigned controller) +{ + _cmsg CMSG; + MESSAGE_EXCHANGE_ERROR error; + int waitcount = 50; + + error = capi_sendf(NULL, 0, CAPI_FACILITY_REQ, controller, get_capi_MessageNumber(), + "w(w(d))", + FACILITYSELECTOR_SUPPLEMENTARY, + 0x0001, /* LISTEN */ + 0x0000079f + ); + + while (waitcount) { + error = capidev_check_wait_get_cmsg(&CMSG); + + if (IS_FACILITY_CONF(&CMSG)) { + break; + } + usleep(30000); + waitcount--; + } + if (!waitcount) { + cc_log(LOG_ERROR,"Unable to supplementary-listen on contr%d (error=0x%x)\n", + controller, error); + } +} + +/* + * CAPI FACILITY_IND supplementary services + */ +int handle_facility_indication_supplementary( + _cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i) +{ + _cword function; + _cword infoword = 0xffff; + unsigned char length; + _cdword handle; + _cword mode; + _cword rbref; + struct ccbsnr_s *ccbsnrlink; + char partybusy = 0; + int ret = 0; + + function = read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1]); + length = FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3]; + + if (length >= 2) { + infoword = read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4]); + } + + /* first check functions without interface needed */ + switch (function) { + case 0x000f: /* CCBS request */ + handle = read_capi_dword(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[6]); + mode = read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[10]); + rbref = read_capi_dword(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[12]); + cc_verbose(1, 1, VERBOSE_PREFIX_3 "contr%d: PLCI=%#x CCBS request reason=0x%04x " + "handle=%d mode=0x%x rbref=0x%x\n", + PLCI & 0xff, PLCI, infoword, handle, mode, rbref); + show_capi_info(NULL, infoword); + if ((ccbsnrlink = get_ccbsnr_link(0, 0, handle, 0xffff, NULL, NULL)) == NULL) { + cc_log(LOG_WARNING, "capi ccbs request indication without request!\n"); + break; + } + if (infoword == 0) { + /* success */ + ccbsnrlink->state = CCBSNR_ACTIVATED; + ccbsnrlink->rbref = rbref; + ccbsnrlink->mode = mode; + } else { + /* error */ + ccbsnrlink->state = CCBSNR_AVAILABLE; + } + break; + case 0x0010: /* CCBS deactivate */ + handle = read_capi_dword(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[6]); + cc_verbose(1, 1, VERBOSE_PREFIX_3 "contr%d: PLCI=%#x CCBS deactivate handle=0x%x reason=0x%x\n", + PLCI & 0xff, PLCI, handle, infoword); + show_capi_info(NULL, infoword); + if ((ccbsnrlink = get_ccbsnr_link(0, 0, handle, 0xffff, NULL, NULL)) == NULL) { + cc_log(LOG_WARNING, "capi ccbs deactivate indication without request!\n"); + break; + } + if (infoword == 0) { + /* success */ + ccbsnrlink->state = CCBSNR_AVAILABLE; + ccbsnrlink->rbref = 0xdead; + ccbsnrlink->id = 0xdead; + ccbsnrlink->mode = 0; + } + break; + case 0x800d: /* CCBS erase call linkage ID */ + cc_verbose(1, 1, VERBOSE_PREFIX_3 "contr%d: PLCI=%#x CCBS/CCNR erase id=0x%04x\n", + PLCI & 0xff, PLCI, infoword); + del_ccbsnr_id(PLCI, infoword); + break; + case 0x800e: /* CCBS status */ + rbref = read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[6]); + cc_verbose(1, 1, VERBOSE_PREFIX_3 "contr%d: PLCI=%#x CCBS status ref=0x%04x mode=0x%x\n", + PLCI & 0xff, PLCI, rbref, infoword); + if (get_ccbsnr_link(CCBSNR_TYPE_CCBS, PLCI, 0, rbref, NULL, &partybusy) == NULL) { + cc_log(LOG_WARNING, "capi CCBS status reference not found!\n"); + } + capi_sendf(NULL, 0, CAPI_FACILITY_RESP, PLCI, HEADER_MSGNUM(CMSG), + "w(w(w))", + FACILITYSELECTOR_SUPPLEMENTARY, + 0x800e, /* CCBS status */ + (partybusy) ? 0x0000 : 0x0001 + ); + ret = 1; + break; + case 0x800f: /* CCBS remote user free */ + rbref = read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[6]); + cc_verbose(1, 1, VERBOSE_PREFIX_3 "contr%d: PLCI=%#x CCBS remote user free ref=0x%04x mode=0x%x\n", + PLCI & 0xff, PLCI, rbref, infoword); + ccbsnr_remote_user_free(CMSG, CCBSNR_TYPE_CCBS, PLCI, rbref); + break; + case 0x8010: /* CCBS B-free */ + rbref = read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[6]); + cc_verbose(1, 1, VERBOSE_PREFIX_3 "contr%d: PLCI=%#x CCBS B-free ref=0x%04x mode=0x%x\n", + PLCI & 0xff, PLCI, rbref, infoword); + break; + case 0x8011: /* CCBS erase (ref), deactivated by network */ + rbref = read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[6]); + cc_verbose(1, 1, VERBOSE_PREFIX_3 "contr%d: PLCI=%#x CCBS deactivate ref=0x%04x mode=0x%x\n", + PLCI & 0xff, PLCI, rbref, infoword); + del_ccbsnr_ref(PLCI, rbref); + break; + case 0x8012: /* CCBS stop alerting */ + cc_verbose(1, 1, VERBOSE_PREFIX_3 "contr%d: PLCI=%#x CCBS B-free ref=0x%04x\n", + PLCI & 0xff, PLCI, infoword); + break; + } + + if (!i) { + cc_verbose(4, 1, "CAPI: FACILITY_IND SUPPLEMENTARY " + "no interface for PLCI=%#x\n", PLCI); + return ret; + } + + /* now functions bound to interface */ + switch (function) { + case 0x0002: /* HOLD */ + if (infoword != 0) { + /* reason != 0x0000 == problem */ + i->onholdPLCI = 0; + cc_log(LOG_WARNING, "%s: unable to put PLCI=%#x onhold, REASON = 0x%04x, maybe you need to subscribe for this...\n", + i->vname, PLCI, infoword); + show_capi_info(i, infoword); + } else { + /* reason = 0x0000 == call on hold */ + i->state = CAPI_STATE_ONHOLD; + cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x put onhold\n", + i->vname, PLCI); + } + break; + case 0x0003: /* RETRIEVE */ + if (infoword != 0) { + cc_log(LOG_WARNING, "%s: unable to retrieve PLCI=%#x, REASON = 0x%04x\n", + i->vname, PLCI, infoword); + show_capi_info(i, infoword); + } else { + i->state = CAPI_STATE_CONNECTED; + i->PLCI = i->onholdPLCI; + i->onholdPLCI = 0; + cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x retrieved\n", + i->vname, PLCI); + cc_start_b3(i); + } + break; + case 0x0006: /* ECT */ + cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x ECT Reason=0x%04x\n", + i->vname, PLCI, infoword); + show_capi_info(i, infoword); + break; + case 0x0007: /* 3PTY begin */ + cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x 3PTY begin Reason=0x%04x\n", + i->vname, PLCI, infoword); + show_capi_info(i, infoword); + break; + case 0x0008: /* 3PTY end */ + cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x 3PTY end Reason=0x%04x\n", + i->vname, PLCI, infoword); + show_capi_info(i, infoword); + break; + case 0x8013: /* CCBS info retain */ + cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x CCBS unique id=0x%04x\n", + i->vname, PLCI, infoword); + new_ccbsnr_id(CCBSNR_TYPE_CCBS, PLCI, infoword, i); + break; + case 0x8015: /* CCNR info retain */ + cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x CCNR unique id=0x%04x\n", + i->vname, PLCI, infoword); + new_ccbsnr_id(CCBSNR_TYPE_CCNR, PLCI, infoword, i); + break; + case 0x000e: /* CCBS status */ + case 0x000f: /* CCBS request */ + case 0x800f: /* CCBS remote user free */ + case 0x800d: /* CCBS erase call linkage ID */ + case 0x8010: /* CCBS B-free */ + case 0x8011: /* CCBS erase (ref), deactivated by network */ + case 0x8012: /* CCBS stop alerting */ + /* handled above */ + break; + default: + cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: unhandled FACILITY_IND supplementary function %04x\n", + i->vname, function); + } + return ret; +} + + +/* + * CAPI FACILITY_CONF supplementary + */ +void handle_facility_confirmation_supplementary( + _cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt **i) +{ + _cword function; + _cword serviceinfo; + char name[64]; + + if (*i) { + strncpy(name, (*i)->vname, sizeof(name) - 1); + } else { + snprintf(name, sizeof(name) - 1, "contr%d", PLCI & 0xff); + } + + function = read_capi_word(&FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[1]); + serviceinfo = read_capi_word(&FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[4]); + + switch(function) { + case 0x0002: /* HOLD */ + if (serviceinfo == 0) { + cc_verbose(2, 0, VERBOSE_PREFIX_3 "%s: Call on hold (PLCI=%#x)\n", + name, PLCI); + } + break; + case 0x0003: /* RETRIEVE */ + if (serviceinfo == 0) { + cc_verbose(2, 0, VERBOSE_PREFIX_3 "%s: Call retreived (PLCI=%#x)\n", + name, PLCI); + } + break; + case 0x000f: /* CCBS request */ + cc_verbose(2, 1, VERBOSE_PREFIX_3 "%s: CCBS request confirmation (0x%04x) (PLCI=%#x)\n", + name, serviceinfo, PLCI); + break; + case 0x0012: /* CCBS call */ + cc_verbose(2, 1, VERBOSE_PREFIX_3 "%s: CCBS call confirmation (0x%04x) (PLCI=%#x)\n", + name, serviceinfo, PLCI); + capidev_handle_connection_conf(i, PLCI, FACILITY_CONF_INFO(CMSG), HEADER_MSGNUM(CMSG)); + break; + default: + cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: unhandled FACILITY_CONF supplementary function %04x\n", + name, function); + } +} + +/* + * capicommand 'ccpartybusy' + */ +int pbx_capi_ccpartybusy(struct ast_channel *c, char *data) +{ + char *slinkageid, *yesno; + unsigned int linkid = 0; + struct ccbsnr_s *ccbsnr; + char partybusy = 0; + + slinkageid = strsep(&data, "|"); + yesno = data; + + if (slinkageid) { + linkid = (unsigned int)strtoul(slinkageid, NULL, 0); + } + + if ((yesno) && ast_true(yesno)) { + partybusy = 1; + } + + cc_mutex_lock(&ccbsnr_lock); + ccbsnr = ccbsnr_list; + while (ccbsnr) { + if (((ccbsnr->plci & 0xff) == ((linkid >> 16) & 0xff)) && + (ccbsnr->id == (linkid & 0xffff))) { + ccbsnr->partybusy = partybusy; + cc_verbose(1, 1, VERBOSE_PREFIX_3 "CAPI: CCBS/NR id=0x%x busy set to %d\n", + linkid, partybusy); + break; + } + ccbsnr = ccbsnr->next; + } + cc_mutex_unlock(&ccbsnr_lock); + + return 0; +} + +/* + * capicommand 'ccbsstop' + */ +int pbx_capi_ccbsstop(struct ast_channel *c, char *data) +{ + char *slinkageid; + unsigned int linkid = 0; + unsigned int handle = 0; + MESSAGE_EXCHANGE_ERROR error; + _cword ref = 0xdead; + struct ccbsnr_s *ccbsnr; + + slinkageid = data; + + if (slinkageid) { + linkid = (unsigned int)strtoul(slinkageid, NULL, 0); + } + + cc_verbose(3, 1, VERBOSE_PREFIX_3 "capi ccbsstop: '%d'\n", + linkid); + + cc_mutex_lock(&ccbsnr_lock); + ccbsnr = ccbsnr_list; + while (ccbsnr) { + if (((ccbsnr->plci & 0xff) == ((linkid >> 16) & 0xff)) && + (ccbsnr->id == (linkid & 0xffff)) && + (ccbsnr->type == CCBSNR_TYPE_CCBS) && + (ccbsnr->state == CCBSNR_ACTIVATED)) { + ref = ccbsnr->rbref; + handle = ccbsnr->handle; + break; + } + ccbsnr = ccbsnr->next; + } + cc_mutex_unlock(&ccbsnr_lock); + + if (ref != 0xdead) { + error = capi_sendf(NULL, 0, CAPI_FACILITY_REQ, (linkid >> 16) & 0xff, + get_capi_MessageNumber(), + "w(w(dw))", + FACILITYSELECTOR_SUPPLEMENTARY, + 0x0010, /* CCBS deactivate */ + handle, /* handle */ + ref /* CCBS reference */ + ); + } else { + cc_verbose(3, 1, VERBOSE_PREFIX_3, "capi ccbsstop: linkid %d not found in table.\n", + linkid); + } + + return 0; +} + +/* + * capicommand 'ccbs' + */ +int pbx_capi_ccbs(struct ast_channel *c, char *data) +{ + char *slinkageid, *context, *exten, *priority; + unsigned int linkid = 0; + unsigned int handle, a; + char *result = "ERROR"; + char *goodresult = "ACTIVATED"; + MESSAGE_EXCHANGE_ERROR error; + unsigned int ccbsnrstate; + + slinkageid = strsep(&data, "|"); + context = strsep(&data, "|"); + exten = strsep(&data, "|"); + priority = data; + + if (slinkageid) { + linkid = (unsigned int)strtoul(slinkageid, NULL, 0); + } + + if ((!context) || (!exten) || (!priority)) { + cc_log(LOG_WARNING, "capi ccbs requires ||\n"); + return -1; + } + + cc_verbose(3, 1, VERBOSE_PREFIX_3 "capi ccbs: '%d' '%s' '%s' '%s'\n", + linkid, context, exten, priority); + + handle = select_ccbsnr_id(linkid, CCBSNR_TYPE_CCBS, + context, exten, (int)strtol(priority, NULL, 0)); + + if (handle > 0) { + error = capi_sendf(NULL, 0, CAPI_FACILITY_REQ, (linkid >> 16) & 0xff, + get_capi_MessageNumber(), + "w(w(dw))", + FACILITYSELECTOR_SUPPLEMENTARY, + 0x000f, /* CCBS request */ + handle, /* handle */ + (linkid & 0xffff) /* CCBS linkage ID */ + ); + + for (a = 0; a < 7; a++) { + /* Wait for CCBS request indication */ + if (ast_safe_sleep_conditional(c, 500, ccbsnr_tell_activated, + (void *)handle) != 0) { + /* we got a hangup */ + cc_verbose(3, 1, + VERBOSE_PREFIX_3 "capi ccbs: hangup.\n"); + break; + } + } + if (get_ccbsnr_link(0, 0, handle, 0xffff, &ccbsnrstate, NULL) != NULL) { + if (ccbsnrstate == CCBSNR_ACTIVATED) { + result = goodresult; + } + } + } else { + cc_verbose(3, 1, VERBOSE_PREFIX_3, "capi ccbs: linkid %d not found in table.\n", + linkid); + } + + pbx_builtin_setvar_helper(c, "CCBSSTATUS", result); + + return 0; +} + diff --git a/chan_capi_supplementary.h b/chan_capi_supplementary.h new file mode 100644 index 0000000..33423a5 --- /dev/null +++ b/chan_capi_supplementary.h @@ -0,0 +1,32 @@ +/* + * (CAPI*) + * + * An implementation of Common ISDN API 2.0 for Asterisk + * + * Copyright (C) 2006-2007 Cytronics & Melware + * + * Armin Schindler + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#ifndef _PBX_CAPI_SUPP_H +#define _PBX_CAPI_SUPP_H + +/* + * prototypes + */ +extern void ListenOnSupplementary(unsigned controller); +extern int handle_facility_indication_supplementary( + _cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i); +extern void handle_facility_confirmation_supplementary( + _cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt **i); +extern int pbx_capi_ccbs(struct ast_channel *c, char *data); +extern int pbx_capi_ccbsstop(struct ast_channel *c, char *data); +extern int pbx_capi_ccpartybusy(struct ast_channel *c, char *data); +extern void cleanup_ccbsnr(void); +extern unsigned int capi_get_ccbsnrcontroller(unsigned int handle); +extern _cword capi_ccbsnr_take_ref(unsigned int handle); + +#endif diff --git a/chan_capi_utils.c b/chan_capi_utils.c new file mode 100644 index 0000000..e5bd593 --- /dev/null +++ b/chan_capi_utils.c @@ -0,0 +1,1252 @@ +/* + * (CAPI*) + * + * An implementation of Common ISDN API 2.0 for Asterisk + * + * Copyright (C) 2006-2007 Cytronics & Melware + * + * Armin Schindler + * + * capi_sendf() by Eicon Networks / Dialogic + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#include +#include +#include +#include +#include +#include +#include "xlaw.h" +#include "chan_capi20.h" +#include "chan_capi.h" +#include "chan_capi_rtp.h" +#include "chan_capi_utils.h" +#include "chan_capi_supplementary.h" + +int capidebug = 0; +char *emptyid = "\0"; + +AST_MUTEX_DEFINE_STATIC(verbose_lock); +AST_MUTEX_DEFINE_STATIC(messagenumber_lock); +AST_MUTEX_DEFINE_STATIC(capi_put_lock); +AST_MUTEX_DEFINE_STATIC(peerlink_lock); +AST_MUTEX_DEFINE_STATIC(nullif_lock); + +static _cword capi_MessageNumber; + +static struct capi_pvt *nulliflist = NULL; +static int controller_nullplcis[CAPI_MAX_CONTROLLERS]; + +#define CAPI_MAX_PEERLINKCHANNELS 32 +static struct peerlink_s { + struct ast_channel *channel; + time_t age; +} peerlinkchannel[CAPI_MAX_PEERLINKCHANNELS]; + +/* + * helper for _verbose with different verbose settings + */ +void cc_verbose(int o_v, int c_d, char *text, ...) +{ + char line[4096]; + va_list ap; + + va_start(ap, text); + vsnprintf(line, sizeof(line), text, ap); + va_end(ap); + +#if 0 + { + FILE *fp; + if ((fp = fopen("/tmp/cclog", "a")) != NULL) { + fprintf(fp, "%s", line); + fclose(fp); + } + } +#endif + + if ((o_v == 0) || (option_verbose > o_v)) { + if ((!c_d) || ((c_d) && (capidebug))) { + cc_mutex_lock(&verbose_lock); + cc_pbx_verbose(line); + cc_mutex_unlock(&verbose_lock); + } + } +} + +/* + * hangup and remove null-interface + */ +void capi_remove_nullif(struct capi_pvt *i) +{ + struct capi_pvt *ii; + struct capi_pvt *tmp = NULL; + int state; + + if (i->channeltype != CAPI_CHANNELTYPE_NULL) { + return; + } + + if (i->PLCI != 0) { + /* if the interface is in use, hangup first */ + cc_mutex_lock(&i->lock); + + state = i->state; + i->state = CAPI_STATE_DISCONNECTING; + capi_activehangup(i, state); + + cc_mutex_unlock(&i->lock); + + return; + } + + cc_mutex_lock(&nullif_lock); + ii = nulliflist; + while (ii) { + if (ii == i) { + if (!tmp) { + nulliflist = ii->next; + } else { + tmp->next = ii->next; + } + cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: removed null-interface from controller %d.\n", + i->vname, i->controller); + if (i->smoother) + ast_smoother_free(i->smoother); + cc_mutex_destroy(&i->lock); + ast_cond_destroy(&i->event_trigger); + controller_nullplcis[i->controller - 1]--; + free(i); + break; + } + tmp = ii; + ii = ii->next; + } + cc_mutex_unlock(&nullif_lock); +} + +/* + * create new null-interface + */ +struct capi_pvt *capi_mknullif(struct ast_channel *c, unsigned long controllermask) +{ + struct capi_pvt *tmp; + unsigned int controller = 1; + int contrcount; + int channelcount = 0xffff; + + /* find the next controller of mask with least plcis used */ + for (contrcount = 0; contrcount < CAPI_MAX_CONTROLLERS; contrcount++) { + if ((controllermask & (1 << contrcount))) { + if (controller_nullplcis[contrcount] < channelcount) { + channelcount = controller_nullplcis[contrcount]; + controller = contrcount + 1; + } + } + } + + tmp = malloc(sizeof(struct capi_pvt)); + if (!tmp) { + return NULL; + } + memset(tmp, 0, sizeof(struct capi_pvt)); + + cc_mutex_init(&tmp->lock); + ast_cond_init(&tmp->event_trigger, NULL); + + snprintf(tmp->name, sizeof(tmp->name) - 1, "%s-NULLPLCI", c->name); + snprintf(tmp->vname, sizeof(tmp->vname) - 1, "%s", tmp->name); + + tmp->channeltype = CAPI_CHANNELTYPE_NULL; + + tmp->used = c; + tmp->peer = c; + + tmp->cip = CAPI_CIPI_SPEECH; + tmp->transfercapability = PRI_TRANS_CAP_SPEECH; + tmp->controller = controller; + tmp->doEC = 1; + tmp->doEC_global = 1; + tmp->ecOption = EC_OPTION_DISABLE_NEVER; + tmp->ecTail = EC_DEFAULT_TAIL; + tmp->isdnmode = CAPI_ISDNMODE_MSN; + tmp->ecSelector = FACILITYSELECTOR_ECHO_CANCEL; + tmp->capability = capi_capability; + + tmp->rxgain = 1.0; + tmp->txgain = 1.0; + capi_gains(&tmp->g, 1.0, 1.0); + + if (!(capi_create_reader_writer_pipe(tmp))) { + free(tmp); + return NULL; + } + + tmp->bproto = CC_BPROTO_TRANSPARENT; + tmp->doB3 = CAPI_B3_DONT; + tmp->smoother = ast_smoother_new(CAPI_MAX_B3_BLOCK_SIZE); + tmp->isdnstate |= CAPI_ISDN_STATE_PBX; + + cc_mutex_lock(&nullif_lock); + tmp->next = nulliflist; /* prepend */ + nulliflist = tmp; + controller_nullplcis[tmp->controller - 1]++; + cc_mutex_unlock(&nullif_lock); + + /* connect to driver */ + tmp->outgoing = 1; + tmp->state = CAPI_STATE_CONNECTPENDING; + tmp->MessageNumber = get_capi_MessageNumber(); + + capi_sendf(NULL, 0, CAPI_CONNECT_REQ, controller, tmp->MessageNumber, + "w()()()()(www()()()())()()()((wwbbb)()()())", + 0, 1,1,0, 3,0,0,0,0); + + cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: created null-interface on controller %d.\n", + tmp->vname, tmp->controller); + + return tmp; +} + +/* + * get a new capi message number atomically + */ +_cword get_capi_MessageNumber(void) +{ + _cword mn; + + cc_mutex_lock(&messagenumber_lock); + + capi_MessageNumber++; + if (capi_MessageNumber == 0) { + /* avoid zero */ + capi_MessageNumber = 1; + } + + mn = capi_MessageNumber; + + cc_mutex_unlock(&messagenumber_lock); + + return(mn); +} + +/* + * find the interface (pvt) the PLCI belongs to + */ +struct capi_pvt *capi_find_interface_by_plci(unsigned int plci) +{ + struct capi_pvt *i; + + if (plci == 0) + return NULL; + + for (i = capi_iflist; i; i = i->next) { + if (i->PLCI == plci) + return i; + } + + cc_mutex_lock(&nullif_lock); + for (i = nulliflist; i; i = i->next) { + if (i->PLCI == plci) + break; + } + cc_mutex_unlock(&nullif_lock); + + return i; +} + +/* + * find the interface (pvt) the messagenumber belongs to + */ +struct capi_pvt *capi_find_interface_by_msgnum(unsigned short msgnum) +{ + struct capi_pvt *i; + + if (msgnum == 0x0000) + return NULL; + + for (i = capi_iflist; i; i = i->next) { + if ((i->PLCI == 0) && (i->MessageNumber == msgnum)) + return i; + } + + cc_mutex_lock(&nullif_lock); + for (i = nulliflist; i; i = i->next) { + if ((i->PLCI == 0) && (i->MessageNumber == msgnum)) + break; + } + cc_mutex_unlock(&nullif_lock); + + return i; +} + +/* + * wait for a specific message + */ +MESSAGE_EXCHANGE_ERROR capi_wait_conf(struct capi_pvt *i, unsigned short wCmd) +{ + MESSAGE_EXCHANGE_ERROR error = 0; + struct timespec abstime; + unsigned char command, subcommand; + + subcommand = wCmd & 0xff; + command = (wCmd & 0xff00) >> 8; + i->waitevent = (unsigned int)wCmd; + abstime.tv_sec = time(NULL) + 2; + abstime.tv_nsec = 0; + cc_verbose(4, 1, "%s: wait for %s (0x%x)\n", + i->vname, capi_cmd2str(command, subcommand), i->waitevent); + if (ast_cond_timedwait(&i->event_trigger, &i->lock, &abstime) != 0) { + error = -1; + cc_log(LOG_WARNING, "%s: timed out waiting for %s\n", + i->vname, capi_cmd2str(command, subcommand)); + } else { + cc_verbose(4, 1, "%s: cond signal received for %s\n", + i->vname, capi_cmd2str(command, subcommand)); + } + return error; +} + +/* + * log an error in sending capi message + */ +static void log_capi_error_message(MESSAGE_EXCHANGE_ERROR err, _cmsg *CMSG) +{ + if (err) { + cc_log(LOG_ERROR, "CAPI error sending %s (NCCI=%#x) (error=%#x %s)\n", + capi_cmsg2str(CMSG), (unsigned int)HEADER_CID(CMSG), + err, capi_info_string((unsigned int)err)); + } +} + +/* + * log verbose a capi message + */ +static void log_capi_message(_cmsg *CMSG) +{ + unsigned short wCmd; + + wCmd = HEADER_CMD(CMSG); + if ((wCmd == CAPI_P_REQ(DATA_B3)) || + (wCmd == CAPI_P_RESP(DATA_B3))) { + cc_verbose(7, 1, "%s\n", capi_cmsg2str(CMSG)); + } else { + cc_verbose(4, 1, "%s\n", capi_cmsg2str(CMSG)); + } +} + +/* + * write a capi message to capi device + */ +static MESSAGE_EXCHANGE_ERROR _capi_put_msg(unsigned char *msg) +{ + MESSAGE_EXCHANGE_ERROR error; + _cmsg CMSG; + + if (cc_mutex_lock(&capi_put_lock)) { + cc_log(LOG_WARNING, "Unable to lock capi put!\n"); + return -1; + } + + capi_message2cmsg(&CMSG, msg); + log_capi_message(&CMSG); + + error = capi20_put_message(capi_ApplID, msg); + + if (cc_mutex_unlock(&capi_put_lock)) { + cc_log(LOG_WARNING, "Unable to unlock capi put!\n"); + return -1; + } + + log_capi_error_message(error, &CMSG); + + return error; +} + +/* + * wait some time for a new capi message + */ +MESSAGE_EXCHANGE_ERROR capidev_check_wait_get_cmsg(_cmsg *CMSG) +{ + MESSAGE_EXCHANGE_ERROR Info; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 500000; + + Info = capi20_waitformessage(capi_ApplID, &tv); + + if (Info == 0x0000) { + + Info = capi_get_cmsg(CMSG, capi_ApplID); + +#if (CAPI_OS_HINT == 1) || (CAPI_OS_HINT == 2) + if (Info == 0x0000) { + /* + * For BSD allow controller 0: + */ + if ((HEADER_CID(CMSG) & 0xFF) == 0) { + HEADER_CID(CMSG) += capi_num_controllers; + } + } +#endif + } + + if ((Info != 0x0000) && (Info != 0x1104)) { + if (capidebug) { + cc_log(LOG_DEBUG, "Error waiting for cmsg... INFO = %#x\n", Info); + } + } + + return Info; +} + +/* + * Eicon's capi_sendf() function to create capi messages easily + * and send this message. + * Copyright by Eicon Networks / Dialogic + */ +MESSAGE_EXCHANGE_ERROR capi_sendf( + struct capi_pvt *capii, int waitconf, + _cword command, _cdword Id, _cword Number, char * format, ...) +{ + MESSAGE_EXCHANGE_ERROR ret; + int i, j; + unsigned int d; + unsigned char *p, *p_length; + unsigned char *string; + unsigned short header_length; + va_list ap; + capi_prestruct_t *s; + unsigned char msg[2048]; + + write_capi_word(&msg[2], capi_ApplID); + write_capi_word(&msg[4], ((command >> 8) & 0xff)); + write_capi_word(&msg[5], (command & 0xff)); + write_capi_word(&msg[6], Number); + write_capi_dword(&msg[8], Id); + + p = &msg[12]; + p_length = 0; + + va_start(ap, format); + for (i = 0; format[i]; i++) { + if (((p - (&msg[0])) + 12) >= sizeof(msg)) { + cc_log(LOG_ERROR, "capi_sendf: message too big (%d)\n", + (p - (&msg[0]))); + return 0x1004; + } + switch(format[i]) { + case 'b': /* byte */ + d = (unsigned char)va_arg(ap, unsigned int); + *(p++) = (unsigned char) d; + break; + case 'w': /* word (2 bytes) */ + d = (unsigned short)va_arg(ap, unsigned int); + *(p++) = (unsigned char) d; + *(p++) = (unsigned char)(d >> 8); + break; + case 'd': /* double word (4 bytes) */ + d = va_arg(ap, unsigned int); + *(p++) = (unsigned char) d; + *(p++) = (unsigned char)(d >> 8); + *(p++) = (unsigned char)(d >> 16); + *(p++) = (unsigned char)(d >> 24); + break; + case 's': /* struct, length is the first byte */ + string = va_arg(ap, unsigned char *); + if (string == NULL) { + *(p++) = 0; + } else { + for (j = 0; j <= string[0]; j++) + *(p++) = string[j]; + } + break; + case 'a': /* ascii string, NULL terminated string */ + string = va_arg(ap, unsigned char *); + for (j = 0; string[j] != '\0'; j++) + *(++p) = string[j]; + *((p++)-j) = (unsigned char) j; + break; + case 'c': /* predefined capi_prestruct_t */ + s = va_arg(ap, capi_prestruct_t *); + if (s->wLen < 0xff) { + *(p++) = (unsigned char)(s->wLen); + } else { + *(p++) = 0xff; + *(p++) = (unsigned char)(s->wLen); + *(p++) = (unsigned char)(s->wLen >> 8); + } + for (j = 0; j < s->wLen; j++) + *(p++) = s->info[j]; + break; + case '(': /* begin of a structure */ + *p = (p_length) ? p - p_length : 0; + p_length = p++; + break; + case ')': /* end of structure */ + if (p_length) { + j = *p_length; + *p_length = (unsigned char)((p - p_length) - 1); + p_length = (j != 0) ? p_length - j : 0; + } else { + cc_log(LOG_ERROR, "capi_sendf: inconsistent format \"%s\"\n", + format); + } + break; + default: + cc_log(LOG_ERROR, "capi_sendf: unknown format \"%s\"\n", + format); + } + } + va_end(ap); + + if (p_length) { + cc_log(LOG_ERROR, "capi_sendf: inconsistent format \"%s\"\n", format); + } + + header_length = (unsigned short)(p - (&msg[0])); + + if ((sizeof(void *) > 4) && (command == CAPI_DATA_B3_REQ)) { + void* req_data; + va_start(ap, format); + req_data = va_arg(ap, void *); + va_end(ap); + + header_length += 8; + write_capi_dword(&msg[12], 0); + memcpy(&msg[22], &req_data, sizeof(void *)); + } + + write_capi_word(&msg[0], header_length); + + ret = _capi_put_msg(&msg[0]); + if ((!(ret)) && (waitconf)) { + ret = capi_wait_conf(capii, (command & 0xff00) | CAPI_CONF); + } + + return (ret); +} + +/* + * decode capi 2.0 info word + */ +char *capi_info_string(unsigned int info) +{ + switch (info) { + /* informative values (corresponding message was processed) */ + case 0x0001: + return "NCPI not supported by current protocol, NCPI ignored"; + case 0x0002: + return "Flags not supported by current protocol, flags ignored"; + case 0x0003: + return "Alert already sent by another application"; + + /* error information concerning CAPI_REGISTER */ + case 0x1001: + return "Too many applications"; + case 0x1002: + return "Logical block size to small, must be at least 128 Bytes"; + case 0x1003: + return "Buffer exceeds 64 kByte"; + case 0x1004: + return "Message buffer size too small, must be at least 1024 Bytes"; + case 0x1005: + return "Max. number of logical connections not supported"; + case 0x1006: + return "Reserved"; + case 0x1007: + return "The message could not be accepted because of an internal busy condition"; + case 0x1008: + return "OS resource error (no memory ?)"; + case 0x1009: + return "CAPI not installed"; + case 0x100A: + return "Controller does not support external equipment"; + case 0x100B: + return "Controller does only support external equipment"; + + /* error information concerning message exchange functions */ + case 0x1101: + return "Illegal application number"; + case 0x1102: + return "Illegal command or subcommand or message length less than 12 bytes"; + case 0x1103: + return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI"; + case 0x1104: + return "Queue is empty"; + case 0x1105: + return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE"; + case 0x1106: + return "Unknown notification parameter"; + case 0x1107: + return "The Message could not be accepted because of an internal busy condition"; + case 0x1108: + return "OS Resource error (no memory ?)"; + case 0x1109: + return "CAPI not installed"; + case 0x110A: + return "Controller does not support external equipment"; + case 0x110B: + return "Controller does only support external equipment"; + + /* error information concerning resource / coding problems */ + case 0x2001: + return "Message not supported in current state"; + case 0x2002: + return "Illegal Controller / PLCI / NCCI"; + case 0x2003: + return "Out of PLCIs"; + case 0x2004: + return "Out of NCCIs"; + case 0x2005: + return "Out of LISTEN requests"; + case 0x2006: + return "Out of FAX resources (protocol T.30)"; + case 0x2007: + return "Illegal message parameter coding"; + + /* error information concerning requested services */ + case 0x3001: + return "B1 protocol not supported"; + case 0x3002: + return "B2 protocol not supported"; + case 0x3003: + return "B3 protocol not supported"; + case 0x3004: + return "B1 protocol parameter not supported"; + case 0x3005: + return "B2 protocol parameter not supported"; + case 0x3006: + return "B3 protocol parameter not supported"; + case 0x3007: + return "B protocol combination not supported"; + case 0x3008: + return "NCPI not supported"; + case 0x3009: + return "CIP Value unknown"; + case 0x300A: + return "Flags not supported (reserved bits)"; + case 0x300B: + return "Facility not supported"; + case 0x300C: + return "Data length not supported by current protocol"; + case 0x300D: + return "Reset procedure not supported by current protocol"; + case 0x300E: + return "TEI assignment failed or supplementary service not supported"; + case 0x3010: + return "Request not allowed in this state"; + + /* informations about the clearing of a physical connection */ + case 0x3301: + return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)"; + case 0x3302: + return "Protocol error layer 2"; + case 0x3303: + return "Protocol error layer 3"; + case 0x3304: + return "Another application got that call"; + + /* T.30 specific reasons */ + case 0x3311: + return "Connecting not successful (remote station is no FAX G3 machine)"; + case 0x3312: + return "Connecting not successful (training error)"; + case 0x3313: + return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)"; + case 0x3314: + return "Disconnected during transfer (remote abort)"; + case 0x3315: + return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)"; + case 0x3316: + return "Disconnected during transfer (local tx data underrun)"; + case 0x3317: + return "Disconnected during transfer (local rx data overflow)"; + case 0x3318: + return "Disconnected during transfer (local abort)"; + case 0x3319: + return "Illegal parameter coding (e.g. SFF coding error)"; + + /* disconnect causes from the network according to ETS 300 102-1/Q.931 */ + case 0x3481: + return "Unallocated (unassigned) number"; + case 0x3482: + return "No route to specified transit network"; + case 0x3483: + return "No route to destination"; + case 0x3486: + return "Channel unacceptable"; + case 0x3487: + return "Call awarded and being delivered in an established channel"; + case 0x3490: + return "Normal call clearing"; + case 0x3491: + return "User busy"; + case 0x3492: + return "No user responding"; + case 0x3493: + return "No answer from user (user alerted)"; + case 0x3495: + return "Call rejected"; + case 0x3496: + return "Number changed"; + case 0x349A: + return "Non-selected user clearing"; + case 0x349B: + return "Destination out of order"; + case 0x349C: + return "Invalid number format"; + case 0x349D: + return "Facility rejected"; + case 0x349E: + return "Response to STATUS ENQUIRY"; + case 0x349F: + return "Normal, unspecified"; + case 0x34A2: + return "No circuit / channel available"; + case 0x34A6: + return "Network out of order"; + case 0x34A9: + return "Temporary failure"; + case 0x34AA: + return "Switching equipment congestion"; + case 0x34AB: + return "Access information discarded"; + case 0x34AC: + return "Requested circuit / channel not available"; + case 0x34AF: + return "Resources unavailable, unspecified"; + case 0x34B1: + return "Quality of service unavailable"; + case 0x34B2: + return "Requested facility not subscribed"; + case 0x34B9: + return "Bearer capability not authorized"; + case 0x34BA: + return "Bearer capability not presently available"; + case 0x34BF: + return "Service or option not available, unspecified"; + case 0x34C1: + return "Bearer capability not implemented"; + case 0x34C2: + return "Channel type not implemented"; + case 0x34C5: + return "Requested facility not implemented"; + case 0x34C6: + return "Only restricted digital information bearer capability is available"; + case 0x34CF: + return "Service or option not implemented, unspecified"; + case 0x34D1: + return "Invalid call reference value"; + case 0x34D2: + return "Identified channel does not exist"; + case 0x34D3: + return "A suspended call exists, but this call identity does not"; + case 0x34D4: + return "Call identity in use"; + case 0x34D5: + return "No call suspended"; + case 0x34D6: + return "Call having the requested call identity has been cleared"; + case 0x34D8: + return "Incompatible destination"; + case 0x34DB: + return "Invalid transit network selection"; + case 0x34DF: + return "Invalid message, unspecified"; + case 0x34E0: + return "Mandatory information element is missing"; + case 0x34E1: + return "Message type non-existent or not implemented"; + case 0x34E2: + return "Message not compatible with call state or message type non-existent or not implemented"; + case 0x34E3: + return "Information element non-existent or not implemented"; + case 0x34E4: + return "Invalid information element contents"; + case 0x34E5: + return "Message not compatible with call state"; + case 0x34E6: + return "Recovery on timer expiry"; + case 0x34EF: + return "Protocol error, unspecified"; + case 0x34FF: + return "Interworking, unspecified"; + + /* B3 protocol 7 (Modem) */ + case 0x3500: + return "Normal end of connection"; + case 0x3501: + return "Carrier lost"; + case 0x3502: + return "Error on negotiation, i.e. no modem with error correction at other end"; + case 0x3503: + return "No answer to protocol request"; + case 0x3504: + return "Remote modem only works in synchronous mode"; + case 0x3505: + return "Framing fails"; + case 0x3506: + return "Protocol negotiation fails"; + case 0x3507: + return "Other modem sends wrong protocol request"; + case 0x3508: + return "Sync information (data or flags) missing"; + case 0x3509: + return "Normal end of connection from the other modem"; + case 0x350a: + return "No answer from other modem"; + case 0x350b: + return "Protocol error"; + case 0x350c: + return "Error on compression"; + case 0x350d: + return "No connect (timeout or wrong modulation)"; + case 0x350e: + return "No protocol fall-back allowed"; + case 0x350f: + return "No modem or fax at requested number"; + case 0x3510: + return "Handshake error"; + + /* error info concerning the requested supplementary service */ + case 0x3600: + return "Supplementary service not subscribed"; + case 0x3603: + return "Supplementary service not available"; + case 0x3604: + return "Supplementary service not implemented"; + case 0x3606: + return "Invalid served user number"; + case 0x3607: + return "Invalid call state"; + case 0x3608: + return "Basic service not provided"; + case 0x3609: + return "Supplementary service not requested for an incoming call"; + case 0x360a: + return "Supplementary service interaction not allowed"; + case 0x360b: + return "Resource unavailable"; + + /* error info concerning the context of a supplementary service request */ + case 0x3700: + return "Duplicate invocation"; + case 0x3701: + return "Unrecognized operation"; + case 0x3702: + return "Mistyped argument"; + case 0x3703: + return "Resource limitation"; + case 0x3704: + return "Initiator releasing"; + case 0x3705: + return "Unrecognized linked-ID"; + case 0x3706: + return "Linked response unexpected"; + case 0x3707: + return "Unexpected child operation"; + + /* Line Interconnect */ + case 0x3800: + return "PLCI has no B-channel"; + case 0x3801: + return "Lines not compatible"; + case 0x3802: + return "PLCI(s) is (are) not in any or not in the same interconnection"; + + default: + return NULL; + } +} + +/* + * show the text for a CAPI message info value + */ +void show_capi_info(struct capi_pvt *i, _cword info) +{ + char *p; + char *name = "?"; + + if (info == 0x0000) { + /* no error, do nothing */ + return; + } + + if (!(p = capi_info_string((unsigned int)info))) { + /* message not available */ + return; + } + + if (i) + name = i->vname; + + cc_verbose(3, 0, VERBOSE_PREFIX_4 "%s: CAPI INFO 0x%04x: %s\n", + name, info, p); + return; +} + +/* + * send Listen to specified controller + */ +unsigned capi_ListenOnController(unsigned int CIPmask, unsigned controller) +{ + MESSAGE_EXCHANGE_ERROR error; + int waitcount = 50; + _cmsg CMSG; + + error = capi_sendf(NULL, 0, CAPI_LISTEN_REQ, controller, get_capi_MessageNumber(), + "ddd()()", + 0x0000ffff, + CIPmask, + 0 + ); + + if (error) + goto done; + + while (waitcount) { + error = capidev_check_wait_get_cmsg(&CMSG); + + if (IS_LISTEN_CONF(&CMSG)) { + error = LISTEN_CONF_INFO(&CMSG); + ListenOnSupplementary(controller); + break; + } + usleep(30000); + waitcount--; + } + if (!waitcount) + error = 0x100F; + + done: + return error; +} + +/* + * convert a number + */ +char *capi_number_func(unsigned char *data, unsigned int strip, char *buf) +{ + unsigned int len; + + if (data == NULL) { + buf[0] = '\0'; + return buf; + } + + if (data[0] == 0xff) { + len = read_capi_word(&data[1]); + data += 2; + } else { + len = data[0]; + data += 1; + } + if (len > (AST_MAX_EXTENSION - 1)) + len = (AST_MAX_EXTENSION - 1); + + /* convert a capi struct to a \0 terminated string */ + if ((!len) || (len < strip)) + return NULL; + + len = len - strip; + data += strip; + + memcpy(buf, data, len); + buf[len] = '\0'; + + return buf; +} + +/* + * parse the dialstring + */ +void capi_parse_dialstring(char *buffer, char **interface, char **dest, char **param, char **ocid) +{ + int cp = 0; + char *buffer_p = buffer; + char *oc; + + /* interface is the first part of the string */ + *interface = buffer; + + *dest = emptyid; + *param = emptyid; + *ocid = NULL; + + while (*buffer_p) { + if (*buffer_p == '/') { + *buffer_p = 0; + buffer_p++; + if (cp == 0) { + *dest = buffer_p; + cp++; + } else if (cp == 1) { + *param = buffer_p; + cp++; + } else { + cc_log(LOG_WARNING, "Too many parts in dialstring '%s'\n", + buffer); + } + continue; + } + buffer_p++; + } + if ((oc = strchr(*dest, ':')) != NULL) { + *ocid = *dest; + *oc = '\0'; + *dest = oc + 1; + } + cc_verbose(3, 1, VERBOSE_PREFIX_4 "parsed dialstring: '%s' '%s' '%s' '%s'\n", + *interface, (*ocid) ? *ocid : "NULL", *dest, *param); + return; +} + +/* + * Add a new peer link id + */ +int cc_add_peer_link_id(struct ast_channel *c) +{ + int a; + + cc_mutex_lock(&peerlink_lock); + for (a = 0; a < CAPI_MAX_PEERLINKCHANNELS; a++) { + if (peerlinkchannel[a].channel == NULL) { + peerlinkchannel[a].channel = c; + peerlinkchannel[a].age = time(NULL); + break; + } else { + /* remove too old entries */ + if ((peerlinkchannel[a].age + 60) < time(NULL)) { + peerlinkchannel[a].channel = NULL; + cc_verbose(3, 1, VERBOSE_PREFIX_4 "capi: peerlink %d timeout-erase\n", + a); + } + } + } + cc_mutex_unlock(&peerlink_lock); + if (a == CAPI_MAX_PEERLINKCHANNELS) { + return -1; + } + return a; +} + +/* + * Get and remove peer link id + */ +struct ast_channel *cc_get_peer_link_id(const char *p) +{ + int id = -1; + struct ast_channel *chan = NULL; + + if (p) { + id = (int)strtol(p, NULL, 0); + } + + cc_mutex_lock(&peerlink_lock); + if ((id >= 0) && (id < CAPI_MAX_PEERLINKCHANNELS)) { + chan = peerlinkchannel[id].channel; + peerlinkchannel[id].channel = NULL; + } + cc_verbose(3, 1, VERBOSE_PREFIX_4 "capi: peerlink %d allocated, peer is %s\n", + id, (chan)?chan->name:"unlinked"); + cc_mutex_unlock(&peerlink_lock); + return chan; +} + +/* + * create pipe for interface connection + */ +int capi_create_reader_writer_pipe(struct capi_pvt *i) +{ + int fds[2]; + int flags; + + if (pipe(fds) != 0) { + cc_log(LOG_ERROR, "%s: unable to create pipe.\n", + i->vname); + return 0; + } + i->readerfd = fds[0]; + i->writerfd = fds[1]; + flags = fcntl(i->readerfd, F_GETFL); + fcntl(i->readerfd, F_SETFL, flags | O_NONBLOCK); + flags = fcntl(i->writerfd, F_GETFL); + fcntl(i->writerfd, F_SETFL, flags | O_NONBLOCK); + + return 1; +} + +/* + * read a frame from the pipe + */ +struct ast_frame *capi_read_pipeframe(struct capi_pvt *i) +{ + struct ast_frame *f; + int readsize; + + if (i == NULL) { + cc_log(LOG_ERROR, "channel has no interface\n"); + return NULL; + } + if (i->readerfd == -1) { + cc_log(LOG_ERROR, "no readerfd\n"); + return NULL; + } + + f = &i->f; + f->frametype = AST_FRAME_NULL; + f->subclass = 0; + + readsize = read(i->readerfd, f, sizeof(struct ast_frame)); + if ((readsize != sizeof(struct ast_frame)) && (readsize > 0)) { + cc_log(LOG_ERROR, "did not read a whole frame (len=%d, err=%d)\n", + readsize, errno); + } + + f->mallocd = 0; + f->data = NULL; + + if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) { + return NULL; + } + + if ((f->frametype == AST_FRAME_VOICE) && (f->datalen > 0)) { + if (f->datalen > sizeof(i->frame_data)) { + cc_log(LOG_ERROR, "f.datalen(%d) greater than space of frame_data(%d)\n", + f->datalen, sizeof(i->frame_data)); + f->datalen = sizeof(i->frame_data); + } + readsize = read(i->readerfd, i->frame_data + AST_FRIENDLY_OFFSET, f->datalen); + if (readsize != f->datalen) { + cc_log(LOG_ERROR, "did not read whole frame data\n"); + } + f->data = i->frame_data + AST_FRIENDLY_OFFSET; + } + return f; +} + +/* + * write for a channel + */ +int capi_write_frame(struct capi_pvt *i, struct ast_frame *f) +{ + MESSAGE_EXCHANGE_ERROR error; + int j = 0; + unsigned char *buf; + struct ast_frame *fsmooth; + int txavg=0; + int ret = 0; + + if (!i) { + cc_log(LOG_ERROR, "channel has no interface\n"); + return -1; + } + + if ((!(i->isdnstate & CAPI_ISDN_STATE_B3_UP)) || (!i->NCCI) || + ((i->isdnstate & (CAPI_ISDN_STATE_B3_CHANGE | CAPI_ISDN_STATE_LI)))) { + return 0; + } + + if ((!(i->ntmode)) && (i->state != CAPI_STATE_CONNECTED)) { + return 0; + } + + if (f->frametype == AST_FRAME_NULL) { + return 0; + } + if (f->frametype == AST_FRAME_DTMF) { + cc_log(LOG_ERROR, "dtmf frame should be written\n"); + return 0; + } + if (f->frametype != AST_FRAME_VOICE) { + cc_log(LOG_ERROR,"not a voice frame\n"); + return 0; + } + if (i->FaxState & CAPI_FAX_STATE_ACTIVE) { + cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: write on fax activity?\n", + i->vname); + return 0; + } + if ((!f->data) || (!f->datalen)) { + cc_log(LOG_DEBUG, "No data for FRAME_VOICE %s\n", i->vname); + return 0; + } + if (i->isdnstate & CAPI_ISDN_STATE_RTP) { + if ((!(f->subclass & i->codec)) && + (f->subclass != capi_capability)) { + cc_log(LOG_ERROR, "don't know how to write subclass %s(%d)\n", + ast_getformatname(f->subclass), f->subclass); + return 0; + } + return capi_write_rtp(i, f); + } + if (i->B3count >= CAPI_MAX_B3_BLOCKS) { + cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: B3count is full, dropping packet.\n", + i->vname); + return 0; + } + + if ((!i->smoother) || (ast_smoother_feed(i->smoother, f) != 0)) { + cc_log(LOG_ERROR, "%s: failed to fill smoother\n", i->vname); + return 0; + } + + for (fsmooth = ast_smoother_read(i->smoother); + fsmooth != NULL; + fsmooth = ast_smoother_read(i->smoother)) { + buf = &(i->send_buffer[(i->send_buffer_handle % CAPI_MAX_B3_BLOCKS) * + (CAPI_MAX_B3_BLOCK_SIZE + AST_FRIENDLY_OFFSET)]); + i->send_buffer_handle++; + + if ((i->doES == 1) && (!capi_tcap_is_digital(i->transfercapability))) { + for (j = 0; j < fsmooth->datalen; j++) { + buf[j] = capi_reversebits[ ((unsigned char *)fsmooth->data)[j] ]; + if (capi_capability == AST_FORMAT_ULAW) { + txavg += abs( capiULAW2INT[capi_reversebits[ ((unsigned char*)fsmooth->data)[j]]] ); + } else { + txavg += abs( capiALAW2INT[capi_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; + } else { + if ((i->txgain == 1.0) || (capi_tcap_is_digital(i->transfercapability))) { + for (j = 0; j < fsmooth->datalen; j++) { + buf[j] = capi_reversebits[((unsigned char *)fsmooth->data)[j]]; + } + } else { + for (j = 0; j < fsmooth->datalen; j++) { + buf[j] = i->g.txgains[capi_reversebits[((unsigned char *)fsmooth->data)[j]]]; + } + } + } + + error = 1; + if (i->B3q > 0) { + error = capi_sendf(NULL, 0, CAPI_DATA_B3_REQ, i->NCCI, get_capi_MessageNumber(), + "dwww", buf, fsmooth->datalen, i->send_buffer_handle, 0); + } else { + cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: too much voice to send for NCCI=%#x\n", + i->vname, i->NCCI); + } + + if (!error) { + cc_mutex_lock(&i->lock); + i->B3count++; + i->B3q -= fsmooth->datalen; + if (i->B3q < 0) + i->B3q = 0; + cc_mutex_unlock(&i->lock); + } + } + return ret; +} + diff --git a/chan_capi_utils.h b/chan_capi_utils.h new file mode 100644 index 0000000..702496e --- /dev/null +++ b/chan_capi_utils.h @@ -0,0 +1,59 @@ +/* + * (CAPI*) + * + * An implementation of Common ISDN API 2.0 for Asterisk + * + * Copyright (C) 2006-2007 Cytronics & Melware + * + * Armin Schindler + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#ifndef _PBX_CAPI_UTILS_H +#define _PBX_CAPI_UTILS_H + +/* + * prototypes + */ +extern int capidebug; +extern char *emptyid; + +extern void cc_verbose(int o_v, int c_d, char *text, ...); +extern _cword get_capi_MessageNumber(void); +extern struct capi_pvt *capi_find_interface_by_msgnum(unsigned short msgnum); +extern struct capi_pvt *capi_find_interface_by_plci(unsigned int plci); +extern MESSAGE_EXCHANGE_ERROR capi_wait_conf(struct capi_pvt *i, unsigned short wCmd); +extern MESSAGE_EXCHANGE_ERROR capidev_check_wait_get_cmsg(_cmsg *CMSG); +extern char *capi_info_string(unsigned int info); +extern void show_capi_info(struct capi_pvt *i, _cword info); +extern unsigned capi_ListenOnController(unsigned int CIPmask, unsigned controller); +extern void capi_parse_dialstring(char *buffer, char **interface, char **dest, char **param, char **ocid); +extern char *capi_number_func(unsigned char *data, unsigned int strip, char *buf); +extern int cc_add_peer_link_id(struct ast_channel *c); +extern struct ast_channel *cc_get_peer_link_id(const char *p); +extern void capi_remove_nullif(struct capi_pvt *i); +extern struct capi_pvt *capi_mknullif(struct ast_channel *c, unsigned long controllermask); +extern int capi_create_reader_writer_pipe(struct capi_pvt *i); +extern struct ast_frame *capi_read_pipeframe(struct capi_pvt *i); +extern int capi_write_frame(struct capi_pvt *i, struct ast_frame *f); + +#define capi_number(data, strip) \ + capi_number_func(data, strip, alloca(AST_MAX_EXTENSION)) + +typedef struct capi_prestruct_s { + unsigned short wLen; + unsigned char *info; +} capi_prestruct_t; + +/* + * Eicon's capi_sendf() function to create capi messages easily + * and send this message. + * Copyright by Eicon Networks / Dialogic + */ +extern MESSAGE_EXCHANGE_ERROR capi_sendf( + struct capi_pvt *capii, int waitconf, + _cword command, _cdword Id, _cword Number, char * format, ...); + +#endif diff --git a/create_config.sh b/create_config.sh index 77edcc9..6a8f8c6 100755 --- a/create_config.sh +++ b/create_config.sh @@ -5,7 +5,7 @@ # Script to create config.h for compatibility with # different asterisk versions. # -# (C) 2005 Cytronics & Melware +# (C) 2005-2007 Cytronics & Melware # Armin Schindler # @@ -83,6 +83,15 @@ else echo " * no extended ast_channel_alloc" fi +if grep -q "ast_channel_alloc.*amaflag" $INCLUDEDIR/channel.h; then + echo "#define CC_AST_HAS_EXT2_CHAN_ALLOC" >>$CONFIGFILE + echo " * found second extended ast_channel_alloc" +else + echo "#undef CC_AST_HAS_EXT2_CHAN_ALLOC" >>$CONFIGFILE + echo " * no second extended ast_channel_alloc" +fi + + if grep -q "send_digit_end.*duration" $INCLUDEDIR/channel.h; then echo "#define CC_AST_HAS_SEND_DIGIT_END_DURATION" >>$CONFIGFILE echo " * found send_digit_end with duration" diff --git a/openpbx.ctrl b/openpbx.ctrl deleted file mode 100644 index c8ee10c..0000000 --- a/openpbx.ctrl +++ /dev/null @@ -1,151 +0,0 @@ - -#define PBX_IS_OPBX - -#undef CC_AST_HAS_STRINGFIELD_IN_CHANNEL -#define CC_AST_CUSTOM_FUNCTION -#undef CC_AST_HAS_INDICATE_DATA - -#define ast_channel opbx_channel -#define ast_frame opbx_frame -#define ast_channel_alloc opbx_channel_alloc -#define ast_channel_free opbx_channel_free -#define ast_channel_tech opbx_channel_tech -#define ast_change_name opbx_change_name -#define ast_setstate opbx_setstate -#define ast_exists_extension opbx_exists_extension -#define ast_canmatch_extension opbx_canmatch_extension -#define ast_getformatname_multiple opbx_getformatname_multiple -#define ast_getformatname opbx_getformatname -#define ast_hostent opbx_hostent -#define ast_gethostbyname opbx_gethostbyname -#define ast_rtp_new_with_bindaddr opbx_rtp_new_with_bindaddr -#define ast_rtp_get_us opbx_rtp_get_us -#define ast_rtp_set_peer opbx_rtp_set_peer -#define ast_inet_ntoa opbx_inet_ntoa -#define ast_rtp_write opbx_rtp_write -#define ast_rtp_read opbx_rtp_read -#define ast_rtp_fd opbx_rtp_fd -#define ast_rtp_destroy opbx_rtp_destroy -#define ast_rtp opbx_rtp -#define ast_pbx_verbose opbx_verbose -#define ast_set_read_format opbx_set_read_format -#define ast_set_write_format opbx_set_write_format -#define ast_channel_unregister opbx_channel_unregister -#define ast_channel_register opbx_channel_register -#define ast_cli_unregister opbx_cli_unregister -#define ast_cli_register opbx_cli_register -#define ast_cli_entry opbx_cli_entry -#define ast_cli opbx_cli -#define ast_strdupa opbx_strdupa -#define ast_check_hangup opbx_check_hangup -#define ast_hangup opbx_hangup -#define ast_softhangup opbx_softhangup -#define ast_pbx_start opbx_pbx_start -#define ast_queue_frame opbx_queue_frame -#define ast_frame_dump opbx_frame_dump -#define ast_queue_hangup opbx_queue_hangup -#define ast_async_goto opbx_async_goto -#define ast_waitfor_n opbx_waitfor_n -#define ast_pthread_create opbx_pthread_create -#define ast_unregister_application opbx_unregister_application -#define ast_custom_function_unregister opbx_custom_function_unregister -#define ast_custom_function_register opbx_custom_function_register -#define ast_custom_function opbx_custom_function -#define ast_register_application opbx_register_application -#define ast_config_destroy opbx_config_destroy -#define ast_config_load opbx_config_load -#define ast_config opbx_config -#define ast_smoother_feed opbx_smoother_feed -#define ast_smoother_read opbx_smoother_read -#define ast_smoother_reset opbx_smoother_reset -#define ast_smoother_new opbx_smoother_new -#define ast_smoother_free opbx_smoother_free -#define ast_smoother opbx_smoother -#define ast_category_browse opbx_category_browse -#define ast_variable_browse opbx_variable_browse -#define ast_variable opbx_variable -#define ast_parse_allow_disallow opbx_parse_allow_disallow -#define ast_true opbx_true -#define ast_false opbx_false -#define ast_frfree opbx_frfree -#define ast_strlen_zero opbx_strlen_zero -#define ast_dsp_process opbx_dsp_process -#define ast_dsp_free opbx_dsp_free -#define ast_dsp_new opbx_dsp_new -#define ast_dsp_set_features opbx_dsp_set_features -#define ast_dsp_digitmode opbx_dsp_digitmode -#define ast_dsp opbx_dsp -#define ast_sendtext opbx_sendtext -#define ast_get_group opbx_get_group -#define ast_group_t opbx_group_t -#define ast_write opbx_write -#define ast_read opbx_read -#define ast_best_codec opbx_best_codec -#define ast_update_use_count opbx_update_use_count -#define ast_codec_pref opbx_codec_pref -#define ast_mutex_t opbx_mutex_t -#define ast_mutex_init opbx_mutex_init -#define ast_mutex_lock opbx_mutex_lock -#define ast_mutex_unlock opbx_mutex_unlock -#define ast_mutex_destroy opbx_mutex_destroy -#define ast_cond_t opbx_cond_t -#define ast_cond_init opbx_cond_init -#define ast_cond_destroy opbx_cond_destroy -#define ast_cond_signal opbx_cond_signal -#define ast_cond_broadcast opbx_cond_broadcast -#define ast_cond_wait opbx_cond_wait -#define ast_cond_timedwait opbx_cond_timedwait -#define ast_log opbx_log -#define ast_verbose opbx_verbose -#define ast_copy_string opbx_copy_string - -#define AST_FORMAT_ALAW OPBX_FORMAT_ALAW -#define AST_FORMAT_ULAW OPBX_FORMAT_ULAW -#define AST_FORMAT_GSM OPBX_FORMAT_GSM -#define AST_FORMAT_G723_1 OPBX_FORMAT_G723_1 -#define AST_FORMAT_G726 OPBX_FORMAT_G726 -#define AST_FORMAT_G729A OPBX_FORMAT_G729A -#define AST_FRAME_VOICE OPBX_FRAME_VOICE -#define AST_FRAME_CONTROL OPBX_FRAME_CONTROL -#define AST_FRAME_DTMF OPBX_FRAME_DTMF -#define AST_FRAME_NULL OPBX_FRAME_NULL -#define AST_FRAME_TEXT OPBX_FRAME_TEXT -#define AST_CONTROL_RINGING OPBX_CONTROL_RINGING -#define AST_CONTROL_PROCEEDING OPBX_CONTROL_PROCEEDING -#define AST_CONTROL_BUSY OPBX_CONTROL_BUSY -#define AST_CONTROL_CONGESTION OPBX_CONTROL_CONGESTION -#define AST_CONTROL_PROGRESS OPBX_CONTROL_PROGRESS -#define AST_CONTROL_HOLD OPBX_CONTROL_HOLD -#define AST_CONTROL_UNHOLD OPBX_CONTROL_UNHOLD -#define AST_CONTROL_ANSWER OPBX_CONTROL_ANSWER -#define AST_CONTROL_HANGUP OPBX_CONTROL_HANGUP -#define AST_STATE_RING OPBX_STATE_RING -#define AST_STATE_UP OPBX_STATE_UP -#define AST_STATE_DOWN OPBX_STATE_DOWN -#define AST_STATE_DIALING OPBX_STATE_DIALING -#define AST_STATE_RESERVED OPBX_STATE_RESERVED -#define AST_FRIENDLY_OFFSET OPBX_FRIENDLY_OFFSET -#define AST_SOFTHANGUP_DEV OPBX_SOFTHANGUP_DEV -#define AST_DEVICE_UNKNOWN OPBX_DEVICE_UNKNOWN -#define AST_CHANNEL_NAME OPBX_CHANNEL_NAME -#define AST_BRIDGE_DTMF_CHANNEL_0 OPBX_BRIDGE_DTMF_CHANNEL_0 -#define AST_BRIDGE_DTMF_CHANNEL_1 OPBX_BRIDGE_DTMF_CHANNEL_1 -#define AST_MAX_EXTENSION OPBX_MAX_EXTENSION -#define AST_CAUSE_INVALID_NUMBER_FORMAT OPBX_CAUSE_INVALID_NUMBER_FORMAT -#define AST_CAUSE_REQUESTED_CHAN_UNAVAIL OPBX_CAUSE_REQUESTED_CHAN_UNAVAIL -#define AST_CAUSE_NORMAL_CIRCUIT_CONGESTION OPBX_CAUSE_NORMAL_CIRCUIT_CONGESTION -#define AST_CAUSE_NO_USER_RESPONSE OPBX_CAUSE_NO_USER_RESPONSE -#define AST_CAUSE_NO_ANSWER OPBX_CAUSE_NO_ANSWER -#define AST_CAUSE_USER_BUSY OPBX_CAUSE_USER_BUSY -#define AST_CAUSE_NORMAL_CLEARING OPBX_CAUSE_NORMAL_CLEARING - -#define AST_MUTEX_DEFINE_STATIC OPBX_MUTEX_DEFINE_STATIC - -#define AST_MUTEX_DEFINE_EXPORTED OPBX_MUTEX_DEFINE_EXPORTED - -#define CC_BRIDGE_RETURN enum opbx_bridge_result -#define AST_BRIDGE_COMPLETE OPBX_BRIDGE_COMPLETE -#define AST_BRIDGE_FAILED OPBX_BRIDGE_FAILED -#define AST_BRIDGE_FAILED_NOWARN OPBX_BRIDGE_FAILED_NOWARN -#define AST_BRIDGE_RETRY OPBX_BRIDGE_RETRY - diff --git a/preparser b/preparser deleted file mode 100755 index bcc088d5c1e92be1f9b5487c3d305ccdeabeb579..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 413028 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 x2?x+{CfIbn) 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 2] #define capi_int2alaw(x) capiINT2ALAW[(x>>4)+4096] -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 -}; +extern const unsigned char capi_reversebits[256]; +extern const short capiULAW2INT[]; +extern const unsigned char capiINT2ULAW[16384]; +extern const short capiALAW2INT[]; +extern const unsigned char capiINT2ALAW[8192]; -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, -}; - -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