Merged current trunk to stable 1.0, prepare next release.
This commit is contained in:
parent
ac40e4c18d
commit
3e3f121c77
13
CHANGES
13
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
|
||||
------------------
|
||||
|
|
30
Makefile
30
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; \
|
||||
)
|
||||
|
||||
|
||||
|
|
117
README
117
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 <armin@melware.de>
|
||||
|
@ -8,9 +7,6 @@ for Asterisk/OpenPBX
|
|||
Copyright (C) 2002-2005 Junghanns.NET GmbH
|
||||
Klaus-Peter Junghanns <kpj@junghanns.net>
|
||||
|
||||
Ported to OpenPBX.org 22nd October 2004,
|
||||
Rob Thomas, <xrobau@gmail.com>
|
||||
|
||||
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 <interface-name> 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}|<context>|<exten>|<priority>)
|
||||
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|<roomname>|<options>|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.
|
||||
|
|
60
README.qsig
60
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<PLCI>" 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<PLCI>". 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
|
||||
|
|
335
c20msg.c
335
c20msg.c
|
@ -1,335 +0,0 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
2341
chan_capi.c
2341
chan_capi.c
File diff suppressed because it is too large
Load Diff
136
chan_capi.h
136
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 <asterisk.h>
|
||||
#endif
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/frame.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/config.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/features.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <asterisk/cli.h>
|
||||
#include <asterisk/rtp.h>
|
||||
#include <asterisk/causes.h>
|
||||
#include <asterisk/strings.h>
|
||||
#include <asterisk/dsp.h>
|
||||
#include <asterisk/devicestate.h>
|
||||
#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
|
||||
|
|
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
* (CAPI*)
|
||||
*
|
||||
* An implementation of Common ISDN API 2.0 for Asterisk
|
||||
*
|
||||
* Copyright (C) 2005-2007 Cytronics & Melware
|
||||
*
|
||||
* Armin Schindler <armin@melware.de>
|
||||
*
|
||||
* This program is free software and may be modified and
|
||||
* distributed under the terms of the GNU Public License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/signal.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* (CAPI*)
|
||||
*
|
||||
* An implementation of Common ISDN API 2.0 for Asterisk
|
||||
*
|
||||
* Copyright (C) 2006-2007 Cytronics & Melware
|
||||
*
|
||||
* Armin Schindler <armin@melware.de>
|
||||
*
|
||||
* 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
|
|
@ -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
|
||||
|
|
|
@ -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 <asterisk/options.h>
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <asterisk/options.h>
|
||||
#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;
|
||||
|
|
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <asterisk/pbx.h>
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* (QSIG)
|
||||
*
|
||||
* Implementation of QSIG extensions for CHAN_CAPI
|
||||
*
|
||||
* Copyright 2006-2007 (c) Mario Goegel
|
||||
*
|
||||
* Mario Goegel <m.goegel@gmx.de>
|
||||
*
|
||||
* 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
|
|
@ -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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
@ -27,41 +21,10 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#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 <asterisk/lock.h>
|
||||
#include <asterisk/frame.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/config.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/features.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <asterisk/rtp.h>
|
||||
#include <asterisk/strings.h>
|
||||
#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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -0,0 +1,845 @@
|
|||
/*
|
||||
* (CAPI*)
|
||||
*
|
||||
* An implementation of Common ISDN API 2.0 for Asterisk
|
||||
*
|
||||
* Copyright (C) 2005-2007 Cytronics & Melware
|
||||
*
|
||||
* Armin Schindler <armin@melware.de>
|
||||
*
|
||||
* This program is free software and may be modified and
|
||||
* distributed under the terms of the GNU Public License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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 <context>|<exten>|<priority>\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;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* (CAPI*)
|
||||
*
|
||||
* An implementation of Common ISDN API 2.0 for Asterisk
|
||||
*
|
||||
* Copyright (C) 2006-2007 Cytronics & Melware
|
||||
*
|
||||
* Armin Schindler <armin@melware.de>
|
||||
*
|
||||
* 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
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* (CAPI*)
|
||||
*
|
||||
* An implementation of Common ISDN API 2.0 for Asterisk
|
||||
*
|
||||
* Copyright (C) 2006-2007 Cytronics & Melware
|
||||
*
|
||||
* Armin Schindler <armin@melware.de>
|
||||
*
|
||||
* 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
|
|
@ -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 <armin@melware.de>
|
||||
#
|
||||
|
||||
|
@ -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"
|
||||
|
|
151
openpbx.ctrl
151
openpbx.ctrl
|
@ -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
|
||||
|
Loading…
Reference in New Issue