Updates from transnexus to osplookup, removes res_osp
[asterisk/asterisk.git] / apps / app_osplookup.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*!
20  * \file
21  * \brief Open Settlement Protocol (OSP) Applications
22  *
23  * \author Mark Spencer <markster@digium.com>
24  * 
25  * \ingroup applications
26  */
27
28 /*** MODULEINFO
29         <depend>libosptk</depend>
30         <depend>ssl</depend>
31  ***/
32
33 #include "asterisk.h"
34
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36
37 #include <sys/types.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <osp/osp.h>
43 #include <osp/osputils.h>
44
45 #include "asterisk/lock.h"
46 #include "asterisk/config.h"
47 #include "asterisk/utils.h"
48 #include "asterisk/causes.h"
49 #include "asterisk/channel.h"
50 #include "asterisk/app.h"
51 #include "asterisk/module.h"
52 #include "asterisk/pbx.h"
53 #include "asterisk/options.h"
54 #include "asterisk/cli.h"
55 #include "asterisk/logger.h"
56 #include "asterisk/astosp.h"
57
58 /* OSP Buffer Sizes */
59 #define OSP_INTSTR_SIZE                 ((unsigned int)16)                      /* OSP signed/unsigned int string buffer size */
60 #define OSP_NORSTR_SIZE                 ((unsigned int)256)                     /* OSP normal string buffer size */
61 #define OSP_TOKSTR_SIZE                 ((unsigned int)4096)            /* OSP token string buffer size */
62
63 /* OSP Constants */
64 #define OSP_INVALID_HANDLE              ((int)-1)                                       /* Invalid OSP handle, provider, transaction etc. */
65 #define OSP_CONFIG_FILE                 ((const char*)"osp.conf")       /* OSP configuration file name */
66 #define OSP_GENERAL_CAT                 ((const char*)"general")        /* OSP global configuration context name */
67 #define OSP_DEF_PROVIDER                ((const char*)"default")        /* OSP default provider context name */
68 #define OSP_MAX_CERTS                   ((unsigned int)10)                      /* OSP max number of cacerts */
69 #define OSP_MAX_SRVS                    ((unsigned int)10)                      /* OSP max number of service points */
70 #define OSP_DEF_MAXCONNECTIONS  ((unsigned int)20)                      /* OSP default max_connections */
71 #define OSP_MIN_MAXCONNECTIONS  ((unsigned int)1)                       /* OSP min max_connections */
72 #define OSP_MAX_MAXCONNECTIONS  ((unsigned int)1000)            /* OSP max max_connections */
73 #define OSP_DEF_RETRYDELAY              ((unsigned int)0)                       /* OSP default retry delay */
74 #define OSP_MIN_RETRYDELAY              ((unsigned int)0)                       /* OSP min retry delay */
75 #define OSP_MAX_RETRYDELAY              ((unsigned int)10)                      /* OSP max retry delay */
76 #define OSP_DEF_RETRYLIMIT              ((unsigned int)2)                       /* OSP default retry times */
77 #define OSP_MIN_RETRYLIMIT              ((unsigned int)0)                       /* OSP min retry times */
78 #define OSP_MAX_RETRYLIMIT              ((unsigned int)100)                     /* OSP max retry times */
79 #define OSP_DEF_TIMEOUT                 ((unsigned int)500)                     /* OSP default timeout in ms */
80 #define OSP_MIN_TIMEOUT                 ((unsigned int)200)                     /* OSP min timeout in ms */
81 #define OSP_MAX_TIMEOUT                 ((unsigned int)10000)           /* OSP max timeout in ms */
82 #define OSP_DEF_AUTHPOLICY              ((enum osp_authpolicy)OSP_AUTH_YES)
83 #define OSP_AUDIT_URL                   ((const char*)"localhost")      /* OSP default Audit URL */
84 #define OSP_LOCAL_VALIDATION    ((int)1)                                        /* Validate OSP token locally */
85 #define OSP_SSL_LIFETIME                ((unsigned int)300)                     /* SSL life time, in seconds */
86 #define OSP_HTTP_PERSISTENCE    ((int)1)                                        /* In seconds */
87 #define OSP_CUSTOMER_ID                 ((const char*)"")                       /* OSP customer ID */
88 #define OSP_DEVICE_ID                   ((const char*)"")                       /* OSP device ID */
89 #define OSP_DEF_DESTINATIONS    ((unsigned int)5)                       /* OSP default max number of destinations */
90 #define OSP_DEF_TIMELIMIT               ((unsigned int)0)                       /* OSP default duration limit, no limit */
91
92 /* OSP Authentication Policy */
93 enum osp_authpolicy {
94         OSP_AUTH_NO,            /* Accept any call */
95         OSP_AUTH_YES,           /* Accept call with valid OSP token or without OSP token */
96         OSP_AUTH_EXCLUSIVE      /* Only accept call with valid OSP token */
97 };
98
99 /* OSP Provider */
100 struct osp_provider {
101         char name[OSP_NORSTR_SIZE];                                             /* OSP provider context name */
102         char privatekey[OSP_NORSTR_SIZE];                               /* OSP private key file name */
103         char localcert[OSP_NORSTR_SIZE];                                /* OSP local cert file name */
104         unsigned int cacount;                                                   /* Number of cacerts */
105         char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE];   /* Cacert file names */
106         unsigned int spcount;                                                   /* Number of service points */
107         char srvpoints[OSP_MAX_SRVS][OSP_NORSTR_SIZE];  /* Service point URLs */
108         int maxconnections;                                                             /* Max number of connections */
109         int retrydelay;                                                                 /* Retry delay */
110         int retrylimit;                                                                 /* Retry limit */
111         int timeout;                                                                    /* Timeout in ms */
112         char source[OSP_NORSTR_SIZE];                                   /* IP of self */
113         enum osp_authpolicy authpolicy;                                 /* OSP authentication policy */
114         OSPTPROVHANDLE handle;                                                  /* OSP provider handle */
115         struct osp_provider* next;                                              /* Pointer to next OSP provider */
116 };
117
118 /* OSP Application In/Output Results */
119 struct osp_result {
120         int inhandle;                                   /* Inbound transaction handle */
121         int outhandle;                                  /* Outbound transaction handle */
122         unsigned int intimelimit;               /* Inbound duration limit */
123         unsigned int outtimelimit;              /* Outbound duration limit */
124         char tech[20];                                  /* Asterisk TECH string */
125         char dest[OSP_NORSTR_SIZE];             /* Destination in called@IP format */
126         char calling[OSP_NORSTR_SIZE];  /* Calling number, may be translated */
127         char token[OSP_TOKSTR_SIZE];    /* Outbound OSP token */
128         int numresults;                                 /* Number of remain destinations */
129 };
130
131 /* OSP Module Global Variables */
132 AST_MUTEX_DEFINE_STATIC(osplock);                                                       /* Lock of OSP provider list */
133 static int osp_initialized = 0;                                                         /* Init flag */
134 static int osp_hardware = 0;                                                            /* Hardware accelleration flag */
135 static struct osp_provider* ospproviders = NULL;                        /* OSP provider list */
136 static unsigned int osp_tokenformat = TOKEN_ALGO_SIGNED;        /* Token format supported */
137
138 /* OSP Client Wrapper APIs */
139
140 /*!
141  * \brief Create OSP provider handle according to configuration
142  * \param cfg OSP configuration
143  * \param provider OSP provider context name
144  * \return 1 Success, 0 Failed, -1 Error
145  */
146 static int osp_create_provider(
147         struct ast_config* cfg,         /* OSP configuration */
148         const char* provider)           /* OSP provider context name */
149 {
150         int res;
151         unsigned int t, i, j;
152         struct osp_provider* p;
153         struct ast_variable* v;
154         OSPTPRIVATEKEY privatekey;
155         OSPTCERT localcert;
156         const char* psrvpoints[OSP_MAX_SRVS];
157         OSPTCERT cacerts[OSP_MAX_CERTS];
158         const OSPTCERT* pcacerts[OSP_MAX_CERTS];
159         int error = OSPC_ERR_NO_ERROR;
160
161         if (!(p = ast_calloc(1, sizeof(*p)))) {
162                 ast_log(LOG_ERROR, "Out of memory\n");
163                 return -1;
164         }
165
166         ast_copy_string(p->name, provider, sizeof(p->name));
167         snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, provider);
168         snprintf(p->localcert, sizeof(p->localcert), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, provider);
169         p->maxconnections = OSP_DEF_MAXCONNECTIONS;
170         p->retrydelay = OSP_DEF_RETRYDELAY;
171         p->retrylimit = OSP_DEF_RETRYLIMIT;
172         p->timeout = OSP_DEF_TIMEOUT;
173         p->authpolicy = OSP_DEF_AUTHPOLICY;
174         p->handle = OSP_INVALID_HANDLE;
175
176         v = ast_variable_browse(cfg, provider);
177         while(v) {
178                 if (!strcasecmp(v->name, "privatekey")) {
179                         if (v->value[0] == '/') {
180                                 ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey));
181                         } else {
182                                 snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value);
183                         }
184                         ast_log(LOG_DEBUG, "OSP: privatekey '%s'\n", p->privatekey);
185                 } else if (!strcasecmp(v->name, "localcert")) {
186                         if (v->value[0] == '/') {
187                                 ast_copy_string(p->localcert, v->value, sizeof(p->localcert));
188                         } else {
189                                 snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
190                         }
191                         ast_log(LOG_DEBUG, "OSP: localcert '%s'\n", p->localcert);
192                 } else if (!strcasecmp(v->name, "cacert")) {
193                         if (p->cacount < OSP_MAX_CERTS) {
194                                 if (v->value[0] == '/') {
195                                         ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0]));
196                                 } else {
197                                         snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
198                                 }
199                                 ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
200                                 p->cacount++;
201                         } else {
202                                 ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno);
203                         }
204                 } else if (!strcasecmp(v->name, "servicepoint")) {
205                         if (p->spcount < OSP_MAX_SRVS) {
206                                 ast_copy_string(p->srvpoints[p->spcount], v->value, sizeof(p->srvpoints[0]));
207                                 ast_log(LOG_DEBUG, "OSP: servicepoint[%d]: '%s'\n", p->spcount, p->srvpoints[p->spcount]);
208                                 p->spcount++;
209                         } else {
210                                 ast_log(LOG_WARNING, "OSP: Too many Service Points at line %d\n", v->lineno);
211                         }
212                 } else if (!strcasecmp(v->name, "maxconnections")) {
213                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_MAXCONNECTIONS) && (t <= OSP_MAX_MAXCONNECTIONS)) {
214                                 p->maxconnections = t;
215                                 ast_log(LOG_DEBUG, "OSP: maxconnections '%d'\n", t);
216                         } else {
217                                 ast_log(LOG_WARNING, "OSP: maxconnections should be an integer from %d to %d, not '%s' at line %d\n", 
218                                         OSP_MIN_MAXCONNECTIONS, OSP_MAX_MAXCONNECTIONS, v->value, v->lineno);
219                         }
220                 } else if (!strcasecmp(v->name, "retrydelay")) {
221                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYDELAY) && (t <= OSP_MAX_RETRYDELAY)) {
222                                 p->retrydelay = t;
223                                 ast_log(LOG_DEBUG, "OSP: retrydelay '%d'\n", t);
224                         } else {
225                                 ast_log(LOG_WARNING, "OSP: retrydelay should be an integer from %d to %d, not '%s' at line %d\n", 
226                                         OSP_MIN_RETRYDELAY, OSP_MAX_RETRYDELAY, v->value, v->lineno);
227                         }
228                 } else if (!strcasecmp(v->name, "retrylimit")) {
229                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYLIMIT) && (t <= OSP_MAX_RETRYLIMIT)) {
230                                 p->retrylimit = t;
231                                 ast_log(LOG_DEBUG, "OSP: retrylimit '%d'\n", t);
232                         } else {
233                                 ast_log(LOG_WARNING, "OSP: retrylimit should be an integer from %d to %d, not '%s' at line %d\n", 
234                                         OSP_MIN_RETRYLIMIT, OSP_MAX_RETRYLIMIT, v->value, v->lineno);
235                         }
236                 } else if (!strcasecmp(v->name, "timeout")) {
237                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_TIMEOUT) && (t <= OSP_MAX_TIMEOUT)) {
238                                 p->timeout = t;
239                                 ast_log(LOG_DEBUG, "OSP: timeout '%d'\n", t);
240                         } else {
241                                 ast_log(LOG_WARNING, "OSP: timeout should be an integer from %d to %d, not '%s' at line %d\n", 
242                                         OSP_MIN_TIMEOUT, OSP_MAX_TIMEOUT, v->value, v->lineno);
243                         }
244                 } else if (!strcasecmp(v->name, "source")) {
245                         ast_copy_string(p->source, v->value, sizeof(p->source));
246                         ast_log(LOG_DEBUG, "OSP: source '%s'\n", p->source);
247                 } else if (!strcasecmp(v->name, "authpolicy")) {
248                         if ((sscanf(v->value, "%d", &t) == 1) && ((t == OSP_AUTH_NO) || (t == OSP_AUTH_YES) || (t == OSP_AUTH_EXCLUSIVE))) {
249                                 p->authpolicy = t;
250                                 ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", t);
251                         } else {
252                                 ast_log(LOG_WARNING, "OSP: authpolicy should be %d, %d or %d, not '%s' at line %d\n", 
253                                         OSP_AUTH_NO, OSP_AUTH_YES, OSP_AUTH_EXCLUSIVE, v->value, v->lineno);
254                         }
255                 }
256                 v = v->next;
257         }
258
259         error = OSPPUtilLoadPEMPrivateKey(p->privatekey, &privatekey);
260         if (error != OSPC_ERR_NO_ERROR) {
261                 ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s', error '%d'\n", p->privatekey, error);
262                 free(p);
263                 return 0;
264         }
265
266         error = OSPPUtilLoadPEMCert(p->localcert, &localcert);
267         if (error != OSPC_ERR_NO_ERROR) {
268                 ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s', error '%d'\n", p->localcert, error);
269                 if (privatekey.PrivateKeyData) {
270                         free(privatekey.PrivateKeyData);
271                 }
272                 free(p);
273                 return 0;
274         }
275
276         if (p->cacount < 1) {
277                 snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, provider);
278                 ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
279                 p->cacount++;
280         }
281         for (i = 0; i < p->cacount; i++) {
282                 error = OSPPUtilLoadPEMCert(p->cacerts[i], &cacerts[i]);
283                 if (error != OSPC_ERR_NO_ERROR) {
284                         ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s', error '%d'\n", p->cacerts[i], error);
285                         for (j = 0; j < i; j++) {
286                                 if (cacerts[j].CertData) {
287                                         free(cacerts[j].CertData);
288                                 }
289                         }
290                         if (localcert.CertData) {
291                                 free(localcert.CertData);
292                         }
293                         if (privatekey.PrivateKeyData) {
294                                 free(privatekey.PrivateKeyData);
295                         }
296                         free(p);
297                         return 0;
298                 }
299                 pcacerts[i] = &cacerts[i];
300         }
301         
302         for (i = 0; i < p->spcount; i++) {
303                 psrvpoints[i] = p->srvpoints[i];
304         }
305
306         error = OSPPProviderNew(
307                 p->spcount, psrvpoints,
308                 NULL,
309                 OSP_AUDIT_URL,
310                 &privatekey,
311                 &localcert,
312                 p->cacount, pcacerts,
313                 OSP_LOCAL_VALIDATION,
314                 OSP_SSL_LIFETIME,
315                 p->maxconnections,
316                 OSP_HTTP_PERSISTENCE,
317                 p->retrydelay,
318                 p->retrylimit,
319                 p->timeout,
320                 OSP_CUSTOMER_ID,
321                 OSP_DEVICE_ID,
322                 &p->handle);
323         if (error != OSPC_ERR_NO_ERROR) {
324                 ast_log(LOG_WARNING, "OSP: Unable to create provider '%s', error '%d'\n", provider, error);
325                 free(p);
326                 res = -1;
327         } else {
328                 ast_log(LOG_DEBUG, "OSP: provider '%s'\n", provider);
329                 ast_mutex_lock(&osplock);
330                 p->next = ospproviders;
331                 ospproviders = p;
332                 ast_mutex_unlock(&osplock);     
333                 res = 1;
334         }
335
336         for (i = 0; i < p->cacount; i++) {
337                 if (cacerts[i].CertData) {
338                         free(cacerts[i].CertData);
339                 }
340         }
341         if (localcert.CertData) {
342                 free(localcert.CertData);
343         }
344         if (privatekey.PrivateKeyData) {
345                 free(privatekey.PrivateKeyData);
346         }
347
348         return res;
349 }
350
351 /*!
352  * \brief Get OSP authenticiation policy of provider
353  * \param provider OSP provider context name
354  * \param policy OSP authentication policy, output
355  * \return 1 Success, 0 Failed, -1 Error
356  */
357 static int osp_get_policy(
358         const char* provider,           /* OSP provider context name */
359         int* policy)                            /* OSP authentication policy, output */
360 {
361         int res = 0;
362         struct osp_provider* p;
363
364         ast_mutex_lock(&osplock);
365         p = ospproviders;
366         while(p) {
367                 if (!strcasecmp(p->name, provider)) {
368                         *policy = p->authpolicy;
369                         ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", *policy);
370                         res = 1;
371                         break;
372                 }
373                 p = p->next;
374         }
375         ast_mutex_unlock(&osplock);
376
377         return res;
378 }
379
380 /*!
381  * \brief Create OSP transaction handle
382  * \param provider OSP provider context name
383  * \param transaction OSP transaction handle, output
384  * \param sourcesize Size of source buffer, in/output
385  * \param source Source of provider, output
386  * \return 1 Success, 0 Failed, -1 Error
387  */
388 static int osp_create_transaction(
389         const char* provider,           /* OSP provider context name */
390         int* transaction,                       /* OSP transaction handle, output */
391         unsigned int sourcesize,        /* Size of source buffer, in/output */
392         char* source)                           /* Source of provider context, output */
393 {
394         int res = 0;
395         struct osp_provider* p;
396         int error;
397
398         ast_mutex_lock(&osplock);
399         p = ospproviders;
400         while(p) {
401                 if (!strcasecmp(p->name, provider)) {
402                         error = OSPPTransactionNew(p->handle, transaction);
403                         if (error == OSPC_ERR_NO_ERROR) {
404                                 ast_log(LOG_DEBUG, "OSP: transaction '%d'\n", *transaction);
405                                 ast_copy_string(source, p->source, sourcesize);
406                                 ast_log(LOG_DEBUG, "OSP: source '%s'\n", source);
407                                 res = 1;
408                         } else {
409                                 *transaction = OSP_INVALID_HANDLE;
410                                 ast_log(LOG_DEBUG, "OSP: Unable to create transaction handle, error '%d'\n", error);
411                                 res = -1;
412                         }
413                         break;
414                 }
415                 p = p->next;
416         }
417         ast_mutex_unlock(&osplock);
418
419         return res;
420 }
421
422 /*!
423  * \brief Validate OSP token of inbound call
424  * \param transaction OSP transaction handle
425  * \param source Source of inbound call
426  * \param dest Destination of inbound call
427  * \param calling Calling number
428  * \param called Called number
429  * \param token OSP token, may be empty
430  * \param timelimit Call duration limit, output
431  * \return 1 Success, 0 Failed, -1 Error
432  */
433 static int osp_validate_token(
434         int transaction,                        /* OSP transaction handle */
435         const char* source,                     /* Source of inbound call */
436         const char* dest,                       /* Destination of inbound call */
437         const char* calling,            /* Calling number */
438         const char* called,                     /* Called number */
439         const char* token,                      /* OSP token, may be empty */
440         unsigned int* timelimit)        /* Call duration limit, output */
441 {
442         int res;
443         int tokenlen;
444         char tokenstr[OSP_TOKSTR_SIZE];
445         unsigned int authorised;
446         unsigned int dummy = 0;
447         int error;
448
449         tokenlen = ast_base64decode(tokenstr, token, strlen(token));
450         error = OSPPTransactionValidateAuthorisation(
451                 transaction, 
452                 source, dest, NULL, NULL,
453                 calling ? calling : "", OSPC_E164, 
454                 called, OSPC_E164, 
455                 0, NULL,
456                 tokenlen, tokenstr, 
457                 &authorised, 
458                 timelimit, 
459                 &dummy, NULL, 
460                 osp_tokenformat); 
461         if (error != OSPC_ERR_NO_ERROR) {
462                 ast_log(LOG_DEBUG, "OSP: Unable to validate inbound token\n");
463                 res = -1;
464         } else if (authorised) {
465                 ast_log(LOG_DEBUG, "OSP: Authorised\n");
466                 res = 1;
467         } else {
468                 ast_log(LOG_DEBUG, "OSP: Unauthorised\n");
469                 res = 0;
470         }
471         
472         return res;
473 }
474
475 /*!
476  * \brief Choose min duration limit
477  * \param in Inbound duration limit
478  * \param out Outbound duration limit
479  * \return min duration limit
480  */
481 static unsigned int osp_choose_timelimit(
482         unsigned int in,                        /* Inbound duration timelimit */
483         unsigned int out)                       /* Outbound duration timelimit */
484 {
485         if (in == OSP_DEF_TIMELIMIT) {
486                 return out;
487         } else if (out == OSP_DEF_TIMELIMIT) {
488                 return in;
489         } else {
490                 return in < out ? in : out;
491         }
492 }
493
494 /*!
495  * \brief Choose min duration limit
496  * \param called Called number
497  * \param calling Calling number
498  * \param destination Destination IP in '[x.x.x.x]' format
499  * \param tokenlen OSP token length
500  * \param token OSP token
501  * \param reason Failure reason, output
502  * \param result OSP lookup results, in/output
503  * \return 1 Success, 0 Failed, -1 Error
504  */
505 static int osp_check_destination(
506         const char* called,                             /* Called number */
507         const char* calling,                    /* Calling number */
508         char* destination,                              /* Destination IP in '[x.x.x.x]' format */
509         unsigned int tokenlen,                  /* OSP token length */
510         const char* token,                              /* OSP token */
511         enum OSPEFAILREASON* reason,    /* Failure reason, output */
512         struct osp_result* result)              /* OSP lookup results, in/output */
513 {
514         int res;
515         OSPE_DEST_OSP_ENABLED enabled;
516         OSPE_DEST_PROT protocol;
517         int error;
518
519         if (strlen(destination) <= 2) {
520                 ast_log(LOG_DEBUG, "OSP: Wrong destination format '%s'\n", destination);
521                 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
522                 return -1;
523         } 
524
525         if ((error = OSPPTransactionIsDestOSPEnabled(result->outhandle, &enabled)) != OSPC_ERR_NO_ERROR) {
526                 ast_log(LOG_DEBUG, "OSP: Unable to get destination OSP version, error '%d'\n", error);
527                 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
528                 return -1;
529         }
530
531         if (enabled == OSPE_OSP_FALSE) {
532                 result->token[0] = '\0';
533         } else {
534                 ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1);
535         }
536
537         if ((error = OSPPTransactionGetDestProtocol(result->outhandle, &protocol)) != OSPC_ERR_NO_ERROR) {
538                 ast_log(LOG_DEBUG, "OSP: Unable to get destination protocol, error '%d'\n", error);
539                 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED; 
540                 result->token[0] = '\0';
541                 return -1;
542         } 
543
544         res = 1;
545         /* Strip leading and trailing brackets */
546         destination[strlen(destination) - 1] = '\0';
547         switch(protocol) {
548                 case OSPE_DEST_PROT_H323_SETUP:
549                         ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
550                         ast_copy_string(result->tech, "H323", sizeof(result->tech));
551                         snprintf(result->dest, sizeof(result->dest), "%s@%s", called, destination + 1);
552                         ast_copy_string(result->calling, calling, sizeof(result->calling));
553                         break;
554                 case OSPE_DEST_PROT_SIP:
555                         ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
556                         ast_copy_string(result->tech, "SIP", sizeof(result->tech));
557                         snprintf(result->dest, sizeof(result->dest), "%s@%s", called, destination + 1);
558                         ast_copy_string(result->calling, calling, sizeof(result->calling));
559                         break;
560                 case OSPE_DEST_PROT_IAX:
561                         ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
562                         ast_copy_string(result->tech, "IAX", sizeof(result->tech));
563                         snprintf(result->dest, sizeof(result->dest), "%s@%s", called, destination + 1);
564                         ast_copy_string(result->calling, calling, sizeof(result->calling));
565                         break;
566                 default:
567                         ast_log(LOG_DEBUG, "OSP: Unknown protocol '%d'\n", protocol);
568                         *reason = OSPC_FAIL_PROTOCOL_ERROR; 
569                         result->token[0] = '\0';
570                         res = 0;
571         }
572
573         return res;
574 }
575
576 /*!
577  * \brief Convert Asterisk status to TC code
578  * \param cause Asterisk hangup cause
579  * \return OSP TC code
580  */
581 static enum OSPEFAILREASON asterisk2osp(
582         int cause)                                              /* Asterisk hangup cause */
583 {
584         return (enum OSPEFAILREASON)cause;
585 }
586
587 /*!
588  * \brief OSP Authentication function
589  * \param provider OSP provider context name
590  * \param transaction OSP transaction handle, output
591  * \param source Source of inbound call
592  * \param calling Calling number
593  * \param called Called number
594  * \param token OSP token, may be empty
595  * \param timelimit Call duration limit, output
596  * \return 1 Authenricated, 0 Unauthenticated, -1 Error
597  */
598 static int osp_auth(
599         const char* provider,           /* OSP provider context name */
600         int* transaction,                       /* OSP transaction handle, output */
601         const char* source,                     /* Source of inbound call */
602         const char* calling,            /* Calling number */
603         const char* called,                     /* Called number */
604         const char* token,                      /* OSP token, may be empty */
605         unsigned int* timelimit)        /* Call duration limit, output */
606 {
607         int res;
608         int policy;
609         char dest[OSP_NORSTR_SIZE];
610
611         *transaction = OSP_INVALID_HANDLE;
612         *timelimit = OSP_DEF_TIMELIMIT;
613
614         if ((res = osp_get_policy(provider, &policy)) <= 0) {
615                 ast_log(LOG_DEBUG, "OSP: Unabe to find OSP authentication policy\n");
616                 return res;
617         }
618
619         switch (policy) {
620                 case OSP_AUTH_NO:
621                         res = 1;
622                         break;
623                 case OSP_AUTH_EXCLUSIVE:
624                         if (ast_strlen_zero(token)) {
625                                 res = 0;
626                         } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
627                                 ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
628                                 *transaction = OSP_INVALID_HANDLE;
629                                 res = 0;
630                         } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
631                                 OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
632                         }
633                         break;
634                 case OSP_AUTH_YES:
635                 default:
636                         if (ast_strlen_zero(token)) {
637                                 res = 1;
638                         } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
639                                 ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
640                                 *transaction = OSP_INVALID_HANDLE;
641                                 res = 0;
642                         } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
643                                 OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
644                         }
645                         break;
646         }
647
648         return res;
649 }
650
651 /*!
652  * \brief OSP Lookup function
653  * \param provider OSP provider context name
654  * \param srcdev Source device of outbound call
655  * \param calling Calling number
656  * \param called Called number
657  * \param result Lookup results
658  * \return 1 Found , 0 No route, -1 Error
659  */
660 static int osp_lookup(
661         const char* provider,           /* OSP provider conttext name */
662         const char* srcdev,                     /* Source device of outbound call */
663         const char* calling,            /* Calling number */
664         const char* called,                     /* Called number */
665         struct osp_result* result)      /* OSP lookup results, in/output */
666 {
667         int res;
668         char source[OSP_NORSTR_SIZE];
669         unsigned int callidlen;
670         char callid[OSPC_CALLID_MAXSIZE];
671         char callingnum[OSP_NORSTR_SIZE];
672         char callednum[OSP_NORSTR_SIZE];
673         char destination[OSP_NORSTR_SIZE];
674         unsigned int tokenlen;
675         char token[OSP_TOKSTR_SIZE];
676         unsigned int dummy = 0;
677         enum OSPEFAILREASON reason;
678         int error;
679
680         result->outhandle = OSP_INVALID_HANDLE;
681         result->tech[0] = '\0';
682         result->dest[0] = '\0';
683         result->calling[0] = '\0';
684         result->token[0] = '\0';
685         result->numresults = 0;
686         result->outtimelimit = OSP_DEF_TIMELIMIT;
687
688         if ((res = osp_create_transaction(provider, &result->outhandle, sizeof(source), source)) <= 0) {
689                 ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
690                 result->outhandle = OSP_INVALID_HANDLE;
691                 if (result->inhandle != OSP_INVALID_HANDLE) {
692                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
693                 }
694                 return -1;
695         }
696
697         result->numresults = OSP_DEF_DESTINATIONS;
698         error = OSPPTransactionRequestAuthorisation(
699                 result->outhandle, 
700                 source, srcdev,
701                 calling ? calling : "", OSPC_E164, 
702                 called, OSPC_E164, 
703                 NULL, 
704                 0, NULL, 
705                 NULL, 
706                 &result->numresults, 
707                 &dummy, NULL);
708         if (error != OSPC_ERR_NO_ERROR) {
709                 ast_log(LOG_DEBUG, "OSP: Unable to request authorization\n");
710                 result->numresults = 0;
711                 if (result->inhandle != OSP_INVALID_HANDLE) {
712                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
713                 }
714                 return -1;
715         }
716
717         if (!result->numresults) {
718                 ast_log(LOG_DEBUG, "OSP: No more destination\n");
719                 if (result->inhandle != OSP_INVALID_HANDLE) {
720                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
721                 }
722                 return 0;
723         }
724
725         callidlen = sizeof(callid);
726         tokenlen = sizeof(token);
727         error = OSPPTransactionGetFirstDestination(
728                 result->outhandle, 
729                 0, NULL, NULL, 
730                 &result->outtimelimit, 
731                 &callidlen, callid,
732                 sizeof(callednum), callednum, 
733                 sizeof(callingnum), callingnum, 
734                 sizeof(destination), destination, 
735                 0, NULL, 
736                 &tokenlen, token);
737         if (error != OSPC_ERR_NO_ERROR) {
738                 ast_log(LOG_DEBUG, "OSP: Unable to get first route\n");
739                 result->numresults = 0;
740                 result->outtimelimit = OSP_DEF_TIMELIMIT;
741                 if (result->inhandle != OSP_INVALID_HANDLE) {
742                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
743                 }
744                 return -1;
745         }
746
747         result->numresults--;
748         result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
749         ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
750         ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
751         ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
752         ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
753         ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
754
755         if ((res = osp_check_destination(callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
756                 return 1;
757         }
758
759         if (!result->numresults) {
760                 ast_log(LOG_DEBUG, "OSP: No more destination\n");
761                 result->outtimelimit = OSP_DEF_TIMELIMIT;
762                 OSPPTransactionRecordFailure(result->outhandle, reason);
763                 if (result->inhandle != OSP_INVALID_HANDLE) {
764                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
765                 }
766                 return 0;
767         }
768
769         while(result->numresults) {
770                 callidlen = sizeof(callid);
771                 tokenlen = sizeof(token);
772                 error = OSPPTransactionGetNextDestination(
773                         result->outhandle, 
774                         reason, 
775                         0, NULL, NULL, 
776                         &result->outtimelimit, 
777                         &callidlen, callid,
778                         sizeof(callednum), callednum, 
779                         sizeof(callingnum), callingnum, 
780                         sizeof(destination), destination, 
781                         0, NULL, 
782                         &tokenlen, token);
783                 if (error == OSPC_ERR_NO_ERROR) {
784                         result->numresults--;
785                         result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
786                         ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
787                         ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
788                         ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
789                         ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
790                         ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
791                         if ((res = osp_check_destination(callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
792                                 break;
793                         } else if (!result->numresults) {
794                                 ast_log(LOG_DEBUG, "OSP: No more destination\n");
795                                 OSPPTransactionRecordFailure(result->outhandle, reason);
796                                 if (result->inhandle != OSP_INVALID_HANDLE) {
797                                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
798                                 }
799                                 res = 0;
800                                 break;
801                         }
802                 } else {
803                         ast_log(LOG_DEBUG, "OSP: Unable to get route, error '%d'\n", error);
804                         result->numresults = 0;
805                         result->outtimelimit = OSP_DEF_TIMELIMIT;
806                         if (result->inhandle != OSP_INVALID_HANDLE) {
807                                 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
808                         }
809                         res = -1;
810                         break;
811                 }
812         }
813         return res;
814 }
815
816 /*!
817  * \brief OSP Lookup Next function
818  * \param cause Asterisk hangup cuase
819  * \param result Lookup results, in/output
820  * \return 1 Found , 0 No route, -1 Error
821  */
822 static int osp_next(
823         int cause,                                      /* Asterisk hangup cuase */
824         struct osp_result* result)      /* OSP lookup results, in/output */
825 {
826         int res;
827         unsigned int callidlen;
828         char callid[OSPC_CALLID_MAXSIZE];
829         char callingnum[OSP_NORSTR_SIZE];
830         char callednum[OSP_NORSTR_SIZE];
831         char destination[OSP_NORSTR_SIZE];
832         unsigned int tokenlen;
833         char token[OSP_TOKSTR_SIZE];
834         enum OSPEFAILREASON reason;
835         int error;
836
837         result->tech[0] = '\0';
838         result->dest[0] = '\0';
839         result->calling[0] = '\0';
840         result->token[0] = '\0';
841         result->outtimelimit = OSP_DEF_TIMELIMIT;
842
843         if (result->outhandle == OSP_INVALID_HANDLE) {
844                 ast_log(LOG_DEBUG, "OSP: Transaction handle undefined\n");
845                 result->numresults = 0;
846                 if (result->inhandle != OSP_INVALID_HANDLE) {
847                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
848                 }
849                 return -1;
850         }
851
852         reason = asterisk2osp(cause);
853
854         if (!result->numresults) {
855                 ast_log(LOG_DEBUG, "OSP: No more destination\n");
856                 OSPPTransactionRecordFailure(result->outhandle, reason);
857                 if (result->inhandle != OSP_INVALID_HANDLE) {
858                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
859                 }
860                 return 0;
861         }
862
863         while(result->numresults) {
864                 callidlen = sizeof(callid);
865                 tokenlen = sizeof(token);
866                 error = OSPPTransactionGetNextDestination(
867                         result->outhandle, 
868                         reason, 
869                         0, NULL, NULL, 
870                         &result->outtimelimit, 
871                         &callidlen, callid,
872                         sizeof(callednum), callednum, 
873                         sizeof(callingnum), callingnum, 
874                         sizeof(destination), destination, 
875                         0, NULL, 
876                         &tokenlen, token);
877                 if (error == OSPC_ERR_NO_ERROR) {
878                         result->numresults--;
879                         result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
880                         ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
881                         ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
882                         ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
883                         ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
884                         ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
885                         if ((res = osp_check_destination(callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
886                                 res = 1;
887                                 break;
888                         } else if (!result->numresults) {
889                                 ast_log(LOG_DEBUG, "OSP: No more destination\n");
890                                 OSPPTransactionRecordFailure(result->outhandle, reason);
891                                 if (result->inhandle != OSP_INVALID_HANDLE) {
892                                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
893                                 }
894                                 res = 0;
895                                 break;
896                         }
897                 } else {
898                         ast_log(LOG_DEBUG, "OSP: Unable to get route, error '%d'\n", error);
899                         result->token[0] = '\0';
900                         result->numresults = 0;
901                         result->outtimelimit = OSP_DEF_TIMELIMIT;
902                         if (result->inhandle != OSP_INVALID_HANDLE) {
903                                 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
904                         }
905                         res = -1;
906                         break;
907                 }
908         }
909
910         return res;
911 }
912
913 /*!
914  * \brief OSP Finish function
915  * \param handle OSP in/outbound transaction handle
916  * \param recorded If failure reason has been recorded
917  * \param cause Asterisk hangup cause
918  * \param start Call start time
919  * \param connect Call connect time
920  * \param end Call end time
921  * \param release Who release first, 0 source, 1 destination
922  * \return 1 Success, 0 Failed, -1 Error
923  */
924 static int osp_finish(
925         int handle,                             /* OSP in/outbound transaction handle */
926         int recorded,                   /* If failure reason has been recorded */
927         int cause,                              /* Asterisk hangup cause */
928         time_t start,                   /* Call start time */
929         time_t connect,                 /* Call connect time */
930         time_t end,                             /* Call end time */
931         unsigned int release)   /* Who release first, 0 source, 1 destination */
932 {
933         int res;
934         enum OSPEFAILREASON reason;
935         time_t alert = 0;
936         unsigned isPddInfoPresent = 0;
937         unsigned pdd = 0;
938         unsigned char* confId = "";
939         unsigned int dummy = 0;
940         int error;
941         
942         if (handle == OSP_INVALID_HANDLE) {
943                 return 0;
944         }
945
946         if (!recorded) {
947                 reason = asterisk2osp(cause);
948                 OSPPTransactionRecordFailure(handle, reason);
949         }
950
951         error = OSPPTransactionReportUsage(
952                 handle, 
953                 difftime(end, connect), start, end, alert, connect, 
954                 isPddInfoPresent, pdd, 
955                 release, 
956                 confId,
957                 0, 0, 0, 0,
958                 &dummy, NULL);
959         if (error == OSPC_ERR_NO_ERROR) {
960                 ast_log(LOG_DEBUG, "OSP: Usage reported\n");
961                 res = 1;
962         } else {
963                 ast_log(LOG_DEBUG, "OSP: Unable to report usage, error '%d'\n", error);
964                 res = -1;
965         }
966         OSPPTransactionDelete(handle);
967
968         return res;
969 }
970
971 /* OSP Application APIs */
972
973 /*!
974  * \brief OSP Application OSPAuth
975  * \param chan Channel
976  * \param data Parameter
977  * \return 0 Success, -1 Failed
978  */
979 static int ospauth_exec(struct ast_channel* chan, void* data)
980 {
981         int res;
982         struct localuser* u;
983         const char* provider = OSP_DEF_PROVIDER;
984         int priority_jump = 0;
985         struct varshead* headp;
986         struct ast_var_t* current;
987         const char* source = "";
988         const char* token = "";
989         int handle;
990         unsigned int timelimit;
991         char buffer[OSP_INTSTR_SIZE];
992         const char* status;
993         char* tmp;
994
995         AST_DECLARE_APP_ARGS(args,
996                 AST_APP_ARG(provider);
997                 AST_APP_ARG(options);
998         );
999
1000         LOCAL_USER_ADD(u);
1001
1002         if (!(tmp = ast_strdupa(data))) {
1003                 ast_log(LOG_ERROR, "Out of memory\n");
1004                 LOCAL_USER_REMOVE(u);
1005                 return -1;
1006         }
1007
1008         AST_STANDARD_APP_ARGS(args, tmp);
1009
1010         if (!ast_strlen_zero(args.provider)) {
1011                 provider = args.provider;
1012         }
1013         ast_log(LOG_DEBUG, "OSPAuth: provider '%s'\n", provider);
1014
1015         if ((args.options) && (strchr(args.options, 'j'))) {
1016                 priority_jump = 1;
1017         }
1018         ast_log(LOG_DEBUG, "OSPAuth: priority jump '%d'\n", priority_jump);
1019
1020         headp = &chan->varshead;
1021         AST_LIST_TRAVERSE(headp, current, entries) {
1022                 if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
1023                         source = ast_var_value(current);
1024                 } else if (!strcasecmp(ast_var_name(current), "OSPINTOKEN")) {
1025                         token = ast_var_value(current);
1026                 }
1027         }
1028         ast_log(LOG_DEBUG, "OSPAuth: source '%s'\n", source);
1029         ast_log(LOG_DEBUG, "OSPAuth: token size '%zd'\n", strlen(token));
1030
1031         
1032         if ((res = osp_auth(provider, &handle, source, chan->cid.cid_num, chan->exten, token, &timelimit)) > 0) {
1033                 status = AST_OSP_SUCCESS;
1034         } else {
1035                 timelimit = OSP_DEF_TIMELIMIT;
1036                 if (!res) {
1037                         status = AST_OSP_FAILED;
1038                 } else {
1039                         status = AST_OSP_ERROR;
1040                 }
1041         }
1042
1043         snprintf(buffer, sizeof(buffer), "%d", handle);
1044         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
1045         ast_log(LOG_DEBUG, "OSPAuth: OSPINHANDLE '%s'\n", buffer);
1046         snprintf(buffer, sizeof(buffer), "%d", timelimit);
1047         pbx_builtin_setvar_helper(chan, "OSPINTIMELIMIT", buffer);
1048         ast_log(LOG_DEBUG, "OSPAuth: OSPINTIMELIMIT '%s'\n", buffer);
1049         pbx_builtin_setvar_helper(chan, "OSPAUTHSTATUS", status);
1050         ast_log(LOG_DEBUG, "OSPAuth: %s\n", status);
1051
1052         if(res <= 0) {
1053                 if (priority_jump || ast_opt_priority_jumping) {
1054                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1055                         res = 0;
1056                 } else {
1057                         res = -1;
1058                 }
1059         } else {
1060                 res = 0;
1061         }
1062
1063         LOCAL_USER_REMOVE(u);
1064
1065         return res;
1066 }
1067
1068 /*!
1069  * \brief OSP Application OSPLookup
1070  * \param chan Channel
1071  * \param data Parameter
1072  * \return 0 Success, -1 Failed
1073  */
1074 static int osplookup_exec(struct ast_channel* chan, void* data)
1075 {
1076         int res, cres;
1077         struct localuser* u;
1078         const char* provider = OSP_DEF_PROVIDER;
1079         int priority_jump = 0;
1080         struct varshead* headp;
1081         struct ast_var_t* current;
1082         const char* srcdev = "";
1083         char buffer[OSP_TOKSTR_SIZE];
1084         struct osp_result result;
1085         const char* status;
1086         char* tmp;
1087
1088         AST_DECLARE_APP_ARGS(args,
1089                 AST_APP_ARG(exten);
1090                 AST_APP_ARG(provider);
1091                 AST_APP_ARG(options);
1092         );
1093         
1094         if (ast_strlen_zero(data)) {
1095                 ast_log(LOG_WARNING, "OSPLookup: Arg required, OSPLookup(exten[|provider[|options]])\n");
1096                 return -1;
1097         }
1098
1099         LOCAL_USER_ADD(u);
1100
1101         if (!(tmp = ast_strdupa(data))) {
1102                 ast_log(LOG_ERROR, "Out of memory\n");
1103                 LOCAL_USER_REMOVE(u);
1104                 return -1;
1105         }
1106
1107         AST_STANDARD_APP_ARGS(args, tmp);
1108
1109         ast_log(LOG_DEBUG, "OSPLookup: exten '%s'\n", args.exten);
1110
1111         if (!ast_strlen_zero(args.provider)) {
1112                 provider = args.provider;
1113         }
1114         ast_log(LOG_DEBUG, "OSPlookup: provider '%s'\n", provider);
1115
1116         if ((args.options) && (strchr(args.options, 'j'))) {
1117                 priority_jump = 1;
1118         }
1119         ast_log(LOG_DEBUG, "OSPLookup: priority jump '%d'\n", priority_jump);
1120
1121         result.inhandle = OSP_INVALID_HANDLE;
1122         result.intimelimit = OSP_DEF_TIMELIMIT;
1123
1124         headp = &chan->varshead;
1125         AST_LIST_TRAVERSE(headp, current, entries) {
1126                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1127                         if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
1128                                 result.inhandle = OSP_INVALID_HANDLE;
1129                         }
1130                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
1131                         if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
1132                                 result.intimelimit = OSP_DEF_TIMELIMIT;
1133                         }
1134                 } else if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
1135                         srcdev = ast_var_value(current);
1136                 }
1137         }
1138         ast_log(LOG_DEBUG, "OSPLookup: OSPINHANDLE '%d'\n", result.inhandle);
1139         ast_log(LOG_DEBUG, "OSPLookup: OSPINTIMELIMIT '%d'\n", result.intimelimit);
1140         ast_log(LOG_DEBUG, "OSPLookup: source device '%s'\n", srcdev);
1141         
1142         if ((cres = ast_autoservice_start(chan)) < 0) {
1143                 LOCAL_USER_REMOVE(u);
1144                 return -1;
1145         }
1146
1147         if ((res = osp_lookup(provider, srcdev, chan->cid.cid_num, args.exten, &result)) > 0) {
1148                 status = AST_OSP_SUCCESS;
1149         } else {
1150                 result.tech[0] = '\0';
1151                 result.dest[0] = '\0';
1152                 result.calling[0] = '\0';
1153                 result.token[0] = '\0'; 
1154                 result.numresults = 0;
1155                 result.outtimelimit = OSP_DEF_TIMELIMIT;
1156                 if (!res) {
1157                         status = AST_OSP_FAILED;
1158                 } else {
1159                         status = AST_OSP_ERROR;
1160                 }
1161         }
1162
1163         snprintf(buffer, sizeof(buffer), "%d", result.outhandle);
1164         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
1165         ast_log(LOG_DEBUG, "OSPLookup: OSPOUTHANDLE '%s'\n", buffer);
1166         pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
1167         ast_log(LOG_DEBUG, "OSPLookup: OSPTECH '%s'\n", result.tech);
1168         pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
1169         ast_log(LOG_DEBUG, "OSPLookup: OSPDEST '%s'\n", result.dest);
1170         pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
1171         ast_log(LOG_DEBUG, "OSPLookup: OSPCALLING '%s'\n", result.calling);
1172         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
1173         ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
1174         snprintf(buffer, sizeof(buffer), "%d", result.numresults);
1175         pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
1176         ast_log(LOG_DEBUG, "OSPLookup: OSPRESULTS '%s'\n", buffer);
1177         snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
1178         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
1179         ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTIMELIMIT '%s'\n", buffer);
1180         pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", status);
1181         ast_log(LOG_DEBUG, "OSPLookup: %s\n", status);
1182
1183         if (!strcasecmp(result.tech, "SIP")) {
1184                 if (!ast_strlen_zero(result.token)) {
1185                         snprintf(buffer, sizeof(buffer), "P-OSP-Auth-Token: %s", result.token);
1186                         pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
1187                         ast_log(LOG_DEBUG, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
1188                 }
1189         } else if (!strcasecmp(result.tech, "H323")) {
1190         } else if (!strcasecmp(result.tech, "IAX")) {
1191         }
1192
1193         if ((cres = ast_autoservice_stop(chan)) < 0) {
1194                 LOCAL_USER_REMOVE(u);
1195                 return -1;
1196         }
1197
1198         if(res <= 0) {
1199                 if (priority_jump || ast_opt_priority_jumping) {
1200                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1201                         res = 0;
1202                 } else {
1203                         res = -1;
1204                 }
1205         } else {
1206                 res = 0;
1207         }
1208
1209         LOCAL_USER_REMOVE(u);
1210
1211         return res;
1212 }
1213
1214 /*!
1215  * \brief OSP Application OSPNext
1216  * \param chan Channel
1217  * \param data Parameter
1218  * \return 0 Success, -1 Failed
1219  */
1220 static int ospnext_exec(struct ast_channel* chan, void* data)
1221 {
1222         int res;
1223         struct localuser* u;
1224         int priority_jump = 0;
1225         int cause = 0;
1226         struct varshead* headp;
1227         struct ast_var_t* current;
1228         struct osp_result result;
1229         char buffer[OSP_TOKSTR_SIZE];
1230         const char* status;
1231         char* tmp;
1232
1233         AST_DECLARE_APP_ARGS(args,
1234                 AST_APP_ARG(cause);
1235                 AST_APP_ARG(options);
1236         );
1237         
1238         if (ast_strlen_zero(data)) {
1239                 ast_log(LOG_WARNING, "OSPNext: Arg required, OSPNext(cause[|options])\n");
1240                 return -1;
1241         }
1242
1243         LOCAL_USER_ADD(u);
1244
1245         if (!(tmp = ast_strdupa(data))) {
1246                 ast_log(LOG_ERROR, "Out of memory\n");
1247                 LOCAL_USER_REMOVE(u);
1248                 return -1;
1249         }
1250
1251         AST_STANDARD_APP_ARGS(args, tmp);
1252
1253         if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%d", &cause) != 1) {
1254                 cause = 0;
1255         }
1256         ast_log(LOG_DEBUG, "OSPNext: cause '%d'\n", cause);
1257
1258         if ((args.options) && (strchr(args.options, 'j'))) {
1259                 priority_jump = 1;
1260         }
1261         ast_log(LOG_DEBUG, "OSPNext: priority jump '%d'\n", priority_jump);
1262
1263         result.inhandle = OSP_INVALID_HANDLE;
1264         result.outhandle = OSP_INVALID_HANDLE;
1265         result.intimelimit = OSP_DEF_TIMELIMIT;
1266         result.numresults = 0;
1267
1268         headp = &chan->varshead;
1269         AST_LIST_TRAVERSE(headp, current, entries) {
1270                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1271                         if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
1272                                 result.inhandle = OSP_INVALID_HANDLE;
1273                         }
1274                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
1275                         if (sscanf(ast_var_value(current), "%d", &result.outhandle) != 1) {
1276                                 result.outhandle = OSP_INVALID_HANDLE;
1277                         }
1278                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
1279                         if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
1280                                 result.intimelimit = OSP_DEF_TIMELIMIT;
1281                         }
1282                 } else if (!strcasecmp(ast_var_name(current), "OSPRESULTS")) {
1283                         if (sscanf(ast_var_value(current), "%d", &result.numresults) != 1) {
1284                                 result.numresults = 0;
1285                         }
1286                 }
1287         }
1288         ast_log(LOG_DEBUG, "OSPNext: OSPINHANDLE '%d'\n", result.inhandle);
1289         ast_log(LOG_DEBUG, "OSPNext: OSPOUTHANDLE '%d'\n", result.outhandle);
1290         ast_log(LOG_DEBUG, "OSPNext: OSPINTIMELIMIT '%d'\n", result.intimelimit);
1291         ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%d'\n", result.numresults);
1292
1293         if ((res = osp_next(cause, &result)) > 0) {
1294                 status = AST_OSP_SUCCESS;
1295         } else {
1296                 result.tech[0] = '\0';
1297                 result.dest[0] = '\0';
1298                 result.calling[0] = '\0';
1299                 result.token[0] = '\0'; 
1300                 result.numresults = 0;
1301                 result.outtimelimit = OSP_DEF_TIMELIMIT;
1302                 if (!res) {
1303                         status = AST_OSP_FAILED;
1304                 } else {
1305                         status = AST_OSP_ERROR;
1306                 }
1307         }
1308
1309         pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
1310         ast_log(LOG_DEBUG, "OSPNext: OSPTECH '%s'\n", result.tech);
1311         pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
1312         ast_log(LOG_DEBUG, "OSPNext: OSPDEST '%s'\n", result.dest);
1313         pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
1314         ast_log(LOG_DEBUG, "OSPNext: OSPCALLING '%s'\n", result.calling);
1315         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
1316         ast_log(LOG_DEBUG, "OSPNext: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
1317         snprintf(buffer, sizeof(buffer), "%d", result.numresults);
1318         pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
1319         ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%s'\n", buffer);
1320         snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
1321         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
1322         ast_log(LOG_DEBUG, "OSPNext: OSPOUTTIMELIMIT '%s'\n", buffer);
1323         pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", status);
1324         ast_log(LOG_DEBUG, "OSPNext: %s\n", status);
1325
1326         if (!strcasecmp(result.tech, "SIP")) {
1327                 if (!ast_strlen_zero(result.token)) {
1328                         snprintf(buffer, sizeof(buffer), "P-OSP-Auth-Token: %s", result.token);
1329                         pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
1330                         ast_log(LOG_DEBUG, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
1331                 }
1332         } else if (!strcasecmp(result.tech, "H323")) {
1333         } else if (!strcasecmp(result.tech, "IAX")) {
1334         }
1335
1336         if(res <= 0) {
1337                 if (priority_jump || ast_opt_priority_jumping) {
1338                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1339                         res = 0;
1340                 } else {
1341                         res = -1;
1342                 }
1343         } else {
1344                 res = 0;
1345         }
1346
1347         LOCAL_USER_REMOVE(u);
1348
1349         return res;
1350 }
1351
1352 /*!
1353  * \brief OSP Application OSPFinish
1354  * \param chan Channel
1355  * \param data Parameter
1356  * \return 0 Success, -1 Failed
1357  */
1358 static int ospfinished_exec(struct ast_channel* chan, void* data)
1359 {
1360         int res = 1;
1361         struct localuser* u;
1362         int priority_jump = 0;
1363         int cause = 0;
1364         struct varshead* headp;
1365         struct ast_var_t* current;
1366         int inhandle = OSP_INVALID_HANDLE;
1367         int outhandle = OSP_INVALID_HANDLE;
1368         int recorded = 0;
1369         time_t start, connect, end;
1370         unsigned int release;
1371         char buffer[OSP_INTSTR_SIZE];
1372         const char* status;
1373         char* tmp;
1374
1375         AST_DECLARE_APP_ARGS(args,
1376                 AST_APP_ARG(cause);
1377                 AST_APP_ARG(options);
1378         );
1379         
1380         LOCAL_USER_ADD(u);
1381
1382         if (!(tmp = ast_strdupa(data))) {
1383                 ast_log(LOG_ERROR, "Out of memory\n");
1384                 LOCAL_USER_REMOVE(u);
1385                 return -1;
1386         }
1387
1388         AST_STANDARD_APP_ARGS(args, tmp);
1389
1390         if ((args.options) && (strchr(args.options, 'j'))) {
1391                 priority_jump = 1;
1392         }
1393         ast_log(LOG_DEBUG, "OSPFinish: priority jump '%d'\n", priority_jump);
1394
1395         headp = &chan->varshead;
1396         AST_LIST_TRAVERSE(headp, current, entries) {
1397                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1398                         if (sscanf(ast_var_value(current), "%d", &inhandle) != 1) {
1399                                 inhandle = OSP_INVALID_HANDLE;
1400                         }
1401                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
1402                         if (sscanf(ast_var_value(current), "%d", &outhandle) != 1) {
1403                                 outhandle = OSP_INVALID_HANDLE;
1404                         }
1405                 } else if (!recorded &&
1406                         (!strcasecmp(ast_var_name(current), "OSPAUTHSTATUS") ||
1407                         !strcasecmp(ast_var_name(current), "OSPLOOKUPSTATUS") || 
1408                         !strcasecmp(ast_var_name(current), "OSPNEXTSTATUS"))) 
1409                 {
1410                         if (strcasecmp(ast_var_value(current), AST_OSP_SUCCESS)) {
1411                                 recorded = 1;
1412                         }
1413                 }
1414         }
1415         ast_log(LOG_DEBUG, "OSPFinish: OSPINHANDLE '%d'\n", inhandle);
1416         ast_log(LOG_DEBUG, "OSPFinish: OSPOUTHANDLE '%d'\n", outhandle);
1417         ast_log(LOG_DEBUG, "OSPFinish: recorded '%d'\n", recorded);
1418
1419         if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%d", &cause) != 1) {
1420                 cause = 0;
1421         }
1422         ast_log(LOG_DEBUG, "OSPFinish: cause '%d'\n", cause);
1423
1424         if (chan->cdr) {
1425                 start = chan->cdr->start.tv_sec;
1426                 connect = chan->cdr->answer.tv_sec;
1427                 if (connect) {
1428                         end = time(NULL);
1429                 } else {
1430                         end = connect;
1431                 }
1432         } else {
1433                 start = 0;
1434                 connect = 0;
1435                 end = 0;
1436         }
1437         ast_log(LOG_DEBUG, "OSPFinish: start '%ld'\n", start);
1438         ast_log(LOG_DEBUG, "OSPFinish: connect '%ld'\n", connect);
1439         ast_log(LOG_DEBUG, "OSPFinish: end '%ld'\n", end);
1440
1441         release = chan->_softhangup ? 0 : 1;
1442
1443         if (osp_finish(outhandle, recorded, cause, start, connect, end, release) <= 0) {
1444                 ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for outbound call\n");
1445         }
1446         switch (cause) {
1447                 case AST_CAUSE_NORMAL_CLEARING:
1448                         break;
1449                 default:
1450                         cause = AST_CAUSE_NO_ROUTE_DESTINATION;
1451                         break;
1452         }
1453         if (osp_finish(inhandle, recorded, cause, start, connect, end, release) <= 0) {
1454                 ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for inbound call\n");
1455         }
1456         snprintf(buffer, sizeof(buffer), "%d", OSP_INVALID_HANDLE);
1457         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
1458         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
1459
1460         if (res > 0) {
1461                 status = AST_OSP_SUCCESS;
1462         } else if (!res) {
1463                 status = AST_OSP_FAILED;
1464         } else {
1465                 status = AST_OSP_ERROR;
1466         }
1467         pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", status);
1468
1469         if(!res) {
1470                 if (priority_jump || ast_opt_priority_jumping) {
1471                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1472                         res = 0;
1473                 } else {
1474                         res = -1;
1475                 }
1476         } else {
1477                 res = 0;
1478         }
1479
1480         LOCAL_USER_REMOVE(u);
1481
1482         return res;
1483 }
1484
1485 /* OSP Module APIs */
1486
1487 static int osp_load(void)
1488 {
1489         char* t;
1490         unsigned int v;
1491         struct ast_config* cfg;
1492         int error = OSPC_ERR_NO_ERROR;
1493
1494         cfg = ast_config_load(OSP_CONFIG_FILE);
1495         if (cfg) {
1496                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "accelerate");
1497                 if (t && ast_true(t)) {
1498                         if ((error = OSPPInit(1)) != OSPC_ERR_NO_ERROR) {
1499                                 ast_log(LOG_WARNING, "OSP: Unable to enable hardware accelleration\n");
1500                                 OSPPInit(0);
1501                         } else {
1502                                 osp_hardware = 1;
1503                         }
1504                 } else {
1505                         OSPPInit(0);
1506                 }
1507                 ast_log(LOG_DEBUG, "OSP: osp_hardware '%d'\n", osp_hardware);
1508
1509                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat");
1510                 if (t) {
1511                         if ((sscanf(t, "%d", &v) == 1) && 
1512                                 ((v == TOKEN_ALGO_SIGNED) || (v == TOKEN_ALGO_UNSIGNED) || (v == TOKEN_ALGO_BOTH))) 
1513                         {
1514                                 osp_tokenformat = v;
1515                         } else {
1516                                 ast_log(LOG_WARNING, "tokenformat should be an integer from %d, %d or %d, not '%s'\n", 
1517                                         TOKEN_ALGO_SIGNED, TOKEN_ALGO_UNSIGNED, TOKEN_ALGO_BOTH, t);
1518                         }
1519                 }
1520                 ast_log(LOG_DEBUG, "OSP: osp_tokenformat '%d'\n", osp_tokenformat);
1521
1522                 t = ast_category_browse(cfg, NULL);
1523                 while(t) {
1524                         if (strcasecmp(t, OSP_GENERAL_CAT)) {
1525                                 osp_create_provider(cfg, t);
1526                         }
1527                         t = ast_category_browse(cfg, t);
1528                 }
1529
1530                 osp_initialized = 1;
1531
1532                 ast_config_destroy(cfg);
1533         } else {
1534                 ast_log(LOG_WARNING, "OSP: Unable to find configuration. OSP support disabled\n");
1535         }
1536         ast_log(LOG_DEBUG, "OSP: osp_initialized '%d'\n", osp_initialized);
1537
1538         return 0;
1539 }
1540
1541 static int osp_unload(void)
1542 {
1543         struct osp_provider* p;
1544         struct osp_provider* next;
1545
1546         if (osp_initialized) {
1547                 ast_mutex_lock(&osplock);
1548                 p = ospproviders;
1549                 while(p) {
1550                         next = p->next;
1551                         OSPPProviderDelete(p->handle, 0);
1552                         free(p);
1553                         p = next;
1554                 }
1555                 ospproviders = NULL;
1556                 ast_mutex_unlock(&osplock);
1557
1558                 OSPPCleanup();
1559
1560                 osp_tokenformat = TOKEN_ALGO_SIGNED;
1561                 osp_hardware = 0;
1562                 osp_initialized = 0;
1563         }
1564         return 0;
1565 }
1566
1567 static int osp_show(int fd, int argc, char* argv[])
1568 {
1569         int i;
1570         int found = 0;
1571         struct osp_provider* p;
1572         const char* provider = NULL;
1573         const char* tokenalgo;
1574
1575         if ((argc < 2) || (argc > 3)) {
1576                 return RESULT_SHOWUSAGE;
1577         }
1578         if (argc > 2) {
1579                 provider = argv[2];
1580         }
1581         if (!provider) {
1582                 switch (osp_tokenformat) {
1583                         case TOKEN_ALGO_BOTH:
1584                                 tokenalgo = "Both";
1585                                 break;
1586                         case TOKEN_ALGO_UNSIGNED:
1587                                 tokenalgo = "Unsigned";
1588                                 break;
1589                         case TOKEN_ALGO_SIGNED:
1590                         default:
1591                                 tokenalgo = "Signed";
1592                                 break;
1593                 }
1594                 ast_cli(fd, "OSP: %s %s %s\n", 
1595                         osp_initialized ? "Initialized" : "Uninitialized", osp_hardware ? "Accelerated" : "Normal", tokenalgo);
1596         }
1597
1598         ast_mutex_lock(&osplock);
1599         p = ospproviders;
1600         while(p) {
1601                 if (!provider || !strcasecmp(p->name, provider)) {
1602                         if (found) {
1603                                 ast_cli(fd, "\n");
1604                         }
1605                         ast_cli(fd, " == OSP Provider '%s' == \n", p->name);
1606                         ast_cli(fd, "Local Private Key: %s\n", p->privatekey);
1607                         ast_cli(fd, "Local Certificate: %s\n", p->localcert);
1608                         for (i = 0; i < p->cacount; i++) {
1609                                 ast_cli(fd, "CA Certificate %d:  %s\n", i + 1, p->cacerts[i]);
1610                         }
1611                         for (i = 0; i < p->spcount; i++) {
1612                                 ast_cli(fd, "Service Point %d:   %s\n", i + 1, p->srvpoints[i]);
1613                         }
1614                         ast_cli(fd, "Max Connections:   %d\n", p->maxconnections);
1615                         ast_cli(fd, "Retry Delay:       %d seconds\n", p->retrydelay);
1616                         ast_cli(fd, "Retry Limit:       %d\n", p->retrylimit);
1617                         ast_cli(fd, "Timeout:           %d milliseconds\n", p->timeout);
1618                         ast_cli(fd, "Source:            %s\n", strlen(p->source) ? p->source : "<unspecified>");
1619                         ast_cli(fd, "Auth Policy        %d\n", p->authpolicy);
1620                         ast_cli(fd, "OSP Handle:        %d\n", p->handle);
1621                         found++;
1622                 }
1623                 p = p->next;
1624         }
1625         ast_mutex_unlock(&osplock);
1626
1627         if (!found) {
1628                 if (provider) {
1629                         ast_cli(fd, "Unable to find OSP provider '%s'\n", provider);
1630                 } else {
1631                         ast_cli(fd, "No OSP providers configured\n");
1632                 }
1633         }
1634         return RESULT_SUCCESS;
1635 }
1636
1637 static const char* app1= "OSPAuth";
1638 static const char* synopsis1 = "OSP authentication";
1639 static const char* descrip1 = 
1640 "  OSPAuth([provider[|options]]):  Authenticate a SIP INVITE by OSP and sets\n"
1641 "the variables:\n"
1642 " ${OSPINHANDLE}:  The inbound call transaction handle\n"
1643 " ${OSPINTIMELIMIT}:  The inbound call duration limit in seconds\n"
1644 "\n"
1645 "The option string may contain the following character:\n"
1646 "       'j' -- jump to n+101 priority if the authentication was NOT successful\n"
1647 "This application sets the following channel variable upon completion:\n"
1648 "       OSPAUTHSTATUS   The status of the OSP Auth attempt as a text string, one of\n"
1649 "               SUCCESS | FAILED | ERROR\n";
1650
1651 static const char* app2= "OSPLookup";
1652 static const char* synopsis2 = "Lookup destination by OSP";
1653 static const char* descrip2 = 
1654 "  OSPLookup(exten[|provider[|options]]):  Looks up an extension via OSP and sets\n"
1655 "the variables, where 'n' is the number of the result beginning with 1:\n"
1656 " ${OSPOUTHANDLE}:  The OSP Handle for anything remaining\n"
1657 " ${OSPTECH}:  The technology to use for the call\n"
1658 " ${OSPDEST}:  The destination to use for the call\n"
1659 " ${OSPCALLING}:  The calling number to use for the call\n"
1660 " ${OSPOUTTOKEN}:  The actual OSP token as a string\n"
1661 " ${OSPOUTTIMELIMIT}:  The outbound call duration limit in seconds\n"
1662 " ${OSPRESULTS}:  The number of OSP results total remaining\n"
1663 "\n"
1664 "The option string may contain the following character:\n"
1665 "       'j' -- jump to n+101 priority if the lookup was NOT successful\n"
1666 "This application sets the following channel variable upon completion:\n"
1667 "       OSPLOOKUPSTATUS The status of the OSP Lookup attempt as a text string, one of\n"
1668 "               SUCCESS | FAILED | ERROR\n";
1669
1670 static const char* app3 = "OSPNext";
1671 static const char* synopsis3 = "Lookup next destination by OSP";
1672 static const char* descrip3 = 
1673 "  OSPNext(cause[|options]):  Looks up the next OSP Destination for ${OSPOUTHANDLE}\n"
1674 "See OSPLookup for more information\n"
1675 "\n"
1676 "The option string may contain the following character:\n"
1677 "       'j' -- jump to n+101 priority if the lookup was NOT successful\n"
1678 "This application sets the following channel variable upon completion:\n"
1679 "       OSPNEXTSTATUS   The status of the OSP Next attempt as a text string, one of\n"
1680 "               SUCCESS | FAILED |ERROR\n";
1681
1682 static const char* app4 = "OSPFinish";
1683 static const char* synopsis4 = "Record OSP entry";
1684 static const char* descrip4 = 
1685 "  OSPFinish([status[|options]]):  Records call state for ${OSPINHANDLE}, according to\n"
1686 "status, which should be one of BUSY, CONGESTION, ANSWER, NOANSWER, or CHANUNAVAIL\n"
1687 "or coincidentally, just what the Dial application stores in its ${DIALSTATUS}.\n"
1688 "\n"
1689 "The option string may contain the following character:\n"
1690 "       'j' -- jump to n+101 priority if the finish attempt was NOT successful\n"
1691 "This application sets the following channel variable upon completion:\n"
1692 "       OSPFINISHSTATUS The status of the OSP Finish attempt as a text string, one of\n"
1693 "               SUCCESS | FAILED |ERROR \n";
1694
1695 static const char osp_usage[] =
1696 "Usage: osp show\n"
1697 "       Displays information on Open Settlement Protocol support\n";
1698
1699 static struct ast_cli_entry osp_cli = {
1700         {"osp", "show", NULL}, 
1701         osp_show, 
1702         "Displays OSP information", 
1703         osp_usage 
1704 };
1705
1706 LOCAL_USER_DECL;
1707
1708 static int load_module(void* mod)
1709 {
1710         int res;
1711         
1712         osp_load();
1713         res = ast_cli_register(&osp_cli);
1714         res |= ast_register_application(app1, ospauth_exec, synopsis1, descrip1);
1715         res |= ast_register_application(app2, osplookup_exec, synopsis2, descrip2);
1716         res |= ast_register_application(app3, ospnext_exec, synopsis3, descrip3);
1717         res |= ast_register_application(app4, ospfinished_exec, synopsis4, descrip4);
1718
1719         return res;
1720 }
1721
1722 static int unload_module(void* mod)
1723 {
1724         int res;
1725         
1726         res = ast_unregister_application(app4);
1727         res |= ast_unregister_application(app3);
1728         res |= ast_unregister_application(app2);
1729         res |= ast_unregister_application(app1);
1730         res |= ast_cli_unregister(&osp_cli);
1731         osp_unload();
1732
1733         STANDARD_HANGUP_LOCALUSERS;
1734
1735         return res;
1736 }
1737
1738 static int reload(void* mod)
1739 {
1740         osp_unload();
1741         osp_load();
1742         return 0;
1743 }
1744
1745 static const char* description(void)
1746 {
1747         return "Open Settlement Protocol Applications";
1748 }
1749
1750 static const char* key(void)
1751 {
1752         return ASTERISK_GPL_KEY;
1753 }
1754
1755 STD_MOD(MOD_1, reload, NULL, NULL);