[Asterisk-Users] app_valetparking.c

Paul Zimm pbzinc at dejazzd.com
Mon Jun 20 08:51:26 MST 2005


Try this

> Since www.bkw.org seems not to exist anymore (getting response from 
> some hosting provider), does anyone happend to have a copy of 
> app_valetparking.c from www.bkw.org - the one that should work with * 
> stable 1.0.X ? If so please contact me.
>
> One that can be downloaded from www.loligo.com dosn't compile with 
> 1.0.X, and SuperValletParking (www.asterlink.com/svp/) seems to be for 
> * HEAD (1.1.X), so it wont do me any good.
>

-------------- next part --------------
/*
 * Asterisk -- A telephony toolkit for Linux.
 *
 * Routines implementing call valetparking
 * 
 * Copyright (C) 1999, Mark Spencer
 *
 * Mark Spencer <markster at linux-support.net>
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License
 */

#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/options.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/say.h>
#include <asterisk/callerid.h>
#include <asterisk/channel_pvt.h>
#include <asterisk/parking.h>
#include <asterisk/musiconhold.h>
#include <asterisk/config.h>
#include <asterisk/cli.h>
#include <asterisk/app.h>
#include <asterisk/manager.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>

#include <pthread.h>

#define DEFAULT_VALETPARK_TIME 45000

static char *valetparking = "ValetParking";
static char *valetparkedcall = "ValetParkCall";
static char *valetunparkedcall = "ValetUnparkCall";
static char *valetparklist = "ValetParkList";

/* No more than 45 seconds valetparked before you do something with them */
static int valetparkingtime = DEFAULT_VALETPARK_TIME;

/* First available extension for valetparking */
static int valetparking_start = 1;

/* Last available extension for valetparking */
static int valetparking_stop = 10000;

static char *vpsynopsis = "Valet Parking";

static char *vpcsynopsis = "Valet Park Call";

static char *vupsynopsis = "Valet UnPark Call";

static char *vlsynopsis = "ValetParkList";

static char *vpdesc =
"ValetParking(<exten>|<lotname>|<timeout>[|<return_ext>][|<return_pri>][|<return_context>])\n"
"Auto-Sense Valet Parking: if <exten> is not occupied, park it, if it is already parked, bridge to it.\n\n";

static char *vpcdesc =
"ValetParkCall(<exten>|<lotname>|<timeout>[|<return_ext>][|<return_pri>][|<return_context>])\n"
"Park Call at <exten> in <lotname> until someone calls ValetUnparkCall on the same <exten> + <lotname>\n"
"set <exten> to 'auto' to auto-choose the slot.\n\n";

static char *vupdesc =
"ValetUnparkCall(<exten>|<lotname>)\n"
"Un-Park the call at <exten> in lot <lotname> use 'fifo' or 'filo' for auto-ordered Un-Park.\n\n";

static char *vldesc =
"ValetParkList(<lotname>)\n"
"Audibly list the slot number of all the calls in <lotname> press * to unpark it.\n\n";

struct valetparkeduser {
	struct ast_channel *chan;
	struct timeval start;
	int valetparkingnum;
	/* Where to go if our valetparking time expires */
	char context[AST_MAX_EXTENSION];
	char exten[AST_MAX_EXTENSION];
	char lotname[AST_MAX_EXTENSION];
	int priority;
	int valetparkingtime;
	struct valetparkeduser *next;
};

static struct valetparkeduser *valetparkinglot;

static ast_mutex_t valetparking_lock = AST_MUTEX_INITIALIZER;

static pthread_t valetparking_thread;

STANDARD_LOCAL_USER;

LOCAL_USER_DECL;

static int valetparking_count(void)
{
	struct valetparkeduser *cur;
	int x=0;
	ast_mutex_lock(&valetparking_lock);
	for(cur = valetparkinglot;cur;cur = cur->next)
		x++;
	ast_mutex_unlock(&valetparking_lock);
	return x;
}

static int valetparking_say(struct ast_channel *chan,char *lotname)
{
	struct valetparkeduser *cur;
	int x=0,y=0,res=0;
	int list[1024];
	if(!lotname)
		return 0;
	ast_mutex_lock(&valetparking_lock);
	for(cur = valetparkinglot;cur;cur = cur->next)
		if(cur->lotname && !strcmp(lotname,cur->lotname))
			list[y++] = cur->valetparkingnum;
	ast_mutex_unlock(&valetparking_lock);
	for(x=0;x<y;x++) {
		ast_say_digits(chan,list[x], "", chan->language);
		res = ast_waitfordigit(chan,1500);
		if(res != 0) {
			res = list[x];
			break;
		}
	}
	return res;
}

