INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) $(SIP_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 \ mISDN.cpp \ dss1.cpp \ loop.c remote.cpp \
+ 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 mISDN.cpp dss1.cpp loop.c remote.cpp \
$(GSM_SOURCE) $(SS5_SOURCE) $(SIP_SOURCE) \
- endpoint.cpp \ endpointapp.cpp \
- apppbx.cpp \ route.c \ action.cpp action_efi.cpp \ action_vbox.cpp \ extension.c \ crypt.cpp \ mail.c \
- join.cpp \ joinpbx.cpp \ joinremote.cpp
+ endpoint.cpp endpointapp.cpp \
+ appbridge.cpp apppbx.cpp route.c action.cpp action_efi.cpp action_vbox.cpp extension.c crypt.cpp mail.c \
+ join.cpp joinpbx.cpp joinremote.cpp
lcr_LDADD = $(LIBCRYPTO) -lmisdn -lpthread $(GSM_LIB) $(SIP_LIB)
--- /dev/null
+/*****************************************************************************\
+** **
+** Linux Call Router **
+** **
+**---------------------------------------------------------------------------**
+** Copyright: Andreas Eversberg **
+** **
+** The EndpointAppBridge implements direct bridge between interfaces **
+** **
+\*****************************************************************************/
+
+
+#include "main.h"
+
+class EndpointAppBridge *appbridge_first = NULL;
+
+/*
+ * EndpointAppBridge constructor
+ */
+EndpointAppBridge::EndpointAppBridge(class Endpoint *epoint, int origin) : EndpointApp(epoint, origin, EAPP_TYPE_BRIDGE)
+{
+ class EndpointAppBridge **apppointer;
+
+ /* add application to chain */
+ next = NULL;
+ apppointer = &appbridge_first;
+ while(*apppointer)
+ apppointer = &((*apppointer)->next);
+ *apppointer = this;
+
+ PDEBUG(DEBUG_EPOINT, "Bridge endpoint created\n");
+}
+
+/*
+ * EpointAppBridge destructor
+ */
+EndpointAppBridge::~EndpointAppBridge(void)
+{
+ class EndpointAppBridge *temp, **tempp;
+
+ /* detach */
+ temp =appbridge_first;
+ tempp = &appbridge_first;
+ while(temp) {
+ if (temp == this)
+ break;
+
+ tempp = &temp->next;
+ temp = temp->next;
+ }
+ if (temp == 0)
+ FATAL("Endpoint not in endpoint's list.\n");
+ *tempp = next;
+
+ PDEBUG(DEBUG_EPOINT, "Bridge endpoint destroyed\n");
+}
+
+
+/*
+ * trace header for application
+ */
+void EndpointAppBridge::trace_header(const char *name, int direction)
+{
+ struct trace _trace;
+
+ char msgtext[sizeof(_trace.name)];
+
+ SCPY(msgtext, name);
+
+ /* init trace with given values */
+ start_trace(-1,
+ NULL,
+ "", //numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international),
+ "", // e_dialinginfo.id,
+ direction,
+ CATEGORY_EP,
+ ea_endpoint->ep_serial,
+ msgtext);
+}
+
+/* hunts for the given interface
+ * it does not need to have an mISDNport instance */
+struct interface *EndpointAppBridge::hunt_interface(char *ifname)
+{
+ struct interface *interface;
+ int there_is_an_external = 0;
+
+ interface = interface_first;
+
+ /* first find the given interface or, if not given, one with no extension */
+ checknext:
+ if (!interface) {
+ if (!there_is_an_external && !(ifname && ifname[0])) {
+ trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
+ add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
+ end_trace();
+ }
+ return(NULL);
+ }
+
+ /* check for given interface */
+ if (ifname && ifname[0]) {
+ if (!strcasecmp(interface->name, ifname)) {
+ /* found explicit interface */
+ trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
+ add_trace("interface", NULL, "%s", ifname);
+ end_trace();
+ goto foundif;
+ }
+
+ } else {
+ if (interface->external) {
+ there_is_an_external = 1;
+ /* found non extension */
+ trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
+ add_trace("interface", NULL, "%s", interface->name);
+ end_trace();
+ goto foundif;
+ }
+ }
+
+ interface = interface->next;
+ goto checknext;
+foundif:
+
+ return interface;
+}
+
+
+/* port MESSAGE_SETUP */
+void EndpointAppBridge::port_setup(struct port_list *portlist, int message_type, union parameter *param)
+{
+ struct interface *interface_in = interface_first;
+ struct interface *interface_out = interface_first;
+ struct port_settings port_settings;
+ class Port *port = NULL;
+ struct lcr_msg *message;
+ unsigned int bridge_id;
+ unsigned int source_port_id = portlist->port_id;
+ char portname[64];
+
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint received setup from='%s' to='%s'\n", ea_endpoint->ep_serial, param->setup.callerinfo.id, param->setup.dialinginfo.id);
+
+ if (!ea_endpoint->ep_portlist) {
+ PERROR("Endpoint has no port in portlist\n");
+ return;
+ }
+ if (ea_endpoint->ep_portlist->next) {
+ PDEBUG(DEBUG_EPOINT, "Endpoint already received setup, ignoring.\n");
+ return;
+ }
+
+ while (interface_in) {
+ if (!strcmp(interface_in->name, param->setup.callerinfo.interface))
+ break;
+ interface_in = interface_in->next;
+ }
+ if (!interface_in) {
+fail:
+ PERROR("Cannot find source interface %s.\n", param->setup.callerinfo.interface);
+ message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
+ message->param.disconnectinfo.cause = 47;
+ message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+ message_put(message);
+
+ /* destroy endpoint */
+ ea_endpoint->ep_use = 0;
+ trigger_work(&ea_endpoint->ep_delete);
+ return;
+ }
+
+ while (interface_out) {
+ if (!strcmp(interface_out->name, interface_in->bridge_if))
+ break;
+ interface_out = interface_out->next;
+ }
+ if (!interface_out) {
+ PERROR("Cannot find destination interface %s.\n", interface_in->bridge_if);
+ goto fail;
+ return;
+ }
+
+ /* create port for interface */
+ SPRINT(portname, "%s-%d-out", interface_out->name, 0);
+ memset(&port_settings, 0, sizeof(port_settings));
+#ifdef WITH_SIP
+ if (interface_out->sip) {
+ port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface_out);
+ }
+#endif
+#ifdef WITH_GSM_BS
+ if (interface_out->gsm_bs) {
+ port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface_out);
+ }
+#endif
+#ifdef WITH_GSM_MS
+ if (interface_out->gsm_ms) {
+ port = new Pgsm_bs(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface_out);
+ }
+#endif
+ if (!port)
+ FATAL("Remote interface, but not supported???\n");
+ portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, interface_out->is_earlyb == IS_YES);
+ if (!portlist)
+ FATAL("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
+ /* forward setup */
+ message_forward(ea_endpoint->ep_serial, port->p_serial, EPOINT_TO_PORT, param);
+
+ /* apply bridge to interfaces */
+ /* FIXME: use mISDN bridge for mISDN ports */
+ bridge_id = join_serial++;
+ message = message_create(ea_endpoint->ep_serial, source_port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
+ message->param.bridge_id = bridge_id;
+ message_put(message);
+ message = message_create(ea_endpoint->ep_serial, port->p_serial, EPOINT_TO_PORT, MESSAGE_BRIDGE);
+ message->param.bridge_id = bridge_id;
+ message_put(message);
+}
+
+/* port MESSAGE_RELEASE */
+void EndpointAppBridge::port_release(struct port_list *portlist, int message_type, union parameter *param)
+{
+ unsigned int remote;
+
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint received release from port\n");
+
+ if (!ea_endpoint->ep_portlist || !ea_endpoint->ep_portlist->next)
+ goto out;
+ if (ea_endpoint->ep_portlist->port_id == portlist->port_id)
+ remote = ea_endpoint->ep_portlist->next->port_id;
+ else
+ remote = ea_endpoint->ep_portlist->port_id;
+ /* forward release */
+ message_forward(ea_endpoint->ep_serial, remote, EPOINT_TO_PORT, param);
+
+out:
+ /* destroy endpoint */
+ ea_endpoint->ep_use = 0;
+ trigger_work(&ea_endpoint->ep_delete);
+}
+
+/* port other messages */
+void EndpointAppBridge::port_other(struct port_list *portlist, int message_type, union parameter *param)
+{
+ unsigned int remote;
+
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint received message %d from port\n", message_type);
+
+ if (!ea_endpoint->ep_portlist || !ea_endpoint->ep_portlist->next)
+ return;
+ if (ea_endpoint->ep_portlist->port_id == portlist->port_id)
+ remote = ea_endpoint->ep_portlist->next->port_id;
+ else
+ remote = ea_endpoint->ep_portlist->port_id;
+ /* forward release */
+ message_forward(ea_endpoint->ep_serial, remote, EPOINT_TO_PORT, param);
+}
+
+/* port sends message to the endpoint
+ */
+void EndpointAppBridge::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
+{
+ struct port_list *portlist;
+
+ portlist = ea_endpoint->ep_portlist;
+ while(portlist) {
+ if (port_id == portlist->port_id)
+ break;
+ portlist = portlist->next;
+ }
+ if (!portlist) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) warning: port is not related to this endpoint. This may happen, if port has been released after the message was created.\n", ea_endpoint->ep_serial);
+ return;
+ }
+
+// PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
+ switch(message_type) {
+ /* PORT sends SETUP message */
+ case MESSAGE_SETUP:
+ port_setup(portlist, message_type, param);
+ break;
+
+ /* PORT sends RELEASE message */
+ case MESSAGE_RELEASE:
+ port_release(portlist, message_type, param);
+ break;
+
+ default:
+ port_other(portlist, message_type, param);
+ }
+
+ /* Note: this endpoint may be destroyed, so we MUST return */
+}
+
--- /dev/null
+/*****************************************************************************\
+** **
+** Linux Call Router **
+** **
+**---------------------------------------------------------------------------**
+** Copyright: Andreas Eversberg **
+** **
+** EndpointAppBridge header file **
+** **
+\*****************************************************************************/
+
+
+extern class EndpointAppBridge *appbridge_first;
+
+/* structure of an EndpointAppBridge */
+class EndpointAppBridge : public EndpointApp
+{
+ public:
+ EndpointAppBridge(class Endpoint *epoint, int origin);
+ ~EndpointAppBridge();
+
+ class EndpointAppBridge *next; /* next in list of apps */
+
+ /* messages */
+ void port_setup(struct port_list *portlist, int message_type, union parameter *param);
+ void port_release(struct port_list *portlist, int message_type, union parameter *param);
+ void port_other(struct port_list *portlist, int message_type, union parameter *param);
+ void ea_message_port(unsigned int port_id, int message, union parameter *param);
+ struct interface *hunt_interface(char *ifname);
+
+ void trace_header(const char *name, int direction);
+};
+
+
+
/*
* EndpointAppPBX constructor
*/
-EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp(epoint, origin)
+EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp(epoint, origin, EAPP_TYPE_PBX)
{
class EndpointAppPBX **apppointer;
FATAL("Incoming call but already got an endpoint.\n");
if (!(epoint = new Endpoint(p_serial, 0)))
FATAL("No memory for Endpoint instance\n");
- if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
- FATAL("No memory for Endpoint Application instance\n");
+ epoint->ep_app = new_endpointapp(epoint, 0, p_m_mISDNport->ifport->interface->app); //incoming
epointlist_new(epoint->ep_serial);
/* send setup message to endpoit */
unsigned int ep_serial; /* a unique serial to identify */
/* applocaton relation */
+ int ep_app_type;
class EndpointApp *ep_app; /* link to application class */
/* port relation */
/*
* EndpointApp constructor
*/
-EndpointApp::EndpointApp(class Endpoint *epoint, int origin)
+EndpointApp::EndpointApp(class Endpoint *epoint, int origin, int type)
{
ea_endpoint = epoint;
+ ea_type = type;
classuse++;
}
PDEBUG(DEBUG_EPOINT, "%s: Spare function.\n", __FUNCTION__);
}
+
+/* create endpoint app */
+class EndpointApp *new_endpointapp(class Endpoint *epoint, int origin, int type)
+{
+ class EndpointApp *app = NULL;
+
+ switch (type) {
+ case EAPP_TYPE_PBX:
+ app = new EndpointAppPBX(epoint, origin);
+ break;
+ case EAPP_TYPE_BRIDGE:
+ app = new EndpointAppBridge(epoint, origin);
+ break;
+ }
+
+ if (!app)
+ FATAL("Failed to create endpoint APP (type %d)\n", type);
+
+ epoint->ep_app_type = type;
+ epoint->ep_app = app;
+
+ return app;
+}
** **
\*****************************************************************************/
+#define EAPP_TYPE_PBX 0
+#define EAPP_TYPE_BRIDGE 1
/* structure of an EndpointApp */
class EndpointApp
{
public:
- EndpointApp(class Endpoint *epoint, int origin);
+ EndpointApp(class Endpoint *epoint, int origin, int type);
virtual ~EndpointApp();
+ int ea_type;
class Endpoint *ea_endpoint;
virtual void ea_message_port(unsigned int port_id, int message, union parameter *param);
virtual void ea_message_join(unsigned int join_id, int message, union parameter *param);
};
+class EndpointApp *new_endpointapp(class Endpoint *epoint, int origin, int type);
+
class Endpoint *epoint;
struct lcr_msg *message;
struct gsm_mncc *mode, *proceeding, *frame;
+ struct interface *interface = interface_first;
+
+ while (interface) {
+ if (!strcmp(interface->name, p_g_interface_name))
+ break;
+ interface = interface->next;
+ }
+ if (!interface) {
+ PERROR("Cannot find interface %s.\n", p_g_interface_name);
+ return;
+ }
/* process given callref */
gsm_trace_header(p_g_interface_name, this, 0, DIRECTION_IN);
FATAL("Incoming call but already got an endpoint.\n");
if (!(epoint = new Endpoint(p_serial, 0)))
FATAL("No memory for Endpoint instance\n");
- if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
- FATAL("No memory for Endpoint Application instance\n");
+ epoint->ep_app = new_endpointapp(epoint, 0, interface->app); //incoming
epointlist_new(epoint->ep_serial);
/* modify lchan to GSM codec V1 */
class Endpoint *epoint;
struct lcr_msg *message;
struct gsm_mncc *mode, *proceeding, *frame;
+ struct interface *interface = interface_first;
+
+ while (interface) {
+ if (!strcmp(interface->name, p_g_interface_name))
+ break;
+ interface = interface->next;
+ }
+ if (!interface) {
+ PERROR("Cannot find interface %s.\n", p_g_interface_name);
+ return;
+ }
/* process given callref */
gsm_trace_header(p_g_interface_name, this, 0, DIRECTION_IN);
FATAL("Incoming call but already got an endpoint.\n");
if (!(epoint = new Endpoint(p_serial, 0)))
FATAL("No memory for Endpoint instance\n");
- if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
- FATAL("No memory for Endpoint Application instance\n");
+ epoint->ep_app = new_endpointapp(epoint, 0, interface->app); //incoming
epointlist_new(epoint->ep_serial);
/* modify lchan to GSM codec V1 */
ifport->remote = 1;
SCPY(ifport->remote_app, value);
-
return(0);
}
-
static int inter_shutdown(struct interface *interface, char *filename, int line, char *parameter, char *value)
{
interface->shutdown = 1;
return(0);
}
+static int inter_bridge(struct interface *interface, char *filename, int line, char *parameter, char *value)
+{
+ if (!value || !value[0]) {
+ SPRINT(interface_error, "Error in %s (line %d): Missing destination interface name.\n", filename, line);
+ return(-1);
+ }
+ interface->app = EAPP_TYPE_BRIDGE;
+ SCPY(interface->bridge_if, value);
+
+ return(0);
+}
/*
"Prevents sending notify messages to this interface. A call placed on hold will\n"
"Not affect the remote end (phone or telcom switch).\n"
"This parameter must follow a 'port' parameter."},
+ {"bridge", &inter_bridge, "<destination interface>",
+ "Define bridge application for this interface. All calls received on this\n"
+ "interface will be directly bridged to the given destination interface.\n"
+ "There will be no PBX application, nor routing."},
#ifdef WITH_SS5
{"ccitt5", &inter_ss5, "[<feature> [feature ...]]",
struct interface {
struct interface *next;
char name[64]; /* name of interface */
+ int app; /* application to use for interface (0 = PBX) */
+ char bridge_if[64]; /* name of destination interface for bridge application */
int external; /* interface used for external calls */
int extension; /* calls are handled as extension */
int is_tones; /* generate tones */
class Join *find_join_id(unsigned int join_id);
+extern unsigned int join_serial;
+
epoint = new Endpoint(0, j_serial);
if (!epoint)
FATAL("No memory for Endpoint instance\n");
- if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 1))) // outgoing
- FATAL("No memory for Endpoint Application instance\n");
+ epoint->ep_app = new_endpointapp(epoint, 1, EAPP_TYPE_PBX); // outgoing
relation->epoint_id = epoint->ep_serial;
/* send setup message to new endpoint */
//printf("JOLLY DEBUG: %d\n",join_countrelations(j_serial));
FATAL("No memory for Endpoint instance\n");
j_epoint_id = epoint->ep_serial;
PDEBUG(DEBUG_JOIN, "Created endpoint %d\n", j_epoint_id);
- if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 1))) // outgoing
- FATAL("No memory for Endpoint Application instance\n");
+ epoint->ep_app = new_endpointapp(epoint, 1, EAPP_TYPE_PBX); // outgoing
}
/* set serial on bchannel message
#define NAME "LCR"
-#define DEFAULT_ENDPOINT_APP EndpointAppPBX
-
#define VERSION_STRING VERSION
extern int memuse;
#include "endpoint.h"
#include "endpointapp.h"
#include "apppbx.h"
+#include "appbridge.h"
#include "callerid.h"
#include "route.h"
#include "port.h"
if (!remote)
return -EINVAL;
-// printf("Traffic: %u -> %u (bridge %u)\n", p_serial, to_port->p_serial, p_bridge->bridge_id);
+// printf("Traffic: %u -> %u (bridge %u)\n", p_serial, remote->p_serial, p_bridge->bridge_id);
return remote->bridge_rx(data, len);
}
FATAL("Incoming call but already got an endpoint.\n");
if (!(epoint = new Endpoint(p_serial, 0)))
FATAL("No memory for Endpoint instance\n");
- if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
- FATAL("No memory for Endpoint Application instance\n");
+ epoint->ep_app = new_endpointapp(epoint, 0, p_m_mISDNport->ifport->interface->app); //incoming
epointlist_new(epoint->ep_serial);
}
PDEBUG(DEBUG_SIP, "remote ip %08x port %d\n", p_s_rtp_ip_remote, p_s_rtp_port_remote);
} else {
PDEBUG(DEBUG_SIP, "RTP info not given by remote, so we do our own RTP\n");
+ p_s_rtp_bridge = 0;
p_s_rtp_payload_type = (options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW;
/* open local RTP peer (if not bridging) */
class Endpoint *epoint;
struct lcr_msg *message;
uint8_t payload_type;
+ struct interface *interface = interface_first;
+
+ while (interface) {
+ if (!strcmp(interface->name, inst->interface_name))
+ break;
+ interface = interface->next;
+ }
+ if (!interface) {
+ PERROR("Cannot find interface %s.\n", inst->interface_name);
+ return;
+ }
if (sip->sip_from && sip->sip_from->a_url)
from = sip->sip_from->a_url->url_user;
FATAL("Incoming call but already got an endpoint.\n");
if (!(epoint = new Endpoint(p_serial, 0)))
FATAL("No memory for Endpoint instance\n");
- if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
- FATAL("No memory for Endpoint Application instance\n");
+ epoint->ep_app = new_endpointapp(epoint, 0, interface->app); //incoming
epointlist_new(epoint->ep_serial);
/* send trying (proceeding) */
if (!(epoint = new Endpoint(0, 0)))
FATAL("No memory for Endpoint instance\n");
- if (!(epoint->ep_app = apppbx = new DEFAULT_ENDPOINT_APP(epoint, 1))) // outgoing
+ if (!(epoint->ep_app = apppbx = new EndpointAppPBX(epoint, 1))) // outgoing
FATAL("No memory for Endpoint Application instance\n");
apppbx->e_adminid = admin->sockserial;
admin->epointid = epoint->ep_serial;
/*release endpoint if exists */
if (admin->epointid) {
epoint = find_epoint_id(admin->epointid);
- if (epoint) {
- ((class DEFAULT_ENDPOINT_APP *)epoint->ep_app)->
+ if (epoint && epoint->ep_app_type == EAPP_TYPE_PBX) {
+ ((class EndpointAppPBX *)epoint->ep_app)->
release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
}
}
FATAL("Incoming call but already got an endpoint.\n");
if (!(epoint = new Endpoint(p_serial, 0)))
FATAL("No memory for Endpoint instance\n");
- if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
- FATAL("No memory for Endpoint Application instance\n");
+ epoint->ep_app = new_endpointapp(epoint, 0, p_m_mISDNport->ifport->interface->app); //incoming
epointlist_new(epoint->ep_serial);
/* send setup message to endpoit */
case MESSAGE_SETUP: /* dial-out command received from epoint, answer with connect */
/* get apppbx */
- memcpy(&p_vbox_ext, &((class EndpointAppPBX *)(epoint->ep_app))->e_ext, sizeof(p_vbox_ext));
+ if (epoint->ep_app_type == EAPP_TYPE_PBX)
+ memcpy(&p_vbox_ext, &((class EndpointAppPBX *)(epoint->ep_app))->e_ext, sizeof(p_vbox_ext));
/* extract optional announcement file */
if ((c = strchr(param->setup.dialinginfo.id, ','))) {
if (c[1] == '/')