From df6009a9aff1e28f00e641e743ea029c0d64bcdc Mon Sep 17 00:00:00 2001 From: MelwareDE Date: Tue, 16 Aug 2005 18:25:03 +0000 Subject: [PATCH] Moved 'hold' and 'retrieve' to capicommand(). --- Makefile | 2 +- README | 22 +++++--- app_capiHOLD.c | 133 -------------------------------------------- app_capiRETRIEVE.c | 136 --------------------------------------------- chan_capi.c | 120 ++++++++++++++++++++++++++++++++------- chan_capi_pvt.h | 5 +- 6 files changed, 116 insertions(+), 302 deletions(-) delete mode 100644 app_capiHOLD.c delete mode 100644 app_capiRETRIEVE.c diff --git a/Makefile b/Makefile index eeb6c62..d2f4737 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ LIBS=-ldl -lpthread -lm CC=gcc INSTALL=install -SHAREDOS=chan_capi.so app_capiHOLD.so app_capiRETRIEVE.so app_capiECT.so +SHAREDOS=chan_capi.so app_capiECT.so CFLAGS+=-Wno-missing-prototypes -Wno-missing-declarations diff --git a/README b/README index c508e2b..21c9c57 100644 --- a/README +++ b/README @@ -120,23 +120,27 @@ Malicious Call Identification: Example: exten => s,1,capicommand(malicious) +Hold: + Puts an answered call on hold, this has nothing to do with asterisk's onhold + thingie (music et al). + After putting a call onhold, never use the Wait application! + Example: + exten => s,1,capicommand(hold) + +Retrieve: + Gets back the holded call + Example: + exten => s,1,capicommand(retrieve) + Helper applications =================== -app_capiHOLD.c - Puts an answered call on hold, this has nothing to do with asterisk's onhold - thingie (music et al) - After putting a call onhold, never use the Wait application! - -app_capiRETRIEVE.c - Gets the holded call back - app_capiECT.c Explicit call transfer of the call on hold (must put call on hold first!) Example: exten => s,1,Answer - exten => s,2,capiHOLD + exten => s,2,capicommand(hold) exten => s,3,capiECT,55:50 Will ECT the call to 50 using 55 as the callerid/outgoing MSN diff --git a/app_capiHOLD.c b/app_capiHOLD.c deleted file mode 100644 index 31ea06b..0000000 --- a/app_capiHOLD.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * (CAPI*) - * - * An implementation of Common ISDN API 2.0 for Asterisk - * - * HOLD ... stop right there...that's close enough - * - * Copyright (C) 2005 Cytronics & Melware - * - * Armin Schindler - * - * Reworked, but based on the work of - * Copyright (C) 2002-2005 Junghanns.NET GmbH - * - * Klaus-Peter Junghanns - * - * This program is free software and may be modified and - * distributed under the terms of the GNU Public License. - */ - -#include "config.h" - -#include -#include -#include -#ifndef CC_AST_HAVE_TECH_PVT -#include -#endif -#include -#include -#include -#include -#include -#include - -#include -#include -#include "chan_capi_pvt.h" -#include "chan_capi_app.h" - - - -static char *tdesc = "(CAPI*) HOLD"; -static char *app = "capiHOLD"; -static char *synopsis = "put the call on hold"; - -STANDARD_LOCAL_USER; - -LOCAL_USER_DECL; - -static int capiHOLD_exec(struct ast_channel *chan, void *data) -{ - struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(chan); - MESSAGE_EXCHANGE_ERROR Info; - _cmsg CMSG; - char fac[4]; - int res = 0; - struct localuser *u; - - LOCAL_USER_ADD(u); - - /* Do our thing here */ - - while (i->state != CAPI_STATE_BCONNECTED) { - usleep(10000); - } - - fac[0] = 3; /* len */ - fac[1] = 0x02; /* this is a HOLD up */ - fac[2] = 0; - fac[3] = 0; - - FACILITY_REQ_HEADER(&CMSG,ast_capi_ApplID, get_ast_capi_MessageNumber(),0); - FACILITY_REQ_PLCI(&CMSG) = i->PLCI; - FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 0x0003; /* sservices */ - FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (char *)&fac; - - if ((Info = _capi_put_cmsg(&CMSG)) != 0) { - LOCAL_USER_REMOVE(u); - return Info; - } else { - ast_log(LOG_NOTICE,"sent FACILITY_REQ PLCI = %#x\n", - i->PLCI); - } - - i->state = CAPI_STATE_PUTTINGONHOLD; - i->onholdPLCI= i->PLCI; - - while (i->state == CAPI_STATE_PUTTINGONHOLD) { - usleep(10000); - } - - if (i->onholdPLCI != 0) { - ast_log(LOG_NOTICE,"PLCI = %#x is on hold now\n", - i->onholdPLCI); - } else { - i->state = CAPI_STATE_BCONNECTED; - ast_log(LOG_NOTICE,"PLCI = %#x did not go on hold. going on!\n", - i->PLCI); - } - - LOCAL_USER_REMOVE(u); - return res; -} - -int unload_module(void) -{ - STANDARD_HANGUP_LOCALUSERS; - return ast_unregister_application(app); -} - -int load_module(void) -{ - return ast_register_application(app, capiHOLD_exec, synopsis, tdesc); -} - -char *description(void) -{ - return tdesc; -} - -int usecount(void) -{ - int res; - STANDARD_USECOUNT(res); - return res; -} - -char *key() -{ - return ASTERISK_GPL_KEY; -} - diff --git a/app_capiRETRIEVE.c b/app_capiRETRIEVE.c deleted file mode 100644 index aba6d7e..0000000 --- a/app_capiRETRIEVE.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * (CAPI*) - * - * An implementation of Common ISDN API 2.0 for Asterisk - * - * RETRIEVE - * - * Copyright (C) 2005 Cytronics & Melware - * - * Armin Schindler - * - * Reworked, but based on the work of - * Copyright (C) 2002-2005 Junghanns.NET GmbH - * - * Klaus-Peter Junghanns - * - * This program is free software and may be modified and - * distributed under the terms of the GNU Public License. - */ - -#include "config.h" - -#include -#include -#include -#ifndef CC_AST_HAVE_TECH_PVT -#include -#endif -#include -#include -#include -#include -#include -#include - -#include -#include -#include "chan_capi_pvt.h" -#include "chan_capi_app.h" - - - -static char *tdesc = "(CAPI*) RETRIEVE"; -static char *app = "capiRETRIEVE"; -static char *synopsis = "retrieve the call that is on hold"; - -STANDARD_LOCAL_USER; - -LOCAL_USER_DECL; - -static int capiRETRIEVE_exec(struct ast_channel *chan, void *data) -{ - struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(chan); - MESSAGE_EXCHANGE_ERROR Info; - _cmsg CMSG; - char fac[4]; - int res = 0; - struct localuser *u; - - if (i->onholdPLCI <= 0) { - ast_log(LOG_WARNING, "no call on hold to retrieve!\n"); - return -1; - } - - LOCAL_USER_ADD(u); - - /* Do our thing here */ - - fac[0] = 3; /* len */ - fac[1] = 0x03; /* retrieve */ - fac[2] = 0x00; - fac[3] = 0; - - FACILITY_REQ_HEADER(&CMSG,ast_capi_ApplID, get_ast_capi_MessageNumber(),0); - FACILITY_REQ_PLCI(&CMSG) = i->onholdPLCI; - FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 0x0003; /* sservices */ - FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (char *)&fac; - - if ((Info = _capi_put_cmsg(&CMSG)) != 0) { - LOCAL_USER_REMOVE(u); - return Info; - } else { - i->state = CAPI_STATE_RETRIEVING; - ast_log(LOG_NOTICE,"sent FACILITY_REQ PLCI = %#x\n",i->onholdPLCI); - } - - while (i->state == CAPI_STATE_RETRIEVING) { - usleep(10000); - } - - /* send a CONNECT_B3_REQ */ - memset(&CMSG, 0, sizeof(_cmsg)); - CONNECT_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(),0); - CONNECT_B3_REQ_PLCI(&CMSG) = i->PLCI; - if ((Info = _capi_put_cmsg(&CMSG)) == 0) { - ast_log(LOG_NOTICE,"sent CONNECT_B3_REQ (PLCI=%#x)\n", - i->PLCI); - } - - while (i->state == CAPI_STATE_CONNECTED) { - usleep(10000); - } - ast_log(LOG_NOTICE,"retrieved PLCI = %#x\n", i->PLCI); - - LOCAL_USER_REMOVE(u); - return res; -} - -int unload_module(void) -{ - STANDARD_HANGUP_LOCALUSERS; - return ast_unregister_application(app); -} - -int load_module(void) -{ - return ast_register_application(app, capiRETRIEVE_exec, synopsis, tdesc); -} - -char *description(void) -{ - return tdesc; -} - -int usecount(void) -{ - int res; - STANDARD_USECOUNT(res); - return res; -} - -char *key() -{ - return ASTERISK_GPL_KEY; -} - diff --git a/chan_capi.c b/chan_capi.c index 552597f..439534e 100644 --- a/chan_capi.c +++ b/chan_capi.c @@ -617,7 +617,7 @@ static void capi_activehangup(struct ast_channel *c) } if ((state == CAPI_STATE_CONNECTED) || (state == CAPI_STATE_CONNECTPENDING) || - (state == CAPI_STATE_ANSWERING)) { + (state == CAPI_STATE_ANSWERING) || (state == CAPI_STATE_ONHOLD)) { DISCONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0); DISCONNECT_REQ_PLCI(&CMSG) = i->PLCI; _capi_put_cmsg(&CMSG); @@ -2101,7 +2101,7 @@ static void capi_handle_facility_indication(_cmsg *CMSG, unsigned int PLCI, unsi return_on_no_interface("FACILITY_IND"); - if (FACILITY_IND_FACILITYSELECTOR(CMSG) == 0x0001) { + if (FACILITY_IND_FACILITYSELECTOR(CMSG) == FACILITYSELECTOR_DTMF) { /* DTMF received */ if (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0] != (0xff)) { dtmflen = FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0]; @@ -2126,7 +2126,7 @@ static void capi_handle_facility_indication(_cmsg *CMSG, unsigned int PLCI, unsi } } - if (FACILITY_IND_FACILITYSELECTOR(CMSG) == 0x0003) { + if (FACILITY_IND_FACILITYSELECTOR(CMSG) == FACILITYSELECTOR_SUPPLEMENTARY) { /* supplementary sservices */ #if 0 ast_log(LOG_NOTICE,"FACILITY_IND PLCI = %#x\n",PLCI); @@ -2140,19 +2140,37 @@ static void capi_handle_facility_indication(_cmsg *CMSG, unsigned int PLCI, unsi /* RETRIEVE */ if ( (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x3) && (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3] == 0x2) ) { - i->state = CAPI_STATE_CONNECTED; - i->PLCI = i->onholdPLCI; - i->onholdPLCI = 0; + if ((FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5] != 0) || + (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4] != 0)) { + ast_log(LOG_WARNING, "%s: unable to retrieve PLCI=%#x, REASON = %#x%#x\n", + i->name, + PLCI, FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5], + FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4]); + } else { + /* reason != 0x0000 == problem */ + i->state = CAPI_STATE_CONNECTED; + i->PLCI = i->onholdPLCI; + i->onholdPLCI = 0; + cc_ast_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x retrieved\n", + i->name, PLCI); + /* send a CONNECT_B3_REQ */ + memset(&CMSG2, 0, sizeof(_cmsg)); + CONNECT_B3_REQ_HEADER(&CMSG2, ast_capi_ApplID, get_ast_capi_MessageNumber(),0); + CONNECT_B3_REQ_PLCI(&CMSG2) = i->PLCI; + _capi_put_cmsg(&CMSG2); + cc_ast_verbose(4, 1, VERBOSE_PREFIX_3 "%s: sent CONNECT_B3_REQ PLCI=%#x\n", + i->name, PLCI); + } } /* HOLD */ if ( (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x2) && (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3] == 0x2) ) { - if ((FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5] != 0) && + if ((FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5] != 0) || (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4] != 0)) { /* reason != 0x0000 == problem */ i->onholdPLCI = 0; - i->state = CAPI_STATE_ONHOLD; + i->state = CAPI_STATE_BCONNECTED; ast_log(LOG_WARNING, "%s: unable to put PLCI=%#x onhold, REASON = %#x%#x, maybe you need to subscribe for this...\n", i->name, PLCI, FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5], @@ -2160,10 +2178,8 @@ static void capi_handle_facility_indication(_cmsg *CMSG, unsigned int PLCI, unsi } else { /* reason = 0x0000 == call on hold */ i->state = CAPI_STATE_ONHOLD; - if (capidebug) { - ast_log(LOG_NOTICE, "%s: PLCI=%#x put onhold\n", - i->name, PLCI); - } + cc_ast_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x put onhold\n", + i->name, PLCI); } } } @@ -2467,12 +2483,6 @@ static void capi_handle_disconnect_indication(_cmsg *CMSG, unsigned int PLCI, un } } - if (PLCI == i->onholdPLCI) { - /* the caller onhold hung up (or ECTed away) */ - interface_cleanup(i); - return; - } - if ((i->owner) && (state == CAPI_STATE_DID) && (i->owner->pbx == NULL)) { /* the pbx was not started yet */ ast_hangup(i->owner); @@ -2842,7 +2852,8 @@ static void capi_handle_facility_confirmation(_cmsg *CMSG, unsigned int PLCI, un (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[2] == 0x0) && ((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[4] != 0x0) || (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[5] != 0x0))) { - i->state = CAPI_STATE_BCONNECTED; + cc_ast_verbose(2, 0, VERBOSE_PREFIX_3 "%s: Call on hold (PLCI=%#x)\n", + i->name, PLCI); } break; default: @@ -2984,6 +2995,73 @@ static void capi_handle_msg(_cmsg *CMSG) break; } } + +/* + * retrieve a hold on call + */ +static int capi_retrieve(struct ast_channel *c, char *param) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); + _cmsg CMSG; + char fac[4]; + + if (i->onholdPLCI == 0) { + ast_log(LOG_WARNING, "%s: %s is not on hold to retrieve!\n", + i->name, c->name); + return -1; + } + + fac[0] = 3; /* len */ + fac[1] = 0x03; /* retrieve */ + fac[2] = 0x00; + fac[3] = 0; + + FACILITY_REQ_HEADER(&CMSG,ast_capi_ApplID, get_ast_capi_MessageNumber(),0); + FACILITY_REQ_PLCI(&CMSG) = i->onholdPLCI; + FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_SUPPLEMENTARY; + FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (char *)&fac; + + _capi_put_cmsg(&CMSG); + cc_ast_verbose(2, 1, VERBOSE_PREFIX_1 "%s: sent RETRIEVE for PLCI=%#x\n", + i->name, i->PLCI); + + return 0; +} + +/* + * hold a call + */ +static int capi_hold(struct ast_channel *c, char *param) +{ + struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c); + _cmsg CMSG; + char fac[4]; + + if (i->state != CAPI_STATE_BCONNECTED) { + ast_log(LOG_NOTICE,"%s: Cannot put on hold %s while not connected.\n", + i->name, c->name); + return -1; + } + + fac[0] = 3; /* len */ + fac[1] = 0x02; /* this is a HOLD up */ + fac[2] = 0x00; + fac[3] = 0; + + FACILITY_REQ_HEADER(&CMSG,ast_capi_ApplID, get_ast_capi_MessageNumber(),0); + FACILITY_REQ_PLCI(&CMSG) = i->PLCI; + FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_SUPPLEMENTARY; + FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (char *)&fac; + + _capi_put_cmsg(&CMSG); + cc_ast_verbose(2, 1, VERBOSE_PREFIX_1 "%s: sent HOLD for PLCI=%#x\n", + i->name, i->PLCI); + + i->onholdPLCI= i->PLCI; + + return 0; +} + /* * report malicious call */ @@ -3118,6 +3196,10 @@ static int capicommand_exec(struct ast_channel *chan, void *data) res = capi_echosquelch(chan, params); } else if (!strcasecmp(command, "malicious")) { res = capi_malicious(chan, params); + } else if (!strcasecmp(command, "hold")) { + res = capi_hold(chan, params); + } else if (!strcasecmp(command, "retrieve")) { + res = capi_retrieve(chan, params); } else { res = -1; ast_log(LOG_WARNING, "Unknown command '%s' for capiCommand\n", diff --git a/chan_capi_pvt.h b/chan_capi_pvt.h index d4c57f1..c99fd3e 100644 --- a/chan_capi_pvt.h +++ b/chan_capi_pvt.h @@ -120,10 +120,7 @@ typedef struct fax3proto3 { #define CAPI_STATE_DID 8 #define CAPI_STATE_INCALL 9 -#define CAPI_STATE_PUTTINGONHOLD 10 -#define CAPI_STATE_RETRIEVING 11 -#define CAPI_STATE_ONHOLD 12 - +#define CAPI_STATE_ONHOLD 10 #define AST_CAPI_B3_DONT 0 #define AST_CAPI_B3_ALWAYS 1