[Asterisk-cvs] asterisk-addons/res_perl AstAPIBase.c, NONE, 1.1 AstAPIBase_wrap.c, NONE, 1.1 INSTALL, NONE, 1.1 Makefile, NONE, 1.1 README, NONE, 1.1 apihelp.c, NONE, 1.1 apihelp.h, NONE, 1.1 astmake.diff, NONE, 1.1 buildperl, NONE, 1.1 data_perl.c, NONE, 1.1 res_perl.c, NONE, 1.1 res_perl.h, NONE, 1.1

anthm at lists.digium.com anthm at lists.digium.com
Thu Sep 23 13:46:16 CDT 2004


Update of /usr/cvsroot/asterisk-addons/res_perl
In directory mongoose.digium.com:/tmp/cvs-serv27645/res_perl

Added Files:
	AstAPIBase.c AstAPIBase_wrap.c INSTALL Makefile README 
	apihelp.c apihelp.h astmake.diff buildperl data_perl.c 
	res_perl.c res_perl.h 
Log Message:
check in res_perl

--- NEW FILE: AstAPIBase.c ---
#include <res_perl.h>
#include <apihelp.h>
#include <linux/zaptel.h>
#include <sys/ioctl.h>
#define CONF_SIZE 160

AST_MUTEX_DEFINE_STATIC(modlock);

#ifdef POST_10
#define ast_set_read_format_a(chan,fmt) ast_set_read_format(chan,fmt,0);
#define ast_set_write_format_a(chan,fmt) ast_set_write_format(chan,fmt,0);

#else
#define ast_set_read_format_a(chan,fmt) ast_set_read_format(chan,fmt);
#define ast_set_write_format_a(chan,fmt) ast_set_write_format(chan,fmt);
#endif



void asterisk_log(char *log,char *msg) {
	
	if(!strcmp(log,"LOG_EVENT"))
		ast_log(LOG_EVENT,msg);

	else if(!strcmp(log,"LOG_NOTICE"))
		ast_log(LOG_NOTICE,msg);


	else if(!strcmp(log,"LOG_WARNING"))
		ast_log(LOG_WARNING,msg);


	else if(!strcmp(log,"LOG_ERROR"))
		ast_log(LOG_ERROR,msg);


	else if(!strcmp(log,"LOG_VERBOSE"))
		ast_log(LOG_VERBOSE,msg);

}

struct ast_channel *asterisk_get_channel_by_name(char *name) {
	struct ast_channel *c=NULL;
	ast_mutex_lock(&modlock);
	if((c=ast_get_channel_by_name_locked(name)))
		ast_mutex_unlock(&c->lock);
	ast_mutex_unlock(&modlock);
	return c;
}



int asterisk_chanlist(int fd)
{
#define FORMAT_STRING  "%15s  (%-10s %-12s %-4d) %7s %-12s  %-15s\n"
#define FORMAT_STRING2 "%15s  (%-10s %-12s %-4s) %7s %-12s  %-15s\n"
	struct ast_channel *c=NULL;
	int numchans = 0;
	c = ast_channel_walk_locked(NULL);
	ast_cli(fd, FORMAT_STRING2, "Channel", "Context", "Extension", "Pri", "State", "Appl.", "Data");
	while(c) {
		ast_log(LOG_WARNING,"WTF %s",c->name);
		ast_cli(fd, FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
				c->appl ? c->appl : "(None)", c->data ? ( strlen(c->data) ? c->data : "(Empty)" ): "(None)");
		numchans++;
		ast_mutex_unlock(&c->lock);
		c = ast_channel_walk_locked(c);
	}
	ast_cli(fd, "%d active channel(s)\n", numchans);
	return RESULT_SUCCESS;
}


int asterisk_chan_priority(struct ast_channel *chan,int pri) {
	
	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return 0;
	}

	if(pri != -1)
		chan->priority = pri;
 
	return chan->priority;
}

int asterisk_run_app(struct ast_channel *chan,char *app_name,char *data,int fork) {

	pthread_attr_t attr;
	struct app_container *tmp;
	struct ast_app *app;
	
	
	app = (struct ast_app *) pbx_findapp(app_name);
	if (app) {
		if(! fork)
			return pbx_exec(chan, app, data, 1);
		else {
			tmp = malloc(sizeof(struct app_container));
			if (tmp) {
				memset(tmp, 0, sizeof(struct app_container));
				strncpy(tmp->app, app_name, sizeof(tmp->app) - 1);
				strncpy(tmp->data, data, sizeof(tmp->data) - 1);
				tmp->chan = chan;
				pthread_attr_init(&attr);
				pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
				if (ast_pthread_create(&tmp->t, &attr, astapi_run_app, tmp)) {
					//ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
					free(tmp);
					return 0;
				}
			}
			else {
				ast_log(LOG_ERROR, "Out of memory :(\n");
				return -1;
			}
		}
	}
	else 
		ast_log(LOG_WARNING, "Could not find application (%s)\n", app_name);
	return -1;
}


int asterisk_exec(struct ast_channel *chan,char *app_name,char *data) {
	
	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return 0;
	}

	return asterisk_run_app(chan,app_name,data,0);

}


int asterisk_control_streamfile(struct ast_channel *chan, char *file, char *fwd, char *rev, char *stop, char *pause, int skipms) {
	return ast_control_streamfile(chan,file,fwd,rev,stop,pause,skipms);
}

int asterisk_answer(struct ast_channel *chan) {
	int res=0;

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}

	if (chan->_state != AST_STATE_UP) {
		/* Answer the chan */
		res = ast_answer(chan);
	}
	
	return res;
}


int asterisk_waitfordigit(struct ast_channel *chan,int to) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}

	return ast_waitfordigit(chan,to);
}



int asterisk_sendtext(struct ast_channel *chan,char *text) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}

	return ast_sendtext(chan,text);
}

int asterisk_recvchar(struct ast_channel *chan, int to) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}

	return ast_recvchar(chan,to);
}

int asterisk_tddmode(struct ast_channel *chan,char *mode) {
	int x;

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}


	if (!strncasecmp(mode,"on",2)) x = 1; else x = 0;
	if (!strncasecmp(mode,"mate",4)) x = 2;
	if (!strncasecmp(mode,"tdd",3)) x = 1;
	return ast_channel_setoption(chan,AST_OPTION_TDD,&x,sizeof(char),0);
}

int asterisk_sendimage(struct ast_channel *chan, char *img_name) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}

	return ast_send_image(chan, img_name);
}

int asterisk_streamfile(struct ast_channel *chan,char *file, char *digits,long sample_offset) {
	int res;
	struct ast_filestream *fs;
	long max_length;
	int input;
	char blank[2] = "";
	

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}

	if(!file) {
		ast_log(LOG_WARNING, "No Filename!\n");
		return -1;
	}
	
	if(!digits) {
		digits=blank;
	}
	

	res = ast_waitfor(chan, -1);
	input = ast_waitfordigit(chan,100);
	if(input < 0)
		return -1;
	
	fs = (struct ast_filestream *) ast_openstream(chan, file, chan->language);
	if(!fs){
		ast_log(LOG_WARNING, "Unable to open %s\n", file);
		return -1;
	}
	ast_seekstream(fs, 0, SEEK_END);
	max_length = ast_tellstream(fs);
	ast_seekstream(fs, sample_offset, SEEK_SET);
	res = ast_applystream(chan, fs);
	res = ast_playstream(fs);
	if (res) {
		return -1;
	}
	res = ast_waitstream(chan,digits);
	sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
	ast_stopstream(chan);
	return res;

}

int asterisk_saynumber(struct ast_channel *chan,int num) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}


	return  ast_say_number(chan, num,AST_DIGIT_ANY, chan->language,(char *) NULL);
}

int asterisk_saydigits(struct ast_channel *chan,char *data) {
	return ast_say_digit_str(chan, data,AST_DIGIT_ANY, chan->language);
}

