Issue #6899 - remove OSP support code from chan_sip.c and app_dial.c
authorOlle Johansson <oej@edvina.net>
Fri, 7 Apr 2006 19:11:22 +0000 (19:11 +0000)
committerOlle Johansson <oej@edvina.net>
Fri, 7 Apr 2006 19:11:22 +0000 (19:11 +0000)
- implement all functions through internal APIs in res_osp.c and app_osplookup.c
(homesick)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@18369 65c4cc65-6c06-0410-ace0-fbb531ad65f3

UPGRADE.txt
apps/app_dial.c
apps/app_osplookup.c
channels/chan_sip.c
configs/osp.conf.sample
doc/channelvariables.txt
include/asterisk/astosp.h
res/res_osp.c

index 6f9af43..a5f9cf6 100644 (file)
@@ -29,6 +29,8 @@ Applications:
   "noanswer" will not work.  Use s or n.  Also there is a new feature i, for
   using indication tones, so typing in skip would give you unexpected results.
 
+* OSPAuth is added to authenticate OSP tokens in in_bound call setup messages.
+
 Variables:
 
 * The builtin variables ${CALLERID}, ${CALLERIDNAME}, ${CALLERIDNUM},
@@ -40,6 +42,10 @@ Variables:
 * The CDR-CSV variables uniqueid, userfield, and basing time on GMT are now 
   adjustable from cdr.conf, instead of recompiling.
 
+* OSP applications exports several new variables, ${OSPINHANDLE},
+  ${OSPOUTHANDLE}, ${OSPINTOKEN}, ${OSPOUTTOKEN}, ${OSPCALLING},
+  ${OSPINTIMELIMIT}, and ${OSPOUTTIMELIMIT}
+
 Functions:
 
 * The function ${CHECK_MD5()} has been deprecated in favor of using an
@@ -66,6 +72,10 @@ The SIP channel:
 
 * The "incominglimit" setting is replaced by the "call-limit" setting in sip.conf.
 
+* OSP support code is removed from SIP channel to OSP applications. ospauth 
+  option in sip.conf is removed to osp.conf as authpolicy. allowguest option
+  in sip.conf cannot be set as osp anymore. 
+
 Installation:
 
 * On BSD systems, the installation directories have changed to more "FreeBSDish" directories. On startup, Asterisk will look for the main configuration in /usr/local/etc/asterisk/asterisk.conf
index 1987908..ba6ea70 100644 (file)
@@ -1189,10 +1189,6 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
        }
        if (peer) {
                time(&answer_time);
-#ifdef OSP_SUPPORT
-               /* Once call is answered, ditch the OSP Handle */
-               pbx_builtin_setvar_helper(chan, "_OSPHANDLE", "");
-#endif
                strcpy(status, "ANSWER");
                /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
                   we will always return with -1 so that it is hung up properly after the 
index 266c66d..374564a 100644 (file)
@@ -16,9 +16,9 @@
  * at the top of the source tree.
  */
 
-/*! \file
- *
- * \brief Open Settlement Protocol Lookup
+/*!
+ * \file
+ * \brief Open Settlement Protocol Applications
  *
  * \author Mark Spencer <markster@digium.com>
  * 
@@ -49,44 +49,55 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/app.h"
 #include "asterisk/options.h"
 
-static char *tdesc = "OSP Lookup";
-
-static char *app = "OSPLookup";
-static char *app2 = "OSPNext";
-static char *app3 = "OSPFinish";
-
-static char *synopsis = "Lookup number in OSP";
-static char *synopsis2 = "Lookup next OSP entry";
-static char *synopsis3 = "Record OSP entry";
+static char *app1= "OSPAuth";
+static char *synopsis1 = "OSP authentication";
+static char *descrip1 = 
+"  OSPAuth([provider[|options]]):  Authenticate a SIP INVITE by OSP and sets\n"
+"the variables:\n"
+" ${OSPINHANDLE}:  The in_bound call transaction handle\n"
+" ${OSPINTIMELIMIT}:  The in_bound call duration limit in seconds\n"
+"\n"
+"The option string may contain the following character:\n"
+"      'j' -- jump to n+101 priority if the authentication was NOT successful\n"
+"This application sets the following channel variable upon completion:\n"
+"      OSPAUTHSTATUS   The status of the OSP Auth attempt as a text string, one of\n"
+"              SUCCESS | FAILED | ERROR\n";
 
-static char *descrip = 
+static char *app2= "OSPLookup";
+static char *synopsis2 = "Lookup destination by OSP";
+static char *descrip2 = 
 "  OSPLookup(exten[|provider[|options]]):  Looks up an extension via OSP and sets\n"
 "the variables, where 'n' is the number of the result beginning with 1:\n"
-" ${OSPTECH}:   The technology to use for the call\n"
-" ${OSPDEST}:   The destination to use for the call\n"
-" ${OSPTOKEN}:  The actual OSP token as a string\n"
-" ${OSPHANDLE}: The OSP Handle for anything remaining\n"
-" ${OSPRESULTS}: The number of OSP results total remaining\n"
+" ${OSPOUTHANDLE}:  The OSP Handle for anything remaining\n"
+" ${OSPTECH}:  The technology to use for the call\n"
+" ${OSPDEST}:  The destination to use for the call\n"
+" ${OSPCALLING}:  The calling number to use for the call\n"
+" ${OSPOUTTOKEN}:  The actual OSP token as a string\n"
+" ${OSPOUTTIMELIMIT}:  The out_bound call duration limit in seconds\n"
+" ${OSPRESULTS}:  The number of OSP results total remaining\n"
 "\n"
 "The option string may contain the following character:\n"
 "      'j' -- jump to n+101 priority if the lookup was NOT successful\n"
 "This application sets the following channel variable upon completion:\n"
 "      OSPLOOKUPSTATUS The status of the OSP Lookup attempt as a text string, one of\n"
-"              SUCCESS | FAILED \n";
-
+"              SUCCESS | FAILED | ERROR\n";
 
-static char *descrip2 = 
-"  OSPNext(cause[|options]):  Looks up the next OSP Destination for ${OSPHANDLE}\n"
+static char *app3 = "OSPNext";
+static char *synopsis3 = "Lookup next destination by OSP";
+static char *descrip3 = 
+"  OSPNext(cause[|options]):  Looks up the next OSP Destination for ${OSPOUTHANDLE}\n"
 "See OSPLookup for more information\n"
 "\n"
 "The option string may contain the following character:\n"
 "      'j' -- jump to n+101 priority if the lookup was NOT successful\n"
 "This application sets the following channel variable upon completion:\n"
 "      OSPNEXTSTATUS   The status of the OSP Next attempt as a text string, one of\n"
-"              SUCCESS | FAILED \n";
+"              SUCCESS | FAILED |ERROR\n";
 
-static char *descrip3 = 
-"  OSPFinish(status[|options]):  Records call state for ${OSPHANDLE}, according to\n"
+static char *app4 = "OSPFinish";
+static char *synopsis4 = "Record OSP entry";
+static char *descrip4 = 
+"  OSPFinish([status[|options]]):  Records call state for ${OSPINHANDLE}, according to\n"
 "status, which should be one of BUSY, CONGESTION, ANSWER, NOANSWER, or CHANUNAVAIL\n"
 "or coincidentally, just what the Dial application stores in its ${DIALSTATUS}.\n"
 "\n"
@@ -94,278 +105,546 @@ static char *descrip3 =
 "      'j' -- jump to n+101 priority if the finish attempt was NOT successful\n"
 "This application sets the following channel variable upon completion:\n"
 "      OSPFINISHSTATUS The status of the OSP Finish attempt as a text string, one of\n"
-"              SUCCESS | FAILED \n";
+"              SUCCESS | FAILED |ERROR \n";
 
 LOCAL_USER_DECL;
 
-static int str2cause(char *cause)
+static int ospauth_exec(struct ast_channel *chan, void *data)
 {
-       if (!strcasecmp(cause, "BUSY"))
-               return AST_CAUSE_BUSY;
-       if (!strcasecmp(cause, "CONGESTION"))
-               return AST_CAUSE_CONGESTION;
-       if (!strcasecmp(cause, "ANSWER"))
-               return AST_CAUSE_NORMAL;
-       if (!strcasecmp(cause, "CANCEL"))
-               return AST_CAUSE_NORMAL;
-       if (!strcasecmp(cause, "NOANSWER"))
-               return AST_CAUSE_NOANSWER;
-       if (!strcasecmp(cause, "NOCHANAVAIL"))
-               return AST_CAUSE_CONGESTION;
-       ast_log(LOG_WARNING, "Unknown cause '%s', using NORMAL\n", cause);
-       return AST_CAUSE_NORMAL;
+       int res = 0;
+       struct localuser* u;
+       char* provider = OSP_DEF_PROVIDER;
+       int priority_jump = 0;
+       struct varshead* headp;
+       struct ast_var_t* current;
+       const char* source = "";
+       const char* token = "";
+       int handle;
+       unsigned int timelimit;
+       char* tmp;
+       char buffer[OSP_INTSTR_SIZE];
+       char* status;
+
+       AST_DECLARE_APP_ARGS(args,
+               AST_APP_ARG(provider);
+               AST_APP_ARG(options);
+       );
+
+       LOCAL_USER_ADD(u);
+
+       if (!(tmp = ast_strdupa(data))) {
+               ast_log(LOG_ERROR, "Out of memory\n");
+               LOCAL_USER_REMOVE(u);
+               return(-1);
+       }
+
+       AST_STANDARD_APP_ARGS(args, tmp);
+
+       if (!ast_strlen_zero(args.provider)) {
+               provider = args.provider;
+       }
+       ast_log(LOG_DEBUG, "OSPAuth: provider '%s'\n", provider);
+
+       if (args.options) {
+               if (strchr(args.options, 'j')) {
+                       priority_jump = 1;
+               }
+       }
+       ast_log(LOG_DEBUG, "OSPAuth: priority jump '%d'\n", priority_jump);
+
+       headp = &chan->varshead;
+       AST_LIST_TRAVERSE(headp, current, entries) {
+               if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
+                       source = ast_var_value(current);
+               } else if (!strcasecmp(ast_var_name(current), "OSPINTOKEN")) {
+                       token = ast_var_value(current);
+               }
+       }
+       ast_log(LOG_DEBUG, "OSPAuth: source '%s'\n", source);
+       ast_log(LOG_DEBUG, "OSPAuth: token size '%d'\n", strlen(token));
+
+       res = ast_osp_auth(provider, &handle, source, chan->cid.cid_num, chan->exten, token, &timelimit);
+       if (res > 0) {
+               status = OSP_APP_SUCCESS;
+       } else {
+               timelimit = OSP_DEF_TIMELIMIT;
+               if (!res) {
+                       status = OSP_APP_FAILED;
+               } else {
+                       handle = OSP_INVALID_HANDLE;
+                       status = OSP_APP_ERROR;
+               }
+       }
+
+       snprintf(buffer, sizeof(buffer), "%d", handle);
+       pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
+       ast_log(LOG_DEBUG, "OSPAuth: OSPINHANDLE '%s'\n", buffer);
+       snprintf(buffer, sizeof(buffer), "%d", timelimit);
+       pbx_builtin_setvar_helper(chan, "OSPINTIMELIMIT", buffer);
+       ast_log(LOG_DEBUG, "OSPAuth: OSPINTIMELIMIT '%s'\n", buffer);
+       pbx_builtin_setvar_helper(chan, "OSPAUTHSTATUS", status);
+       ast_log(LOG_DEBUG, "OSPAuth: %s\n", status);
+
+       if(!res) {
+               if (priority_jump || ast_opt_priority_jumping) {
+                       ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
+               } else {
+                       res = -1;
+               }
+       } else if (res > 0) {
+               res = 0;
+       }
+
+       LOCAL_USER_REMOVE(u);
+
+       return(res);
 }
 
 static int osplookup_exec(struct ast_channel *chan, void *data)
 {
-       int res=0;
-       struct localuser *u;
-       char *temp;
-       struct ast_osp_result result;
+       int res = 0;
+       struct localuser* u;
+       char* provider = OSP_DEF_PROVIDER;
        int priority_jump = 0;
+       struct varshead* headp;
+       struct ast_var_t* current;
+       const char* srcdev = "";
+       char* tmp;
+       char buffer[OSP_TOKSTR_SIZE];
+       struct ast_osp_result result;
+       char* status;
+
        AST_DECLARE_APP_ARGS(args,
-               AST_APP_ARG(extension);
+               AST_APP_ARG(exten);
                AST_APP_ARG(provider);
                AST_APP_ARG(options);
        );
        
        if (ast_strlen_zero(data)) {
-               ast_log(LOG_WARNING, "OSPLookup requires an argument OSPLookup(exten[|provider[|options]])\n");
-               return -1;
+               ast_log(LOG_WARNING, "OSPLookup: Arg required, OSPLookup(exten[|provider[|options]])\n");
+               return(-1);
        }
 
        LOCAL_USER_ADD(u);
 
-       if (!(temp = ast_strdupa(data))) {
+       if (!(tmp = ast_strdupa(data))) {
+               ast_log(LOG_ERROR, "Out of memory\n");
                LOCAL_USER_REMOVE(u);
-               return -1;
+               return(-1);
        }
 
-       AST_STANDARD_APP_ARGS(args, temp);
+       AST_STANDARD_APP_ARGS(args, tmp);
+
+       ast_log(LOG_DEBUG, "OSPLookup: exten '%s'\n", args.exten);
+
+       if (!ast_strlen_zero(args.provider)) {
+               provider = args.provider;
+       }
+       ast_log(LOG_DEBUG, "OSPlookup: provider '%s'\n", provider);
 
        if (args.options) {
-               if (strchr(args.options, 'j'))
+               if (strchr(args.options, 'j')) {
                        priority_jump = 1;
+               }
        }
+       ast_log(LOG_DEBUG, "OSPLookup: priority jump '%d'\n", priority_jump);
+
+       result.inhandle = OSP_INVALID_HANDLE;
+
+       headp = &chan->varshead;
+       AST_LIST_TRAVERSE(headp, current, entries) {
+               if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
+                       if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
+                               result.inhandle = OSP_INVALID_HANDLE;
+                       }
+               } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
+                       if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
+                               result.intimelimit = OSP_DEF_TIMELIMIT;
+                       }
+               } else if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
+                       srcdev = ast_var_value(current);
+               }
+       }
+       ast_log(LOG_DEBUG, "OSPLookup: OSPINHANDLE '%d'\n", result.inhandle);
+       ast_log(LOG_DEBUG, "OSPLookup: OSPINTIMELIMIT '%d'\n", result.intimelimit);
+       ast_log(LOG_DEBUG, "OSPLookup: source device '%s'\n", srcdev);
 
-       ast_log(LOG_DEBUG, "Whoo hoo, looking up OSP on '%s' via '%s'\n", args.extension, args.provider ? args.provider : "<default>");
-       if ((res = ast_osp_lookup(chan, args.provider, args.extension, chan->cid.cid_num, &result)) > 0) {
-               char tmp[80];
-               snprintf(tmp, sizeof(tmp), "%d", result.handle);
-               pbx_builtin_setvar_helper(chan, "_OSPHANDLE", tmp);
-               pbx_builtin_setvar_helper(chan, "_OSPTECH", result.tech);
-               pbx_builtin_setvar_helper(chan, "_OSPDEST", result.dest);
-               pbx_builtin_setvar_helper(chan, "_OSPTOKEN", result.token);
-               snprintf(tmp, sizeof(tmp), "%d", result.numresults);
-               pbx_builtin_setvar_helper(chan, "_OSPRESULTS", tmp);
-               pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", "SUCCESS");
-
+       res = ast_osp_lookup(provider, srcdev, chan->cid.cid_num, args.exten, &result);
+       if (res > 0) {
+               status = OSP_APP_SUCCESS;
        } else {
+               result.tech[0] = '\0';
+               result.dest[0] = '\0';
+               result.calling[0] = '\0';
+               result.token[0] = '\0'; 
+               result.numresults = 0;
+               result.outtimelimit = OSP_DEF_TIMELIMIT;
                if (!res) {
-                       ast_log(LOG_NOTICE, "OSP Lookup failed for '%s' (provider '%s')\n", args.extension, args.provider ? args.provider : "<default>");
-                       pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", "FAILED");
-               } else
-                       ast_log(LOG_DEBUG, "Got hangup on '%s' while doing OSP Lookup for '%s' (provider '%s')!\n", chan->name, args.extension, args.provider ? args.provider : "<default>" );
+                       status = OSP_APP_FAILED;
+               } else {
+                       result.outhandle = OSP_INVALID_HANDLE;
+                       status = OSP_APP_ERROR;
+               }
+       }
+
+       snprintf(buffer, sizeof(buffer), "%d", result.outhandle);
+       pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
+       ast_log(LOG_DEBUG, "OSPLookup: OSPOUTHANDLE '%s'\n", buffer);
+       pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
+       ast_log(LOG_DEBUG, "OSPLookup: OSPTECH '%s'\n", result.tech);
+       pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
+       ast_log(LOG_DEBUG, "OSPLookup: OSPDEST '%s'\n", result.dest);
+       pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
+       ast_log(LOG_DEBUG, "OSPLookup: OSPCALLING '%s'\n", result.calling);
+       pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
+       ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTOKEN size '%d'\n", strlen(result.token));
+       if (!ast_strlen_zero(result.token)) {
+               snprintf(buffer, sizeof(buffer), "P-OSP-Auth-Token: %s", result.token);
+               pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
+               ast_log(LOG_DEBUG, "OSPLookup: SIPADDHEADER size '%d'\n", strlen(buffer));
        }
-       if (!res) {
-               /* Look for a "busy" place */
-               if (priority_jump || ast_opt_priority_jumping)
+       snprintf(buffer, sizeof(buffer), "%d", result.numresults);
+       pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
+       ast_log(LOG_DEBUG, "OSPLookup: OSPRESULTS '%s'\n", buffer);
+       snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
+       pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
+       ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTIMELIMIT '%s'\n", buffer);
+       pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", status);
+       ast_log(LOG_DEBUG, "OSPLookup: %s\n", status);
+
+       if(!res) {
+               if (priority_jump || ast_opt_priority_jumping) {
                        ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
-       } else if (res > 0)
+               } else {
+                       res = -1;
+               }
+       } else if (res > 0) {
                res = 0;
+       }
+
        LOCAL_USER_REMOVE(u);
