- added support for cli callback.
- added support for incoming calls. - added support for leased lines. - added manual page.
This commit is contained in:
parent
a4f59461cf
commit
5374218260
|
@ -4,7 +4,7 @@ LDFLAGS = -shared -L../capi20
|
||||||
|
|
||||||
PLUGINDIR=${DESTDIR}/etc/ppp/plugins
|
PLUGINDIR=${DESTDIR}/etc/ppp/plugins
|
||||||
PEERDIR=${DESTDIR}/etc/ppp/peers/isdn
|
PEERDIR=${DESTDIR}/etc/ppp/peers/isdn
|
||||||
PEERS= arcor otelo talkline avm avm-ml
|
PEERS= arcor otelo talkline avm avm-ml leased
|
||||||
INSTALL=./install-sh -c
|
INSTALL=./install-sh -c
|
||||||
|
|
||||||
ALL = capiplugin.so userpass.so
|
ALL = capiplugin.so userpass.so
|
||||||
|
@ -33,6 +33,12 @@ install: $(ALL)
|
||||||
echo $(INSTALL) peers/$$i $(PEERDIR); \
|
echo $(INSTALL) peers/$$i $(PEERDIR); \
|
||||||
$(INSTALL) peers/$$i $(PEERDIR); \
|
$(INSTALL) peers/$$i $(PEERDIR); \
|
||||||
done
|
done
|
||||||
|
for i in /usr/share/man /usr/man; do \
|
||||||
|
if [ -d $$i/man8 ] ; then \
|
||||||
|
echo $(INSTALL) capiplugin.8 $$i/man8; \
|
||||||
|
$(INSTALL) capiplugin.8 $$i/man8; \
|
||||||
|
fi ; \
|
||||||
|
done
|
||||||
|
|
||||||
config:
|
config:
|
||||||
@echo nothing to configure
|
@echo nothing to configure
|
||||||
|
|
|
@ -0,0 +1,393 @@
|
||||||
|
.\" manual page [] for capiplugin 2.3
|
||||||
|
.\" $Id: capiplugin.8,v 1.1 2000/10/20 17:19:20 calle Exp $
|
||||||
|
.\" SH section heading
|
||||||
|
.\" SS subsection heading
|
||||||
|
.\" LP paragraph
|
||||||
|
.\" IP indented paragraph
|
||||||
|
.\" TP hanging label
|
||||||
|
.TH CAPIPLUGIN 8
|
||||||
|
.SH NAME
|
||||||
|
capiplugin \- Plugin for pppd (Point to Point Protocol daemon)
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B pppd
|
||||||
|
[\fIoptions\fR]
|
||||||
|
.B plugin
|
||||||
|
.B /etc/ppp/plugins/capiplugin.so
|
||||||
|
[\fIoptions for capiplugin\fR]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.LP
|
||||||
|
The capiplugin provides a method to use PPP over ISDN with
|
||||||
|
ISDN controllers that provide a CAPI2.0 interface.
|
||||||
|
The plugin is responsible for the call setup with CAPI2.0.
|
||||||
|
You can dial out, wait for incoming calls and setup communication over
|
||||||
|
leased lines. It implements the feature to reject a incoming call
|
||||||
|
and call back. When dialing out this feature can also be used.
|
||||||
|
In this case the called party has to reject the call and call back soon.
|
||||||
|
.SH HOW IS WORKS
|
||||||
|
.LP
|
||||||
|
The capiplugin registers a new_phase_hook and its own options to the pppd
|
||||||
|
when loaded. When the pppd goes into phase SERIALCONN the capiplugin
|
||||||
|
will setup a connection and sets the global variable devnam.
|
||||||
|
The capiplugin will register a timer function that is
|
||||||
|
called every second to handle the capi messages while pppd is running.
|
||||||
|
To let pppd wakeup when capi messages arrive, the capi file desciptor
|
||||||
|
is added to the list of file descriptors on which the pppd waits for input.
|
||||||
|
After the connection is established the pppd will start PPP negotiation
|
||||||
|
on device devnam. When the pppd goes into phase DEAD, the connection will
|
||||||
|
be dropped (if not already dropped) and the timer function and the capi file
|
||||||
|
desciptor will be unregistered.
|
||||||
|
|
||||||
|
.SH MODES OF OPERATION
|
||||||
|
.TP
|
||||||
|
.B normal dial out
|
||||||
|
Simply make a connection, for example to your internet provider.
|
||||||
|
.br
|
||||||
|
Required options: \fInumber\fR.
|
||||||
|
Recommended options: \fImsn\fR.
|
||||||
|
Other possible options:
|
||||||
|
\fIcontroller\fR,
|
||||||
|
\fIdialmax\fR,
|
||||||
|
\fIdialtimeout\fR,
|
||||||
|
\fIprotocol\fR and
|
||||||
|
\fIredialdelay\fR.
|
||||||
|
.TP
|
||||||
|
.B dial out with callback
|
||||||
|
Call a given number, the called party call back after rejecting the call
|
||||||
|
and then call back.
|
||||||
|
.br
|
||||||
|
Required options: \fInumber\fR and \fIclicb\fR.
|
||||||
|
Recommended options: \fIcli\fR and \fImsn\fR or \fIinmsn\fR.
|
||||||
|
Other possible options:
|
||||||
|
\fIcbwait\fR,
|
||||||
|
\fIcontroller\fR,
|
||||||
|
\fIconnectdelay\fR,
|
||||||
|
\fIdialtimeout\fR,
|
||||||
|
\fIprotocol\fR
|
||||||
|
.TP
|
||||||
|
.B wait for dial in
|
||||||
|
Wait for calls and accept incoming calls.
|
||||||
|
.br
|
||||||
|
Recommended options: \fIcli\fR and \fImsn\fR or \fIinmsn\fR.
|
||||||
|
Possible options:
|
||||||
|
\fIconnectdelay\fR,
|
||||||
|
\fIcontroller\fR,
|
||||||
|
\fIdialtimeout\fR,
|
||||||
|
\fIprotocol\fR
|
||||||
|
.TP
|
||||||
|
.B wait for dial in and call back.
|
||||||
|
Wait for calls, reject the call and then call back.
|
||||||
|
.br
|
||||||
|
Required options: \fIcbnumber\fR.
|
||||||
|
Recommended options: \fIcli\fR and \fImsn\fR or \fIinmsn\fR.
|
||||||
|
Other possible options:
|
||||||
|
\fIcbdelay\fR,
|
||||||
|
\fIconnectdelay\fR,
|
||||||
|
\fIcontroller\fR,
|
||||||
|
\fIdialtimeout\fR,
|
||||||
|
\fIprotocol\fR
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B leased line
|
||||||
|
setup a leased line connection, with or without CAPI channel bundling
|
||||||
|
.br
|
||||||
|
Required options: \fIchannels\fR.
|
||||||
|
Other possible options:
|
||||||
|
\fIconnectdelay\fR,
|
||||||
|
\fIcontroller\fR,
|
||||||
|
\fIdialtimeout\fR and
|
||||||
|
\fIprotocol\fR
|
||||||
|
|
||||||
|
|
||||||
|
.SH OPTIONS
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B cbdelay \fI<seconds>
|
||||||
|
Number of seconds to wait before callback, when acting as
|
||||||
|
dialin server with callback. Default is 2 seconds.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B cbnumber \fI<phone numbers>
|
||||||
|
Comma seperated list of phone numbers for call back, when acting as
|
||||||
|
dialin server with callback.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B cbwait \fI<seconds>
|
||||||
|
Time to wait for a call back, before giving up. Default is 60 seconds.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B channels \fI<channel specification>
|
||||||
|
Comma seperated list of b-channels or ranges to activate leased line mode.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B cli \fI<telephon numbers>
|
||||||
|
A comma seperated list of numbers from where incoming calls will be accepted.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B clicb
|
||||||
|
Enable callback mode. When option \fInumber\fR is present, call number
|
||||||
|
and wait for callback. When option \fInumber\fR is not present,
|
||||||
|
wait for incoming call, reject the call and call back.
|
||||||
|
This option is is optional if option \fIcbnumber\fR is present.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B connectdelay \fI<seconds>
|
||||||
|
Number of seconds to wait after connecting is established,
|
||||||
|
before PPP negotiation starts. Defaultvalue is 0 seconds.
|
||||||
|
This option is use full, when connecting with protocol \fImodem\fR.
|
||||||
|
Some internet access servers will hang up, if they get data immediatly
|
||||||
|
after connection is established.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B controller \fI<controller specification>
|
||||||
|
For point to multipoint \fI<controller specification\fR is only the
|
||||||
|
CAPI2.0 controller number , default is 1.
|
||||||
|
For point-to-point specify \fI<controller number>\fR,\fI<ddi>\fR,\fI<length of internal numbers\>
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B dialmax \fI<times>
|
||||||
|
Maximum number of times the list of phone numbers is tried before give up.
|
||||||
|
Default is 4.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B dialtimeout \fI<seconds>
|
||||||
|
Time to wait until connection established or failed before giving up.
|
||||||
|
Default is 60 seconds.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B inmsn \fI<msn>
|
||||||
|
Phone umber to listen on for calls, when different from option \fImsn\fR.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B msn \fI<msn>
|
||||||
|
Phone umber from where to call out. Also used for incoming calls
|
||||||
|
if option \fIinmsn\fR is not present.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B number \fI<phone numbers>
|
||||||
|
Comma seperated list of phone numbers to call.
|
||||||
|
Every number in the list is called until a connection can be established.
|
||||||
|
When the end of the list is reached, the first number is called again.
|
||||||
|
See option \fIdialmax\fR.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B numberprefix \fI<prefix>
|
||||||
|
phone number to dial to get outline access. For example. \fInumberprefix 0\fR.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B protocol \fIhdlc\fR | \fIx75\fR | \fIv42bis\fR | \fImodem\fR
|
||||||
|
ISDN protocol to use. With \fIhdlc\fR you need to add option \fIsync\fR
|
||||||
|
to the pppd. With \fIx75\fR,\fIv42bis\fR and \fImodem\fR option \fIsync\fR
|
||||||
|
MUST NOT be present. Defaultvalue is \fIhdlc\fR.
|
||||||
|
Not all controllers support \fIv42bis\fR and \fImodem\fR.
|
||||||
|
Use capiinfo(8) to see the features your controller support.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B redialdelay \fI<seconds>
|
||||||
|
Number of seconds to wait between redialing. Default is 5 seconds.
|
||||||
|
|
||||||
|
.SH EXAMPLE FOR NORMAL DIAL OUT
|
||||||
|
.LP
|
||||||
|
Probably the most common use of pppd is to dial out to an ISP. This
|
||||||
|
can be done with a command such as
|
||||||
|
.IP
|
||||||
|
pppd call isp
|
||||||
|
.LP
|
||||||
|
where the /etc/ppp/peers/isp file is set up by the system
|
||||||
|
administrator to contain something like this:
|
||||||
|
.IP
|
||||||
|
sync
|
||||||
|
.br
|
||||||
|
noauth
|
||||||
|
.br
|
||||||
|
defaultroute
|
||||||
|
.br
|
||||||
|
name USERNAME
|
||||||
|
.br
|
||||||
|
plugin /etc/ppp/plugins/capiplugin.so
|
||||||
|
.r
|
||||||
|
msn MSN
|
||||||
|
.br
|
||||||
|
number PHONENUMBER
|
||||||
|
.br
|
||||||
|
protocol hdlc
|
||||||
|
.br
|
||||||
|
ipcp-accept-local
|
||||||
|
.br
|
||||||
|
ipcp-accept-remote
|
||||||
|
.br
|
||||||
|
/dev/null
|
||||||
|
.LP
|
||||||
|
where the /etc/ppp/pap-secrets and /etc/ppp/chap-secrets file is set up by
|
||||||
|
the system administrator to contain something like this:
|
||||||
|
.IP
|
||||||
|
USERNAME * PASSWORD *
|
||||||
|
|
||||||
|
.SH EXAMPLE FOR DIAL OUT WITH CALLBACK
|
||||||
|
.LP
|
||||||
|
Dial out with callback can be done with a command such as
|
||||||
|
.IP
|
||||||
|
pppd call isp-callback
|
||||||
|
.LP
|
||||||
|
where the /etc/ppp/peers/isp-callback file is set up by the system
|
||||||
|
administrator to contain something like this:
|
||||||
|
.IP
|
||||||
|
sync
|
||||||
|
.br
|
||||||
|
noauth
|
||||||
|
.br
|
||||||
|
defaultroute
|
||||||
|
.br
|
||||||
|
name USERNAME
|
||||||
|
.br
|
||||||
|
plugin /etc/ppp/plugins/capiplugin.so
|
||||||
|
.br
|
||||||
|
msn MSN
|
||||||
|
.br
|
||||||
|
number PHONENUMBER
|
||||||
|
.br
|
||||||
|
clicb
|
||||||
|
.br
|
||||||
|
cli PHONENUMBER
|
||||||
|
.br
|
||||||
|
protocol hdlc
|
||||||
|
.br
|
||||||
|
ipcp-accept-local
|
||||||
|
.br
|
||||||
|
ipcp-accept-remote
|
||||||
|
.br
|
||||||
|
/dev/null
|
||||||
|
.LP
|
||||||
|
where the /etc/ppp/pap-secrets and /etc/ppp/chap-secrets file is set up by
|
||||||
|
the system administrator to contain something like this:
|
||||||
|
.br
|
||||||
|
USERNAME * PASSWORD *
|
||||||
|
|
||||||
|
.SH EXAMPLE FOR WAIT FOR DIAL IN WITHOUT CLI AUTHENTICATION
|
||||||
|
.LP
|
||||||
|
Wait for incoming calls, accept them according to options \fImsn\fR,
|
||||||
|
\fIinmsn\fR, and \fIprotocol\fI.
|
||||||
|
.LP
|
||||||
|
Do not provide option \fIcli\fR to the capiplugin.
|
||||||
|
Start a pppd for every b channel.
|
||||||
|
Authorisation is made with PAP or CHAP and the ip numbers are assigned
|
||||||
|
according to file /etc/ppp/pap-secrets or file /etc/ppp/chap-secrets.
|
||||||
|
Let's assume the server has ip number 192.168.0.1 and the clients should
|
||||||
|
have the ip numbers starting at 192.168.0.2 and the hostname of the
|
||||||
|
server is \"dialinserver\".
|
||||||
|
Add this two lines to the file /etc/inittab:
|
||||||
|
.IP
|
||||||
|
p0:23:respawn:/usr/sbin/pppd call incoming
|
||||||
|
.br
|
||||||
|
p1:23:respawn:/usr/sbin/pppd call incoming
|
||||||
|
.LP
|
||||||
|
where the /etc/ppp/peers/incoming file is set up
|
||||||
|
to contain something like this:
|
||||||
|
.IP
|
||||||
|
sync
|
||||||
|
.br
|
||||||
|
auth
|
||||||
|
.br
|
||||||
|
persist
|
||||||
|
.br
|
||||||
|
plugin /etc/ppp/plugins/capiplugin.so
|
||||||
|
.br
|
||||||
|
inmsn MSN
|
||||||
|
.br
|
||||||
|
protocol hdlc
|
||||||
|
192.168.0.1:
|
||||||
|
.LP
|
||||||
|
with the file /etc/ppp/pap-secrets and file /etc/ppp/chap-secrets file is set up
|
||||||
|
to contain something like this:
|
||||||
|
.IP
|
||||||
|
user1 dialinserver PASSWORD1 192.168.0.2
|
||||||
|
.br
|
||||||
|
user2 dialinserver PASSWORD2 192.168.0.2
|
||||||
|
|
||||||
|
.SH EXAMPLE FOR WAIT FOR DIAL IN WITH CLI AUTHENTICATION
|
||||||
|
.LP
|
||||||
|
Wait for incoming calls, accept them according to options \fImsn\fR,
|
||||||
|
\fIinmsn\fR, \fIcli\fR and \fIprotocol\fI.
|
||||||
|
.LP
|
||||||
|
Start a pppd for every client.
|
||||||
|
Let's assume the server has ip number 192.168.0.1 and the clients should
|
||||||
|
have the ip numbers starting at 192.168.0.2.
|
||||||
|
Add this three lines to file /etc/inittab:
|
||||||
|
.IP
|
||||||
|
p0:23:respawn:/usr/sbin/pppd call incoming cli 04711 192.168.0.1:192.168.0.2
|
||||||
|
.br
|
||||||
|
p1:23:respawn:/usr/sbin/pppd call incoming cli 04712 192.168.0.1:192.168.0.3
|
||||||
|
.br
|
||||||
|
p2:23:respawn:/usr/sbin/pppd call incoming cli 04713 192.168.0.1:192.168.0.4
|
||||||
|
|
||||||
|
.LP
|
||||||
|
where the /etc/ppp/peers/incoming file is set up
|
||||||
|
to contain something like this:
|
||||||
|
.IP
|
||||||
|
sync
|
||||||
|
.br
|
||||||
|
auth
|
||||||
|
.br
|
||||||
|
persist
|
||||||
|
.br
|
||||||
|
plugin /etc/ppp/plugins/capiplugin.so
|
||||||
|
.br
|
||||||
|
inmsn MSN
|
||||||
|
.br
|
||||||
|
protocol hdlc
|
||||||
|
|
||||||
|
.SH EXAMPLE FOR WAIT FOR DIAL IN WITH CLI AUTHENTICATION AND CALLBACK
|
||||||
|
.LP
|
||||||
|
Wait for incoming calls, accept them according to options \fImsn\fR,
|
||||||
|
\fIinmsn\fR, \fIcli\fR and \fIprotocol\fI, reject incoming calls
|
||||||
|
and call back.
|
||||||
|
.LP
|
||||||
|
.B start a pppd for every client
|
||||||
|
Let assume the server has ip numbers 192.168.0.1 and the clients should
|
||||||
|
have the ip numbers starting at 192.168.0.2.
|
||||||
|
Add this three lines to the file /etc/inittab.
|
||||||
|
.IP
|
||||||
|
p0:23:respawn:/usr/sbin/pppd call incoming cli 04711 cbnumber 4711 192.168.0.1:192.168.0.2
|
||||||
|
.br
|
||||||
|
p1:23:respawn:/usr/sbin/pppd call incoming cli 04712 cbnumber 4712 192.168.0.1:192.168.0.3
|
||||||
|
.br
|
||||||
|
p2:23:respawn:/usr/sbin/pppd call incoming cli 04713 cbnumber 4713 192.168.0.1:192.168.0.4
|
||||||
|
|
||||||
|
.LP
|
||||||
|
where the /etc/ppp/peers/incoming file is set up
|
||||||
|
to contain something like this:
|
||||||
|
.IP
|
||||||
|
sync
|
||||||
|
.br
|
||||||
|
auth
|
||||||
|
.br
|
||||||
|
persist
|
||||||
|
.br
|
||||||
|
plugin /etc/ppp/plugins/capiplugin.so
|
||||||
|
.br
|
||||||
|
inmsn MSN
|
||||||
|
.br
|
||||||
|
protocol hdlc
|
||||||
|
|
||||||
|
.SH CAVEATS
|
||||||
|
.LP
|
||||||
|
Every pppd waiting for incoming calls can get an incoming call first.
|
||||||
|
So when you start two pppd listening on the same MSN, one with
|
||||||
|
CLI Authentication and the other not, the following can happen:
|
||||||
|
.IP
|
||||||
|
The Client with the CLI specified to the first pppd calls, but the pppd
|
||||||
|
without option \fIcli\fR will get the call first and accepts the call.
|
||||||
|
.LP
|
||||||
|
So if you want to mix CLI Authentication and PAP/CHAP Authentication
|
||||||
|
use one MSN for CLI authenticated calls and another for the PAP/CHAP
|
||||||
|
authenticated calls.
|
||||||
|
|
||||||
|
.SH DIAGNOSTICS
|
||||||
|
.LP
|
||||||
|
Messages are sent to the syslog daemon like pppd did usually, see
|
||||||
|
pppd manual page.
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
pppd(8), capiinfo(8), capiinit(8), capictrl(8)
|
||||||
|
|
||||||
|
.SH AUTHORS
|
||||||
|
Carsten Paeth (calle@calle.in-berlin.de)
|
|
@ -8,35 +8,78 @@
|
||||||
* as published by the Free Software Foundation; either version
|
* as published by the Free Software Foundation; either version
|
||||||
* 2 of the License, or (at your option) any later version.
|
* 2 of the License, or (at your option) any later version.
|
||||||
*/
|
*/
|
||||||
|
#include <unistd.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include "pppd.h"
|
#include "pppd.h"
|
||||||
#include "capiconn.h"
|
#include "capiconn.h"
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
static char *revision = "$Revision: 1.5 $";
|
static char *revision = "$Revision: 1.6 $";
|
||||||
|
|
||||||
static capiconn_context *ctx;
|
static capiconn_context *ctx;
|
||||||
static capi_connection *conn = 0;
|
static capi_connection *conn = 0;
|
||||||
static int isconnected = 0;
|
static int isconnected = 0;
|
||||||
static unsigned applid;
|
static unsigned applid;
|
||||||
|
#define CM(x) (1<<(x))
|
||||||
|
#define CIPMASK_ALL 0x1FFF03FF
|
||||||
|
#define CIPMASK_VOICE (CM(1)|CM(4)|CM(5)|CM(16)|CM(26))
|
||||||
|
#define CIPMASK_DATA (CM(2)|CM(3))
|
||||||
|
static unsigned long cipmask = CIPMASK_ALL;
|
||||||
|
static int controller = 1;
|
||||||
|
static capi_contrinfo cinfo = { 0 , 0, 0 };
|
||||||
|
|
||||||
static int opt_contr = 1;
|
static char *opt_controller = "1";
|
||||||
static char *opt_numberprefix = 0;
|
static char *opt_numberprefix = 0;
|
||||||
static char *opt_number = 0;
|
static char *opt_number = 0;
|
||||||
|
static char *opt_callbacknumber = 0;
|
||||||
static char *opt_msn = 0;
|
static char *opt_msn = 0;
|
||||||
|
static char *opt_inmsn = 0;
|
||||||
static char *opt_proto = 0;
|
static char *opt_proto = 0;
|
||||||
|
static char *opt_channels = 0;
|
||||||
|
static unsigned char AdditionalInfo[1+2+2+31];
|
||||||
|
static int opt_dialtimeout = 60;
|
||||||
|
static int opt_dialmax = 4;
|
||||||
|
static int opt_redialdelay = 5;
|
||||||
|
static int opt_cbdelay = 2;
|
||||||
|
static int opt_connectdelay = 0;
|
||||||
|
|
||||||
|
static char *opt_cli = 0;
|
||||||
|
static int opt_cbflag = 0;
|
||||||
|
static int opt_cbwait = 60;
|
||||||
|
static int opt_acceptdelayflag = 0;
|
||||||
|
|
||||||
|
typedef struct stringlist {
|
||||||
|
struct stringlist *next;
|
||||||
|
char *s;
|
||||||
|
} STRINGLIST;
|
||||||
|
|
||||||
|
static STRINGLIST *numbers;
|
||||||
|
static STRINGLIST *callbacknumbers;
|
||||||
|
static STRINGLIST *clis;
|
||||||
|
static STRINGLIST *parsed_controller;
|
||||||
|
|
||||||
|
static int optcb(void)
|
||||||
|
{
|
||||||
|
return opt_cbflag = 1;
|
||||||
|
}
|
||||||
|
static int optacceptdelay(void)
|
||||||
|
{
|
||||||
|
return opt_acceptdelayflag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
static option_t my_options[] = {
|
static option_t my_options[] = {
|
||||||
{
|
{
|
||||||
"controller", o_int, &opt_contr,
|
"controller", o_string, &opt_controller,
|
||||||
"capi controller"
|
"capi controller specification"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"number", o_string, &opt_number,
|
"number", o_string, &opt_number,
|
||||||
"number to call"
|
"number to call (may be comma separated)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"numberprefix", o_string, &opt_numberprefix,
|
"numberprefix", o_string, &opt_numberprefix,
|
||||||
|
@ -48,13 +91,112 @@ static option_t my_options[] = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"protocol", o_string, &opt_proto,
|
"protocol", o_string, &opt_proto,
|
||||||
"protocol x75 or hdlc"
|
"protocol x75, hdlc or modem"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"inmsn", o_string, &opt_inmsn,
|
||||||
|
"called number for incoming calls"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cli", o_string, &opt_cli,
|
||||||
|
"calling number for incoming calls (may be comma separated list)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clicb", o_special_noarg, &optcb,
|
||||||
|
"call number and wait for callback"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cbwait", o_int, &opt_cbwait,
|
||||||
|
"number of seconds to wait for callback"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dialtimeout", o_int, &opt_dialtimeout,
|
||||||
|
"number of seconds to wait for connection or reject"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dialmax", o_int, &opt_dialmax,
|
||||||
|
"number of dial retries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"redialdelay", o_int, &opt_redialdelay,
|
||||||
|
"number of seconds to wait between dial retries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"channels", o_string, &opt_channels,
|
||||||
|
"channel to use for leased line (may be comma separated list)"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"cbdelay", o_int, &opt_cbdelay,
|
||||||
|
"number of seconds to wait before calling back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cbnumber", o_string, &opt_callbacknumber,
|
||||||
|
"number to call (may be comma separated)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"connectdelay", o_int, &opt_connectdelay,
|
||||||
|
"number of seconds to wait after connection is established"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"acceptdelay", o_special_noarg, &optacceptdelay,
|
||||||
|
"wait 1 second before accept incoming call"
|
||||||
|
},
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static void stringlist_free(STRINGLIST **pp)
|
||||||
|
{
|
||||||
|
STRINGLIST *p, *next;
|
||||||
|
|
||||||
|
p = *pp;
|
||||||
|
while (p) {
|
||||||
|
next = p->next;
|
||||||
|
if (p->s) free(p->s);
|
||||||
|
free(p);
|
||||||
|
p = next;
|
||||||
|
}
|
||||||
|
*pp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stringlist_append_string(STRINGLIST **pp, char *s)
|
||||||
|
{
|
||||||
|
STRINGLIST *p;
|
||||||
|
for (; *pp; pp = &(*pp)->next) ;
|
||||||
|
if ((p = (STRINGLIST *)malloc(sizeof(STRINGLIST))) == 0)
|
||||||
|
return -1;
|
||||||
|
memset(p, 0, sizeof(STRINGLIST));
|
||||||
|
if ((p->s = strdup(s)) == 0) {
|
||||||
|
free(p);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
p->next = 0;
|
||||||
|
*pp = p;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static STRINGLIST *stringlist_split(char *tosplit, char *seps)
|
||||||
|
{
|
||||||
|
STRINGLIST *p = 0;
|
||||||
|
char *str = strdup(tosplit);
|
||||||
|
char *s;
|
||||||
|
if (!str) return 0;
|
||||||
|
for (s = strtok(str, seps); s; s = strtok(0, seps)) {
|
||||||
|
if (*s == 0) continue; /* if strtok is not working correkt */
|
||||||
|
if (stringlist_append_string(&p, s) < 0) {
|
||||||
|
stringlist_free(&p);
|
||||||
|
free(str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(str);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
static int timeoutrunning = 0;
|
static int timeoutrunning = 0;
|
||||||
static int timeoutshouldrun = 0;
|
static int timeoutshouldrun = 0;
|
||||||
|
|
||||||
|
@ -85,112 +227,474 @@ static void unsetup_timeout(void)
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
static void dodisconnect(void)
|
static void handlemessages(void)
|
||||||
{
|
{
|
||||||
if (!conn)
|
unsigned char *msg = 0;
|
||||||
return;
|
struct timeval tv;
|
||||||
(void)capiconn_disconnect(conn, 0);
|
tv.tv_sec = 1;
|
||||||
while (conn) {
|
tv.tv_usec = 0;
|
||||||
unsigned char *msg = 0;
|
if (capi20_waitformessage(applid, &tv) == 0) {
|
||||||
struct timeval tv;
|
if (capi20_get_message(applid, &msg) == 0)
|
||||||
tv.tv_sec = 1;
|
capiconn_inject(applid, msg);
|
||||||
tv.tv_usec = 0;
|
|
||||||
if (capi20_waitformessage(applid, &tv) == 0) {
|
|
||||||
if (capi20_get_message (applid, &msg) == 0)
|
|
||||||
capiconn_inject(applid, msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void makeconnection(void)
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static void dodisconnect(void)
|
||||||
|
{
|
||||||
|
time_t t;
|
||||||
|
if (!conn)
|
||||||
|
return;
|
||||||
|
(void)capiconn_disconnect(conn, 0);
|
||||||
|
t = time(0)+10;
|
||||||
|
while (conn && time(0) < t)
|
||||||
|
handlemessages();
|
||||||
|
if (conn)
|
||||||
|
fatal("capiplugin: timeout while waiting for disconnect");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setupconnection(char *num)
|
||||||
{
|
{
|
||||||
char number[256];
|
char number[256];
|
||||||
|
|
||||||
if (opt_number == 0) {
|
|
||||||
fatal("capiplugin: no number");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(number, sizeof(number), "%s%s",
|
snprintf(number, sizeof(number), "%s%s",
|
||||||
opt_numberprefix ? opt_numberprefix : "",
|
opt_numberprefix ? opt_numberprefix : "", num);
|
||||||
opt_number);
|
|
||||||
if (opt_proto == 0 || strcasecmp(opt_proto, "hdlc") == 0) {
|
if (opt_proto == 0 || strcasecmp(opt_proto, "hdlc") == 0) {
|
||||||
conn = capiconn_connect(ctx,
|
conn = capiconn_connect(ctx,
|
||||||
opt_contr, /* contr */
|
controller, /* contr */
|
||||||
2, /* cipvalue */
|
2, /* cipvalue */
|
||||||
number,
|
opt_channels ? 0 : number,
|
||||||
opt_msn,
|
opt_channels ? 0 : opt_msn,
|
||||||
0, 1, 0,
|
0, 1, 0,
|
||||||
0, 0, 0, 0, 0);
|
0, 0, 0,
|
||||||
|
opt_channels ? AdditionalInfo : 0,
|
||||||
|
0);
|
||||||
} else if (strcasecmp(opt_proto, "x75") == 0) {
|
} else if (strcasecmp(opt_proto, "x75") == 0) {
|
||||||
conn = capiconn_connect(ctx,
|
conn = capiconn_connect(ctx,
|
||||||
opt_contr, /* contr */
|
controller, /* contr */
|
||||||
2, /* cipvalue */
|
2, /* cipvalue */
|
||||||
number,
|
opt_channels ? 0 : number,
|
||||||
opt_msn,
|
opt_channels ? 0 : opt_msn,
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
0, 0, 0, 0, 0);
|
0, 0, 0,
|
||||||
|
opt_channels ? AdditionalInfo : 0,
|
||||||
|
0);
|
||||||
|
} else if (strcasecmp(opt_proto, "v42bis") == 0) {
|
||||||
|
conn = capiconn_connect(ctx,
|
||||||
|
controller, /* contr */
|
||||||
|
2, /* cipvalue */
|
||||||
|
opt_channels ? 0 : number,
|
||||||
|
opt_channels ? 0 : opt_msn,
|
||||||
|
0, 8, 0,
|
||||||
|
0, 0, 0,
|
||||||
|
opt_channels ? AdditionalInfo : 0,
|
||||||
|
0);
|
||||||
} else if (strcasecmp(opt_proto, "modem") == 0) {
|
} else if (strcasecmp(opt_proto, "modem") == 0) {
|
||||||
conn = capiconn_connect(ctx,
|
conn = capiconn_connect(ctx,
|
||||||
opt_contr, /* contr */
|
controller, /* contr */
|
||||||
1, /* cipvalue */
|
1, /* cipvalue */
|
||||||
number,
|
opt_channels ? 0 : number,
|
||||||
opt_msn,
|
opt_channels ? 0 : opt_msn,
|
||||||
8, 1, 0,
|
8, 1, 0,
|
||||||
0, 0, 0, 0, 0);
|
0, 0, 0,
|
||||||
|
opt_channels ? AdditionalInfo : 0,
|
||||||
|
0);
|
||||||
} else {
|
} else {
|
||||||
fatal("capiplugin: unknown protocol \"%s\"", opt_proto);
|
fatal("capiplugin: unknown protocol \"%s\"", opt_proto);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (!isconnected && conn) {
|
if (opt_channels) {
|
||||||
unsigned char *msg = 0;
|
info("capiplugin: leased line (%s)",
|
||||||
struct timeval tv;
|
opt_proto ? opt_proto : "hdlc");
|
||||||
tv.tv_sec = 1;
|
} else {
|
||||||
tv.tv_usec = 0;
|
info("capiplugin: dial %s (%s)",
|
||||||
if (capi20_waitformessage(applid, &tv) == 0) {
|
number, opt_proto ? opt_proto : "hdlc");
|
||||||
if (capi20_get_message (applid, &msg) == 0)
|
}
|
||||||
capiconn_inject(applid, msg);
|
}
|
||||||
|
|
||||||
|
static void makeleasedline(void)
|
||||||
|
{
|
||||||
|
time_t t;
|
||||||
|
|
||||||
|
setupconnection("");
|
||||||
|
|
||||||
|
t = time(0)+opt_dialtimeout;
|
||||||
|
do {
|
||||||
|
handlemessages();
|
||||||
|
if (status != EXIT_OK && conn)
|
||||||
|
dodisconnect();
|
||||||
|
} while (time(0) < t && conn && !isconnected);
|
||||||
|
|
||||||
|
if (status != EXIT_OK)
|
||||||
|
die(status);
|
||||||
|
|
||||||
|
if (conn && isconnected) {
|
||||||
|
t = time(0)+opt_connectdelay;
|
||||||
|
do {
|
||||||
|
handlemessages();
|
||||||
|
} while (time(0) < t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != EXIT_OK)
|
||||||
|
die(status);
|
||||||
|
|
||||||
|
if (!conn)
|
||||||
|
fatal("capiplugin: couldn't make connection");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void makeconnection(STRINGLIST *numbers)
|
||||||
|
{
|
||||||
|
time_t t;
|
||||||
|
STRINGLIST *p;
|
||||||
|
int retry = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
for (p = numbers; p; p = p->next) {
|
||||||
|
if (retry || p != numbers) {
|
||||||
|
t = time(0)+opt_redialdelay;
|
||||||
|
do {
|
||||||
|
handlemessages();
|
||||||
|
if (status != EXIT_OK)
|
||||||
|
die(status);
|
||||||
|
} while (time(0) < t);
|
||||||
|
}
|
||||||
|
|
||||||
|
setupconnection(p->s);
|
||||||
|
|
||||||
|
t = time(0)+opt_dialtimeout;
|
||||||
|
do {
|
||||||
|
handlemessages();
|
||||||
|
if (status != EXIT_OK && conn)
|
||||||
|
dodisconnect();
|
||||||
|
} while (time(0) < t && conn && !isconnected);
|
||||||
|
|
||||||
|
if (conn && isconnected)
|
||||||
|
goto connected;
|
||||||
|
|
||||||
|
if (status != EXIT_OK)
|
||||||
|
die(status);
|
||||||
|
}
|
||||||
|
} while (++retry < opt_dialmax);
|
||||||
|
connected:
|
||||||
|
|
||||||
|
if (!conn)
|
||||||
|
fatal("capiplugin: couldn't make connection after %d retries",
|
||||||
|
retry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void makeconnection_with_callback(void)
|
||||||
|
{
|
||||||
|
STRINGLIST *p;
|
||||||
|
time_t t;
|
||||||
|
|
||||||
|
for (p = numbers; p; p = p->next) {
|
||||||
|
|
||||||
|
setupconnection(p->s);
|
||||||
|
|
||||||
|
info("capiplugin: wait for call reject");
|
||||||
|
/* Wait specific time for the server rejecting the call */
|
||||||
|
t = time(0)+opt_dialtimeout;
|
||||||
|
do {
|
||||||
|
handlemessages();
|
||||||
|
if (status != EXIT_OK)
|
||||||
|
die(status);
|
||||||
|
} while (time(0) < t && conn && !isconnected);
|
||||||
|
|
||||||
|
if (!conn) { /* Call has been rejected */
|
||||||
|
|
||||||
|
(void) capiconn_listen(ctx, controller, cipmask, 0);
|
||||||
|
info("capiplugin: waiting for callback...");
|
||||||
|
|
||||||
|
/* Wait for server calling back */
|
||||||
|
t = time(0)+opt_cbwait;
|
||||||
|
do {
|
||||||
|
handlemessages();
|
||||||
|
if (status != EXIT_OK) {
|
||||||
|
(void) capiconn_listen(ctx, controller, 0, 0);
|
||||||
|
die(status);
|
||||||
|
}
|
||||||
|
} while (!isconnected && time(0) < t);
|
||||||
|
|
||||||
|
if (isconnected) {
|
||||||
|
add_fd(capi20_fileno(applid));
|
||||||
|
setup_timeout();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (p->next == 0)
|
||||||
|
fatal("capiplugin: callback failed (no call)");
|
||||||
|
else
|
||||||
|
info("capiplugin: callback failed (no call)");
|
||||||
|
} else {
|
||||||
|
dodisconnect();
|
||||||
|
fatal("capiplugin: callback failed (no reject)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!conn)
|
}
|
||||||
fatal("capiplugin: couldn't make connection");
|
|
||||||
|
static void makecallback(void)
|
||||||
|
{
|
||||||
|
time_t t;
|
||||||
|
|
||||||
|
t = time(0)+opt_cbdelay;
|
||||||
|
do {
|
||||||
|
handlemessages();
|
||||||
|
if (status != EXIT_OK)
|
||||||
|
die(status);
|
||||||
|
} while (time(0) < t);
|
||||||
|
|
||||||
|
makeconnection(callbacknumbers);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void waitforcall(void)
|
||||||
|
{
|
||||||
|
(void) capiconn_listen(ctx, controller, cipmask, 0);
|
||||||
|
info("capiplugin: waiting for incoming call ...");
|
||||||
|
|
||||||
|
do {
|
||||||
|
handlemessages();
|
||||||
|
if (status != EXIT_OK) {
|
||||||
|
(void) capiconn_listen(ctx, controller, 0, 0);
|
||||||
|
die(status);
|
||||||
|
}
|
||||||
|
} while (!isconnected);
|
||||||
|
|
||||||
|
add_fd(capi20_fileno(applid));
|
||||||
|
setup_timeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_capiconn(void)
|
static void init_capiconn(void)
|
||||||
{
|
{
|
||||||
static capi_contrinfo cinfo = { 0 , 0, 0 };
|
|
||||||
static int init = 0;
|
static int init = 0;
|
||||||
|
|
||||||
if (init)
|
if (init)
|
||||||
return;
|
return;
|
||||||
init = 1;
|
init = 1;
|
||||||
|
|
||||||
if (capiconn_addcontr(ctx, opt_contr, &cinfo) != CAPICONN_OK) {
|
if (capiconn_addcontr(ctx, controller, &cinfo) != CAPICONN_OK) {
|
||||||
(void)capiconn_freecontext(ctx);
|
(void)capiconn_freecontext(ctx);
|
||||||
(void)capi20_release(applid);
|
(void)capi20_release(applid);
|
||||||
fatal("capiplugin: add controller %d failed", opt_contr);
|
fatal("capiplugin: add controller %d failed", controller);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (cinfo.ddi)
|
||||||
|
dbglog("capiplugin: contr=%d ddi=\"%s\" n=%d",
|
||||||
|
controller, cinfo.ddi, cinfo.ndigits);
|
||||||
|
else
|
||||||
|
dbglog("capiplugin: contr=%d", controller);
|
||||||
|
|
||||||
add_fd(capi20_fileno(applid));
|
add_fd(capi20_fileno(applid));
|
||||||
setup_timeout();
|
setup_timeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle leased lines (CAPI-Bundling)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int decodechannels(char *teln, unsigned long *bmaskp, int *activep)
|
||||||
|
{
|
||||||
|
unsigned long bmask = 0;
|
||||||
|
int active = !0;
|
||||||
|
char *s;
|
||||||
|
int channel;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
s = teln;
|
||||||
|
while (*s && *s == ' ') s++;
|
||||||
|
if (!*s)
|
||||||
|
fatal("capiplugin; option channels: list empty");
|
||||||
|
if (*s == 'p' || *s == 'P') {
|
||||||
|
active = 0;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
if (*s == 'a' || *s == 'A') {
|
||||||
|
active = !0;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
while (*s) {
|
||||||
|
int digit1 = 0;
|
||||||
|
int digit2 = 0;
|
||||||
|
if (!isdigit(*s))
|
||||||
|
goto illegal;
|
||||||
|
while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; }
|
||||||
|
channel = digit1;
|
||||||
|
if (channel <= 0 && channel > 30)
|
||||||
|
goto rangeerror;
|
||||||
|
if (*s == 0 || *s == ',' || *s == ' ') {
|
||||||
|
bmask |= (1 << digit1);
|
||||||
|
digit1 = 0;
|
||||||
|
if (*s) s++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*s != '-')
|
||||||
|
goto illegal;
|
||||||
|
s++;
|
||||||
|
if (!isdigit(*s)) return -3;
|
||||||
|
while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; }
|
||||||
|
channel = digit2;
|
||||||
|
if (channel <= 0 && channel > 30)
|
||||||
|
goto rangeerror;
|
||||||
|
if (*s == 0 || *s == ',' || *s == ' ') {
|
||||||
|
if (digit1 > digit2)
|
||||||
|
for (i = digit2; i <= digit1 ; i++)
|
||||||
|
bmask |= (1 << i);
|
||||||
|
else
|
||||||
|
for (i = digit1; i <= digit2 ; i++)
|
||||||
|
bmask |= (1 << i);
|
||||||
|
digit1 = digit2 = 0;
|
||||||
|
if (*s) s++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
goto illegal;
|
||||||
|
}
|
||||||
|
if (activep) *activep = active;
|
||||||
|
if (bmaskp) *bmaskp = bmask;
|
||||||
|
return 0;
|
||||||
|
illegal:
|
||||||
|
fatal("capiplugin: option channels: illegal octet '%c'", *s);
|
||||||
|
return -1;
|
||||||
|
rangeerror:
|
||||||
|
fatal("capiplugin: option channels: channel %d out of range", channel);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int channels2capi20(char *teln, unsigned char *AdditionalInfo)
|
||||||
|
{
|
||||||
|
unsigned long bmask;
|
||||||
|
int active;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
decodechannels(teln, &bmask, &active);
|
||||||
|
/* info("capiplugin: \"%s\" 0x%lx %d\n", teln, bmask, active); */
|
||||||
|
/* Length */
|
||||||
|
AdditionalInfo[0] = 2+2+31;
|
||||||
|
/* Channel: 3 => use channel allocation */
|
||||||
|
AdditionalInfo[1] = 3; AdditionalInfo[2] = 0;
|
||||||
|
/* Operation: 0 => DTE mode, 1 => DCE mode */
|
||||||
|
if (active) {
|
||||||
|
AdditionalInfo[3] = 0; AdditionalInfo[4] = 0;
|
||||||
|
} else {
|
||||||
|
AdditionalInfo[3] = 1; AdditionalInfo[4] = 0;
|
||||||
|
}
|
||||||
|
/* Channel mask array */
|
||||||
|
AdditionalInfo[5] = 0; /* no D-Channel */
|
||||||
|
for (i=1; i <= 30; i++)
|
||||||
|
AdditionalInfo[5+i] = (bmask & (1 << i)) ? 0xff : 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_options(void)
|
||||||
|
{
|
||||||
|
if ( opt_proto
|
||||||
|
&& strcasecmp(opt_proto, "hdlc")
|
||||||
|
&& strcasecmp(opt_proto, "x75")
|
||||||
|
&& strcasecmp(opt_proto, "v42bis")
|
||||||
|
&& strcasecmp(opt_proto, "modem")) {
|
||||||
|
option_error("capiplugin: unknown protocol \"%s\"", opt_proto);
|
||||||
|
die(1);
|
||||||
|
}
|
||||||
|
if (strcasecmp(opt_proto, "modem") == 0)
|
||||||
|
cipmask = CIPMASK_VOICE;
|
||||||
|
else cipmask = CIPMASK_DATA;
|
||||||
|
|
||||||
|
if (opt_channels) {
|
||||||
|
channels2capi20(opt_channels, AdditionalInfo);
|
||||||
|
if (opt_number)
|
||||||
|
option_error("capiplugin: option number ignored");
|
||||||
|
if (opt_numberprefix)
|
||||||
|
option_error("capiplugin: option numberprefix ignored");
|
||||||
|
if (opt_callbacknumber)
|
||||||
|
option_error("capiplugin: option callbacknumber ignored");
|
||||||
|
if (opt_msn)
|
||||||
|
option_error("capiplugin: option msn ignored");
|
||||||
|
if (opt_inmsn)
|
||||||
|
option_error("capiplugin: option inmsn ignored");
|
||||||
|
} else if (opt_number) {
|
||||||
|
stringlist_free(&numbers);
|
||||||
|
numbers = stringlist_split(opt_number, " \t,");
|
||||||
|
if (opt_callbacknumber)
|
||||||
|
option_error("capiplugin: option callbacknumber ignored");
|
||||||
|
} else if (opt_cbflag) {
|
||||||
|
if (opt_callbacknumber == 0) {
|
||||||
|
option_error("capiplugin: option callbacknumber missing");
|
||||||
|
die(1);
|
||||||
|
}
|
||||||
|
stringlist_free(&callbacknumbers);
|
||||||
|
callbacknumbers = stringlist_split(opt_callbacknumber, " \t,");
|
||||||
|
} else {
|
||||||
|
if (opt_callbacknumber) {
|
||||||
|
opt_cbflag = 1;
|
||||||
|
stringlist_free(&callbacknumbers);
|
||||||
|
callbacknumbers = stringlist_split(opt_callbacknumber, " \t,");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (opt_cli) {
|
||||||
|
stringlist_free(&clis);
|
||||||
|
clis = stringlist_split(opt_cli, " \t,");
|
||||||
|
}
|
||||||
|
if (opt_controller) {
|
||||||
|
STRINGLIST *sl;
|
||||||
|
char *tmp;
|
||||||
|
stringlist_free(&parsed_controller);
|
||||||
|
memset(&cinfo, 0, sizeof(cinfo));
|
||||||
|
parsed_controller = stringlist_split(opt_controller, " \t,");
|
||||||
|
sl = parsed_controller;
|
||||||
|
if (!sl) goto illcontr;
|
||||||
|
tmp = sl->s;
|
||||||
|
controller = strtol(sl->s, &tmp, 10);
|
||||||
|
if (tmp == sl->s || *tmp) goto illcontr;
|
||||||
|
if (sl->next) {
|
||||||
|
sl = sl->next;
|
||||||
|
cinfo.ddi = sl->s;
|
||||||
|
if (sl->next && sl->next->s) {
|
||||||
|
sl = sl->next;
|
||||||
|
cinfo.ndigits = strtol(sl->s, &tmp, 10);
|
||||||
|
if (tmp == sl->s || *tmp) goto illcontr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memset(&cinfo, 0, sizeof(cinfo));
|
||||||
|
controller = 1;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
illcontr:
|
||||||
|
option_error("capiplugin: illegal controller specification \"%s\"",
|
||||||
|
opt_controller);
|
||||||
|
die(1);
|
||||||
|
}
|
||||||
|
|
||||||
static int capi_new_phase_hook(int phase)
|
static int capi_new_phase_hook(int phase)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
switch (phase) {
|
switch (phase) {
|
||||||
case PHASE_DEAD:
|
case PHASE_DEAD:
|
||||||
info("capiplugin: phase dead");
|
info("capiplugin: phase dead");
|
||||||
|
if ((fd = capi20_fileno(applid)) >= 0)
|
||||||
|
remove_fd(fd);
|
||||||
|
unsetup_timeout();
|
||||||
dodisconnect();
|
dodisconnect();
|
||||||
break;
|
break;
|
||||||
case PHASE_INITIALIZE:
|
case PHASE_INITIALIZE:
|
||||||
info("capiplugin: phase initialize");
|
info("capiplugin: phase initialize");
|
||||||
break;
|
break;
|
||||||
case PHASE_SERIALCONN:
|
case PHASE_SERIALCONN:
|
||||||
info("capiplugin: phase serialconn");
|
info("capiplugin: phase serialconn%s",
|
||||||
|
opt_cbflag ? " (callback)" : "");
|
||||||
|
check_options();
|
||||||
init_capiconn();
|
init_capiconn();
|
||||||
makeconnection();
|
if (opt_number) {
|
||||||
|
if (opt_cbflag) {
|
||||||
|
makeconnection_with_callback();
|
||||||
|
} else {
|
||||||
|
makeconnection(numbers);
|
||||||
|
}
|
||||||
|
} else if (opt_channels) {
|
||||||
|
makeleasedline();
|
||||||
|
} else {
|
||||||
|
waitforcall();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PHASE_DORMANT:
|
case PHASE_DORMANT:
|
||||||
info("capiplugin: phase dormant");
|
info("capiplugin: phase dormant");
|
||||||
|
@ -212,9 +716,6 @@ static int capi_new_phase_hook(int phase)
|
||||||
break;
|
break;
|
||||||
case PHASE_TERMINATE:
|
case PHASE_TERMINATE:
|
||||||
info("capiplugin: phase terminate");
|
info("capiplugin: phase terminate");
|
||||||
if ((fd = capi20_fileno(applid)) >= 0)
|
|
||||||
remove_fd(fd);
|
|
||||||
unsetup_timeout();
|
|
||||||
break;
|
break;
|
||||||
case PHASE_DISCONNECT:
|
case PHASE_DISCONNECT:
|
||||||
info("capiplugin: phase disconnect");
|
info("capiplugin: phase disconnect");
|
||||||
|
@ -232,13 +733,28 @@ static char *conninfo(capi_connection *p)
|
||||||
{
|
{
|
||||||
static char buf[1024];
|
static char buf[1024];
|
||||||
capi_conninfo *cp = capiconn_getinfo(p);
|
capi_conninfo *cp = capiconn_getinfo(p);
|
||||||
|
char *callingnumber = "";
|
||||||
|
char *callednumber = "";
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf),
|
if (cp->callingnumber && cp->callingnumber[0] > 2)
|
||||||
"plci=0x%x ncci=0x%x %s",
|
callingnumber = cp->callingnumber+3;
|
||||||
cp->plci,
|
if (cp->callednumber && cp->callednumber[0] > 1)
|
||||||
cp->ncci,
|
callednumber = cp->callednumber+2;
|
||||||
cp->isincoming ? "incoming" : "outgoing"
|
|
||||||
);
|
if (debug) {
|
||||||
|
snprintf(buf, sizeof(buf),
|
||||||
|
"\"%s\" -> \"%s\" %s (pcli=0x%x/ncci=0x%x)",
|
||||||
|
callingnumber, callednumber,
|
||||||
|
cp->isincoming ? "incoming" : "outgoing",
|
||||||
|
cp->plci, cp->ncci
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, sizeof(buf),
|
||||||
|
"\"%s\" -> \"%s\" %s",
|
||||||
|
callingnumber, callednumber,
|
||||||
|
cp->isincoming ? "incoming" : "outgoing");
|
||||||
|
}
|
||||||
|
buf[sizeof(buf)-1] = 0;
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,14 +763,136 @@ static void disconnected(capi_connection *cp,
|
||||||
unsigned reason,
|
unsigned reason,
|
||||||
unsigned reason_b3)
|
unsigned reason_b3)
|
||||||
{
|
{
|
||||||
info("capiplugin: disconnected(%s): %s: 0x%04x (0x%04x) - %s",
|
if (reason != 0x3304 || debug) /* Another Applikation got the call */
|
||||||
conninfo(cp),
|
info("capiplugin: disconnect(%s): %s 0x%04x (0x%04x) - %s",
|
||||||
localdisconnect ? "local" : "remote",
|
localdisconnect ? "local" : "remote",
|
||||||
|
conninfo(cp),
|
||||||
reason, reason_b3, capi_info2str(reason));
|
reason, reason_b3, capi_info2str(reason));
|
||||||
conn = 0;
|
conn = 0;
|
||||||
isconnected = 0;
|
isconnected = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void incoming(capi_connection *cp,
|
||||||
|
unsigned contr,
|
||||||
|
unsigned cipvalue,
|
||||||
|
char *callednumber,
|
||||||
|
char *callingnumber)
|
||||||
|
{
|
||||||
|
STRINGLIST *p;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
info("capiplugin: incoming call: %s (0x%x)", conninfo(cp), cipvalue);
|
||||||
|
|
||||||
|
if (opt_inmsn) {
|
||||||
|
if ( (s = strstr(callednumber, opt_inmsn)) == 0
|
||||||
|
|| strcmp(s, opt_inmsn) != 0) {
|
||||||
|
info("capiplugin: ignoring call, msn mismatch (%s != %s)",
|
||||||
|
opt_inmsn, callednumber);
|
||||||
|
(void) capiconn_ignore(cp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (opt_msn) {
|
||||||
|
if ( (s = strstr(callednumber, opt_msn)) == 0
|
||||||
|
|| strcmp(s, opt_msn) != 0) {
|
||||||
|
info("capiplugin: ignoring call, msn mismatch (%s != %s)",
|
||||||
|
opt_msn, callednumber);
|
||||||
|
(void) capiconn_ignore(cp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt_cli) {
|
||||||
|
for (p = clis; p; p = p->next) {
|
||||||
|
if (strcmp(p->s, callingnumber) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!p) {
|
||||||
|
info("capiplugin: ignoring call, cli mismatch (%s != %s)",
|
||||||
|
opt_cli, callingnumber);
|
||||||
|
(void) capiconn_ignore(cp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (opt_number) {
|
||||||
|
for (p = numbers; p; p = p->next) {
|
||||||
|
if ( (s = strstr(callingnumber, p->s)) != 0
|
||||||
|
|| strcmp(s, p->s) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!p) {
|
||||||
|
info("capiplugin: ignoring call, number mismatch (%s != %s)",
|
||||||
|
opt_number, callingnumber);
|
||||||
|
(void) capiconn_ignore(cp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (opt_acceptdelayflag) {
|
||||||
|
/*
|
||||||
|
* non cli or number match,
|
||||||
|
* give more specific listen a chance (bad)
|
||||||
|
*/
|
||||||
|
info("capiplugin: accept delayed, no cli or number match");
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cipvalue) {
|
||||||
|
case 1: /* Speech */
|
||||||
|
case 4: /* 3.1 kHz audio */
|
||||||
|
case 5: /* 7 kHz audio */
|
||||||
|
case 16: /* Telephony */
|
||||||
|
case 26: /* 7 kHz telephony */
|
||||||
|
if (opt_proto && strcasecmp(opt_proto, "modem") == 0) {
|
||||||
|
if (opt_cbflag) goto callback;
|
||||||
|
(void) capiconn_accept(cp, 8, 1, 0, 0, 0, 0, 0);
|
||||||
|
goto accepted;
|
||||||
|
} else {
|
||||||
|
info("capiplugin: ignoring speech call from %s",
|
||||||
|
callingnumber);
|
||||||
|
(void) capiconn_ignore(cp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2: /* Unrestricted digital information */
|
||||||
|
case 3: /* Restricted digital information */
|
||||||
|
if (opt_proto == 0
|
||||||
|
|| strcasecmp(opt_proto, "hdlc") == 0) {
|
||||||
|
if (opt_cbflag) goto callback;
|
||||||
|
(void) capiconn_accept(cp, 0, 1, 0, 0, 0, 0, 0);
|
||||||
|
goto accepted;
|
||||||
|
} else if (strcasecmp(opt_proto, "x75") == 0) {
|
||||||
|
if (opt_cbflag) goto callback;
|
||||||
|
(void) capiconn_accept(cp, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
goto accepted;
|
||||||
|
} else if (strcasecmp(opt_proto, "v42bis") == 0) {
|
||||||
|
if (opt_cbflag) goto callback;
|
||||||
|
(void) capiconn_accept(cp, 0, 8, 0, 0, 0, 0, 0);
|
||||||
|
goto accepted;
|
||||||
|
} else {
|
||||||
|
info("capiplugin: ignoring digital call from %s",
|
||||||
|
callingnumber);
|
||||||
|
(void) capiconn_ignore(cp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 17: /* Group 2/3 facsimile */
|
||||||
|
info("capiplugin: ignoring fax call from %s",
|
||||||
|
callingnumber);
|
||||||
|
(void) capiconn_ignore(cp);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
info("capiplugin: ignoring type %d call from %s",
|
||||||
|
cipvalue, callingnumber);
|
||||||
|
(void) capiconn_ignore(cp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
accepted:
|
||||||
|
(void) capiconn_listen(ctx, controller, 0, 0);
|
||||||
|
return;
|
||||||
|
callback:
|
||||||
|
(void) capiconn_listen(ctx, controller, 0, 0);
|
||||||
|
info("capiplugin: rejecting call: %s (0x%x)", conninfo(cp), cipvalue);
|
||||||
|
capiconn_reject(cp);
|
||||||
|
makecallback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static void connected(capi_connection *cp, _cstruct NCPI)
|
static void connected(capi_connection *cp, _cstruct NCPI)
|
||||||
{
|
{
|
||||||
capi_conninfo *p = capiconn_getinfo(cp);
|
capi_conninfo *p = capiconn_getinfo(cp);
|
||||||
|
@ -262,8 +900,10 @@ static void connected(capi_connection *cp, _cstruct NCPI)
|
||||||
char *tty;
|
char *tty;
|
||||||
|
|
||||||
tty = capi20ext_get_tty_devname(p->appid, p->ncci, buf, sizeof(buf));
|
tty = capi20ext_get_tty_devname(p->appid, p->ncci, buf, sizeof(buf));
|
||||||
info("capiplugin: connected(%s) %s", conninfo(cp), tty);
|
info("capiplugin: connected(%s): %s", conninfo(cp), tty);
|
||||||
strcpy(devnam, tty);
|
strcpy(devnam, tty);
|
||||||
|
if (opt_connectdelay)
|
||||||
|
sleep(opt_connectdelay);
|
||||||
isconnected = 1;
|
isconnected = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +912,7 @@ void put_message(unsigned appid, unsigned char *msg)
|
||||||
unsigned err;
|
unsigned err;
|
||||||
err = capi20_put_message (appid, msg);
|
err = capi20_put_message (appid, msg);
|
||||||
if (err)
|
if (err)
|
||||||
fatal("capiplugin: putmessage(appid=%u) = 0x%x", appid, err);
|
fatal("capiplugin: putmessage(appid=%d) = 0x%x", appid, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
@ -282,7 +922,7 @@ capiconn_callbacks callbacks = {
|
||||||
free: free,
|
free: free,
|
||||||
|
|
||||||
disconnected: disconnected,
|
disconnected: disconnected,
|
||||||
incoming: 0,
|
incoming: incoming,
|
||||||
connected: connected,
|
connected: connected,
|
||||||
received: 0,
|
received: 0,
|
||||||
datasent: 0,
|
datasent: 0,
|
||||||
|
@ -299,7 +939,7 @@ void plugin_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
info("plugin_init: capiconnect (%s)", revision);
|
info("capiplugin: %s", revision);
|
||||||
|
|
||||||
add_options(my_options);
|
add_options(my_options);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
debug
|
||||||
|
sync
|
||||||
|
noauth
|
||||||
|
defaultroute
|
||||||
|
lcp-echo-interval 5
|
||||||
|
lcp-echo-failure 3
|
||||||
|
lcp-max-configure 50
|
||||||
|
lcp-max-terminate 2
|
||||||
|
noccp
|
||||||
|
noipx
|
||||||
|
persist
|
||||||
|
plugin /etc/ppp/plugins/capiplugin.so
|
||||||
|
channels 1
|
||||||
|
protocol hdlc
|
||||||
|
ipcp-accept-local
|
||||||
|
ipcp-accept-remote
|
||||||
|
:
|
Loading…
Reference in New Issue