char *asterisk_getdata(struct ast_channel *chan,char *filename,int max,int timeout ) {
	int res;
	char data[1024] = {""};
	char *ptr;

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return NULL;
	}


	res = ast_app_getdata(chan, filename, data, max, timeout);
	if(!res) {
		ptr=data;
		return ptr ? ptr : "";
	}
	else
		return "hangup";
}

int asterisk_setcontext(struct ast_channel *chan,char *context) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}


	strncpy(chan->context, context, sizeof(chan->context)-1);
	return 1;
}
	
int asterisk_setextension(struct ast_channel *chan,char *exten) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}
	

	strncpy(chan->exten, exten, sizeof(chan->exten)-1);
	return 0;
}

int asterisk_setpriority(struct ast_channel *chan,int pri) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}


	chan->priority = pri - 1;
	return 1;
}
		

int asterisk_recordfile(struct ast_channel *chan,char *filename,char *format,char *digits,int timeout,int silence,int beep) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}
	

	struct ast_filestream *fs;
	struct ast_frame *f;
	struct timeval tv, start;
	long sample_offset = 0;
	int res = 0;
	int ms=timeout;	

	struct ast_dsp *sildet=NULL;         /* silence detector dsp */
	int totalsilence = 0;
	int dspsilence = 0;

	int gotsilence = 0;             /* did we timeout for silence? */

	int rfmt=0;


	if (silence > 0) {
		rfmt = chan->readformat;
		res = ast_set_read_format_a(chan, AST_FORMAT_SLINEAR);
		if (res < 0) {
			ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
			return -1;
		}
		sildet = (struct ast_dsp *) ast_dsp_new();
		if (!sildet) {
			ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
			return -1;
		}
		ast_dsp_set_threshold(sildet, 256);
	}

	if (beep)
		res = ast_streamfile(chan, "beep", chan->language);
	if (!res)
		res = ast_waitstream(chan, digits);
	if (!res) {
		fs = ast_writefile(filename, format, NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
		if (!fs) {
			res = -1;
			return res;
		}
		
		chan->stream = fs;
		ast_applystream(chan,fs);
		/* really should have checks */
		ast_seekstream(fs, sample_offset, SEEK_SET);
		ast_truncstream(fs);
		
		gettimeofday(&start, NULL);
		gettimeofday(&tv, NULL);
		while ((ms < 0) || (((tv.tv_sec - start.tv_sec) * 1000 + (tv.tv_usec - start.tv_usec)/1000) < ms)) {
			res = ast_waitfor(chan, -1);
			if (res < 0) {
				ast_closestream(fs);
				return res;
			}
			f = ast_read(chan);
			if (!f) {
				ast_closestream(fs);
				return -1;
			}
			switch(f->frametype) {
			case AST_FRAME_DTMF:
				if (strchr(digits, f->subclass)) {
					/* This is an interrupting chracter */
					sample_offset = ast_tellstream(fs);
					ast_closestream(fs);
					ast_frfree(f);
					return 1;
						
				}
				break;
			case AST_FRAME_VOICE:
				ast_writestream(fs, f);
				/* this is a safe place to check progress since we know that fs
				 * is valid after a write, and it will then have our current
				 * location */
				sample_offset = ast_tellstream(fs);
				if (silence > 0) {
					dspsilence = 0;
					ast_dsp_silence(sildet, f, &dspsilence);
					if (dspsilence) {
						totalsilence = dspsilence;
					} else {
						totalsilence = 0;
					}
					if (totalsilence > silence) {
						/* Ended happily with silence */
						ast_frfree(f);
						gotsilence = 1;
						break;
					}
				}
				break;
			}
			ast_frfree(f);
			gettimeofday(&tv, NULL);
			if (gotsilence)
				break;
		}
			
		if (gotsilence) {
			ast_stream_rewind(fs, silence-1000);
			ast_truncstream(fs);
		}		
		ast_closestream(fs);
	} else
		
		if (silence > 0) {
			res = ast_set_read_format_a(chan, rfmt);
			if (res)
				ast_dsp_free(sildet);
		}

	return sample_offset;
}


int asterisk_autohangup(struct ast_channel *chan, int timeout) {


	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}
	

	if (timeout < 0)
		timeout = 0;
	if (timeout)
		chan->whentohangup = time(NULL) + timeout;
	else
		chan->whentohangup = 0;

	return 1;
}

int asterisk_soft_hangup(struct ast_channel *chan) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}


	return ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
}

int asterisk_hangup(struct ast_channel *chan) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}
	
	return ast_hangup(chan);
}

void asterisk_setcallerid(struct ast_channel *chan,char *callerid) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return;
	}


	ast_set_callerid(chan, callerid, 0);
}

int asterisk_channelstatus(struct ast_channel *chan) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}


	return chan->_state;
}

int asterisk_setvariable(struct ast_channel *chan,char *var, char *val) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}


	pbx_builtin_setvar_helper(chan, var, val);
	return 0;
}

char *asterisk_getvariable(struct ast_channel *chan, char *var) {
	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return NULL;
	}
	
	return (char *) pbx_builtin_getvar_helper(chan,var);
}

void asterisk_verbose(int level,char *msg) {
	char *prefix;

	switch (level) {
	case 4:
		prefix = VERBOSE_PREFIX_4;
		break;
	case 3:
		prefix = VERBOSE_PREFIX_3;
		break;
	case 2:
		prefix = VERBOSE_PREFIX_2;
		break;
	case 1:
		prefix = VERBOSE_PREFIX_1;
		break;
	case 0:
	default:
		prefix = "";
		break;
	}

	if (level <= option_verbose)
		ast_verbose("%s%s", prefix,msg);
	

}

char *asterisk_dbget(struct ast_channel *chan,char *db, char *name) {
	int res;
	char tmp[256] = {""};
	char *ptr;


	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return NULL;
	}
	

	res = ast_db_get(db, name, tmp, sizeof(tmp));
	ptr = tmp;

	if (ptr)
		return ptr;

	return "";

}

int asterisk_dbput(struct ast_channel *chan,char *db, char *name,char *data) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}

	return ast_db_put(db, name, data);
}

int asterisk_dbdel(struct ast_channel *chan,char *db, char *name) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}
	
	return ast_db_del(db,name);
}

int asterisk_dbdeltree(struct ast_channel *chan,char *family,char *keytree) {


	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}


	if (keytree && strlen(keytree))
		return ast_db_deltree(family,keytree);
	else
		return ast_db_deltree(family, NULL);

}

void asterisk_moh_start(struct ast_channel *chan,char *moh) {


	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return;
	}


	if (moh && strlen(moh))
		ast_moh_start(chan,moh);
	else
		ast_moh_start(chan, NULL);

}



void asterisk_moh_stop(struct ast_channel *chan) {

	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return;
	}
	

	ast_moh_stop(chan);
}


int asterisk_bridge_call(struct ast_channel *chan, struct ast_channel *peer, int allowredir_in, int allowredir_out, int allowdisconnect) {
	struct ast_bridge_config config;
  
	if(!chan || !peer) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return -1;
	}
  
	memset(&config,0,sizeof(struct ast_bridge_config));
	config.allowredirect_in = allowredir_in;
	config.allowredirect_out = allowredir_out;
	config.allowdisconnect_in = allowdisconnect;
	config.allowdisconnect_out = allowdisconnect;
	return ast_bridge_call(chan,peer,&config);
	
}


struct ast_channel *asterisk_request_and_dial(char *type,char *data,int format,char *callerid, int timeout) {
	int reason;
	struct ast_channel *chan;
	chan = ast_request_and_dial(type,AST_FORMAT_ULAW, data, timeout, &reason,callerid);
	return chan;
}


int asterisk_manager_command(int fd,char *cmd) {
	return ast_cli_command(fd, cmd);
}

int asterisk_cli(int fd,char *cmd) {
	ast_cli(fd,cmd);
	return 0;
}

int asterisk_best_format(struct ast_channel *chan) {
	return ast_best_codec(chan->nativeformats);
}

void asterisk_set_read_format(struct ast_channel *chan,int format) {
	ast_set_read_format_a(chan,format);
}


void asterisk_set_write_format(struct ast_channel *chan,int format) {
	ast_set_write_format_a(chan,format);
}

