Added support for ISDN CAPI interface using libcapi20.

This commit is contained in:
MelwareDE 2005-06-02 18:33:27 +00:00
parent fa6be5da46
commit a9f752ad69
12 changed files with 2717 additions and 54 deletions

View File

@ -1,6 +1,9 @@
Copyright (c) 1997 Ulrich Dessauer
All rights reserved.
Support for ISDN CAPI copyright (c) 2004-2005 by
Armin Schindler <armin@melware.de>
You may distribute under the terms of the GNU General Public
License.

View File

@ -7,9 +7,9 @@ CFLAGS := $(CFLAGS)
#
DEFS = -DCFGFILE=\"$(YAPS_CFGFILE)\" -DLCFGFILE=\"$(YAPS_LCFGFILE)\" \
-DLIBDIR=\"$(YAPS_LIBDIR)\"
LIBS = -L. -lpager $(LLIBS)
LIBS = -L. -lpager $(LLIBS) -lcapi20
OBJS = data.o util.o cfg.o tty.o cv.o asc.o scr.o tap.o ucp.o \
slang.o lua.o #mem.o
slang.o lua.o capiconn.o #mem.o
YOBJS = yaps.o valid.o
DSTFLE = $(YAPS_BINDIR)/yaps

4
README
View File

@ -14,6 +14,9 @@ Copyright:
Copyright (c) 1997 Ulrich Dessauer
All rights reserved.
Support for ISDN-CAPI copyright (c) 2004-2005 by
Armin Schindler <armin@melware.de>
You may distribute under the terms of the GNU General Public
License.
@ -106,6 +109,7 @@ Makefile, Config: Make rules
yaps.rc: Sample configuration file
yaps.c: The driver program
valid.c, valid.h: Support routines for the driver program
capiconn.c, capiconn.h: CAPI support
remaining *.c, *.h: The paging library
yaps.html, yaps.doc: Documentation in HTML and plain text
yaps.1: A minimal manual page

1778
capiconn.c Normal file

File diff suppressed because it is too large Load Diff

429
capiconn.h Normal file
View File

