Mon Mar 20 08:20:05 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

app_alarmreceiver.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C)  2004 - 2005 Steve Rodgers
00005  *
00006  * Steve Rodgers <hwstar@rodgers.sdcoxmail.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  * \brief Central Station Alarm receiver for Ademco Contact ID  
00021  * \author Steve Rodgers <hwstar@rodgers.sdcoxmail.com>
00022  * 
00023  * *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** 
00024  *
00025  * Use at your own risk. Please consult the GNU GPL license document included with Asterisk details. *
00026  *
00027  * *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING ***
00028  *
00029  * \ingroup applications
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: 7221 $")
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 /* Config Variables */
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 /* Misc variables */
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 * Attempt to access a database variable and increment it,
00111 * provided that the user defined db-family in alarmreceiver.conf
00112 * The alarmreceiver app will write statistics to a few variables
00113 * in this family if it is defined. If the new key doesn't exist in the
00114 * family, then create it and set its value to 1.
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; /* If not defined, don't do anything */
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       /* Guess we have to create it */
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 * Build a MuLaw data block for a single frequency tone
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    /* wrap back around from 8000 */
00169 
00170    if (*x >= 8000) *x = 0;
00171    return;
00172 }
00173 
00174 /*
00175 * Send a single tone burst for a specifed duration and frequency. 
00176 * Returns 0 if successful
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 * Receive a string of DTMF digits where the length of the digit string is known in advance. Do not give preferential
00236 * treatment to any digit value, and allow separate time out values to be specified for the first digit and all subsequent
00237 * digits.
00238 *
00239 * Returns 0 if all digits successfully received.
00240 * Returns 1 if a digit time out occurred
00241 * Returns -1 if the caller hung up or there was a channel error.
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         /* if outa time, leave */
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       /* If they hung up, leave */
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       /* if not DTMF, just do it again */
00288       if (f->frametype != AST_FRAME_DTMF){
00289          ast_frfree(f);
00290          continue;
00291       }
00292 
00293       digit_string[i++] = f->subclass;  /* save digit */
00294       
00295       ast_frfree(f);
00296       
00297       /* If we have all the digits we expect, leave */
00298       if(i >= length)
00299          break;
00300       
00301       lastdigittime = ast_tvnow();
00302    }
00303    
00304    digit_string[i] = '\0'; /* Nul terminate the end of the digit string */
00305    return res;
00306 
00307 }
00308 
00309 /*
00310 * Write the metadata to the log file
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    /* Extract the caller ID location */
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    /* Get the current time */
00333       
00334    time(&t);
00335    ast_localtime(&t, &now, NULL);
00336    
00337    /* Format the time */
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 * Write a single event to the log file
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 * If we are configured to log events, do so here.
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       /* Make a template */
00402       
00403       ast_copy_string(workstring, event_spool_dir, sizeof(workstring));
00404       strncat(workstring, event_file, sizeof(workstring) - strlen(workstring) - 1);
00405       
00406       /* Make the temporary file */
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             /* Write the file */
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 * This function implements the logic to receive the Ademco contact ID  format.
00445 *
00446 * The function will return 0 when the caller hangs up, else a -1 if there was a problem.
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    /* Wait for first event */
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             /* Send ACK tone sequence */
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             /* Hangup with no events received should be logged in the DB */
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           /* Didn't get all of the digits */
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       /* Calculate checksum */
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; /* Bad character */
00553       }
00554 
00555       /* Checksum is mod(15) of the total */
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       /* Check the message type for correctness */
00569 
00570       if(strncmp(event + 4, "18", 2)){
00571          if(strncmp(event + 4, "98", 2)){
00572             database_increment("format-errors");
00573             if(option_verbose >= 2)
00574                ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Wrong message type\n");
00575             ast_log(LOG_DEBUG, "AlarmReceiver: Wrong message type\n");
00576          continue;
00577          }
00578       }
00579 
00580       events_received++;
00581       
00582       /* Queue the Event */
00583 
00584       if((enew = malloc(sizeof(event_node_t))) == NULL){
00585          if(option_verbose >= 1)
00586             ast_verbose(VERBOSE_PREFIX_1 "AlarmReceiver: Failed to allocate memory\n");
00587          ast_log(LOG_WARNING, "AlarmReceiver Failed to allocate memory\n");
00588          res = -1;
00589                         break;
00590       }
00591 
00592       memset(enew, 0, sizeof(event_node_t));
00593       
00594       enew->next = NULL;
00595       ast_copy_string(enew->data, event, sizeof(enew->data));
00596 
00597       /*
00598       * Insert event onto end of list
00599       */
00600       
00601       if(*ehead == NULL){
00602          *ehead = enew;
00603       }
00604       else{
00605          for(elp = *ehead; elp->next != NULL; elp = elp->next)
00606          ;
00607          
00608          elp->next = enew;
00609       }
00610       
00611       if(res > 0)
00612          res = 0;
00613       
00614       /* Let the user have the option of logging the single event before sending the kissoff tone */
00615 
00616       if((res == 0) && (log_individual_events))
00617          res = log_events(chan, ADEMCO_CONTACT_ID, enew);
00618    
00619       /* Wait 200 msec before sending kissoff */   
00620          
00621       if(res == 0)   
00622          res = ast_safe_sleep(chan, 200);
00623 
00624       /* Send the kissoff tone */
00625 
00626       if(res == 0)      
00627          res = send_tone_burst(chan, 1400.0, 900, tldn);
00628    }
00629 
00630    
00631    return res;
00632 }
00633 
00634 
00635 /*
00636 * This is the main function called by Asterisk Core whenever the App is invoked in the extension logic.
00637 * This function will always return 0.
00638 */
00639 
00640 static int alarmreceiver_exec(struct ast_channel *chan, void *data)
00641 {
00642    int res = 0;
00643    struct localuser *u;
00644    event_node_t *elp, *efree;
00645    char signalling_type[64] = "";
00646 
00647    event_node_t *event_head = NULL;
00648 
00649    LOCAL_USER_ADD(u);
00650 
00651    /* Set write and read formats to ULAW */
00652 
00653    if(option_verbose >= 4)
00654       ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Setting read and write formats to ULAW\n");
00655 
00656    if (ast_set_write_format(chan,AST_FORMAT_ULAW)){
00657       ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",chan->name);
00658       LOCAL_USER_REMOVE(u);
00659       return -1;
00660    }
00661    
00662    if (ast_set_read_format(chan,AST_FORMAT_ULAW)){
00663       ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",chan->name);
00664       LOCAL_USER_REMOVE(u);
00665       return -1;
00666    }
00667 
00668    /* Set default values for this invokation of the application */
00669    
00670    ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type));
00671 
00672 
00673    /* Answer the channel if it is not already */
00674 
00675    if(option_verbose >= 4)
00676       ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Answering channel\n");
00677 
00678    if (chan->_state != AST_STATE_UP) {
00679    
00680       res = ast_answer(chan);
00681       
00682       if (res) {
00683          LOCAL_USER_REMOVE(u);
00684          return -1;
00685       }
00686    }
00687 
00688    /* Wait for the connection to settle post-answer */
00689 
00690    if(option_verbose >= 4)
00691       ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Waiting for connection to stabilize\n");
00692 
00693    res = ast_safe_sleep(chan, 1250);
00694 
00695    /* Attempt to receive the events */
00696 
00697    if(!res){
00698    
00699       /* Determine the protocol to receive in advance */
00700       /* Note: Ademco contact is the only one supported at this time */
00701       /* Others may be added later */
00702       
00703       if(!strcmp(signalling_type, ADEMCO_CONTACT_ID))
00704          receive_ademco_contact_id(chan, data, fdtimeout, sdtimeout, toneloudness, &event_head);
00705       else
00706          res = -1;
00707    }
00708    
00709       
00710    
00711    /* Events queued by receiver, write them all out here if so configured */
00712 
00713    if((!res) && (log_individual_events == 0)){
00714       res = log_events(chan, signalling_type, event_head);
00715 
00716    }
00717 
00718    /*
00719    * Do we exec a command line at the end?
00720    */
00721    
00722    if((!res) && (!ast_strlen_zero(event_app)) && (event_head)){
00723       ast_log(LOG_DEBUG,"Alarmreceiver: executing: %s\n", event_app);
00724       ast_safe_system(event_app);
00725    }
00726 
00727    /*
00728    * Free up the data allocated in our linked list
00729    */
00730       
00731    for(elp = event_head; (elp != NULL);){
00732       efree = elp;
00733       elp = elp->next;
00734       free(efree);
00735    }
00736 
00737 
00738    LOCAL_USER_REMOVE(u);
00739 
00740    return 0;
00741 }
00742 
00743 /* 
00744 * Load the configuration from the configuration file
00745 */
00746 
00747 static int load_config(void)
00748 {
00749    struct ast_config *cfg;
00750    char *p;
00751 
00752    /* Read in the config file */
00753 
00754    cfg = ast_config_load(ALMRCV_CONFIG);
00755                                                                                                                                   
00756    if(!cfg){
00757    
00758       if(option_verbose >= 4)
00759          ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: No config file\n");
00760    }
00761    else{
00762 
00763       
00764       p = ast_variable_retrieve(cfg, "general", "eventcmd");
00765       
00766       if(p){
00767          ast_copy_string(event_app, p, sizeof(event_app));
00768          event_app[sizeof(event_app) - 1] = '\0';
00769       }
00770       
00771       p = ast_variable_retrieve(cfg, "general", "loudness");
00772       if(p){
00773          toneloudness = atoi(p);
00774          if(toneloudness < 100)
00775             toneloudness = 100;
00776          if(toneloudness > 8192)
00777             toneloudness = 8192;
00778       }
00779       p = ast_variable_retrieve(cfg, "general", "fdtimeout");
00780       if(p){
00781          fdtimeout = atoi(p);
00782          if(fdtimeout < 1000)
00783             fdtimeout = 1000;
00784          if(fdtimeout > 10000)
00785             fdtimeout = 10000;   
00786       }
00787       
00788       p = ast_variable_retrieve(cfg, "general", "sdtimeout");
00789       if(p){
00790          sdtimeout = atoi(p);
00791          if(sdtimeout < 110)
00792             sdtimeout = 110;
00793          if(sdtimeout > 4000)
00794             sdtimeout = 4000;       
00795 
00796       }
00797       
00798       p = ast_variable_retrieve(cfg, "general", "logindividualevents");
00799       if(p){
00800          log_individual_events = ast_true(p);
00801 
00802       }
00803       
00804       p = ast_variable_retrieve(cfg, "general", "eventspooldir");
00805          
00806       if(p){
00807          ast_copy_string(event_spool_dir, p, sizeof(event_spool_dir));
00808          event_spool_dir[sizeof(event_spool_dir) - 1] = '\0';
00809       }
00810       
00811       p = ast_variable_retrieve(cfg, "general", "timestampformat");
00812          
00813       if(p){
00814          ast_copy_string(time_stamp_format, p, sizeof(time_stamp_format));
00815          time_stamp_format[sizeof(time_stamp_format) - 1] = '\0';
00816       }
00817 
00818       p = ast_variable_retrieve(cfg, "general", "db-family");
00819                                                                                                                                             
00820       if(p){
00821          ast_copy_string(db_family, p, sizeof(db_family));
00822          db_family[sizeof(db_family) - 1] = '\0';
00823       }
00824       ast_config_destroy(cfg);
00825    }
00826    return 0;
00827 
00828 }
00829 
00830 /*
00831 * These functions are required to implement an Asterisk App.
00832 */
00833 
00834 
00835 int unload_module(void)
00836 {
00837    int res;
00838 
00839    res = ast_unregister_application(app);
00840 
00841    STANDARD_HANGUP_LOCALUSERS;
00842 
00843    return res;
00844 }
00845 
00846 int load_module(void)
00847 {
00848    load_config();
00849    return ast_register_application(app, alarmreceiver_exec, synopsis, descrip);
00850 }
00851 
00852 char *description(void)
00853 {
00854    return tdesc;
00855 }
00856 
00857 int usecount(void)
00858 {
00859    int res;
00860    STANDARD_USECOUNT(res);
00861    return res;
00862 }
00863 
00864 char *key()
00865 {
00866    return ASTERISK_GPL_KEY;
00867 }

Generated on Mon Mar 20 08:20:05 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1