void asterisk_set_best_read_format(struct ast_channel *chan) {
	ast_set_read_format_a(chan, ast_best_codec(chan->nativeformats));
}


void asterisk_set_best_write_format(struct ast_channel *chan) {
	ast_set_write_format_a(chan, ast_best_codec(chan->nativeformats));
}


struct ast_channel *asterisk_request(int format,char *type,char *data,char *callerid) {
	struct ast_channel *chan=NULL;
	chan = ast_request(type, format, data);
	if (callerid && strlen(callerid))
		ast_set_callerid(chan, callerid, 1);

	return chan;
}


int asterisk_dial(struct ast_channel *chan,char *data,int timeout) {
	int res=0,state=0;
	struct ast_frame *f;
	
	if (!ast_call(chan, data, 0)) {
		while(timeout && (chan->_state != AST_STATE_UP)) {
			res = ast_waitfor(chan, timeout);
			if (res < 0) {
				/* Something not cool, or timed out */
				break;
			}
			/* If done, break out */
			if (!res)
				break;
			if (timeout > -1)
				timeout = res;
			f = ast_read(chan);
			if (!f) {
				state = AST_CONTROL_HANGUP;
				res = 0;
				break;
			}
			if (f->frametype == AST_FRAME_CONTROL) {
				if (f->subclass == AST_CONTROL_RINGING)
					state = AST_CONTROL_RINGING;
				else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
					state = f->subclass;
					ast_frfree(f);
					break;
				} else if (f->subclass == AST_CONTROL_ANSWER) {
					state = f->subclass;
					ast_frfree(f);
					break;
				} else {
					ast_log(LOG_NOTICE, "Don't know what to do with control frame %d\n", f->subclass);
				}
			}
			ast_frfree(f);
		}
	} else
		ast_log(LOG_NOTICE, "Unable to dial channel %s/%s\n", chan->type, (char *)data);

	if (chan && res <= 0) {
		if (!chan->cdr) {
			chan->cdr = ast_cdr_alloc();
			if (chan->cdr)
				ast_cdr_init(chan->cdr, chan);
		}
		if (chan->cdr) {
			char tmp[256];
			sprintf(tmp, "%s/%s",chan->type,(char *)data);
			ast_cdr_setapp(chan->cdr,"Dial",tmp);
			ast_cdr_update(chan);
			ast_cdr_start(chan->cdr);
			ast_cdr_end(chan->cdr);
			/* If the cause wasn't handled properly */
			if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
				ast_cdr_failed(chan->cdr);
		} else
			ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
		ast_hangup(chan);
		chan = NULL;
	}


	return res;
}


void asterisk_waitfor(struct ast_channel *chan,int wait) {
	if(!chan) {
		ast_log(LOG_WARNING, "No Channel!\n");
		return ;
	}

	ast_waitfor(chan,wait);
}


int asterisk_make_compatible(struct ast_channel *chan,struct ast_channel *peer) {

	if(!chan || ! peer) {
		ast_log(LOG_WARNING, "No Channels!\n");
		return -1;
	}

	return ast_channel_make_compatible(chan, peer);
	
}


void asterisk_wait_for_control(struct ast_channel *chan,int subclass,int timeout) {
	struct ast_frame *f;
	time_t start,now;

	time(&now);
	start = now;

	if(!chan) {
		ast_log(LOG_WARNING, "No Channels!\n");
		return;
	}

	while(ast_waitfor(chan, -1) > -1) {
		time(&now);

		f = ast_read(chan);
		if (!f)
			break;
		
		if (f->frametype == AST_FRAME_CONTROL) {

			if (! subclass || f->subclass == subclass) {
				break;
			}
		}
		
		ast_log(LOG_WARNING,"debug: %d->%d\n",f->frametype,f->subclass);


		if((now-start) > timeout)
			break;

	}
	
}


--- NEW FILE: AstAPIBase_wrap.c ---
/* ----------------------------------------------------------------------------
 * This file was automatically generated by SWIG (http://www.swig.org).
 * Version 1.3.20
 * 
 * This file is not intended to be easily readable and contains a number of 
 * coding conventions designed to improve portability and efficiency. Do not make
 * changes to this file unless you know what you are doing--modify the SWIG 
 * interface file instead. 
 * ----------------------------------------------------------------------------- */

/*************************************************************** -*- c -*-
 * perl5/precommon.swg
 *
 * Rename all exported symbols from common.swg, to avoid symbol
 * clashes if multiple interpreters are included
 *
 ************************************************************************/

#define SWIG_TypeRegister    SWIG_Perl_TypeRegister
[...2439 lines suppressed...]
            break;
            case SWIG_STRING:
            sv_setpv(sv, (char *) swig_constants[i].pvalue);
            break;
            case SWIG_POINTER:
            SWIG_MakePtr(sv, swig_constants[i].pvalue, *(swig_constants[i].ptype),0);
            break;
            case SWIG_BINARY:
            SWIG_MakePackedObj(sv, swig_constants[i].pvalue, swig_constants[i].lvalue, *(swig_constants[i].ptype));
            break;
            default:
            break;
        }
        SvREADONLY_on(sv);
    }
    
    ST(0) = &PL_sv_yes;
    XSRETURN(1);
}


--- NEW FILE: INSTALL ---
1) make patch to patch asterisk 

2) Re-Build Asterisk

3) cd to the res_perl dir (wherever you put it.  You're probably there now!)

4) If you have res_config.so installed , Edit Makefile and uncomment the line the looks like this:
   #CFLAGS += -DHAVE_RES_CONFIG
   Then you will have access to the config handler too

5) 'make; make install' "should" do it for ya.


--- NEW FILE: Makefile ---
# what compiler
CC=gcc -Wall

# where is the perl binary **PRETTY IMPORTANT**
PERL        =/usr/local/bin/perl
PERL_LIBDIR =-L$(shell perl -MConfig -e 'print $$Config{archlib}')/CORE
PERL_LIBS   =$(shell perl -MConfig -e 'print $$Config{libs}')

# where is the asterisk source tree
ASTSRC = /usr/src/asterisk

LIBS = $(PERL_LIBS)


PWD=$(shell pwd)

#CFLAGS += $(shell if [ -f "$(ASTSRC)/res/res_config.c" ]; then echo "-DHAVE_RES_CONFIG"; fi)
CFLAGS += -DHAVE_AST_CUST_CONFIG



#####################################################################################
# copy these from the asterisk top level Makefile
INSTALL_PREFIX=
ASTLIBDIR=$(INSTALL_PREFIX)/usr/lib/asterisk
ASTVARLIBDIR=$(INSTALL_PREFIX)/var/lib/asterisk
ASTETCDIR=$(INSTALL_PREFIX)/etc/asterisk
ASTSPOOLDIR=$(INSTALL_PREFIX)/var/spool/asterisk
ASTLOGDIR=$(INSTALL_PREFIX)/var/log/asterisk
ASTHEADERDIR=$(INSTALL_PREFIX)/usr/include/asterisk
ASTCONFPATH=$(ASTETCDIR)/asterisk.conf
ASTBINDIR=$(INSTALL_PREFIX)/usr/bin
ASTSBINDIR=$(INSTALL_PREFIX)/usr/sbin
ASTVARRUNDIR=$(INSTALL_PREFIX)/var/run
MODULES_DIR=$(ASTLIBDIR)/modules
AGI_DIR=$(ASTVARLIBDIR)/agi-bin


CFLAGS +=  $(INCLUDES)
CFLAGS +=  -DAST_INSTALL_PREFIX=\"$(INSTALL_PREFIX)\" -DASTETCDIR=\"$(ASTETCDIR)\" -DASTLIBDIR=\"$(ASTLIBDIR)\"
CFLAGS +=  -DASTVARLIBDIR=\"$(ASTVARLIBDIR)\" -DASTVARRUNDIR=\"$(ASTVARRUNDIR)\" -DASTSPOOLDIR=\"$(ASTSPOOLDIR)\" -DASTLOGDIR=\"$(ASTLOGDIR)\"
CFLAGS +=  -DASTCONFPATH=\"$(ASTCONFPATH)\" -DASTMODDIR=\"$(MODULES_DIR)\" -DASTAGIDIR=\"$(AGI_DIR)\" 
CFLAGS +=  -DMULTIPLICITY $(shell $(PERL) -MExtUtils::Embed -e ccopts) 

