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