static int ast_pop_valetparking_top(char *lotname)
{
	struct valetparkeduser *cur;

	ast_mutex_lock(&valetparking_lock);
	for(cur = valetparkinglot;cur;cur = cur->next)
		if(cur->lotname && !strcmp(lotname,cur->lotname))
			break;

	ast_mutex_unlock(&valetparking_lock);
	return cur ? cur->valetparkingnum : 0;
}

static int ast_pop_valetparking_bot(char *lotname)
{
	struct valetparkeduser *cur,*last=NULL;
	ast_mutex_lock(&valetparking_lock);
	for(cur = valetparkinglot;cur;cur = cur->next) {
		if(cur->lotname && !strcmp(lotname,cur->lotname)) {
			last = cur;
		}
	}
	ast_mutex_unlock(&valetparking_lock);
	return last ? last->valetparkingnum : 0;
}

static int ast_is_valetparked(char *exten,char *lotname)
{
	struct valetparkeduser *cur;
	int ext=0;
	int ret = 0;
	ext = atoi(exten);
	if(! ext > 0) {
		return ret;
	}
	ast_mutex_lock(&valetparking_lock);
	cur = valetparkinglot;
	while(cur) {
		if (cur->valetparkingnum == ext && lotname && cur->lotname && !strcmp(lotname,cur->lotname)) {
			ret = 1;
			break;
		}
		cur = cur->next;
	}
	ast_mutex_unlock(&valetparking_lock);
	return ret;
}

static int ast_valetpark_call(struct ast_channel *chan, int timeout, int *extout,char *lotname)
{
	/* We put the user in the valetparking list, then wake up the valetparking thread to be sure it looks
	   after these channels too */
	struct valetparkeduser *pu, *cur;
	int x;

	x = *extout;
	pu = malloc(sizeof(struct valetparkeduser));
	if (pu) {
		memset(pu,0,sizeof(struct valetparkeduser));
		ast_mutex_lock(&valetparking_lock);
		if(lotname) {
			strncpy(pu->lotname,lotname,sizeof(pu->lotname));
			if(chan->exten) 
				strncpy(pu->exten,chan->exten,sizeof(pu->exten)-1);
			if(chan->context)
				strncpy(pu->context,chan->context,sizeof(pu->context)-1);
			
			pu->priority = chan->priority;

			x = *extout;
			if(x == -1) {
				for (x=valetparking_start;x<=valetparking_stop;x++) {
					for(cur = valetparkinglot;cur;cur=cur->next) {
						if (cur->valetparkingnum == x && cur->lotname && !strcmp(cur->lotname,lotname))
							break;
					}
					if (!cur)
						break;
				}
			}
		}
		if (x <= valetparking_stop) {
			chan->appl = "Valet Parked Call";
			chan->data = NULL; 

			pu->chan = chan;
			/* Start music on hold */
			ast_moh_start(pu->chan, NULL);
			gettimeofday(&pu->start, NULL);
			pu->valetparkingnum = x;
			if (timeout >= 0)
				pu->valetparkingtime = timeout;
			else
				pu->valetparkingtime = valetparkingtime;

			*extout = x;
			/* Remember what had been dialed, so that if the valetparking
			   expires, we try to come back to the same place */
			if (strlen(chan->macrocontext))
				strncpy(pu->context, chan->macrocontext, sizeof(pu->context)-1);
			else
				strncpy(pu->context, chan->context, sizeof(pu->context)-1);
			if (strlen(chan->macroexten))
				strncpy(pu->exten, chan->macroexten, sizeof(pu->exten)-1);
			else
				strncpy(pu->exten, chan->exten, sizeof(pu->exten)-1);
			if (chan->macropriority)
				pu->priority = chan->macropriority;
			else
				pu->priority = chan->priority;
			pu->next = valetparkinglot;
			valetparkinglot = pu;
			ast_mutex_unlock(&valetparking_lock);
			/* Wake up the (presumably select()ing) thread */
			pthread_kill(valetparking_thread, SIGURG);
			if (option_verbose > 1) 
				ast_verbose(VERBOSE_PREFIX_2 "Valet Parked %s on slot %d\n", pu->chan->name, pu->valetparkingnum);

				manager_event(EVENT_FLAG_CALL, "VirtualValetparkedCall",
							  "Exten: %d\r\n"
							  "Channel: %s\r\n"
							  "LotName: %s\r\n"
							  "Timeout: %ld\r\n"
							  "CallerID: %s\r\n"
							  ,pu->valetparkingnum, pu->chan->name, lotname
							  ,(long)pu->start.tv_sec + (long)(pu->valetparkingtime/1000) - (long)time(NULL)
							  ,(pu->chan->callerid ? pu->chan->callerid : "")
							  );
				return 0;
		} else {
			ast_log(LOG_WARNING, "No more valetparking spaces\n");
			free(pu);
			ast_mutex_unlock(&valetparking_lock);
			return -1;
		}
	} else {
		ast_log(LOG_WARNING, "Out of memory\n");
		return -1;
	}
	return 0;
}