LDFLAGS  =  $(shell $(PERL) -MExtUtils::Embed -e ldopts)
LDFLAGS +=  $(shell perl -MConfig -e 'print $$Config{libs}')
INCLUDES =  -I$(ASTSRC) -I$(ASTSRC)/include -I.

OBJS=perlxsi.o res_perl.o apihelp.o




all: res_perl.so api

.perlok:
	@(${PERL} -V | grep -i usemultiplicity=define >/dev/null && echo Phew, You have the right perl.) || ((echo Sorry, you need to compile perl with threads and multiplicity. && echo If you are lazy run buildperl to auto-download and install the correct version && echo Make sure you dont have any exta libperl\*.so\* anywhere. && exit 1))
	@touch .perlok

uninstall:
	@/bin/rm -fr $(ASTETCDIR)/perl $(MODULES_DIR)/res_perl.so
	@echo OK ITS GONE \(not the ast patch! =\>\)

new_config: wipe_config install

wipe_config:
	/bin/rm -fr $(ASTETCDIR)/perl

AstAPI_wrap.c:
	swig -DMULTIPLICITY -perl5 -module AstAPIBase AstAPIBase.c

perlxsi.c:
	perl -MExtUtils::Embed -e xsinit


AstAPIBase_wrap.o: 
	@echo
	@echo THIS FILE IS AUTO GENERATED BY SWIG SO IT IS GONNA GENERATE COMPILER WARNINGS
	@echo =============================================================================
	$(CC) -fPIC $(CFLAGS) -c -o $@ AstAPIBase_wrap.c
	@echo =============================================================================
	@echo

%.o:  %.c
	$(CC) -fPIC $(CFLAGS) -c -o $@ $< 


res_perl.so: .perlok $(OBJS) AstAPIBase.o
	$(CC) -fPIC -shared -Xlinker -x -o $@ $(OBJS) $(LDFLAGS) $(PERL_LINKED) AstAPIBase.o

install_api: all
	/bin/cp -p AstAPIBase.so $(ASTETCDIR)/perl
	/bin/cp -p INC/AstAPIBase.pm INC/AstAPI.pm $(ASTETCDIR)/perl

install: all 
	@/bin/cp -p -u res_perl.so $(MODULES_DIR)
	@if [ ! -d $(ASTETCDIR)/perl ] ; then mkdir $(ASTETCDIR)/perl ; fi
	@/bin/cp -p AstAPIBase.so $(ASTETCDIR)/perl
	@/bin/cp -p INC/AstAPIBase.pm INC/AstAPI.pm $(ASTETCDIR)/perl
	@/bin/cp -r -p -i --reply=no INC/* $(ASTETCDIR)/perl
	@/bin/rm -fr `find $(ASTETCDIR)/perl -type d -name CVS`
	@echo OK INSTALL COMPLETE

clean:
	rm -f *.o *.so *~ perlxsi.c

swigclean: clean
	rm -f *_wrap.c *.pm

distclean: clean
	rm -f *.cache


reswig: swigclean AstAPI_wrap.c
	/bin/mv AstAPIBase.pm INC 


AstAPIBase.so: AstAPIBase_wrap.c AstAPIBase.o AstAPIBase_wrap.o  $(ASTLIBDIR)/modules/res_musiconhold.so perlxsi.o
	$(CC) -fPIC -shared -Xlinker -x apihelp.o AstAPIBase.o AstAPIBase_wrap.o res_perl.o perlxsi.o $(ASTLIBDIR)/modules/res_musiconhold.so $(LDFLAGS) -o AstAPIBase.so


api: AstAPIBase.so 

perl: 
	./buildperl

everything: patch asterisk clean all install


patch:
	@echo applying the necessary ast patch for res_perl
	@(/bin/grep -q perlxsi.o $(ASTSRC)/Makefile && echo Patch Already Applied Don\'t Fret!) || (cd $(ASTSRC) && \
	perl -MExtUtils::Embed -e xsinit && patch -N -t -p0 < $(PWD)/astmake.diff || echo Patch Already Applied Don\'t Fret!)


asterisk:
	@cd $(ASTSRC) && /bin/rm -f asterisk && make install



--- NEW FILE: README ---
Asterisk   -- A telephony toolkit for Linux.
res_perl   -- A Module To Incoperate Perl Into Asterisk.

Copyright (C) 2003, Anthony Minessale
Anthony Minessale <anthm at cylynx.com>


res_perl 3.0


This is res_perl the "mod_perl" of sorts for asterisk.  It is an actual live Perl Interpreter 
embeded in a module so when it starts up the perl stays resident in memory the whole life of the 
Asterisk process.

IMPORTANT: As of this version you need to have perl compiled with usethreads and useithreads
           For a quick build of perl from src use 'make perl' *NOTE* ***this will erase your current perl***

FEATURES:

	It can call perl functions from extensions.conf in a special package called Asterisk::Embed
        that is loaded on startup from /etc/asterisk/asterisk_init.pm

	exten => 1,1,Perl(myfunc:arg_1:arg_2:arg_n......)

	If you change asterisk_init.pm you need to enter the cli command "perl labotomy" to read the changes.

	There is a also module included called LoadFile that allows you to store your perl apps
	in a seperate file and load them into memory without restarting they are loaded from 
	/etc/asterisk/perl/apps automaticly.
	exten => 1,1,Perl(Loadfile:demo.pl:arg_1:arg_2:arg_n....)
	If you change the file demo.pl it will load it from disk instead of memory to recache
	just send the cli command "perl call LoadFileCacheAll"
	

	inside these functions you have access to several perlified api commands starting with asterisk_* <--funny
	see INC/asterisk_init.pm for a few examples (there are a lot more than that implemented see AstAPIBase.c for
	em all. just assume any args to those C func are perl scalars)

	There are also some special return commands: (1 for now)

	thread:<function>

	This will spin off a thread with the perl sub you specify running inside it.
	the sub will get 1 scalar arg being the number of times it was run (starting with 1)

	The functions startup() and shutdown() are called respectively on load and unload of the module

BUGS:

	If you stare at the source code from about 2 feet back for approx 30 seconds you will start
	to see that the entire thing is in itself 1 large bug.  I am not so much a C programmer as I am
	a Perl programmer so that was my motivation for this idea but it probably is sucky to some
	arrogant linux zelot somewhere out there.  If that is you , ha ha I made you download it.....



WARNING:

	I, of course, am not responsible for the damage you or my intelectual property (stupid program) do to your or anybody's PC
	(People don't kill PC's...................Micro$oft kills PC's) 
	[hmm a shot at linux zelots and Micro$oft in the same file.  Who ..DO.. i like....?]


--- NEW FILE: apihelp.c ---
#include <apihelp.h>

void *astapi_run_app(void *tmp_in) {
	struct app_container *tmp = (struct app_container *) tmp_in;
	asterisk_run_app(tmp->chan,tmp->app,tmp->data,0);
	return NULL;
}


--- NEW FILE: apihelp.h ---
#ifndef _APIHELP_H
#define _APIHELP_H
#include <pthread.h>

struct app_container {
    char app[256];
    char data[256];
    struct ast_channel *chan;
    pthread_t t;
};


void *astapi_run_app(void *tmp_in);
int asterisk_run_app(struct ast_channel *chan,char *app_name,char *data,int fork);
#endif

--- NEW FILE: astmake.diff ---
Index: Makefile
===================================================================
RCS file: /usr/cvsroot/asterisk/Makefile,v
retrieving revision 1.97
diff -u -r1.97 Makefile
--- Makefile	25 Jun 2004 04:06:11 -0000	1.97
+++ Makefile	25 Jun 2004 20:00:46 -0000
@@ -191,6 +191,13 @@
 CC=gcc
 INSTALL=install
 
+
+#######  res_perl
+LIBS += $(shell /usr/local/bin/perl -MExtUtils::Embed -e ldopts) $(shell perl -MConfig -e 'print $$Config{libs}')
+PERLCFLAGS += $(shell /usr/local/bin/perl -MExtUtils::Embed -e ccopts)
+OBJS += perlxsi.o
+####### /res_perl
+
 _all: all
 	@echo " +--------- Asterisk Build Complete ---------+"  
 	@echo " + Asterisk has successfully been built, but +"  
@@ -202,6 +209,11 @@
 
 all: depend asterisk subdirs
 
+#######  res_perl
+perlxsi.o: 
+	$(CC) -c perlxsi.c $(PERLCFLAGS) -o perlxsi.o
+####### /res_perl
+
 editline/config.h:
 	cd editline && unset CFLAGS LIBS && ./configure ; \
 

--- NEW FILE: buildperl ---

mkdir /usr/src/res_perl_perl > /dev/null 2>&1
cd /usr/src/res_perl_perl
rm -fr stable.tar.gz perl* > /dev/null 2>&1
wget http://archive.progeny.com/CPAN/src/stable.tar.gz
tar -zxf stable.tar.gz
cd perl*
./Configure -Dusethreads -Duseithreads -d
make 
make install




--- NEW FILE: data_perl.c ---
/*
 * Asterisk -- A telephony toolkit for Linux.
 *
 * PostGreSQL Data Resource
 * 
 * Copyright(C) 2004, Rob Gagnon
 * Rob Gagnon <rgagnon at networkip.net>
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License.
 *
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <asterisk/config.h>
[...1956 lines suppressed...]

	/* count number of pool connections checked out */
	dbentry = db_list;
	while (dbentry) {
		poolentry = dbentry->pool;
		while (poolentry) {
			count += poolentry->checkedout;
			poolentry = poolentry->next;
		}
		dbentry = dbentry->next;
	}
	return(count);
}

