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: 211580 $")
00035
00036 #include <math.h>
00037 #include <sys/wait.h>
00038 #include <sys/time.h>
00039
00040 #include "asterisk/lock.h"
00041 #include "asterisk/file.h"
00042 #include "asterisk/channel.h"
00043 #include "asterisk/pbx.h"
00044 #include "asterisk/module.h"
00045 #include "asterisk/translate.h"
00046 #include "asterisk/ulaw.h"
00047 #include "asterisk/app.h"
00048 #include "asterisk/dsp.h"
00049 #include "asterisk/config.h"
00050 #include "asterisk/localtime.h"
00051 #include "asterisk/callerid.h"
00052 #include "asterisk/astdb.h"
00053 #include "asterisk/utils.h"
00054
00055 #define ALMRCV_CONFIG "alarmreceiver.conf"
00056 #define ADEMCO_CONTACT_ID "ADEMCO_CONTACT_ID"
00057
00058 struct event_node{
00059 char data[17];
00060 struct event_node *next;
00061 };
00062
00063 typedef struct event_node event_node_t;
00064
00065 static char *app = "AlarmReceiver";
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 static int fdtimeout = 2000;
00090 static int sdtimeout = 200;
00091 static int toneloudness = 4096;
00092 static int log_individual_events = 0;
00093 static char event_spool_dir[128] = {'\0'};
00094 static char event_app[128] = {'\0'};
00095 static char db_family[128] = {'\0'};
00096 static char time_stamp_format[128] = {"%a %b %d, %Y @ %H:%M:%S %Z"};
00097
00098
00099 static char event_file[14] = "/event-XXXXXX";
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 ast_verb(4, "AlarmReceiver: Creating database entry %s and setting to 1\n", key);
00122
00123 res = ast_db_put(db_family, key, "1");
00124 return;
00125 }
00126
00127 sscanf(value, "%30u", &v);
00128 v++;
00129
00130 ast_verb(4, "AlarmReceiver: New value for %s: %u\n", key, v);
00131
00132 snprintf(value, sizeof(value), "%u", v);
00133
00134 res = ast_db_put(db_family, key, value);
00135
00136 if (res)
00137 ast_verb(4, "AlarmReceiver: database_increment write error\n");
00138
00139 return;
00140 }
00141
00142
00143
00144
00145
00146 static void make_tone_burst(unsigned char *data, float freq, float loudness, int len, int *x)
00147 {
00148 int i;
00149 float val;
00150
00151 for (i = 0; i < len; i++) {
00152 val = loudness * sin((freq * 2.0 * M_PI * (*x)++)/8000.0);
00153 data[i] = AST_LIN2MU((int)val);
00154 }
00155
00156
00157
00158 if (*x >= 8000)
00159 *x = 0;
00160 return;
00161 }
00162
00163
00164
00165
00166
00167 static int send_tone_burst(struct ast_channel *chan, float freq, int duration, int tldn)
00168 {
00169 int res = 0;
00170 int i = 0;
00171 int x = 0;
00172 struct ast_frame *f, wf;
00173
00174 struct {
00175 unsigned char offset[AST_FRIENDLY_OFFSET];
00176 unsigned char buf[640];
00177 } tone_block;
00178
00179 for (;;) {
00180
00181 if (ast_waitfor(chan, -1) < 0) {
00182 res = -1;
00183 break;
00184 }
00185
00186 f = ast_read(chan);
00187 if (!f) {
00188 res = -1;
00189 break;
00190 }
00191
00192 if (f->frametype == AST_FRAME_VOICE) {
00193 wf.frametype = AST_FRAME_VOICE;
00194 wf.subclass = AST_FORMAT_ULAW;
00195 wf.offset = AST_FRIENDLY_OFFSET;
00196 wf.mallocd = 0;
00197 wf.data.ptr = tone_block.buf;
00198 wf.datalen = f->datalen;
00199 wf.samples = wf.datalen;
00200
00201 make_tone_burst(tone_block.buf, freq, (float) tldn, wf.datalen, &x);
00202
00203 i += wf.datalen / 8;
00204 if (i > duration) {
00205 ast_frfree(f);
00206 break;
00207 }
00208 if (ast_write(chan, &wf)) {
00209 ast_verb(4, "AlarmReceiver: Failed to write frame on %s\n", chan->name);
00210 ast_log(LOG_WARNING, "AlarmReceiver Failed to write frame on %s\n",chan->name);
00211 res = -1;
00212 ast_frfree(f);
00213 break;
00214 }
00215 }
00216
00217 ast_frfree(f);
00218 }
00219 return res;
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int length, int fdto, int sdto)
00233 {
00234 int res = 0;
00235 int i = 0;
00236 int r;
00237 struct ast_frame *f;
00238 struct timeval lastdigittime;
00239
00240 lastdigittime = ast_tvnow();
00241 for (;;) {
00242
00243 if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((i > 0) ? sdto : fdto)) {
00244 ast_verb(4, "AlarmReceiver: DTMF Digit Timeout on %s\n", chan->name);
00245 ast_debug(1,"AlarmReceiver: DTMF timeout on chan %s\n",chan->name);
00246 res = 1;
00247 break;
00248 }
00249
00250 if ((r = ast_waitfor(chan, -1) < 0)) {
00251 ast_debug(1, "Waitfor returned %d\n", r);
00252 continue;
00253 }
00254
00255 f = ast_read(chan);
00256
00257 if (f == NULL) {
00258 res = -1;
00259 break;
00260 }
00261
00262
00263 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
00264 if (f->data.uint32) {
00265 chan->hangupcause = f->data.uint32;
00266 }
00267 ast_frfree(f);
00268 res = -1;
00269 break;
00270 }
00271
00272
00273 if (f->frametype != AST_FRAME_DTMF) {
00274 ast_frfree(f);
00275 continue;
00276 }
00277
00278 digit_string[i++] = f->subclass;
00279
00280 ast_frfree(f);
00281
00282
00283 if(i >= length)
00284 break;
00285
00286 lastdigittime = ast_tvnow();
00287 }
00288
00289 digit_string[i] = '\0';
00290 return res;
00291 }
00292
00293
00294
00295
00296 static int write_metadata( FILE *logfile, char *signalling_type, struct ast_channel *chan)
00297 {
00298 int res = 0;
00299 struct timeval t;
00300 struct ast_tm now;
00301 char *cl,*cn;
00302 char workstring[80];
00303 char timestamp[80];
00304
00305
00306 if (chan->cid.cid_num)
00307 ast_copy_string(workstring, chan->cid.cid_num, sizeof(workstring));
00308 workstring[sizeof(workstring) - 1] = '\0';
00309
00310 ast_callerid_parse(workstring, &cn, &cl);
00311 if (cl)
00312 ast_shrink_phone_number(cl);
00313
00314
00315 t = ast_tvnow();
00316 ast_localtime(&t, &now, NULL);
00317
00318
00319 ast_strftime(timestamp, sizeof(timestamp), time_stamp_format, &now);
00320
00321 res = fprintf(logfile, "\n\n[metadata]\n\n");
00322
00323 if (res >= 0)
00324 res = fprintf(logfile, "PROTOCOL=%s\n", signalling_type);
00325
00326 if (res >= 0)
00327 res = fprintf(logfile, "CALLINGFROM=%s\n", (!cl) ? "<unknown>" : cl);
00328
00329 if (res >- 0)
00330 res = fprintf(logfile, "CALLERNAME=%s\n", (!cn) ? "<unknown>" : cn);
00331
00332 if (res >= 0)
00333 res = fprintf(logfile, "TIMESTAMP=%s\n\n", timestamp);
00334
00335 if (res >= 0)
00336 res = fprintf(logfile, "[events]\n\n");
00337
00338 if (res < 0) {
00339 ast_verb(3, "AlarmReceiver: can't write metadata\n");
00340 ast_debug(1,"AlarmReceiver: can't write metadata\n");
00341 } else
00342 res = 0;
00343
00344 return res;
00345 }
00346
00347
00348
00349
00350 static int write_event( FILE *logfile, event_node_t *event)
00351 {
00352 int res = 0;
00353
00354 if (fprintf(logfile, "%s\n", event->data) < 0)
00355 res = -1;
00356
00357 return res;
00358 }
00359
00360
00361
00362
00363
00364 static int log_events(struct ast_channel *chan, char *signalling_type, event_node_t *event)
00365 {
00366
00367 int res = 0;
00368 char workstring[sizeof(event_spool_dir)+sizeof(event_file)] = "";
00369 int fd;
00370 FILE *logfile;
00371 event_node_t *elp = event;
00372
00373 if (!ast_strlen_zero(event_spool_dir)) {
00374
00375
00376 ast_copy_string(workstring, event_spool_dir, sizeof(workstring));
00377 strncat(workstring, event_file, sizeof(workstring) - strlen(workstring) - 1);
00378
00379
00380 fd = mkstemp(workstring);
00381
00382 if (fd == -1) {
00383 ast_verb(3, "AlarmReceiver: can't make temporary file\n");
00384 ast_debug(1,"AlarmReceiver: can't make temporary file\n");
00385 res = -1;
00386 }
00387
00388 if (!res) {
00389 logfile = fdopen(fd, "w");
00390 if (logfile) {
00391
00392 res = write_metadata(logfile, signalling_type, chan);
00393 if (!res)
00394 while ((!res) && (elp != NULL)) {
00395 res = write_event(logfile, elp);
00396 elp = elp->next;
00397 }
00398 if (!res) {
00399 if (fflush(logfile) == EOF)
00400 res = -1;
00401 if (!res) {
00402 if (fclose(logfile) == EOF)
00403 res = -1;
00404 }
00405 }
00406 } else
00407 res = -1;
00408 }
00409 }
00410
00411 return res;
00412 }
00413
00414
00415
00416
00417
00418
00419 static int receive_ademco_contact_id( struct ast_channel *chan, void *data, int fdto, int sdto, int tldn, event_node_t **ehead)
00420 {
00421 int i, j;
00422 int res = 0;
00423 int checksum;
00424 char event[17];
00425 event_node_t *enew, *elp;
00426 int got_some_digits = 0;
00427 int events_received = 0;
00428 int ack_retries = 0;
00429
00430 static char digit_map[15] = "0123456789*#ABC";
00431 static unsigned char digit_weights[15] = {10,1,2,3,4,5,6,7,8,9,11,12,13,14,15};
00432
00433 database_increment("calls-received");
00434
00435
00436 ast_verb(4, "AlarmReceiver: Waiting for first event from panel\n");
00437
00438 while (res >= 0) {
00439 if (got_some_digits == 0) {
00440
00441 ast_verb(4, "AlarmReceiver: Sending 1400Hz 100ms burst (ACK)\n");
00442 res = send_tone_burst(chan, 1400.0, 100, tldn);
00443 if (!res)
00444 res = ast_safe_sleep(chan, 100);
00445 if (!res) {
00446 ast_verb(4, "AlarmReceiver: Sending 2300Hz 100ms burst (ACK)\n");
00447 res = send_tone_burst(chan, 2300.0, 100, tldn);
00448 }
00449 }
00450 if ( res >= 0)
00451 res = receive_dtmf_digits(chan, event, sizeof(event) - 1, fdto, sdto);
00452 if (res < 0) {
00453 if (events_received == 0) {
00454
00455 database_increment("no-events-received");
00456 } else {
00457 if (ack_retries) {
00458 ast_verb(4, "AlarmReceiver: ACK retries during this call: %d\n", ack_retries);
00459 database_increment("ack-retries");
00460 }
00461 }
00462 ast_verb(4, "AlarmReceiver: App exiting...\n");
00463 res = -1;
00464 break;
00465 }
00466
00467 if (res != 0) {
00468
00469 ast_verb(2, "AlarmReceiver: Incomplete string: %s, trying again...\n", event);
00470
00471 if (!got_some_digits) {
00472 got_some_digits = (!ast_strlen_zero(event)) ? 1 : 0;
00473 ack_retries++;
00474 }
00475 continue;
00476 }
00477
00478 got_some_digits = 1;
00479
00480 ast_verb(2, "AlarmReceiver: Received Event %s\n", event);
00481 ast_debug(1, "AlarmReceiver: Received event: %s\n", event);
00482
00483
00484
00485 for (j = 0, checksum = 0; j < 16; j++) {
00486 for (i = 0; i < sizeof(digit_map); i++) {
00487 if (digit_map[i] == event[j])
00488 break;
00489 }
00490
00491 if (i == 16)
00492 break;
00493
00494 checksum += digit_weights[i];
00495 }
00496 if (i == 16) {
00497 ast_verb(2, "AlarmReceiver: Bad DTMF character %c, trying again\n", event[j]);
00498 continue;
00499 }
00500
00501
00502
00503 checksum = checksum % 15;
00504
00505 if (checksum) {
00506 database_increment("checksum-errors");
00507 ast_verb(2, "AlarmReceiver: Nonzero checksum\n");
00508 ast_debug(1, "AlarmReceiver: Nonzero checksum\n");
00509 continue;
00510 }
00511
00512
00513
00514 if (strncmp(event + 4, "18", 2)) {
00515 if (strncmp(event + 4, "98", 2)) {
00516 database_increment("format-errors");
00517 ast_verb(2, "AlarmReceiver: Wrong message type\n");
00518 ast_debug(1, "AlarmReceiver: Wrong message type\n");
00519 continue;
00520 }
00521 }
00522
00523 events_received++;
00524
00525
00526 if (!(enew = ast_calloc(1, sizeof(*enew)))) {
00527 res = -1;
00528 break;
00529 }
00530
00531 enew->next = NULL;
00532 ast_copy_string(enew->data, event, sizeof(enew->data));
00533
00534
00535
00536
00537 if (*ehead == NULL)
00538 *ehead = enew;
00539 else {
00540 for(elp = *ehead; elp->next != NULL; elp = elp->next)
00541 ;
00542 elp->next = enew;
00543 }
00544
00545 if (res > 0)
00546 res = 0;
00547
00548
00549 if ((res == 0) && (log_individual_events))
00550 res = log_events(chan, ADEMCO_CONTACT_ID, enew);
00551
00552 if (res == 0)
00553 res = ast_safe_sleep(chan, 200);
00554
00555
00556 if (res == 0)
00557 res = send_tone_burst(chan, 1400.0, 900, tldn);
00558 }
00559
00560 return res;
00561 }
00562
00563
00564
00565
00566
00567 static int alarmreceiver_exec(struct ast_channel *chan, void *data)
00568 {
00569 int res = 0;
00570 event_node_t *elp, *efree;
00571 char signalling_type[64] = "";
00572 event_node_t *event_head = NULL;
00573
00574
00575 ast_verb(4, "AlarmReceiver: Setting read and write formats to ULAW\n");
00576
00577 if (ast_set_write_format(chan,AST_FORMAT_ULAW)) {
00578 ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",chan->name);
00579 return -1;
00580 }
00581
00582 if (ast_set_read_format(chan,AST_FORMAT_ULAW)) {
00583 ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",chan->name);
00584 return -1;
00585 }
00586
00587
00588 ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type));
00589
00590
00591 ast_verb(4, "AlarmReceiver: Answering channel\n");
00592 if (chan->_state != AST_STATE_UP) {
00593 if ((res = ast_answer(chan)))
00594 return -1;
00595 }
00596
00597
00598 ast_verb(4, "AlarmReceiver: Waiting for connection to stabilize\n");
00599 res = ast_safe_sleep(chan, 1250);
00600
00601
00602 if (!res) {
00603
00604
00605
00606 if(!strcmp(signalling_type, ADEMCO_CONTACT_ID))
00607 receive_ademco_contact_id(chan, data, fdtimeout, sdtimeout, toneloudness, &event_head);
00608 else
00609 res = -1;
00610 }
00611
00612
00613 if ((!res) && (log_individual_events == 0))
00614 res = log_events(chan, signalling_type, event_head);
00615
00616
00617
00618
00619 if ((!res) && (!ast_strlen_zero(event_app)) && (event_head)) {
00620 ast_debug(1,"Alarmreceiver: executing: %s\n", event_app);
00621 ast_safe_system(event_app);
00622 }
00623
00624
00625
00626
00627 for (elp = event_head; (elp != NULL);) {
00628 efree = elp;
00629 elp = elp->next;
00630 ast_free(efree);
00631 }
00632
00633 return 0;
00634 }
00635
00636
00637
00638
00639 static int load_config(void)
00640 {
00641 struct ast_config *cfg;
00642 const char *p;
00643 struct ast_flags config_flags = { 0 };
00644
00645
00646 cfg = ast_config_load(ALMRCV_CONFIG, config_flags);
00647
00648 if (!cfg) {
00649 ast_verb(4, "AlarmReceiver: No config file\n");
00650 return 0;
00651 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00652 ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", ALMRCV_CONFIG);
00653 return 0;
00654 } else {
00655 p = ast_variable_retrieve(cfg, "general", "eventcmd");
00656 if (p) {
00657 ast_copy_string(event_app, p, sizeof(event_app));
00658 event_app[sizeof(event_app) - 1] = '\0';
00659 }
00660 p = ast_variable_retrieve(cfg, "general", "loudness");
00661 if (p) {
00662 toneloudness = atoi(p);
00663 if(toneloudness < 100)
00664 toneloudness = 100;
00665 if(toneloudness > 8192)
00666 toneloudness = 8192;
00667 }
00668 p = ast_variable_retrieve(cfg, "general", "fdtimeout");
00669 if (p) {
00670 fdtimeout = atoi(p);
00671 if(fdtimeout < 1000)
00672 fdtimeout = 1000;
00673 if(fdtimeout > 10000)
00674 fdtimeout = 10000;
00675 }
00676
00677 p = ast_variable_retrieve(cfg, "general", "sdtimeout");
00678 if (p) {
00679 sdtimeout = atoi(p);
00680 if(sdtimeout < 110)
00681 sdtimeout = 110;
00682 if(sdtimeout > 4000)
00683 sdtimeout = 4000;
00684 }
00685
00686 p = ast_variable_retrieve(cfg, "general", "logindividualevents");
00687 if (p)
00688 log_individual_events = ast_true(p);
00689
00690 p = ast_variable_retrieve(cfg, "general", "eventspooldir");
00691 if (p) {
00692 ast_copy_string(event_spool_dir, p, sizeof(event_spool_dir));
00693 event_spool_dir[sizeof(event_spool_dir) - 1] = '\0';
00694 }
00695
00696 p = ast_variable_retrieve(cfg, "general", "timestampformat");
00697 if (p) {
00698 ast_copy_string(time_stamp_format, p, sizeof(time_stamp_format));
00699 time_stamp_format[sizeof(time_stamp_format) - 1] = '\0';
00700 }
00701
00702 p = ast_variable_retrieve(cfg, "general", "db-family");
00703 if (p) {
00704 ast_copy_string(db_family, p, sizeof(db_family));
00705 db_family[sizeof(db_family) - 1] = '\0';
00706 }
00707 ast_config_destroy(cfg);
00708 }
00709 return 1;
00710 }
00711
00712
00713
00714
00715 static int unload_module(void)
00716 {
00717 return ast_unregister_application(app);
00718 }
00719
00720 static int load_module(void)
00721 {
00722 if (load_config()) {
00723 if (ast_register_application_xml(app, alarmreceiver_exec))
00724 return AST_MODULE_LOAD_FAILURE;
00725 return AST_MODULE_LOAD_SUCCESS;
00726 } else
00727 return AST_MODULE_LOAD_DECLINE;
00728 }
00729
00730 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Alarm Receiver for Asterisk");