-       return res;
+
+       return(res);
+}
+
+static int str2cause(char *str)
+{
+       int cause = AST_CAUSE_NORMAL;
+
+       if (ast_strlen_zero(str)) {
+               cause = AST_CAUSE_NOTDEFINED;
+       } else if (!strcasecmp(str, "BUSY")) {
+               cause = AST_CAUSE_BUSY;
+       } else if (!strcasecmp(str, "CONGESTION")) {
+               cause = AST_CAUSE_CONGESTION;
+       } else if (!strcasecmp(str, "ANSWER")) {
+               cause = AST_CAUSE_NORMAL;
+       } else if (!strcasecmp(str, "CANCEL")) {
+               cause = AST_CAUSE_NORMAL;
+       } else if (!strcasecmp(str, "NOANSWER")) {
+               cause = AST_CAUSE_NOANSWER;
+       } else if (!strcasecmp(str, "NOCHANAVAIL")) {
+               cause = AST_CAUSE_CONGESTION;
+       } else {
+               ast_log(LOG_WARNING, "OSP: Unknown cause '%s', using NORMAL\n", str);
+       }
+
+       return(cause);
 }
 
 static int ospnext_exec(struct ast_channel *chan, void *data)
 {
        int res=0;
        struct localuser *u;
-       char *temp;
-       const char *val;
+       int priority_jump = 0;
        int cause;
+       struct varshead* headp;
+       struct ast_var_t* current;
        struct ast_osp_result result;
-       int priority_jump = 0;
+       char *tmp;
+       char buffer[OSP_TOKSTR_SIZE];
+       char* status;
+
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(cause);
                AST_APP_ARG(options);
        );
        
        if (ast_strlen_zero(data)) {
-               ast_log(LOG_WARNING, "OSPNext should have an argument (cause[|options])\n");
-               return -1;
+               ast_log(LOG_WARNING, "OSPNext: Arg required, OSPNext(cause[|options])\n");
+               return(-1);
        }
 
        LOCAL_USER_ADD(u);
 
-       if (!(temp = ast_strdupa(data))) {
+       if (!(tmp = ast_strdupa(data))) {
+               ast_log(LOG_ERROR, "Out of memory\n");
                LOCAL_USER_REMOVE(u);
-               return -1;
+               return(-1);
        }
 
-       AST_STANDARD_APP_ARGS(args, temp);
+       AST_STANDARD_APP_ARGS(args, tmp);
+
+       cause = str2cause(args.cause);
+       ast_log(LOG_DEBUG, "OSPNext: cause '%d'\n", cause);
 
        if (args.options) {
                if (strchr(args.options, 'j'))
                        priority_jump = 1;
        }
-
-       cause = str2cause(args.cause);
-       val = pbx_builtin_getvar_helper(chan, "OSPHANDLE");
-       result.handle = -1;
-       if (!ast_strlen_zero(val) && (sscanf(val, "%d", &result.handle) == 1) && (result.handle > -1)) {
-               val = pbx_builtin_getvar_helper(chan, "OSPRESULTS");
-               if (ast_strlen_zero(val) || (sscanf(val, "%d", &result.numresults) != 1)) {
-                       result.numresults = 0;
-               }
-               if ((res = ast_osp_next(&result, cause)) > 0) {
-                       char tmp[80];
-                       snprintf(tmp, sizeof(tmp), "%d", result.handle);
-                       pbx_builtin_setvar_helper(chan, "_OSPHANDLE", tmp);
-                       pbx_builtin_setvar_helper(chan, "_OSPTECH", result.tech);
-                       pbx_builtin_setvar_helper(chan, "_OSPDEST", result.dest);
-                       pbx_builtin_setvar_helper(chan, "_OSPTOKEN", result.token);
-                       snprintf(tmp, sizeof(tmp), "%d", result.numresults);
-                       pbx_builtin_setvar_helper(chan, "_OSPRESULTS", tmp);
-                       pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", "SUCCESS");
+       ast_log(LOG_DEBUG, "OSPNext: priority jump '%d'\n", priority_jump);
+
+       result.inhandle = OSP_INVALID_HANDLE;
+       result.outhandle = OSP_INVALID_HANDLE;
+       result.numresults = 0;
+
+       headp = &chan->varshead;
+       AST_LIST_TRAVERSE(headp, current, entries) {
+               if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
+                       if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
+                               result.inhandle = OSP_INVALID_HANDLE;
+                       }
+               } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
+                       if (sscanf(ast_var_value(current), "%d", &result.outhandle) != 1) {
+                               result.outhandle = OSP_INVALID_HANDLE;
+                       }
+               } else if (!strcasecmp(ast_var_name(current), "OSPINTIMEOUT")) {
+                       if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
+                               result.intimelimit = OSP_DEF_TIMELIMIT;
+                       }
+               } else if (!strcasecmp(ast_var_name(current), "OSPRESULTS")) {
+                       if (sscanf(ast_var_value(current), "%d", &result.numresults) != 1) {
+                               result.numresults = 0;
+                       }
                }
+       }
+       ast_log(LOG_DEBUG, "OSPNext: OSPINHANDLE '%d'\n", result.inhandle);
+       ast_log(LOG_DEBUG, "OSPNext: OSPOUTHANDLE '%d'\n", result.outhandle);
+       ast_log(LOG_DEBUG, "OSPNext: OSPINTIMELIMIT '%d'\n", result.intimelimit);
+       ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%d'\n", result.numresults);
+
+       if ((res = ast_osp_next(cause, &result)) > 0) {
+               status = OSP_APP_SUCCESS;
        } else {
+               result.tech[0] = '\0';
+               result.dest[0] = '\0';
+               result.calling[0] = '\0';
+               result.token[0] = '\0'; 
+               result.numresults = 0;
+               result.outtimelimit = OSP_DEF_TIMELIMIT;
                if (!res) {
-                       if (result.handle < 0)
-                               ast_log(LOG_NOTICE, "OSP Lookup Next failed for handle '%d'\n", result.handle);
-                       else
-                               ast_log(LOG_DEBUG, "No OSP handle specified\n");
-                       pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", "FAILED");     
-               } else
-                       ast_log(LOG_DEBUG, "Got hangup on '%s' while doing OSP Next!\n", chan->name);
+                       status = OSP_APP_FAILED;
+               } else {
+                       result.outhandle = OSP_INVALID_HANDLE;
+                       status = OSP_APP_ERROR;
+               }
+       }
+
+       pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
+       ast_log(LOG_DEBUG, "OSPNext: OSPTECH '%s'\n", result.tech);
+       pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
+       ast_log(LOG_DEBUG, "OSPNext: OSPDEST '%s'\n", result.dest);
+       pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
+       ast_log(LOG_DEBUG, "OSPNext: OSPCALLING '%s'\n", result.calling);
+       pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
+       ast_log(LOG_DEBUG, "OSPNext: OSPOUTTOKEN size '%d'\n", strlen(result.token));
+       if (!ast_strlen_zero(result.token)) {
+               snprintf(buffer, sizeof(buffer), "P-OSP-Auth-Token: %s", result.token);
+               pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
+               ast_log(LOG_DEBUG, "OSPNext: SIPADDHEADER size '%d'\n", strlen(buffer));
        }
-       if (!res) {
-               /* Look for a "busy" place */
-               if (priority_jump || ast_opt_priority_jumping)
+       snprintf(buffer, sizeof(buffer), "%d", result.numresults);
+       pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
+       ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%s'\n", buffer);
+       snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
+       pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
+       ast_log(LOG_DEBUG, "OSPNext: OSPOUTTIMELIMIT '%s'\n", buffer);
+       pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", status);
+       ast_log(LOG_DEBUG, "OSPNext: %s\n", status);
+
+       if(!res) {
+               if (priority_jump || ast_opt_priority_jumping) {
                        ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
-       } else if (res > 0)
+               } else {
+                       res = -1;
+               }
+       } else if (res > 0) {
                res = 0;
+       }
+
        LOCAL_USER_REMOVE(u);
-       return res;
+
+       return(res);
 }
 
 static int ospfinished_exec(struct ast_channel *chan, void *data)
 {
-       int res=0;
-       struct localuser *u;
-       char *temp;
-       const char *val;
-       int cause;
-       time_t start=0, duration=0;
-       struct ast_osp_result result;
+       int res = 1;
+       struct localuser* u;
        int priority_jump = 0;
+       int cause;
+       struct varshead* headp;
+       struct ast_var_t* current;
+       int inhandle = OSP_INVALID_HANDLE;
+       int outhandle = OSP_INVALID_HANDLE;
+       int recorded = 0;
+       time_t start, connect, end;
+       char* tmp;
+       char* str = "";
+       char buffer[OSP_INTSTR_SIZE];
+       char* status;
+
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(status);
                AST_APP_ARG(options);
        );
        
-       if (ast_strlen_zero(data)) {
-               ast_log(LOG_WARNING, "OSPFinish should have an argument (status[|options])\n");
-               return -1;
-       }
-
        LOCAL_USER_ADD(u);
 
-       if (!(temp = ast_strdupa(data))) {
+       if (!(tmp = ast_strdupa(data))) {
+               ast_log(LOG_ERROR, "Out of memory\n");
                LOCAL_USER_REMOVE(u);
-               return -1;
+               return(-1);
        }
 
-       AST_STANDARD_APP_ARGS(args, temp);
+       AST_STANDARD_APP_ARGS(args, tmp);
 
        if (args.options) {
                if (strchr(args.options, 'j'))
                        priority_jump = 1;
        }
+       ast_log(LOG_DEBUG, "OSPFinish: priority jump '%d'\n", priority_jump);
+
+       headp = &chan->varshead;
+       AST_LIST_TRAVERSE(headp, current, entries) {
+               if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
+                       if (sscanf(ast_var_value(current), "%d", &inhandle) != 1) {
+                               inhandle = OSP_INVALID_HANDLE;
+                       }
+               } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
+                       if (sscanf(ast_var_value(current), "%d", &outhandle) != 1) {
+                               outhandle = OSP_INVALID_HANDLE;
+                       }
+               } else if (!recorded &&
+                       (!strcasecmp(ast_var_name(current), "OSPAUTHSTATUS") ||
+                       !strcasecmp(ast_var_name(current), "OSPLOOKUPSTATUS") || 
+                       !strcasecmp(ast_var_name(current), "OSPNEXTSTATUS"))) 
+               {
+                       if (strcasecmp(ast_var_value(current), OSP_APP_SUCCESS)) {
+                               recorded = 1;
+                       }
+               }
+       }
+       ast_log(LOG_DEBUG, "OSPFinish: OSPINHANDLE '%d'\n", inhandle);
+       ast_log(LOG_DEBUG, "OSPFinish: OSPOUTHANDLE '%d'\n", outhandle);
+       ast_log(LOG_DEBUG, "OSPFinish: recorded '%d'\n", recorded);
+
+       if (!recorded) {
+               str = args.status;
+       }
+       cause = str2cause(str);
+       ast_log(LOG_DEBUG, "OSPFinish: cause '%d'\n", cause);
 
        if (chan->cdr) {
-               start = chan->cdr->answer.tv_sec;
-               if (start)
-                       duration = time(NULL) - start;
-               else
-                       duration = 0;
-       } else
-               ast_log(LOG_WARNING, "OSPFinish called on channel '%s' with no CDR!\n", chan->name);
-       
-       cause = str2cause(args.status);
-       val = pbx_builtin_getvar_helper(chan, "OSPHANDLE");
-       result.handle = -1;
-       if (!ast_strlen_zero(val) && (sscanf(val, "%d", &result.handle) == 1) && (result.handle > -1)) {
-               if (!ast_osp_terminate(result.handle, cause, start, duration)) {
-                       pbx_builtin_setvar_helper(chan, "_OSPHANDLE", "");
-                       pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", "SUCCESS");
-                       res = 1;
+               start = chan->cdr->start.tv_sec;
+               connect = chan->cdr->answer.tv_sec;
+               if (connect) {
+                       end = time(NULL);
+               } else {
+                       end = connect;
                }
        } else {
-               if (!res) {
-                       if (result.handle > -1)
-                               ast_log(LOG_NOTICE, "OSP Finish failed for handle '%d'\n", result.handle);
-                       else
-                               ast_log(LOG_DEBUG, "No OSP handle specified\n");
-                       pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", "FAILED");
-               } else
-                       ast_log(LOG_DEBUG, "Got hangup on '%s' while doing OSP Terminate!\n", chan->name);
+               start = 0;
+               connect = 0;
+               end = 0;
+       }
+       ast_log(LOG_DEBUG, "OSPFinish: start '%ld'\n", start);
+       ast_log(LOG_DEBUG, "OSPFinish: connect '%ld'\n", connect);
+       ast_log(LOG_DEBUG, "OSPFinish: end '%ld'\n", end);
+
+       if (ast_osp_finish(outhandle, cause, start, connect, end) <= 0) {
+               ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for out_bound call\n");
+       }
+       if (ast_osp_finish(inhandle, cause, start, connect, end) <= 0) {
+               ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for in_bound call\n");
+       }
+       snprintf(buffer, sizeof(buffer), "%d", OSP_INVALID_HANDLE);
+       pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
+       pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
+
+       if (res > 0) {
+               status = OSP_APP_SUCCESS;
+       } else if (!res) {
+               status = OSP_APP_FAILED;
+       } else {
+               status = OSP_APP_ERROR;
        }
-       if (!res) {
-               /* Look for a "busy" place */
-               if (priority_jump || ast_opt_priority_jumping)
+       pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", status);
+
+       if(!res) {
+               if (priority_jump || ast_opt_priority_jumping) {
                        ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
-       } else if (res > 0)
+               } else {
+                       res = -1;
+               }
+       } else if (res > 0) {
                res = 0;
+       }
+
        LOCAL_USER_REMOVE(u);
-       return res;
-}
 