/***************************************************************************/

char *
key() {
	return(ASTERISK_GPL_KEY);
}

--- NEW FILE: res_perl.c ---
/*
 * Asterisk	  -- A telephony toolkit for Linux.
 *
 * res_perl.c -- A Module To Incoperate Perl Into Asterisk.
 * 
 * Copyright (C) 2003, Anthony Minessale 
 *
 * Anthony Minessale <anthm at cylynx.com>
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License
 */

#define CSV_LOGUNIQUEID
#define CSV_LOGUSERFIELD

#include <res_perl.h>

#define RES_PERL_VERSION "1.0"
#define CREATE_STRING(name,size) char name[size];

// <PERL SPECIFIC MUMBO JUMBO>

static PerlInterpreter *global_perl;
static char *embedding[] = { "", "-e",""};
static STRLEN n_a;
static HV* PERL_CONFIG;
// </PERL SPECIFIC MUMBO JUMBO>

static char delim=129;

AST_MUTEX_DEFINE_STATIC(perl_lock);
AST_MUTEX_DEFINE_STATIC(users_lock);
static int reloading=0;
static int users=0;
int _unload_module(void);
int _load_module(void);

#ifdef HAVE_AST_CUST_CONFIG
static struct ast_config_reg reg1;
static int use_config=0;
#endif

static int use_switch=0;
static int use_cdr=0;
static int clone_on_config=0;

static void replace_delim(char *arg,char a,char b) {
	int i;
	for(i=0;i<strlen(arg);i++) {
		if(arg[i] == a)
			arg[i] = b;
	}
}

static char *get_hash_val(PerlInterpreter *my_perl,HV *hash,char *key) {
    SV *val;
    char *ret=NULL;
    if (hash) {
		val = *hv_fetch(hash,key,strlen(key),FALSE);
		if (val)
			ret = SvPV_nolen(val);
    }
    return ret;
}


static void init_perl(PerlInterpreter **new_perl) {
    char code[100];
    //ast_log(LOG_WARNING,"CREATING PERL INTREPRETER\n");
    *new_perl = perl_alloc();
    PERL_SET_CONTEXT(*new_perl);
    perl_construct(*new_perl);
    perl_parse(*new_perl, xs_init, 3, embedding, NULL);
    perl_run(*new_perl);
    sprintf(code,"use lib '%s/perl';package Asterisk::Embed;use asterisk_init;\n",ASTETCDIR);
    Perl_eval_pv(*new_perl,code, TRUE);
    return;
    
}


static void dest_perl(PerlInterpreter **old_perl) {
    if (*old_perl != NULL) {
		//ast_log(LOG_WARNING,"DESTROYING PERL INTREPRETER\n");
		perl_destruct(*old_perl);
		perl_free(*old_perl);
		*old_perl=NULL;
    }
}


static void users_inc() {
    ast_mutex_lock(&users_lock);
    users++;
    ast_mutex_unlock(&users_lock);
}

static void users_dec() {
    ast_mutex_lock(&users_lock);
    users--;
    if (users < 0)
		users = 0;
    ast_mutex_unlock(&users_lock);
}

static struct threadlist {
    char func[256];
    pthread_t thread;
    struct threadlist*next;
} *threads;


static char *tdesc = "Perl Interface";
static char *app = "Perl";
static char *synopsis = "Use Perl in Asterisk";
static char *descrip = "Use Perl in Asterisk";



STANDARD_LOCAL_USER;
LOCAL_USER_DECL;

static void list_threads(int fd) {
    struct threadlist *ptr;

    ast_cli(fd,"\n\nACTIVE THREADS:\n");
    for (ptr=threads;ptr;ptr=ptr->next) {
		if ((long) ptr->thread)
			ast_cli(fd,"thread %ld -> %s\n",(long) ptr->thread,ptr->func);
    }
    ast_cli(fd,"\n\n");
}





static void rem_thread(struct threadlist *tl) {
    struct threadlist *ptr,*prev;

    for (ptr=threads;ptr;ptr=ptr->next) {

		if ((long)ptr->thread == (long)tl->thread) {
			if (ptr==threads) {
				threads=NULL;
				break;
			} else {
				if (prev) {
					prev->next = ptr->next;
				}
			}
	    
		}

		prev=ptr;
    }
}

static void add_thread(struct threadlist *tl) {
    struct threadlist *ptr;

    if (threads)
		for (ptr=threads;ptr->next;ptr=ptr->next);

    if (ptr)
		ptr->next = tl;
    else
		threads = tl;

}


static void end_thread(char *thread_in) {
    struct threadlist *ptr;
    pthread_t thread;
    long thread_id;

    if (thread_in == NULL)
		thread_id=0;
    else 
		thread_id=atol(thread_in);
    
    
    for (ptr=threads;ptr;ptr=ptr->next) {
		if (((long) ptr->thread == thread_id) || thread_id==0) {
			thread = ptr->thread;
			ast_log(LOG_NOTICE,"Kill Thread: %ld\n",(long)ptr->thread);
			pthread_kill(thread,SIGQUIT);
			rem_thread(ptr);
		}

    }



}




void launch_perl_thread(char *function) {
    pthread_t thread;
    pthread_attr_t attr;
    int result;
    if (!function)
		return;

    result = pthread_attr_init(&attr);
    pthread_attr_setschedpolicy(&attr, SCHED_RR);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    result = ast_pthread_create(&thread, &attr,perl_thread,function);
    result = pthread_attr_destroy(&attr);

}



void *perl_thread(void *function) {
    AV *array;
    int x,i,exit;
    char *stringp,*func,*arg;
    pthread_t thread;
    struct threadlist tl;


    x = i = 0;
    exit = 1;
    ast_log(LOG_WARNING,"Started Thread\n");  

    stringp=strdup(function);
    func=strsep(&stringp,":");
    arg=strsep(&stringp,"\0");
    thread = pthread_self();
    tl.thread = thread;
    strncpy(tl.func,func,sizeof(tl.func));
    /* clone perl for this thread */
	PerlInterpreter *my_perl=perl_clone(global_perl,CLONEf_COPY_STACKS|CLONEf_KEEP_PTR_TABLE);

    add_thread(&tl);
    array=eval_some_perl(my_perl,func,arg);
    rem_thread(&tl);
    ast_log(LOG_WARNING,"%s is shutting down\n",(char *) func);
    ast_log(LOG_WARNING,"Ended Thread\n");
    dest_perl(&my_perl);
    return((void *) 1);
}