static int ast_masq_valetpark_call(struct ast_channel *rchan,int timeout, int *extout,char *lotname)
{
	struct ast_channel *chan;
	struct ast_frame *f;

	/* Make a new, fake channel that we'll use to masquerade in the real one */
	chan = ast_channel_alloc(0);
	if (chan) {
		/* Let us keep track of the channel name */
		snprintf(chan->name, sizeof (chan->name), "ValetParked/%s",rchan->name);
		/* Make formats okay */
		chan->readformat = rchan->readformat;
		chan->writeformat = rchan->writeformat;
		ast_channel_masquerade(chan, rchan);
		/* Setup the extensions and such */
		strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
		strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
		chan->priority = rchan->priority;
		/* Make the masq execute */
		f = ast_read(chan);
		if (f)
			ast_frfree(f);
		ast_valetpark_call(chan, timeout, extout,lotname);
	} else {
		ast_log(LOG_WARNING, "Unable to create Valet Parked channel\n");
		return -1;
	}
	return 0;
}

static void *do_valetparking_thread(void *ignore)
{
	int ms, tms, max;
	struct valetparkeduser *pu, *pl, *pt = NULL;
	struct timeval tv;
	struct ast_frame *f;
	int x;
	int gc=0;
	fd_set rfds, efds;
	fd_set nrfds, nefds;
	FD_ZERO(&rfds);
	FD_ZERO(&efds);
	for (;;) {
		ms = -1;
		max = -1;
		ast_mutex_lock(&valetparking_lock);
		pl = NULL;
		pu = valetparkinglot;
		gettimeofday(&tv, NULL);
		FD_ZERO(&nrfds);
		FD_ZERO(&nefds);
		while(pu) {
			tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;

			if(gc < 5 && !pu->chan->generator) {
				gc++;
				ast_moh_start(pu->chan,NULL);
			}
			if(pu->valetparkingtime > 0 && tms > pu->valetparkingtime) {
				/* They've been waiting too long, send them back to where they came.  Theoretically they
				   should have their original extensions and such, but we copy to be on the safe side */
				strncpy(pu->chan->exten, pu->exten, sizeof(pu->chan->exten)-1);
				strncpy(pu->chan->context, pu->context, sizeof(pu->chan->context)-1);
				pu->chan->priority = pu->priority;
				/* Stop music on hold */
				ast_moh_stop(pu->chan);
				/* Start up the PBX, or hang them up */
				if (ast_pbx_start(pu->chan))  {
					ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
					ast_hangup(pu->chan);
				}
				/* And take them out of the valetparking lot */
				if (pl) 
					pl->next = pu->next;
				else
					valetparkinglot = pu->next;
				pt = pu;
				pu = pu->next;
				free(pt);
			} else {
				for (x=0;x<AST_MAX_FDS;x++) {
					if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
						if (FD_ISSET(pu->chan->fds[x], &efds))
							pu->chan->exception = 1;
						pu->chan->fdno = x;
						/* See if they need servicing */
						f = ast_read(pu->chan);
						if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
							/* There's a problem, hang them up*/
							if (option_verbose > 1) 
								ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being Valet Parked\n", pu->chan->name);
							ast_hangup(pu->chan);
							/* And take them out of the valetparking lot */
							if (pl) 
								pl->next = pu->next;
							else
								valetparkinglot = pu->next;
							pt = pu;
							pu = pu->next;
							free(pt);
							break;
						} else {
							/* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
							ast_frfree(f);
							goto std;	/* XXX Ick: jumping into an else statement??? XXX */
						}
					}
				}
				if (x >= AST_MAX_FDS) {
std:					for (x=0;x<AST_MAX_FDS;x++) {
						/* Keep this one for next one */
						if (pu->chan->fds[x] > -1) {
							FD_SET(pu->chan->fds[x], &nrfds);
							FD_SET(pu->chan->fds[x], &nefds);
							if (pu->chan->fds[x] > max)
								max = pu->chan->fds[x];
						}
					}
					/* Keep track of our longest wait */
					if ((tms < ms) || (ms < 0))
						ms = tms;
					pl = pu;
					pu = pu->next;
				}
			}
		}
		ast_mutex_unlock(&valetparking_lock);
		rfds = nrfds;
		efds = nefds;
		tv.tv_sec = ms / 1000;
		tv.tv_usec = (ms % 1000) * 1000;
		/* Wait for something to happen */
		ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
		pthread_testcancel();
	}
	return NULL;	/* Never reached */
}

