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: 7221 $")
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");
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 break;
00219 }
00220 if (ast_write(chan, &wf)){
00221 if(option_verbose >= 4)
00222 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Failed to write frame on %s\n", chan->name);
00223 ast_log(LOG_WARNING, "AlarmReceiver Failed to write frame on %s\n",chan->name);
00224 res = -1;
00225 break;
00226 }
00227 }
00228
00229 ast_frfree(f);
00230 }
00231 return res;
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int length, int fdto, int sdto)
00246 {
00247 int res = 0;
00248 int i = 0;
00249 int r;
00250 struct ast_frame *f;
00251 struct timeval lastdigittime;
00252
00253 lastdigittime = ast_tvnow();
00254 for(;;){
00255
00256 if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) >
00257 ((i > 0) ? sdto : fdto)){
00258 if(option_verbose >= 4)
00259 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: DTMF Digit Timeout on %s\n", chan->name);
00260
00261 ast_log(LOG_DEBUG,"AlarmReceiver: DTMF timeout on chan %s\n",chan->name);
00262
00263 res = 1;
00264 break;
00265 }
00266
00267 if ((r = ast_waitfor(chan, -1) < 0)) {
00268 ast_log(LOG_DEBUG, "Waitfor returned %d\n", r);
00269 continue;
00270 }
00271
00272 f = ast_read(chan);
00273
00274 if (f == NULL){
00275 res = -1;
00276 break;
00277 }
00278
00279
00280 if ((f->frametype == AST_FRAME_CONTROL) &&
00281 (f->subclass == AST_CONTROL_HANGUP)){
00282 ast_frfree(f);
00283 res = -1;
00284 break;
00285 }
00286
00287
00288 if (f->frametype != AST_FRAME_DTMF){
00289 ast_frfree(f);
00290 continue;
00291 }
00292
00293 digit_string[i++] = f->subclass;
00294
00295 ast_frfree(f);
00296
00297
00298 if(i >= length)
00299 break;
00300
00301 lastdigittime = ast_tvnow();
00302 }
00303
00304 digit_string[i] = '\0';
00305 return res;
00306
00307 }
00308
00309
00310
00311
00312
00313 static int write_metadata( FILE *logfile, char *signalling_type, struct ast_channel *chan)
00314 {
00315 int res = 0;
00316 time_t t;
00317 struct tm now;
00318 char *cl,*cn;
00319 char workstring[80];
00320 char timestamp[80];
00321
00322
00323 if (chan->cid.cid_num)
00324 ast_copy_string(workstring, chan->cid.cid_num, sizeof(workstring));
00325 workstring[sizeof(workstring) - 1] = '\0';
00326
00327 ast_callerid_parse(workstring, &cn, &cl);
00328 if (cl)
00329 ast_shrink_phone_number(cl);
00330
00331
00332
00333
00334 time(&t);
00335 ast_localtime(&t, &now, NULL);
00336
00337
00338
00339 strftime(timestamp, sizeof(timestamp), time_stamp_format, &now);
00340
00341
00342 res = fprintf(logfile, "\n\n[metadata]\n\n");
00343
00344 if(res >= 0)
00345 res = fprintf(logfile, "PROTOCOL=%s\n", signalling_type);
00346
00347 if(res >= 0)
00348 res = fprintf(logfile, "CALLINGFROM=%s\n", (!cl) ? "<unknown>" : cl);
00349
00350 if(res >- 0)
00351 res = fprintf(logfile, "CALLERNAME=%s\n", (!cn) ? "<unknown>" : cn);
00352
00353 if(res >= 0)
00354 res = fprintf(logfile, "TIMESTAMP=%s\n\n", timestamp);
00355
00356 if(res >= 0)
00357 res = fprintf(logfile, "[events]\n\n");
00358
00359 if(res < 0){
00360 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: can't write metadata\n");
00361
00362 ast_log(LOG_DEBUG,"AlarmReceiver: can't write metadata\n");
00363 }
00364 else
00365 res = 0;
00366
00367 return res;
00368 }
00369
00370
00371
00372
00373
00374 static int write_event( FILE *logfile, event_node_t *event)
00375 {
00376 int res = 0;
00377
00378 if( fprintf(logfile, "%s\n", event->data) < 0)
00379 res = -1;
00380
00381 return res;
00382 }
00383
00384
00385
00386
00387
00388
00389
00390 static int log_events(struct ast_channel *chan, char *signalling_type, event_node_t *event)
00391 {
00392
00393 int res = 0;
00394 char workstring[sizeof(event_spool_dir)+sizeof(event_file)] = "";
00395 int fd;
00396 FILE *logfile;
00397 event_node_t *elp = event;
00398
00399 if (!ast_strlen_zero(event_spool_dir)) {
00400
00401
00402
00403 ast_copy_string(workstring, event_spool_dir, sizeof(workstring));
00404 strncat(workstring, event_file, sizeof(workstring) - strlen(workstring) - 1);
00405
00406
00407
00408 fd = mkstemp(workstring);
00409
00410 if(fd == -1){
00411 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: can't make temporary file\n");
00412 ast_log(LOG_DEBUG,"AlarmReceiver: can't make temporary file\n");
00413 res = -1;
00414 }
00415
00416 if(!res){
00417 logfile = fdopen(fd, "w");
00418 if(logfile){
00419
00420 res = write_metadata(logfile, signalling_type, chan);
00421 if(!res)
00422 while((!res) && (elp != NULL)){
00423 res = write_event(logfile, elp);
00424 elp = elp->next;
00425 }
00426 if(!res){
00427 if(fflush(logfile) == EOF)
00428 res = -1;
00429 if(!res){
00430 if(fclose(logfile) == EOF)
00431 res = -1;
00432 }
00433 }
00434 }
00435 else
00436 res = -1;
00437 }
00438 }
00439
00440 return res;
00441 }
00442
00443
00444
00445
00446
00447
00448
00449 static int receive_ademco_contact_id( struct ast_channel *chan, void *data, int fdto, int sdto, int tldn, event_node_t **ehead)
00450 {
00451 int i,j;
00452 int res = 0;
00453 int checksum;
00454 char event[17];
00455 event_node_t *enew, *elp;
00456 int got_some_digits = 0;
00457 int events_received = 0;
00458 int ack_retries = 0;
00459
00460 static char digit_map[15] = "0123456789*#ABC";
00461 static unsigned char digit_weights[15] = {10,1,2,3,4,5,6,7,8,9,11,12,13,14,15};
00462
00463 database_increment("calls-received");
00464
00465
00466
00467 if(option_verbose >= 4)
00468 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Waiting for first event from panel\n");
00469
00470 while(res >= 0){
00471
00472 if(got_some_digits == 0){
00473
00474
00475
00476
00477 if(option_verbose >= 4)
00478 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Sending 1400Hz 100ms burst (ACK)\n");
00479
00480
00481 res = send_tone_burst(chan, 1400.0, 100, tldn);
00482
00483 if(!res)
00484 res = ast_safe_sleep(chan, 100);
00485
00486 if(!res){
00487 if(option_verbose >= 4)
00488 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Sending 2300Hz 100ms burst (ACK)\n");
00489
00490 res = send_tone_burst(chan, 2300.0, 100, tldn);
00491 }
00492
00493 }
00494
00495 if( res >= 0)
00496 res = receive_dtmf_digits(chan, event, sizeof(event) - 1, fdto, sdto);
00497
00498 if (res < 0){
00499
00500 if(events_received == 0)
00501
00502 database_increment("no-events-received");
00503 else{
00504 if(ack_retries){
00505 if(option_verbose >= 4)
00506 ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: ACK retries during this call: %d\n", ack_retries);
00507
00508 database_increment("ack-retries");
00509 }
00510 }
00511 if(option_verbose >= 4)
00512 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: App exiting...\n");
00513 res = -1;
00514 break;
00515 }
00516
00517 if(res != 0){
00518
00519 if(option_verbose >= 2)
00520 ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Incomplete string: %s, trying again...\n", event);
00521
00522 if(!got_some_digits){
00523 got_some_digits = (!ast_strlen_zero(event)) ? 1 : 0;
00524 ack_retries++;
00525 }
00526 continue;
00527 }
00528
00529 got_some_digits = 1;
00530
00531 if(option_verbose >= 2)
00532 ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Received Event %s\n", event);
00533 ast_log(LOG_DEBUG, "AlarmReceiver: Received event: %s\n", event);
00534
00535
00536
00537 for(j = 0, checksum = 0; j < 16; j++){
00538 for(i = 0 ; i < sizeof(digit_map) ; i++){
00539 if(digit_map[i] == event[j])
00540 break;
00541 }
00542
00543 if(i == 16)
00544 break;
00545
00546 checksum += digit_weights[i];
00547 }
00548
00549 if(i == 16){
00550 if(option_verbose >= 2)
00551 ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Bad DTMF character %c, trying again\n", event[j]);
00552 continue;
00553 }
00554
00555
00556
00557 checksum = checksum % 15;
00558
00559 if(checksum){
00560 database_increment("checksum-errors");
00561 if(option_verbose >= 2){
00562 ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Nonzero checksum\n");
00563 ast_log(LOG_DEBUG, "AlarmReceiver: Nonzero checksum\n");
00564 continue;
00565 }
00566 }
00567
00568
00569
00570 if(strncmp(event + 4, "18", 2)){
00571 if(strncmp(event + 4, "98", 2)){
00572 database_increment("format-errors");
00573 if(option_verbose >= 2)
00574 ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Wrong message type\n");
00575 ast_log(LOG_DEBUG, "AlarmReceiver: Wrong message type\n");
00576 continue;
00577 }
00578 }
00579
00580 events_received++;
00581
00582
00583
00584 if((enew = malloc(sizeof(event_node_t))) == NULL){
00585 if(option_verbose >= 1)
00586 ast_verbose(VERBOSE_PREFIX_1 "AlarmReceiver: Failed to allocate memory\n");
00587 ast_log(LOG_WARNING, "AlarmReceiver Failed to allocate memory\n");
00588 res = -1;
00589 break;
00590 }
00591
00592 memset(enew, 0, sizeof(event_node_t));
00593
00594 enew->next = NULL;
00595 ast_copy_string(enew->data, event, sizeof(enew->data));
00596
00597
00598
00599
00600
00601 if(*ehead == NULL){
00602 *ehead = enew;
00603 }
00604 else{
00605 for(elp = *ehead; elp->next != NULL; elp = elp->next)
00606 ;
00607
00608 elp->next = enew;
00609 }
00610
00611 if(res > 0)
00612 res = 0;
00613
00614
00615
00616 if((res == 0) && (log_individual_events))
00617 res = log_events(chan, ADEMCO_CONTACT_ID, enew);
00618
00619
00620
00621 if(res == 0)
00622 res = ast_safe_sleep(chan, 200);
00623
00624
00625
00626 if(res == 0)
00627 res = send_tone_burst(chan, 1400.0, 900, tldn);
00628 }
00629
00630
00631 return res;
00632 }
00633
00634
00635
00636
00637
00638
00639
00640 static int alarmreceiver_exec(struct ast_channel *chan, void *data)
00641 {
00642 int res = 0;
00643 struct localuser *u;
00644 event_node_t *elp, *efree;
00645 char signalling_type[64] = "";
00646
00647 event_node_t *event_head = NULL;
00648
00649 LOCAL_USER_ADD(u);
00650
00651
00652
00653 if(option_verbose >= 4)
00654 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Setting read and write formats to ULAW\n");
00655
00656 if (ast_set_write_format(chan,AST_FORMAT_ULAW)){
00657 ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",chan->name);
00658 LOCAL_USER_REMOVE(u);
00659 return -1;
00660 }
00661
00662 if (ast_set_read_format(chan,AST_FORMAT_ULAW)){
00663 ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",chan->name);
00664 LOCAL_USER_REMOVE(u);
00665 return -1;
00666 }
00667
00668
00669
00670 ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type));
00671
00672
00673
00674
00675 if(option_verbose >= 4)
00676 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Answering channel\n");
00677
00678 if (chan->_state != AST_STATE_UP) {
00679
00680 res = ast_answer(chan);
00681
00682 if (res) {
00683 LOCAL_USER_REMOVE(u);
00684 return -1;
00685 }
00686 }
00687
00688
00689
00690 if(option_verbose >= 4)
00691 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Waiting for connection to stabilize\n");
00692
00693 res = ast_safe_sleep(chan, 1250);
00694
00695
00696
00697 if(!res){
00698
00699
00700
00701
00702
00703 if(!strcmp(signalling_type, ADEMCO_CONTACT_ID))
00704 receive_ademco_contact_id(chan, data, fdtimeout, sdtimeout, toneloudness, &event_head);
00705 else
00706 res = -1;
00707 }
00708
00709
00710
00711
00712
00713 if((!res) && (log_individual_events == 0)){
00714 res = log_events(chan, signalling_type, event_head);
00715
00716 }
00717
00718
00719
00720
00721
00722 if((!res) && (!ast_strlen_zero(event_app)) && (event_head)){
00723 ast_log(LOG_DEBUG,"Alarmreceiver: executing: %s\n", event_app);
00724 ast_safe_system(event_app);
00725 }
00726
00727
00728
00729
00730
00731 for(elp = event_head; (elp != NULL);){
00732 efree = elp;
00733 elp = elp->next;
00734 free(efree);
00735 }
00736
00737
00738 LOCAL_USER_REMOVE(u);
00739
00740 return 0;
00741 }
00742
00743
00744
00745
00746
00747 static int load_config(void)
00748 {
00749 struct ast_config *cfg;
00750 char *p;
00751
00752
00753
00754 cfg = ast_config_load(ALMRCV_CONFIG);
00755
00756 if(!cfg){
00757
00758 if(option_verbose >= 4)
00759 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: No config file\n");
00760 }
00761 else{
00762
00763
00764 p = ast_variable_retrieve(cfg, "general", "eventcmd");
00765
00766 if(p){
00767 ast_copy_string(event_app, p, sizeof(event_app));
00768 event_app[sizeof(event_app) - 1] = '\0';
00769 }
00770
00771 p = ast_variable_retrieve(cfg, "general", "loudness");
00772 if(p){
00773 toneloudness = atoi(p);
00774 if(toneloudness < 100)
00775 toneloudness = 100;
00776 if(toneloudness > 8192)
00777 toneloudness = 8192;
00778 }
00779 p = ast_variable_retrieve(cfg, "general", "fdtimeout");
00780 if(p){
00781 fdtimeout = atoi(p);
00782 if(fdtimeout < 1000)
00783 fdtimeout = 1000;
00784 if(fdtimeout > 10000)
00785 fdtimeout = 10000;
00786 }
00787
00788 p = ast_variable_retrieve(cfg, "general", "sdtimeout");
00789 if(p){
00790 sdtimeout = atoi(p);
00791 if(sdtimeout < 110)
00792 sdtimeout = 110;
00793 if(sdtimeout > 4000)
00794 sdtimeout = 4000;
00795
00796 }
00797
00798 p = ast_variable_retrieve(cfg, "general", "logindividualevents");
00799 if(p){
00800 log_individual_events = ast_true(p);
00801
00802 }
00803
00804 p = ast_variable_retrieve(cfg, "general", "eventspooldir");
00805
00806 if(p){
00807 ast_copy_string(event_spool_dir, p, sizeof(event_spool_dir));
00808 event_spool_dir[sizeof(event_spool_dir) - 1] = '\0';
00809 }
00810
00811 p = ast_variable_retrieve(cfg, "general", "timestampformat");
00812
00813 if(p){
00814 ast_copy_string(time_stamp_format, p, sizeof(time_stamp_format));
00815 time_stamp_format[sizeof(time_stamp_format) - 1] = '\0';
00816 }
00817
00818 p = ast_variable_retrieve(cfg, "general", "db-family");
00819
00820 if(p){
00821 ast_copy_string(db_family, p, sizeof(db_family));
00822 db_family[sizeof(db_family) - 1] = '\0';
00823 }
00824 ast_config_destroy(cfg);
00825 }
00826 return 0;
00827
00828 }
00829
00830
00831
00832
00833
00834
00835 int unload_module(void)
00836 {
00837 int res;
00838
00839 res = ast_unregister_application(app);
00840
00841 STANDARD_HANGUP_LOCALUSERS;
00842
00843 return res;
00844 }
00845
00846 int load_module(void)
00847 {
00848 load_config();
00849 return ast_register_application(app, alarmreceiver_exec, synopsis, descrip);
00850 }
00851
00852 char *description(void)
00853 {
00854 return tdesc;
00855 }
00856
00857 int usecount(void)
00858 {
00859 int res;
00860 STANDARD_USECOUNT(res);
00861 return res;
00862 }
00863
00864 char *key()
00865 {
00866 return ASTERISK_GPL_KEY;
00867 }