00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <string.h>
00033 #include <stdlib.h>
00034 #include <stdio.h>
00035 #include <math.h>
00036 #include <sys/wait.h>
00037 #include <unistd.h>
00038 #include <sys/time.h>
00039
00040 #include "asterisk.h"
00041
00042 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 43924 $")
00043
00044 #include "asterisk/lock.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/logger.h"
00047 #include "asterisk/channel.h"
00048 #include "asterisk/pbx.h"
00049 #include "asterisk/module.h"
00050 #include "asterisk/translate.h"
00051 #include "asterisk/ulaw.h"
00052 #include "asterisk/options.h"
00053 #include "asterisk/app.h"
00054 #include "asterisk/dsp.h"
00055 #include "asterisk/config.h"
00056 #include "asterisk/localtime.h"
00057 #include "asterisk/callerid.h"
00058 #include "asterisk/astdb.h"
00059
00060 #define ALMRCV_CONFIG "alarmreceiver.conf"
00061 #define ADEMCO_CONTACT_ID "ADEMCO_CONTACT_ID"
00062
00063 struct event_node{
00064 char data[17];
00065 struct event_node *next;
00066 };
00067
00068 typedef struct event_node event_node_t;
00069
00070 static char *tdesc = "Alarm Receiver for Asterisk";
00071
00072 static char *app = "AlarmReceiver";
00073
00074 static char *synopsis = "Provide support for receving alarm reports from a burglar or fire alarm panel";
00075 static char *descrip =
00076 " AlarmReceiver(): Only 1 signalling format is supported at this time: Ademco\n"
00077 "Contact ID. This application should be called whenever there is an alarm\n"
00078 "panel calling in to dump its events. The application will handshake with the\n"
00079 "alarm panel, and receive events, validate them, handshake them, and store them\n"
00080 "until the panel hangs up. Once the panel hangs up, the application will run the\n"
00081 "system command specified by the eventcmd setting in alarmreceiver.conf and pipe\n"
00082 "the events to the standard input of the application. The configuration file also\n"
00083 "contains settings for DTMF timing, and for the loudness of the acknowledgement\n"
00084 "tones.\n";
00085
00086
00087
00088 static int fdtimeout = 2000;
00089 static int sdtimeout = 200;
00090 static int toneloudness = 4096;
00091 static int log_individual_events = 0;
00092 static char event_spool_dir[128] = {'\0'};
00093 static char event_app[128] = {'\0'};
00094 static char db_family[128] = {'\0'};
00095 static char time_stamp_format[128] = {"%a %b %d, %Y @ %H:%M:%S %Z"};
00096
00097
00098
00099
00100
00101 static char event_file[14] = "/event-XXXXXX";
00102
00103
00104
00105 STANDARD_LOCAL_USER;
00106
00107 LOCAL_USER_DECL;
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117 static void database_increment( char *key )
00118 {
00119 int res = 0;
00120 unsigned v;
00121 char value[16];
00122
00123
00124 if (ast_strlen_zero(db_family))
00125 return;
00126
00127 res = ast_db_get(db_family, key, value, sizeof(value) - 1);
00128
00129 if(res){
00130 if(option_verbose >= 4)
00131 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Creating database entry %s and setting to 1\n", key);
00132
00133 res = ast_db_put(db_family, key, "1");
00134 return;
00135 }
00136
00137 sscanf(value, "%u", &v);
00138 v++;
00139
00140 if(option_verbose >= 4)
00141 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: New value for %s: %u\n", key, v);
00142
00143 snprintf(value, sizeof(value), "%u", v);
00144
00145 res = ast_db_put(db_family, key, value);
00146
00147 if((res)&&(option_verbose >= 4))
00148 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: database_increment write error\n");
00149
00150 return;
00151 }
00152
00153
00154
00155
00156
00157
00158 static void make_tone_burst(unsigned char *data, float freq, float loudness, int len, int *x)
00159 {
00160 int i;
00161 float val;
00162
00163 for(i = 0; i < len; i++){
00164 val = loudness * sin((freq * 2.0 * M_PI * (*x)++)/8000.0);
00165 data[i] = AST_LIN2MU((int)val);
00166 }
00167
00168
00169
00170 if (*x >= 8000) *x = 0;
00171 return;
00172 }
00173
00174
00175
00176
00177
00178
00179 static int send_tone_burst(struct ast_channel *chan, float freq, int duration, int tldn)
00180 {
00181 int res = 0;
00182 int i = 0;
00183 int x = 0;
00184 struct ast_frame *f, wf;
00185
00186 struct {
00187 unsigned char offset[AST_FRIENDLY_OFFSET];
00188 unsigned char buf[640];
00189 } tone_block;
00190
00191 for(;;)
00192 {
00193
00194 if (ast_waitfor(chan, -1) < 0){
00195 res = -1;
00196 break;
00197 }
00198
00199 f = ast_read(chan);
00200 if (!f){
00201 res = -1;
00202 break;
00203 }
00204
00205 if (f->frametype == AST_FRAME_VOICE) {
00206 wf.frametype = AST_FRAME_VOICE;
00207 wf.subclass = AST_FORMAT_ULAW;
00208 wf.offset = AST_FRIENDLY_OFFSET;
00209 wf.mallocd = 0;
00210 wf.data = tone_block.buf;
00211 wf.datalen = f->datalen;
00212 wf.samples = wf.datalen;
00213
00214 make_tone_burst(tone_block.buf, freq, (float) tldn, wf.datalen, &x);
00215
00216 i += wf.datalen / 8;
00217 if (i > duration) {
00218 ast_frfree(f);
00219 break;
00220 }
00221 if (ast_write(chan, &wf)){
00222 if(option_verbose >= 4)
00223 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Failed to write frame on %s\n", chan->name);
00224 ast_log(LOG_WARNING, "AlarmReceiver Failed to write frame on %s\n",chan->name);
00225 res = -1;
00226 ast_frfree(f);
00227 break;
00228 }
00229 }
00230
00231 ast_frfree(f);
00232 }
00233 return res;
00234 }
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247 static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int length, int fdto, int sdto)
00248 {
00249 int res = 0;
00250 int i = 0;
00251 int r;
00252 struct ast_frame *f;
00253 struct timeval lastdigittime;
00254
00255 lastdigittime = ast_tvnow();
00256 for(;;){
00257
00258 if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) >
00259 ((i > 0) ? sdto : fdto)){
00260 if(option_verbose >= 4)
00261 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: DTMF Digit Timeout on %s\n", chan->name);
00262
00263 ast_log(LOG_DEBUG,"AlarmReceiver: DTMF timeout on chan %s\n",chan->name);
00264
00265 res = 1;
00266 break;
00267 }
00268
00269 if ((r = ast_waitfor(chan, -1) < 0)) {
00270 ast_log(LOG_DEBUG, "Waitfor returned %d\n", r);
00271 continue;
00272 }
00273
00274 f = ast_read(chan);
00275
00276 if (f == NULL){
00277 res = -1;
00278 break;
00279 }
00280
00281
00282 if ((f->frametype == AST_FRAME_CONTROL) &&
00283 (f->subclass == AST_CONTROL_HANGUP)){
00284 ast_frfree(f);
00285 res = -1;
00286 break;
00287 }
00288
00289
00290 if (f->frametype != AST_FRAME_DTMF){
00291 ast_frfree(f);
00292 continue;
00293 }
00294
00295 digit_string[i++] = f->subclass;
00296
00297 ast_frfree(f);
00298
00299
00300 if(i >= length)
00301 break;
00302
00303 lastdigittime = ast_tvnow();
00304 }
00305
00306 digit_string[i] = '\0';
00307 return res;
00308
00309 }
00310
00311
00312
00313
00314
00315 static int write_metadata( FILE *logfile, char *signalling_type, struct ast_channel *chan)
00316 {
00317 int res = 0;
00318 time_t t;
00319 struct tm now;
00320 char *cl,*cn;
00321 char workstring[80];
00322 char timestamp[80];
00323
00324
00325 if (chan->cid.cid_num)
00326 ast_copy_string(workstring, chan->cid.cid_num, sizeof(workstring));
00327 workstring[sizeof(workstring) - 1] = '\0';
00328
00329 ast_callerid_parse(workstring, &cn, &cl);
00330 if (cl)
00331 ast_shrink_phone_number(cl);
00332
00333
00334
00335
00336 time(&t);
00337 ast_localtime(&t, &now, NULL);
00338
00339
00340
00341 strftime(timestamp, sizeof(timestamp), time_stamp_format, &now);
00342
00343
00344 res = fprintf(logfile, "\n\n[metadata]\n\n");
00345
00346 if(res >= 0)
00347 res = fprintf(logfile, "PROTOCOL=%s\n", signalling_type);
00348
00349 if(res >= 0)
00350 res = fprintf(logfile, "CALLINGFROM=%s\n", (!cl) ? "<unknown>" : cl);
00351
00352 if(res >- 0)
00353 res = fprintf(logfile, "CALLERNAME=%s\n", (!cn) ? "<unknown>" : cn);
00354
00355 if(res >= 0)
00356 res = fprintf(logfile, "TIMESTAMP=%s\n\n", timestamp);
00357
00358 if(res >= 0)
00359 res = fprintf(logfile, "[events]\n\n");
00360
00361 if(res < 0){
00362 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: can't write metadata\n");
00363
00364 ast_log(LOG_DEBUG,"AlarmReceiver: can't write metadata\n");
00365 }
00366 else
00367 res = 0;
00368
00369 return res;
00370 }
00371
00372
00373
00374
00375
00376 static int write_event( FILE *logfile, event_node_t *event)
00377 {
00378 int res = 0;
00379
00380 if( fprintf(logfile, "%s\n", event->data) < 0)
00381 res = -1;
00382
00383 return res;
00384 }
00385
00386
00387
00388
00389
00390
00391
00392 static int log_events(struct ast_channel *chan, char *signalling_type, event_node_t *event)
00393 {
00394
00395 int res = 0;
00396 char workstring[sizeof(event_spool_dir)+sizeof(event_file)] = "";
00397 int fd;
00398 FILE *logfile;
00399 event_node_t *elp = event;
00400
00401 if (!ast_strlen_zero(event_spool_dir)) {
00402
00403
00404
00405 ast_copy_string(workstring, event_spool_dir, sizeof(workstring));
00406 strncat(workstring, event_file, sizeof(workstring) - strlen(workstring) - 1);
00407
00408
00409
00410 fd = mkstemp(workstring);
00411
00412 if(fd == -1){
00413 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: can't make temporary file\n");
00414 ast_log(LOG_DEBUG,"AlarmReceiver: can't make temporary file\n");
00415 res = -1;
00416 }
00417
00418 if(!res){
00419 logfile = fdopen(fd, "w");
00420 if(logfile){
00421
00422 res = write_metadata(logfile, signalling_type, chan);
00423 if(!res)
00424 while((!res) && (elp != NULL)){
00425 res = write_event(logfile, elp);
00426 elp = elp->next;
00427 }
00428 if(!res){
00429 if(fflush(logfile) == EOF)
00430 res = -1;
00431 if(!res){
00432 if(fclose(logfile) == EOF)
00433 res = -1;
00434 }
00435 }
00436 }
00437 else
00438 res = -1;
00439 }
00440 }
00441
00442 return res;
00443 }
00444
00445
00446
00447
00448
00449
00450
00451 static int receive_ademco_contact_id( struct ast_channel *chan, void *data, int fdto, int sdto, int tldn, event_node_t **ehead)
00452 {
00453 int i,j;
00454 int res = 0;
00455 int checksum;
00456 char event[17];
00457 event_node_t *enew, *elp;
00458 int got_some_digits = 0;
00459 int events_received = 0;
00460 int ack_retries = 0;
00461
00462 static char digit_map[15] = "0123456789*#ABC";
00463 static unsigned char digit_weights[15] = {10,1,2,3,4,5,6,7,8,9,11,12,13,14,15};
00464
00465 database_increment("calls-received");
00466
00467
00468
00469 if(option_verbose >= 4)
00470 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Waiting for first event from panel\n");
00471
00472 while(res >= 0){
00473
00474 if(got_some_digits == 0){
00475
00476
00477
00478
00479 if(option_verbose >= 4)
00480 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Sending 1400Hz 100ms burst (ACK)\n");
00481
00482
00483 res = send_tone_burst(chan, 1400.0, 100, tldn);
00484
00485 if(!res)
00486 res = ast_safe_sleep(chan, 100);
00487
00488 if(!res){
00489 if(option_verbose >= 4)
00490 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Sending 2300Hz 100ms burst (ACK)\n");
00491
00492 res = send_tone_burst(chan, 2300.0, 100, tldn);
00493 }
00494
00495 }
00496
00497 if( res >= 0)
00498 res = receive_dtmf_digits(chan, event, sizeof(event) - 1, fdto, sdto);
00499
00500 if (res < 0){
00501
00502 if(events_received == 0)
00503
00504 database_increment("no-events-received");
00505 else{
00506 if(ack_retries){
00507 if(option_verbose >= 4)
00508 ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: ACK retries during this call: %d\n", ack_retries);
00509
00510 database_increment("ack-retries");
00511 }
00512 }
00513 if(option_verbose >= 4)
00514 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: App exiting...\n");
00515 res = -1;
00516 break;
00517 }
00518
00519 if(res != 0){
00520
00521 if(option_verbose >= 2)
00522 ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Incomplete string: %s, trying again...\n", event);
00523
00524 if(!got_some_digits){
00525 got_some_digits = (!ast_strlen_zero(event)) ? 1 : 0;
00526 ack_retries++;
00527 }
00528 continue;
00529 }
00530
00531 got_some_digits = 1;
00532
00533 if(option_verbose >= 2)
00534 ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Received Event %s\n", event);
00535 ast_log(LOG_DEBUG, "AlarmReceiver: Received event: %s\n", event);
00536
00537
00538
00539 for(j = 0, checksum = 0; j < 16; j++){
00540 for(i = 0 ; i < sizeof(digit_map) ; i++){
00541 if(digit_map[i] == event[j])
00542 break;
00543 }
00544
00545 if(i == 16)
00546 break;
00547
00548 checksum += digit_weights[i];
00549 }
00550
00551 if(i == 16){
00552 if(option_verbose >= 2)
00553 ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Bad DTMF character %c, trying again\n", event[j]);
00554 continue;
00555 }
00556
00557
00558
00559 checksum = checksum % 15;
00560
00561 if(checksum){
00562 database_increment("checksum-errors");
00563 if(option_verbose >= 2)
00564 ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Nonzero checksum\n");
00565 ast_log(LOG_DEBUG, "AlarmReceiver: Nonzero checksum\n");
00566 continue;
00567 }
00568
00569
00570
00571 if(strncmp(event + 4, "18", 2)){
00572 if(strncmp(event + 4, "98", 2)){
00573 database_increment("format-errors");
00574 if(option_verbose >= 2)
00575 ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Wrong message type\n");
00576 ast_log(LOG_DEBUG, "AlarmReceiver: Wrong message type\n");
00577 continue;
00578 }
00579 }
00580
00581 events_received++;
00582
00583
00584
00585 if((enew = malloc(sizeof(event_node_t))) == NULL){
00586 if(option_verbose >= 1)
00587 ast_verbose(VERBOSE_PREFIX_1 "AlarmReceiver: Failed to allocate memory\n");
00588 ast_log(LOG_WARNING, "AlarmReceiver Failed to allocate memory\n");
00589 res = -1;
00590 break;
00591 }
00592
00593 memset(enew, 0, sizeof(event_node_t));
00594
00595 enew->next = NULL;
00596 ast_copy_string(enew->data, event, sizeof(enew->data));
00597
00598
00599
00600
00601
00602 if(*ehead == NULL){
00603 *ehead = enew;
00604 }
00605 else{
00606 for(elp = *ehead; elp->next != NULL; elp = elp->next)
00607 ;
00608
00609 elp->next = enew;
00610 }
00611
00612 if(res > 0)
00613 res = 0;
00614
00615
00616
00617 if((res == 0) && (log_individual_events))
00618 res = log_events(chan, ADEMCO_CONTACT_ID, enew);
00619
00620
00621
00622 if(res == 0)
00623 res = ast_safe_sleep(chan, 200);
00624
00625
00626
00627 if(res == 0)
00628 res = send_tone_burst(chan, 1400.0, 900, tldn);
00629 }
00630
00631
00632 return res;
00633 }
00634
00635
00636
00637
00638
00639
00640
00641 static int alarmreceiver_exec(struct ast_channel *chan, void *data)
00642 {
00643 int res = 0;
00644 struct localuser *u;
00645 event_node_t *elp, *efree;
00646 char signalling_type[64] = "";
00647
00648 event_node_t *event_head = NULL;
00649
00650 LOCAL_USER_ADD(u);
00651
00652
00653
00654 if(option_verbose >= 4)
00655 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Setting read and write formats to ULAW\n");
00656
00657 if (ast_set_write_format(chan,AST_FORMAT_ULAW)){
00658 ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",chan->name);
00659 LOCAL_USER_REMOVE(u);
00660 return -1;
00661 }
00662
00663 if (ast_set_read_format(chan,AST_FORMAT_ULAW)){
00664 ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",chan->name);
00665 LOCAL_USER_REMOVE(u);
00666 return -1;
00667 }
00668
00669
00670
00671 ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type));
00672
00673
00674
00675
00676 if(option_verbose >= 4)
00677 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Answering channel\n");
00678
00679 if (chan->_state != AST_STATE_UP) {
00680
00681 res = ast_answer(chan);
00682
00683 if (res) {
00684 LOCAL_USER_REMOVE(u);
00685 return -1;
00686 }
00687 }
00688
00689
00690
00691 if(option_verbose >= 4)
00692 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Waiting for connection to stabilize\n");
00693
00694 res = ast_safe_sleep(chan, 1250);
00695
00696
00697
00698 if(!res){
00699
00700
00701
00702
00703
00704 if(!strcmp(signalling_type, ADEMCO_CONTACT_ID))
00705 receive_ademco_contact_id(chan, data, fdtimeout, sdtimeout, toneloudness, &event_head);
00706 else
00707 res = -1;
00708 }
00709
00710
00711
00712
00713
00714 if((!res) && (log_individual_events == 0)){
00715 res = log_events(chan, signalling_type, event_head);
00716
00717 }
00718
00719
00720
00721
00722
00723 if((!res) && (!ast_strlen_zero(event_app)) && (event_head)){
00724 ast_log(LOG_DEBUG,"Alarmreceiver: executing: %s\n", event_app);
00725 ast_safe_system(event_app);
00726 }
00727
00728
00729
00730
00731
00732 for(elp = event_head; (elp != NULL);){
00733 efree = elp;
00734 elp = elp->next;
00735 free(efree);
00736 }
00737
00738
00739 LOCAL_USER_REMOVE(u);
00740
00741 return 0;
00742 }
00743
00744
00745
00746
00747
00748 static int load_config(void)
00749 {
00750 struct ast_config *cfg;
00751 char *p;
00752
00753
00754
00755 cfg = ast_config_load(ALMRCV_CONFIG);
00756
00757 if(!cfg){
00758
00759 if(option_verbose >= 4)
00760 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: No config file\n");
00761 }
00762 else{
00763
00764
00765 p = ast_variable_retrieve(cfg, "general", "eventcmd");
00766
00767 if(p){
00768 ast_copy_string(event_app, p, sizeof(event_app));
00769 event_app[sizeof(event_app) - 1] = '\0';
00770 }
00771
00772 p = ast_variable_retrieve(cfg, "general", "loudness");
00773 if(p){
00774 toneloudness = atoi(p);
00775 if(toneloudness < 100)
00776 toneloudness = 100;
00777 if(toneloudness > 8192)
00778 toneloudness = 8192;
00779 }
00780 p = ast_variable_retrieve(cfg, "general", "fdtimeout");
00781 if(p){
00782 fdtimeout = atoi(p);
00783 if(fdtimeout < 1000)
00784 fdtimeout = 1000;
00785 if(fdtimeout > 10000)
00786 fdtimeout = 10000;
00787 }
00788
00789 p = ast_variable_retrieve(cfg, "general", "sdtimeout");
00790 if(p){
00791 sdtimeout = atoi(p);
00792 if(sdtimeout < 110)
00793 sdtimeout = 110;
00794 if(sdtimeout > 4000)
00795 sdtimeout = 4000;
00796
00797 }
00798
00799 p = ast_variable_retrieve(cfg, "general", "logindividualevents");
00800 if(p){
00801 log_individual_events = ast_true(p);
00802
00803 }
00804
00805 p = ast_variable_retrieve(cfg, "general", "eventspooldir");
00806
00807 if(p){
00808 ast_copy_string(event_spool_dir, p, sizeof(event_spool_dir));
00809 event_spool_dir[sizeof(event_spool_dir) - 1] = '\0';
00810 }
00811
00812 p = ast_variable_retrieve(cfg, "general", "timestampformat");
00813
00814 if(p){
00815 ast_copy_string(time_stamp_format, p, sizeof(time_stamp_format));
00816 time_stamp_format[sizeof(time_stamp_format) - 1] = '\0';
00817 }
00818
00819 p = ast_variable_retrieve(cfg, "general", "db-family");
00820
00821 if(p){
00822 ast_copy_string(db_family, p, sizeof(db_family));
00823 db_family[sizeof(db_family) - 1] = '\0';
00824 }
00825 ast_config_destroy(cfg);
00826 }
00827 return 0;
00828
00829 }
00830
00831
00832
00833
00834
00835
00836 int unload_module(void)
00837 {
00838 int res;
00839
00840 res = ast_unregister_application(app);
00841
00842 STANDARD_HANGUP_LOCALUSERS;
00843
00844 return res;
00845 }
00846
00847 int load_module(void)
00848 {
00849 load_config();
00850 return ast_register_application(app, alarmreceiver_exec, synopsis, descrip);
00851 }
00852
00853 char *description(void)
00854 {
00855 return tdesc;
00856 }
00857
00858 int usecount(void)
00859 {
00860 int res;
00861 STANDARD_USECOUNT(res);
00862 return res;
00863 }
00864
00865 char *key()
00866 {
00867 return ASTERISK_GPL_KEY;
00868 }