static int ast_valetparking(struct ast_channel *chan, void *data) 
{
	struct localuser *u;
	char *appname;	
	char buf[512],*exten,*lotname,*to;
	struct ast_app *app;
	int res=0;

	if (!data) {
		ast_log(LOG_WARNING, "ValetParking requires an argument (extension number)\n");
		return -1;
	}

	exten=lotname=to=NULL;
	strncpy(buf,data,512);
	exten = buf;
	if((lotname=strchr(exten,'|'))) {
		*lotname = '\0';
		*lotname++;
        	if((to=strchr(lotname,'|'))) {
            		*to = '\0';
            		*to++;
        	}
	}
	if(exten[0] >= 97) {
		ast_log(LOG_WARNING, "ValetParking requires a numeric extension.\n");
        return -1;
	}
	appname = ast_is_valetparked(exten,lotname) ? "ValetParkCall" : "ValetUnparkCall";
	app = pbx_findapp(appname);
	LOCAL_USER_ADD(u);
	if(app) {
		res = pbx_exec(chan,app,data,1);
	} else {
		ast_log(LOG_WARNING, "Error: Can't find app %s\n",appname);
		res = -1;
	}
	LOCAL_USER_REMOVE(u);
	return res;
}

static int valetpark_call(struct ast_channel *chan, void *data)
{
	struct localuser *u;
	int timeout = DEFAULT_VALETPARK_TIME;
	int ext = 0,res = 0;
	char buf[512],*exten,*lotname,*to,*findme,*context,*priority=NULL,tmp[80];
	if (!data) {
		ast_log(LOG_WARNING, "ValetParkCall requires an argument (extension number)\n");
		return -1;
	}
	exten=lotname=to=findme=context=NULL;
	strncpy(buf,data,512);
	exten = buf;
	if((lotname=strchr(exten,'|'))) {
        *lotname = '\0';
        *lotname++;
        if((to=strchr(lotname,'|'))) {
            *to = '\0';
            *to++;
			timeout = atoi(to) * 1000;
			if((findme=strchr(to,'|'))) {
				*findme = '\0';
				*findme++;
				if((priority=strchr(findme,'|'))) {
					*priority = '\0';
					*priority++;
					if((context=strchr(priority,'|'))) {
						*context = '\0';
						*context++;
					}
				}
			}
		}
	}
	if(!lotname) {
		ast_log(LOG_WARNING,"Please specify a lotname in the dialplan.");
		return -1;
	}
	if(ast_is_valetparked(exten,lotname)) {
		ast_log(LOG_WARNING,"Call is already Valet Parked Here [%s]\n",exten);
		return -1;
	}
	LOCAL_USER_ADD(u);
	ast_answer(chan);
	if(exten && lotname) {
		if(!strcmp(exten,"auto"))
			ext = -1;
		else if(!strcmp(exten,"query")) {
			ast_waitfor(chan,-1);
			memset(&tmp,0,80);
			ast_streamfile(chan, "vm-extension", chan->language);
			res = ast_waitstream(chan, AST_DIGIT_ANY);
			if(res)
				return -1;

			ast_app_getdata(chan,"vm-then-pound",tmp,80,5000);
			if(tmp[0])
				ext = atoi(tmp);
		} else { 
			ext = atoi(exten);
		}
		if(ext == 0)
			ext = -1;
		if(findme)
			strncpy(chan->exten,findme,sizeof(chan->exten)-1);
		if (context)
			strncpy(chan->context, context, sizeof(chan->context)-1);
		if(priority) {
			chan->priority = atoi(priority);
			if(!chan->priority)
				chan->priority = 1;
		}
		ast_masq_valetpark_call(chan,timeout,&ext,lotname);
	}
	LOCAL_USER_REMOVE(u);
	return 1;
}

