From 8b34dc8192c833c508cc10ad18ee61db73292ce6 Mon Sep 17 00:00:00 2001 From: Pedro Kiefer Date: Wed, 17 Oct 2012 19:02:46 +0000 Subject: Adds new formats to app_alarmreceiver, ALAW calls support and enhanced protection. Commiting this on behalf of Kaloyan Kovachev (license 5506). AlarmReceiver now supports the following DTMF signaling types: - ContactId - 4x1 - 4x2 - High Speed - Super Fast We are also auto-detecting which signaling is being received. So support for those protocols should work out-the-box. Correctly identify ALAW / ULAW calls. Some enhanced protection for broken panels and malicious callers where added. (closes issue ASTERISK-20289) Reported by: Kaloyan Kovachev Review: https://reviewboard.asterisk.org/r/2088/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@375150 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_alarmreceiver.c | 431 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 336 insertions(+), 95 deletions(-) (limited to 'apps/app_alarmreceiver.c') diff --git a/apps/app_alarmreceiver.c b/apps/app_alarmreceiver.c index be53c9713..e307626b5 100644 --- a/apps/app_alarmreceiver.c +++ b/apps/app_alarmreceiver.c @@ -34,7 +34,7 @@ * \addtogroup configuration_file Configuration Files */ -/*! +/*! * \page alarmreceiver.conf alarmreceiver.conf * \verbinclude alarmreceiver.conf.sample */ @@ -67,9 +67,65 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/indications.h" #define ALMRCV_CONFIG "alarmreceiver.conf" +#define UNKNOWN_FORMAT "UNKNOWN_FORMAT" + #define ADEMCO_CONTACT_ID "ADEMCO_CONTACT_ID" +/* + AAAA _ID_ P CCC XX ZZZ S + +where AAAA is the account number, _ID_ is 18 or 98, P is the pin status (alarm or restore), CCC +is the alarm code which is pre-defined by Ademco (but you may be able to reprogram it in the panel), XX +is the dialer group, partition or area number, ZZZ is the zone or user number and S is the checksum +*/ + +#define ADEMCO_EXPRESS_4_1 "ADEMCO_EXPRESS_4_1" +/* + AAAA _ID_ C S + +where AAAA is the account number, _ID_ is 17, C is the alarm code and S is the checksum. +*/ + +#define ADEMCO_EXPRESS_4_2 "ADEMCO_EXPRESS_4_2" +/* + AAAA _ID_ C Z S + +where AAAA is the account number, _ID_ is 27, C is the alarm code, Z is the zone or user number and S is the checksum. +*/ + +#define ADEMCO_HIGH_SPEED "ADEMCO_HIGH_SPEED" +/* + AAAA _ID_ PPPP PPPP X S + +where AAAA is the account number, _ID_ is 55, PPPP PPPP is the status of each zone, X +is a special digit which describes the type of information in the PPPP PPPP fields and S is checksum. +Each P field contains one of the following values: + 1 new alarm 3 new restore 5 normal + 2 new opening 4 new closing 6 outstanding +The X field contains one of the following values: + 0 AlarmNet messages + 1 ambush or duress + 2 opening by user (the first P field contains the user number) + 3 bypass (the P fields indicate which zones are bypassed) + 4 closing by user (the first P field contain the user number) + 5 trouble (the P fields contain which zones are in trouble) + 6 system trouble + 7 normal message (the P fields indicate zone status) + 8 low battery (the P fields indicate zone status) + 9 test (the P fields indicate zone status) +*/ +#define ADEMCO_SUPER_FAST "ADEMCO_SUPER_FAST" +/* + AAAA _ID_ PPPP PPPP X +where AAA is the account number, _ID_ is 56 +*/ + #define ADEMCO_MSG_TYPE_1 "18" #define ADEMCO_MSG_TYPE_2 "98" +#define ADEMCO_MSG_TYPE_3 "17" +#define ADEMCO_MSG_TYPE_4 "27" +#define ADEMCO_MSG_TYPE_5 "55" +#define ADEMCO_MSG_TYPE_6 "56" + #define ADEMCO_AUDIO_CALL_NEXT "606" struct { @@ -86,6 +142,8 @@ struct event_node{ typedef struct event_node event_node_t; +struct timeval call_start_time; + static const char app[] = "AlarmReceiver"; /*** DOCUMENTATION @@ -101,8 +159,20 @@ static const char app[] = "AlarmReceiver"; 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. - Only 1 signalling format is supported at this time: Ademco Contact ID. + Few Ademco DTMF signalling formats are detected automaticaly: Contact ID, Express 4+1, + Express 4+2, High Speed and Super Fast. + The application is affected by the following variables: + + + Maximum call time, in milliseconds. + If set, this variable causes application to exit after the specified time. + + + Maximum number of retries per call. + If set, this variable causes application to exit after the specified number of messages. + + alarmreceiver.conf @@ -112,8 +182,10 @@ static const char app[] = "AlarmReceiver"; /* Config Variables */ static int fdtimeout = 2000; static int sdtimeout = 200; +static int answait = 1250; static int toneloudness = 4096; static int log_individual_events = 0; +static int no_group_meta = 0; static char event_spool_dir[128] = {'\0'}; static char event_app[128] = {'\0'}; static char db_family[128] = {'\0'}; @@ -172,26 +244,24 @@ static void database_increment(char *key) * \param chan Asterisk Channel * \param digit_string Digits String * \param buf_size The size of the Digits String buffer - * \param length Length of the message we expect - * \param fdto First Digit Timeout - * \param sdto Other Digits Timeout + * \param expected Digits expected for this message type + * \param received Pointer to number of digits received so far * * \retval 0 if all digits were successfully received * \retval 1 if a timeout occurred * \retval -1 if the caller hung up or on channel errors */ -static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int buf_size, int length, int fdto, int sdto) +static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int buf_size, int expected, int *received) { int rtn = 0; - int i = 0; int r; struct ast_frame *f; struct timeval lastdigittime; lastdigittime = ast_tvnow(); - while (i < length && i < buf_size - 1) { + while (*received < expected && *received < buf_size - 1) { /* If timed out, leave */ - if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((i > 0) ? sdto : fdto)) { + if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((*received > 0) ? sdtimeout : fdtimeout)) { 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)); rtn = 1; @@ -226,14 +296,15 @@ static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int } /* Save digit */ - digit_string[i++] = f->subclass.integer; + digit_string[(*received)++] = f->subclass.integer; ast_frfree(f); lastdigittime = ast_tvnow(); } - /* Null terminate the end of the digit string */ - digit_string[i] = '\0'; + /* Null terminate the end of the digit_string */ + digit_string[*received] = '\0'; + return rtn; } @@ -243,11 +314,12 @@ static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int * \param logfile Log File Pointer * \param signalling_type Signaling Type * \param chan Asterisk Channel + * \param no_checksum Expecting messages without checksum * * \retval 0 success * \retval -1 failure */ -static int write_metadata(FILE *logfile, char *signalling_type, struct ast_channel *chan) +static int write_metadata(FILE *logfile, char *signalling_type, struct ast_channel *chan, int no_checksum) { struct timeval t; struct ast_tm now; @@ -276,18 +348,27 @@ static int write_metadata(FILE *logfile, char *signalling_type, struct ast_chann /* Format the time */ ast_strftime(timestamp, sizeof(timestamp), time_stamp_format, &now); - if (fprintf(logfile, "\n\n[metadata]\n\n" + if (no_group_meta && fprintf(logfile, "PROTOCOL=%s\n" + "CHECKSUM=%s\n" + "CALLINGFROM=%s\n" + "CALLERNAME=%s\n" + "TIMESTAMP=%s\n\n", + signalling_type, (!no_checksum) ? "yes" : "no", cl, cn, timestamp) > -1) { + return 0; + } else if (fprintf(logfile, "\n\n[metadata]\n\n" "PROTOCOL=%s\n" + "CHECKSUM=%s\n" "CALLINGFROM=%s\n" "CALLERNAME=%s\n" "TIMESTAMP=%s\n\n" - "[events]\n\n", signalling_type, cl, cn, timestamp) < 0) { - ast_verb(3, "AlarmReceiver: can't write metadata\n"); - ast_debug(1, "AlarmReceiver: can't write metadata\n"); - return -1; + "[events]\n\n", + signalling_type, (!no_checksum) ? "yes" : "no", cl, cn, timestamp) > -1) { + return 0; } - return 0; + ast_verb(3, "AlarmReceiver: can't write metadata\n"); + ast_debug(1, "AlarmReceiver: can't write metadata\n"); + return -1; } /*! @@ -301,23 +382,25 @@ static int write_metadata(FILE *logfile, char *signalling_type, struct ast_chann */ static int write_event(FILE *logfile, event_node_t *event) { - if (fprintf(logfile, "%s\n", event->data) < 0) { + if (fprintf(logfile, "%s%s\n", no_group_meta ? "event=" : "", event->data) < 0) { return -1; } + return 0; } /*! - * \brief Log events if configuration key logindividualevents is enabled + * \brief Log events if configuration key logindividualevents is enabled or on exit * * \param chan Asterisk Channel * \param signalling_type Signaling Type * \param event Event Structure + * \param no_checksum Expecting messages without checksum * * \retval 0 success * \retval -1 failure */ -static int log_events(struct ast_channel *chan, char *signalling_type, event_node_t *event) +static int log_events(struct ast_channel *chan, char *signalling_type, event_node_t *event, int no_checksum) { char workstring[sizeof(event_spool_dir) + sizeof(event_file)] = ""; int fd; @@ -344,13 +427,13 @@ static int log_events(struct ast_channel *chan, char *signalling_type, event_nod } /* Write the file */ - if (write_metadata(logfile, signalling_type, chan) != 0) { + if (write_metadata(logfile, signalling_type, chan, no_checksum)) { fflush(logfile); fclose(logfile); return -1; } - while ((write_event(logfile, elp) > 0) && (elp != NULL)) { + while ((elp != NULL) && (write_event(logfile, elp) == 0)) { elp = elp->next; } @@ -406,19 +489,18 @@ static int ademco_verify_checksum(char *event, int expected) * \param chan Asterisk Channel * \param tone_freq Frequency of the tone to send * \param tone_duration Tone duration in ms - * \param tldn Tone loudness * \param delay Delay before sending the tone * * \retval 0 success * \retval -1 failure */ -static int send_tone_burst(struct ast_channel *chan, const char *tone_freq, int tone_duration, int tldn, int delay) +static int send_tone_burst(struct ast_channel *chan, const char *tone_freq, int tone_duration, int delay) { if (delay && ast_safe_sleep(chan, delay)) { return -1; } - if (ast_playtones_start(chan, tldn, tone_freq, 0)) { + if (ast_playtones_start(chan, toneloudness, tone_freq, 0)) { return -1; } @@ -431,26 +513,113 @@ static int send_tone_burst(struct ast_channel *chan, const char *tone_freq, int } /*! - * \brief Receive Ademco ContactID Data String + * \brief Check if the message is in known and valid Ademco format + * + * \param signalling_type Expected signalling type for the message + * \param event event received + * + * \retval 0 The event is valid + * \retval -1 The event is not valid + */ +static int ademco_check_valid(char *signalling_type, char *event) +{ + if (!strcmp(signalling_type, UNKNOWN_FORMAT)) { + return 1; + } + + if (!strcmp(signalling_type, ADEMCO_CONTACT_ID) + && strncmp(event + 4, ADEMCO_MSG_TYPE_1, 2) + && strncmp(event + 4, ADEMCO_MSG_TYPE_2, 2)) { + return -1; + } + + if (!strcmp(signalling_type, ADEMCO_EXPRESS_4_1) && strncmp(event + 4, ADEMCO_MSG_TYPE_3, 2)) { + return -1; + } + + if (!strcmp(signalling_type, ADEMCO_EXPRESS_4_2) && strncmp(event + 4, ADEMCO_MSG_TYPE_4, 2)) { + return -1; + } + + if (!strcmp(signalling_type, ADEMCO_HIGH_SPEED) && strncmp(event + 4, ADEMCO_MSG_TYPE_5, 2)) { + return -1; + } + + if (!strcmp(signalling_type, ADEMCO_SUPER_FAST) && strncmp(event + 4, ADEMCO_MSG_TYPE_6, 2)) { + return -1; + } + + return 0; +} + +/*! + * \brief Detect the message format of an event + * + * \param signalling_type Expected signalling type for the message + * \param event event received + * \param no_checksum Should we calculate checksum for the message + * + * \returns The expected digits for the detected event type + */ +static int ademco_detect_format(char *signalling_type, char *event, int *no_checksum) +{ + int res = 16; + + if (!strncmp(event + 4, ADEMCO_MSG_TYPE_1, 2) + || !strncmp(event + 4, ADEMCO_MSG_TYPE_2, 2)) { + sprintf(signalling_type, "%s", ADEMCO_CONTACT_ID); + } + + if (!strncmp(event + 4, ADEMCO_MSG_TYPE_3, 2)) { + sprintf(signalling_type, "%s", ADEMCO_EXPRESS_4_1); + res = 8; + } + + if (!strncmp(event + 4, ADEMCO_MSG_TYPE_4, 2)) { + sprintf(signalling_type, "%s", ADEMCO_EXPRESS_4_2); + res = 9; + } + + if (!strncmp(event + 4, ADEMCO_MSG_TYPE_5, 2)) { + sprintf(signalling_type, "%s", ADEMCO_HIGH_SPEED); + } + + if (!strncmp(event + 4, ADEMCO_MSG_TYPE_6, 2)) { + sprintf(signalling_type, "%s", ADEMCO_SUPER_FAST); + *no_checksum = 1; + res = 15; + } + + if (strcmp(signalling_type, UNKNOWN_FORMAT)) { + ast_verb(4, "AlarmMonitoring: Detected format %s.\n", signalling_type); + ast_debug(1, "AlarmMonitoring: Autodetected format %s.\n", signalling_type); + } + + return res; +} + +/*! + * \brief Receive Ademco ContactID or other format Data String * * \param chan Asterisk Channel - * \param fdto First Digit Timeout - * \param sdto Other Digits Timeout - * \param tldn Tone loudness * \param ehead Pointer to events list + * \param signalling_type Expected signalling type for the message + * \param no_checksum Should we calculate checksum for the message * * \retval 0 success * \retval -1 failure */ -static int receive_ademco_contact_id(struct ast_channel *chan, int fdto, int sdto, int tldn, event_node_t **ehead) +static int receive_ademco_event(struct ast_channel *chan, event_node_t **ehead, char *signalling_type, int *no_checksum) { int res = 0; - int exit_on_next = 0; + const char *limit; char event[17]; event_node_t *enew, *elp; int got_some_digits = 0; int events_received = 0; int ack_retries = 0; + int limit_retries = 0; + int expected_length = sizeof(event) - 1; database_increment("calls-received"); @@ -458,43 +627,90 @@ static int receive_ademco_contact_id(struct ast_channel *chan, int fdto, int sdt ast_verb(4, "AlarmReceiver: Waiting for first event from panel...\n"); while (res >= 0) { + int digits_received = 0; + res = 0; + + if (log_individual_events) { + sprintf(signalling_type, "%s", UNKNOWN_FORMAT); + expected_length = 16; + *no_checksum = 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", 100, tldn, 0); + res = send_tone_burst(chan, "1400", 100, 0); if (!res) { ast_verb(4, "AlarmReceiver: Sending 2300Hz 100ms burst (ACK)\n"); - res = send_tone_burst(chan, "2300", 100, tldn, 100); + res = send_tone_burst(chan, "2300", 100, 100); } } if (res) { return -1; } - if (exit_on_next) { - res = send_tone_burst(chan, "1400", 900, tldn, 200); - return 0; - } - - res = receive_dtmf_digits(chan, event, sizeof(event), sizeof(event) - 1, fdto, sdto); + res = receive_dtmf_digits(chan, event, sizeof(event), expected_length, &digits_received); if (res < 0) { if (events_received == 0) { /* Hangup with no events received should be logged in the DB */ database_increment("no-events-received"); + ast_verb(4, "AlarmReceiver: No events received!\n"); } else { if (ack_retries) { - ast_verb(4, "AlarmReceiver: ACK retries during this call: %d\n", ack_retries); database_increment("ack-retries"); + ast_verb(4, "AlarmReceiver: ACK retries during this call: %d\n", ack_retries); } } ast_verb(4, "AlarmReceiver: App exiting...\n"); break; } + if (!strcmp(signalling_type, UNKNOWN_FORMAT) && digits_received > 5) { + expected_length = ademco_detect_format(signalling_type, event, no_checksum); + + if (res > 0) { + if (digits_received == expected_length) { + res = limit_retries = 0; + } else if (digits_received == expected_length - 1 + && (!strcmp(signalling_type, ADEMCO_EXPRESS_4_2) + || !strcmp(signalling_type, ADEMCO_EXPRESS_4_1))) { + /* ADEMCO EXPRESS without checksum */ + res = limit_retries = 0; + expected_length--; + *no_checksum = 1; + ast_verb(4, "AlarmMonitoring: Skipping checksum for format %s.\n", signalling_type); + ast_debug(1, "AlarmMonitoring: Skipping checksum for format %s.\n", signalling_type); + } + } + } + + ast_channel_lock(chan); + limit = pbx_builtin_getvar_helper(chan, "ALARMRECEIVER_CALL_LIMIT"); + if (!ast_strlen_zero(limit)) { + if (ast_tvdiff_ms(ast_tvnow(), call_start_time) > atoi(limit)) { + ast_channel_unlock(chan); + return -1; + } + } + limit = pbx_builtin_getvar_helper(chan, "ALARMRECEIVER_RETRIES_LIMIT"); + ast_channel_unlock(chan); + if (!ast_strlen_zero(limit)) { + if (limit_retries + 1 >= atoi(limit)) { + return -1; + } + } + if (res) { /* Didn't get all of the digits */ ast_verb(2, "AlarmReceiver: Incomplete string: %s, trying again...\n", event); + limit_retries++; + + if (!events_received && strcmp(signalling_type, UNKNOWN_FORMAT)) + { + sprintf(signalling_type, "%s", UNKNOWN_FORMAT); + expected_length = sizeof(event) - 1; + } if (!got_some_digits) { got_some_digits = (!ast_strlen_zero(event)) ? 1 : 0; @@ -509,7 +725,7 @@ static int receive_ademco_contact_id(struct ast_channel *chan, int fdto, int sdt ast_debug(1, "AlarmReceiver: Received event: %s\n", event); /* Calculate checksum */ - if (ademco_verify_checksum(event, 16)) { + if (!(*no_checksum) && ademco_verify_checksum(event, expected_length)) { database_increment("checksum-errors"); ast_verb(2, "AlarmReceiver: Nonzero checksum\n"); ast_debug(1, "AlarmReceiver: Nonzero checksum\n"); @@ -517,13 +733,11 @@ static int receive_ademco_contact_id(struct ast_channel *chan, int fdto, int sdt } /* Check the message type for correctness */ - if (strncmp(event + 4, ADEMCO_MSG_TYPE_1, 2)) { - if (strncmp(event + 4, ADEMCO_MSG_TYPE_2, 2)) { - database_increment("format-errors"); - ast_verb(2, "AlarmReceiver: Wrong message type\n"); - ast_debug(1, "AlarmReceiver: Wrong message type\n"); + if (ademco_check_valid(signalling_type, event)) { + database_increment("format-errors"); + ast_verb(2, "AlarmReceiver: Wrong message type\n"); + ast_debug(1, "AlarmReceiver: Wrong message type\n"); continue; - } } events_received++; @@ -546,25 +760,22 @@ static int receive_ademco_contact_id(struct ast_channel *chan, int fdto, int sdt elp->next = enew; } - /* Audio call follows, exit alarm receiver app */ - if (!strncmp(event + 7, ADEMCO_AUDIO_CALL_NEXT, 3)) { - ast_verb(4, "AlarmReceiver: App exiting... Audio call next!\n"); - exit_on_next = 1; - } - /* Let the user have the option of logging the single event before sending the kissoff tone */ - if (log_individual_events) { - res = log_events(chan, ADEMCO_CONTACT_ID, enew); - if (res) { - return -1; - } + if (log_individual_events && log_events(chan, signalling_type, enew, *no_checksum)) { + return -1; } /* Send the kissoff tone (1400 Hz, 900 ms, after 200ms delay) */ - res = send_tone_burst(chan, "1400", 900, tldn, 200); - if (res) { + if (send_tone_burst(chan, "1400", 900, 200)) { return -1; } + + /* If audio call follows, exit alarm receiver app */ + if (!strcmp(signalling_type, ADEMCO_CONTACT_ID) + && !strncmp(event + 7, ADEMCO_AUDIO_CALL_NEXT, 3)) { + ast_verb(4, "AlarmReceiver: App exiting... Audio call next!\n"); + return 0; + } } return res; @@ -582,53 +793,53 @@ static int receive_ademco_contact_id(struct ast_channel *chan, int fdto, int sdt static int alarmreceiver_exec(struct ast_channel *chan, const char *data) { int res = 0; + int no_checksum = 0; event_node_t *elp, *efree; char signalling_type[64] = ""; event_node_t *event_head = NULL; - /* Set write and read formats to ULAW */ - ast_verb(4, "AlarmReceiver: Setting read and write formats to ULAW\n"); - - if (ast_set_write_format_by_id(chan,AST_FORMAT_ULAW)) { - ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",ast_channel_name(chan)); - return -1; + if (ast_channel_writeformat(chan)->id != AST_FORMAT_ALAW + && ast_channel_writeformat(chan)->id != AST_FORMAT_ULAW) { + ast_verb(4, "AlarmReceiver: Setting write format to Mu-law\n"); + if (ast_set_write_format_by_id(chan,AST_FORMAT_ULAW)) { + ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",ast_channel_name(chan)); + return -1; + } } - if (ast_set_read_format_by_id(chan,AST_FORMAT_ULAW)) { - ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",ast_channel_name(chan)); - return -1; + if (ast_channel_readformat(chan)->id != AST_FORMAT_ALAW + && ast_channel_readformat(chan)->id != AST_FORMAT_ULAW) { + ast_verb(4, "AlarmReceiver: Setting read format to Mu-law\n"); + if (ast_set_read_format_by_id(chan,AST_FORMAT_ULAW)) { + ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",ast_channel_name(chan)); + return -1; + } } /* Set default values for this invocation of the application */ - ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type)); + ast_copy_string(signalling_type, UNKNOWN_FORMAT, sizeof(signalling_type)); + call_start_time = ast_tvnow(); /* Answer the channel if it is not already */ - ast_verb(4, "AlarmReceiver: Answering channel\n"); if (ast_channel_state(chan) != AST_STATE_UP) { - if ((res = ast_answer(chan))) { + ast_verb(4, "AlarmReceiver: Answering channel\n"); + if (ast_answer(chan)) { return -1; } } /* Wait for the connection to settle post-answer */ ast_verb(4, "AlarmReceiver: Waiting for connection to stabilize\n"); - res = ast_safe_sleep(chan, 1250); + if (ast_safe_sleep(chan, answait)) { + return -1; + } /* Attempt to receive the events */ - if (!res) { - /* 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, fdtimeout, sdtimeout, toneloudness, &event_head); - } else { - res = -1; - } - } + receive_ademco_event(chan, &event_head, signalling_type, &no_checksum); /* Events queued by receiver, write them all out here if so configured */ - if ((!res) && (log_individual_events == 0)) { - res = log_events(chan, signalling_type, event_head); + if (!log_individual_events) { + res = log_events(chan, signalling_type, event_head, no_checksum); } /* Do we exec a command line at the end? */ @@ -650,14 +861,16 @@ static int alarmreceiver_exec(struct ast_channel *chan, const char *data) /*! * \brief Load the configuration from the configuration file * + * \param reload True on reload + * * \retval 1 success * \retval 0 failure */ -static int load_config(void) +static int load_config(int reload) { struct ast_config *cfg; const char *value; - struct ast_flags config_flags = { 0 }; + struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; /* Read in the config file */ cfg = ast_config_load(ALMRCV_CONFIG, config_flags); @@ -665,6 +878,8 @@ static int load_config(void) if (!cfg) { ast_verb(4, "AlarmReceiver: No config file\n"); return 0; + } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { + return 1; } else if (cfg == CONFIG_STATUS_FILEINVALID) { ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", ALMRCV_CONFIG); @@ -702,6 +917,19 @@ static int load_config(void) } } + if ((value = ast_variable_retrieve(cfg, "general", "answait")) != NULL) { + answait = atoi(value); + if (answait < 500) { + answait = 500; + } else if (answait > 10000) { + answait = 10000; + } + } + + if ((value = ast_variable_retrieve(cfg, "general", "no_group_meta")) != NULL) { + no_group_meta = ast_true(value); + } + if ((value = ast_variable_retrieve(cfg, "general", "logindividualevents")) != NULL) { log_individual_events = ast_true(value); } @@ -740,20 +968,33 @@ static int unload_module(void) * Module loading including tests for configuration or dependencies. * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails - * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the - * configuration file or other non-critical problem return + * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the + * configuration file or other non-critical problem return * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. */ static int load_module(void) { - if (load_config()) { + if (load_config(0)) { if (ast_register_application_xml(app, alarmreceiver_exec)) { return AST_MODULE_LOAD_FAILURE; } return AST_MODULE_LOAD_SUCCESS; - } else { - return AST_MODULE_LOAD_DECLINE; } + + return AST_MODULE_LOAD_DECLINE; +} + +static int reload(void) +{ + if (load_config(1)) { + return AST_MODULE_LOAD_SUCCESS; + } + + return AST_MODULE_LOAD_DECLINE; } -AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Alarm Receiver for Asterisk"); +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Alarm Receiver for Asterisk", + .load = load_module, + .unload = unload_module, + .reload = reload, +); -- cgit v1.2.3