Mon May 14 04:42:53 2007

Asterisk developer's documentation


app_osplookup.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.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 /*!
00020  * \file
00021  * \brief Open Settlement Protocol (OSP) Applications
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  * 
00025  * \ingroup applications
00026  */
00027 
00028 /*** MODULEINFO
00029    <depend>osptk</depend>
00030    <depend>ssl</depend>
00031  ***/
00032 
00033 #include "asterisk.h"
00034 
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00036 
00037 #include <sys/types.h>
00038 #include <stdio.h>
00039 #include <string.h>
00040 #include <unistd.h>
00041 #include <errno.h>
00042 #include <osp/osp.h>
00043 #include <osp/osputils.h>
00044 
00045 #include "asterisk/lock.h"
00046 #include "asterisk/config.h"
00047 #include "asterisk/utils.h"
00048 #include "asterisk/causes.h"
00049 #include "asterisk/channel.h"
00050 #include "asterisk/app.h"
00051 #include "asterisk/module.h"
00052 #include "asterisk/pbx.h"
00053 #include "asterisk/options.h"
00054 #include "asterisk/cli.h"
00055 #include "asterisk/logger.h"
00056 #include "asterisk/astosp.h"
00057 
00058 /* OSP Buffer Sizes */
00059 #define OSP_INTSTR_SIZE       ((unsigned int)16)         /* OSP signed/unsigned int string buffer size */
00060 #define OSP_NORSTR_SIZE       ((unsigned int)256)        /* OSP normal string buffer size */
00061 #define OSP_TOKSTR_SIZE       ((unsigned int)4096)       /* OSP token string buffer size */
00062 
00063 /* OSP Constants */
00064 #define OSP_INVALID_HANDLE    ((int)-1)            /* Invalid OSP handle, provider, transaction etc. */
00065 #define OSP_CONFIG_FILE       ((const char*)"osp.conf")     /* OSP configuration file name */
00066 #define OSP_GENERAL_CAT       ((const char*)"general")      /* OSP global configuration context name */
00067 #define OSP_DEF_PROVIDER      ((const char*)"default")      /* OSP default provider context name */
00068 #define OSP_MAX_CERTS         ((unsigned int)10)         /* OSP max number of cacerts */
00069 #define OSP_MAX_SRVS       ((unsigned int)10)         /* OSP max number of service points */
00070 #define OSP_DEF_MAXCONNECTIONS      ((unsigned int)20)         /* OSP default max_connections */
00071 #define OSP_MIN_MAXCONNECTIONS      ((unsigned int)1)       /* OSP min max_connections */
00072 #define OSP_MAX_MAXCONNECTIONS      ((unsigned int)1000)       /* OSP max max_connections */
00073 #define OSP_DEF_RETRYDELAY    ((unsigned int)0)       /* OSP default retry delay */
00074 #define OSP_MIN_RETRYDELAY    ((unsigned int)0)       /* OSP min retry delay */
00075 #define OSP_MAX_RETRYDELAY    ((unsigned int)10)         /* OSP max retry delay */
00076 #define OSP_DEF_RETRYLIMIT    ((unsigned int)2)       /* OSP default retry times */
00077 #define OSP_MIN_RETRYLIMIT    ((unsigned int)0)       /* OSP min retry times */
00078 #define OSP_MAX_RETRYLIMIT    ((unsigned int)100)        /* OSP max retry times */
00079 #define OSP_DEF_TIMEOUT       ((unsigned int)500)        /* OSP default timeout in ms */
00080 #define OSP_MIN_TIMEOUT       ((unsigned int)200)        /* OSP min timeout in ms */
00081 #define OSP_MAX_TIMEOUT       ((unsigned int)10000)         /* OSP max timeout in ms */
00082 #define OSP_DEF_AUTHPOLICY    ((enum osp_authpolicy)OSP_AUTH_YES)
00083 #define OSP_AUDIT_URL         ((const char*)"localhost")    /* OSP default Audit URL */
00084 #define OSP_LOCAL_VALIDATION     ((int)1)          /* Validate OSP token locally */
00085 #define OSP_SSL_LIFETIME      ((unsigned int)300)        /* SSL life time, in seconds */
00086 #define OSP_HTTP_PERSISTENCE     ((int)1)          /* In seconds */
00087 #define OSP_CUSTOMER_ID       ((const char*)"")       /* OSP customer ID */
00088 #define OSP_DEVICE_ID         ((const char*)"")       /* OSP device ID */
00089 #define OSP_DEF_DESTINATIONS     ((unsigned int)5)       /* OSP default max number of destinations */
00090 #define OSP_DEF_TIMELIMIT     ((unsigned int)0)       /* OSP default duration limit, no limit */
00091 
00092 /* OSP Authentication Policy */
00093 enum osp_authpolicy {
00094    OSP_AUTH_NO,      /* Accept any call */
00095    OSP_AUTH_YES,     /* Accept call with valid OSP token or without OSP token */
00096    OSP_AUTH_EXCLUSIVE   /* Only accept call with valid OSP token */
00097 };
00098 
00099 /* OSP Provider */
00100 struct osp_provider {
00101    char name[OSP_NORSTR_SIZE];            /* OSP provider context name */
00102    char privatekey[OSP_NORSTR_SIZE];         /* OSP private key file name */
00103    char localcert[OSP_NORSTR_SIZE];       /* OSP local cert file name */
00104    unsigned int cacount;               /* Number of cacerts */
00105    char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE];      /* Cacert file names */
00106    unsigned int spcount;               /* Number of service points */
00107    char srvpoints[OSP_MAX_SRVS][OSP_NORSTR_SIZE];     /* Service point URLs */
00108    int maxconnections;              /* Max number of connections */
00109    int retrydelay;                  /* Retry delay */
00110    int retrylimit;                  /* Retry limit */
00111    int timeout;                  /* Timeout in ms */
00112    char source[OSP_NORSTR_SIZE];          /* IP of self */
00113    enum osp_authpolicy authpolicy;           /* OSP authentication policy */
00114    OSPTPROVHANDLE handle;              /* OSP provider handle */
00115    struct osp_provider* next;          /* Pointer to next OSP provider */
00116 };
00117 
00118 /* OSP Application In/Output Results */
00119 struct osp_result {
00120    int inhandle;                 /* Inbound transaction handle */
00121    int outhandle;                /* Outbound transaction handle */
00122    unsigned int intimelimit;           /* Inbound duration limit */
00123    unsigned int outtimelimit;          /* Outbound duration limit */
00124    char tech[20];                /* Asterisk TECH string */
00125    char dest[OSP_NORSTR_SIZE];            /* Destination in called@IP format */
00126    char calling[OSP_NORSTR_SIZE];            /* Calling number, may be translated */
00127    char token[OSP_TOKSTR_SIZE];           /* Outbound OSP token */
00128    unsigned int numresults;            /* Number of remain destinations */
00129 };
00130 
00131 /* OSP Module Global Variables */
00132 AST_MUTEX_DEFINE_STATIC(osplock);            /* Lock of OSP provider list */
00133 static int osp_initialized = 0;              /* Init flag */
00134 static int osp_hardware = 0;              /* Hardware acceleration flag */
00135 static struct osp_provider* ospproviders = NULL;      /* OSP provider list */
00136 static unsigned int osp_tokenformat = TOKEN_ALGO_SIGNED; /* Token format supported */
00137 
00138 /* OSP Client Wrapper APIs */
00139 
00140 /*!
00141  * \brief Create OSP provider handle according to configuration
00142  * \param cfg OSP configuration
00143  * \param provider OSP provider context name
00144  * \return 1 Success, 0 Failed, -1 Error
00145  */
00146 static int osp_create_provider(struct ast_config* cfg, const char* provider)
00147 {
00148    int res;
00149    unsigned int t, i, j;
00150    struct osp_provider* p;
00151    struct ast_variable* v;
00152    OSPTPRIVATEKEY privatekey;
00153    OSPTCERT localcert;
00154    const char* psrvpoints[OSP_MAX_SRVS];
00155    OSPTCERT cacerts[OSP_MAX_CERTS];
00156    const OSPTCERT* pcacerts[OSP_MAX_CERTS];
00157    int error = OSPC_ERR_NO_ERROR;
00158 
00159    if (!(p = ast_calloc(1, sizeof(*p)))) {
00160       ast_log(LOG_ERROR, "Out of memory\n");
00161       return -1;
00162    }
00163 
00164    ast_copy_string(p->name, provider, sizeof(p->name));
00165    snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, provider);
00166    snprintf(p->localcert, sizeof(p->localcert), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, provider);
00167    p->maxconnections = OSP_DEF_MAXCONNECTIONS;
00168    p->retrydelay = OSP_DEF_RETRYDELAY;
00169    p->retrylimit = OSP_DEF_RETRYLIMIT;
00170    p->timeout = OSP_DEF_TIMEOUT;
00171    p->authpolicy = OSP_DEF_AUTHPOLICY;
00172    p->handle = OSP_INVALID_HANDLE;
00173 
00174    v = ast_variable_browse(cfg, provider);
00175    while(v) {
00176       if (!strcasecmp(v->name, "privatekey")) {
00177          if (v->value[0] == '/') {
00178             ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey));
00179          } else {
00180             snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value);
00181          }
00182          ast_log(LOG_DEBUG, "OSP: privatekey '%s'\n", p->privatekey);
00183       } else if (!strcasecmp(v->name, "localcert")) {
00184          if (v->value[0] == '/') {
00185             ast_copy_string(p->localcert, v->value, sizeof(p->localcert));
00186          } else {
00187             snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
00188          }
00189          ast_log(LOG_DEBUG, "OSP: localcert '%s'\n", p->localcert);
00190       } else if (!strcasecmp(v->name, "cacert")) {
00191          if (p->cacount < OSP_MAX_CERTS) {
00192             if (v->value[0] == '/') {
00193                ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0]));
00194             } else {
00195                snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
00196             }
00197             ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
00198             p->cacount++;
00199          } else {
00200             ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno);
00201          }
00202       } else if (!strcasecmp(v->name, "servicepoint")) {
00203          if (p->spcount < OSP_MAX_SRVS) {
00204             ast_copy_string(p->srvpoints[p->spcount], v->value, sizeof(p->srvpoints[0]));
00205             ast_log(LOG_DEBUG, "OSP: servicepoint[%d]: '%s'\n", p->spcount, p->srvpoints[p->spcount]);
00206             p->spcount++;
00207          } else {
00208             ast_log(LOG_WARNING, "OSP: Too many Service Points at line %d\n", v->lineno);
00209          }
00210       } else if (!strcasecmp(v->name, "maxconnections")) {
00211          if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_MAXCONNECTIONS) && (t <= OSP_MAX_MAXCONNECTIONS)) {
00212             p->maxconnections = t;
00213             ast_log(LOG_DEBUG, "OSP: maxconnections '%d'\n", t);
00214          } else {
00215             ast_log(LOG_WARNING, "OSP: maxconnections should be an integer from %d to %d, not '%s' at line %d\n", 
00216                OSP_MIN_MAXCONNECTIONS, OSP_MAX_MAXCONNECTIONS, v->value, v->lineno);
00217          }
00218       } else if (!strcasecmp(v->name, "retrydelay")) {
00219          if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYDELAY) && (t <= OSP_MAX_RETRYDELAY)) {
00220             p->retrydelay = t;
00221             ast_log(LOG_DEBUG, "OSP: retrydelay '%d'\n", t);
00222          } else {
00223             ast_log(LOG_WARNING, "OSP: retrydelay should be an integer from %d to %d, not '%s' at line %d\n", 
00224                OSP_MIN_RETRYDELAY, OSP_MAX_RETRYDELAY, v->value, v->lineno);
00225          }
00226       } else if (!strcasecmp(v->name, "retrylimit")) {
00227          if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYLIMIT) && (t <= OSP_MAX_RETRYLIMIT)) {
00228             p->retrylimit = t;
00229             ast_log(LOG_DEBUG, "OSP: retrylimit '%d'\n", t);
00230          } else {
00231             ast_log(LOG_WARNING, "OSP: retrylimit should be an integer from %d to %d, not '%s' at line %d\n", 
00232                OSP_MIN_RETRYLIMIT, OSP_MAX_RETRYLIMIT, v->value, v->lineno);
00233          }
00234       } else if (!strcasecmp(v->name, "timeout")) {
00235          if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_TIMEOUT) && (t <= OSP_MAX_TIMEOUT)) {
00236             p->timeout = t;
00237             ast_log(LOG_DEBUG, "OSP: timeout '%d'\n", t);
00238          } else {
00239             ast_log(LOG_WARNING, "OSP: timeout should be an integer from %d to %d, not '%s' at line %d\n", 
00240                OSP_MIN_TIMEOUT, OSP_MAX_TIMEOUT, v->value, v->lineno);
00241          }
00242       } else if (!strcasecmp(v->name, "source")) {
00243          ast_copy_string(p->source, v->value, sizeof(p->source));
00244          ast_log(LOG_DEBUG, "OSP: source '%s'\n", p->source);
00245       } else if (!strcasecmp(v->name, "authpolicy")) {
00246          if ((sscanf(v->value, "%d", &t) == 1) && ((t == OSP_AUTH_NO) || (t == OSP_AUTH_YES) || (t == OSP_AUTH_EXCLUSIVE))) {
00247             p->authpolicy = t;
00248             ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", t);
00249          } else {
00250             ast_log(LOG_WARNING, "OSP: authpolicy should be %d, %d or %d, not '%s' at line %d\n", 
00251                OSP_AUTH_NO, OSP_AUTH_YES, OSP_AUTH_EXCLUSIVE, v->value, v->lineno);
00252          }
00253       }
00254       v = v->next;
00255    }
00256 
00257    error = OSPPUtilLoadPEMPrivateKey((unsigned char *) p->privatekey, &privatekey);
00258    if (error != OSPC_ERR_NO_ERROR) {
00259       ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s', error '%d'\n", p->privatekey, error);
00260       free(p);
00261       return 0;
00262    }
00263 
00264    error = OSPPUtilLoadPEMCert((unsigned char *) p->localcert, &localcert);
00265    if (error != OSPC_ERR_NO_ERROR) {
00266       ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s', error '%d'\n", p->localcert, error);
00267       if (privatekey.PrivateKeyData) {
00268          free(privatekey.PrivateKeyData);
00269       }
00270       free(p);
00271       return 0;
00272    }
00273 
00274    if (p->cacount < 1) {
00275       snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, provider);
00276       ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
00277       p->cacount++;
00278    }
00279    for (i = 0; i < p->cacount; i++) {
00280       error = OSPPUtilLoadPEMCert((unsigned char *) p->cacerts[i], &cacerts[i]);
00281       if (error != OSPC_ERR_NO_ERROR) {
00282          ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s', error '%d'\n", p->cacerts[i], error);
00283          for (j = 0; j < i; j++) {
00284             if (cacerts[j].CertData) {
00285                free(cacerts[j].CertData);
00286             }
00287          }
00288          if (localcert.CertData) {
00289             free(localcert.CertData);
00290          }
00291          if (privatekey.PrivateKeyData) {
00292             free(privatekey.PrivateKeyData);
00293          }
00294          free(p);
00295          return 0;
00296       }
00297       pcacerts[i] = &cacerts[i];
00298    }
00299    
00300    for (i = 0; i < p->spcount; i++) {
00301       psrvpoints[i] = p->srvpoints[i];
00302    }
00303 
00304    error = OSPPProviderNew(p->spcount, psrvpoints, NULL, OSP_AUDIT_URL, &privatekey, &localcert, p->cacount, pcacerts, OSP_LOCAL_VALIDATION,
00305             OSP_SSL_LIFETIME, p->maxconnections, OSP_HTTP_PERSISTENCE, p->retrydelay, p->retrylimit,p->timeout, OSP_CUSTOMER_ID,
00306             OSP_DEVICE_ID, &p->handle);
00307    if (error != OSPC_ERR_NO_ERROR) {
00308       ast_log(LOG_WARNING, "OSP: Unable to create provider '%s', error '%d'\n", provider, error);
00309       free(p);
00310       res = -1;
00311    } else {
00312       ast_log(LOG_DEBUG, "OSP: provider '%s'\n", provider);
00313       ast_mutex_lock(&osplock);
00314       p->next = ospproviders;
00315       ospproviders = p;
00316       ast_mutex_unlock(&osplock);   
00317       res = 1;
00318    }
00319 
00320    for (i = 0; i < p->cacount; i++) {
00321       if (cacerts[i].CertData) {
00322          free(cacerts[i].CertData);
00323       }
00324    }
00325    if (localcert.CertData) {
00326       free(localcert.CertData);
00327    }
00328    if (privatekey.PrivateKeyData) {
00329       free(privatekey.PrivateKeyData);
00330    }
00331 
00332    return res;
00333 }
00334 
00335 /*!
00336  * \brief Get OSP authenticiation policy of provider
00337  * \param provider OSP provider context name
00338  * \param policy OSP authentication policy, output
00339  * \return 1 Success, 0 Failed, -1 Error
00340  */
00341 static int osp_get_policy(const char* provider, int* policy)
00342 {
00343    int res = 0;
00344    struct osp_provider* p;
00345 
00346    ast_mutex_lock(&osplock);
00347    p = ospproviders;
00348    while(p) {
00349       if (!strcasecmp(p->name, provider)) {
00350          *policy = p->authpolicy;
00351          ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", *policy);
00352          res = 1;
00353          break;
00354       }
00355       p = p->next;
00356    }
00357    ast_mutex_unlock(&osplock);
00358 
00359    return res;
00360 }
00361 
00362 /*!
00363  * \brief Create OSP transaction handle
00364  * \param provider OSP provider context name
00365  * \param transaction OSP transaction handle, output
00366  * \param sourcesize Size of source buffer, in/output
00367  * \param source Source of provider, output
00368  * \return 1 Success, 0 Failed, -1 Error
00369  */
00370 static int osp_create_transaction(const char* provider, int* transaction, unsigned int sourcesize, char* source)
00371 {
00372    int res = 0;
00373    struct osp_provider* p;
00374    int error;
00375 
00376    ast_mutex_lock(&osplock);
00377    p = ospproviders;
00378    while(p) {
00379       if (!strcasecmp(p->name, provider)) {
00380          error = OSPPTransactionNew(p->handle, transaction);
00381          if (error == OSPC_ERR_NO_ERROR) {
00382             ast_log(LOG_DEBUG, "OSP: transaction '%d'\n", *transaction);
00383             ast_copy_string(source, p->source, sourcesize);
00384             ast_log(LOG_DEBUG, "OSP: source '%s'\n", source);
00385             res = 1;
00386          } else {
00387             *transaction = OSP_INVALID_HANDLE;
00388             ast_log(LOG_DEBUG, "OSP: Unable to create transaction handle, error '%d'\n", error);
00389             res = -1;
00390          }
00391          break;
00392       }
00393       p = p->next;
00394    }
00395    ast_mutex_unlock(&osplock);
00396 
00397    return res;
00398 }
00399 
00400 /*!
00401  * \brief Validate OSP token of inbound call
00402  * \param transaction OSP transaction handle
00403  * \param source Source of inbound call
00404  * \param dest Destination of inbound call
00405  * \param calling Calling number
00406  * \param called Called number
00407  * \param token OSP token, may be empty
00408  * \param timelimit Call duration limit, output
00409  * \return 1 Success, 0 Failed, -1 Error
00410  */
00411 static int osp_validate_token(int transaction, const char* source, const char* dest, const char* calling, const char* called, const char* token, unsigned int* timelimit)
00412 {
00413    int res;
00414    int tokenlen;
00415    unsigned char tokenstr[OSP_TOKSTR_SIZE];
00416    unsigned int authorised;
00417    unsigned int dummy = 0;
00418    int error;
00419 
00420    tokenlen = ast_base64decode(tokenstr, token, strlen(token));
00421    error = OSPPTransactionValidateAuthorisation(
00422       transaction, 
00423       source, dest, NULL, NULL,
00424       calling ? calling : "", OSPC_E164, 
00425       called, OSPC_E164, 
00426       0, NULL,
00427       tokenlen, (char *) tokenstr, 
00428       &authorised, 
00429       timelimit, 
00430       &dummy, NULL, 
00431       osp_tokenformat); 
00432    if (error != OSPC_ERR_NO_ERROR) {
00433       ast_log(LOG_DEBUG, "OSP: Unable to validate inbound token\n");
00434       res = -1;
00435    } else if (authorised) {
00436       ast_log(LOG_DEBUG, "OSP: Authorised\n");
00437       res = 1;
00438    } else {
00439       ast_log(LOG_DEBUG, "OSP: Unauthorised\n");
00440       res = 0;
00441    }
00442    
00443    return res;
00444 }
00445 
00446 /*!
00447  * \brief Choose min duration limit
00448  * \param in Inbound duration limit
00449  * \param out Outbound duration limit
00450  * \return min duration limit
00451  */
00452 static unsigned int osp_choose_timelimit(unsigned int in, unsigned int out)
00453 {
00454    if (in == OSP_DEF_TIMELIMIT) {
00455       return out;
00456    } else if (out == OSP_DEF_TIMELIMIT) {
00457       return in;
00458    } else {
00459       return in < out ? in : out;
00460    }
00461 }
00462 
00463 /*!
00464  * \brief Choose min duration limit
00465  * \param called Called number
00466  * \param calling Calling number
00467  * \param destination Destination IP in '[x.x.x.x]' format
00468  * \param tokenlen OSP token length
00469  * \param token OSP token
00470  * \param reason Failure reason, output
00471  * \param result OSP lookup results, in/output
00472  * \return 1 Success, 0 Failed, -1 Error
00473  */
00474 static int osp_check_destination(const char* called, const char* calling, char* destination, unsigned int tokenlen, const char* token, enum OSPEFAILREASON* reason, struct osp_result* result)
00475 {
00476    int res;
00477    OSPE_DEST_OSP_ENABLED enabled;
00478    OSPE_DEST_PROT protocol;
00479    int error;
00480 
00481    if (strlen(destination) <= 2) {
00482       ast_log(LOG_DEBUG, "OSP: Wrong destination format '%s'\n", destination);
00483       *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
00484       return -1;
00485    } 
00486 
00487    if ((error = OSPPTransactionIsDestOSPEnabled(result->outhandle, &enabled)) != OSPC_ERR_NO_ERROR) {
00488       ast_log(LOG_DEBUG, "OSP: Unable to get destination OSP version, error '%d'\n", error);
00489       *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
00490       return -1;
00491    }
00492 
00493    if (enabled == OSPE_OSP_FALSE) {
00494       result->token[0] = '\0';
00495    } else {
00496       ast_base64encode(result->token, (const unsigned char *) token, tokenlen, sizeof(result->token) - 1);
00497    }
00498 
00499    if ((error = OSPPTransactionGetDestProtocol(result->outhandle, &protocol)) != OSPC_ERR_NO_ERROR) {
00500       ast_log(LOG_DEBUG, "OSP: Unable to get destination protocol, error '%d'\n", error);
00501       *reason = OSPC_FAIL_NORMAL_UNSPECIFIED; 
00502       result->token[0] = '\0';
00503       return -1;
00504    } 
00505 
00506    res = 1;
00507    /* Strip leading and trailing brackets */
00508    destination[strlen(destination) - 1] = '\0';
00509    switch(protocol) {
00510       case OSPE_DEST_PROT_H323_SETUP:
00511          ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
00512          ast_copy_string(result->tech, "H323", sizeof(result->tech));
00513          snprintf(result->dest, sizeof(result->dest), "%s@%s", called, destination + 1);
00514          ast_copy_string(result->calling, calling, sizeof(result->calling));
00515          break;
00516       case OSPE_DEST_PROT_SIP:
00517          ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
00518          ast_copy_string(result->tech, "SIP", sizeof(result->tech));
00519          snprintf(result->dest, sizeof(result->dest), "%s@%s", called, destination + 1);
00520          ast_copy_string(result->calling, calling, sizeof(result->calling));
00521          break;
00522       case OSPE_DEST_PROT_IAX:
00523          ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
00524          ast_copy_string(result->tech, "IAX", sizeof(result->tech));
00525          snprintf(result->dest, sizeof(result->dest), "%s@%s", called, destination + 1);
00526          ast_copy_string(result->calling, calling, sizeof(result->calling));
00527          break;
00528       default:
00529          ast_log(LOG_DEBUG, "OSP: Unknown protocol '%d'\n", protocol);
00530          *reason = OSPC_FAIL_PROTOCOL_ERROR; 
00531          result->token[0] = '\0';
00532          res = 0;
00533    }
00534 
00535    return res;
00536 }
00537 
00538 /*!
00539  * \brief Convert Asterisk status to TC code
00540  * \param cause Asterisk hangup cause
00541  * \return OSP TC code
00542  */
00543 static enum OSPEFAILREASON asterisk2osp(int cause)
00544 {
00545    return (enum OSPEFAILREASON)cause;
00546 }
00547 
00548 /*!
00549  * \brief OSP Authentication function
00550  * \param provider OSP provider context name
00551  * \param transaction OSP transaction handle, output
00552  * \param source Source of inbound call
00553  * \param calling Calling number
00554  * \param called Called number
00555  * \param token OSP token, may be empty
00556  * \param timelimit Call duration limit, output
00557  * \return 1 Authenricated, 0 Unauthenticated, -1 Error
00558  */
00559 static int osp_auth(const char* provider, int* transaction, const char* source, const char* calling, const char* called, const char* token, unsigned int* timelimit)
00560 {
00561    int res;
00562    int policy = OSP_AUTH_YES;
00563    char dest[OSP_NORSTR_SIZE];
00564 
00565    *transaction = OSP_INVALID_HANDLE;
00566    *timelimit = OSP_DEF_TIMELIMIT;
00567    res = osp_get_policy(provider, &policy);
00568    if (!res) {
00569       ast_log(LOG_DEBUG, "OSP: Unabe to find OSP authentication policy\n");
00570       return res;
00571    }
00572 
00573    switch (policy) {
00574       case OSP_AUTH_NO:
00575          res = 1;
00576          break;
00577       case OSP_AUTH_EXCLUSIVE:
00578          if (ast_strlen_zero(token)) {
00579             res = 0;
00580          } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
00581             ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
00582             *transaction = OSP_INVALID_HANDLE;
00583             res = 0;
00584          } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
00585             OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
00586          }
00587          break;
00588       case OSP_AUTH_YES:
00589       default:
00590          if (ast_strlen_zero(token)) {
00591             res = 1;
00592          } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
00593             ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
00594             *transaction = OSP_INVALID_HANDLE;
00595             res = 0;
00596          } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
00597             OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
00598          }
00599          break;
00600    }
00601 
00602    return res;
00603 }
00604 
00605 /*!
00606  * \brief OSP Lookup function
00607  * \param provider OSP provider context name
00608  * \param srcdev Source device of outbound call
00609  * \param calling Calling number
00610  * \param called Called number
00611  * \param result Lookup results
00612  * \return 1 Found , 0 No route, -1 Error
00613  */
00614 static int osp_lookup(const char* provider, const char* srcdev, const char* calling, const char* called, struct osp_result* result)
00615 {
00616    int res;
00617    char source[OSP_NORSTR_SIZE];
00618    unsigned int callidlen;
00619    char callid[OSPC_CALLID_MAXSIZE];
00620    char callingnum[OSP_NORSTR_SIZE];
00621    char callednum[OSP_NORSTR_SIZE];
00622    char destination[OSP_NORSTR_SIZE];
00623    unsigned int tokenlen;
00624    char token[OSP_TOKSTR_SIZE];
00625    unsigned int dummy = 0;
00626    enum OSPEFAILREASON reason;
00627    int error;
00628 
00629    result->outhandle = OSP_INVALID_HANDLE;
00630    result->tech[0] = '\0';
00631    result->dest[0] = '\0';
00632    result->calling[0] = '\0';
00633    result->token[0] = '\0';
00634    result->numresults = 0;
00635    result->outtimelimit = OSP_DEF_TIMELIMIT;
00636 
00637    if ((res = osp_create_transaction(provider, &result->outhandle, sizeof(source), source)) <= 0) {
00638       ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
00639       result->outhandle = OSP_INVALID_HANDLE;
00640       if (result->inhandle != OSP_INVALID_HANDLE) {
00641          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
00642       }
00643       return -1;
00644    }
00645 
00646    result->numresults = OSP_DEF_DESTINATIONS;
00647    error = OSPPTransactionRequestAuthorisation(result->outhandle, source, srcdev, calling ? calling : "",
00648          OSPC_E164, called, OSPC_E164, NULL, 0, NULL, NULL, &result->numresults, &dummy, NULL);
00649    if (error != OSPC_ERR_NO_ERROR) {
00650       ast_log(LOG_DEBUG, "OSP: Unable to request authorization\n");
00651       result->numresults = 0;
00652       if (result->inhandle != OSP_INVALID_HANDLE) {
00653          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
00654       }
00655       return -1;
00656    }
00657 
00658    if (!result->numresults) {
00659       ast_log(LOG_DEBUG, "OSP: No more destination\n");
00660       if (result->inhandle != OSP_INVALID_HANDLE) {
00661          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
00662       }
00663       return 0;
00664    }
00665 
00666    callidlen = sizeof(callid);
00667    tokenlen = sizeof(token);
00668    error = OSPPTransactionGetFirstDestination(result->outhandle, 0, NULL, NULL, &result->outtimelimit, &callidlen, callid,
00669          sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token);
00670    if (error != OSPC_ERR_NO_ERROR) {
00671       ast_log(LOG_DEBUG, "OSP: Unable to get first route\n");
00672       result->numresults = 0;
00673       result->outtimelimit = OSP_DEF_TIMELIMIT;
00674       if (result->inhandle != OSP_INVALID_HANDLE) {
00675          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
00676       }
00677       return -1;
00678    }
00679 
00680    result->numresults--;
00681    result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
00682    ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
00683    ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
00684    ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
00685    ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
00686    ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
00687 
00688    if ((res = osp_check_destination(callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
00689       return 1;
00690    }
00691 
00692    if (!result->numresults) {
00693       ast_log(LOG_DEBUG, "OSP: No more destination\n");
00694       result->outtimelimit = OSP_DEF_TIMELIMIT;
00695       OSPPTransactionRecordFailure(result->outhandle, reason);
00696       if (result->inhandle != OSP_INVALID_HANDLE) {
00697          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
00698       }
00699       return 0;
00700    }
00701 
00702    while(result->numresults) {
00703       callidlen = sizeof(callid);
00704       tokenlen = sizeof(token);
00705       error = OSPPTransactionGetNextDestination(result->outhandle, reason, 0, NULL, NULL, &result->outtimelimit, &callidlen, callid,
00706             sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token);
00707       if (error == OSPC_ERR_NO_ERROR) {
00708          result->numresults--;
00709          result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
00710          ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
00711          ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
00712          ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
00713          ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
00714          ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
00715          if ((res = osp_check_destination(callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
00716             break;
00717          } else if (!result->numresults) {
00718             ast_log(LOG_DEBUG, "OSP: No more destination\n");
00719             OSPPTransactionRecordFailure(result->outhandle, reason);
00720             if (result->inhandle != OSP_INVALID_HANDLE) {
00721                OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
00722             }
00723             res = 0;
00724             break;
00725          }
00726       } else {
00727          ast_log(LOG_DEBUG, "OSP: Unable to get route, error '%d'\n", error);
00728          result->numresults = 0;
00729          result->outtimelimit = OSP_DEF_TIMELIMIT;
00730          if (result->inhandle != OSP_INVALID_HANDLE) {
00731             OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
00732          }
00733          res = -1;
00734          break;
00735       }
00736    }
00737    return res;
00738 }
00739 
00740 /*!
00741  * \brief OSP Lookup Next function
00742  * \param cause Asterisk hangup cuase
00743  * \param result Lookup results, in/output
00744  * \return 1 Found , 0 No route, -1 Error
00745  */
00746 static int osp_next(int cause, struct osp_result* result)
00747 {
00748    int res;
00749    unsigned int callidlen;
00750    char callid[OSPC_CALLID_MAXSIZE];
00751    char callingnum[OSP_NORSTR_SIZE];
00752    char callednum[OSP_NORSTR_SIZE];
00753    char destination[OSP_NORSTR_SIZE];
00754    unsigned int tokenlen;
00755    char token[OSP_TOKSTR_SIZE];
00756    enum OSPEFAILREASON reason;
00757    int error;
00758 
00759    result->tech[0] = '\0';
00760    result->dest[0] = '\0';
00761    result->calling[0] = '\0';
00762    result->token[0] = '\0';
00763    result->outtimelimit = OSP_DEF_TIMELIMIT;
00764 
00765    if (result->outhandle == OSP_INVALID_HANDLE) {
00766       ast_log(LOG_DEBUG, "OSP: Transaction handle undefined\n");
00767       result->numresults = 0;
00768       if (result->inhandle != OSP_INVALID_HANDLE) {
00769          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
00770       }
00771       return -1;
00772    }
00773 
00774    reason = asterisk2osp(cause);
00775 
00776    if (!result->numresults) {
00777       ast_log(LOG_DEBUG, "OSP: No more destination\n");
00778       OSPPTransactionRecordFailure(result->outhandle, reason);
00779       if (result->inhandle != OSP_INVALID_HANDLE) {
00780          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
00781       }
00782       return 0;
00783    }
00784 
00785    while(result->numresults) {
00786       callidlen = sizeof(callid);
00787       tokenlen = sizeof(token);
00788       error = OSPPTransactionGetNextDestination(result->outhandle, reason, 0, NULL, NULL, &result->outtimelimit, &callidlen,
00789             callid, sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token);
00790       if (error == OSPC_ERR_NO_ERROR) {
00791          result->numresults--;
00792          result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
00793          ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
00794          ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
00795          ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
00796          ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
00797          ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
00798          if ((res = osp_check_destination(callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
00799             res = 1;
00800             break;
00801          } else if (!result->numresults) {
00802             ast_log(LOG_DEBUG, "OSP: No more destination\n");
00803             OSPPTransactionRecordFailure(result->outhandle, reason);
00804             if (result->inhandle != OSP_INVALID_HANDLE) {
00805                OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
00806             }
00807             res = 0;
00808             break;
00809          }
00810       } else {
00811          ast_log(LOG_DEBUG, "OSP: Unable to get route, error '%d'\n", error);
00812          result->token[0] = '\0';
00813          result->numresults = 0;
00814          result->outtimelimit = OSP_DEF_TIMELIMIT;
00815          if (result->inhandle != OSP_INVALID_HANDLE) {
00816             OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
00817          }
00818          res = -1;
00819          break;
00820       }
00821    }
00822 
00823    return res;
00824 }
00825 
00826 /*!
00827  * \brief OSP Finish function
00828  * \param handle OSP in/outbound transaction handle
00829  * \param recorded If failure reason has been recorded
00830  * \param cause Asterisk hangup cause
00831  * \param start Call start time
00832  * \param connect Call connect time
00833  * \param end Call end time
00834  * \param release Who release first, 0 source, 1 destination
00835  * \return 1 Success, 0 Failed, -1 Error
00836  */
00837 static int osp_finish(int handle, int recorded, int cause, time_t start, time_t connect, time_t end, unsigned int release)
00838 {
00839    int res;
00840    enum OSPEFAILREASON reason;
00841    time_t alert = 0;
00842    unsigned isPddInfoPresent = 0;
00843    unsigned pdd = 0;
00844    unsigned int dummy = 0;
00845    int error;
00846    
00847    if (handle == OSP_INVALID_HANDLE) {
00848       return 0;
00849    }
00850 
00851    if (!recorded) {
00852       reason = asterisk2osp(cause);
00853       OSPPTransactionRecordFailure(handle, reason);
00854    }
00855 
00856    error = OSPPTransactionReportUsage(handle, difftime(end, connect), start, end, alert, connect, isPddInfoPresent, pdd,
00857                   release, (unsigned char *) "", 0, 0, 0, 0, &dummy, NULL);
00858    if (error == OSPC_ERR_NO_ERROR) {
00859       ast_log(LOG_DEBUG, "OSP: Usage reported\n");
00860       res = 1;
00861    } else {
00862       ast_log(LOG_DEBUG, "OSP: Unable to report usage, error '%d'\n", error);
00863       res = -1;
00864    }
00865    OSPPTransactionDelete(handle);
00866 
00867    return res;
00868 }
00869 
00870 /* OSP Application APIs */
00871 
00872 /*!
00873  * \brief OSP Application OSPAuth
00874  * \param chan Channel
00875  * \param data Parameter
00876  * \return 0 Success, -1 Failed
00877  */
00878 static int ospauth_exec(struct ast_channel* chan, void* data)
00879 {
00880    int res;
00881    struct ast_module_user *u;
00882    const char* provider = OSP_DEF_PROVIDER;
00883    int priority_jump = 0;
00884    struct varshead *headp;
00885    struct ast_var_t *current;
00886    const char *source = "";
00887    const char *token = "";
00888    int handle;
00889    unsigned int timelimit;
00890    char buffer[OSP_INTSTR_SIZE];
00891    const char *status;
00892    char *tmp;
00893 
00894    AST_DECLARE_APP_ARGS(args,
00895       AST_APP_ARG(provider);
00896       AST_APP_ARG(options);
00897    );
00898 
00899    u = ast_module_user_add(chan);
00900 
00901    if (!(tmp = ast_strdupa(data))) {
00902       ast_log(LOG_ERROR, "Out of memory\n");
00903       ast_module_user_remove(u);
00904       return -1;
00905    }
00906 
00907    AST_STANDARD_APP_ARGS(args, tmp);
00908 
00909    if (!ast_strlen_zero(args.provider)) {
00910       provider = args.provider;
00911    }
00912    ast_log(LOG_DEBUG, "OSPAuth: provider '%s'\n", provider);
00913 
00914    if ((args.options) && (strchr(args.options, 'j'))) {
00915       priority_jump = 1;
00916    }
00917    ast_log(LOG_DEBUG, "OSPAuth: priority jump '%d'\n", priority_jump);
00918 
00919    headp = &chan->varshead;
00920    AST_LIST_TRAVERSE(headp, current, entries) {
00921       if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
00922          source = ast_var_value(current);
00923       } else if (!strcasecmp(ast_var_name(current), "OSPINTOKEN")) {
00924          token = ast_var_value(current);
00925       }
00926    }
00927    ast_log(LOG_DEBUG, "OSPAuth: source '%s'\n", source);
00928    ast_log(LOG_DEBUG, "OSPAuth: token size '%zd'\n", strlen(token));
00929 
00930    
00931    if ((res = osp_auth(provider, &handle, source, chan->cid.cid_num, chan->exten, token, &timelimit)) > 0) {
00932       status = AST_OSP_SUCCESS;
00933    } else {
00934       timelimit = OSP_DEF_TIMELIMIT;
00935       if (!res) {
00936          status = AST_OSP_FAILED;
00937       } else {
00938          status = AST_OSP_ERROR;
00939       }
00940    }
00941 
00942    snprintf(buffer, sizeof(buffer), "%d", handle);
00943    pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
00944    ast_log(LOG_DEBUG, "OSPAuth: OSPINHANDLE '%s'\n", buffer);
00945    snprintf(buffer, sizeof(buffer), "%d", timelimit);
00946    pbx_builtin_setvar_helper(chan, "OSPINTIMELIMIT", buffer);
00947    ast_log(LOG_DEBUG, "OSPAuth: OSPINTIMELIMIT '%s'\n", buffer);
00948    pbx_builtin_setvar_helper(chan, "OSPAUTHSTATUS", status);
00949    ast_log(LOG_DEBUG, "OSPAuth: %s\n", status);
00950 
00951    if(res <= 0) {
00952       if (priority_jump || ast_opt_priority_jumping) {
00953          ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
00954          res = 0;
00955       } else {
00956          res = -1;
00957       }
00958    } else {
00959       res = 0;
00960    }
00961 
00962    ast_module_user_remove(u);
00963 
00964    return res;
00965 }
00966 
00967 /*!
00968  * \brief OSP Application OSPLookup
00969  * \param chan Channel
00970  * \param data Parameter
00971  * \return 0 Success, -1 Failed
00972  */
00973 static int osplookup_exec(struct ast_channel* chan, void* data)
00974 {
00975    int res, cres;
00976    struct ast_module_user *u;
00977    const char *provider = OSP_DEF_PROVIDER;
00978    int priority_jump = 0;
00979    struct varshead *headp;
00980    struct ast_var_t* current;
00981    const char *srcdev = "";
00982    char buffer[OSP_TOKSTR_SIZE];
00983    struct osp_result result;
00984    const char *status;
00985    char *tmp;
00986 
00987    AST_DECLARE_APP_ARGS(args,
00988       AST_APP_ARG(exten);
00989       AST_APP_ARG(provider);
00990       AST_APP_ARG(options);
00991    );
00992    
00993    if (ast_strlen_zero(data)) {
00994       ast_log(LOG_WARNING, "OSPLookup: Arg required, OSPLookup(exten[|provider[|options]])\n");
00995       return -1;
00996    }
00997 
00998    u = ast_module_user_add(chan);
00999 
01000    if (!(tmp = ast_strdupa(data))) {
01001       ast_log(LOG_ERROR, "Out of memory\n");
01002       ast_module_user_remove(u);
01003       return -1;
01004    }
01005 
01006    AST_STANDARD_APP_ARGS(args, tmp);
01007 
01008    ast_log(LOG_DEBUG, "OSPLookup: exten '%s'\n", args.exten);
01009 
01010    if (!ast_strlen_zero(args.provider)) {
01011       provider = args.provider;
01012    }
01013    ast_log(LOG_DEBUG, "OSPlookup: provider '%s'\n", provider);
01014 
01015    if ((args.options) && (strchr(args.options, 'j'))) {
01016       priority_jump = 1;
01017    }
01018    ast_log(LOG_DEBUG, "OSPLookup: priority jump '%d'\n", priority_jump);
01019 
01020    result.inhandle = OSP_INVALID_HANDLE;
01021    result.intimelimit = OSP_DEF_TIMELIMIT;
01022 
01023    headp = &chan->varshead;
01024    AST_LIST_TRAVERSE(headp, current, entries) {
01025       if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
01026          if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
01027             result.inhandle = OSP_INVALID_HANDLE;
01028          }
01029       } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
01030          if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
01031             result.intimelimit = OSP_DEF_TIMELIMIT;
01032          }
01033       } else if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
01034          srcdev = ast_var_value(current);
01035       }
01036    }
01037    ast_log(LOG_DEBUG, "OSPLookup: OSPINHANDLE '%d'\n", result.inhandle);
01038    ast_log(LOG_DEBUG, "OSPLookup: OSPINTIMELIMIT '%d'\n", result.intimelimit);
01039    ast_log(LOG_DEBUG, "OSPLookup: source device '%s'\n", srcdev);
01040    
01041    if ((cres = ast_autoservice_start(chan)) < 0) {
01042       ast_module_user_remove(u);
01043       return -1;
01044    }
01045 
01046    if ((res = osp_lookup(provider, srcdev, chan->cid.cid_num, args.exten, &result)) > 0) {
01047       status = AST_OSP_SUCCESS;
01048    } else {
01049       result.tech[0] = '\0';
01050       result.dest[0] = '\0';
01051       result.calling[0] = '\0';
01052       result.token[0] = '\0'; 
01053       result.numresults = 0;
01054       result.outtimelimit = OSP_DEF_TIMELIMIT;
01055       if (!res) {
01056          status = AST_OSP_FAILED;
01057       } else {
01058          status = AST_OSP_ERROR;
01059       }
01060    }
01061 
01062    snprintf(buffer, sizeof(buffer), "%d", result.outhandle);
01063    pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
01064    ast_log(LOG_DEBUG, "OSPLookup: OSPOUTHANDLE '%s'\n", buffer);
01065    pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
01066    ast_log(LOG_DEBUG, "OSPLookup: OSPTECH '%s'\n", result.tech);
01067    pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
01068    ast_log(LOG_DEBUG, "OSPLookup: OSPDEST '%s'\n", result.dest);
01069    pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
01070    ast_log(LOG_DEBUG, "OSPLookup: OSPCALLING '%s'\n", result.calling);
01071    pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
01072    ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
01073    snprintf(buffer, sizeof(buffer), "%d", result.numresults);
01074    pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
01075    ast_log(LOG_DEBUG, "OSPLookup: OSPRESULTS '%s'\n", buffer);
01076    snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
01077    pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
01078    ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTIMELIMIT '%s'\n", buffer);
01079    pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", status);
01080    ast_log(LOG_DEBUG, "OSPLookup: %s\n", status);
01081 
01082    if (!strcasecmp(result.tech, "SIP")) {
01083       if (!ast_strlen_zero(result.token)) {
01084          snprintf(buffer, sizeof(buffer), "P-OSP-Auth-Token: %s", result.token);
01085          pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
01086          ast_log(LOG_DEBUG, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
01087       }
01088    } else if (!strcasecmp(result.tech, "H323")) {
01089    } else if (!strcasecmp(result.tech, "IAX")) {
01090    }
01091 
01092    if ((cres = ast_autoservice_stop(chan)) < 0) {
01093       ast_module_user_remove(u);
01094       return -1;
01095    }
01096 
01097    if(res <= 0) {
01098       if (priority_jump || ast_opt_priority_jumping) {
01099          ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
01100          res = 0;
01101       } else {
01102          res = -1;
01103       }
01104    } else {
01105       res = 0;
01106    }
01107 
01108    ast_module_user_remove(u);
01109 
01110    return res;
01111 }
01112 
01113 /*!
01114  * \brief OSP Application OSPNext
01115  * \param chan Channel
01116  * \param data Parameter
01117  * \return 0 Success, -1 Failed
01118  */
01119 static int ospnext_exec(struct ast_channel* chan, void* data)
01120 {
01121    int res;
01122    struct ast_module_user *u;
01123    int priority_jump = 0;
01124    int cause = 0;
01125    struct varshead* headp;
01126    struct ast_var_t* current;
01127    struct osp_result result;
01128    char buffer[OSP_TOKSTR_SIZE];
01129    const char* status;
01130    char* tmp;
01131 
01132    AST_DECLARE_APP_ARGS(args,
01133       AST_APP_ARG(cause);
01134       AST_APP_ARG(options);
01135    );
01136    
01137    if (ast_strlen_zero(data)) {
01138       ast_log(LOG_WARNING, "OSPNext: Arg required, OSPNext(cause[|options])\n");
01139       return -1;
01140    }
01141 
01142    u = ast_module_user_add(chan);
01143 
01144    if (!(tmp = ast_strdupa(data))) {
01145       ast_log(LOG_ERROR, "Out of memory\n");
01146       ast_module_user_remove(u);
01147       return -1;
01148    }
01149 
01150    AST_STANDARD_APP_ARGS(args, tmp);
01151 
01152    if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%d", &cause) != 1) {
01153       cause = 0;
01154    }
01155    ast_log(LOG_DEBUG, "OSPNext: cause '%d'\n", cause);
01156 
01157    if ((args.options) && (strchr(args.options, 'j'))) {
01158       priority_jump = 1;
01159    }
01160    ast_log(LOG_DEBUG, "OSPNext: priority jump '%d'\n", priority_jump);
01161 
01162    result.inhandle = OSP_INVALID_HANDLE;
01163    result.outhandle = OSP_INVALID_HANDLE;
01164    result.intimelimit = OSP_DEF_TIMELIMIT;
01165    result.numresults = 0;
01166 
01167    headp = &chan->varshead;
01168    AST_LIST_TRAVERSE(headp, current, entries) {
01169       if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
01170          if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
01171             result.inhandle = OSP_INVALID_HANDLE;
01172          }
01173       } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
01174          if (sscanf(ast_var_value(current), "%d", &result.outhandle) != 1) {
01175             result.outhandle = OSP_INVALID_HANDLE;
01176          }
01177       } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
01178          if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
01179             result.intimelimit = OSP_DEF_TIMELIMIT;
01180          }
01181       } else if (!strcasecmp(ast_var_name(current), "OSPRESULTS")) {
01182          if (sscanf(ast_var_value(current), "%d", &result.numresults) != 1) {
01183             result.numresults = 0;
01184          }
01185       }
01186    }
01187    ast_log(LOG_DEBUG, "OSPNext: OSPINHANDLE '%d'\n", result.inhandle);
01188    ast_log(LOG_DEBUG, "OSPNext: OSPOUTHANDLE '%d'\n", result.outhandle);
01189    ast_log(LOG_DEBUG, "OSPNext: OSPINTIMELIMIT '%d'\n", result.intimelimit);
01190    ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%d'\n", result.numresults);
01191 
01192    if ((res = osp_next(cause, &result)) > 0) {
01193       status = AST_OSP_SUCCESS;
01194    } else {
01195       result.tech[0] = '\0';
01196       result.dest[0] = '\0';
01197       result.calling[0] = '\0';
01198       result.token[0] = '\0'; 
01199       result.numresults = 0;
01200       result.outtimelimit = OSP_DEF_TIMELIMIT;
01201       if (!res) {
01202          status = AST_OSP_FAILED;
01203       } else {
01204          status = AST_OSP_ERROR;
01205       }
01206    }
01207 
01208    pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
01209    ast_log(LOG_DEBUG, "OSPNext: OSPTECH '%s'\n", result.tech);
01210    pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
01211    ast_log(LOG_DEBUG, "OSPNext: OSPDEST '%s'\n", result.dest);
01212    pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
01213    ast_log(LOG_DEBUG, "OSPNext: OSPCALLING '%s'\n", result.calling);
01214    pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
01215    ast_log(LOG_DEBUG, "OSPNext: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
01216    snprintf(buffer, sizeof(buffer), "%d", result.numresults);
01217    pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
01218    ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%s'\n", buffer);
01219    snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
01220    pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
01221    ast_log(LOG_DEBUG, "OSPNext: OSPOUTTIMELIMIT '%s'\n", buffer);
01222    pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", status);
01223    ast_log(LOG_DEBUG, "OSPNext: %s\n", status);
01224 
01225    if (!strcasecmp(result.tech, "SIP")) {
01226       if (!ast_strlen_zero(result.token)) {
01227          snprintf(buffer, sizeof(buffer), "P-OSP-Auth-Token: %s", result.token);
01228          pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
01229          ast_log(LOG_DEBUG, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
01230       }
01231    } else if (!strcasecmp(result.tech, "H323")) {
01232    } else if (!strcasecmp(result.tech, "IAX")) {
01233    }
01234 
01235    if(res <= 0) {
01236       if (priority_jump || ast_opt_priority_jumping) {
01237          ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
01238          res = 0;
01239       } else {
01240          res = -1;
01241       }
01242    } else {
01243       res = 0;
01244    }
01245 
01246    ast_module_user_remove(u);
01247 
01248    return res;
01249 }
01250 
01251 /*!
01252  * \brief OSP Application OSPFinish
01253  * \param chan Channel
01254  * \param data Parameter
01255  * \return 0 Success, -1 Failed
01256  */
01257 static int ospfinished_exec(struct ast_channel* chan, void* data)
01258 {
01259    int res = 1;
01260    struct ast_module_user *u;
01261    int priority_jump = 0;
01262    int cause = 0;
01263    struct varshead *headp;
01264    struct ast_var_t *current;
01265    int inhandle = OSP_INVALID_HANDLE;
01266    int outhandle = OSP_INVALID_HANDLE;
01267    int recorded = 0;
01268    time_t start, connect, end;
01269    unsigned int release;
01270    char buffer[OSP_INTSTR_SIZE];
01271    const char *status;
01272    char *tmp;
01273 
01274    AST_DECLARE_APP_ARGS(args,
01275       AST_APP_ARG(cause);
01276       AST_APP_ARG(options);
01277    );
01278    
01279    u = ast_module_user_add(chan);
01280 
01281    if (!(tmp = ast_strdupa(data))) {
01282       ast_log(LOG_ERROR, "Out of memory\n");
01283       ast_module_user_remove(u);
01284       return -1;
01285    }
01286 
01287    AST_STANDARD_APP_ARGS(args, tmp);
01288 
01289    if ((args.options) && (strchr(args.options, 'j'))) {
01290       priority_jump = 1;
01291    }
01292    ast_log(LOG_DEBUG, "OSPFinish: priority jump '%d'\n", priority_jump);
01293 
01294    headp = &chan->varshead;
01295    AST_LIST_TRAVERSE(headp, current, entries) {
01296       if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
01297          if (sscanf(ast_var_value(current), "%d", &inhandle) != 1) {
01298             inhandle = OSP_INVALID_HANDLE;
01299          }
01300       } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
01301          if (sscanf(ast_var_value(current), "%d", &outhandle) != 1) {
01302             outhandle = OSP_INVALID_HANDLE;
01303          }
01304       } else if (!recorded &&
01305          (!strcasecmp(ast_var_name(current), "OSPAUTHSTATUS") ||
01306          !strcasecmp(ast_var_name(current), "OSPLOOKUPSTATUS") || 
01307          !strcasecmp(ast_var_name(current), "OSPNEXTSTATUS"))) 
01308       {
01309          if (strcasecmp(ast_var_value(current), AST_OSP_SUCCESS)) {
01310             recorded = 1;
01311          }
01312       }
01313    }
01314    ast_log(LOG_DEBUG, "OSPFinish: OSPINHANDLE '%d'\n", inhandle);
01315    ast_log(LOG_DEBUG, "OSPFinish: OSPOUTHANDLE '%d'\n", outhandle);
01316    ast_log(LOG_DEBUG, "OSPFinish: recorded '%d'\n", recorded);
01317 
01318    if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%d", &cause) != 1) {
01319       cause = 0;
01320    }
01321    ast_log(LOG_DEBUG, "OSPFinish: cause '%d'\n", cause);
01322 
01323    if (chan->cdr) {
01324       start = chan->cdr->start.tv_sec;
01325       connect = chan->cdr->answer.tv_sec;
01326       if (connect) {
01327          end = time(NULL);
01328       } else {
01329          end = connect;
01330       }
01331    } else {
01332       start = 0;
01333       connect = 0;
01334       end = 0;
01335    }
01336    ast_log(LOG_DEBUG, "OSPFinish: start '%ld'\n", start);
01337    ast_log(LOG_DEBUG, "OSPFinish: connect '%ld'\n", connect);
01338    ast_log(LOG_DEBUG, "OSPFinish: end '%ld'\n", end);
01339 
01340    release = chan->_softhangup ? 0 : 1;
01341 
01342    if (osp_finish(outhandle, recorded, cause, start, connect, end, release) <= 0) {
01343       ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for outbound call\n");
01344    }
01345    switch (cause) {
01346       case AST_CAUSE_NORMAL_CLEARING:
01347          break;
01348       default:
01349          cause = AST_CAUSE_NO_ROUTE_DESTINATION;
01350          break;
01351    }
01352    if (osp_finish(inhandle, recorded, cause, start, connect, end, release) <= 0) {
01353       ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for inbound call\n");
01354    }
01355    snprintf(buffer, sizeof(buffer), "%d", OSP_INVALID_HANDLE);
01356    pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
01357    pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
01358 
01359    if (res > 0) {
01360       status = AST_OSP_SUCCESS;
01361    } else if (!res) {
01362       status = AST_OSP_FAILED;
01363    } else {
01364       status = AST_OSP_ERROR;
01365    }
01366    pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", status);
01367 
01368    if(!res) {
01369       if (priority_jump || ast_opt_priority_jumping) {
01370          ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
01371          res = 0;
01372       } else {
01373          res = -1;
01374       }
01375    } else {
01376       res = 0;
01377    }
01378 
01379    ast_module_user_remove(u);
01380 
01381    return res;
01382 }
01383 
01384 /* OSP Module APIs */
01385 
01386 static int osp_load(void)
01387 {
01388    const char* t;
01389    unsigned int v;
01390    struct ast_config* cfg;
01391    int error = OSPC_ERR_NO_ERROR;
01392 
01393    cfg = ast_config_load(OSP_CONFIG_FILE);
01394    if (cfg) {
01395       t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "accelerate");
01396       if (t && ast_true(t)) {
01397          if ((error = OSPPInit(1)) != OSPC_ERR_NO_ERROR) {
01398             ast_log(LOG_WARNING, "OSP: Unable to enable hardware acceleration\n");
01399             OSPPInit(0);
01400          } else {
01401             osp_hardware = 1;
01402          }
01403       } else {
01404          OSPPInit(0);
01405       }
01406       ast_log(LOG_DEBUG, "OSP: osp_hardware '%d'\n", osp_hardware);
01407 
01408       t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat");
01409       if (t) {
01410          if ((sscanf(t, "%d", &v) == 1) && 
01411             ((v == TOKEN_ALGO_SIGNED) || (v == TOKEN_ALGO_UNSIGNED) || (v == TOKEN_ALGO_BOTH))) 
01412          {
01413             osp_tokenformat = v;
01414          } else {
01415             ast_log(LOG_WARNING, "tokenformat should be an integer from %d, %d or %d, not '%s'\n", 
01416                TOKEN_ALGO_SIGNED, TOKEN_ALGO_UNSIGNED, TOKEN_ALGO_BOTH, t);
01417          }
01418       }
01419       ast_log(LOG_DEBUG, "OSP: osp_tokenformat '%d'\n", osp_tokenformat);
01420 
01421       t = ast_category_browse(cfg, NULL);
01422       while(t) {
01423          if (strcasecmp(t, OSP_GENERAL_CAT)) {
01424             osp_create_provider(cfg, t);
01425          }
01426          t = ast_category_browse(cfg, t);
01427       }
01428 
01429       osp_initialized = 1;
01430 
01431       ast_config_destroy(cfg);
01432    } else {
01433       ast_log(LOG_WARNING, "OSP: Unable to find configuration. OSP support disabled\n");
01434       return 0;
01435    }
01436    ast_log(LOG_DEBUG, "OSP: osp_initialized '%d'\n", osp_initialized);
01437 
01438    return 1;
01439 }
01440 
01441 static int osp_unload(void)
01442 {
01443    struct osp_provider* p;
01444    struct osp_provider* next;
01445 
01446    if (osp_initialized) {
01447       ast_mutex_lock(&osplock);
01448       p = ospproviders;
01449       while(p) {
01450          next = p->next;
01451          OSPPProviderDelete(p->handle, 0);
01452          free(p);
01453          p = next;
01454       }
01455       ospproviders = NULL;
01456       ast_mutex_unlock(&osplock);
01457 
01458       OSPPCleanup();
01459 
01460       osp_tokenformat = TOKEN_ALGO_SIGNED;
01461       osp_hardware = 0;
01462       osp_initialized = 0;
01463    }
01464    return 0;
01465 }
01466 
01467 static int osp_show(int fd, int argc, char* argv[])
01468 {
01469    int i;
01470    int found = 0;
01471    struct osp_provider* p;
01472    const char* provider = NULL;
01473    const char* tokenalgo;
01474 
01475    if ((argc < 2) || (argc > 3)) {
01476       return RESULT_SHOWUSAGE;
01477    }
01478    if (argc > 2) {
01479       provider = argv[2];
01480    }
01481    if (!provider) {
01482       switch (osp_tokenformat) {
01483          case TOKEN_ALGO_BOTH:
01484             tokenalgo = "Both";
01485             break;
01486          case TOKEN_ALGO_UNSIGNED:
01487             tokenalgo = "Unsigned";
01488             break;
01489          case TOKEN_ALGO_SIGNED:
01490          default:
01491             tokenalgo = "Signed";
01492             break;
01493       }
01494       ast_cli(fd, "OSP: %s %s %s\n", 
01495          osp_initialized ? "Initialized" : "Uninitialized", osp_hardware ? "Accelerated" : "Normal", tokenalgo);
01496    }
01497 
01498    ast_mutex_lock(&osplock);
01499    p = ospproviders;
01500    while(p) {
01501       if (!provider || !strcasecmp(p->name, provider)) {
01502          if (found) {
01503             ast_cli(fd, "\n");
01504          }
01505          ast_cli(fd, " == OSP Provider '%s' == \n", p->name);
01506          ast_cli(fd, "Local Private Key: %s\n", p->privatekey);
01507          ast_cli(fd, "Local Certificate: %s\n", p->localcert);
01508          for (i = 0; i < p->cacount; i++) {
01509             ast_cli(fd, "CA Certificate %d:  %s\n", i + 1, p->cacerts[i]);
01510          }
01511          for (i = 0; i < p->spcount; i++) {
01512             ast_cli(fd, "Service Point %d:   %s\n", i + 1, p->srvpoints[i]);
01513          }
01514          ast_cli(fd, "Max Connections:   %d\n", p->maxconnections);
01515          ast_cli(fd, "Retry Delay:       %d seconds\n", p->retrydelay);
01516          ast_cli(fd, "Retry Limit:       %d\n", p->retrylimit);
01517          ast_cli(fd, "Timeout:           %d milliseconds\n", p->timeout);
01518          ast_cli(fd, "Source:            %s\n", strlen(p->source) ? p->source : "<unspecified>");
01519          ast_cli(fd, "Auth Policy        %d\n", p->authpolicy);
01520          ast_cli(fd, "OSP Handle:        %d\n", p->handle);
01521          found++;
01522       }
01523       p = p->next;
01524    }
01525    ast_mutex_unlock(&osplock);
01526 
01527    if (!found) {
01528       if (provider) {
01529          ast_cli(fd, "Unable to find OSP provider '%s'\n", provider);
01530       } else {
01531          ast_cli(fd, "No OSP providers configured\n");
01532       }
01533    }
01534    return RESULT_SUCCESS;
01535 }
01536 
01537 static const char* app1= "OSPAuth";
01538 static const char* synopsis1 = "OSP authentication";
01539 static const char* descrip1 = 
01540 "  OSPAuth([provider[|options]]):  Authenticate a SIP INVITE by OSP and sets\n"
01541 "the variables:\n"
01542 " ${OSPINHANDLE}:  The inbound call transaction handle\n"
01543 " ${OSPINTIMELIMIT}:  The inbound call duration limit in seconds\n"
01544 "\n"
01545 "The option string may contain the following character:\n"
01546 "  'j' -- jump to n+101 priority if the authentication was NOT successful\n"
01547 "This application sets the following channel variable upon completion:\n"
01548 "  OSPAUTHSTATUS  The status of the OSP Auth attempt as a text string, one of\n"
01549 "     SUCCESS | FAILED | ERROR\n";
01550 
01551 static const char* app2= "OSPLookup";
01552 static const char* synopsis2 = "Lookup destination by OSP";
01553 static const char* descrip2 = 
01554 "  OSPLookup(exten[|provider[|options]]):  Looks up an extension via OSP and sets\n"
01555 "the variables, where 'n' is the number of the result beginning with 1:\n"
01556 " ${OSPOUTHANDLE}:  The OSP Handle for anything remaining\n"
01557 " ${OSPTECH}:  The technology to use for the call\n"
01558 " ${OSPDEST}:  The destination to use for the call\n"
01559 " ${OSPCALLING}:  The calling number to use for the call\n"
01560 " ${OSPOUTTOKEN}:  The actual OSP token as a string\n"
01561 " ${OSPOUTTIMELIMIT}:  The outbound call duration limit in seconds\n"
01562 " ${OSPRESULTS}:  The number of OSP results total remaining\n"
01563 "\n"
01564 "The option string may contain the following character:\n"
01565 "  'j' -- jump to n+101 priority if the lookup was NOT successful\n"
01566 "This application sets the following channel variable upon completion:\n"
01567 "  OSPLOOKUPSTATUS   The status of the OSP Lookup attempt as a text string, one of\n"
01568 "     SUCCESS | FAILED | ERROR\n";
01569 
01570 static const char* app3 = "OSPNext";
01571 static const char* synopsis3 = "Lookup next destination by OSP";
01572 static const char* descrip3 = 
01573 "  OSPNext(cause[|options]):  Looks up the next OSP Destination for ${OSPOUTHANDLE}\n"
01574 "See OSPLookup for more information\n"
01575 "\n"
01576 "The option string may contain the following character:\n"
01577 "  'j' -- jump to n+101 priority if the lookup was NOT successful\n"
01578 "This application sets the following channel variable upon completion:\n"
01579 "  OSPNEXTSTATUS  The status of the OSP Next attempt as a text string, one of\n"
01580 "     SUCCESS | FAILED |ERROR\n";
01581 
01582 static const char* app4 = "OSPFinish";
01583 static const char* synopsis4 = "Record OSP entry";
01584 static const char* descrip4 = 
01585 "  OSPFinish([status[|options]]):  Records call state for ${OSPINHANDLE}, according to\n"
01586 "status, which should be one of BUSY, CONGESTION, ANSWER, NOANSWER, or CHANUNAVAIL\n"
01587 "or coincidentally, just what the Dial application stores in its ${DIALSTATUS}.\n"
01588 "\n"
01589 "The option string may contain the following character:\n"
01590 "  'j' -- jump to n+101 priority if the finish attempt was NOT successful\n"
01591 "This application sets the following channel variable upon completion:\n"
01592 "  OSPFINISHSTATUS   The status of the OSP Finish attempt as a text string, one of\n"
01593 "     SUCCESS | FAILED |ERROR \n";
01594 
01595 static const char osp_usage[] =
01596 "Usage: osp show\n"
01597 "       Displays information on Open Settlement Protocol support\n";
01598 
01599 static struct ast_cli_entry cli_osp[] = {
01600    { { "osp", "show", NULL},
01601    osp_show, "Displays OSP information",
01602    osp_usage },
01603 };
01604 
01605 static int load_module(void)
01606 {
01607    int res;
01608    
01609    if(!osp_load())
01610       return AST_MODULE_LOAD_DECLINE;
01611 
01612    ast_cli_register_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
01613    res = ast_register_application(app1, ospauth_exec, synopsis1, descrip1);
01614    res |= ast_register_application(app2, osplookup_exec, synopsis2, descrip2);
01615    res |= ast_register_application(app3, ospnext_exec, synopsis3, descrip3);
01616    res |= ast_register_application(app4, ospfinished_exec, synopsis4, descrip4);
01617 
01618    return res;
01619 }
01620 
01621 static int unload_module(void)
01622 {
01623    int res;
01624    
01625    res = ast_unregister_application(app4);
01626    res |= ast_unregister_application(app3);
01627    res |= ast_unregister_application(app2);
01628    res |= ast_unregister_application(app1);
01629    ast_cli_unregister_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
01630    osp_unload();
01631 
01632    ast_module_user_hangup_all();
01633 
01634    return res;
01635 }
01636 
01637 static int reload(void)
01638 {
01639    osp_unload();
01640    osp_load();
01641 
01642    return 0;
01643 }
01644 
01645 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Open Settlement Protocol Applications",
01646       .load = load_module,
01647       .unload = unload_module,
01648       .reload = reload,
01649       );

Generated on Mon May 14 04:42:53 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1