+       return(res);
+}
 
-int unload_module(void)
+int load_module(void)
 {
        int res;
        
-       res = ast_unregister_application(app3);
-       res |= ast_unregister_application(app2);
-       res |= ast_unregister_application(app);
+       ast_osp_adduse();
 
-       STANDARD_HANGUP_LOCALUSERS;
+       res = ast_register_application(app1, ospauth_exec, synopsis1, descrip1);
+       res |= ast_register_application(app2, osplookup_exec, synopsis2, descrip2);
+       res |= ast_register_application(app3, ospnext_exec, synopsis3, descrip3);
+       res |= ast_register_application(app4, ospfinished_exec, synopsis4, descrip4);
 
-       return res;
+       return(res);
 }
 
-int load_module(void)
+int unload_module(void)
 {
        int res;
        
-       res = ast_register_application(app, osplookup_exec, synopsis, descrip);
-       res |= ast_register_application(app2, ospnext_exec, synopsis2, descrip2);
-       res |= ast_register_application(app3, ospfinished_exec, synopsis3, descrip3);
-       
-       return res;
+       res = ast_unregister_application(app4);
+       res |= ast_unregister_application(app3);
+       res |= ast_unregister_application(app2);
+       res |= ast_unregister_application(app1);
+
+       STANDARD_HANGUP_LOCALUSERS;
+
+       ast_osp_deluse();
+
+       return(res);
 }
 
 int reload(void)
 {
-       return 0;
+       return(0);
 }
 
-
 char *description(void)
 {
-       return tdesc;
+       return("Open Settlement Protocol Applications");
 }
 
 int usecount(void)
 {
        int res;
        STANDARD_USECOUNT(res);
-       return res;
+       return(res);
 }
 
 char *key()
 {
-       return ASTERISK_GPL_KEY;
+       return(ASTERISK_GPL_KEY);
 }
 
index 7b2d58a..196e60f 100644 (file)
@@ -93,10 +93,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/stringfields.h"
 #include "asterisk/monitor.h"
 
-#ifdef OSP_SUPPORT
-#include "asterisk/astosp.h"
-#endif
-
 #ifndef FALSE
 #define FALSE  0
 #endif
