9063e1a606ab92503a2ce4bc4ca55cae36c1f2cd
[asterisk/asterisk.git] / apps / app_alarmreceiver.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C)  2004 - 2005 Steve Rodgers
5  *
6  * Steve Rodgers <hwstar@rodgers.sdcoxmail.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Central Station Alarm receiver for Ademco Contact ID
22  * \author Steve Rodgers <hwstar@rodgers.sdcoxmail.com>
23  *
24  * *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING ***
25  *
26  * Use at your own risk. Please consult the GNU GPL license document included with Asterisk.         *
27  *
28  * *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING ***
29  *
30  * \ingroup applications
31  */
32
33 /*! \li \ref app_alarmreceiver.c uses the configuration file \ref alarmreceiver.conf
34  * \addtogroup configuration_file Configuration Files
35  */
36
37 /*!
38  * \page alarmreceiver.conf alarmreceiver.conf
39  * \verbinclude alarmreceiver.conf.sample
40  */
41
42 /*** MODULEINFO
43         <support_level>extended</support_level>
44  ***/
45
46 #include "asterisk.h"
47
48 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
49
50 #include <math.h>
51 #include <sys/wait.h>
52 #include <sys/time.h>
53
54 #include "asterisk/lock.h"
55 #include "asterisk/file.h"
56 #include "asterisk/channel.h"
57 #include "asterisk/pbx.h"
58 #include "asterisk/module.h"
59 #include "asterisk/translate.h"
60 #include "asterisk/app.h"
61 #include "asterisk/dsp.h"
62 #include "asterisk/config.h"
63 #include "asterisk/localtime.h"
64 #include "asterisk/callerid.h"
65 #include "asterisk/astdb.h"
66 #include "asterisk/utils.h"
67 #include "asterisk/indications.h"
68
69 #define ALMRCV_CONFIG "alarmreceiver.conf"
70 #define UNKNOWN_FORMAT "UNKNOWN_FORMAT"
71
72 #define ADEMCO_CONTACT_ID "ADEMCO_CONTACT_ID"
73 /*
74         AAAA _ID_ P CCC XX ZZZ S
75
76 where AAAA is the account number, _ID_ is 18 or 98, P is the pin status (alarm or restore), CCC
77 is the alarm code which is pre-defined by Ademco (but you may be able to reprogram it in the panel), XX
78 is the dialer group, partition or area number, ZZZ is the zone or user number and S is the checksum
79 */
80
81 #define ADEMCO_EXPRESS_4_1 "ADEMCO_EXPRESS_4_1"
82 /*
83         AAAA _ID_ C S
84
85 where AAAA is the account number, _ID_ is 17, C is the alarm code and S is the checksum.
86 */
87
88 #define ADEMCO_EXPRESS_4_2 "ADEMCO_EXPRESS_4_2"
89 /*
90         AAAA _ID_ C Z S
91
92 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.
93 */
94
95 #define ADEMCO_HIGH_SPEED "ADEMCO_HIGH_SPEED"
96 /*
97         AAAA _ID_ PPPP PPPP X S
98
99 where AAAA is the account number, _ID_ is 55, PPPP PPPP is the status of each zone, X
100 is a special digit which describes the type of information in the PPPP PPPP fields and S is checksum.
101 Each P field contains one of the following values:
102         1  new alarm           3  new restore           5  normal
103         2  new opening         4  new closing           6  outstanding
104 The X field contains one of the following values:
105         0  AlarmNet messages
106         1  ambush or duress
107         2  opening by user (the first P field contains the user number)
108         3  bypass (the P fields indicate which zones are bypassed)
109         4  closing by user (the first P field contain the user number)
110         5  trouble (the P fields contain which zones are in trouble)
111         6  system trouble
112         7  normal message (the P fields indicate zone status)
113         8  low battery (the P fields indicate zone status)
114         9  test (the P fields indicate zone status)
115 */
116 #define ADEMCO_SUPER_FAST "ADEMCO_SUPER_FAST"
117 /*
118         AAAA _ID_ PPPP PPPP X
119 where AAA is the account number, _ID_ is 56
120 */
121
122 #define ADEMCO_MSG_TYPE_1 "18"
123 #define ADEMCO_MSG_TYPE_2 "98"
124 #define ADEMCO_MSG_TYPE_3 "17"
125 #define ADEMCO_MSG_TYPE_4 "27"
126 #define ADEMCO_MSG_TYPE_5 "55"
127 #define ADEMCO_MSG_TYPE_6 "56"
128
129 #define ADEMCO_AUDIO_CALL_NEXT "606"
130
131 struct {
132   char digit;
133   char weight;
134 } digits_mapping[] = { {'0', 10}, {'1', 1} , {'2', 2}, {'3', 3}, {'4', 4}, {'5', 5},
135         {'6', 6}, {'7', 7}, {'8', 8}, {'9', 9}, {'*', 11}, {'#', 12},
136         {'A', 13}, {'B', 14}, {'C', 15} };
137
138 struct event_node{
139         char data[17];
140         struct event_node *next;
141 };
142
143 typedef struct event_node event_node_t;
144
145 struct timeval call_start_time;
146
147 static const char app[] = "AlarmReceiver";
148 /*** DOCUMENTATION
149         <application name="AlarmReceiver" language="en_US">
150                 <synopsis>
151                         Provide support for receiving alarm reports from a burglar or fire alarm panel.
152                 </synopsis>
153                 <syntax />
154                 <description>
155                         <para>This application should be called whenever there is an alarm panel calling in to dump its events.
156                         The application will handshake with the alarm panel, and receive events, validate them, handshake them,
157                         and store them until the panel hangs up. Once the panel hangs up, the application will run the system
158                         command specified by the eventcmd setting in <filename>alarmreceiver.conf</filename> and pipe the
159                         events to the standard input of the application.
160                         The configuration file also contains settings for DTMF timing, and for the loudness of the
161                         acknowledgement tones.</para>
162                         <note><para>Few Ademco DTMF signalling formats are detected automaticaly: Contact ID, Express 4+1,
163                         Express 4+2, High Speed and Super Fast.</para></note>
164                         <para>The application is affected by the following variables:</para>
165                         <variablelist>
166                                 <variable name="ALARMRECEIVER_CALL_LIMIT">
167                                         <para>Maximum call time, in milliseconds.</para>
168                                         <para>If set, this variable causes application to exit after the specified time.</para>
169                                 </variable>
170                                 <variable name="ALARMRECEIVER_RETRIES_LIMIT">
171                                         <para>Maximum number of retries per call.</para>
172                                         <para>If set, this variable causes application to exit after the specified number of messages.</para>
173                                 </variable>
174                         </variablelist>
175                 </description>
176                 <see-also>
177                         <ref type="filename">alarmreceiver.conf</ref>
178                 </see-also>
179         </application>
180  ***/
181
182 /* Config Variables */
183 static int fdtimeout = 2000;
184 static int sdtimeout = 200;
185 static int answait = 1250;
186 static int toneloudness = 4096;
187 static int log_individual_events = 0;
188 static int no_group_meta = 0;
189 static char event_spool_dir[128] = {'\0'};
190 static char event_app[128] = {'\0'};
191 static char db_family[128] = {'\0'};
192 static char time_stamp_format[128] = {"%a %b %d, %Y @ %H:%M:%S %Z"};
193
194 /* Misc variables */
195 static char event_file[14] = "/event-XXXXXX";
196
197 /*!
198  * \brief Attempt to access a database variable and increment it
199  *
200  * \note Only if the user defined db-family in alarmreceiver.conf
201  *
202  * The alarmreceiver app will write statistics to a few variables
203  * in this family if it is defined. If the new key doesn't exist in the
204  * family, then create it and set its value to 1.
205  *
206  * \param key A database key to increment
207  * \return Nothing
208  */
209 static void database_increment(char *key)
210 {
211         unsigned v;
212         char value[16];
213
214         if (ast_strlen_zero(db_family)) {
215                 return; /* If not defined, don't do anything */
216         }
217
218         if (ast_db_get(db_family, key, value, sizeof(value) - 1)) {
219                 ast_verb(4, "AlarmReceiver: Creating database entry %s and setting to 1\n", key);
220                 /* Guess we have to create it */
221                 ast_db_put(db_family, key, "1");
222                 return;
223         }
224
225         sscanf(value, "%30u", &v);
226         v++;
227
228         ast_verb(4, "AlarmReceiver: New value for %s: %u\n", key, v);
229         snprintf(value, sizeof(value), "%u", v);
230
231         if (ast_db_put(db_family, key, value)) {
232                 ast_verb(4, "AlarmReceiver: database_increment write error\n");
233         }
234
235         return;
236 }
237
238 /*!
239  * \brief Receive a fixed length DTMF string.
240  *
241  * \note Doesn't give preferential treatment to any digit,
242  * \note allow different timeout values for the first and all subsequent digits
243  *
244  * \param chan Asterisk Channel
245  * \param digit_string Digits String
246  * \param buf_size The size of the Digits String buffer
247  * \param expected Digits expected for this message type
248  * \param received Pointer to number of digits received so far
249  *
250  * \retval 0 if all digits were successfully received
251  * \retval 1 if a timeout occurred
252  * \retval -1 if the caller hung up or on channel errors
253  */
254 static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int buf_size, int expected, int *received)
255 {
256         int rtn = 0;
257         int r;
258         struct ast_frame *f;
259         struct timeval lastdigittime;
260
261         lastdigittime = ast_tvnow();
262         while (*received < expected && *received < buf_size - 1) {
263                 /* If timed out, leave */
264                 if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((*received > 0) ? sdtimeout : fdtimeout)) {
265                         ast_verb(4, "AlarmReceiver: DTMF Digit Timeout on %s\n", ast_channel_name(chan));
266                         ast_debug(1, "AlarmReceiver: DTMF timeout on chan %s\n", ast_channel_name(chan));
267                         rtn = 1;
268                         break;
269                 }
270
271                 if ((r = ast_waitfor(chan, -1)) < 0) {
272                         ast_debug(1, "Waitfor returned %d\n", r);
273                         continue;
274                 }
275
276                 if ((f = ast_read(chan)) == NULL) {
277                         rtn = -1;
278                         break;
279                 }
280
281                 /* If they hung up, leave */
282                 if ((f->frametype == AST_FRAME_CONTROL)
283                         && (f->subclass.integer == AST_CONTROL_HANGUP)) {
284                         if (f->data.uint32) {
285                                 ast_channel_hangupcause_set(chan, f->data.uint32);
286                         }
287                         ast_frfree(f);
288                         rtn = -1;
289                         break;
290                 }
291
292                 /* If not DTMF, just do it again */
293                 if (f->frametype != AST_FRAME_DTMF) {
294                         ast_frfree(f);
295                         continue;
296                 }
297
298                 /* Save digit */
299                 digit_string[(*received)++] = f->subclass.integer;
300                 ast_frfree(f);
301
302                 lastdigittime = ast_tvnow();
303         }
304
305         /* Null terminate the end of the digit_string */
306         digit_string[*received] = '\0';
307
308         return rtn;
309 }
310
311 /*!
312  * \brief Write metadata to log file
313  *
314  * \param logfile Log File Pointer
315  * \param signalling_type Signaling Type
316  * \param chan Asterisk Channel
317  * \param no_checksum Expecting messages without checksum
318  *
319  * \retval 0 success
320  * \retval -1 failure
321  */
322 static int write_metadata(FILE *logfile, char *signalling_type, struct ast_channel *chan, int no_checksum)
323 {
324         struct timeval t;
325         struct ast_tm now;
326         char *cl;
327         char *cn;
328         char workstring[80];
329         char timestamp[80];
330
331         /* Extract the caller ID location */
332         ast_copy_string(workstring,
333                 S_COR(ast_channel_caller(chan)->id.number.valid,
334                 ast_channel_caller(chan)->id.number.str, ""), sizeof(workstring));
335         ast_shrink_phone_number(workstring);
336         if (ast_strlen_zero(workstring)) {
337                 cl = "<unknown>";
338         } else {
339                 cl = workstring;
340         }
341         cn = S_COR(ast_channel_caller(chan)->id.name.valid,
342                 ast_channel_caller(chan)->id.name.str, "<unknown>");
343
344         /* Get the current time */
345         t = ast_tvnow();
346         ast_localtime(&t, &now, NULL);
347
348         /* Format the time */
349         ast_strftime(timestamp, sizeof(timestamp), time_stamp_format, &now);
350
351         if (no_group_meta && fprintf(logfile, "PROTOCOL=%s\n"
352                         "CHECKSUM=%s\n"
353                         "CALLINGFROM=%s\n"
354                         "CALLERNAME=%s\n"
355                         "TIMESTAMP=%s\n\n",
356                         signalling_type, (!no_checksum) ? "yes" : "no", cl, cn, timestamp) > -1) {
357                 return 0;
358         } else if (fprintf(logfile, "\n\n[metadata]\n\n"
359                         "PROTOCOL=%s\n"
360                         "CHECKSUM=%s\n"
361                         "CALLINGFROM=%s\n"
362                         "CALLERNAME=%s\n"
363                         "TIMESTAMP=%s\n\n"
364                         "[events]\n\n",
365                         signalling_type, (!no_checksum) ? "yes" : "no", cl, cn, timestamp) > -1) {
366                 return 0;
367         }
368
369         ast_verb(3, "AlarmReceiver: can't write metadata\n");
370         ast_debug(1, "AlarmReceiver: can't write metadata\n");
371         return -1;
372 }
373
374 /*!
375  * \brief Log a single event
376  *
377  * \param logfile Log File Pointer
378  * \param event Event Structure
379  *
380  * \retval 0 success
381  * \retval -1 failure
382  */
383 static int write_event(FILE *logfile, event_node_t *event)
384 {
385         if (fprintf(logfile, "%s%s\n", no_group_meta ? "event=" : "", event->data) < 0) {
386                 return -1;
387         }
388
389         return 0;
390 }
391
392 /*!
393  * \brief Log events if configuration key logindividualevents is enabled or on exit
394  *
395  * \param chan Asterisk Channel
396  * \param signalling_type Signaling Type
397  * \param event Event Structure
398  * \param no_checksum Expecting messages without checksum
399  *
400  * \retval 0 success
401  * \retval -1 failure
402  */
403 static int log_events(struct ast_channel *chan, char *signalling_type, event_node_t *event, int no_checksum)
404 {
405         char workstring[sizeof(event_spool_dir) + sizeof(event_file)] = "";
406         int fd;
407         FILE *logfile;
408         event_node_t *elp = event;
409
410         if (!ast_strlen_zero(event_spool_dir)) {
411
412                 /* Make a template */
413                 ast_copy_string(workstring, event_spool_dir, sizeof(workstring));
414                 strncat(workstring, event_file, sizeof(workstring) - strlen(workstring) - 1);
415
416                 /* Make the temporary file */
417                 fd = mkstemp(workstring);
418
419                 if (fd == -1) {
420                         ast_verb(3, "AlarmReceiver: can't make temporary file\n");
421                         ast_debug(1, "AlarmReceiver: can't make temporary file\n");
422                         return -1;
423                 }
424
425                 if ((logfile = fdopen(fd, "w")) == NULL) {
426                         return -1;
427                 }
428
429                 /* Write the file */
430                 if (write_metadata(logfile, signalling_type, chan, no_checksum)) {
431                         fflush(logfile);
432                         fclose(logfile);
433                         return -1;
434                 }
435
436                 while ((elp != NULL) && (write_event(logfile, elp) == 0)) {
437                         elp = elp->next;
438                 }
439
440                 fflush(logfile);
441                 fclose(logfile);
442         }
443
444         return 0;
445 }
446
447 /*!
448  * \brief Verify Ademco checksum
449  * \since 11.0
450  *
451  * \param event Received DTMF String
452  * \param expected Number of Digits expected
453  *
454  * \retval 0 success
455  * \retval -1 failure
456  */
457 static int ademco_verify_checksum(char *event, int expected)
458 {
459         int checksum = 0;
460         int i, j;
461
462         for (j = 0; j < expected; j++) {
463                 for (i = 0; i < ARRAY_LEN(digits_mapping); i++) {
464                         if (digits_mapping[i].digit == event[j]) {
465                                 break;
466                         }
467                 }
468
469                 if (i >= ARRAY_LEN(digits_mapping)) {
470                         ast_verb(2, "AlarmReceiver: Bad DTMF character %c, trying again\n", event[j]);
471                         return -1;
472                 }
473
474                 checksum += digits_mapping[i].weight;
475         }
476
477         /* Checksum is mod(15) of the total */
478         if (!(checksum % 15)) {
479                 return 0;
480         }
481
482         return -1;
483 }
484
485 /*!
486  * \brief Send a single tone burst for a specifed duration and frequency.
487  * \since 11.0
488  *
489  * \param chan Asterisk Channel
490  * \param tone_freq Frequency of the tone to send
491  * \param tone_duration Tone duration in ms
492  * \param delay Delay before sending the tone
493  *
494  * \retval 0 success
495  * \retval -1 failure
496  */
497 static int send_tone_burst(struct ast_channel *chan, const char *tone_freq, int tone_duration, int delay)
498 {
499         if (delay && ast_safe_sleep(chan, delay)) {
500                 return -1;
501         }
502
503         if (ast_playtones_start(chan, toneloudness, tone_freq, 0)) {
504                 return -1;
505         }
506
507         if (ast_safe_sleep(chan, tone_duration)) {
508                 return -1;
509         }
510
511         ast_playtones_stop(chan);
512         return 0;
513 }
514
515 /*!
516  * \brief Check if the message is in known and valid Ademco format
517  *
518  * \param signalling_type Expected signalling type for the message
519  * \param event event received
520  *
521  * \retval 0 The event is valid
522  * \retval -1 The event is not valid
523  */
524 static int ademco_check_valid(char *signalling_type, char *event)
525 {
526         if (!strcmp(signalling_type, UNKNOWN_FORMAT)) {
527                 return 1;
528         }
529
530         if (!strcmp(signalling_type, ADEMCO_CONTACT_ID)
531                 && strncmp(event + 4, ADEMCO_MSG_TYPE_1, 2)
532                 && strncmp(event + 4, ADEMCO_MSG_TYPE_2, 2)) {
533                 return -1;
534         }
535
536         if (!strcmp(signalling_type, ADEMCO_EXPRESS_4_1) && strncmp(event + 4, ADEMCO_MSG_TYPE_3, 2)) {
537                 return -1;
538         }
539
540         if (!strcmp(signalling_type, ADEMCO_EXPRESS_4_2) && strncmp(event + 4, ADEMCO_MSG_TYPE_4, 2)) {
541                 return -1;
542         }
543
544         if (!strcmp(signalling_type, ADEMCO_HIGH_SPEED) && strncmp(event + 4, ADEMCO_MSG_TYPE_5, 2)) {
545                 return -1;
546         }
547
548         if (!strcmp(signalling_type, ADEMCO_SUPER_FAST) && strncmp(event + 4, ADEMCO_MSG_TYPE_6, 2)) {
549                 return -1;
550         }
551
552         return 0;
553 }
554
555 /*!
556  * \brief Detect the message format of an event
557  *
558  * \param signalling_type Expected signalling type for the message
559  * \param event event received
560  * \param no_checksum Should we calculate checksum for the message
561  *
562  * \returns The expected digits for the detected event type
563  */
564 static int ademco_detect_format(char *signalling_type, char *event, int *no_checksum)
565 {
566         int res = 16;
567
568         if (!strncmp(event + 4, ADEMCO_MSG_TYPE_1, 2)
569                 || !strncmp(event + 4, ADEMCO_MSG_TYPE_2, 2)) {
570                 sprintf(signalling_type, "%s", ADEMCO_CONTACT_ID);
571         }
572
573         if (!strncmp(event + 4, ADEMCO_MSG_TYPE_3, 2)) {
574                 sprintf(signalling_type, "%s", ADEMCO_EXPRESS_4_1);
575                 res = 8;
576         }
577
578         if (!strncmp(event + 4, ADEMCO_MSG_TYPE_4, 2)) {
579                 sprintf(signalling_type, "%s", ADEMCO_EXPRESS_4_2);
580                 res = 9;
581         }
582
583         if (!strncmp(event + 4, ADEMCO_MSG_TYPE_5, 2)) {
584                 sprintf(signalling_type, "%s", ADEMCO_HIGH_SPEED);
585         }
586
587         if (!strncmp(event + 4, ADEMCO_MSG_TYPE_6, 2)) {
588                 sprintf(signalling_type, "%s", ADEMCO_SUPER_FAST);
589                 *no_checksum = 1;
590                 res = 15;
591         }
592
593         if (strcmp(signalling_type, UNKNOWN_FORMAT)) {
594                 ast_verb(4, "AlarmMonitoring: Detected format %s.\n", signalling_type);
595                 ast_debug(1, "AlarmMonitoring: Autodetected format %s.\n", signalling_type);
596         }
597
598         return res;
599 }
600
601 /*!
602  * \brief Receive Ademco ContactID or other format Data String
603  *
604  * \param chan Asterisk Channel
605  * \param ehead Pointer to events list
606  * \param signalling_type Expected signalling type for the message
607  * \param no_checksum Should we calculate checksum for the message
608  *
609  * \retval 0 success
610  * \retval -1 failure
611  */
612 static int receive_ademco_event(struct ast_channel *chan, event_node_t **ehead, char *signalling_type, int *no_checksum)
613 {
614         int res = 0;
615         const char *limit;
616         char event[17];
617         event_node_t *enew, *elp;
618         int got_some_digits = 0;
619         int events_received = 0;
620         int ack_retries = 0;
621         int limit_retries = 0;
622         int expected_length = sizeof(event) - 1;
623
624         database_increment("calls-received");
625
626         /* Wait for first event */
627         ast_verb(4, "AlarmReceiver: Waiting for first event from panel...\n");
628
629         while (res >= 0) {
630                 int digits_received = 0;
631
632                 res = 0;
633
634                 if (log_individual_events) {
635                         sprintf(signalling_type, "%s", UNKNOWN_FORMAT);
636                         expected_length = 16;
637                         *no_checksum = 0;
638                 }
639
640                 if (got_some_digits == 0) {
641                         /* Send ACK tone sequence */
642                         ast_verb(4, "AlarmReceiver: Sending 1400Hz 100ms burst (ACK)\n");
643                         res = send_tone_burst(chan, "1400", 100, 0);
644                         if (!res) {
645                                 ast_verb(4, "AlarmReceiver: Sending 2300Hz 100ms burst (ACK)\n");
646                                 res = send_tone_burst(chan, "2300", 100, 100);
647                         }
648                 }
649                 if (res) {
650                         return -1;
651                 }
652
653                 res = receive_dtmf_digits(chan, event, sizeof(event), expected_length, &digits_received);
654                 if (res < 0) {
655                         if (events_received == 0) {
656                                 /* Hangup with no events received should be logged in the DB */
657                                 database_increment("no-events-received");
658                                 ast_verb(4, "AlarmReceiver: No events received!\n");
659                         } else {
660                                 if (ack_retries) {
661                                         database_increment("ack-retries");
662                                         ast_verb(4, "AlarmReceiver: ACK retries during this call: %d\n", ack_retries);
663                                 }
664                         }
665                         ast_verb(4, "AlarmReceiver: App exiting...\n");
666                         break;
667                 }
668
669                 if (!strcmp(signalling_type, UNKNOWN_FORMAT) && digits_received > 5) {
670                         expected_length = ademco_detect_format(signalling_type, event, no_checksum);
671
672                         if (res > 0) {
673                                 if (digits_received == expected_length) {
674                                         res = limit_retries = 0;
675                                 } else if (digits_received == expected_length - 1
676                                         && (!strcmp(signalling_type, ADEMCO_EXPRESS_4_2)
677                                         || !strcmp(signalling_type, ADEMCO_EXPRESS_4_1))) {
678                                         /* ADEMCO EXPRESS without checksum */
679                                         res = limit_retries = 0;
680                                         expected_length--;
681                                         *no_checksum = 1;
682                                         ast_verb(4, "AlarmMonitoring: Skipping checksum for format %s.\n", signalling_type);
683                                         ast_debug(1, "AlarmMonitoring: Skipping checksum for format %s.\n", signalling_type);
684                                 }
685                         }
686                 }
687
688                 ast_channel_lock(chan);
689                 limit = pbx_builtin_getvar_helper(chan, "ALARMRECEIVER_CALL_LIMIT");
690                 if (!ast_strlen_zero(limit)) {
691                         if (ast_tvdiff_ms(ast_tvnow(), call_start_time) > atoi(limit)) {
692                                 ast_channel_unlock(chan);
693                                 return -1;
694                         }
695                 }
696                 limit = pbx_builtin_getvar_helper(chan, "ALARMRECEIVER_RETRIES_LIMIT");
697                 ast_channel_unlock(chan);
698                 if (!ast_strlen_zero(limit)) {
699                         if (limit_retries + 1 >= atoi(limit)) {
700                                 return -1;
701                         }
702                 }
703
704                 if (res) {
705                         /* Didn't get all of the digits */
706                         ast_verb(2, "AlarmReceiver: Incomplete string: %s, trying again...\n", event);
707                         limit_retries++;
708
709                         if (!events_received && strcmp(signalling_type, UNKNOWN_FORMAT))
710                         {
711                                 sprintf(signalling_type, "%s", UNKNOWN_FORMAT);
712                                 expected_length = sizeof(event) - 1;
713                         }
714
715                         if (!got_some_digits) {
716                                 got_some_digits = (!ast_strlen_zero(event)) ? 1 : 0;
717                                 ack_retries++;
718                         }
719                         continue;
720                 }
721
722                 got_some_digits = 1;
723
724                 ast_verb(2, "AlarmReceiver: Received Event %s\n", event);
725                 ast_debug(1, "AlarmReceiver: Received event: %s\n", event);
726
727                 /* Calculate checksum */
728                 if (!(*no_checksum) && ademco_verify_checksum(event, expected_length)) {
729                         database_increment("checksum-errors");
730                         ast_verb(2, "AlarmReceiver: Nonzero checksum\n");
731                         ast_debug(1, "AlarmReceiver: Nonzero checksum\n");
732                         continue;
733                 }
734
735                 /* Check the message type for correctness */
736                 if (ademco_check_valid(signalling_type, event)) {
737                         database_increment("format-errors");
738                         ast_verb(2, "AlarmReceiver: Wrong message type\n");
739                         ast_debug(1, "AlarmReceiver: Wrong message type\n");
740                         continue;
741                 }
742
743                 events_received++;
744
745                 /* Queue the Event */
746                 if (!(enew = ast_calloc(1, sizeof(*enew)))) {
747                         return -1;
748                 }
749
750                 enew->next = NULL;
751                 ast_copy_string(enew->data, event, sizeof(enew->data));
752
753                 /* Insert event onto end of list */
754                 if (*ehead == NULL) {
755                         *ehead = enew;
756                 } else {
757                         for (elp = *ehead; elp->next != NULL; elp = elp->next) {
758                                 ;
759                         }
760                         elp->next = enew;
761                 }
762
763                 /* Let the user have the option of logging the single event before sending the kissoff tone */
764                 if (log_individual_events && log_events(chan, signalling_type, enew, *no_checksum)) {
765                         return -1;
766                 }
767
768                 /* Send the kissoff tone (1400 Hz, 900 ms, after 200ms delay) */
769                 if (send_tone_burst(chan, "1400", 900, 200)) {
770                         return -1;
771                 }
772
773                 /* If audio call follows, exit alarm receiver app */
774                 if (!strcmp(signalling_type, ADEMCO_CONTACT_ID)
775                         && !strncmp(event + 7, ADEMCO_AUDIO_CALL_NEXT, 3)) {
776                         ast_verb(4, "AlarmReceiver: App exiting... Audio call next!\n");
777                         return 0;
778                 }
779         }
780
781         return res;
782 }
783
784 /*!
785  * \brief This is the main function called by Asterisk Core whenever the App is invoked in the extension logic.
786  *
787  * \param chan Asterisk Channel
788  * \param data Application data
789  *
790  * \retval 0 success
791  * \retval -1 failure
792  */
793 static int alarmreceiver_exec(struct ast_channel *chan, const char *data)
794 {
795         int res = 0;
796         int no_checksum = 0;
797         event_node_t *elp, *efree;
798         char signalling_type[64] = "";
799         event_node_t *event_head = NULL;
800
801         if (ast_channel_writeformat(chan)->id != AST_FORMAT_ALAW
802                 && ast_channel_writeformat(chan)->id != AST_FORMAT_ULAW) {
803                 ast_verb(4, "AlarmReceiver: Setting write format to Mu-law\n");
804                 if (ast_set_write_format_by_id(chan,AST_FORMAT_ULAW)) {
805                         ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",ast_channel_name(chan));
806                         return -1;
807                 }
808         }
809
810         if (ast_channel_readformat(chan)->id != AST_FORMAT_ALAW
811                 && ast_channel_readformat(chan)->id != AST_FORMAT_ULAW) {
812                 ast_verb(4, "AlarmReceiver: Setting read format to Mu-law\n");
813                 if (ast_set_read_format_by_id(chan,AST_FORMAT_ULAW)) {
814                         ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",ast_channel_name(chan));
815                         return -1;
816                 }
817         }
818
819         /* Set default values for this invocation of the application */
820         ast_copy_string(signalling_type, UNKNOWN_FORMAT, sizeof(signalling_type));
821         call_start_time = ast_tvnow();
822
823         /* Answer the channel if it is not already */
824         if (ast_channel_state(chan) != AST_STATE_UP) {
825                 ast_verb(4, "AlarmReceiver: Answering channel\n");
826                 if (ast_answer(chan)) {
827                         return -1;
828                 }
829         }
830
831         /* Wait for the connection to settle post-answer */
832         ast_verb(4, "AlarmReceiver: Waiting for connection to stabilize\n");
833         if (ast_safe_sleep(chan, answait)) {
834                 return -1;
835         }
836
837         /* Attempt to receive the events */
838         receive_ademco_event(chan, &event_head, signalling_type, &no_checksum);
839
840         /* Events queued by receiver, write them all out here if so configured */
841         if (!log_individual_events) {
842                 res = log_events(chan, signalling_type, event_head, no_checksum);
843         }
844
845         /* Do we exec a command line at the end? */
846         if ((!res) && (!ast_strlen_zero(event_app)) && (event_head)) {
847                 ast_debug(1,"Alarmreceiver: executing: %s\n", event_app);
848                 ast_safe_system(event_app);
849         }
850
851         /* Free up the data allocated in our linked list */
852         for (elp = event_head; (elp != NULL);) {
853                 efree = elp;
854                 elp = elp->next;
855                 ast_free(efree);
856         }
857
858         return 0;
859 }
860
861 /*!
862  * \brief Load the configuration from the configuration file
863  *
864  * \param reload True on reload
865  *
866  * \retval 1 success
867  * \retval 0 failure
868  */
869 static int load_config(int reload)
870 {
871         struct ast_config *cfg;
872         const char *value;
873         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
874
875         /* Read in the config file */
876         cfg = ast_config_load(ALMRCV_CONFIG, config_flags);
877
878         if (!cfg) {
879                 ast_verb(4, "AlarmReceiver: No config file\n");
880                 return 0;
881         } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
882                 return 1;
883         } else if (cfg == CONFIG_STATUS_FILEINVALID) {
884                 ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n",
885                         ALMRCV_CONFIG);
886                 return 0;
887         }
888
889         if ((value = ast_variable_retrieve(cfg, "general", "eventcmd")) != NULL) {
890                 ast_copy_string(event_app, value, sizeof(event_app));
891         }
892
893         if ((value = ast_variable_retrieve(cfg, "general", "loudness")) != NULL) {
894                 toneloudness = atoi(value);
895                 if (toneloudness < 100) {
896                         toneloudness = 100;
897                 } else if (toneloudness > 8192) {
898                         toneloudness = 8192;
899                 }
900         }
901
902         if ((value = ast_variable_retrieve(cfg, "general", "fdtimeout")) != NULL) {
903                 fdtimeout = atoi(value);
904                 if (fdtimeout < 1000) {
905                         fdtimeout = 1000;
906                 } else if (fdtimeout > 10000) {
907                         fdtimeout = 10000;
908                 }
909         }
910
911         if ((value = ast_variable_retrieve(cfg, "general", "sdtimeout")) != NULL) {
912                 sdtimeout = atoi(value);
913                 if (sdtimeout < 110) {
914                         sdtimeout = 110;
915                 } else if (sdtimeout > 4000) {
916                         sdtimeout = 4000;
917                 }
918         }
919
920         if ((value = ast_variable_retrieve(cfg, "general", "answait")) != NULL) {
921                 answait = atoi(value);
922                 if (answait < 500) {
923                         answait = 500;
924                 } else if (answait > 10000) {
925                         answait = 10000;
926                 }
927         }
928
929         if ((value = ast_variable_retrieve(cfg, "general", "no_group_meta")) != NULL) {
930                 no_group_meta = ast_true(value);
931         }
932
933         if ((value = ast_variable_retrieve(cfg, "general", "logindividualevents")) != NULL) {
934                 log_individual_events = ast_true(value);
935         }
936
937         if ((value = ast_variable_retrieve(cfg, "general", "eventspooldir")) != NULL) {
938                 ast_copy_string(event_spool_dir, value, sizeof(event_spool_dir));
939         }
940
941         if ((value = ast_variable_retrieve(cfg, "general", "timestampformat")) != NULL) {
942                 ast_copy_string(time_stamp_format, value, sizeof(time_stamp_format));
943         }
944
945         if ((value = ast_variable_retrieve(cfg, "general", "db-family")) != NULL) {
946                 ast_copy_string(db_family, value, sizeof(db_family));
947         }
948
949         ast_config_destroy(cfg);
950
951         return 1;
952 }
953
954 /*!
955  * \brief Unregister Alarm Receiver App
956  *
957  * \retval 0 success
958  * \retval -1 failure
959  */
960 static int unload_module(void)
961 {
962         return ast_unregister_application(app);
963 }
964
965 /*!
966  * \brief Load the module
967  *
968  * Module loading including tests for configuration or dependencies.
969  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
970  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
971  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
972  * configuration file or other non-critical problem return
973  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
974  */
975 static int load_module(void)
976 {
977         if (load_config(0)) {
978                 if (ast_register_application_xml(app, alarmreceiver_exec)) {
979                         return AST_MODULE_LOAD_FAILURE;
980                 }
981                 return AST_MODULE_LOAD_SUCCESS;
982         }
983
984         return AST_MODULE_LOAD_DECLINE;
985 }
986
987 static int reload(void)
988 {
989         if (load_config(1)) {
990                 return AST_MODULE_LOAD_SUCCESS;
991         }
992
993         return AST_MODULE_LOAD_DECLINE;
994 }
995
996 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Alarm Receiver for Asterisk",
997                 .load = load_module,
998                 .unload = unload_module,
999                 .reload = reload,
1000 );