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: 17945 $")
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 if(strncmp(event + 4, "18", 2)){
00570 if(strncmp(event + 4, "98", 2)){
00571 database_increment("format-errors");
00572 if(option_verbose >= 2)
00573 ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Wrong message type\n");
00574 ast_log(LOG_DEBUG, "AlarmReceiver: Wrong message type\n");
00575 continue;
00576 }
00577 }
00578
00579 events_received++;
00580
00581
00582
00583 if((enew = malloc(sizeof(event_node_t))) == NULL){
00584 if(option_verbose >= 1)
00585 ast_verbose(VERBOSE_PREFIX_1 "AlarmReceiver: Failed to allocate memory\n");
00586 ast_log(LOG_WARNING, "AlarmReceiver Failed to allocate memory\n");
00587 res = -1;
00588 break;
00589 }
00590
00591 memset(enew, 0, sizeof(event_node_t));
00592
00593 enew->next = NULL;
00594 ast_copy_string(enew->data, event, sizeof(enew->data));
00595
00596
00597
00598
00599
00600 if(*ehead == NULL){
00601 *ehead = enew;
00602 }
00603 else{
00604 for(elp = *ehead; elp->next != NULL; elp = elp->next)
00605 ;
00606
00607 elp->next = enew;
00608 }
00609
00610 if(res > 0)
00611 res = 0;
00612
00613
00614
00615 if((res == 0) && (log_individual_events))
00616 res = log_events(chan, ADEMCO_CONTACT_ID, enew);
00617
00618
00619
00620 if(res == 0)
00621 res = ast_safe_sleep(chan, 200);
00622
00623
00624
00625 if(res == 0)
00626 res = send_tone_burst(chan, 1400.0, 900, tldn);
00627 }
00628
00629
00630 return res;
00631 }
00632
00633
00634
00635
00636
00637
00638
00639 static int alarmreceiver_exec(struct ast_channel *chan, void *data)
00640 {
00641 int res = 0;
00642 struct localuser *u;
00643 event_node_t *elp, *efree;
00644 char signalling_type[64] = "";
00645
00646 event_node_t *event_head = NULL;
00647
00648 LOCAL_USER_ADD(u);
00649
00650
00651
00652 if(option_verbose >= 4)
00653 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Setting read and write formats to ULAW\n");
00654
00655 if (ast_set_write_format(chan,AST_FORMAT_ULAW)){
00656 ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",chan->name);
00657 LOCAL_USER_REMOVE(u);
00658 return -1;
00659 }
00660
00661 if (ast_set_read_format(chan,AST_FORMAT_ULAW)){
00662 ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",chan->name);
00663 LOCAL_USER_REMOVE(u);
00664 return -1;
00665 }
00666
00667
00668
00669 ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type));
00670
00671
00672
00673
00674 if(option_verbose >= 4)
00675 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Answering channel\n");
00676
00677 if (chan->_state != AST_STATE_UP) {
00678
00679 res = ast_answer(chan);
00680
00681 if (res) {
00682 LOCAL_USER_REMOVE(u);
00683 return -1;
00684 }
00685 }
00686
00687
00688
00689 if(option_verbose >= 4)
00690 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Waiting for connection to stabilize\n");
00691
00692 res = ast_safe_sleep(chan, 1250);
00693
00694
00695
00696 if(!res){
00697
00698
00699
00700
00701
00702 if(!strcmp(signalling_type, ADEMCO_CONTACT_ID))
00703 receive_ademco_contact_id(chan, data, fdtimeout, sdtimeout, toneloudness, &event_head);
00704 else
00705 res = -1;
00706 }
00707
00708
00709
00710
00711
00712 if((!res) && (log_individual_events == 0)){
00713 res = log_events(chan, signalling_type, event_head);
00714
00715 }
00716
00717
00718
00719
00720
00721 if((!res) && (!ast_strlen_zero(event_app)) && (event_head)){
00722 ast_log(LOG_DEBUG,"Alarmreceiver: executing: %s\n", event_app);
00723 ast_safe_system(event_app);
00724 }
00725
00726
00727
00728
00729
00730 for(elp = event_head; (elp != NULL);){
00731 efree = elp;
00732 elp = elp->next;
00733 free(efree);
00734 }
00735
00736
00737 LOCAL_USER_REMOVE(u);
00738
00739 return 0;
00740 }
00741
00742
00743
00744
00745
00746 static int load_config(void)
00747 {
00748 struct ast_config *cfg;
00749 char *p;
00750
00751
00752
00753 cfg = ast_config_load(ALMRCV_CONFIG);
00754
00755 if(!cfg){
00756
00757 if(option_verbose >= 4)
00758 ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: No config file\n");
00759 }
00760 else{
00761
00762
00763 p = ast_variable_retrieve(cfg, "general", "eventcmd");
00764
00765 if(p){
00766 ast_copy_string(event_app, p, sizeof(event_app));
00767 event_app[sizeof(event_app) - 1] = '\0';
00768 }
00769
00770 p = ast_variable_retrieve(cfg, "general", "loudness");
00771 if(p){
00772 toneloudness = atoi(p);
00773 if(toneloudness < 100)
00774 toneloudness = 100;
00775 if(toneloudness > 8192)
00776 toneloudness = 8192;
00777 }
00778 p = ast_variable_retrieve(cfg, "general", "fdtimeout");
00779 if(p){
00780 fdtimeout = atoi(p);
00781 if(fdtimeout < 1000)
00782 fdtimeout = 1000;
00783 if(fdtimeout > 10000)
00784 fdtimeout = 10000;
00785 }
00786
00787 p = ast_variable_retrieve(cfg, "general", "sdtimeout");
00788 if(p){
00789 sdtimeout = atoi(p);
00790 if(sdtimeout < 110)
00791 sdtimeout = 110;
00792 if(sdtimeout > 4000)
00793 sdtimeout = 4000;
00794
00795 }
00796
00797 p = ast_variable_retrieve(cfg, "general", "logindividualevents");
00798 if(p){
00799 log_individual_events = ast_true(p);
00800
00801 }
00802
00803 p = ast_variable_retrieve(cfg, "general", "eventspooldir");
00804
00805 if(p){
00806 ast_copy_string(event_spool_dir, p, sizeof(event_spool_dir));
00807 event_spool_dir[sizeof(event_spool_dir) - 1] = '\0';
00808 }
00809
00810 p = ast_variable_retrieve(cfg, "general", "timestampformat");
00811
00812 if(p){
00813 ast_copy_string(time_stamp_format, p, sizeof(time_stamp_format));
00814 time_stamp_format[sizeof(time_stamp_format) - 1] = '\0';
00815 }
00816
00817 p = ast_variable_retrieve(cfg, "general", "db-family");
00818
00819 if(p){
00820 ast_copy_string(db_family, p, sizeof(db_family));
00821 db_family[sizeof(db_family) - 1] = '\0';
00822 }
00823 ast_config_destroy(cfg);
00824 }
00825 return 0;
00826
00827 }
00828
00829
00830
00831
00832
00833
00834 int unload_module(void)
00835 {
00836 int res;
00837
00838 res = ast_unregister_application(app);
00839
00840 STANDARD_HANGUP_LOCALUSERS;
00841
00842 return res;
00843 }
00844
00845 int load_module(void)
00846 {
00847 load_config();
00848 return ast_register_application(app, alarmreceiver_exec, synopsis, descrip);
00849 }
00850
00851 char *description(void)
00852 {
00853 return tdesc;
00854 }
00855
00856 int usecount(void)
00857 {
00858 int res;
00859 STANDARD_USECOUNT(res);
00860 return res;
00861 }
00862
00863 char *key()
00864 {
00865 return ASTERISK_GPL_KEY;
00866 }