@@ -506,7 +502,6 @@ struct sip_pkt;
 /*! \brief Parameters to the transmit_invite function */
 struct sip_invite_param {
        const char *distinctive_ring;   /*!< Distinctive ring header */
-       const char *osptoken;           /*!< OSP token for this call */
        int addsipheaders;      /*!< Add extra SIP headers */
        const char *uri_options;        /*!< URI options to add to the URI */
        const char *vxml_url;           /*!< VXML url for Cisco phones */
@@ -596,20 +591,14 @@ struct sip_auth {
 #define SIP_PROG_INBAND_NEVER  (0 << 24)
 #define SIP_PROG_INBAND_NO     (1 << 24)
 #define SIP_PROG_INBAND_YES    (2 << 24)
-/* Open Settlement Protocol authentication */
-#define SIP_OSPAUTH            (3 << 26)       /*!< four settings, uses two bits */
-#define SIP_OSPAUTH_NO         (0 << 26)
-#define SIP_OSPAUTH_GATEWAY    (1 << 26)
-#define SIP_OSPAUTH_PROXY      (2 << 26)
-#define SIP_OSPAUTH_EXCLUSIVE  (3 << 26)
-#define SIP_CALL_ONHOLD                (1 << 28)       /*!< Call states */
-#define SIP_CALL_LIMIT         (1 << 29)       /*!< Call limit enforced for this call */
-#define SIP_SENDRPID           (1 << 30)       /*!< Remote Party-ID Support */
-#define SIP_INC_COUNT          (1 << 31)       /*!< Did this connection increment the counter of in-use calls? */
+#define SIP_CALL_ONHOLD                (1 << 26)       /*!< Call states */
+#define SIP_CALL_LIMIT         (1 << 27)       /*!< Call limit enforced for this call */
+#define SIP_SENDRPID           (1 << 28)       /*!< Remote Party-ID Support */
+#define SIP_INC_COUNT          (1 << 29)       /*!< Did this connection increment the counter of in-use calls? */
 
 #define SIP_FLAGS_TO_COPY \
        (SIP_PROMISCREDIR | SIP_TRUSTRPID | SIP_SENDRPID | SIP_DTMF | SIP_REINVITE | \
-        SIP_PROG_INBAND | SIP_OSPAUTH | SIP_USECLIENTCODE | SIP_NAT | \
+        SIP_PROG_INBAND | SIP_USECLIENTCODE | SIP_NAT | \
         SIP_USEREQPHONE | SIP_INSECURE_PORT | SIP_INSECURE_INVITE)
 
 /* a new page of flags for peers */
@@ -721,11 +710,6 @@ static struct sip_pvt {
        char lastmsg[256];                      /*!< Last Message sent/received */
        int amaflags;                           /*!< AMA Flags */
        int pendinginvite;                      /*!< Any pending invite */
-#ifdef OSP_SUPPORT
-       int osphandle;                          /*!< OSP Handle for call */
-       time_t ospstart;                        /*!< OSP Start time */
-       unsigned int osptimelimit;              /*!< OSP call duration limit */
-#endif
        struct sip_request initreq;             /*!< Initial request that opened the SIP dialog */
        
        int maxtime;                            /*!< Max time for first response */
@@ -2066,9 +2050,6 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
 {
        int res;
        struct sip_pvt *p;
-#ifdef OSP_SUPPORT
-       const char *osphandle = NULL;
-#endif 
        struct varshead *headp;
        struct ast_var_t *current;
        
@@ -2093,29 +2074,10 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
                        /* Check whether there is a variable with a name starting with SIPADDHEADER */
                        p->options->addsipheaders = 1;
                }
-
-               
-#ifdef OSP_SUPPORT
-               else if (!p->options->osptoken && !strcasecmp(ast_var_name(current), "OSPTOKEN")) {
-                       p->options->osptoken = ast_var_value(current);
-               } else if (!osphandle && !strcasecmp(ast_var_name(current), "OSPHANDLE")) {
-                       osphandle = ast_var_value(current);
-               }
-#endif
        }
        
        res = 0;
        ast_set_flag(&p->flags[0], SIP_OUTGOING);
-#ifdef OSP_SUPPORT
-       if (!p->options->osptoken || !osphandle || (sscanf(osphandle, "%d", &p->osphandle) != 1)) {
-               /* Force Disable OSP support */
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Disabling OSP support for this call. osptoken = %s, osphandle = %s\n", p->options->osptoken, osphandle);
-               p->options->osptoken = NULL;
-               osphandle = NULL;
-               p->osphandle = -1;
-       }
-#endif
        ast_log(LOG_DEBUG, "Outgoing Call for %s\n", p->username);
        res = update_call_counter(p, INC_CALL_LIMIT);
        if ( res != -1 ) {
@@ -2530,11 +2492,6 @@ static int sip_hangup(struct ast_channel *ast)
                ast_log(LOG_DEBUG, "Hangup call %s, SIP callid %s)\n", ast->name, p->callid);
 
        ast_mutex_lock(&p->lock);
-#ifdef OSP_SUPPORT
-       if ((p->osphandle > -1) && (ast->_state == AST_STATE_UP)) {
-               ast_osp_terminate(p->osphandle, AST_CAUSE_NORMAL, p->ospstart, time(NULL) - p->ospstart);
-       }
-#endif 
        if (option_debug && sipdebug)
                ast_log(LOG_DEBUG, "update_call_counter(%s) - decrement call limit counter on hangup\n", p->username);
        update_call_counter(p, DEC_CALL_LIMIT);
@@ -2638,9 +2595,6 @@ static int sip_answer(struct ast_channel *ast)
 
        ast_mutex_lock(&p->lock);
        if (ast->_state != AST_STATE_UP) {
-#ifdef OSP_SUPPORT     
-               time(&p->ospstart);
-#endif
                try_suggested_sip_codec(p);     
 
                ast_setstate(ast, AST_STATE_UP);
@@ -2868,10 +2822,6 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
        struct ast_variable *v = NULL;
        int fmt;
        int what;
-#ifdef OSP_SUPPORT
-       char iabuf[INET_ADDRSTRLEN];
-       char peer[MAXHOSTNAMELEN];
-#endif 
        
        ast_mutex_unlock(&i->lock);
        /* Don't hold a sip pvt lock while we allocate a channel */
@@ -2961,10 +2911,6 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
        if (!ast_strlen_zero(i->callid)) {
                pbx_builtin_setvar_helper(tmp, "SIPCALLID", i->callid);
        }
-#ifdef OSP_SUPPORT
-       snprintf(peer, sizeof(peer), "[%s]:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), i->sa.sin_addr), ntohs(i->sa.sin_port));
-       pbx_builtin_setvar_helper(tmp, "OSPPEER", peer);
-#endif
        ast_setstate(tmp, state);
        if (state != AST_STATE_DOWN) {
                if (ast_pbx_start(tmp)) {
@@ -3212,10 +3158,6 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
 
        if (intended_method != SIP_OPTIONS)     /* Peerpoke has it's own system */
                p->timer_t1 = 500;      /* Default SIP retransmission timer T1 (RFC 3261) */
-#ifdef OSP_SUPPORT
-       p->osphandle = -1;
-       p->osptimelimit = 0;
-#endif 
        if (sin) {
                p->sa = *sin;
                if (ast_sip_ouraddrfor(&p->sa.sin_addr,&p->ourip))
@@ -5076,12 +5018,6 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init)
                if (!ast_strlen_zero(p->referred_by))
                        add_header(&req, "Referred-By", p->referred_by);
        }
-#ifdef OSP_SUPPORT
-       if ((req.method != SIP_OPTIONS) && p->options && !ast_strlen_zero(p->options->osptoken)) {
-               ast_log(LOG_DEBUG,"Adding OSP Token: %s\n", p->options->osptoken);
-               add_header(&req, "P-OSP-Auth-Token", p->options->osptoken);
-       }
-#endif
        if (p->options && !ast_strlen_zero(p->options->distinctive_ring))
        {
                add_header(&req, "Alert-Info", p->options->distinctive_ring);
@@ -6286,21 +6222,6 @@ static void build_route(struct sip_pvt *p, struct sip_request *req, int backward
                list_route(p->route);
 }
 
-#ifdef OSP_SUPPORT
-/*! \brief Validate OSP token for user authorization */
-static int check_osptoken (struct sip_pvt *p, char *token)
-{
-       char tmp[80];
-
-       if (ast_osp_validate (NULL, token, &p->osphandle, &p->osptimelimit, p->cid_num, p->sa.sin_addr, p->exten) < 1) {
-               return -1;
-       } else {
-               snprintf (tmp, sizeof (tmp), "%d", p->osphandle);
-               pbx_builtin_setvar_helper (p->owner, "_OSPHANDLE", tmp);
-               return 0;
-       }
-}
-#endif
 
 /*! \brief  Check user authorization from peer definition 
        Some actions, like REGISTER and INVITEs from peers require
@@ -6318,12 +6239,7 @@ static int check_auth(struct sip_pvt *p, struct sip_request *req, const char *us
        const char *authtoken;
 
        /* Always OK if no secret */
-       if (ast_strlen_zero(secret) && ast_strlen_zero(md5secret)
-#ifdef OSP_SUPPORT
-           && !ast_test_flag(&p->flags[0], SIP_OSPAUTH)
-           && global_allowguest != 2
-#endif
-               )
+       if (ast_strlen_zero(secret) && ast_strlen_zero(md5secret))
                return 0;
        if (sipmethod == SIP_REGISTER || sipmethod == SIP_SUBSCRIBE) {
                /* On a REGISTER, we have to use 401 and its family of headers instead of 407 and its family
@@ -6333,38 +6249,6 @@ static int check_auth(struct sip_pvt *p, struct sip_request *req, const char *us
                reqheader = "Authorization";
                respheader = "WWW-Authenticate";
        }
-#ifdef OSP_SUPPORT
-       else {
-               char *osptoken;
-               if (option_debug)
-                       ast_log (LOG_DEBUG, "Checking OSP Authentication!\n");
-               osptoken = get_header (req, "P-OSP-Auth-Token");
-               switch (ast_test_flag(&p->flags[0], SIP_OSPAUTH)) {
-                       case SIP_OSPAUTH_NO:
-                               break;
-                       case SIP_OSPAUTH_GATEWAY:
-                               if (ast_strlen_zero(osptoken)) {
-                                       if (ast_strlen_zero(secret) && ast_strlen_zero (md5secret))
-                                               return 0;
-                               } else {
-                                       return check_osptoken(p, osptoken);
-                               }
-                               break;
-                       case SIP_OSPAUTH_PROXY:
-                               if (ast_strlen_zero(osptoken))
-                                       return 0;
-                               return check_osptoken(p, osptoken);
-                               break;
-                       case SIP_OSPAUTH_EXCLUSIVE:
-                               if (ast_strlen_zero(osptoken))
-                                       return -1;
-                               return check_osptoken(p, osptoken);
-                               break;
-                       default:
-                               return -1;
-               }
-       }
-#endif 
        authtoken =  get_header(req, reqheader);        
        if (ignore && !ast_strlen_zero(p->randdata) && ast_strlen_zero(authtoken)) {
                /* This is a retransmitted invite/register/etc, don't reconstruct authentication
@@ -7447,12 +7331,6 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, int sipme
                        /* do we allow guests? */
                        if (!global_allowguest)
                                res = -1;  /* we don't want any guests, authentication will fail */
-#ifdef OSP_SUPPORT                     
-                       else if (global_allowguest == 2) {
-                               ast_copy_flags(&p->flags[0], &global_flags[0], SIP_OSPAUTH);
-                               res = check_auth(p, req, "", "", "", sipmethod, uri, reliable, ignore); 
-                       }
-#endif
                }
 
        }
@@ -8456,11 +8334,6 @@ static int sip_show_settings(int fd, int argc, char *argv[])
        ast_cli(fd, "  IP ToS SIP:             %s\n", ast_tos2str(global_tos_sip));
        ast_cli(fd, "  IP ToS RTP audio:       %s\n", ast_tos2str(global_tos_audio));
        ast_cli(fd, "  IP ToS RTP video:       %s\n", ast_tos2str(global_tos_video));
-#ifdef OSP_SUPPORT
-       ast_cli(fd, "  OSP Support:            Yes\n");
-#else
-       ast_cli(fd, "  OSP Support:            No\n");
-#endif
        if (!realtimepeers && !realtimeusers)
                ast_cli(fd, "  SIP realtime:           Disabled\n" );
        else
@@ -9777,9 +9650,6 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
                
                if (!ignore && p->owner) {
                        if (p->owner->_state != AST_STATE_UP) {
-#ifdef OSP_SUPPORT     
-                               time(&p->ospstart);
-#endif
                                ast_queue_control(p->owner, AST_CONTROL_ANSWER);
                        } else {        /* RE-invite */
                                ast_queue_frame(p->owner, &ast_null_frame);
@@ -10926,9 +10796,6 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
        if (!ignore && p)
                p->lastinvite = seqno;
        if (c) {
-#ifdef OSP_SUPPORT
-               ast_channel_setwhentohangup (c, p->osptimelimit);
-#endif
                switch(c->_state) {
                case AST_STATE_DOWN:
                        transmit_response(p, "100 Trying", req);
@@ -12281,26 +12148,10 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask
                else if (strcasecmp(v->value, "never"))
                        ast_set_flag(&flags[0], SIP_PROG_INBAND_NO);
        } else if (!strcasecmp(v->name, "allowguest")) {
-#ifdef OSP_SUPPORT
-               if (!strcasecmp(v->value, "osp"))
-                       global_allowguest = 2;
-               else 
-#endif
                        if (ast_true(v->value)) 
                                global_allowguest = 1;
                        else
                                global_allowguest = 0;
-#ifdef OSP_SUPPORT
-       } else if (!strcasecmp(v->name, "ospauth")) {
-               ast_set_flag(&mask[0], SIP_OSPAUTH);
-               ast_clear_flag(&flags[0], SIP_OSPAUTH);
-               if (!strcasecmp(v->value, "proxy"))
-                       ast_set_flag(&flags[0], SIP_OSPAUTH_PROXY);
-               else if (!strcasecmp(v->value, "gateway"))
-                       ast_set_flag(&flags[0], SIP_OSPAUTH_GATEWAY);
-               else if(!strcasecmp (v->value, "exclusive"))
-                       ast_set_flag(&flags[0], SIP_OSPAUTH_EXCLUSIVE);
-#endif
        } else if (!strcasecmp(v->name, "promiscredir")) {
                ast_set_flag(&mask[0], SIP_PROMISCREDIR);
                ast_set2_flag(&flags[0], ast_true(v->value), SIP_PROMISCREDIR);
index e7e0403..7554571 100644 (file)
 ; Set the "source" for requesting authorization
 ;
 ;source=foo
+;
+; Set the authentication policy.  
+; 0 - NO 
+; 1 - YES
+; 2 - EXCLUSIVE
+; Default is 1, validate token but allow no token.
+;
+;authpolicy=1
index 3b3a742..d2befa3 100644 (file)
@@ -612,6 +612,7 @@ ${DBGETSTATUS}                      * dbget()
 ${ENUMSTATUS}                  * enumlookup()
 ${HASVMSTATUS}                 * hasnewvoicemail()
 ${LOOKUPBLSTATUS}              * lookupblacklist()
+${OSPAUTHSTATUS}               * ospauth()
 ${OSPLOOKUPSTATUS}             * osplookup()
 ${OSPNEXTSTATUS}               * ospnext()
 ${OSPFINISHSTATUS}             * ospfinish()
@@ -754,14 +755,17 @@ ${MACRO_CONTEXT}  * The calling context
 ${MACRO_PRIORITY}      * The calling priority
 ${MACRO_OFFSET}                Offset to add to priority at return from macro
 
-If you compile with OSP support in the SIP channel, these
-variables are used:
+If you compile with OSP support, these variables are used:
 ---------------------------------------------------------
-${OSPHANDLE}           Handle from the OSP Library
-${OSPTECH}             OSP Technology from Library
-${OSPDEST}             OSP Destination from Library
-${OSPTOKEN}            OSP Token to use for call from Library
-${OSPRESULTS}          Number of OSP results
+${OSPINHANDLE}         OSP handle of in_bound call
+${OSPINTIMELIMIT}      Duration limit for in_bound call
+${OSPOUTHANDLE}                OSP handle of out_bound call
+${OSPTECH}                     OSP technology 
+${OSPDEST}                     OSP destination
+${OSPCALLING}          OSP calling number
+${OSPOUTTOKEN}         OSP token to use for out_bound call
+${OSPOUTTIMELIMIT}     Duration limit for out_bound call
+${OSPRESULTS}          Number of remained destinations
 
 ____________________________________
 CDR Variables
index 9781ca6..b7ef465 100644 (file)
  * at the top of the source tree.
  */
 
-/*! \file
+/*! 
+ * \file
  * \brief OSP support (Open Settlement Protocol)
  */
 
 #ifndef _ASTERISK_OSP_H
 #define _ASTERISK_OSP_H
 
-#include "asterisk/channel.h"
-#include <netinet/in.h>
 #include <time.h>
+#include <netinet/in.h>
 
-struct ast_osp_result {
-       int handle;
-       int numresults;
-       char tech[20];
-       char dest[256];
-       char token[4096];
-};
+#include "asterisk/channel.h"
 
-/* Note: Channel will be auto-serviced if specified.  Returns -1 on hangup, 
-   0 if nothing found, or 1 if something is found */
-int ast_osp_lookup(struct ast_channel *chan, char *provider, char *extension, char *callerid, struct ast_osp_result *result);
+#define OSP_DEF_PROVIDER       ((char*)"default")              /* Default provider context name */
+#define OSP_INVALID_HANDLE     ((int)-1)                               /* Invalid OSP handle, provider, transaction etc. */
+#define OSP_DEF_TIMELIMIT      ((unsigned int)0)               /* Default duration limit, no limit */
 
-int ast_osp_next(struct ast_osp_result *result, int cause);
+#define OSP_INTSTR_SIZE                ((unsigned int)16)              /* Signed/unsigned int string buffer size */
+#define OSP_NORSTR_SIZE                ((unsigned int)256)             /* Normal string buffer size */
+#define OSP_TOKSTR_SIZE                ((unsigned int)4096)    /* Token string buffer size */
 
-int ast_osp_terminate(int handle, int cause, time_t start, time_t duration);
+#define OSP_APP_SUCCESS                ((char*)"SUCCESS")              /* Return status, success */
+#define OSP_APP_FAILED         ((char*)"FAILED")               /* Return status, failed */
+#define OSP_APP_ERROR          ((char*)"ERROR")                /* Return status, error */
 
-int ast_osp_validate(char *provider, char *token, int *handle, unsigned int *timeout, const char *callerid, struct in_addr addr, const char *extension);
+struct ast_osp_result {
+       int inhandle;
+       int outhandle;
+       unsigned int intimelimit;
+       unsigned int outtimelimit;
+       char tech[20];
+       char dest[OSP_NORSTR_SIZE];
+       char calling[OSP_NORSTR_SIZE];
+       char token[OSP_TOKSTR_SIZE];
+       int numresults;
+};
+
+/*!
+ * \brief OSP Increase Use Count function
+ */
+void ast_osp_adduse(void);
+/*!
+ * \brief OSP Decrease Use Count function
+ */
+void ast_osp_deluse(void);
+/*!
+ * \brief OSP Authentication function
+ * \param provider OSP provider context name
+ * \param transaction OSP transaction handle, output
+ * \param source Source of in_bound call
+ * \param calling Calling number
+ * \param called Called number
+ * \param token OSP token, may be empty
+ * \param timelimit Call duration limit, output
+ * \return 1 Authenricated, 0 Unauthenticated, -1 Error
+ */
+int ast_osp_auth(
+       const char* provider,           /* OSP provider context name */
+       int* transaction,                       /* OSP transaction handle, output */
+       const char* source,                     /* Source of in_bound call */
+       const char* calling,            /* Calling number */
+       const char* called,                     /* Called number */
+       const char* token,                      /* OSP token, may be empty */
+       unsigned int* timelimit         /* Call duration limit, output */
+);
+/*!
+ * \brief OSP Lookup function
+ * \param provider OSP provider context name
+ * \param srcdev Source device of out_bound call
+ * \param calling Calling number
+ * \param called Called number
+ * \param result Lookup results
+ * \return 1 Found , 0 No route, -1 Error
+ */
+int ast_osp_lookup(
+       const char* provider,                   /* OSP provider conttext name */
+       const char* srcdev,                             /* Source device of out_bound call */
+       const char* calling,                    /* Calling number */
+       const char* called,                             /* Called number */
+       struct ast_osp_result* result   /* OSP lookup results, in/output */
+);
+/*!
+ * \brief OSP Next function
+ * \param reason Last destination failure reason
+ * \param result Lookup results, in/output
+ * \return 1 Found , 0 No route, -1 Error
+ */
+int ast_osp_next(
+       int reason,                                             /* Last destination failure reason */
+       struct ast_osp_result *result   /* OSP lookup results, in/output */
+);
+/*!
+ * \brief OSP Finish function
+ * \param handle OSP in/out_bound transaction handle
+ * \param reason Last destination failure reason
+ * \param start Call start time
+ * \param duration Call duration
+ * \return 1 Success, 0 Failed, -1 Error
+ */
+int ast_osp_finish(
+       int handle,                                             /* OSP in/out_bound transaction handle */
+       int reason,                                             /* Last destination failure reason */
+       time_t start,                                   /* Call start time */
+       time_t connect,                                 /* Call connect time */
+       time_t end                                              /* Call end time */
+);
 
 #endif /* _ASTERISK_OSP_H */
index 65b6a57..43cb403 100644 (file)
  * at the top of the source tree.
  */
 
-/*! \file
- *
+/*! 
+ * \file
  * \brief Provide Open Settlement Protocol capability
  *
  * \author Mark Spencer <markster@digium.com>
  *
- * \arg See also: \ref chan_sip.c
+ * \arg See also: \ref app_osplookup.c
  */
 
 #include <sys/types.h>
 #include <osp.h>
+#include <osputils.h>
 #include <openssl/err.h>
 #include <stdio.h>
 #include <dirent.h>
@@ -61,809 +62,1042 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/callerid.h"
 #include "asterisk/pbx.h"
 
-#define MAX_CERTS 10
-#define MAX_SERVICEPOINTS 10
-#define OSP_MAX 256
-
-#define OSP_DEFAULT_MAX_CONNECTIONS    20
-#define OSP_DEFAULT_RETRY_DELAY                0
-#define OSP_DEFAULT_RETRY_LIMIT                2
-#define OSP_DEFAULT_TIMEOUT                    500
-
-static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len);
-static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len);
-
-AST_MUTEX_DEFINE_STATIC(osplock);
+/* OSP Authentication Policy */
+enum osp_authpolicy {
+       OSP_AUTH_NO,
+       OSP_AUTH_YES,
+       OSP_AUTH_EXCLUSIVE
+};
 
-static int initialized = 0;
-static int hardware = 0;
-static unsigned tokenformat = TOKEN_ALGO_SIGNED;
+#define OSP_CONFIG_FILE                        ((char*)"osp.conf")
+#define OSP_GENERAL_CAT                        ((char*)"general")
+#define OSP_MAX_CERTS                  ((unsigned int)10)
+#define OSP_MAX_SRVS                   ((unsigned int)10)
+#define OSP_DEF_MAXCONNECTIONS ((unsigned int)20)
+#define OSP_MIN_MAXCONNECTIONS ((unsigned int)1)
+#define OSP_MAX_MAXCONNECTIONS ((unsigned int)1000)
+#define OSP_DEF_RETRYDELAY             ((unsigned int)0)
+#define OSP_MIN_RETRYDELAY             ((unsigned int)0)
+#define OSP_MAX_RETRYDELAY             ((unsigned int)10)
+#define OSP_DEF_RETRYLIMIT             ((unsigned int)2)
+#define OSP_MIN_RETRYLIMIT             ((unsigned int)0)
+#define OSP_MAX_RETRYLIMIT             ((unsigned int)100)
+#define OSP_DEF_TIMEOUT                        ((unsigned int)500)
+#define OSP_MIN_TIMEOUT                        ((unsigned int)200)
+#define OSP_MAX_TIMEOUT                        ((unsigned int)10000)
+#define OSP_DEF_AUTHPOLICY             ((enum osp_authpolicy)OSP_AUTH_YES)
+#define OSP_AUDIT_URL                  ((char*)"localhost")
+#define OSP_LOCAL_VALIDATION   ((int)1)
+#define OSP_SSL_LIFETIME               ((unsigned int)300)
+#define OSP_HTTP_PERSISTENCE   ((int)1)
+#define OSP_CUSTOMER_ID                        ((char*)"")
+#define OSP_DEVICE_ID                  ((char*)"")
+#define OSP_DEF_DESTINATIONS   ((unsigned int)5)
 
 struct osp_provider {
-       char name[OSP_MAX];
-       char localpvtkey[OSP_MAX];
-       char localcert[OSP_MAX];
-       char cacerts[MAX_CERTS][OSP_MAX]; 
-       int cacount;
-       char servicepoints[MAX_SERVICEPOINTS][OSP_MAX];
-       char source[OSP_MAX];
-       int spcount;
-       int dead;
+       char name[OSP_NORSTR_SIZE];
+       char privatekey[OSP_NORSTR_SIZE];
+       char localcert[OSP_NORSTR_SIZE];
+       unsigned int cacount;
+       char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE]; 
+       unsigned int spcount;
+       char srvpoints[OSP_MAX_SRVS][OSP_NORSTR_SIZE];
        int maxconnections;
        int retrydelay;
        int retrylimit;
        int timeout;
+       char source[OSP_NORSTR_SIZE];
+       enum osp_authpolicy authpolicy;
        OSPTPROVHANDLE handle;
        struct osp_provider *next;
 };
-static struct osp_provider *providers;
 
-static int osp_build(struct ast_config *cfg, char *cat)
+AST_MUTEX_DEFINE_STATIC(osplock);
+static unsigned int osp_usecount = 0;
+static int osp_initialized = 0;
+static int osp_hardware = 0;
+static struct osp_provider* ospproviders = NULL;
+static unsigned int osp_tokenformat = TOKEN_ALGO_SIGNED;
+
+static int osp_buildProvider(
+       struct ast_config* cfg,         /* OSP configuration */
+       char* provider);                        /* OSP provider context name */
+static int osp_getPolicy(
+       const char* provider,           /* OSP provider context name */
+       int* policy);                           /* OSP authentication policy, output */
+static int osp_genTransaction(
+       const char* provider,           /* OSP provider context name */
+       int* transaction,                       /* OSP transaction handle, output */
+       unsigned int sourcesize,        /* Size of source buffer, in/output */
+       char* source);                          /* Source of provider context, output */
+static int osp_valToken(
+       int transaction,                        /* OSP transaction handle */
+       const char* source,                     /* Source of in_bound call */
+       const char* dest,                       /* Destination of in_bound call */
+       const char* calling,            /* Calling number */
+       const char* called,                     /* Called number */
+       const char* token,                      /* OSP token, may be empty */
+       unsigned int* timelimit);       /* Call duration limit, output */
+static unsigned int osp_choTimelimit(
+       unsigned int in,                        /* In_bound OSP timelimit */
+       unsigned int out);                      /* Out_bound OSP timelimit */
+static enum OSPEFAILREASON reason2cause(
+       int reason);                            /* Last call failure reason */
+static int osp_chkDest(
+       const char* callednum,                  /* Called number */
+       const char* callingnum,                 /* Calling number */
+       char* destination,                              /* Destination IP in OSP format */
+       unsigned int tokenlen,                  /* OSP token length */
+       const char* token,                              /* OSP token */
+       enum OSPEFAILREASON* cause,             /* Failure cause, output */
+       struct ast_osp_result* result); /* OSP lookup results, in/output */
+
+static int osp_load(void);
+static int osp_unload(void);
+static int osp_show(int fd, int argc, char *argv[]);
+
+static int osp_buildProvider(
+       struct ast_config *cfg,         /* OSP configuration */
+       char* provider)                         /* OSP provider context name */
 {
-       OSPTCERT TheAuthCert[MAX_CERTS];
-       unsigned char Reqbuf[4096],LocalBuf[4096],AuthBuf[MAX_CERTS][4096];
-       struct ast_variable *v;
-       struct osp_provider *osp;
-       int x,length,errorcode=0;
-       int mallocd=0,i;
-       char *cacerts[MAX_CERTS];
-       const char *servicepoints[MAX_SERVICEPOINTS];
+       int res;
+       unsigned int t, i, j;
+       struct osp_provider* p;
+       struct ast_variable* v;
        OSPTPRIVATEKEY privatekey;
        OSPTCERT localcert;
-       OSPTCERT *authCerts[MAX_CERTS];
+       const char* psrvpoints[OSP_MAX_SRVS];
+       OSPTCERT cacerts[OSP_MAX_CERTS];
+       const OSPTCERT* pcacerts[OSP_MAX_CERTS];
+       int error = OSPC_ERR_NO_ERROR;
 
-       
-       
-       ast_mutex_lock(&osplock);
-       osp = providers;
-       while(osp) {
-               if (!strcasecmp(osp->name, cat))
-                       break;
-               osp = osp->next;
+       p = ast_calloc(1, sizeof(*p));
+       if (!p) {
+               ast_log(LOG_ERROR, "Out of memory\n");
+               return(-1);
        }
-       ast_mutex_unlock(&osplock);
-       if (!osp) {
-               mallocd = 1;
-               if (!(osp = ast_calloc(1, sizeof(*osp)))) {
-                       return -1;
-               }
-               osp->handle = -1;
-       }
-       ast_copy_string(osp->name, cat, sizeof(osp->name));
-       snprintf(osp->localpvtkey, sizeof(osp->localpvtkey) ,"%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, cat);
-       snprintf(osp->localcert, sizeof(osp->localpvtkey), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, cat);
-       osp->maxconnections=OSP_DEFAULT_MAX_CONNECTIONS;
-       osp->retrydelay = OSP_DEFAULT_RETRY_DELAY;
-       osp->retrylimit = OSP_DEFAULT_RETRY_LIMIT;
-       osp->timeout = OSP_DEFAULT_TIMEOUT;
-       osp->source[0] = '\0';
-       ast_log(LOG_DEBUG, "Building OSP Provider '%s'\n", cat);
-       v = ast_variable_browse(cfg, cat);
+
+       ast_copy_string(p->name, provider, sizeof(p->name));
+       p->handle = OSP_INVALID_HANDLE;
+       snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, provider);
+       snprintf(p->localcert, sizeof(p->localcert), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, provider);
+       p->maxconnections = OSP_DEF_MAXCONNECTIONS;
+       p->retrydelay = OSP_DEF_RETRYDELAY;
+       p->retrylimit = OSP_DEF_RETRYLIMIT;
+       p->timeout = OSP_DEF_TIMEOUT;
+       p->authpolicy = OSP_DEF_AUTHPOLICY;
+
+       v = ast_variable_browse(cfg, provider);
        while(v) {
                if (!strcasecmp(v->name, "privatekey")) {
-                       if (v->value[0] == '/')
-                               ast_copy_string(osp->localpvtkey, v->value, sizeof(osp->localpvtkey));
-                       else
-                               snprintf(osp->localpvtkey, sizeof(osp->localpvtkey), "%s/%s", ast_config_AST_KEY_DIR , v->value);
+                       if (v->value[0] == '/') {
+                               ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey));
+                       } else {
+                               snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value);
+                       }
+                       ast_log(LOG_DEBUG, "OSP: privatekey '%s'\n", p->privatekey);
                } else if (!strcasecmp(v->name, "localcert")) {
-                       if (v->value[0] == '/')
-                               ast_copy_string(osp->localcert, v->value, sizeof(osp->localcert));
-                       else
-                               snprintf(osp->localcert, sizeof(osp->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
+                       if (v->value[0] == '/') {
+                               ast_copy_string(p->localcert, v->value, sizeof(p->localcert));
+                       } else {
+                               snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
+                       }
+                       ast_log(LOG_DEBUG, "OSP: localcert '%s'\n", p->localcert);
                } else if (!strcasecmp(v->name, "cacert")) {
-                       if (osp->cacount < MAX_CERTS) {
-                               if (v->value[0] == '/')
-                                       ast_copy_string(osp->cacerts[osp->cacount], v->value, sizeof(osp->cacerts[0]));
-                               else
-                                       snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
-                               osp->cacount++;
-                       } else
-                               ast_log(LOG_WARNING, "Too many CA Certificates at line %d\n", v->lineno);
+                       if (p->cacount < OSP_MAX_CERTS) {
+                               if (v->value[0] == '/') {
+                                       ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0]));
+                               } else {
+                                       snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
+                               }
+                               ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
+                               p->cacount++;
+                       } else {
+                               ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno);
+                       }
                } else if (!strcasecmp(v->name, "servicepoint")) {
-                       if (osp->spcount < MAX_SERVICEPOINTS) {
-                               ast_copy_string(osp->servicepoints[osp->spcount], v->value, sizeof(osp->servicepoints[0]));
-                               osp->spcount++;
-                       } else
-                               ast_log(LOG_WARNING, "Too many Service points at line %d\n", v->lineno);
+                       if (p->spcount < OSP_MAX_SRVS) {
+                               ast_copy_string(p->srvpoints[p->spcount], v->value, sizeof(p->srvpoints[0]));
+                               ast_log(LOG_DEBUG, "OSP: servicepoint[%d]: '%s'\n", p->spcount, p->srvpoints[p->spcount]);
+                               p->spcount++;
+                       } else {
+                               ast_log(LOG_WARNING, "OSP: Too many Service Points at line %d\n", v->lineno);
+                       }
                } else if (!strcasecmp(v->name, "maxconnections")) {
-                       if ((sscanf(v->value, "%d", &x) == 1) && (x > 0) && (x <= 1000)) {
-                               osp->maxconnections = x;
-                       } else
-                               ast_log(LOG_WARNING, "maxconnections should be an integer from 1 to 1000, not '%s' at line %d\n", v->value, v->lineno);
+                       if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_MAXCONNECTIONS) && (t <= OSP_MAX_MAXCONNECTIONS)) {
+                               p->maxconnections = t;
+                               ast_log(LOG_DEBUG, "OSP: maxconnections '%d'\n", t);
+                       } else {
+                               ast_log(LOG_WARNING, "OSP: maxconnections should be an integer from %d to %d, not '%s' at line %d\n", 
+                                       OSP_MIN_MAXCONNECTIONS, OSP_MAX_MAXCONNECTIONS, v->value, v->lineno);
+                       }
                } else if (!strcasecmp(v->name, "retrydelay")) {
-                       if ((sscanf(v->value, "%d", &x) == 1) && (x >= 0) && (x <= 10)) {
-                               osp->retrydelay = x;
-                       } else
-                               ast_log(LOG_WARNING, "retrydelay should be an integer from 0 to 10, not '%s' at line %d\n", v->value, v->lineno);
+                       if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYDELAY) && (t <= OSP_MAX_RETRYDELAY)) {
+                               p->retrydelay = t;
+                               ast_log(LOG_DEBUG, "OSP: retrydelay '%d'\n", t);
+                       } else {
+                               ast_log(LOG_WARNING, "OSP: retrydelay should be an integer from %d to %d, not '%s' at line %d\n", 
+                                       OSP_MIN_RETRYDELAY, OSP_MAX_RETRYDELAY, v->value, v->lineno);
+                       }
                } else if (!strcasecmp(v->name, "retrylimit")) {
-                       if ((sscanf(v->value, "%d", &x) == 1) && (x >= 0) && (x <= 100)) {
-                               osp->retrylimit = x;
-                       } else
-                               ast_log(LOG_WARNING, "retrylimit should be an integer from 0 to 100, not '%s' at line %d\n", v->value, v->lineno);
+                       if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYLIMIT) && (t <= OSP_MAX_RETRYLIMIT)) {
+                               p->retrylimit = t;
+                               ast_log(LOG_DEBUG, "OSP: retrylimit '%d'\n", t);
+                       } else {
+                               ast_log(LOG_WARNING, "OSP: retrylimit should be an integer from %d to %d, not '%s' at line %d\n", 
+                                       OSP_MIN_RETRYLIMIT, OSP_MAX_RETRYLIMIT, v->value, v->lineno);
+                       }
                } else if (!strcasecmp(v->name, "timeout")) {
-                       if ((sscanf(v->value, "%d", &x) == 1) && (x >= 200) && (x <= 10000)) {
-                               osp->timeout = x;
-                       } else
-                               ast_log(LOG_WARNING, "timeout should be an integer from 200 to 10000, not '%s' at line %d\n", v->value, v->lineno);
+                       if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_TIMEOUT) && (t <= OSP_MAX_TIMEOUT)) {
+                               p->timeout = t;
+                               ast_log(LOG_DEBUG, "OSP: timeout '%d'\n", t);
+                       } else {
+                               ast_log(LOG_WARNING, "OSP: timeout should be an integer from %d to %d, not '%s' at line %d\n", 
+                                       OSP_MIN_TIMEOUT, OSP_MAX_TIMEOUT, v->value, v->lineno);
+                       }
                } else if (!strcasecmp(v->name, "source")) {
-                       ast_copy_string(osp->source, v->value, sizeof(osp->source));
+                       ast_copy_string(p->source, v->value, sizeof(p->source));
+                       ast_log(LOG_DEBUG, "OSP: source '%s'\n", p->source);
+               } else if (!strcasecmp(v->name, "authpolicy")) {
+                       if ((sscanf(v->value, "%d", &t) == 1) && ((t == OSP_AUTH_NO) || (t == OSP_AUTH_YES) || (t == OSP_AUTH_EXCLUSIVE))) {
+                               p->authpolicy = t;
+                               ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", t);
+                       } else {
+                               ast_log(LOG_WARNING, "OSP: authpolicy should be %d, %d or %d, not '%s' at line %d\n", 
+                                       OSP_AUTH_NO, OSP_AUTH_YES, OSP_AUTH_EXCLUSIVE, v->value, v->lineno);
+                       }
                }
                v = v->next;
        }
