Fri May 26 01:45:26 2006

Asterisk developer's documentation


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: 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 /* 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       /* Check the message type for correctness */
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       /* Queue the Event */
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       * Insert event onto end of list
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       /* Let the user have the option of logging the single event before sending the kissoff tone */
00614 
00615       if((res == 0) && (log_individual_events))
00616          res = log_events(chan, ADEMCO_CONTACT_ID, enew);
00617    
00618       /* Wait 200 msec before sending kissoff */   
00619          
00620       if(res == 0)   
00621          res = ast_safe_sleep(chan, 200);
00622 
00623       /* Send the kissoff tone */
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 * This is the main function called by Asterisk Core whenever the App is invoked in the extension logic.
00636 * This function will always return 0.
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    /* Set write and read formats to ULAW */
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    /* Set default values for this invokation of the application */
00668    
00669    ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type));
00670 
00671 
00672    /* Answer the channel if it is not already */
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    /* Wait for the connection to settle post-answer */
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    /* Attempt to receive the events */
00695 
00696    if(!res){
00697    
00698       /* Determine the protocol to receive in advance */
00699       /* Note: Ademco contact is the only one supported at this time */
00700       /* Others may be added later */
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    /* Events queued by receiver, write them all out here if so configured */
00711 
00712    if((!res) && (log_individual_events == 0)){
00713       res = log_events(chan, signalling_type, event_head);
00714 
00715    }
00716 
00717    /*
00718    * Do we exec a command line at the end?
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    * Free up the data allocated in our linked list
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 * Load the configuration from the configuration file
00744 */
00745 
00746 static int load_config(void)
00747 {
00748    struct ast_config *cfg;
00749    char *p;
00750 
00751    /* Read in the config file */
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 * These functions are required to implement an Asterisk App.
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 }

Generated on Fri May 26 01:45:26 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.6