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: 276347 $")
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 const 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.codec = 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.integer == 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.integer;
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;
00302 char *cn;
00303 char workstring[80];
00304 char timestamp[80];
00305
00306
00307 ast_copy_string(workstring,
00308 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
00309 sizeof(workstring));
00310 ast_shrink_phone_number(workstring);
00311 if (ast_strlen_zero(workstring)) {
00312 cl = "<unknown>";
00313 } else {
00314 cl = workstring;
00315 }
00316 cn = S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "<unknown>");
00317
00318
00319 t = ast_tvnow();
00320 ast_localtime(&t, &now, NULL);
00321
00322
00323 ast_strftime(timestamp, sizeof(timestamp), time_stamp_format, &now);
00324
00325 res = fprintf(logfile, "\n\n[metadata]\n\n");
00326 if (res >= 0) {
00327 res = fprintf(logfile, "PROTOCOL=%s\n", signalling_type);
00328 }
00329 if (res >= 0) {
00330 res = fprintf(logfile, "CALLINGFROM=%s\n", cl);
00331 }
00332 if (res >= 0) {
00333 res = fprintf(logfile, "CALLERNAME=%s\n", cn);
00334 }
00335 if (res >= 0) {
00336 res = fprintf(logfile, "TIMESTAMP=%s\n\n", timestamp);
00337 }
00338 if (res >= 0) {
00339 res = fprintf(logfile, "[events]\n\n");
00340 }
00341 if (res < 0) {
00342 ast_verb(3, "AlarmReceiver: can't write metadata\n");
00343 ast_debug(1,"AlarmReceiver: can't write metadata\n");
00344 } else {
00345 res = 0;
00346 }
00347
00348 return res;
00349 }
00350
00351
00352
00353
00354 static int write_event( FILE *logfile, event_node_t *event)
00355 {
00356 int res = 0;
00357
00358 if (fprintf(logfile, "%s\n", event->data) < 0)
00359 res = -1;
00360
00361 return res;
00362 }
00363
00364
00365
00366
00367
00368 static int log_events(struct ast_channel *chan, char *signalling_type, event_node_t *event)
00369 {
00370
00371 int res = 0;
00372 char workstring[sizeof(event_spool_dir)+sizeof(event_file)] = "";
00373 int fd;
00374 FILE *logfile;
00375 event_node_t *elp = event;
00376
00377 if (!ast_strlen_zero(event_spool_dir)) {
00378
00379
00380 ast_copy_string(workstring, event_spool_dir, sizeof(workstring));
00381 strncat(workstring, event_file, sizeof(workstring) - strlen(workstring) - 1);
00382
00383
00384 fd = mkstemp(workstring);
00385
00386 if (fd == -1) {
00387 ast_verb(3, "AlarmReceiver: can't make temporary file\n");
00388 ast_debug(1,"AlarmReceiver: can't make temporary file\n");
00389 res = -1;
00390 }
00391
00392 if (!res) {
00393 logfile = fdopen(fd, "w");
00394 if (logfile) {
00395
00396 res = write_metadata(logfile, signalling_type, chan);
00397 if (!res)
00398 while ((!res) && (elp != NULL)) {
00399 res = write_event(logfile, elp);
00400 elp = elp->next;
00401 }
00402 if (!res) {
00403 if (fflush(logfile) == EOF)
00404 res = -1;
00405 if (!res) {
00406 if (fclose(logfile) == EOF)
00407 res = -1;
00408 }
00409 }
00410 } else
00411 res = -1;
00412 }
00413 }
00414
00415 return res;
00416 }
00417
00418
00419
00420
00421
00422
00423 static int receive_ademco_contact_id(struct ast_channel *chan, const void *data, int fdto, int sdto, int tldn, event_node_t **ehead)
00424 {
00425 int i, j;
00426 int res = 0;
00427 int checksum;
00428 char event[17];
00429 event_node_t *enew, *elp;
00430 int got_some_digits = 0;
00431 int events_received = 0;
00432 int ack_retries = 0;
00433
00434 static char digit_map[15] = "0123456789*#ABC";
00435 static unsigned char digit_weights[15] = {10,1,2,3,4,5,6,7,8,9,11,12,13,14,15};
00436
00437 database_increment("calls-received");
00438
00439
00440 ast_verb(4, "AlarmReceiver: Waiting for first event from panel\n");
00441
00442 while (res >= 0) {
00443 if (got_some_digits == 0) {
00444
00445 ast_verb(4, "AlarmReceiver: Sending 1400Hz 100ms burst (ACK)\n");
00446 res = send_tone_burst(chan, 1400.0, 100, tldn);
00447 if (!res)
00448 res = ast_safe_sleep(chan, 100);
00449 if (!res) {
00450 ast_verb(4, "AlarmReceiver: Sending 2300Hz 100ms burst (ACK)\n");
00451 res = send_tone_burst(chan, 2300.0, 100, tldn);
00452 }
00453 }
00454 if ( res >= 0)
00455 res = receive_dtmf_digits(chan, event, sizeof(event) - 1, fdto, sdto);
00456 if (res < 0) {
00457 if (events_received == 0) {
00458
00459 database_increment("no-events-received");
00460 } else {
00461 if (ack_retries) {
00462 ast_verb(4, "AlarmReceiver: ACK retries during this call: %d\n", ack_retries);
00463 database_increment("ack-retries");
00464 }
00465 }
00466 ast_verb(4, "AlarmReceiver: App exiting...\n");
00467 res = -1;
00468 break;
00469 }
00470
00471 if (res != 0) {
00472
00473 ast_verb(2, "AlarmReceiver: Incomplete string: %s, trying again...\n", event);
00474
00475 if (!got_some_digits) {
00476 got_some_digits = (!ast_strlen_zero(event)) ? 1 : 0;
00477 ack_retries++;
00478 }
00479 continue;
00480 }
00481
00482 got_some_digits = 1;
00483
00484 ast_verb(2, "AlarmReceiver: Received Event %s\n", event);
00485 ast_debug(1, "AlarmReceiver: Received event: %s\n", event);
00486
00487
00488
00489 for (j = 0, checksum = 0; j < 16; j++) {
00490 for (i = 0; i < sizeof(digit_map); i++) {
00491 if (digit_map[i] == event[j])
00492 break;
00493 }
00494
00495 if (i == 16)
00496 break;
00497
00498 checksum += digit_weights[i];
00499 }
00500 if (i == 16) {
00501 ast_verb(2, "AlarmReceiver: Bad DTMF character %c, trying again\n", event[j]);
00502 continue;
00503 }
00504
00505
00506
00507 checksum = checksum % 15;
00508
00509 if (checksum) {
00510 database_increment("checksum-errors");
00511 ast_verb(2, "AlarmReceiver: Nonzero checksum\n");
00512 ast_debug(1, "AlarmReceiver: Nonzero checksum\n");
00513 continue;
00514 }
00515
00516
00517
00518 if (strncmp(event + 4, "18", 2)) {
00519 if (strncmp(event + 4, "98", 2)) {
00520 database_increment("format-errors");
00521 ast_verb(2, "AlarmReceiver: Wrong message type\n");
00522 ast_debug(1, "AlarmReceiver: Wrong message type\n");
00523 continue;
00524 }
00525 }
00526
00527 events_received++;
00528
00529
00530 if (!(enew = ast_calloc(1, sizeof(*enew)))) {
00531 res = -1;
00532 break;
00533 }
00534
00535 enew->next = NULL;
00536 ast_copy_string(enew->data, event, sizeof(enew->data));
00537
00538
00539
00540
00541 if (*ehead == NULL)
00542 *ehead = enew;
00543 else {
00544 for(elp = *ehead; elp->next != NULL; elp = elp->next)
00545 ;
00546 elp->next = enew;
00547 }
00548
00549 if (res > 0)
00550 res = 0;
00551
00552
00553 if ((res == 0) && (log_individual_events))
00554 res = log_events(chan, ADEMCO_CONTACT_ID, enew);
00555
00556 if (res == 0)
00557 res = ast_safe_sleep(chan, 200);
00558
00559
00560 if (res == 0)
00561 res = send_tone_burst(chan, 1400.0, 900, tldn);
00562 }
00563
00564 return res;
00565 }
00566
00567
00568
00569
00570
00571 static int alarmreceiver_exec(struct ast_channel *chan, const char *data)
00572 {
00573 int res = 0;
00574 event_node_t *elp, *efree;
00575 char signalling_type[64] = "";
00576 event_node_t *event_head = NULL;
00577
00578
00579 ast_verb(4, "AlarmReceiver: Setting read and write formats to ULAW\n");
00580
00581 if (ast_set_write_format(chan,AST_FORMAT_ULAW)) {
00582 ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",chan->name);
00583 return -1;
00584 }
00585
00586 if (ast_set_read_format(chan,AST_FORMAT_ULAW)) {
00587 ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",chan->name);
00588 return -1;
00589 }
00590
00591
00592 ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type));
00593
00594
00595 ast_verb(4, "AlarmReceiver: Answering channel\n");
00596 if (chan->_state != AST_STATE_UP) {
00597 if ((res = ast_answer(chan)))
00598 return -1;
00599 }
00600
00601
00602 ast_verb(4, "AlarmReceiver: Waiting for connection to stabilize\n");
00603 res = ast_safe_sleep(chan, 1250);
00604
00605
00606 if (!res) {
00607
00608
00609
00610 if(!strcmp(signalling_type, ADEMCO_CONTACT_ID))
00611 receive_ademco_contact_id(chan, data, fdtimeout, sdtimeout, toneloudness, &event_head);
00612 else
00613 res = -1;
00614 }
00615
00616
00617 if ((!res) && (log_individual_events == 0))
00618 res = log_events(chan, signalling_type, event_head);
00619
00620
00621
00622
00623 if ((!res) && (!ast_strlen_zero(event_app)) && (event_head)) {
00624 ast_debug(1,"Alarmreceiver: executing: %s\n", event_app);
00625 ast_safe_system(event_app);
00626 }
00627
00628
00629
00630
00631 for (elp = event_head; (elp != NULL);) {
00632 efree = elp;
00633 elp = elp->next;
00634 ast_free(efree);
00635 }
00636
00637 return 0;
00638 }
00639
00640
00641
00642
00643 static int load_config(void)
00644 {
00645 struct ast_config *cfg;
00646 const char *p;
00647 struct ast_flags config_flags = { 0 };
00648
00649
00650 cfg = ast_config_load(ALMRCV_CONFIG, config_flags);
00651
00652 if (!cfg) {
00653 ast_verb(4, "AlarmReceiver: No config file\n");
00654 return 0;
00655 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00656 ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", ALMRCV_CONFIG);
00657 return 0;
00658 } else {
00659 p = ast_variable_retrieve(cfg, "general", "eventcmd");
00660 if (p) {
00661 ast_copy_string(event_app, p, sizeof(event_app));
00662 event_app[sizeof(event_app) - 1] = '\0';
00663 }
00664 p = ast_variable_retrieve(cfg, "general", "loudness");
00665 if (p) {
00666 toneloudness = atoi(p);
00667 if(toneloudness < 100)
00668 toneloudness = 100;
00669 if(toneloudness > 8192)
00670 toneloudness = 8192;
00671 }
00672 p = ast_variable_retrieve(cfg, "general", "fdtimeout");
00673 if (p) {
00674 fdtimeout = atoi(p);
00675 if(fdtimeout < 1000)
00676 fdtimeout = 1000;
00677 if(fdtimeout > 10000)
00678 fdtimeout = 10000;
00679 }
00680
00681 p = ast_variable_retrieve(cfg, "general", "sdtimeout");
00682 if (p) {
00683 sdtimeout = atoi(p);
00684 if(sdtimeout < 110)
00685 sdtimeout = 110;
00686 if(sdtimeout > 4000)
00687 sdtimeout = 4000;
00688 }
00689
00690 p = ast_variable_retrieve(cfg, "general", "logindividualevents");
00691 if (p)
00692 log_individual_events = ast_true(p);
00693
00694 p = ast_variable_retrieve(cfg, "general", "eventspooldir");
00695 if (p) {
00696 ast_copy_string(event_spool_dir, p, sizeof(event_spool_dir));
00697 event_spool_dir[sizeof(event_spool_dir) - 1] = '\0';
00698 }
00699
00700 p = ast_variable_retrieve(cfg, "general", "timestampformat");
00701 if (p) {
00702 ast_copy_string(time_stamp_format, p, sizeof(time_stamp_format));
00703 time_stamp_format[sizeof(time_stamp_format) - 1] = '\0';
00704 }
00705
00706 p = ast_variable_retrieve(cfg, "general", "db-family");
00707 if (p) {
00708 ast_copy_string(db_family, p, sizeof(db_family));
00709 db_family[sizeof(db_family) - 1] = '\0';
00710 }
00711 ast_config_destroy(cfg);
00712 }
00713 return 1;
00714 }
00715
00716
00717
00718
00719 static int unload_module(void)
00720 {
00721 return ast_unregister_application(app);
00722 }
00723
00724 static int load_module(void)
00725 {
00726 if (load_config()) {
00727 if (ast_register_application_xml(app, alarmreceiver_exec))
00728 return AST_MODULE_LOAD_FAILURE;
00729 return AST_MODULE_LOAD_SUCCESS;
00730 } else
00731 return AST_MODULE_LOAD_DECLINE;
00732 }
00733
00734 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Alarm Receiver for Asterisk");