AV *eval_some_perl(PerlInterpreter *my_perl,char *func,char *arg) {
    char *callfunc;
	char *fmt = "eval{\n$SIG{QUIT} = sub {die q|SIGQUIT! Exit Requested.\n|};\nmy @args=split(chr 129,q`%s`);\nforeach (@args) {s/\\\\n/\\n/g};\n@%s=&Asterisk::Embed::%s(@args)};\nif($@) {Asterisk::Embed::asterisk_verbose(0,\"ERROR:\n$@\n\")\n};\n ";
	size_t size = (strlen(func) * 2) + strlen(arg) + strlen(fmt) + 128;
	callfunc=alloca(size);
    snprintf(callfunc,size,fmt,arg ? arg : "",func,func);
    PERL_SET_CONTEXT(my_perl);
    eval_pv(callfunc, TRUE);
    return get_av(func, FALSE);
    
}

int can_run_nochan(char *test) {
    static char *list[] = {"setvar","add_ext","include","thread"};
    int i=0;
    int ret=0;
    for (i=0;i<4;i++) {
		if (!strcmp(test,list[i])) {
			ret=1;
			break;
		}
    }
    return(ret);
}

int process_perl_return_value(struct ast_channel *chan,char *ret) {
    char *arg,*stringp,*func;

    if (!ret)
		return 0;




    stringp=strdup(ret);
    func=strsep(&stringp,":");
    arg=strsep(&stringp,"\0");

    if (func && arg) {


		ast_log(LOG_WARNING,"call function [%s]\n",func);

		if (func && ! chan && can_run_nochan(func) == 0) {
			ast_log(LOG_WARNING, "cannot use function [%s] from here,skipping...\n",func);
			return 1;
		}
		if (!strcmp(func,"thread")) {
			launch_perl_thread(arg);
		}
    }

    return 0;
}



static int perl_exec(struct ast_channel *chan, void *data)
{
    char *func;
    char *arg;
	char *info;
    char *stringp=NULL;
    char buf[2048];
    AV *array;
    int i;
    I32 array_size;
    char *rval;
    PerlInterpreter *my_perl;
    int retme=0;


    if (!data || !strlen(data)) {
		ast_log(LOG_WARNING, "Ignoring blank arg\n");
		return -1;
    }
    
    /* clone perl for this execution */
	my_perl=perl_clone(global_perl,CLONEf_COPY_STACKS|CLONEf_KEEP_PTR_TABLE);
    users_inc();

	info=ast_strdupa(data);
    stringp=info;
    func=strsep(&stringp,":");
    arg=strsep(&stringp,"\0");


    if (chan && chan->name && arg) {
		sprintf(buf,"%s%c%s",chan->name,':',arg);
		arg=buf + strlen(chan->name);
    } else if(chan && chan->name) {
		sprintf(buf,"%s",chan->name);
		arg=buf;
    } else {
		ast_log(LOG_WARNING,"No channel, sorry...\n");
		return -1;
    }

	replace_delim(arg,':',delim);
    ast_log(LOG_WARNING, "Calling Perl Sub [%s] [%s]\n",func,buf);

	array=eval_some_perl(my_perl,func,buf);

    if (array) {
		array_size = av_len(array) + 1;
		for (i = 0; i < array_size; i++) {
			rval = SvPV(*av_fetch(array, i, FALSE),n_a);
			retme = atoi(rval);
			if (! process_perl_return_value(chan,rval)) {
				users_dec();
				dest_perl(&my_perl);
				return retme;
			}
		}
    }

    users_dec();
    dest_perl(&my_perl);
    return(retme);
}		





static int perl_reload(int fd) {

    ast_log(LOG_WARNING, "This wont work yet\n");
    return 0;


    if (users) {
		ast_log(LOG_WARNING, "Too Busy for reload wait for %d users first.\n",users);
		return 0;
    }
    if (reloading) {
		ast_log(LOG_WARNING, "Not done reloading from last time yet!\n");
    }


    ast_mutex_lock(&perl_lock);
    reloading = 1;
    _unload_module();
    _load_module();
    reloading = 0;
    users = 0;
    ast_mutex_unlock(&perl_lock);

    return 0;
}



static int perl_cli(int fd, int argc, char *argv[]) {
    AV *array;
    int i;
    I32 array_size;
    char * rval;
    PerlInterpreter *my_perl = global_perl;
    char arg1[255],arg2[255];

    if (argv[1] && !strcmp(argv[1],"reload")) {
		perl_reload(fd);
		return 0;
    } else if(argv[1] && argv[2] && !strcmp(argv[1],"thread")) {
		launch_perl_thread(argv[2]);
		ast_cli(fd,"\n\n");
		return 0;
    } else if(argv[1] && !strcmp(argv[1],"threads")) {
		list_threads(fd);
		return 0;
    } else if(argv[1] && argv[2] && !strcmp(argv[1],"end")) {
		if (!strcmp(argv[2],"all"))
			end_thread(NULL);
		else 
			end_thread(argv[2]);
		ast_cli(fd,"OK\n\n");
		return 0;
    } else if(argv[1] && !strcmp(argv[1],"labotomy")) {
		dest_perl(&global_perl);
		init_perl(&global_perl);
		ast_cli(fd,"OK, One Flew Over The KooKoo's Nest!.....\n");
		return 0;
    } else if(argv[1] && !strcmp(argv[1],"call")) {
		if (!argv[2]) {
			ast_cli(fd,"\nusage perlcall <args>\n"); 
			return 0;
		}

		if (argv[2] && argv[3]) {
			strncpy(arg1,argv[2],255);
			strncpy(arg2,argv[3],255);
			replace_delim(arg1,':',delim);
			replace_delim(arg2,':',delim);
			array=eval_some_perl(my_perl,arg1,arg2);
		} else if(argv[2]) {
			strncpy(arg1,argv[2],255);
			replace_delim(arg1,':',delim);
			array=eval_some_perl(my_perl,arg1,"");
		}
		if (array) {
			array_size = av_len(array) + 1;
			for (i = 0; i < array_size; i++) {
				rval = SvPV(*av_fetch(array, i, FALSE),n_a);
				process_perl_return_value(NULL,rval);
			}
		}
	

		return 0;
    }

    if (argv[1])
		ast_cli(fd,"\nUnknown Command: %s\n",argv[1]);
    else 
		ast_cli(fd,"\nusage perl <command> <args>\n");

    return 0;
}

/* <SWITCH> */


static int perl_switch_handler(char *func,struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, char *data,int clone) {

	AV *array;
	int array_size=0,i=0,ret=0;
	char args[256],*rval=NULL;
	PerlInterpreter *my_perl;
	if (clone) {
	    my_perl=perl_clone(global_perl,CLONEf_COPY_STACKS|CLONEf_KEEP_PTR_TABLE);
	} else {
	    my_perl = global_perl;
	}
	snprintf(args,sizeof(args),"%s:%s:%s:%s:%d:%s:%s",func,chan->name?chan->name:"nochan",context,exten,priority,callerid,data);
	replace_delim(args,':',delim);
	array=eval_some_perl(my_perl,"perl_switch_handler",args);
	if (array) {
	    array_size = av_len(array) + 1;
	    for (i = 0; i < array_size; i++) {
			rval = SvPV(*av_fetch(array, i, FALSE),n_a);
			ret = atoi(rval);
			if (ret >= 0)
				break;
	    }

	} else {
	    ret = 0;
	}

	if (clone)
	    dest_perl(&my_perl);

	return ret;
}

static int perl_switch_exists(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, char *data) {
    return perl_switch_handler("exists",chan,context,exten,priority,callerid,data,0);
}

