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