-       if (osp->cacount < 1) {
-               snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, cat);
-               osp->cacount++;
+
+       error = OSPPUtilLoadPEMPrivateKey(p->privatekey, &privatekey);
+       if (error != OSPC_ERR_NO_ERROR) {
+               ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s'\n", p->privatekey);
+               free(p);
+               return(-1);
        }
-       for (x=0;x<osp->cacount;x++)
-               cacerts[x] = osp->cacerts[x];
-       for (x=0;x<osp->spcount;x++)
-               servicepoints[x] = osp->servicepoints[x];
-       
-       ast_mutex_lock(&osplock);
-       osp->dead = 0;
-       if (osp->handle > -1) {
-               ast_log(LOG_DEBUG, "Deleting old handle for '%s'\n", osp->name);
-               OSPPProviderDelete(osp->handle, 0);
-       }
-               
-
-    length = 0;
-       ast_log(LOG_DEBUG, "Loading private key for '%s' (%s)\n", osp->name, osp->localpvtkey);
-    errorcode = loadPemPrivateKey(osp->localpvtkey,Reqbuf,&length);
-    if (errorcode == 0)
-    {
-        privatekey.PrivateKeyData = Reqbuf;
-        privatekey.PrivateKeyLength = length;
-    }
-    else
-    {
-         return -1;
-    }
-
-    length = 0;
-       ast_log(LOG_DEBUG, "Loading local cert for '%s' (%s)\n", osp->name, osp->localcert);
-    errorcode = loadPemCert(osp->localcert,LocalBuf,&length);
-    if (errorcode == 0)
-    {
-        localcert.CertData = LocalBuf;
-        localcert.CertDataLength = length;
-    }
-    else
-    {
-         return -1;
-    }
-
-    for (i=0;i<osp->cacount;i++)
-    {
-        length = 0;
-               ast_log(LOG_DEBUG, "Loading CA cert %d for '%s' (%s)\n", i + 1, osp->name, osp->cacerts[i]);
-        errorcode = loadPemCert(osp->cacerts[i],AuthBuf[i],&length);
-        if (errorcode == 0)
-        {
-            TheAuthCert[i].CertData = AuthBuf[i];
-            TheAuthCert[i].CertDataLength = length;
-            authCerts[i] = &(TheAuthCert[i]);
-        }
-        else
-        {
-                       return -1;        
+
+       error = OSPPUtilLoadPEMCert(p->localcert, &localcert);
+       if (error != OSPC_ERR_NO_ERROR) {
+               ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s'\n", p->localcert);
+               if (privatekey.PrivateKeyData) {
+                       free(privatekey.PrivateKeyData);
                }
-    }
-       
-       ast_log(LOG_DEBUG, "Creating provider handle for '%s'\n", osp->name);
-       
-       ast_log(LOG_DEBUG, "Service point '%s %d'\n", servicepoints[0], osp->spcount);
-       
-       if (OSPPProviderNew(osp->spcount, 
-                                           servicepoints, 
-                                          NULL, 
-                                          "localhost", 
-                                          &privatekey, 
-                                          &localcert, 
-                                          osp->cacount, 
-                                          (const OSPTCERT **)authCerts, 
-                                          1, 
-                                          300, 
-                                          osp->maxconnections, 
-                                          1, 
-                                          osp->retrydelay, 
-                                          osp->retrylimit, 
-                                          osp->timeout, 
-                                          "", 
-                                          "", 
-                                          &osp->handle)) {
-               ast_log(LOG_WARNING, "Unable to initialize provider '%s'\n", cat);
-               osp->dead = 1;
+               free(p);
+               return(-1);
+       }
+
+       if (p->cacount < 1) {
+               snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, provider);
+               ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
+               p->cacount++;
+       }
+       for (i = 0; i < p->cacount; i++) {
+               error = OSPPUtilLoadPEMCert(p->cacerts[i], &cacerts[i]);
+               if (error != OSPC_ERR_NO_ERROR) {
+                       ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s'\n", p->cacerts[i]);
+                       for (j = 0; j < i; j++) {
+                               if (cacerts[j].CertData) {
+                                       free(cacerts[j].CertData);
+                               }
+                       }
+                       if (localcert.CertData) {
+                               free(localcert.CertData);
+                       }
+                       if (privatekey.PrivateKeyData) {
+                               free(privatekey.PrivateKeyData);
+                       }
+                       free(p);
+                       return(-1);
+               }
+               pcacerts[i] = &cacerts[i];
        }
        
-       if (mallocd) {
-               osp->next = providers;
-               providers = osp;
+       for (i = 0; i < p->spcount; i++) {
+               psrvpoints[i] = p->srvpoints[i];
        }
-       ast_mutex_unlock(&osplock);     
-       return 0;
-}
 
-static int show_osp(int fd, int argc, char *argv[])
-{
-       struct osp_provider *osp;
-       char *search = NULL;
-       int x;
-       int found = 0;
-       char *tokenalgo;
-
-       if ((argc < 2) || (argc > 3))
-               return RESULT_SHOWUSAGE;
-       if (argc > 2)
-               search = argv[2];
-       if (!search) {
-               switch (tokenformat) {
-                       case TOKEN_ALGO_BOTH:
-                               tokenalgo = "Both";
-                               break;
-                       case TOKEN_ALGO_UNSIGNED:
-                               tokenalgo = "Unsigned";
-                               break;
-                       case TOKEN_ALGO_SIGNED:
-                       default:
-                               tokenalgo = "Signed";
-                               break;
-               }
-               ast_cli(fd, "OSP: %s %s %s\n", initialized ? "Initialized" : "Uninitialized", hardware ? "Accelerated" : "Normal", tokenalgo);
+       error = OSPPProviderNew(
+               p->spcount, psrvpoints,
+               NULL,
+               OSP_AUDIT_URL,
+               &privatekey,
+               &localcert,
+               p->cacount, pcacerts,
+               OSP_LOCAL_VALIDATION,
+               OSP_SSL_LIFETIME,
+               p->maxconnections,
+               OSP_HTTP_PERSISTENCE,
+               p->retrydelay,
+               p->retrylimit,
+               p->timeout,
+               OSP_CUSTOMER_ID,
+               OSP_DEVICE_ID,
+               &p->handle);
+       if (error != OSPC_ERR_NO_ERROR) {
+               ast_log(LOG_WARNING, "OSP: Unable to initialize provider '%s'\n", provider);
+               free(p);
+               res = -1;
+       } else {
+               ast_log(LOG_DEBUG, "OSP: provider '%s'\n", provider);
+               ast_mutex_lock(&osplock);
+               p->next = ospproviders;
+               ospproviders = p;
+               ast_mutex_unlock(&osplock);     
+               res = 0;
        }
 
-       ast_mutex_lock(&osplock);
-       osp = providers;
-       while(osp) {
-               if (!search || !strcasecmp(osp->name, search)) {
-                       if (found)
-                               ast_cli(fd, "\n");
-                       ast_cli(fd, " == OSP Provider '%s' ==\n", osp->name);
-                       ast_cli(fd, "Local Private Key: %s\n", osp->localpvtkey);
-                       ast_cli(fd, "Local Certificate: %s\n", osp->localcert);
-                       for (x=0;x<osp->cacount;x++)
-                               ast_cli(fd, "CA Certificate %d:  %s\n", x + 1, osp->cacerts[x]);
-                       for (x=0;x<osp->spcount;x++)
-                               ast_cli(fd, "Service Point %d:   %s\n", x + 1, osp->servicepoints[x]);
-                       ast_cli(fd, "Max Connections:   %d\n", osp->maxconnections);
-                       ast_cli(fd, "Retry Delay:       %d seconds\n", osp->retrydelay);
-                       ast_cli(fd, "Retry Limit:       %d\n", osp->retrylimit);
-                       ast_cli(fd, "Timeout:           %d milliseconds\n", osp->timeout);
-                       ast_cli(fd, "Source:            %s\n", strlen(osp->source) ? osp->source : "<unspecified>");
-                       ast_cli(fd, "OSP Handle:        %d\n", osp->handle);
-                       found++;
+       for (i = 0; i < p->cacount; i++) {
+               if (cacerts[i].CertData) {
+                       free(cacerts[i].CertData);
                }
-               osp = osp->next;
        }
-       ast_mutex_unlock(&osplock);
-       if (!found) {
-               if (search) 
-                       ast_cli(fd, "Unable to find OSP provider '%s'\n", search);
-               else
-                       ast_cli(fd, "No OSP providers configured\n");
+       if (localcert.CertData) {
+               free(localcert.CertData);
+       }
+       if (privatekey.PrivateKeyData) {
+               free(privatekey.PrivateKeyData);
        }
-       return RESULT_SUCCESS;
-}
-
 
-/*----------------------------------------------*
- *               Loads the Certificate          *
- *----------------------------------------------*/
-static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len)
-{
-    int length = 0;
-    unsigned char *temp;
-    BIO *bioIn = NULL;
-    X509 *cert=NULL;
-    int retVal = OSPC_ERR_NO_ERROR;
-
-    temp = buffer;
-    bioIn = BIO_new_file((const char*)FileName,"r");
-    if (bioIn == NULL)
-    {
-               ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName);
-               return -1;
-    }
-    else
-    {
-        cert = PEM_read_bio_X509(bioIn,NULL,NULL,NULL);
-        if (cert == NULL)
-        {
-                       ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s \n",FileName);
-                       return -1;
-        }
-        else
-        {
-            length = i2d_X509(cert,&temp);
-            if (cert == 0)
-            {
-                               ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s, Length=0 \n",FileName);
-                               return -1;
-            }
-            else
-                       {
-               *len = length;
-            }
-        }
-    }
-
-    if (bioIn != NULL)
-    {
-        BIO_free(bioIn);
-    }
-
-    if (cert != NULL)
-    {
-        X509_free(cert);
-    }
-    return retVal;
+       return(res);
 }
 
-/*----------------------------------------------*
- *               Loads the Private Key          *
- *----------------------------------------------*/
-static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len)
+static int osp_getPolicy(
+       const char* provider,           /* OSP provider context name */
+       int* policy)                            /* OSP authentication policy, output */
 {
-    int length = 0;
-    unsigned char *temp;
-    BIO *bioIn = NULL;
-    RSA *pKey = NULL;
-    int retVal = OSPC_ERR_NO_ERROR;
-
-    temp = buffer;
-
-    bioIn = BIO_new_file((const char*)FileName,"r");
-    if (bioIn == NULL)
-    {
-               ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName);
-               return -1;
-    }
-    else
-    {
-        pKey = PEM_read_bio_RSAPrivateKey(bioIn,NULL,NULL,NULL);
-        if (pKey == NULL)
-        {
-                       ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s \n",FileName);
-                       return -1;
-        }
-        else
-        {
-            length = i2d_RSAPrivateKey(pKey,&temp);
-            if (length == 0)
-            {
-                               ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s, Length=0 \n",FileName);
-                               return -1;
-            }
-            else
-            {
-                *len = length;
-            }
-        }
-    }
-    if (bioIn != NULL)
-    {
-        BIO_free(bioIn);
-    }
-
-    if (pKey != NULL)
-    {
-       RSA_free(pKey);
-    }
-    return retVal;
+       int res = 0;
+       struct osp_provider* p;
+
+       ast_mutex_lock(&osplock);
+       p = ospproviders;
+       while(p) {
+               if (!strcasecmp(p->name, provider)) {
+                       *policy = p->authpolicy;
+                       ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", *policy);
+                       res = 1;
+                       break;
+               }
+               p = p->next;
+       }
+       ast_mutex_unlock(&osplock);
+
+       return(res);
 }
 
-int ast_osp_validate(char *provider, char *token, int *handle, unsigned int *timelimit, const char *callerid, struct in_addr addr, const char *extension)
+static int osp_genTransaction(
+       const char* provider,           /* OSP provider context name */
+       int* transaction,                       /* OSP transaction handle, output */
+       unsigned int sourcesize,        /* Size of source buffer, in/output */
+       char* source)                           /* Source of provider context, output */
 {
-       char tmp[256]="", *l, *n;
-       char iabuf[INET_ADDRSTRLEN];
-       char source[OSP_MAX] = ""; /* Same length as osp->source */
-       char *token2;
-       int tokenlen;
-       struct osp_provider *osp;
        int res = 0;
-       unsigned int authorised, dummy;
-
-       if (!provider || !strlen(provider))
-               provider = "default";
-
-       token2 = ast_strdupa(token);
-       if (!token2)
-               return -1;
-       tokenlen = ast_base64decode(token2, token, strlen(token));
-       *handle = -1;
-       if (!callerid)
-               callerid = "";
-       ast_copy_string(tmp, callerid, sizeof(tmp));
-       ast_callerid_parse(tmp, &n, &l);
-       if (!l)
-               l = "";
-       else {
-               ast_shrink_phone_number(l);
-               if (!ast_isphonenumber(l))
-                       l = "";
-       }
-       callerid = l;
+       struct osp_provider *p;
+       int error;
+
        ast_mutex_lock(&osplock);
-       ast_inet_ntoa(iabuf, sizeof(iabuf), addr);
-       osp = providers;
-       while(osp) {
-               if (!strcasecmp(osp->name, provider)) {
-                       if (OSPPTransactionNew(osp->handle, handle)) {
-                               ast_log(LOG_WARNING, "Unable to create OSP Transaction handle!\n");
-                       } else {
-                               ast_copy_string(source, osp->source, sizeof(source));
+       p = ospproviders;
+       while(p) {
+               if (!strcasecmp(p->name, provider)) {
+                       error = OSPPTransactionNew(p->handle, transaction);
+                       if (error == OSPC_ERR_NO_ERROR) {
+                               ast_log(LOG_DEBUG, "OSP: transaction '%d'\n", *transaction);
+                               ast_copy_string(source, p->source, sourcesize);
+                               ast_log(LOG_DEBUG, "OSP: source '%s'\n", source);
                                res = 1;
+                       } else {
+                               *transaction = OSP_INVALID_HANDLE;
+                               ast_log(LOG_WARNING, "OSP: Unable to create transaction handle\n");
+                               res = -1;
                        }
                        break;
                }
-               osp = osp->next;
+               p = p->next;
        }
        ast_mutex_unlock(&osplock);
-       if (res) {
-               res = 0;
-               dummy = 0;
-               if (!OSPPTransactionValidateAuthorisation(*handle, iabuf, source, NULL, NULL, 
-                       callerid, OSPC_E164, extension, OSPC_E164, 0, "", tokenlen, token2, &authorised, timelimit, &dummy, NULL, tokenformat)) {
-                       if (authorised) {
-                               ast_log(LOG_DEBUG, "Validated token for '%s' from '%s@%s'\n", extension, callerid, iabuf);
+
+       return(res);
+}
+
+static int osp_valToken(
+       int transaction,                        /* OSP transaction handle */
+       const char* source,                     /* Source of in_bound call */
+       const char* dest,                       /* Destination of in_bound call */
+       const char* calling,            /* Calling number */
+       const char* called,                     /* Called number */
+       const char* token,                      /* OSP token, may be empty */
+       unsigned int* timelimit)        /* Call duration limit, output */
+{
+       int res = 0;
+       char tokenstr[OSP_TOKSTR_SIZE];
+       int tokenlen;
+       unsigned int authorised;
+       unsigned int dummy = 0;
+       int error;
+
+       tokenlen = ast_base64decode(tokenstr, token, strlen(token));
+       error = OSPPTransactionValidateAuthorisation(
+               transaction, 
+               source, dest, NULL, NULL,
+               calling ? calling : "", OSPC_E164, 
+               called, OSPC_E164, 
+               0, NULL,
+               tokenlen, tokenstr, 
+               &authorised, 
+               timelimit, 
+               &dummy, NULL, 
+               osp_tokenformat); 
+       if (error == OSPC_ERR_NO_ERROR) {
+               if (authorised) {
+                       ast_log(LOG_DEBUG, "OSP: Authorised\n");
+                       res = 1;
+               }
+       }
+       return(res);
+}
+
+int ast_osp_auth(
+       const char* provider,           /* OSP provider context name */
+       int* transaction,                       /* OSP transaction handle, output */
+       const char* source,                     /* Source of in_bound call */
+       const char* calling,            /* Calling number */
+       const char* called,                     /* Called number */
+       const char* token,                      /* OSP token, may be empty */
+       unsigned int* timelimit)        /* Call duration limit, output */
+{
+       int res;
+       char dest[OSP_NORSTR_SIZE];
+       int policy = OSP_AUTH_YES;
+
+       *transaction = OSP_INVALID_HANDLE;
+       *timelimit = OSP_DEF_TIMELIMIT;
+
+       res = osp_getPolicy(provider, &policy);
+       if (!res) {
+               ast_log(LOG_WARNING, "OSP: Unabe to find authentication policy\n");
+               return(-1);
+       }
+
+       switch (policy) {
+               case OSP_AUTH_NO:
+                       res = 1;
+                       break;
+               case OSP_AUTH_EXCLUSIVE:
+                       if (ast_strlen_zero(token)) {
+                               res = 0;
+                       } else if ((res = osp_genTransaction(provider, transaction, sizeof(dest), dest)) <= 0) {
+                               *transaction = OSP_INVALID_HANDLE;
+                               ast_log(LOG_WARNING, "OSP: Unable to generate transaction handle\n");
+                               res = -1;
+                       } else {
+                               res = osp_valToken(*transaction, source, dest, calling, called, token, timelimit);
+                       }
+                       break;
+               case OSP_AUTH_YES:
+               default:
+                       if (ast_strlen_zero(token)) {
                                res = 1;
+                       } else if ((res = osp_genTransaction(provider, transaction, sizeof(dest), dest)) <= 0) {
+                               *transaction = OSP_INVALID_HANDLE;
+                               ast_log(LOG_WARNING, "OSP: Unable to generate transaction handle\n");
+                               res = -1;
+                       } else {
+                               res = osp_valToken(*transaction, source, dest, calling, called, token, timelimit);
                        }
-               }
+                       break;
+       }
+
+       if (!res) {
+               OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
+       }
+
+       return(res);    
+}
+
+static unsigned int osp_choTimelimit(
+       unsigned int in,                        /* In_bound OSP timelimit */
+       unsigned int out)                       /* Out_bound OSP timelimit */
+{
+       if (in == OSP_DEF_TIMELIMIT) {
+               return (out);
+       } else if (out == OSP_DEF_TIMELIMIT) {
+               return (in);
+       } else {
+               return(in < out ? in : out);
        }
-       return res;     
 }
 
-static int check_dest(struct ast_osp_result *result, char *token, int tokensize)
+static int osp_chkDest(
+       const char* callednum,                  /* Called number */
+       const char* callingnum,                 /* Calling number */
+       char* destination,                              /* Destination IP in OSP format */
+       unsigned int tokenlen,                  /* OSP token length */
+       const char* token,                              /* OSP token */
+       enum OSPEFAILREASON* cause,             /* Failure cause, output */
+       struct ast_osp_result* result)  /* OSP lookup results, in/output */
 {
+       int res = 0;
        OSPE_DEST_OSP_ENABLED enabled;
-       OSPE_DEST_PROT prot;
-       int res = 1;
+       OSPE_DEST_PROT protocol;
+       int error;
 
-       /* Check destination OSP version */
-       if (!OSPPTransactionIsDestOSPEnabled(result->handle, &enabled) && (enabled == OSPE_OSP_FALSE)) {
-               result->token[0] = 0;
+       if (strlen(destination) <= 2) {
+               *cause = OSPC_FAIL_INCOMPATIBLE_DEST;
        } else {
-               ast_base64encode(result->token, token, tokensize, sizeof(result->token) - 1);
-       }
-
-       /* Check destination protocol */
-       if (OSPPTransactionGetDestProtocol(result->handle, &prot)) {
-               prot = OSPE_DEST_PROT_UNDEFINED;
-       }
-       switch(prot) {
-       case OSPE_DEST_PROT_UNDEFINED:  /* Protocol is not configured, use SIP as default */
-       case OSPE_DEST_PROT_SIP:
-               ast_copy_string(result->tech, "SIP", sizeof(result->tech));
-               break;
-       case OSPE_DEST_PROT_H323_SETUP:
-               ast_copy_string(result->tech, "H323", sizeof(result->tech));
-               break;
-       case OSPE_DEST_PROT_IAX:
-               ast_copy_string(result->tech, "IAX", sizeof(result->tech));
-               break;
-       case OSPE_DEST_PROT_H323_LRQ:
-       case OSPE_DEST_PROT_UNKNOWN:
-       default:
-               ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot);
-               res = 0;
-       }
+               error = OSPPTransactionIsDestOSPEnabled(result->outhandle, &enabled);
+               if ((error == OSPC_ERR_NO_ERROR) && (enabled == OSPE_OSP_FALSE)) {
+                       result->token[0] = '\0';
+               } else {
+                       ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1);
+               }
 
-       return res;
+               error = OSPPTransactionGetDestProtocol(result->outhandle, &protocol);
+               if (error != OSPC_ERR_NO_ERROR) {
+                       *cause = OSPC_FAIL_PROTOCOL_ERROR; 
+               } else {
+                       res = 1;
+                       /* Strip leading and trailing brackets */
+                       destination[strlen(destination) - 1] = '\0';
+                       switch(protocol) {
+                               case OSPE_DEST_PROT_H323_SETUP:
+                                       ast_copy_string(result->tech, "H323", sizeof(result->tech));
+                                       ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
+                                       snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
+                                       ast_copy_string(result->calling, callingnum, sizeof(result->calling));
+                                       break;
+                               case OSPE_DEST_PROT_SIP:
+                                       ast_copy_string(result->tech, "SIP", sizeof(result->tech));
+                                       ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
+                                       snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
+                                       ast_copy_string(result->calling, callingnum, sizeof(result->calling));
+                                       break;
+                               case OSPE_DEST_PROT_IAX:
+                                       ast_copy_string(result->tech, "IAX", sizeof(result->tech));
+                                       ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
+                                       snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
+                                       ast_copy_string(result->calling, callingnum, sizeof(result->calling));
+                                       break;
+                               default:
+                                       ast_log(LOG_DEBUG, "OSP: Unknown protocol '%d'\n", protocol);
+                                       *cause = OSPC_FAIL_PROTOCOL_ERROR; 
+                                       res = 0;
+                       }
+               }
+       }
+       return(res);
 }
 
-int ast_osp_lookup(struct ast_channel *chan, char *provider, char *extension, char *callerid, struct ast_osp_result *result)
+int ast_osp_lookup(
+       const char* provider,                   /* OSP provider conttext name */
+       const char* srcdev,                             /* Source device of out_bound call */
+       const char* calling,                    /* Calling number */
+       const char* called,                             /* Called number */
+       struct ast_osp_result* result)  /* OSP lookup results, in/output */
 {
-       int cres;
-       int res = 0;
-       int counts;
-       int tokenlen;
-       unsigned int dummy=0;
-       unsigned int timelimit;
+       int res;
+       char source[OSP_NORSTR_SIZE];
        unsigned int callidlen;
-       char callidstr[OSPC_CALLID_MAXSIZE] = "";
-       struct osp_provider *osp;
-       char source[OSP_MAX] = ""; /* Same length as osp->source */
-       char callednum[2048]="";
-       char callingnum[2048]="";
-       char destination[2048]="";
-       char token[2000];
-       char tmp[256]="", *l, *n;
-       const char *devinfo = NULL;
-
-       result->handle = -1;
-       result->numresults = 0;
+       char callidstr[OSPC_CALLID_MAXSIZE];
+       char callingnum[OSP_NORSTR_SIZE];
+       char callednum[OSP_NORSTR_SIZE];
+       char destination[OSP_NORSTR_SIZE];
+       unsigned int tokenlen;
+       char token[OSP_TOKSTR_SIZE];
+       unsigned int dummy = 0;
+       enum OSPEFAILREASON cause;
+       int error;
+
+       result->outhandle = OSP_INVALID_HANDLE;
        result->tech[0] = '\0';
        result->dest[0] = '\0';
+       result->calling[0] = '\0';
        result->token[0] = '\0';
+       result->numresults = 0;
+       result->outtimelimit = OSP_DEF_TIMELIMIT;
 
-       if (!provider || !strlen(provider))
-               provider = "default";
-
-       if (!callerid)
-               callerid = "";
-       ast_copy_string(tmp, callerid, sizeof(tmp));
-       ast_callerid_parse(tmp, &n, &l);
-       if (!l)
-               l = "";
-       else {
-               ast_shrink_phone_number(l);
-               if (!ast_isphonenumber(l))
-                       l = "";
+       if ((res = osp_genTransaction(provider, &result->outhandle, sizeof(source), source)) <= 0) {
+               result->outhandle = OSP_INVALID_HANDLE;
+               if (result->inhandle != OSP_INVALID_HANDLE) {
+                       OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
+               }
+               ast_log(LOG_WARNING, "OSP: Unable to generate transaction handle\n");
+               return(-1);
        }
-       callerid = l;
 
-       if (chan) {
-               cres = ast_autoservice_start(chan);
-               if (cres < 0)
-                       return cres;
+       res = 0;
+       dummy = 0;
+       result->numresults = OSP_DEF_DESTINATIONS;
+       error = OSPPTransactionRequestAuthorisation(
+               result->outhandle, 
+               source, srcdev,
+               calling ? calling : "", OSPC_E164, 
+               called, OSPC_E164, 
+               NULL, 
+               0, NULL, 
+               NULL, 
+               &result->numresults, 
+               &dummy, NULL);
+       if (error != OSPC_ERR_NO_ERROR) {
+               result->numresults = 0;
+               OSPPTransactionRecordFailure(result->outhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
+               if (result->inhandle != OSP_INVALID_HANDLE) {
+                       OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
+               }
+               return(res);
        }
-       ast_mutex_lock(&osplock);
-       osp = providers;
-       while(osp) {
-               if (!strcasecmp(osp->name, provider)) {
-                       if (OSPPTransactionNew(osp->handle, &result->handle)) {
-                               ast_log(LOG_WARNING, "Unable to create OSP Transaction handle!\n");
-                       } else {
-                               ast_copy_string(source, osp->source, sizeof(source));
-                               res = 1;
-                       }
-                       break;
+
+       if (!result->numresults) {
+               result->numresults = 0;
+               OSPPTransactionRecordFailure(result->outhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
+               if (result->inhandle != OSP_INVALID_HANDLE) {
+                       OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
                }
-               osp = osp->next;
+               return(res);
        }
-       ast_mutex_unlock(&osplock);
-       if (res) {
-               res = 0;
-               /* No more than 10 back */
-               counts = 10;
-               dummy = 0;
-               devinfo = pbx_builtin_getvar_helper (chan, "OSPPEER");
-               if (!devinfo) {
-                       devinfo = "";
+
+       callidlen = sizeof(callidstr);
+       tokenlen = sizeof(token);
+       error = OSPPTransactionGetFirstDestination(
+               result->outhandle, 
+               0, NULL, NULL, 
+               &result->outtimelimit, 
+               &callidlen, callidstr,
+               sizeof(callednum), callednum, 
+               sizeof(callingnum), callingnum, 
+               sizeof(destination), destination, 
+               0, NULL, 
+               &tokenlen, token);
+       if (error != OSPC_ERR_NO_ERROR) {
+               result->token[0] = '\0';
+               result->numresults = 0;
+               result->outtimelimit = OSP_DEF_TIMELIMIT;
+               OSPPTransactionRecordFailure(result->outhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
+               if (result->inhandle != OSP_INVALID_HANDLE) {
+                       OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
                }
-               if (!OSPPTransactionRequestAuthorisation(result->handle, source, devinfo, 
-                         callerid,OSPC_E164, extension, OSPC_E164, NULL, 0, NULL, NULL, &counts, &dummy, NULL)) {
-                       if (counts) {
-                               tokenlen = sizeof(token);
-                               result->numresults = counts - 1;
+               ast_log(LOG_DEBUG, "OSP: Unable to get first route\n");
+               return(res);
+       }
+
+       do {
+               result->outtimelimit = osp_choTimelimit(result->intimelimit, result->outtimelimit);
+               ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
+               ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
+               ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
+               ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
+               ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
+
+               res = osp_chkDest(callednum, callingnum, destination, tokenlen, token, &cause, result);
+               if (!res) {
+                       result->numresults--;
+                       if (result->numresults) {
                                callidlen = sizeof(callidstr);
-                               if (!OSPPTransactionGetFirstDestination(result->handle, 0, NULL, NULL, &timelimit, &callidlen, callidstr, 
-                                       sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
-                                       ast_log(LOG_DEBUG, "Got destination '%s' and called: '%s' calling: '%s' for '%s' (provider '%s')\n",
-                                               destination, callednum, callingnum, extension, provider);
-                                       /* Only support OSP server with only one duration limit */
-                                       if (ast_channel_cmpwhentohangup (chan, timelimit) < 0) {
-                                               ast_channel_setwhentohangup (chan, timelimit);  
+                               tokenlen = sizeof(token);
+                               error = OSPPTransactionGetNextDestination(
+                                       result->outhandle, 
+                                       cause, 
+                                       0, NULL, NULL, 
+                                       &result->outtimelimit, 
+                                       &callidlen, callidstr,
+                                       sizeof(callednum), callednum, 
+                                       sizeof(callingnum), callingnum, 
+                                       sizeof(destination), destination, 
+                                       0, NULL, 
+                                       &tokenlen, token);
+                               if (error != OSPC_ERR_NO_ERROR) {
+                                       result->token[0] = '\0';
+                                       result->numresults = 0;
+                                       result->outtimelimit = OSP_DEF_TIMELIMIT;
+                                       OSPPTransactionRecordFailure(result->outhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
+                                       if (result->inhandle != OSP_INVALID_HANDLE) {
+                                               OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
                                        }
-                                       do {
-                                               if ((strlen(destination) > 2) && (check_dest(result, token, tokenlen))) {
-                                                       /* Strip leading and trailing brackets */
-                                                       destination[strlen(destination) - 1] = '\0';
-                                                       snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
-                                                       res = 1;
-                                               } else {
-                                                       if(result->numresults) {
-                                                               result->numresults--;
-                                                               callidlen = sizeof(callidstr);
-                                                               if (!OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, 
-                                                                       callidstr, sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, 
-                                                                       &tokenlen, token))
-                                                               {
-                                                                       continue;
-                                                               }
-                                                       }
-                                               }
-                                               break;
-                                       } while (1);
+                                       break;
+                               }
+                       } else {
+                               result->token[0] = '\0';
+                               result->numresults = 0;
+                               result->outtimelimit = OSP_DEF_TIMELIMIT;
+                               OSPPTransactionRecordFailure(result->outhandle, cause);
+                               if (result->inhandle != OSP_INVALID_HANDLE) {
+                                       OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
                                }
                        }
+               } else {
+                       result->numresults--;
                }
-               if (!res) {
-                       OSPPTransactionDelete(result->handle);
-                       result->handle = -1;
-               }
-               
-       }
-       if (!osp) 
-               ast_log(LOG_NOTICE, "OSP Provider '%s' does not exist!\n", provider);
-       if (chan) {
-               cres = ast_autoservice_stop(chan);
-               if (cres < 0)
-                       return cres;
+       } while(!res && result->numresults);
+
+       return(res);
+}
+
+static enum OSPEFAILREASON reason2cause(
+       int reason)                                             /* Last call failure reason */
+{
+       enum OSPEFAILREASON cause;
+
+       switch(reason) {
+               case AST_CAUSE_NOTDEFINED:
+                       cause = OSPC_FAIL_NONE;
+                       break;
+               case AST_CAUSE_BUSY:
+                       cause = OSPC_FAIL_USER_BUSY;
+                       break;
+               case AST_CAUSE_CONGESTION:
+                       cause = OSPC_FAIL_SWITCHING_EQUIPMENT_CONGESTION;
+                       break;
+               case AST_CAUSE_UNALLOCATED:
+                       cause = OSPC_FAIL_UNALLOC_NUMBER;
+                       break;
+               case AST_CAUSE_NOANSWER:
+                       cause = OSPC_FAIL_NO_ANSWER_FROM_USER;
+                       break;
+               case AST_CAUSE_NORMAL:
+               default:
+                       cause = OSPC_FAIL_NORMAL_CALL_CLEARING;
+                       break;
        }
-       return res;
+
+       return(cause);
 }
 
-int ast_osp_next(struct ast_osp_result *result, int cause)
+int ast_osp_next(
+       int reason,                                             /* Last desintaion failure reason */
+       struct ast_osp_result *result)  /* OSP lookup results, output */
 {
        int res = 0;
-       int tokenlen;
-       unsigned int timelimit;
        unsigned int callidlen;
-       char callidstr[OSPC_CALLID_MAXSIZE] = "";
-       char callednum[2048]="";
-       char callingnum[2048]="";
-       char destination[2048]="";
-       char token[2000];
+       char callidstr[OSPC_CALLID_MAXSIZE];
+       char callingnum[OSP_NORSTR_SIZE];
+       char callednum[OSP_NORSTR_SIZE];
+       char destination[OSP_NORSTR_SIZE];
+       unsigned int tokenlen;
+       char token[OSP_TOKSTR_SIZE];
+       enum OSPEFAILREASON cause;
+       int error;
 
        result->tech[0] = '\0';
        result->dest[0] = '\0';
+       result->calling[0] = '\0';
        result->token[0] = '\0';
+       result->outtimelimit = OSP_DEF_TIMELIMIT;
 
-       if (result->handle > -1) {
-               if (result->numresults) {
-                       tokenlen = sizeof(token);
-                       while(!res && result->numresults) {
-                               result->numresults--;
-                               callidlen = sizeof(callidstr);
-                               if (!OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, callidstr, 
-                                       sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) 
-                               {
-                                       if ((strlen(destination) > 2) && check_dest(result, token, tokenlen)) {
-                                               /* Strip leading and trailing brackets */
-                                               destination[strlen(destination) - 1] = '\0';
-                                               snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
-                                               res = 1;
-                                       }
-                               }
-                       }
+       if (result->outhandle == OSP_INVALID_HANDLE) {
+               result->numresults = 0;
+               if (result->inhandle != OSP_INVALID_HANDLE) {
+                       OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
                }
-               if (!res) {
-                       OSPPTransactionDelete(result->handle);
-                       result->handle = -1;
+               ast_log(LOG_WARNING, "OSP: Transaction handle undefined\n");
+               return(-1);
+       }
+
+       cause = reason2cause(reason);
+       if (!result->numresults) {
+               OSPPTransactionRecordFailure(result->outhandle, cause);
+               if (result->inhandle != OSP_INVALID_HANDLE) {
+                       OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
                }
+               ast_log(LOG_DEBUG, "OSP: No more destination\n");
+               return(res);
        }
-       return res;
-}
 
-static enum OSPEFAILREASON cause2reason(int cause)
-{
-       switch(cause) {
-       case AST_CAUSE_BUSY:
-               return OSPC_FAIL_USER_BUSY;
-       case AST_CAUSE_CONGESTION:
-               return OSPC_FAIL_SWITCHING_EQUIPMENT_CONGESTION;
-       case AST_CAUSE_UNALLOCATED:
-               return OSPC_FAIL_UNALLOC_NUMBER;
-       case AST_CAUSE_NOTDEFINED:
-               return OSPC_FAIL_NORMAL_UNSPECIFIED;
-       case AST_CAUSE_NOANSWER:
-               return OSPC_FAIL_NO_ANSWER_FROM_USER;
-       case AST_CAUSE_NORMAL:
-       default:
-               return OSPC_FAIL_NORMAL_CALL_CLEARING;
+       while(!res && result->numresults) {
+               result->numresults--;
+               callidlen = sizeof(callidstr);
+               tokenlen = sizeof(token);
+               error = OSPPTransactionGetNextDestination(
+                       result->outhandle, 
+                       cause, 
+                       0, NULL, NULL, 
+                       &result->outtimelimit, 
+                       &callidlen, callidstr,
+                       sizeof(callednum), callednum, 
+                       sizeof(callingnum), callingnum, 
+                       sizeof(destination), destination, 
+                       0, NULL, 
+                       &tokenlen, token);
+               if (error == OSPC_ERR_NO_ERROR) {
+                       result->outtimelimit = osp_choTimelimit(result->intimelimit, result->outtimelimit);
+                       ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
+                       ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
+                       ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
+                       ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
+                       ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
+
+                       res = osp_chkDest(callednum, callingnum, destination, tokenlen, token, &cause, result);
+                       if (!res && !result->numresults) {
+                               OSPPTransactionRecordFailure(result->outhandle, cause);
+                               if (result->inhandle != OSP_INVALID_HANDLE) {
+                                       OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
+                               }
+                       }
+               } else {
+                       result->token[0] = '\0';
+                       result->numresults = 0;
+                       result->outtimelimit = OSP_DEF_TIMELIMIT;
+                       OSPPTransactionRecordFailure(result->outhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
+                       if (result->inhandle != OSP_INVALID_HANDLE) {
+                               OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
+                       }
+               }
        }
+
+       return(res);
 }
 
-int ast_osp_terminate(int handle, int cause, time_t start, time_t duration)
+int ast_osp_finish(
+       int handle,                                             /* OSP in/out_bound transaction handle */
+       int reason,                                             /* Last destination failure reason */
+       time_t start,                                   /* Call start time */
+       time_t connect,                                 /* Call connect time */
+       time_t end)                                             /* Call end time*/
 {
+       int res = 1;
        unsigned int dummy = 0;
-       int res = -1;
-       enum OSPEFAILREASON reason;
-
-       time_t endTime = 0;
-       time_t alertTime = 0;
-       time_t connectTime = 0;
+       enum OSPEFAILREASON cause;
+       time_t alert = 0;
        unsigned isPddInfoPresent = 0;
        unsigned pdd = 0;
        unsigned releaseSource = 0;
        unsigned char *confId = "";
+       int error;
        
-       reason = cause2reason(cause);
-       if (OSPPTransactionRecordFailure(handle, reason))
-               ast_log(LOG_WARNING, "Failed to record call termination for handle %d\n", handle);
-       else if (OSPPTransactionReportUsage(handle, duration, start,
-                              endTime,alertTime,connectTime,isPddInfoPresent,pdd,releaseSource,confId,
-                              0, 0, 0, 0, &dummy, NULL))
-               ast_log(LOG_WARNING, "Failed to report duration for handle %d\n", handle);
-       else {
-               ast_log(LOG_DEBUG, "Completed recording handle %d\n", handle);
-               OSPPTransactionDelete(handle);
+       if (handle == OSP_INVALID_HANDLE) {
+               return(res);
+       }
+
+       if ((cause = reason2cause(reason)) != OSPC_FAIL_NONE) {
+               OSPPTransactionRecordFailure(handle, cause);
+       }
+       error = OSPPTransactionReportUsage(
+               handle, 
+               difftime(end, connect), start, end, alert, connect, 
+               isPddInfoPresent, pdd, 
+               releaseSource, 
+               confId,
+               0, 0, 0, 0,
+               &dummy, NULL);
+       if (error == OSPC_ERR_NO_ERROR) {
+               ast_log(LOG_DEBUG, "OSP: Usage reported\n");
+               res = 1;
+       } else {
+               ast_log(LOG_DEBUG, "OSP: Unable to report usage, error = %d\n", error);
                res = 0;
        }
-       return res;
+       OSPPTransactionDelete(handle);
+
+       return(res);
 }
 
-static int config_load(void)
+void ast_osp_adduse(void)
 {
-       struct ast_config *cfg;
-       char *cat;
-       struct osp_provider *osp, *prev = NULL, *next;
-       ast_mutex_lock(&osplock);
-       osp = providers;
-       while(osp) {
-               osp->dead = 1;
-               osp = osp->next;
+       osp_usecount++;
+}
+
+void ast_osp_deluse(void)
+{
+       if (osp_usecount > 0) {
+               osp_usecount--;
        }
-       ast_mutex_unlock(&osplock);
-       cfg = ast_config_load("osp.conf");
+}
+
+static char osp_usage[] =
+"Usage: show osp\n"
+"       Displays information on Open Settlement Protocol support\n";
+
+static struct ast_cli_entry osp_cli = {
+       {"show", "osp", NULL}, 
+       osp_show, 
+       "Displays OSP information", 
+       osp_usage 
+};
+
+static int osp_load(void)
+{
+       char* t;
+       unsigned int v;
+       struct ast_config* cfg;
+       int error = OSPC_ERR_NO_ERROR;
+
+       cfg = ast_config_load(OSP_CONFIG_FILE);
        if (cfg) {
-               if (!initialized) {
-                       cat = ast_variable_retrieve(cfg, "general", "accelerate");
-                       if (cat && ast_true(cat))
-                               if (OSPPInit(1)) {
-                                       ast_log(LOG_WARNING, "Failed to enable hardware accelleration, falling back to software mode\n");
-                                       OSPPInit(0);
-                               } else
-                                       hardware = 1;
-                       else
+               t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "accelerate");
+               if (t && ast_true(t)) {
+                       if ((error = OSPPInit(1)) != OSPC_ERR_NO_ERROR) {
+                               ast_log(LOG_WARNING, "OSP: Unable to enable hardware accelleration\n");
                                OSPPInit(0);
-                       initialized = 1;
+                       } else {
+                               osp_hardware = 1;
+                       }
+               } else {
+                       OSPPInit(0);
                }
-               cat = ast_variable_retrieve(cfg, "general", "tokenformat");
-               if (cat) {
-                       if ((sscanf(cat, "%d", &tokenformat) != 1) || (tokenformat < TOKEN_ALGO_SIGNED) || (tokenformat > TOKEN_ALGO_BOTH)) {
-                               tokenformat = TOKEN_ALGO_SIGNED;
-                               ast_log(LOG_WARNING, "tokenformat should be an integer from 0 to 2, not '%s'\n", cat);
+               ast_log(LOG_DEBUG, "OSP: osp_hardware '%d'\n", osp_hardware);
+
+               t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat");
+               if (t) {
+                       if ((sscanf(t, "%d", &v) == 1) && 
+                               ((v == TOKEN_ALGO_SIGNED) || (v == TOKEN_ALGO_UNSIGNED) || (v == TOKEN_ALGO_BOTH))) 
+                       {
+                               osp_tokenformat = v;
+                       } else {
+                               ast_log(LOG_WARNING, "tokenformat should be an integer from %d, %d or %d, not '%s'\n", 
+                                       TOKEN_ALGO_SIGNED, TOKEN_ALGO_UNSIGNED, TOKEN_ALGO_BOTH, t);
                        }
                }
-               cat = ast_category_browse(cfg, NULL);
-               while(cat) {
-                       if (strcasecmp(cat, "general"))
-                               osp_build(cfg, cat);
-                       cat = ast_category_browse(cfg, cat);
+               ast_log(LOG_DEBUG, "OSP: osp_tokenformat '%d'\n", osp_tokenformat);
+
+               t = ast_category_browse(cfg, NULL);
+               while(t) {
+                       if (strcasecmp(t, OSP_GENERAL_CAT)) {
+                               osp_buildProvider(cfg, t);
+                       }
+                       t = ast_category_browse(cfg, t);
                }
+
+               osp_initialized = 1;
+
                ast_config_destroy(cfg);
-       } else
-               ast_log(LOG_NOTICE, "No OSP configuration found.  OSP support disabled\n");
-       ast_mutex_lock(&osplock);
-       osp = providers;
-       while(osp) {
-               next = osp->next;
-               if (osp->dead) {
-                       if (prev)
-                               prev->next = next;
-                       else
-                               providers = next;
-                       /* XXX Cleanup OSP structure first XXX */
-                       free(osp);
-               } else 
-                       prev = osp;
-               osp = next;
+       } else {
+               ast_log(LOG_WARNING, "OSP: Unable to find configuration. OSP support disabled\n");
        }
-       ast_mutex_unlock(&osplock);
-       return 0;
+       ast_log(LOG_DEBUG, "OSP: osp_initialized '%d'\n", osp_initialized);
+
+       return(0);
 }
 
-static char show_osp_usage[] = 
-"Usage: show osp\n"
-"       Displays information on Open Settlement Protocol\n";
+static int osp_unload(void)
+{
+       struct osp_provider* p;
+       struct osp_provider* next;
+
+       if (osp_initialized) {
+               ast_mutex_lock(&osplock);
+               p = ospproviders;
+               while(p) {
+                       next = p->next;
+                       OSPPProviderDelete(p->handle, 0);
+                       free(p);
+                       p = next;
+               }
+               ospproviders = NULL;
+               ast_mutex_unlock(&osplock);
 
-static struct ast_cli_entry cli_show_osp = 
-{ { "show", "osp", NULL }, show_osp, "Displays OSP information", show_osp_usage };
+               OSPPCleanup();
 
-int reload(void)
+               osp_usecount = 0;
+               osp_tokenformat = TOKEN_ALGO_SIGNED;
+               osp_hardware = 0;
+               osp_initialized = 0;
+       }
+       return(0);
+}
+
+static int osp_show(int fd, int argc, char *argv[])
 {
-       config_load();
-       ast_log(LOG_NOTICE, "XXX Should reload OSP config XXX\n");
-       return 0;
+       int i;
+       int found = 0;
+       struct osp_provider* p;
+       char* provider = NULL;
+       char* tokenalgo;
+
+       if ((argc < 2) || (argc > 3)) {
+               return(RESULT_SHOWUSAGE);
+       }
+       if (argc > 2) {
+               provider = argv[2];
+       }
+       if (!provider) {
+               switch (osp_tokenformat) {
+                       case TOKEN_ALGO_BOTH:
+                               tokenalgo = "Both";
+                               break;
+                       case TOKEN_ALGO_UNSIGNED:
+                               tokenalgo = "Unsigned";
+                               break;
+                       case TOKEN_ALGO_SIGNED:
+                       default:
+                               tokenalgo = "Signed";
+                               break;
+               }
+               ast_cli(fd, "OSP: %s %s %s\n", 
+                       osp_initialized ? "Initialized" : "Uninitialized", osp_hardware ? "Accelerated" : "Normal", tokenalgo);
+       }
+
+       ast_mutex_lock(&osplock);
+       p = ospproviders;
+       while(p) {
+               if (!provider || !strcasecmp(p->name, provider)) {
+                       if (found) {
+                               ast_cli(fd, "\n");
+                       }
+                       ast_cli(fd, " == OSP Provider '%s' == \n", p->name);
+                       ast_cli(fd, "Local Private Key: %s\n", p->privatekey);
+                       ast_cli(fd, "Local Certificate: %s\n", p->localcert);
+                       for (i = 0; i < p->cacount; i++) {
+                               ast_cli(fd, "CA Certificate %d:  %s\n", i + 1, p->cacerts[i]);
+                       }
+                       for (i = 0; i < p->spcount; i++) {
+                               ast_cli(fd, "Service Point %d:   %s\n", i + 1, p->srvpoints[i]);
+                       }
+                       ast_cli(fd, "Max Connections:   %d\n", p->maxconnections);
+                       ast_cli(fd, "Retry Delay:       %d seconds\n", p->retrydelay);
+                       ast_cli(fd, "Retry Limit:       %d\n", p->retrylimit);
+                       ast_cli(fd, "Timeout:           %d milliseconds\n", p->timeout);
+                       ast_cli(fd, "Source:            %s\n", strlen(p->source) ? p->source : "<unspecified>");
+                       ast_cli(fd, "Auth Policy        %d\n", p->authpolicy);
+                       ast_cli(fd, "OSP Handle:        %d\n", p->handle);
+                       found++;
+               }
+               p = p->next;
+       }
+       ast_mutex_unlock(&osplock);
+
+       if (!found) {
+               if (provider) {
+                       ast_cli(fd, "Unable to find OSP provider '%s'\n", provider);
+               } else {
+                       ast_cli(fd, "No OSP providers configured\n");
+               }
+       }
+       return(RESULT_SUCCESS);
 }
 
 int load_module(void)
 {
-       config_load();
-       ast_cli_register(&cli_show_osp);
-       return 0;
+       osp_load();
+       ast_cli_register(&osp_cli);
+       return(0);
+}
+
+int reload(void)
+{
+       ast_cli_unregister(&osp_cli);
+       osp_unload();
+       osp_load();
+       ast_cli_register(&osp_cli);
+       return(0);
 }
 
 int unload_module(void)
 {
-       /* Can't unload this once we're loaded */
-       return -1;
+       ast_cli_unregister(&osp_cli);
+       osp_unload();
+       return(0);
 }
 
 char *description(void)
 {
-       return "Open Settlement Protocol Support";
+       return("Open Settlement Protocol Support");
 }
 
 int usecount(void)
 {
-       /* We should never be unloaded */
-       return 1;
+       return(osp_usecount);
 }
 
 char *key()
 {
-       return ASTERISK_GPL_KEY;
+       return(ASTERISK_GPL_KEY);
 }
+