| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-09-15 15:44:26 +00:00
										 |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-01-21 07:06:25 +00:00
										 |  |  |  * Copyright (C)  2004 - 2005 Steve Rodgers | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Steve Rodgers <hwstar@rodgers.sdcoxmail.com> | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-09-15 15:44:26 +00:00
										 |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  |  * This program is free software, distributed under the terms of | 
					
						
							| 
									
										
										
										
											2005-09-15 15:44:26 +00:00
										 |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  | /*! \file
 | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  |  * \brief Central Station Alarm receiver for Ademco Contact ID | 
					
						
							| 
									
										
										
										
											2005-11-06 15:09:47 +00:00
										 |  |  |  * \author Steve Rodgers <hwstar@rodgers.sdcoxmail.com> | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2006-06-07 18:54:56 +00:00
										 |  |  |  * Use at your own risk. Please consult the GNU GPL license document included with Asterisk.         * | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-11-06 15:09:47 +00:00
										 |  |  |  * \ingroup applications | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-14 20:28:54 +00:00
										 |  |  | /*** MODULEINFO
 | 
					
						
							|  |  |  | 	<support_level>extended</support_level> | 
					
						
							|  |  |  |  ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-07 18:54:56 +00:00
										 |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-06 22:39:32 +00:00
										 |  |  | #include <math.h>
 | 
					
						
							|  |  |  | #include <sys/wait.h>
 | 
					
						
							|  |  |  | #include <sys/time.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-21 06:02:45 +00:00
										 |  |  | #include "asterisk/lock.h"
 | 
					
						
							|  |  |  | #include "asterisk/file.h"
 | 
					
						
							|  |  |  | #include "asterisk/channel.h"
 | 
					
						
							|  |  |  | #include "asterisk/pbx.h"
 | 
					
						
							|  |  |  | #include "asterisk/module.h"
 | 
					
						
							|  |  |  | #include "asterisk/translate.h"
 | 
					
						
							|  |  |  | #include "asterisk/ulaw.h"
 | 
					
						
							|  |  |  | #include "asterisk/app.h"
 | 
					
						
							|  |  |  | #include "asterisk/dsp.h"
 | 
					
						
							|  |  |  | #include "asterisk/config.h"
 | 
					
						
							|  |  |  | #include "asterisk/localtime.h"
 | 
					
						
							|  |  |  | #include "asterisk/callerid.h"
 | 
					
						
							|  |  |  | #include "asterisk/astdb.h"
 | 
					
						
							| 
									
										
										
										
											2006-01-11 22:41:34 +00:00
										 |  |  | #include "asterisk/utils.h"
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define ALMRCV_CONFIG "alarmreceiver.conf"
 | 
					
						
							|  |  |  | #define ADEMCO_CONTACT_ID "ADEMCO_CONTACT_ID"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct event_node{ | 
					
						
							|  |  |  | 	char data[17]; | 
					
						
							|  |  |  | 	struct event_node *next; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct event_node event_node_t; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-07 14:55:51 +00:00
										 |  |  | static const char app[] = "AlarmReceiver"; | 
					
						
							| 
									
										
										
										
											2008-11-01 21:10:07 +00:00
										 |  |  | /*** DOCUMENTATION
 | 
					
						
							|  |  |  | 	<application name="AlarmReceiver" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							| 
									
										
										
										
											2008-11-05 14:37:07 +00:00
										 |  |  | 			Provide support for receiving alarm reports from a burglar or fire alarm panel. | 
					
						
							| 
									
										
										
										
											2008-11-01 21:10:07 +00:00
										 |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax /> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>This application should be called whenever there is an alarm panel calling in to dump its events. | 
					
						
							| 
									
										
										
										
											2008-11-05 14:37:07 +00:00
										 |  |  | 			The application will handshake with the alarm panel, and receive events, validate them, handshake them, | 
					
						
							|  |  |  | 			and store them until the panel hangs up. Once the panel hangs up, the application will run the system | 
					
						
							|  |  |  | 			command specified by the eventcmd setting in <filename>alarmreceiver.conf</filename> and pipe the | 
					
						
							|  |  |  | 			events to the standard input of the application. | 
					
						
							|  |  |  | 			The configuration file also contains settings for DTMF timing, and for the loudness of the | 
					
						
							|  |  |  | 			acknowledgement tones.</para> | 
					
						
							| 
									
										
										
										
											2008-11-01 21:10:07 +00:00
										 |  |  | 			<note><para>Only 1 signalling format is supported at this time: Ademco Contact ID.</para></note> | 
					
						
							|  |  |  | 		</description> | 
					
						
							| 
									
										
										
										
											2008-11-05 14:37:07 +00:00
										 |  |  | 		<see-also> | 
					
						
							|  |  |  | 			<ref type="filename">alarmreceiver.conf</ref> | 
					
						
							|  |  |  | 		</see-also> | 
					
						
							| 
									
										
										
										
											2008-11-01 21:10:07 +00:00
										 |  |  | 	</application> | 
					
						
							|  |  |  |  ***/ | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Config Variables */ | 
					
						
							|  |  |  | static int fdtimeout = 2000; | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | static int sdtimeout = 200; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | static int toneloudness = 4096; | 
					
						
							|  |  |  | static int log_individual_events = 0; | 
					
						
							|  |  |  | static char event_spool_dir[128] = {'\0'}; | 
					
						
							|  |  |  | static char event_app[128] = {'\0'}; | 
					
						
							|  |  |  | static char db_family[128] = {'\0'}; | 
					
						
							|  |  |  | static char time_stamp_format[128] = {"%a %b %d, %Y @ %H:%M:%S %Z"}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Misc variables */ | 
					
						
							|  |  |  | static char event_file[14] = "/event-XXXXXX"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | * Attempt to access a database variable and increment it, | 
					
						
							|  |  |  | * provided that the user defined db-family in alarmreceiver.conf | 
					
						
							|  |  |  | * The alarmreceiver app will write statistics to a few variables | 
					
						
							|  |  |  | * in this family if it is defined. If the new key doesn't exist in the | 
					
						
							|  |  |  | * family, then create it and set its value to 1. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | static void database_increment( char *key ) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							|  |  |  | 	unsigned v; | 
					
						
							|  |  |  | 	char value[16]; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2005-10-26 19:48:14 +00:00
										 |  |  | 	if (ast_strlen_zero(db_family)) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		return; /* If not defined, don't do anything */ | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	res = ast_db_get(db_family, key, value, sizeof(value) - 1); | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	if (res) { | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 		ast_verb(4, "AlarmReceiver: Creating database entry %s and setting to 1\n", key); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		/* Guess we have to create it */ | 
					
						
							|  |  |  | 		res = ast_db_put(db_family, key, "1"); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2009-08-10 19:20:57 +00:00
										 |  |  | 	sscanf(value, "%30u", &v); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	v++; | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-05 23:00:15 +00:00
										 |  |  | 	ast_verb(4, "AlarmReceiver: New value for %s: %u\n", key, v); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-07-14 07:22:30 +00:00
										 |  |  | 	snprintf(value, sizeof(value), "%u", v); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	res = ast_db_put(db_family, key, value); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-05 23:00:15 +00:00
										 |  |  | 	if (res) | 
					
						
							|  |  |  | 		ast_verb(4, "AlarmReceiver: database_increment write error\n"); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | * Build a MuLaw data block for a single frequency tone | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | static void make_tone_burst(unsigned char *data, float freq, float loudness, int len, int *x) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int     i; | 
					
						
							|  |  |  | 	float   val; | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < len; i++) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		val = loudness * sin((freq * 2.0 * M_PI * (*x)++)/8000.0); | 
					
						
							|  |  |  | 		data[i] = AST_LIN2MU((int)val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* wrap back around from 8000 */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	if (*x >= 8000) | 
					
						
							|  |  |  | 		*x = 0; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | * Send a single tone burst for a specifed duration and frequency. | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | * Returns 0 if successful | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | static int send_tone_burst(struct ast_channel *chan, float freq, int duration, int tldn) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							|  |  |  | 	int i = 0; | 
					
						
							|  |  |  | 	int x = 0; | 
					
						
							|  |  |  | 	struct ast_frame *f, wf; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	struct { | 
					
						
							|  |  |  | 		unsigned char offset[AST_FRIENDLY_OFFSET]; | 
					
						
							|  |  |  | 		unsigned char buf[640]; | 
					
						
							|  |  |  | 	} tone_block; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	for (;;) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (ast_waitfor(chan, -1) < 0) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			res = -1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		f = ast_read(chan); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (!f) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			res = -1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		if (f->frametype == AST_FRAME_VOICE) { | 
					
						
							|  |  |  | 			wf.frametype = AST_FRAME_VOICE; | 
					
						
							| 
									
										
										
										
											2011-02-03 16:22:10 +00:00
										 |  |  | 			ast_format_set(&wf.subclass.format, AST_FORMAT_ULAW, 0); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			wf.offset = AST_FRIENDLY_OFFSET; | 
					
						
							|  |  |  | 			wf.mallocd = 0; | 
					
						
							| 
									
										
										
										
											2008-05-22 16:29:54 +00:00
										 |  |  | 			wf.data.ptr = tone_block.buf; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			wf.datalen = f->datalen; | 
					
						
							|  |  |  | 			wf.samples = wf.datalen; | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			make_tone_burst(tone_block.buf, freq, (float) tldn, wf.datalen, &x); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			i += wf.datalen / 8; | 
					
						
							|  |  |  | 			if (i > duration) { | 
					
						
							| 
									
										
										
										
											2006-06-11 20:39:19 +00:00
										 |  |  | 				ast_frfree(f); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 			if (ast_write(chan, &wf)) { | 
					
						
							| 
									
										
										
										
											2012-01-09 22:15:50 +00:00
										 |  |  | 				ast_verb(4, "AlarmReceiver: Failed to write frame on %s\n", ast_channel_name(chan)); | 
					
						
							|  |  |  | 				ast_log(LOG_WARNING, "AlarmReceiver Failed to write frame on %s\n",ast_channel_name(chan)); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 				res = -1; | 
					
						
							| 
									
										
										
										
											2006-06-11 20:39:19 +00:00
										 |  |  | 				ast_frfree(f); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		ast_frfree(f); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | * Receive a string of DTMF digits where the length of the digit string is known in advance. Do not give preferential | 
					
						
							|  |  |  | * treatment to any digit value, and allow separate time out values to be specified for the first digit and all subsequent | 
					
						
							|  |  |  | * digits. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * Returns 0 if all digits successfully received. | 
					
						
							|  |  |  | * Returns 1 if a digit time out occurred | 
					
						
							|  |  |  | * Returns -1 if the caller hung up or there was a channel error. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int length, int fdto, int sdto) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							|  |  |  | 	int i = 0; | 
					
						
							|  |  |  | 	int r; | 
					
						
							|  |  |  | 	struct ast_frame *f; | 
					
						
							| 
									
										
										
										
											2005-07-15 23:00:47 +00:00
										 |  |  | 	struct timeval lastdigittime; | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-07-15 23:00:47 +00:00
										 |  |  | 	lastdigittime = ast_tvnow(); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	for (;;) { | 
					
						
							|  |  |  | 		/* if outa time, leave */ | 
					
						
							|  |  |  | 		if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((i > 0) ? sdto : fdto)) { | 
					
						
							| 
									
										
										
										
											2012-01-09 22:15:50 +00:00
										 |  |  | 			ast_verb(4, "AlarmReceiver: DTMF Digit Timeout on %s\n", ast_channel_name(chan)); | 
					
						
							|  |  |  | 			ast_debug(1,"AlarmReceiver: DTMF timeout on chan %s\n",ast_channel_name(chan)); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			res = 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-08 20:49:48 +00:00
										 |  |  | 		if ((r = ast_waitfor(chan, -1)) < 0) { | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 			ast_debug(1, "Waitfor returned %d\n", r); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		f = ast_read(chan); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (f == NULL) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			res = -1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		/* If they hung up, leave */ | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 		if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP)) { | 
					
						
							| 
									
										
										
										
											2008-05-22 16:29:54 +00:00
										 |  |  | 			if (f->data.uint32) { | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 				ast_channel_hangupcause_set(chan, f->data.uint32); | 
					
						
							| 
									
										
										
										
											2008-04-24 22:16:48 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			ast_frfree(f); | 
					
						
							|  |  |  | 			res = -1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		/* if not DTMF, just do it again */ | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (f->frametype != AST_FRAME_DTMF) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			ast_frfree(f); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 		digit_string[i++] = f->subclass.integer;  /* save digit */ | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		ast_frfree(f); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		/* If we have all the digits we expect, leave */ | 
					
						
							|  |  |  | 		if(i >= length) | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-07-15 23:00:47 +00:00
										 |  |  | 		lastdigittime = ast_tvnow(); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	digit_string[i] = '\0'; /* Nul terminate the end of the digit string */ | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | * Write the metadata to the log file | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | static int write_metadata( FILE *logfile, char *signalling_type, struct ast_channel *chan) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							| 
									
										
										
										
											2007-07-18 19:47:20 +00:00
										 |  |  | 	struct timeval t; | 
					
						
							|  |  |  | 	struct ast_tm now; | 
					
						
							| 
									
										
										
										
											2010-07-14 15:48:36 +00:00
										 |  |  | 	char *cl; | 
					
						
							|  |  |  | 	char *cn; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	char workstring[80]; | 
					
						
							|  |  |  | 	char timestamp[80]; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	/* Extract the caller ID location */ | 
					
						
							| 
									
										
										
										
											2010-07-14 15:48:36 +00:00
										 |  |  | 	ast_copy_string(workstring, | 
					
						
							| 
									
										
										
										
											2012-02-29 16:52:47 +00:00
										 |  |  | 		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""), | 
					
						
							| 
									
										
										
										
											2010-07-14 15:48:36 +00:00
										 |  |  | 		sizeof(workstring)); | 
					
						
							|  |  |  | 	ast_shrink_phone_number(workstring); | 
					
						
							|  |  |  | 	if (ast_strlen_zero(workstring)) { | 
					
						
							|  |  |  | 		cl = "<unknown>"; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		cl = workstring; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-02-29 16:52:47 +00:00
										 |  |  | 	cn = S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "<unknown>"); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Get the current time */ | 
					
						
							| 
									
										
										
										
											2007-07-18 19:47:20 +00:00
										 |  |  | 	t = ast_tvnow(); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	ast_localtime(&t, &now, NULL); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	/* Format the time */ | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	ast_strftime(timestamp, sizeof(timestamp), time_stamp_format, &now); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	res = fprintf(logfile, "\n\n[metadata]\n\n"); | 
					
						
							| 
									
										
										
										
											2010-07-14 15:48:36 +00:00
										 |  |  | 	if (res >= 0) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		res = fprintf(logfile, "PROTOCOL=%s\n", signalling_type); | 
					
						
							| 
									
										
										
										
											2010-07-14 15:48:36 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (res >= 0) { | 
					
						
							|  |  |  | 		res = fprintf(logfile, "CALLINGFROM=%s\n", cl); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (res >= 0) { | 
					
						
							|  |  |  | 		res = fprintf(logfile, "CALLERNAME=%s\n", cn); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (res >= 0) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		res = fprintf(logfile, "TIMESTAMP=%s\n\n", timestamp); | 
					
						
							| 
									
										
										
										
											2010-07-14 15:48:36 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (res >= 0) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		res = fprintf(logfile, "[events]\n\n"); | 
					
						
							| 
									
										
										
										
											2010-07-14 15:48:36 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	if (res < 0) { | 
					
						
							|  |  |  | 		ast_verb(3, "AlarmReceiver: can't write metadata\n"); | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 		ast_debug(1,"AlarmReceiver: can't write metadata\n"); | 
					
						
							| 
									
										
										
										
											2010-07-14 15:48:36 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		res = 0; | 
					
						
							| 
									
										
										
										
											2010-07-14 15:48:36 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | * Write a single event to the log file | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | static int write_event( FILE *logfile,  event_node_t *event) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	if (fprintf(logfile, "%s\n", event->data) < 0) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		res = -1; | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | * If we are configured to log events, do so here. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | static int log_events(struct ast_channel *chan,  char *signalling_type, event_node_t *event) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							| 
									
										
										
										
											2004-07-14 07:22:30 +00:00
										 |  |  | 	char workstring[sizeof(event_spool_dir)+sizeof(event_file)] = ""; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	int fd; | 
					
						
							|  |  |  | 	FILE *logfile; | 
					
						
							|  |  |  | 	event_node_t *elp = event; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2005-10-26 19:48:14 +00:00
										 |  |  | 	if (!ast_strlen_zero(event_spool_dir)) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		/* Make a template */ | 
					
						
							| 
									
										
										
										
											2005-07-10 23:12:25 +00:00
										 |  |  | 		ast_copy_string(workstring, event_spool_dir, sizeof(workstring)); | 
					
						
							| 
									
										
										
										
											2004-07-14 07:22:30 +00:00
										 |  |  | 		strncat(workstring, event_file, sizeof(workstring) - strlen(workstring) - 1); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		/* Make the temporary file */ | 
					
						
							|  |  |  | 		fd = mkstemp(workstring); | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (fd == -1) { | 
					
						
							|  |  |  | 			ast_verb(3, "AlarmReceiver: can't make temporary file\n"); | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 			ast_debug(1,"AlarmReceiver: can't make temporary file\n"); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			res = -1; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (!res) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			logfile = fdopen(fd, "w"); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 			if (logfile) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 				/* Write the file */ | 
					
						
							|  |  |  | 				res = write_metadata(logfile, signalling_type, chan); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 				if (!res) | 
					
						
							|  |  |  | 					while ((!res) && (elp != NULL)) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 						res = write_event(logfile, elp); | 
					
						
							|  |  |  | 						elp = elp->next; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 				if (!res) { | 
					
						
							|  |  |  | 					if (fflush(logfile) == EOF) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 						res = -1; | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 					if (!res) { | 
					
						
							|  |  |  | 						if (fclose(logfile) == EOF) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 							res = -1; | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 			} else | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 				res = -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | * This function implements the logic to receive the Ademco contact ID  format. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * The function will return 0 when the caller hangs up, else a -1 if there was a problem. | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static int receive_ademco_contact_id(struct ast_channel *chan, const void *data, int fdto, int sdto, int tldn, event_node_t **ehead) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	int i, j; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	int res = 0; | 
					
						
							|  |  |  | 	int checksum; | 
					
						
							|  |  |  | 	char event[17]; | 
					
						
							|  |  |  | 	event_node_t *enew, *elp; | 
					
						
							|  |  |  | 	int got_some_digits = 0; | 
					
						
							|  |  |  | 	int events_received = 0; | 
					
						
							|  |  |  | 	int ack_retries = 0; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	static char digit_map[15] = "0123456789*#ABC"; | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	static unsigned char digit_weights[15] = {10,1,2,3,4,5,6,7,8,9,11,12,13,14,15}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	database_increment("calls-received"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Wait for first event */ | 
					
						
							| 
									
										
										
										
											2008-02-05 23:00:15 +00:00
										 |  |  | 	ast_verb(4, "AlarmReceiver: Waiting for first event from panel\n"); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	while (res >= 0) { | 
					
						
							|  |  |  | 		if (got_some_digits == 0) { | 
					
						
							|  |  |  | 			/* Send ACK tone sequence */ | 
					
						
							|  |  |  | 			ast_verb(4, "AlarmReceiver: Sending 1400Hz 100ms burst (ACK)\n"); | 
					
						
							|  |  |  | 			res = send_tone_burst(chan, 1400.0, 100, tldn); | 
					
						
							|  |  |  | 			if (!res) | 
					
						
							|  |  |  | 				res = ast_safe_sleep(chan, 100); | 
					
						
							|  |  |  | 			if (!res) { | 
					
						
							|  |  |  | 				ast_verb(4, "AlarmReceiver: Sending 2300Hz 100ms burst (ACK)\n"); | 
					
						
							|  |  |  | 				res = send_tone_burst(chan, 2300.0, 100, tldn); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if ( res >= 0) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			res = receive_dtmf_digits(chan, event, sizeof(event) - 1, fdto, sdto); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (res < 0) { | 
					
						
							|  |  |  | 			if (events_received == 0) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 				/* Hangup with no events received should be logged in the DB */ | 
					
						
							|  |  |  | 				database_increment("no-events-received"); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				if (ack_retries) { | 
					
						
							| 
									
										
										
										
											2008-02-05 23:00:15 +00:00
										 |  |  | 					ast_verb(4, "AlarmReceiver: ACK retries during this call: %d\n", ack_retries); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 					database_increment("ack-retries"); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-02-05 23:00:15 +00:00
										 |  |  | 			ast_verb(4, "AlarmReceiver: App exiting...\n"); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			res = -1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (res != 0) { | 
					
						
							|  |  |  | 			/* Didn't get all of the digits */ | 
					
						
							| 
									
										
										
										
											2008-02-05 23:00:15 +00:00
										 |  |  | 			ast_verb(2, "AlarmReceiver: Incomplete string: %s, trying again...\n", event); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 			if (!got_some_digits) { | 
					
						
							| 
									
										
										
										
											2005-10-26 19:48:14 +00:00
										 |  |  | 				got_some_digits = (!ast_strlen_zero(event)) ? 1 : 0; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 				ack_retries++; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		got_some_digits = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 		ast_verb(2, "AlarmReceiver: Received Event %s\n", event); | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 		ast_debug(1, "AlarmReceiver: Received event: %s\n", event); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		/* Calculate checksum */ | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		for (j = 0, checksum = 0; j < 16; j++) { | 
					
						
							|  |  |  | 			for (i = 0; i < sizeof(digit_map); i++) { | 
					
						
							|  |  |  | 				if (digit_map[i] == event[j]) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if (i == 16) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			checksum += digit_weights[i]; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (i == 16) { | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 			ast_verb(2, "AlarmReceiver: Bad DTMF character %c, trying again\n", event[j]); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			continue; /* Bad character */ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Checksum is mod(15) of the total */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		checksum = checksum % 15; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-04 16:59:27 +00:00
										 |  |  | 		if (checksum) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			database_increment("checksum-errors"); | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 			ast_verb(2, "AlarmReceiver: Nonzero checksum\n"); | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 			ast_debug(1, "AlarmReceiver: Nonzero checksum\n"); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Check the message type for correctness */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (strncmp(event + 4, "18", 2)) { | 
					
						
							|  |  |  | 			if (strncmp(event + 4, "98", 2)) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 				database_increment("format-errors"); | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 				ast_verb(2, "AlarmReceiver: Wrong message type\n"); | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 				ast_debug(1, "AlarmReceiver: Wrong message type\n"); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		events_received++; | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* Queue the Event */ | 
					
						
							| 
									
										
										
										
											2006-01-11 22:41:34 +00:00
										 |  |  | 		if (!(enew = ast_calloc(1, sizeof(*enew)))) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			res = -1; | 
					
						
							| 
									
										
										
										
											2006-01-11 22:41:34 +00:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		enew->next = NULL; | 
					
						
							| 
									
										
										
										
											2005-07-10 23:12:25 +00:00
										 |  |  | 		ast_copy_string(enew->data, event, sizeof(enew->data)); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		* Insert event onto end of list | 
					
						
							|  |  |  | 		*/ | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (*ehead == NULL) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			*ehead = enew; | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		else { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			for(elp = *ehead; elp->next != NULL; elp = elp->next) | 
					
						
							|  |  |  | 			; | 
					
						
							|  |  |  | 			elp->next = enew; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (res > 0) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			res = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		/* Let the user have the option of logging the single event before sending the kissoff tone */ | 
					
						
							|  |  |  | 		if ((res == 0) && (log_individual_events)) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			res = log_events(chan, ADEMCO_CONTACT_ID, enew); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		/* Wait 200 msec before sending kissoff */ | 
					
						
							|  |  |  | 		if (res == 0) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			res = ast_safe_sleep(chan, 200); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Send the kissoff tone */ | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (res == 0) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			res = send_tone_burst(chan, 1400.0, 900, tldn); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | * This is the main function called by Asterisk Core whenever the App is invoked in the extension logic. | 
					
						
							|  |  |  | * This function will always return 0. | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static int alarmreceiver_exec(struct ast_channel *chan, const char *data) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							|  |  |  | 	event_node_t *elp, *efree; | 
					
						
							| 
									
										
										
										
											2004-07-14 07:22:30 +00:00
										 |  |  | 	char signalling_type[64] = ""; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	event_node_t *event_head = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Set write and read formats to ULAW */ | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 	ast_verb(4, "AlarmReceiver: Setting read and write formats to ULAW\n"); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-03 16:22:10 +00:00
										 |  |  | 	if (ast_set_write_format_by_id(chan,AST_FORMAT_ULAW)) { | 
					
						
							| 
									
										
										
										
											2012-01-09 22:15:50 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",ast_channel_name(chan)); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-03 16:22:10 +00:00
										 |  |  | 	if (ast_set_read_format_by_id(chan,AST_FORMAT_ULAW)) { | 
					
						
							| 
									
										
										
										
											2012-01-09 22:15:50 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",ast_channel_name(chan)); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-26 17:52:15 +00:00
										 |  |  | 	/* Set default values for this invocation of the application */ | 
					
						
							| 
									
										
										
										
											2005-07-10 23:12:25 +00:00
										 |  |  | 	ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type)); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Answer the channel if it is not already */ | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 	ast_verb(4, "AlarmReceiver: Answering channel\n"); | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 	if (ast_channel_state(chan) != AST_STATE_UP) { | 
					
						
							| 
									
										
										
										
											2007-07-16 14:39:29 +00:00
										 |  |  | 		if ((res = ast_answer(chan))) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Wait for the connection to settle post-answer */ | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 	ast_verb(4, "AlarmReceiver: Waiting for connection to stabilize\n"); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	res = ast_safe_sleep(chan, 1250); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Attempt to receive the events */ | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	if (!res) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		/* Determine the protocol to receive in advance */ | 
					
						
							|  |  |  | 		/* Note: Ademco contact is the only one supported at this time */ | 
					
						
							|  |  |  | 		/* Others may be added later */ | 
					
						
							|  |  |  | 		if(!strcmp(signalling_type, ADEMCO_CONTACT_ID)) | 
					
						
							|  |  |  | 			receive_ademco_contact_id(chan, data, fdtimeout, sdtimeout, toneloudness, &event_head); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			res = -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	/* Events queued by receiver, write them all out here if so configured */ | 
					
						
							|  |  |  | 	if ((!res) && (log_individual_events == 0)) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		res = log_events(chan, signalling_type, event_head); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	* Do we exec a command line at the end? | 
					
						
							|  |  |  | 	*/ | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	if ((!res) && (!ast_strlen_zero(event_app)) && (event_head)) { | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 		ast_debug(1,"Alarmreceiver: executing: %s\n", event_app); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		ast_safe_system(event_app); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	* Free up the data allocated in our linked list | 
					
						
							|  |  |  | 	*/ | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	for (elp = event_head; (elp != NULL);) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		efree = elp; | 
					
						
							|  |  |  | 		elp = elp->next; | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 		ast_free(efree); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | * Load the configuration from the configuration file | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | static int load_config(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_config *cfg; | 
					
						
							| 
									
										
										
										
											2006-09-20 20:57:57 +00:00
										 |  |  | 	const char *p; | 
					
						
							| 
									
										
										
										
											2007-08-16 21:09:46 +00:00
										 |  |  | 	struct ast_flags config_flags = { 0 }; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Read in the config file */ | 
					
						
							| 
									
										
										
										
											2007-08-16 21:09:46 +00:00
										 |  |  | 	cfg = ast_config_load(ALMRCV_CONFIG, config_flags); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!cfg) { | 
					
						
							| 
									
										
										
										
											2008-02-05 23:00:15 +00:00
										 |  |  | 		ast_verb(4, "AlarmReceiver: No config file\n"); | 
					
						
							| 
									
										
										
										
											2006-08-31 21:00:20 +00:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2008-09-12 23:30:03 +00:00
										 |  |  | 	} else if (cfg == CONFIG_STATUS_FILEINVALID) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", ALMRCV_CONFIG); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		p = ast_variable_retrieve(cfg, "general", "eventcmd"); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (p) { | 
					
						
							| 
									
										
										
										
											2005-07-10 23:12:25 +00:00
										 |  |  | 			ast_copy_string(event_app, p, sizeof(event_app)); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		p = ast_variable_retrieve(cfg, "general", "loudness"); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (p) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			toneloudness = atoi(p); | 
					
						
							|  |  |  | 			if(toneloudness < 100) | 
					
						
							|  |  |  | 				toneloudness = 100; | 
					
						
							|  |  |  | 			if(toneloudness > 8192) | 
					
						
							|  |  |  | 				toneloudness = 8192; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		p = ast_variable_retrieve(cfg, "general", "fdtimeout"); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (p) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			fdtimeout = atoi(p); | 
					
						
							|  |  |  | 			if(fdtimeout < 1000) | 
					
						
							|  |  |  | 				fdtimeout = 1000; | 
					
						
							|  |  |  | 			if(fdtimeout > 10000) | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 				fdtimeout = 10000; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		p = ast_variable_retrieve(cfg, "general", "sdtimeout"); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (p) { | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			sdtimeout = atoi(p); | 
					
						
							|  |  |  | 			if(sdtimeout < 110) | 
					
						
							|  |  |  | 				sdtimeout = 110; | 
					
						
							|  |  |  | 			if(sdtimeout > 4000) | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 				sdtimeout = 4000; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		p = ast_variable_retrieve(cfg, "general", "logindividualevents"); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (p) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 			log_individual_events = ast_true(p); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		p = ast_variable_retrieve(cfg, "general", "eventspooldir"); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (p) { | 
					
						
							| 
									
										
										
										
											2005-07-10 23:12:25 +00:00
										 |  |  | 			ast_copy_string(event_spool_dir, p, sizeof(event_spool_dir)); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		p = ast_variable_retrieve(cfg, "general", "timestampformat"); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (p) { | 
					
						
							| 
									
										
										
										
											2005-07-10 23:12:25 +00:00
										 |  |  | 			ast_copy_string(time_stamp_format, p, sizeof(time_stamp_format)); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		p = ast_variable_retrieve(cfg, "general", "db-family"); | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 		if (p) { | 
					
						
							| 
									
										
										
										
											2005-07-10 23:12:25 +00:00
										 |  |  | 			ast_copy_string(db_family, p, sizeof(db_family)); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2005-01-25 06:10:20 +00:00
										 |  |  | 		ast_config_destroy(cfg); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-08-31 21:00:20 +00:00
										 |  |  | 	return 1; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | * These functions are required to implement an Asterisk App. | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int unload_module(void) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-07-16 13:35:20 +00:00
										 |  |  | 	return ast_unregister_application(app); | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int load_module(void) | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	if (load_config()) { | 
					
						
							| 
									
										
										
										
											2008-11-01 21:10:07 +00:00
										 |  |  | 		if (ast_register_application_xml(app, alarmreceiver_exec)) | 
					
						
							| 
									
										
										
										
											2007-12-26 20:02:27 +00:00
										 |  |  | 			return AST_MODULE_LOAD_FAILURE; | 
					
						
							|  |  |  | 		return AST_MODULE_LOAD_SUCCESS; | 
					
						
							| 
									
										
										
										
											2008-02-07 20:42:59 +00:00
										 |  |  | 	} else | 
					
						
							| 
									
										
										
										
											2006-08-31 21:00:20 +00:00
										 |  |  | 		return AST_MODULE_LOAD_DECLINE; | 
					
						
							| 
									
										
										
										
											2004-06-21 19:28:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Alarm Receiver for Asterisk"); |