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