[Asterisk-Users] chan_capi patch: app_capiFax modifications
Andrew Yager
andrew at rwts.com.au
Sat Jan 22 20:43:54 MST 2005
Hi,
Since Carl has kindly provided us with fax support for CAPI based
cards, we have been using it with much success. Today I have modified
app_capiFax so that it now supports a dynamic CSID. The following
example uses the DNID created by chan_capi on an AVM Fritz! card.
* Receive a fax with CAPI API.
* Usage : capiAnswerFax2(path_output_file.SFF|stationID)
*
* This function can be called even after a regular Answer (voice mode),
* the channel will be changed to Fax Mode.
*
* Example of use :
* line number 123, play something, if a fax tone is detected, handle it
* line number 124, answer directly in fax mode
*
* [incoming]
* exten => 123,1,Answer()
* exten => 123,2,BackGround(jpop)
* exten => 124,1,Goto(handle_fax,s,1)
* exten => fax,1,Goto(handle_fax,s,1)
*
* [handle_fax]
* exten => s,1,capiAnswerFax2(/tmp/${UNIQUEID}|1234567890) // Answer
fax with CSID 1234567890
* exten => s,2,Hangup()
* exten => h,1,deadagi,fax.php // Run SFF2TIFF and mail it.
*
Please note that this can only be used with the capi fax patch
available at http://www.mlkj.net/asterisk/chan_capi-0.3.5-patch.tar.bz2
. You will also need to modify the Makefile and add app_capiFax2.so to
the object list.
Andrew
_________________________
Andrew Yager
Real World Technology Solutions
Real People, Real SolUtions (tm)
ph: (02) 9563 4840 fax: (02) 9563 4848
mob: 0405 15 2568
http://www.rwts.com.au/
_________________________
-------------- next part --------------
/*
* (CAPI*)
*
* Receive a fax with CAPI API.
* Usage : capiAnswerFax2(path_output_file.SFF,stationID)
*
* This function can be called even after a regular Answer (voice mode),
* the channel will be changed to Fax Mode.
*
* Example of use :
* line number 123, play something, if a fax tone is detected, handle it
* line number 124, answer directly in fax mode
*
* [incoming]
* exten => 123,1,Answer()
* exten => 123,2,BackGround(jpop)
* exten => 124,1,Goto(handle_fax,s,1)
* exten => fax,1,Goto(handle_fax,s,1)
*
* [handle_fax]
* exten => s,1,capiAnswerFax(/tmp/${UNIQUEID},${DNID})
* exten => s,2,Hangup()
* exten => h,1,deadagi,fax.php // Run SFF2TIFF and mail it.
*
* An implementation of Common ISDN API 2.0 for Asterisk
*
* This program is free software and may be modified and
* distributed under the terms of the GNU Public License.
*/
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/channel_pvt.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <linux/capi.h>
#include <capi20.h>
#include "chan_capi_pvt.h"
#include "chan_capi_app.h"
/* FAX Resolutions */
#define FAX_STANDARD_RESOLUTION 0
#define FAX_HIGH_RESOLUTION 1
/* FAX Formats */
#define FAX_SFF_FORMAT 0
#define FAX_PLAIN_FORMAT 1
#define FAX_PCX_FORMAT 2
#define FAX_DCX_FORMAT 3
#define FAX_TIFF_FORMAT 4
#define FAX_ASCII_FORMAT 5
#define FAX_EXTENDED_ASCII_FORMAT 6
#define FAX_BINARY_FILE_TRANSFER_FORMAT 7
typedef struct fax3proto3 {
unsigned char len;
unsigned short resolution __attribute__ ((packed));
unsigned short format __attribute__ ((packed));
unsigned char Infos[100] __attribute__ ((packed));
} B3_PROTO_FAXG3;
static char *tdesc = "(CAPI*) Receive Faxes.";
static char *app = "capiAnswerFax2";
static char *synopsis = "Answer Fax with CAPI (Allow Station ID Setting)";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
void SetupB3Config(B3_PROTO_FAXG3 *B3conf, int FAX_Format, char* stationID) {
int len1;
int len2;
char *headLine = "CAPI FAXServer";
B3conf->resolution = FAX_HIGH_RESOLUTION;
B3conf->format = (unsigned short)FAX_Format;
len1 = strlen(stationID);
B3conf->Infos[0] = (unsigned char)len1;
strcpy((char *)&B3conf->Infos[1], stationID);
len2 = strlen(headLine);
B3conf->Infos[len1 + 1] = (unsigned char)len2;
strcpy((char *)&B3conf->Infos[len1 + 2], headLine);
B3conf->len = (unsigned char)(2 * sizeof(unsigned short) + len1 + len2 + 2);
}
static int capi_change_bchan_fax(struct ast_channel *c, char* stationID) {
struct ast_capi_pvt *i = c->pvt->pvt;
MESSAGE_EXCHANGE_ERROR error;
_cmsg CMSG;
B3_PROTO_FAXG3 B3conf;
SetupB3Config(&B3conf, FAX_SFF_FORMAT, stationID); // Format ignored by eicon cards
DISCONNECT_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI;
if ((error = _capi_put_cmsg(&CMSG)) != 0) {
ast_log(LOG_ERROR, "error sending DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI);
} else {
if (option_verbose > 5) {
ast_verbose(VERBOSE_PREFIX_4 "sent DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI);
}
}
// wait for the B3 layer to go down
while (i->state != CAPI_STATE_CONNECTED) {
usleep(10000);
}
SELECT_B_PROTOCOL_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
SELECT_B_PROTOCOL_REQ_PLCI(&CMSG) = i->PLCI;
SELECT_B_PROTOCOL_REQ_B1PROTOCOL(&CMSG) = 4;
SELECT_B_PROTOCOL_REQ_B2PROTOCOL(&CMSG) = 4;
SELECT_B_PROTOCOL_REQ_B3PROTOCOL(&CMSG) = 4;
SELECT_B_PROTOCOL_REQ_B1CONFIGURATION(&CMSG) = NULL;
SELECT_B_PROTOCOL_REQ_B2CONFIGURATION(&CMSG) = NULL;
SELECT_B_PROTOCOL_REQ_B3CONFIGURATION(&CMSG) = (_cstruct)&B3conf;
if ((error = _capi_put_cmsg(&CMSG)) != 0)
ast_log(LOG_WARNING, "capiAnswerFax CAPI SELECT_B_PROTOCOL put_cmsg error\n");
return 0;
}
static int capi_answer_fax(struct ast_channel *c, char* stationID) {
struct ast_capi_pvt *i = c->pvt->pvt;
MESSAGE_EXCHANGE_ERROR error;
_cmsg CMSG;
char buf[AST_MAX_EXTENSION];
char *dnid;
B3_PROTO_FAXG3 B3conf;
if (i->isdnmode && (strlen(i->incomingmsn)<strlen(i->dnid)))
dnid = i->dnid + strlen(i->incomingmsn);
else
dnid = i->dnid;
SetupB3Config(&B3conf, FAX_SFF_FORMAT, stationID); // Format ignored by eicon cards
CONNECT_RESP_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0);
CONNECT_RESP_PLCI(&CMSG) = i->PLCI;
CONNECT_RESP_REJECT(&CMSG) = 0;
buf[0] = strlen(dnid)+2;
buf[1] = 0x0;
buf[2] = 0x80;
strncpy(&buf[3],dnid,sizeof(buf)-4);
CONNECT_RESP_CONNECTEDNUMBER(&CMSG) = buf;
CONNECT_RESP_CONNECTEDSUBADDRESS(&CMSG) = NULL;
CONNECT_RESP_LLC(&CMSG) = NULL;
CONNECT_RESP_B1PROTOCOL(&CMSG) = 4; // T.30 modem for Group 3 fax
CONNECT_RESP_B2PROTOCOL(&CMSG) = 4; // T.30 for Group 3 fax
CONNECT_RESP_B3PROTOCOL(&CMSG) = 4; // T.30 for Group 3 fax
CONNECT_RESP_B3CONFIGURATION(&CMSG) = (_cstruct)&B3conf;
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_3 "CAPI Answering in fax mode for MSN %s\n", dnid);
if ((error = _capi_put_cmsg(&CMSG)) != 0) {
ast_log(LOG_WARNING, "capiAnswerFax CAPI put_cmsg error\n");
return -1;
} else {
if (option_verbose > 5) {
if (capidebug)
ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_RESP PLCI = %#x DNID = %s\n",i->PLCI,i->dnid);
}
}
i->state = CAPI_STATE_ANSWERING;
i->doB3 = AST_CAPI_B3_DONT;
i->outgoing = 0;
i->earlyB3 = -1;
return 0;
}
static int capianswerfax_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct localuser *u;
char *vdata, *fname, *stationID;
struct ast_capi_pvt *i = chan->pvt->pvt;
if (!data) { /* no data implies no filename or anything is present */
ast_log(LOG_WARNING, "capiAnswerFax requires an argument (filename)\n");
return -1;
}
vdata = ast_strdupa(data);
LOCAL_USER_ADD(u);
fname = vdata;
if (fname) {
stationID = strchr(vdata, '|');
if (stationID) {
*stationID='\0';
stationID++;
} else stationID = "00000000";
} else stationID = "00000000";
if (strcasecmp("CAPI", chan->type) == 0) {
i->fFax = fopen(vdata, "wb");
if(i->fFax == NULL) {
ast_log(LOG_WARNING, "capiAnswerFax can't create the output file (%s)\n", strerror(errno));
res = -1;
} else {
if(i->state != CAPI_STATE_BCONNECTED)
capi_answer_fax(chan, stationID);
else
capi_change_bchan_fax(chan, stationID);
while (i->state != CAPI_STATE_DISCONNECTED) {
sleep(1);
}
}
} else {
ast_log(LOG_WARNING, "capiFax only works on CAPI channels, check your extensions.conf!\n");
res = -1;
}
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, capianswerfax_exec,synopsis,tdesc);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}
More information about the asterisk-users
mailing list