@ -0,0 +1,429 @@
/*
* CAPI connection handling
*
* heavily based on capiconn.* of pppdcapiplugin by
* Carsten Paeth (calle@calle.in-berlin.de)
*
* Copyright 2004 Armin Schindler <armin@melware.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef __CAPICONN_H__
#define __CAPICONN_H__
#include <stdarg.h>
#include <capi20.h>
/*
* CAPI_MESSAGES:
* capiconn_inject():
* inject capi message into state machine
*
* capiconn_context:
* capiconn_getcontext():
* get a context and supply callback functions
* capiconn_freecontext():
* free a context allocated with "capiconn_getcontext"
* capiconn_addcontr():
* add a controller to the context
* capi_connection:
* capiconn_connect():
* connection setup, return a capi_connection.
* capiconn_accept():
* accept an incoming connection
* capiconn_ignore():
* ignore an incoming connection
* capiconn_reject():
* reject an incoming connection
* capiconn_send():
* send data to the connection
* capiconn_disconnect():
* disconnect a connection
* capiconn_getinfo()
* get infos about the connection
* capiconn_listen():
* setup listen
*/
/* -------- returncodes -------------------------------------------------- */
#define CAPICONN_OK 0
#define CAPICONN_NO_CONTROLLER -1
#define CAPICONN_NO_MEMORY -2
#define CAPICONN_WRONG_STATE 1
#define CAPICONN_NOT_SENT 2
#define CAPICONN_ALREADY_DISCONNECTING 3
/* -------- states for CAPI2.0 machine ----------------------------------- */
/*
* LISTEN state machine
*/
#define ST_LISTEN_NONE 0 /* L-0 */
#define ST_LISTEN_WAIT_CONF 1 /* L-0.1 */
#define ST_LISTEN_ACTIVE 2 /* L-1 */
#define ST_LISTEN_ACTIVE_WAIT_CONF 3 /* L-1.1 */
#define EV_LISTEN_REQ 1 /* L-0 -> L-0.1
L-1 -> L-1.1 */
#define EV_LISTEN_CONF_ERROR 2 /* L-0.1 -> L-0
L-1.1 -> L-1 */
#define EV_LISTEN_CONF_EMPTY 3 /* L-0.1 -> L-0
L-1.1 -> L-0 */
#define EV_LISTEN_CONF_OK 4 /* L-0.1 -> L-1
L-1.1 -> L.1 */
/*
* per plci state machine
*/
#define ST_PLCI_NONE 0 /* P-0 */
#define ST_PLCI_OUTGOING 1 /* P-0.1 */
#define ST_PLCI_ALLOCATED 2 /* P-1 */
#define ST_PLCI_ACTIVE 3 /* P-ACT */
#define ST_PLCI_INCOMING 4 /* P-2 */
#define ST_PLCI_FACILITY_IND 5 /* P-3 */
#define ST_PLCI_ACCEPTING 6 /* P-4 */
#define ST_PLCI_DISCONNECTING 7 /* P-5 */
#define ST_PLCI_DISCONNECTED 8 /* P-6 */
#define ST_PLCI_RESUMEING 9 /* P-0.Res */
#define ST_PLCI_RESUME 10 /* P-Res */
#define ST_PLCI_HELD 11 /* P-HELD */
#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1
*/
#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0
*/
#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1
*/
#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1
*/
#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2
*/
#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT
*/
#define EV_PLCI_CONNECT_REJECT 7 /* P-2 -> P-5
P-3 -> P-5
*/
#define EV_PLCI_DISCONNECT_REQ 8 /* P-1 -> P-5
P-2 -> P-5
P-3 -> P-5
P-4 -> P-5
P-ACT -> P-5
P-Res -> P-5 (*)
P-HELD -> P-5 (*)
*/
#define EV_PLCI_DISCONNECT_IND 9 /* P-1 -> P-6
P-2 -> P-6
P-3 -> P-6
P-4 -> P-6
P-5 -> P-6
P-ACT -> P-6
P-Res -> P-6 (*)
P-HELD -> P-6 (*)
*/
#define EV_PLCI_FACILITY_IND_DOWN 10 /* P-0.1 -> P-5
P-1 -> P-5
P-ACT -> P-5
P-2 -> P-5
P-3 -> P-5
P-4 -> P-5
*/
#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0
*/
#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0
*/
#define EV_PLCI_RESUME_REQ 13 /* P-0 -> P-0.Res
*/
#define EV_PLCI_RESUME_CONF_OK 14 /* P-0.Res -> P-Res
*/
#define EV_PLCI_RESUME_CONF_ERROR 15 /* P-0.Res -> P-0
*/
#define EV_PLCI_RESUME_IND 16 /* P-Res -> P-ACT
*/
#define EV_PLCI_HOLD_IND 17 /* P-ACT -> P-HELD
*/
#define EV_PLCI_RETRIEVE_IND 18 /* P-HELD -> P-ACT
*/
#define EV_PLCI_SUSPEND_IND 19 /* P-ACT -> P-5
*/
#define EV_PLCI_CD_IND 20 /* P-2 -> P-5
*/
/*
* per ncci state machine
*/
#define ST_NCCI_PREVIOUS -1
#define ST_NCCI_NONE 0 /* N-0 */
#define ST_NCCI_OUTGOING 1 /* N-0.1 */
#define ST_NCCI_INCOMING 2 /* N-1 */
#define ST_NCCI_ALLOCATED 3 /* N-2 */
#define ST_NCCI_ACTIVE 4 /* N-ACT */
#define ST_NCCI_RESETING 5 /* N-3 */
#define ST_NCCI_DISCONNECTING 6 /* N-4 */
#define ST_NCCI_DISCONNECTED 7 /* N-5 */
#define EV_NCCI_CONNECT_B3_REQ 1 /* N-0 -> N-0.1 */
#define EV_NCCI_CONNECT_B3_IND 2 /* N-0 -> N.1 */
#define EV_NCCI_CONNECT_B3_CONF_OK 3 /* N-0.1 -> N.2 */
#define EV_NCCI_CONNECT_B3_CONF_ERROR 4 /* N-0.1 -> N.0 */
#define EV_NCCI_CONNECT_B3_REJECT 5 /* N-1 -> N-4 */
#define EV_NCCI_CONNECT_B3_RESP 6 /* N-1 -> N-2 */
#define EV_NCCI_CONNECT_B3_ACTIVE_IND 7 /* N-2 -> N-ACT */
#define EV_NCCI_RESET_B3_REQ 8 /* N-ACT -> N-3 */
#define EV_NCCI_RESET_B3_IND 9 /* N-3 -> N-ACT */
#define EV_NCCI_DISCONNECT_B3_IND 10 /* N-4 -> N.5 */
#define EV_NCCI_DISCONNECT_B3_CONF_ERROR 11 /* N-4 -> previous */
#define EV_NCCI_DISCONNECT_B3_REQ 12 /* N-1 -> N-4
N-2 -> N-4
N-3 -> N-4
N-ACT -> N-4 */
#define EV_NCCI_DISCONNECT_B3_RESP 13 /* N-5 -> N-0 */
/* ----------------------------------------------------------------------- */
char *capiconn_version(void);
/* -------- context ------------------------------------------------------ */
struct capi_connection; typedef struct capi_connection capi_connection;
struct capiconn_context; typedef struct capiconn_context capiconn_context;
struct capiconn_callbacks
{
/* ---------- memory functions ----------------- */
void *(*malloc)(size_t size);
void (*free)(void *buf);
/* ---------- connection callbacks ------------- */
/*
* the capi_connection will be destoried after
* calling this function
*/
void (*disconnected)(capi_connection *,
int localdisconnect,
unsigned reason,
unsigned reason_b3);
/*
* The application should call capiconn_accept()
* capiconn_ignore() or capiconn_reject() inside
* of the function. If not called an ALERT_REQ will
* be sent, to let the application time to decide ...
*/
void (*incoming)(capi_connection *,
unsigned contr,
unsigned chipvalue,
char *callednumber,
char *callingnumber);
/*
* Channel is ready to send and receive data
*/
void (*connected)(capi_connection *, _cstruct);
/*
* Data received on channel, the data pointer
* can not be used, after this function is called.
*/
void (*received)(capi_connection *,
unsigned char *data,
unsigned datalen);
/*
* called for every call to capiconn_send().
*/
void (*datasent)(capi_connection *, unsigned char *);
/*
* charge info received
*/
void (*chargeinfo)(capi_connection *,
unsigned long charge,
int inunits);
/*
* capi functions
*/
void (*capi_put_message) (unsigned appid, unsigned char *msg);
/*
* message functions
*/
void (*debugmsg)(const char *fmt, ...);
void (*infomsg)(const char *fmt, ...);
void (*errmsg)(const char *fmt, ...);
};
typedef struct capiconn_callbacks capiconn_callbacks;
/* -------- context functions -------------------------------------------- */
capiconn_context *capiconn_getcontext(unsigned appid, capiconn_callbacks *env);
int capiconn_freecontext(capiconn_context *ctx);
/* -------- inject capi message into state machine ----------------------- */
void capiconn_inject(unsigned appid, unsigned char *msg);
/* -------- add controller to context ------------------------------------ */
struct capi_contrinfo {
int bchannels;
char *ddi;
int ndigits; /* Durchwahllaenge */
};
typedef struct capi_contrinfo capi_contrinfo;
/*
* returncodes:
* CAPICONN_OK - controller added to the context
* CAPICONN_NO_MEMORY - callback "malloc" returns no memory.
*/
int capiconn_addcontr(capiconn_context *ctx,
unsigned contr, capi_contrinfo *cinfo);
/* -------- initiate a connection & disconnect a connection -------------- */
/*
* returncodes:
* a capi connection or 0 if
* - controller not found
* - memory problems
*/
capi_connection *
capiconn_connect(
capiconn_context *ctx,
unsigned contr,
_cword cipvalue,
char *callednumber, /* remote number */
char *callingnumber, /* own number */
_cword b1proto,
_cword b2proto,
_cword b3proto,
_cstruct b1config,
_cstruct b2config,
_cstruct b3config,
_cstruct bchaninfo,
_cstruct ncpi);
/*
* returncodes:
* CAPICONN_OK - disconnect initiated
* CAPICONN_ALREADY_DISCONNECTING - disconnect already initiated
* CAPICONN_WRONG_STATE - should not happen
*/
int capiconn_disconnect(capi_connection *connection, _cstruct ncpi);
/* -------- reaction on incoming calls ----------------------------------- */
/*
* returncodes:
* CAPICONN_OK - Accept initiated
* CAPICONN_WRONG_STATE - "conn" ist not in state "incoming"
* CAPICONN_NO_MEMORY - callback "malloc" returns no memory.
*/
int capiconn_accept(
capi_connection *conn,
_cword b1proto,
_cword b2proto,
_cword b3proto,
_cstruct b1config,
_cstruct b2config,
_cstruct b3config,
_cstruct ncpi);
/*
* returncodes:
* CAPICONN_OK - call will be ignored
* CAPICONN_WRONG_STATE - "conn" ist not in state "incoming"
*/
int capiconn_ignore(capi_connection *conn);
/*
* returncodes:
* CAPICONN_OK - call will be rejected
* CAPICONN_WRONG_STATE - "conn" ist not in state "incoming"
*/
int capiconn_reject(capi_connection *conn);
/*
* returncode:
* CAPICONN_OK - Data sent to CAPI
* CAPICONN_NOT_SENT - Data not sent (8 messages not acked)
* CAPICONN_WRONG_STATE - Connection is not connected
*/
int capiconn_send(capi_connection *plcip,
unsigned char *data,
unsigned len);
/*
* get info about connection
*/
struct capi_conninfo {
unsigned appid;
unsigned plci;
int plci_state;
unsigned ncci;
int ncci_state;
unsigned isincoming:1,
disconnect_was_local;
unsigned disconnectreason;
unsigned disconnectreason_b3;
/* user supplied */
_cword cipvalue;
_cstruct callednumber;
_cstruct callingnumber;
_cword b1proto;
_cword b2proto;
_cword b3proto;
_cstruct b1config;
_cstruct b2config;
_cstruct b3config;
_cstruct bchaninfo;
_cstruct ncpi;
};
typedef struct capi_conninfo capi_conninfo;
/*
* returncode:
* always a pointer to the conninfo.
* the conninfo will not be update automaticly,
* you always have to call this function to get
* the actual informations.
*/
capi_conninfo *capiconn_getinfo(capi_connection *p);
/*
* returncodes:
* CAPICONN_OK - Listen request sent
* CAPICONN_NO_CONTROLLER - Controller "contr" not added with
* capiconn_addcontr()
*/
int capiconn_listen(capiconn_context *ctx,
unsigned contr, unsigned cipmask, unsigned cipmask2);
/*
* returncodes:
* CAPICONN_OK - got ack for listen request
* CAPICONN_NO_CONTROLLER - Controller "contr" not added with
* capiconn_addcontr()
* CAPICONN_WRONG_STATE - got no ack for listen request
*/
int capiconn_listenstate(capiconn_context *ctx, unsigned contr);
#endif /* __CAPICONN_H__ */

