endif
+VOOTP_LIB =
+
+if ENABLE_VOOTP
+
+VOOTP_INCLUDE = -DWITH_VOOTP $(VOOTP_CFLAGS)
+
+VOOTP_SOURCE =
+
+VOOTP_LIB += $(VOOTP_LIBS)
+
+endif
+
bin_PROGRAMS = lcradmin gentones genwave
sbin_PROGRAMS = lcr genrc genextension
cd '$(DESTDIR)$(astmoddir)' && rm -f chan_lcr.so
endif
-AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include $(MISDN_INCLUDE) $(GSM_INCLUDE) $(SS5_INCLUDE) $(SIP_INCLUDE) -Wall $(INSTALLATION_DEFINES)
+AM_CPPFLAGS = $(all_includes) $(MISDN_INCLUDE) $(GSM_INCLUDE) $(SS5_INCLUDE) $(SIP_INCLUDE) $(VOOTP_INCLUDE) -Wall $(INSTALLATION_DEFINES)
lcr_SOURCES = \
main.c select.c trace.c options.c tones.c alawulaw.c cause.c interface.c message.c callerid.c socket_server.c \
port.cpp vbox.cpp remote.cpp \
- $(MISDN_SOURCE) $(GSM_SOURCE) $(SS5_SOURCE) $(SIP_SOURCE) \
+ $(MISDN_SOURCE) $(GSM_SOURCE) $(SS5_SOURCE) $(SIP_SOURCE) $(VOOTP_SOURCE) \
endpoint.cpp endpointapp.cpp \
appbridge.cpp apppbx.cpp route.c action.cpp action_efi.cpp action_vbox.cpp extension.c mail.c \
join.cpp joinpbx.cpp
-lcr_LDADD = $(LIBCRYPTO) $(MISDN_LIB) -lpthread $(GSM_LIB) $(SIP_LIB)
+lcr_LDADD = $(LIBCRYPTO) $(MISDN_LIB) -lpthread $(GSM_LIB) $(SIP_LIB) $(VOOTP_LIB)
lcradmin_SOURCES = lcradmin.c cause.c options.c
join_join_dss1();
break;
+ /* VOOTP on */
+ case '1':
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) enable VoOTP.\n", ea_endpoint->ep_serial);
+ vootp_on(1);
+ break;
+
+ /* VOOTP off */
+ case '2':
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) disable VoOTP.\n", ea_endpoint->ep_serial);
+ vootp_on(0);
+ break;
+
#ifdef WITH_CRYPT
/* crypt shared */
case '7':
encrypt_off();
break;
#endif
-
default:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit);
}
}
+/* port MESSAGE_UPDATEBRIDGE */
+void EndpointAppPBX::port_updatebridge(struct port_list *portlist, int message_type, union parameter *param)
+{
+ struct lcr_msg *message;
+
+ message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_UPDATEBRIDGE);
+ message_put(message);
+}
+
+
+/* port MESSAGE_VOOTP */
+void EndpointAppPBX::port_vootp(struct port_list *portlist, int message_type, union parameter *param)
+{
+ if (param->vootp.failed)
+ set_tone(ea_endpoint->ep_portlist, "crypt_off");
+}
+
+
/* port sends message to the endpoint
*/
void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
port_disable_dejitter(portlist, message_type, param);
break;
+ case MESSAGE_UPDATEBRIDGE:
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming updatebridge message (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
+ port_updatebridge(portlist, message_type, param);
+ break;
+
+ case MESSAGE_VOOTP:
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming vootp message (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
+ port_vootp(portlist, message_type, param);
+ break;
+
default:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received a wrong message: %d\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, message_type);
return(0);
}
+int EndpointAppPBX::vootp_on(int on)
+{
+#ifndef WITH_VOOTP
+ set_tone(ea_endpoint->ep_portlist, "crypt_off");
+#else
+ if (!e_ext.otp_ident[0]) {
+ set_tone(ea_endpoint->ep_portlist, "crypt_off");
+ return -EINVAL;
+ }
+ if(ea_endpoint->ep_portlist) {
+ struct lcr_msg *message;
+
+ message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_VOOTP);
+ message->param.vootp.enable = on;
+ SCPY(message->param.vootp.id, e_ext.otp_ident);
+ message_put(message);
+ }
+ if (!on)
+ set_tone(ea_endpoint->ep_portlist, "crypt_off");
+#endif
+
+ return 0;
+}
+
void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
{
const char *logtext = "unknown";
void port_resume(struct port_list *portlist, int message_type, union parameter *param);
void port_enablekeypad(struct port_list *portlist, int message_type, union parameter *param);
void port_disable_dejitter(struct port_list *portlist, int message_type, union parameter *param);
+ void port_updatebridge(struct port_list *portlist, int message_type, union parameter *param);
+ void port_vootp(struct port_list *portlist, int message_type, union parameter *param);
void ea_message_join(unsigned int join_id, int message, union parameter *param);
void join_crypt(struct port_list *portlist, int message_type, union parameter *param);
void join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param);
void cryptman_msg2crengine(int msg, unsigned char *buf, int len);
void cryptman_state(int state);
void cryptman_timeout(int secs);
+ int vootp_on(int enable);
+
void message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display);
void logmessage(int message_type, union parameter *param, unsigned int port_id, int dir);
void trace_header(const char *name, int direction);
PKG_CHECK_MODULES(SOFIA, sofia-sip-ua >= 1.12)
])
+# check for VoOTP
+AC_ARG_WITH([vootp],
+ [AS_HELP_STRING([--with-vootp],
+ [compile with VoOTP support (libvootp is required) @<:@default=no@:>@])
+ ],
+ [],
+ [with_vootp="check"])
+
+AM_CONDITIONAL(ENABLE_VOOTP, test "x$with_vootp" == "xyes" )
+
+AS_IF([test "x$with_vootp" == xyes -o "x$with_vootp" == xyes], [
+ PKG_CHECK_MODULES(VOOTP, libvootp >= 0.0)
+ ])
+
# Checks for libraries.
AC_CHECK_LIB([m], [main])
AC_CHECK_LIB([ncurses], [main])
AS_IF([test "x$with_asterisk" == xyes],[AC_MSG_NOTICE( Compiled with Asterisk channel driver support )],[AC_MSG_NOTICE( Not compiled with Asterisk channel driver support)])
AS_IF([test "x$with_ss5" == xyes],[AC_MSG_NOTICE( Compiled with CCITT No.5 support )],[AC_MSG_NOTICE( Not compiled with CCITT No.5 support)])
AS_IF([test "x$with_sip" == xyes],[AC_MSG_NOTICE( Compiled with SIP support )],[AC_MSG_NOTICE( Not compiled with SIP support)])
+AS_IF([test "x$with_vootp" == xyes],[AC_MSG_NOTICE( Compiled with VoOTP support )],[AC_MSG_NOTICE( Not compiled with VoOTP support)])
# This feature is temporarily for test purpose. Don't enable it
#polling
+# Define OTP directory and identity
+#otp-dir /root/
+#otp-ident myname
+
/* screen outgoing caller id */
do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_m_mISDNport->ifport->interface->name);
- /* only display at connect state */
- if (p_state == PORT_STATE_CONNECT)
- if (p_connectinfo.display[0]) {
- /* sending information */
- l3m = create_l3msg();
- l1l2l3_trace_header(p_m_mISDNport, this, L3_INFORMATION_REQ, DIRECTION_OUT);
- if (p_m_d_ntmode || p_m_d_tespecial)
- enc_ie_display(l3m, (unsigned char *)p_connectinfo.display);
- end_trace();
- p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_INFORMATION, p_m_d_l3id, l3m);
- return;
- }
+ set_display(p_connectinfo.display);
if (p_state!=PORT_STATE_IN_SETUP && p_state!=PORT_STATE_IN_OVERLAP && p_state!=PORT_STATE_IN_PROCEEDING && p_state!=PORT_STATE_IN_ALERTING) {
/* connect command only possible in setup, proceeding or alerting state */
return(0);
}
+void Pdss1::set_display(const char *text)
+{
+ l3_msg *l3m;
+
+ /* only display at connect state */
+ if (p_state == PORT_STATE_CONNECT)
+ if (text[0]) {
+ /* sending information */
+ l3m = create_l3msg();
+ l1l2l3_trace_header(p_m_mISDNport, this, L3_INFORMATION_REQ, DIRECTION_OUT);
+ if (p_m_d_ntmode || p_m_d_tespecial)
+ enc_ie_display(l3m, (unsigned char *)text);
+ end_trace();
+ p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_INFORMATION, p_m_d_l3id, l3m);
+ return;
+ }
+}
void message_isdn(unsigned int cmd, unsigned int pid, struct l3_msg *l3m);
int p_m_d_ces; /* ntmode: tei&sapi */
int message_epoint(unsigned int epoint_id, int message, union parameter *param);
+ void set_display(const char *text);
int p_m_d_ntmode; /* flags the nt-mode */
int p_m_d_tespecial; /* special te-mode with all nt-mode IEs */
} else {
PDEBUG(DEBUG_CONFIG, "unknown param for seconds: %s\n", param);
}
+ } else
+ if (!strcmp(option,"otp-ident")) {
+ SCPY(ext->otp_ident, param);
+ PDEBUG(DEBUG_CONFIG, "otp-ident: %s\n",param);
} else {
PERROR_RUNTIME("Error in %s (line %d): wrong option keyword %s.\n",filename,line,option);
}
fprintf(fp,"# Include seconds (time) in the connect message. (Should be always enabled.)\n");
fprintf(fp,"seconds %s\n\n",ext_yesno[1-ext->no_seconds]);
+ fprintf(fp,"# Identity string for VoOTP encryption\n");
+ fprintf(fp,"otp-ident %s\n\n", ext->otp_ident);
+
fprintf(fp,"# Last outgoing and incoming numbers (including prefix)\n");
i = 0;
while(i < MAX_REMEMBER) {
int facility; /* must be set to forward facility to terminal */
int datacall; /* data calls are handled as voice calls */
int no_seconds; /* don't include seconds in the connect message */
+
+ char otp_ident[9]; /* up to 8 bytes of ident */
};
int read_extension(struct extension *ext, char *number);
/* send traffic to gsm */
int Pgsm::bridge_rx(unsigned char *data, int len)
{
+ int ret;
+
+ if ((ret = Port::bridge_rx(data, len)))
+ return ret;
+
if (p_tone_name[0])
return -EINVAL;
relation = relation->next;
continue;
}
+#ifdef WITH_VOOTP
+ if (port->p_vootp) {
+ PDEBUG(DEBUG_JOIN, "join%d ignoring relation ep%d because it's port uses VoOTP.\n", j_serial, epoint->ep_serial);
+ if (allmISDN) {
+ PDEBUG(DEBUG_JOIN, "join%d not all endpoints can support mISDN bridging.\n", j_serial);
+ allmISDN = 0;
+ }
+ relation = relation->next;
+ continue;
+ }
+#endif
relation = relation->next;
}
relation = relation->next;
continue;
}
+#ifdef WITH_VOOTP
+ if (port->p_vootp) {
+ PDEBUG(DEBUG_JOIN, "join%d ignoring relation ep%d because it's port uses VoOTP.\n", joinpbx_3pty->j_serial, epoint->ep_serial);
+ if (allmISDN) {
+ PDEBUG(DEBUG_JOIN, "join%d not all endpoints can support mISDN bridging.\n", joinpbx_3pty->j_serial);
+ allmISDN = 0;
+ }
+ relation = relation->next;
+ continue;
+ }
+#endif
relation = relation->next;
}
}
return;
+ case MESSAGE_UPDATEBRIDGE:
+ trigger_work(&j_updatebridge);
+ joinpbx_debug(this, "Join::message_epoint{bridge is updated due to request from mISDN port}");
+ break;
+
/* track notify */
case MESSAGE_NOTIFY:
switch(param->notifyinfo.notify) {
}
+/* MESSAGE_VOOTP */
+void PmISDN::message_vootp(unsigned int epoint_id, int message_id, union parameter *param)
+{
+ struct lcr_msg *message;
+
+ message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_UPDATEBRIDGE);
+ message_put(message);
+
+#if 0
+does not make sense, since remote port may dejitter
+ if (param->vootp.enable) {
+ PDEBUG(DEBUG_ISDN, "PmISDN(%s) received vootp enable order, so we disable de-jitter.\n", p_name);
+ p_m_disable_dejitter = 1;
+ }
+#endif
+ update_rxoff();
+}
+
/*
* endpoint sends messages to the port
*/
int PmISDN::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
{
+ /* messages also handled by base class */
+ switch(message_id) {
+ case MESSAGE_VOOTP: /* crypt control command */
+ PDEBUG(DEBUG_ISDN, "PmISDN(%s) received VoOTP encryption\n", p_name);
+ message_vootp(epoint_id, message_id, param);
+ break;
+ }
+
if (Port::message_epoint(epoint_id, message_id, param)) {
if (message_id == MESSAGE_BRIDGE)
update_rxoff();
return 1;
}
+ /* messages not handled by base class */
switch(message_id) {
case MESSAGE_mISDNSIGNAL: /* user command */
PDEBUG(DEBUG_ISDN, "PmISDN(%s) received special ISDN SIGNAL %d.\n", p_name, param->mISDNsignal.message);
struct mISDNhead *hh = (struct mISDNhead *)buf;
int ret;
+ if ((ret = Port::bridge_rx(data, length)))
+ return ret;
+
if (p_m_b_index < 0)
return -EIO;
if (p_m_mISDNport->b_state[p_m_b_index] != B_STATE_ACTIVE)
int message_epoint(unsigned int epoint_id, int message, union parameter *param);
void message_mISDNsignal(unsigned int epoint_id, int message_id, union parameter *param);
void message_crypt(unsigned int epoint_id, int message_id, union parameter *param);
+ void message_vootp(unsigned int epoint_id, int message_id, union parameter *param);
struct mISDNport *p_m_mISDNport; /* pointer to port */
int p_m_delay; /* use delay instead of dejitter */
int p_m_tx_dejitter; /* use dejitter on transmit data to DSP */
crc_init();
#endif
+#ifdef WITH_VOOTP
+ /* init VoOTP */
+ vootp_init(stderr);
+ vootp_loglevel(VOOTP_LOGL_INFO);
+#endif
+
/* the mutex init */
if (pthread_mutex_init(&mutexd, NULL)) {
fprintf(stderr, "cannot create 'PDEBUG' mutex\n");
#include <stdio.h>
#include <stdlib.h>
+#include <stdint.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include "appbridge.h"
#include "callerid.h"
#include "route.h"
+#ifdef WITH_VOOTP
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+#include <vootp.h>
+ #ifdef __cplusplus
+ }
+ #endif
+#endif
#include "port.h"
#include "remote.h"
#ifdef WITH_MISDN
unsigned char invoke_id;
};
+struct param_vootp {
+ int enable;
+ int failed;
+ char id[32];
+};
+
/* structure of message parameter */
union parameter {
struct param_tone tone; /* MESSAGE_TONE */
struct param_traffic traffic; /* MESSAGE_TRAFFIC */
struct param_3pty threepty; /* MESSAGE_TRAFFIC */
unsigned int queue; /* MESSAGE_DISABLE_DEJITTER */
+ struct param_vootp vootp; /* MESSAGE_VOOTP */
};
enum { /* message flow */
MESSAGE_TRAFFIC, /* exchange bchannel traffic */
MESSAGE_3PTY, /* 3PTY call invoke */
MESSAGE_TRANSFER, /* call transfer invoke */
- MESSAGE_DISABLE_DEJITTER/* tell (mISDN) port not to dejitter */
+ MESSAGE_DISABLE_DEJITTER,/* tell (mISDN) port not to dejitter */
+ MESSAGE_UPDATEBRIDGE, /* tell join to update bridge. (sent by mISDN port) */
+ MESSAGE_VOOTP, /* enable/disable VoOTP */
};
#define MESSAGES static const char *messages_txt[] = { \
"MESSAGE_3PTY", \
"MESSAGE_TRANSFER", \
"MESSAGE_DISABLE_DEJITTER", \
+ "MESSAGE_UPDATEBRIDGE", \
+ "MESSAGE_VOOTP", \
};
0700, /* rights of lcr admin socket */
-1, /* socket user (-1= no change) */
-1, /* socket group (-1= no change) */
- 1, /* use polling of main loop */
+ 0, /* use polling of main loop */
+ "/root", /* OTP directory */
};
char options_error[256];
} else
if (!strcmp(option,"polling")) {
options.polling = 1;
+ } else
+ if (!strcmp(option,"otp-dir")) {
+ if (param[0]==0) {
+ UPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n", filename,line,option);
+ goto error;
+ }
+ SCPY(options.otp_dir, param);
} else {
UPRINT(options_error, "Error in %s (line %d): wrong option keyword %s.\n", filename,line,option);
goto error;
int socketuser; /* socket chown to this user */
int socketgroup; /* socket chgrp to this group */
int polling;
+ char otp_dir[256]; /* directory of OTP files */
};
extern struct options options;
p_record_buffer_writep = 0;
p_record_buffer_dir = 0;
+ /* VoOTP */
+#ifdef WITH_VOOTP
+ p_vootp = NULL;
+#endif
+
/* append port to chain */
next = NULL;
temp = port_first;
PDEBUG(DEBUG_PORT, "removing port (%d) of type 0x%x, name '%s' interface '%s'\n", p_serial, p_type, p_name, p_interface_name);
+#ifdef WITH_VOOTP
+ if (p_vootp) {
+ vootp_destroy(p_vootp);
+ p_vootp = NULL;
+ }
+#endif
+
if (p_bridge) {
PDEBUG(DEBUG_PORT, "Removing us from bridge %u\n", p_bridge->bridge_id);
remove_bridge(p_bridge, this);
}
+void Port::set_display(const char *text)
+{
+}
+
/*
* set the file in the tone directory for vbox playback
* also set the play_eof-flag
PDEBUG(DEBUG_PORT, "PORT(%s) bridging to id %d\n", p_name, param->bridge_id);
bridge(param->bridge_id);
return 1;
+
+#ifdef WITH_VOOTP
+ case MESSAGE_VOOTP: /* enable / disable VoOTP */
+ PDEBUG(DEBUG_PORT, "PORT(%s) VoOTP enabled: %d\n", p_name, param->vootp.enable);
+ set_vootp(¶m->vootp);
+ return 1;
+#endif
}
return 0;
signed long *sum;
unsigned char *buf;
+#ifdef WITH_VOOTP
+ if (p_vootp)
+ vootp_encrypt_stream(p_vootp, data, len);
+#endif
+
/* less than two ports, so drop */
if (!p_bridge || !p_bridge->first || !p_bridge->first->next)
return -EIO;
}
-/* receive data from remote Port (dummy, needs to be inherited) */
+/* receive data from remote Port */
int Port::bridge_rx(unsigned char *data, int len)
{
- return 0; /* datenklo */
+
+#ifdef WITH_VOOTP
+ if (p_vootp)
+ vootp_decrypt_stream(p_vootp, data, len);
+#endif
+
+ return 0;
+}
+
+#ifdef WITH_VOOTP
+static void vootp_info(void *priv, const char *text)
+{
+ class Port *port = (class Port *)priv;
+ char display[strlen(text) + 1];
+
+ SCPY(display, text);
+ if (display[0])
+ display[strlen(display) - 1] = '\0';
+
+ port->set_display(display);
}
+void Port::set_vootp(struct param_vootp *vootp)
+{
+ if (p_vootp) {
+ vootp_destroy(p_vootp);
+ p_vootp = NULL;
+ }
+ if (vootp->enable) {
+ p_vootp = vootp_create(this, (options.law=='a'), options.otp_dir, NULL, NULL, vootp->id, vootp_info);
+// vootp_loglevel(VOOTP_LOGL_DEBUG);
+ if (!p_vootp) {
+ struct lcr_msg *message;
+
+ message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_VOOTP);
+ message->param.vootp.failed = 1;
+ message_put(message);
+ }
+ }
+}
+#endif
virtual void set_tone(const char *dir, const char *name);
virtual int read_audio(unsigned char *buffer, int length);
virtual void update_load(void);
+ virtual void set_display(const char *text);
struct port_settings p_settings;
char p_interface_name[64];
int p_record_vbox_email_file;
virtual void update_rxoff(void); /* inherited by mISDNport, to control rxoff */
+#ifdef WITH_VOOTP
+ vootp_t *p_vootp; /* VoOTP instance */
+ void set_vootp(struct param_vootp *vootp);
+#endif
+
void free_epointlist(struct epoint_list *epointlist);
void free_epointid(unsigned int epoint_id);
struct epoint_list *epointlist_new(unsigned int epoint_id);
{
union parameter newparam;
int l;
+ int ret;
+
+ if ((ret = Port::bridge_rx(data, len)))
+ return ret;
/* send tones, if connected, or if early audio is enabled in proceeding/alerting state */
if (p_state != PORT_STATE_CONNECT
/* receive from remote */
int Psip::bridge_rx(unsigned char *data, int len)
{
+ int ret;
+
/* don't bridge, if tones are provided */
if (p_tone_name[0])
return -EBUSY;
+ if ((ret = Port::bridge_rx(data, len)))
+ return ret;
+
/* write to rx buffer */
while(len--) {
p_s_rxdata[p_s_rxpos++] = flip[*data++];
int VBoxPort::bridge_rx(unsigned char *data, int len)
{
+ int ret;
+
+ if ((ret = Port::bridge_rx(data, len)))
+ return ret;
+
if (p_record)
record(data, len, 1); // from up
return 0;