static int perl_switch_canmatch(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, char *data) {
    return perl_switch_handler("canmatch",chan,context,exten,priority,callerid,data,0);
}

static int perl_switch_exec(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, int newstack, char *data) {
    return perl_switch_handler("exec",chan,context,exten,priority,callerid,data,1);
}

static int perl_switch_matchmore(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, char *data) {
    return perl_switch_handler("matchmore",chan,context,exten,priority,callerid,data,0);
}


static struct ast_switch perl_switch =
	{
		name:			"Perl",
		description:	"Perl Switch",
		exists:			perl_switch_exists,
		canmatch:		perl_switch_canmatch,
		exec:			perl_switch_exec,
		matchmore:		perl_switch_matchmore,
	};






/* </SWITCH> */

static struct ast_cli_entry  cli_perl = { { "perl", NULL }, perl_cli, "Perl", "Perl" };

int _unload_module(void) {
    
    if (use_switch) {
		ast_unregister_switch(&perl_switch);
    }

    if (use_cdr) {
		ast_cdr_unregister("perl");
    }


    eval_some_perl(global_perl,"shutdown","");
    end_thread(NULL);

    dest_perl(&global_perl);

    if (reloading)
		return 0;



#ifdef HAVE_AST_CUST_CONFIG
    if (use_config) {
		ast_log(LOG_NOTICE,"unloading perl config engine.\n");
		ast_cust_config_deregister(&reg1);
    }
#endif

    STANDARD_HANGUP_LOCALUSERS;
    ast_cli_unregister(&cli_perl);
    ast_unregister_application(app);
    return 0;

}


static int append_string(char *buf, char *s, int len)
{
    int pos = strlen(buf);
    int spos = 0;
    int error = 0;
    if (pos >= len - 4)
		return -1;
    error = -1;
    while (pos < len - 3) {
		if (!s[spos]) {
			error = 0;
			break;
		}
		buf[pos++] = s[spos];
		spos++;
    }
    buf[pos++] = delim;
    buf[pos++] = '\0';
    return error;
}

static int append_int(char *buf, int s, int len)
{
    char tmp[32];
    int pos = strlen(buf);
    snprintf(tmp, sizeof(tmp), "%d", s);
    if (pos + strlen(tmp) > len - 3)
		return -1;
    strncat(buf, tmp, len);
    pos = strlen(buf);
    buf[pos++] = delim;
    buf[pos++] = '\0';
    return 0;
}

static int append_long(char *buf, long s, int len)
{
    char tmp[32];
    int pos = strlen(buf);
    snprintf(tmp, sizeof(tmp), "%ld", s);
    if (pos + strlen(tmp) > len - 3)
		return -1;
    strncat(buf, tmp, len);
    pos = strlen(buf);
    buf[pos++] = delim;
    buf[pos++] = '\0';
    return 0;
}



static int append_tv_diff(char *buf,struct timeval *ended,struct timeval *started, int len)
{
    char tmp[32];
    int pos = strlen(buf);
    long elapsed = (((ended->tv_sec * 1000) + ended->tv_usec / 1000) - ((started->tv_sec * 1000) + started->tv_usec / 1000));  

    snprintf(tmp, sizeof(tmp), "%ld", elapsed);
    if (pos + strlen(tmp) > len - 3)
		return -1;
    strncat(buf, tmp, len);
    pos = strlen(buf);
    buf[pos++] = delim;
    buf[pos++] = '\0';
    return 0;
}

static int build_csv_record(char *buf, int len, struct ast_cdr *cdr)
{

    buf[0] = '\0';
    /* Account code */
	append_string(buf,"accountcode", len);
    append_string(buf, cdr->accountcode, len);
    /* Source */
	append_string(buf,"src", len);
    append_string(buf, cdr->src, len);
    /* Destination */
	append_string(buf,"dest", len);
    append_string(buf, cdr->dst, len);
    /* Destination context */
	append_string(buf,"destcontext", len);
    append_string(buf, cdr->dcontext, len);
    /* Caller*ID */
	append_string(buf,"callerid", len);
    append_string(buf, cdr->clid, len);
    /* Channel */
	append_string(buf,"chan", len);
    append_string(buf, cdr->channel, len);
    /* Destination Channel */
	append_string(buf,"destchan", len);
    append_string(buf, cdr->dstchannel, len);
    /* Last Application */
	append_string(buf,"lastapp", len);
    append_string(buf, cdr->lastapp, len);
    /* Last Data */
	append_string(buf,"lastapparg", len);
    append_string(buf, cdr->lastdata, len);
    /* Start Time */
	append_string(buf,"start_time", len);
    append_long(buf, cdr->start.tv_sec, len);
    /* Answer Time */
	append_string(buf,"answer_time", len);
    append_long(buf, cdr->answer.tv_sec, len);
    /* End Time */
	append_string(buf,"end_time", len);
    append_long(buf, cdr->end.tv_sec, len);
    /* Duration */
	append_string(buf,"duration", len);
    append_int(buf, cdr->duration, len);

    append_string(buf,"duration_ms", len);
    append_tv_diff(buf, &cdr->end,&cdr->start, len);


    /* Billable seconds */
	append_string(buf,"billable", len);
    append_int(buf, cdr->billsec, len);

    append_string(buf,"billable_ms", len);
    append_tv_diff(buf,&cdr->end,&cdr->answer, len);


    /* Disposition */
	append_string(buf,"disposition", len);
    append_string(buf, ast_cdr_disp2str(cdr->disposition), len);
    /* AMA Flags */
	append_string(buf,"amaflags", len);
    append_string(buf, ast_cdr_flags2str(cdr->amaflags), len);

#ifdef CSV_LOGUNIQUEID
    /* Unique ID */
	append_string(buf,"uniqueid",len);
    append_string(buf, cdr->uniqueid, len);
#endif
#ifdef CSV_LOGUSERFIELD
    /* append the user field */
	append_string(buf,"user",len);
    append_string(buf, cdr->userfield,len);	
#endif
    /* If we hit the end of our buffer, log an error */
	if (strlen(buf) < len - 5) {
	    /* Trim off trailing comma */
		buf[strlen(buf) - 1] = '\0';
	    return 0;
	}
    return -1;
}


static int perl_log(struct ast_cdr *cdr) {
    char buf[1024];
    PerlInterpreter *my_perl;
    
    my_perl=perl_clone(global_perl,CLONEf_COPY_STACKS|CLONEf_KEEP_PTR_TABLE);
    if (build_csv_record(buf,1024, cdr)) {
		ast_log(LOG_WARNING, "Unable to create CSV record in 1024 bytes.  CDR not recorded!\n");
    } else {
		eval_some_perl(my_perl,"perl_cdr",buf);
    }
    dest_perl(&my_perl);
    return 0;
}