14
pager.h
View File

@ -204,4 +204,18 @@ extern void ucp_postdeinit (void);
extern int verbose;
extern int (*verbout) (char *, ...);
/*}}}*/
/*{{{ CAPI */
extern int device_is_capi(char *dev);
extern int hyla_is_capi(void *sp);
extern void *hyla_capi_init(char *dev);
extern void hyla_capi_disconnect(void *sp);
extern void *hyla_capi_close(void *sp);
extern int hyla_capi_connect(void *sp, char *dial, char *number);
extern int hyla_capi_send(void *sp, char *str, int len);
extern size_t hyla_capi_read(void *sp, void *buf, size_t count);
extern void hyla_capi_iflush(void *sp);
extern void hyla_capi_oflush(void *sp);
extern void hyla_capi_drain(void *sp);
extern void hyla_capi_sendbreak(void *sp, int duration);
/*}}}*/
# endif /* __PAGER_H */

1
scr.c
View File

@ -2,6 +2,7 @@
# include "config.h"
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include "pager.h"
# include "script.h"

443
tty.c
View File

@ -78,6 +78,11 @@ typedef struct {
void (*callback) (void *, string_t *, char_t, void *);
void *data;
Bool suspend;
/* CAPI */
int is_capi;
int controller;
char *msn;
int connected;
} serial;
typedef struct _expect {
@ -88,6 +93,9 @@ typedef struct _expect {
struct _expect
*next;
} expect;
static int data_ready (serial *s, int fd, int *msec);
/*}}}*/
/*{{{ support routines */
static char *
@ -186,24 +194,6 @@ msleep (int msec)
}
}
static inline int
data_ready (int fd, int *msec)
{
int ret = 0;
struct timeval tv;
fd_set fset;
FD_ZERO (& fset);
FD_SET (fd, & fset);
tv.tv_sec = *msec / 1000;
tv.tv_usec = (*msec % 1000) * 1000;
if (((ret = select (fd + 1, & fset, NULL, NULL, & tv)) > 0) && FD_ISSET (fd, & fset)) {
*msec = tv.tv_sec * 1000 + (tv.tv_usec / 1000);
return 1;
}
return ret;
}
static Bool
do_lock (serial *s, char *dev, char *prefix, char *method)
{
@ -366,6 +356,7 @@ tty_open (char *dev, char *lckprefix, char *lckmethod)
# ifndef NDEBUG
s -> magic = MAGIC;
# endif /* NDEBUG */
s -> is_capi = 0;
if (do_lock (s, dev, lckprefix, lckmethod)) {
if ((s -> fd = open (dev, O_RDWR)) != -1) {
n = tcgetattr (s -> fd, & s -> sav);
@ -401,6 +392,9 @@ tty_close (void *sp)
serial *s = (serial *) sp;
MCHK (s);
if (s -> is_capi) {
return(hyla_capi_close(sp));
}
if (s) {
if (s -> fd != -1) {
tcsetattr (s -> fd, TCSANOW, & s -> sav);
@ -424,6 +418,11 @@ tty_reopen (void *sp, int msec)
serial *s = (serial *) sp;
MCHK (s);
if (s -> is_capi) {
return((s -> connected) ? True : False);
}
if (s -> fd != -1) {
close (s -> fd);
if (msec > 0)
@ -445,6 +444,10 @@ tty_hangup (void *sp, int msec)
MCHK (s);
V (2, ("[Hangup] "));
if (s && (s -> fd != -1)) {
if (s -> is_capi) {
hyla_capi_disconnect(sp);
return;
} else {
tmp = s -> tty;
cfsetispeed (& tmp, B0);
cfsetospeed (& tmp, B0);
@ -454,6 +457,7 @@ tty_hangup (void *sp, int msec)
}
tty_reopen (s, msec);
}
}
V (2, ("\n"));
}
@ -598,7 +602,14 @@ tty_send (void *sp, char *str, int len)
return -1;
V (2, ("[Send] %s", mkprint (str, len)));
sent = 0;
while (len > 0)
while (len > 0) {
if (s -> is_capi) {
if (hyla_capi_send(sp, str, len)) {
sent = len;
len = 0;
}
break;
}
if ((n = write (s -> fd, str, len)) > 0) {
str += n;
sent += n;
@ -612,6 +623,7 @@ tty_send (void *sp, char *str, int len)
msleep (200);
else if (errno != EINTR)
break;
}
V (2, ("\n"));
return sent;
}
@ -640,6 +652,14 @@ addline (serial *s, char ch)
}
}
static size_t dev_read(serial *s, int fd, void *buf, size_t count)
{
if (s -> is_capi)
return(hyla_capi_read(s, buf, count));
return(read(fd, buf, count));
}
static int
do_expect (serial *s, int tout, expect *base)
{
@ -657,8 +677,8 @@ do_expect (serial *s, int tout, expect *base)
msec = (tout > 0) ? tout * 1000 : 0;
ret = 0;
while (! ret)
if ((n = data_ready (s -> fd, & msec)) > 0) {
while ((n = read (s -> fd, & ch, 1)) == 1) {
if ((n = data_ready (s, s -> fd, & msec)) > 0) {
while ((n = dev_read (s, s -> fd, & ch, 1)) == 1) {
addline (s, ch);
V (3, ("%s", mkprint (& ch, 1)));
for (run = base; run; run = run -> next)
@ -900,6 +920,9 @@ handle_command (void *sp, char *str)
case 'b':
if (s && (s -> fd != -1)) {
V (2, (" Brk %d", mult));
if (s -> is_capi)
hyla_capi_sendbreak(s, mult);
else
tcsendbreak (s -> fd, mult);
}
break;
@ -912,18 +935,27 @@ handle_command (void *sp, char *str)
case 'o':
if (s && (s -> fd != -1)) {
V (2, (" Drain"));
if (s -> is_capi)
hyla_capi_drain(s);
else
tcdrain (s -> fd);
}
break;
case '<':
if (s && (s -> fd != -1)) {
V (2, (" Iflush"));
if (s -> is_capi)
hyla_capi_iflush(s);
else
tcflush (s -> fd, TCIFLUSH);
}
break;
case '>':
if (s && (s -> fd != -1)) {
V (2, (" Oflush"));
if (s -> is_capi)
hyla_capi_oflush(s);
else
tcflush (s -> fd, TCOFLUSH);
}
break;
@ -1110,8 +1142,8 @@ tty_mdrain (void *sp, int msecs)
if (msecs < 0)
msecs = 0;
do {
if ((n = data_ready (s -> fd, & msecs)) > 0) {
while ((m = read (s -> fd, & ch, 1)) == 1) {
if ((n = data_ready (s, s -> fd, & msecs)) > 0) {
while ((m = dev_read (s, s -> fd, & ch, 1)) == 1) {
addline (s, ch);
V (2, ("%s", mkprint (& ch, 1)));
}
@ -1130,3 +1162,368 @@ tty_drain (void *sp, int secs)
tty_mdrain (sp, secs * 1000);
}
/*}}}*/
/*
* CAPI
*/
#include "capiconn.h"
static capiconn_context *ctx;
static unsigned applid;
static capi_contrinfo cinfo = { 0 , 0, 0 };
static struct capi_connection *capi_conn = NULL;
static serial *capi_serial;
static int conn_in_progress = 0;
static int capi_data_sent;
static unsigned char capi_data[4096];
static int capi_data_len = 0;
static void handle_messages(void)
{
unsigned char *msg = 0;
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
again:
if (capi20_waitformessage(applid, &tv) == 0) {
if (capi20_get_message(applid, &msg) == 0)
capiconn_inject(applid, msg);
tv.tv_sec = 0;
tv.tv_usec = 0;
goto again;
}
}
int device_is_capi(char *dev)
{
if (!dev)
return(0);
if (strlen(dev) < 4)
return(0);
if (strncasecmp(dev, "capi", 4))
return(0);
return(1);
}
int hyla_is_capi(void *sp)
{
serial *s = (serial *) sp;
return(s->is_capi);
}
static void capi_log(const char *format, ...)
{
char buffer[2048];
va_list ap;
va_start(ap, format);
vsprintf(buffer, format, ap);
strcat(buffer, "\n");
va_end(ap);
V (3, (buffer));
}
static void chargeinfo(capi_connection *cp, unsigned long charge, int inunits)
{
if (inunits) {
V (3, ("charge in units: %d\n", charge));
} else {
V (3, ("charge in currency: %d\n", charge));
}
}
static void put_message(unsigned appid, unsigned char *msg)
{
unsigned err;
err = capi20_put_message (appid, msg);
if (err)
V (2, ("capi putmessage %s 0x%x\n",
capi_info2str(err), err));
}
static void connected(capi_connection *cp, _cstruct NCPI)
{
capi_serial -> connected = 1;
conn_in_progress = 0;
V (3, ("CAPI connected\n"));
}
static void disconnected(capi_connection *cp,
int localdisconnect,
unsigned reason,
unsigned reason_b3)
{
capi_serial -> connected = 0;
conn_in_progress = 0;
capi_conn = NULL;
V (3, ("CAPI disconnected\n"));
}
static void handle_capi_sent(capi_connection *con, unsigned char* data)
{
capi_data_sent = 1;
}
static void handle_capi_data(capi_connection *con, unsigned char* data, unsigned int len)
{
int mlen = ((sizeof(capi_data) - capi_data_len) < len) ?
(sizeof(capi_data) - capi_data_len) : len;
if (mlen) {
memcpy(&capi_data[capi_data_len], data, mlen);
capi_data_len += mlen;
} else {
V (3, ("\ncapi data buffer overflow\n"));
}
}
capiconn_callbacks callbacks = {
malloc: malloc,
free: free,
disconnected: disconnected,
incoming: 0,
connected: connected,
received: handle_capi_data,
datasent: handle_capi_sent,
chargeinfo: chargeinfo,
capi_put_message: put_message,
debugmsg: (void (*)(const char *, ...))capi_log,
infomsg: (void (*)(const char *, ...))capi_log,
errmsg: (void (*)(const char *, ...))capi_log
};
void *hyla_capi_init(char *dev)
{
serial *s;
char *p, *p1, *p2;
if (s = (serial *) malloc (sizeof (serial))) {
if ((capi20_register (1, 8, 2048, &applid)) != 0) {
free (s);
V (3, ("Error CAPI register\n"));
return(NULL);
}
# ifndef NDEBUG
s -> magic = MAGIC;
# endif /* NDEBUG */
s -> device = strdup (dev);
p = skipch(s -> device, '/');
p1 = p;
p2 = skipch(p, '/');
if (*p1)
s -> controller = strtol(p1, NULL, 10);
else
s -> controller = 1;
if (*p2)
s -> msn = strdup(p2);
else
s -> msn = NULL;
V (3, ("CAPI controller=%d MSN=%s\n", s -> controller, s -> msn));
if ((ctx = capiconn_getcontext(applid, &callbacks)) != 0) {
if (capiconn_addcontr(ctx, s -> controller, &cinfo) != CAPICONN_OK) {
(void)capiconn_freecontext(ctx);
(void)capi20_release(applid);
if (s -> msn)
free (s -> msn);
if (s -> device)
free (s -> device);
free (s);
s = NULL;
}
s -> fd = capi20_fileno(applid);
s -> is_capi = 1;
s -> connected = 0;
s -> line = NULL;
s -> sep = NULL;
s -> callback = NULL;
s -> data = NULL;
s -> suspend = False;
capi_serial = s;
} else {
(void)capi20_release(applid);
V (3, ("Error CAPI-conn register\n"));
if (s -> msn)
free (s -> msn);
if (s -> device)
free (s -> device);
free (s);
s = NULL;
}
}
return s;
}
void hyla_capi_disconnect(void *sp)
{
serial *s = (serial *) sp;
time_t t;
if (!s || !s -> connected)
return;
(void)capiconn_disconnect(capi_conn, 0);
t = time(NULL) + 3; /* 3 seconds */
do {
handle_messages();
} while ((time(NULL) < t) && (s -> connected));
}
void *hyla_capi_close(void *sp)
{
serial *s = (serial *) sp;
MCHK (s);
if (s) {
hyla_capi_disconnect(sp);
(void)capi20_release(applid);
(void)capiconn_freecontext(ctx);
if (s -> device)
free (s -> device);
if (s -> msn)
free (s -> msn);
if (s -> sep)
free (s -> sep);
if (s -> line)
sfree (s -> line);
free (s);
capi_serial = NULL;
capi_conn = NULL;
}
return(NULL);
}
int hyla_capi_connect(void *sp, char *dial, char *number)
{
serial *s = (serial *) sp;
struct capi_connection *cp;
time_t t;
char num[128];
conn_in_progress = 1;
if (!dial)
dial = "";
sprintf(num, "%s%s", dial, number);
/* X.75 connect */
cp = capiconn_connect(ctx,
s -> controller,
2, /* cip */
num,
s -> msn,
0, 0, 0,
0, 0, 0,
0, 0);
capi_conn = cp;
t = time(NULL) + 10; /* 10 seconds */
do {
handle_messages();
} while ((time(NULL) < t) && (conn_in_progress));
if ((!s -> connected) && (capi_conn))
(void)capiconn_disconnect(capi_conn, 0);
return(s -> connected);
}
int hyla_capi_send(void *sp, char *str, int len)
{
serial *s = (serial *) sp;
time_t t;
if (!s || !s -> connected)
return(0);
capi_data_sent = 0;
capiconn_send(capi_conn, str, len);
t = time(NULL) + 5; /* 5 seconds */
do {
handle_messages();
} while ((time(NULL) < t) && (!capi_data_sent));
return(capi_data_sent);
}
size_t hyla_capi_read(void *sp, void *buf, size_t count)
{
serial *s = (serial *) sp;
size_t ret=0;
if (!capi_data_len)
handle_messages();
if (!s || !s -> connected)
return(-1);
ret = (count < capi_data_len) ? count : capi_data_len;
memcpy(buf, capi_data, ret);
capi_data_len -= ret;
memmove(capi_data, capi_data+ret, capi_data_len);
return(ret);
}
void hyla_capi_iflush(void *sp)
{
capi_data_len = 0;
}
void hyla_capi_oflush(void *sp)
{
/* not necessary */
}
void hyla_capi_drain(void *sp)
{
/* not necessary */
}
void hyla_capi_sendbreak(void *sp, int duration)
{
/* ... */
}
static int
data_ready (serial *s, int fd, int *msec)
{
int ret = 0;
struct timeval tv;
fd_set fset;
if (s -> is_capi) {
if (capi_data_len)
return(1);
if (!s -> connected)
return(0);
}
FD_ZERO (& fset);
FD_SET (fd, & fset);
tv.tv_sec = *msec / 1000;
tv.tv_usec = (*msec % 1000) * 1000;
if (((ret = select (fd + 1, & fset, NULL, NULL, & tv)) > 0) && FD_ISSET (fd, & fset)) {
*msec = tv.tv_sec * 1000 + (tv.tv_usec / 1000);
return 1;
}
return ret;
}

38
yaps.c
View File

@ -22,7 +22,7 @@
# include "valid.h"
/*}}}*/
/*{{{ general definitions */
# define VERSION "0.96 (alpha software)"
# define VERSION "0.96.c2 (alpha software, CAPI support V2)"
# ifndef LIBDIR
# define LIBDIR NULL
@ -389,7 +389,10 @@ do_dial (void *cfg, char *service, char *pagerid, char **modem)
s2 = p2;
p2 = skipch (p2, ',');
V (3, ("Trying to open %s for modem %s\n", s2, sav));
if (sp = tty_open (s2, lckpre, lckmethod)) {
if (device_is_capi(s2)) {
if (sp = hyla_capi_init(s2))
break;
} else if (sp = tty_open (s2, lckpre, lckmethod)) {
if (tty_setup (sp, True, True, rspeed, bpb, sb, parity) != -1) {
if (! (n = setjmp (env))) {
dojump = True;
@ -425,7 +428,20 @@ do_dial (void *cfg, char *service, char *pagerid, char **modem)
s2 = p2;
p2 = skipch (p2, ',');
siz = strlen (dial) + strlen (phone) + 64;
if (tmp = malloc (siz + 2)) {
if (hyla_is_capi(sp)) {
if ((!dial) || (!isdigit(*dial)))
dial = "";
V (3, ("Trying do dial %s%s\n",
(dial) ? dial : "", s2));
if (hyla_capi_connect(sp, dial, s2)) {
V (1, ("Dial successful\n"));
while (*p2)
++p2;
} else {
if (!*p2)
sp = hyla_capi_close(sp);
}
} else if (tmp = malloc (siz + 2)) {
for (n = 0, m = 0; dial[n]; ) {
if (dial[n] == '%') {
++n;
@ -1130,7 +1146,7 @@ remove_invalids (char *str, char *rmv)
static message *
create_messages (void *cfg, char *service, serv *sbase, char **argv, int argc, char *mfile, int *mcnt,
char *callid, char *sig, Bool trunc, Bool force, date_t *delay, date_t *expire, Bool rds)
char *callid, char *sig, Bool ytrunc, Bool force, date_t *delay, date_t *expire, Bool rds)
{
char **recv;
int rcnt, rsiz;
@ -1430,14 +1446,14 @@ create_messages (void *cfg, char *service, serv *sbase, char **argv, int argc, c
}
for (n = 0; n < cnt; ++n) {
sr = mg[n].service;
if (! trunc)
if (! ytrunc)
ttrunc = cfg_bget (cfg, sr, CFG_TRUNCATE, False);
else
ttrunc = trunc;
ttrunc = ytrunc;
msize = cfg_iget (cfg, sr, CFG_MAXSIZE, 0);
msplit = cfg_bget (cfg, sr, CFG_MAYSPLIT, False);
if ((msize > 0) && (mg[n].msg -> len > msize))
if (trunc)
if (ytrunc)
mg[n].msg -> len = msize;
else if (! msplit) {
fprintf (stderr, "Unable to split message for service %s\n", sr);
@ -2168,7 +2184,7 @@ main (int argc, char **argv)
serv *sbase, *sprev, *stmp;
char *chk;
char *service;
Bool trunc;
Bool ytrunc;
char *callid;
char *sig;
Bool force;
@ -2191,7 +2207,7 @@ main (int argc, char **argv)
cfgfile = CFGFILE;
service = NULL;
trunc = False;
ytrunc = False;
callid = NULL;
sig = NULL;
force = False;
@ -2219,7 +2235,7 @@ main (int argc, char **argv)
service = optarg;
break;
case 't':
trunc = True;
ytrunc = True;
break;
case 'c':
callid = optarg;
@ -2373,7 +2389,7 @@ main (int argc, char **argv)
fprintf (stderr, "No services found\n");
return 1;
}
if (! (mg = create_messages (cfg, service, sbase, argv + optind, argc - optind, mfile, & mcnt, callid, sig, trunc, force, delay, expire, rds)))
if (! (mg = create_messages (cfg, service, sbase, argv + optind, argc - optind, mfile, & mcnt, callid, sig, ytrunc, force, delay, expire, rds)))
return 1;
while (sbase) {
stmp = sbase;

View File

@ -401,12 +401,15 @@ Modem section
currently supported:
device <text>
The filename for the device where the modem is attached to.
The filename for the device where the modem is attached to. If
the CAPI interface should be used, the parameter must be coded
as capi/<controller>/<MSN> Note, there must not be a '/' at the
beginning, when using CAPI.
lock-prefix <text>
This is the pathname to prefix the basename of the modemdevice
to create lockfiles. This can be used to enable more than one
application to use the modem.
application to use the modem. Not used by CAPI.
lock-method <text>
This is a comma seperated list of locking mechanism. Currently
@ -420,23 +423,29 @@ Modem section
basename of the device.
+ timeout=<secs> tries to lock the device secs seconds.
Not used by CAPI.
init <text>
This is the init sequence to initialize the modem.
This is the init sequence to initialize the modem. Not used by
CAPI.
dial <text>
This is the dial sequence to dial a phone number with the
modem. An \L in the string will be replaced by the phone
number.
number. If the CAPI interface is used, this entry just defines
a possible needed prefix to dial out, e.g. '0'.
timeout <num>
This is the default timeout to wait for responses of the modem.
Not used by CAPI.
reset <text>
This is the sequence to reset the modem.
This is the sequence to reset the modem. Not used by CAPI.
local-init <text>
This is used to customize an existing modem entry for different
purpose (e.g. force a specific connect rate, etc.)
purpose (e.g. force a specific connect rate, etc.) Not used by
CAPI.
Beside this the section may contain protocol specific entries to adapt
the protocol for this service.

View File

@ -388,10 +388,15 @@ supported:
<Dl>
<Dt> device &lt;text&gt;
<Dd> The filename for the device where the modem is attached to.
If the CAPI interface should be used, the parameter <text>
must be coded as
capi/&lt;controller&gt;/&lt;MSN&gt;
Note, there must not be a '/' at the beginning, when using CAPI.
<Dt> lock-prefix &lt;text&gt;
<Dd> This is the pathname to prefix the basename of the modemdevice to
create lockfiles. This can be used to enable more than one application to
use the modem.
Not used by CAPI.
<Dt> lock-method &lt;text&gt;
<Dd> This is a comma seperated list of locking mechanism. Currently these
flags are supported:
@ -406,18 +411,25 @@ flags are supported:
<Li> <em>timeout=&lt;secs&gt;</em> tries to lock the device
<strong>secs</strong> seconds.
</Ul>
Not used by CAPI.
<Dt> init &lt;text&gt;
<Dd> This is the init sequence to initialize the modem.
Not used by CAPI.
<Dt> dial &lt;text&gt;
<Dd> This is the dial sequence to dial a phone number with the modem. An
<strong>\L</strong> in the string will be replaced by the phone number.
If the CAPI interface is used, this entry just defines a
possible needed prefix to dial out, e.g. '0'.
<Dt> timeout &lt;num&gt;
<Dd> This is the default timeout to wait for responses of the modem.
Not used by CAPI.
<Dt> reset &lt;text&gt;
<Dd> This is the sequence to reset the modem.
Not used by CAPI.
<Dt> local-init &lt;text&gt;
<Dd> This is used to customize an existing modem entry for different purpose
(e.g. force a specific connect rate, etc.)
Not used by CAPI.
</Dl>
Beside this the section may contain protocol specific entries to adapt the

View File

@ -1,6 +1,6 @@
Begin3
Title: yaps
Version: 0.96
Version: 0.96.c2
Entered-date: 14JUN97
Description: This is a standalone program to send messages to paging
devices over a modem gateway using well defined protocols.