static int valetpark_list(struct ast_channel *chan, void *data)
{
	struct localuser *u;
	int res=0;
	struct ast_app *app;
	char buf[512];
	if(!data) {
		ast_log(LOG_WARNING,"Parameter 'lotname' is required.\n");
		return -1;
	}
	LOCAL_USER_ADD(u);
	res = valetparking_say(chan,data);
	if(res > 0) {
		app = pbx_findapp("ValetUnparkCall");
		if(app) {
			snprintf(buf,512,"%d|%s",res,(char *)data);
			res = pbx_exec(chan,app,buf,1);
		}
	}
	LOCAL_USER_REMOVE(u);
	return 1;
}

static int valetunpark_call(struct ast_channel *chan, void *data)
{
	int res=0;
	struct localuser *u;
	struct ast_channel *peer=NULL;
	struct valetparkeduser *pu, *pl=NULL;
	int valetpark=-1;
	int dres;
	struct ast_bridge_config config;
	char buf[512],tmp[80],*exten,*lotname;
	if (!data) {
		ast_log(LOG_WARNING, "Valetpark requires an argument (extension number)\n");
		return -1;
	}
	exten=lotname=NULL;
	strncpy(buf,data,512);
	exten = buf;
	if((lotname=strchr(exten,'|'))) {
		*lotname = '\0';
		*lotname++;
	}
	if(!lotname) {
		ast_log(LOG_WARNING,"Please specify a lotname in the dialplan.");
		return -1;
	}
	LOCAL_USER_ADD(u);
	ast_answer(chan);
	if(exten) {
		if(!strcmp(exten,"fifo")) {
			valetpark = ast_pop_valetparking_top(lotname);
		}
		else if(!strcmp(exten,"filo")) {
			valetpark = ast_pop_valetparking_bot(lotname);
		}
		else if(!strcmp(exten,"query")) {
			ast_waitfor(chan,-1);
			memset(&tmp,0,80);
			ast_streamfile(chan, "vm-extension", chan->language);
			res = ast_waitstream(chan, AST_DIGIT_ANY);
			if(res)
				return -1;
			ast_app_getdata(chan,"vm-then-pound",tmp,80,5000);
			if(tmp[0])
				valetpark = atoi(tmp);
		}
		else {
			valetpark = atoi(exten);
		}

		if(valetpark == 0) {
			ast_log(LOG_WARNING, "Nobody Valet Parked in %s",lotname);
			LOCAL_USER_REMOVE(u);
			return -1;
		}

	}
	else 
		valetpark = atoi((char *)data);
	ast_mutex_lock(&valetparking_lock);
	pu = valetparkinglot;
	while(pu) {
		if ((lotname && pu->valetparkingnum == valetpark && pu->lotname && !strcmp(pu->lotname,lotname)) 
			|| (! lotname && pu->valetparkingnum == valetpark)) {
			if (pl)
				pl->next = pu->next;
			else
				valetparkinglot = pu->next;
			break;
		}
		pl = pu;
		pu = pu->next;
	}
	ast_mutex_unlock(&valetparking_lock);
	if (pu) {
		peer = pu->chan;
		free(pu);
	}
	/* JK02: it helps to answer the channel if not already up */
	if (chan->_state != AST_STATE_UP) {
		ast_answer(chan);
	}

	if (peer) {
		ast_moh_stop(peer);
		res = ast_channel_make_compatible(chan, peer);
		if (res < 0) {
			ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
			ast_hangup(peer);
			LOCAL_USER_REMOVE(u);
			return -1;
		}
		/* This runs sorta backwards, since we give the incoming channel control, as if it
		   were the person called. */

		if (option_verbose > 2) 
			ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to Valet Parked call %d in lot %s\n", chan->name, valetpark,lotname);

		memset(&config,0,sizeof(struct ast_bridge_config));
		config.allowredirect_in = 1;
		config.allowredirect_out = 1;
		config.allowdisconnect = 0;
		config.timelimit = 0;
		config.play_warning = 0;
		config.warning_freq = 0;
		config.warning_sound=NULL;
		res = ast_bridge_call(chan,peer,&config);

		/* Simulate the PBX hanging up */
		if (res != AST_PBX_NO_HANGUP_PEER)
			ast_hangup(peer);
		LOCAL_USER_REMOVE(u);
		return res;
	} else {
		/* XXX Play a message XXX */
		dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
		if (!dres) {
			dres = ast_waitstream(chan, "");
	 	} else {
			ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
			res = 0;
		}
		if (option_verbose > 2) 
			ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to non-existant Valet Parked call %d\n", chan->name, valetpark);
		res = -1;
	}
	LOCAL_USER_REMOVE(u);
	return res;
}