#ifdef HAVE_AST_CUST_CONFIG
struct ast_config *perl_config(char *file, struct ast_config *new_config_s,struct ast_category **new_cat_p,struct ast_variable **new_v_p,int recur
#ifdef PRESERVE_COMMENTS
							   ,struct ast_comment_struct *acs
#endif

							   ) {

    PerlInterpreter *my_perl;

    if (clone_on_config)
		my_perl=perl_clone(global_perl,CLONEf_COPY_STACKS|CLONEf_KEEP_PTR_TABLE);
    else 
		my_perl = global_perl;
    
    struct ast_config *new;
    struct ast_variable *cur_v=NULL,*new_v;
    struct ast_category *cur_cat=NULL,*new_cat=NULL;
    char last[80];
    int cat_started=0;
    int var_started=0;
    AV *array;
    int i=0,ii=0;
    I32 array_size,vars_size;
    HV *hash;
    char *category=NULL;

    AV *vars;
    HV *varshash;
    SV *name,*var,*val,*tmp;
    
    if (file && !strcmp(file,"res_perl.conf"))
		return NULL; // cant configure myself

	if (new_config_s) {
	    new = new_config_s;
	    cat_started++;
	} else 
	    new = ast_new_config();
    
    last[0] = '\0';

    cat_started=0;
    var_started=0;

    cur_cat = *new_cat_p;
    cur_v = *new_v_p;

    if (cur_cat)
		cat_started=1;
    if (cur_v)
		var_started=1;
    
    array=eval_some_perl(my_perl,"perl_config",file);

    if (array) {
		array_size = av_len(array) + 1;
    } else {
		return NULL;
    }
    
    for (i = 0; i < array_size; i++) {
		tmp = *av_fetch(array, i, FALSE);
		if (!SvROK(tmp))
			continue ;
	
		hash = (HV*) SvRV(tmp);
		if (hash && SvTYPE(hash) == SVt_PVHV) {
			name = *hv_fetch(hash,"name",4,FALSE);
			vars = (AV*) SvRV(*hv_fetch(hash,"vars",4,FALSE));
	    
			if (name && strcmp(last,SvPV_nolen(name))) {
				// new cat
				category = SvPV_nolen(name);
				strcpy(last,category);
				new_cat = (struct ast_category *) ast_new_category(category);
		
				if (!cat_started) {
					cat_started++;
					new->root = new_cat;
					cur_cat=new->root;
				} else {
					cur_cat->next = new_cat;
					cur_cat = cur_cat->next;
				}
				var_started=0;
			}
	    

			if (name && vars && SvTYPE(vars) == SVt_PVAV) {
				if (vars)
					vars_size = av_len(vars) + 1;
				else
					return NULL;
				for (ii = 0; ii < vars_size; ii++) {
					varshash = (HV*) SvRV(*av_fetch(vars, ii, FALSE));
					if (varshash && SvTYPE(varshash) == SVt_PVHV) {
						var = *hv_fetch(varshash,"var",3,FALSE);
						val = *hv_fetch(varshash,"val",3,FALSE);
			
						if (category && var && val) {
							new_v = ast_new_variable(SvPV_nolen(var),SvPV_nolen(val));
							if (!var_started) {
								var_started++;
								cur_cat->root = new_v;
								cur_v = cur_cat->root;
							} else {
								cur_v->next = new_v;
								cur_v = cur_v->next;
							}


						}
					}
				}

		
			}
		}
    }
    if (!i)
		new = NULL;

    if (clone_on_config)
		dest_perl(&my_perl);
    
    return new;


}
#endif

int _load_module(void) {
    AV *array=NULL;
    int i=0,res=0;
    I32 array_size;
    char *rval;
    users = 0;
    PerlInterpreter *my_perl;


    if (global_perl == NULL)
		init_perl(&global_perl);



    /* perl has hard coded macros on my_perl, need it */
	my_perl = global_perl;

    array=eval_some_perl(global_perl,"startup","");
    if (array)
		array_size = av_len(array) + 1;
    else 
		return 0;

    for (i = 0; i < array_size; i++) {
		rval = SvPV(*av_fetch(array, i, FALSE),n_a);
		ast_verbose(VERBOSE_PREFIX_1 " == res_perl: startup function returned %s\n",rval);
		process_perl_return_value((struct ast_channel *) NULL,rval);
	
    }
    
    if (reloading)
		return 0;

    ast_cli_register(&cli_perl); 
    
    PERL_CONFIG = get_hv("Asterisk::Embed::PERL_CONFIG",0);
    if (PERL_CONFIG) {
#ifdef HAVE_AST_CUST_CONFIG

		if (hv_exists(PERL_CONFIG,"USE_CONFIG",strlen("USE_CONFIG"))) {
			rval = get_hash_val(my_perl,PERL_CONFIG,"USE_CONFIG");
			if (rval && ast_true(rval)) {
				use_config = 1;
				
				ast_log(LOG_NOTICE,"loading perl config engine.\n");
				memset(&reg1,0,sizeof(struct ast_config_reg));
				strcpy(reg1.name,"perl");
				reg1.func = perl_config;
				ast_cust_config_register(&reg1);
				
			} else 
				ast_log(LOG_NOTICE,"perl config engine disabled.\n");
			
		} else
			ast_log(LOG_NOTICE,"perl config engine disabled.\n");
		

#endif

		if (hv_exists(PERL_CONFIG,"CLONE_ON_CONFIG",strlen("CLONE_ON_CONFIG"))) {
			rval = get_hash_val(my_perl,PERL_CONFIG,"CLONE_ON_CONFIG");
			if (rval && ast_true(rval)) {
				ast_log(LOG_NOTICE, "Perl Option: CLONE_ON_CONFIG Activated..\n");
				clone_on_config=1;
			}
		}
	
		if (hv_exists(PERL_CONFIG,"USE_CDR",strlen("USE_CDR"))) {
			rval = get_hash_val(my_perl,PERL_CONFIG,"USE_CDR");
			if (rval && ast_true(rval)) {
				use_cdr = 1;
				res = ast_cdr_register("perl","Perl CDR", perl_log);
				if (res) 
					ast_log(LOG_ERROR, "Unable to register Perl CDR handling\n");
			} else
				ast_log(LOG_NOTICE, "Perl CDR Disabled.\n");
		} else 
			ast_log(LOG_NOTICE, "Perl CDR Disabled.\n");
	
		if (hv_exists(PERL_CONFIG,"USE_SWITCH",strlen("USE_SWITCH"))) {
			rval = get_hash_val(my_perl,PERL_CONFIG,"USE_SWITCH");
			if (rval && ast_true(rval)) {
				use_switch = 1;
				if (ast_register_switch(&perl_switch))
					ast_log(LOG_ERROR, "Unable to register Perl Switch\n");
				else
					ast_log(LOG_NOTICE, "Registering Perl Switch\n");
			} else
				ast_log(LOG_NOTICE, "Perl Switch Disabled.\n");
		} else
			ast_log(LOG_NOTICE, "Perl Switch Disabled.\n");
		
	
	} else
		ast_log(LOG_WARNING,"CONFIG HASH TABLE %%PERL_CONFIG NOT FOUND MANY FEATURES DISABLED!\n");

	return ast_register_application(app, perl_exec, synopsis, descrip);
}




char *description(void) {
    return tdesc;
}

int usecount(void) {
    int res;
    STANDARD_USECOUNT(res);
    return res;
}

char *key() {
    return ASTERISK_GPL_KEY;
}

--- NEW FILE: res_perl.h ---
#ifndef __RES_PERL_H
#define __RES_PERL_H
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/astdb.h>
#include <asterisk/cli.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/image.h>
#include <asterisk/say.h>
#include <asterisk/app.h>
#include <asterisk/dsp.h>
#include <asterisk/musiconhold.h>
#include <asterisk.h>
#include <arpa/inet.h>
#include <asterisk/ast_expr.h>
#include <asterisk/callerid.h>
#include <asterisk/cdr.h>
#include <asterisk/channel.h>
#include <asterisk/channel_pvt.h>
#include <asterisk/cli.h>
#include <asterisk/config.h>
#include <asterisk/config_pvt.h>
#include <asterisk/file.h>
#include <asterisk/linkedlists.h>
#include <asterisk/lock.h>
#include <asterisk/logger.h>
#include <asterisk/manager.h>
#include <asterisk/md5.h>
#include <asterisk/module.h>
#include <asterisk/options.h>
#include <asterisk/pbx.h>
#include <asterisk/utils.h>
#include <asterisk/say.h>
#include <asterisk/term.h>
#include <asterisk/features.h>
#include <EXTERN.h>
#include <perl.h>
#include <sys/time.h>

EXTERN_C void xs_init (pTHX);
void *perl_thread(void *ignore);
AV *eval_some_perl(PerlInterpreter *perl,char *func,char *arg);
int can_run_nochan(char *test);
int process_perl_return_value(struct ast_channel *chan,char *ret);

#ifdef HAVE_RES_CONFIG
struct ast_config *perl_config(char *file, struct ast_config *new_config_s,struct ast_category **new_cat_p,struct ast_variable **new_v_p,int recur
#ifdef PRESERVE_COMMENTS
							   ,struct ast_comment_struct *acs
#endif

							   );

#endif

void launch_perl_thread(char *function);

#endif




More information about the svn-commits mailing list