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