static int handle_valetparkedcalls(int fd, int argc, char *argv[])
{
	struct valetparkeduser *cur;

	ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s %-6s %-15s\n", "Num", "Channel"
		, "Context", "Extension", "Pri", "Elapsed","Timeout","LotName");

	ast_mutex_lock(&valetparking_lock);

	cur=valetparkinglot;
	while(cur) {
		ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds %6lds %-15s\n"
			,cur->valetparkingnum, cur->chan->name, cur->context, cur->exten
			,cur->priority,(time(NULL) - cur->start.tv_sec),cur->valetparkingtime ? (cur->start.tv_sec +  (cur->valetparkingtime/1000) - time(NULL)) : 0,cur->lotname);

		cur = cur->next;
	}

	ast_mutex_unlock(&valetparking_lock);

	return RESULT_SUCCESS;
}

static char showvaletparked_help[] =
"Usage: show valetparkedcalls\n"
"       Lists currently Valet Parked calls.\n";

static struct ast_cli_entry showvaletparked =
{ { "show", "valetparkedcalls", NULL }, handle_valetparkedcalls, "Lists valetparked calls", showvaletparked_help };
/* Dump lot status */
static int manager_valetparking_status( struct mansession *s, struct message *m )
{
	struct valetparkeduser *cur;

	astman_send_ack(s, m, "Valet Parked calls will follow");

        ast_mutex_lock(&valetparking_lock);

        cur=valetparkinglot;
        while(cur) {
                ast_cli(s->fd, "Event: ValetParkedCall\r\n"
			"Exten: %d\r\n"
			"Channel: %s\r\n"
			"Timeout: %ld\r\n"
			"CallerID: %s\r\n"
			"\r\n"
                        ,cur->valetparkingnum, cur->chan->name
                        ,(long)cur->start.tv_sec + (long)(cur->valetparkingtime/1000) - (long)time(NULL)
			,(cur->chan->callerid ? cur->chan->callerid : "")
			);

                cur = cur->next;
        }

        ast_mutex_unlock(&valetparking_lock);

        return RESULT_SUCCESS;
}

int load_module(void)
{
	int res;

	ast_cli_register(&showvaletparked);
	valetparkingtime = DEFAULT_VALETPARK_TIME;
	pthread_create(&valetparking_thread, NULL, do_valetparking_thread, NULL);
	res = ast_register_application(valetunparkedcall, valetunpark_call, vupsynopsis, vupdesc);
	res = ast_register_application(valetparkedcall, valetpark_call, vpcsynopsis, vpcdesc);
	res = ast_register_application(valetparking, ast_valetparking, vpsynopsis, vpdesc);
	res = ast_register_application(valetparklist,valetpark_list, vlsynopsis, vldesc);



	if (!res) {
		ast_manager_register( "ValetparkedCalls", 0, manager_valetparking_status, "List valetparked calls" );
	}

	return res;
}

int unload_module(void)
{
	STANDARD_HANGUP_LOCALUSERS;

	if (!ast_mutex_lock(&valetparking_lock)) {
        if (valetparking_thread && (valetparking_thread != AST_PTHREADT_STOP)) {
            pthread_cancel(valetparking_thread);
            pthread_kill(valetparking_thread, SIGURG);
            pthread_join(valetparking_thread, NULL);
        }
        valetparking_thread = AST_PTHREADT_STOP;
        ast_mutex_unlock(&valetparking_lock);
    } else {
        ast_log(LOG_WARNING, "Unable to lock the valet\n");
        return -1;
    }


	ast_manager_unregister( "ValetparkedCalls" );
	ast_cli_unregister(&showvaletparked);
	ast_unregister_application(valetunparkedcall);
	ast_unregister_application(valetparkedcall);
	ast_unregister_application(valetparking);
	ast_unregister_application(valetparklist);
	return 0;
}

char *description(void)
{
	return "Valet Parking Application";
}

int usecount(void)
{
	int res;
	STANDARD_USECOUNT(res);
	res += valetparking_count();
	return res;
}

char *key()
{
	return ASTERISK_GPL_KEY;
}


More information about the asterisk-users mailing list