Creating new doxygen macro "\extref" to create page that lists
[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  * \extref The OSP Toolkit: http://www.transnexus.com
26  * \extref OpenSSL http://www.openssl.org
27  *
28  * \ingroup applications
29  */
30
31 /*** MODULEINFO
32         <depend>osptk</depend>
33         <depend>ssl</depend>
34  ***/
35
36 #include "asterisk.h"
37
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39
40 #include <sys/types.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <errno.h>
45 #include <osp/osp.h>
46 #include <osp/osputils.h>
47
48 #include "asterisk/lock.h"
49 #include "asterisk/config.h"
50 #include "asterisk/utils.h"
51 #include "asterisk/causes.h"
52 #include "asterisk/channel.h"
53 #include "asterisk/app.h"
54 #include "asterisk/module.h"
55 #include "asterisk/pbx.h"
56 #include "asterisk/options.h"
57 #include "asterisk/cli.h"
58 #include "asterisk/logger.h"
59 #include "asterisk/astosp.h"
60
61 /* OSP Buffer Sizes */
62 #define OSP_INTSTR_SIZE         ((unsigned int)16)              /* OSP signed/unsigned int string buffer size */
63 #define OSP_NORSTR_SIZE         ((unsigned int)256)             /* OSP normal string buffer size */
64 #define OSP_TOKSTR_SIZE         ((unsigned int)4096)    /* OSP token string buffer size */
65 #define OSP_TECHSTR_SIZE        ((unsigned int)32)              /* OSP signed/unsigned int string buffer size */
66 #define OSP_UUID_SIZE           ((unsigned int)16)              /* UUID size */
67 #define OSP_UUIDSTR_SIZE        ((unsigned int)36)              /* UUID string size */
68
69 /* OSP Authentication Policy */
70 enum osp_authpolicy {
71         OSP_AUTH_NO,            /* Accept any call */
72         OSP_AUTH_YES,           /* Accept call with valid OSP token or without OSP token */
73         OSP_AUTH_EXCLUSIVE      /* Only accept call with valid OSP token */
74 };
75
76 /* Call ID type*/
77 #define OSP_CALLID_UNDEFINED    ((unsigned int)0)                       /* UNDEFINED */
78 #define OSP_CALLID_H323                 ((unsigned int)(1 << 0))        /* H.323 */
79 #define OSP_CALLID_SIP                  ((unsigned int)(1 << 1))        /* SIP */
80 #define OSP_CALLID_IAX                  ((unsigned int)(1 << 2))        /* IAX2 */
81 #define OSP_CALLID_MAXNUM               ((unsigned int)3)                       /* Max number of call ID type */
82
83 /* OSP Supported Destination Protocols */
84 #define OSP_PROT_H323                   ((char*)"H323")                         /* H323 Q931 protocol name*/
85 #define OSP_PROT_SIP                    ((char*)"SIP")                          /* SIP protocol name */
86 #define OSP_PROT_IAX                    ((char*)"IAX")                          /* IAX protocol name */
87 #define OSP_PROT_OTHER                  ((char*)"OTHER")                        /* Other protocol name */
88
89 /* OSP supported Destination Tech */
90 #if 0
91 #define OSP_TECH_H323                   ((char*)"OOH323")                       /* OOH323 tech name */
92 #endif
93 #define OSP_TECH_H323                   ((char*)"H323")                         /* OH323 tech name */
94 #define OSP_TECH_SIP                    ((char*)"SIP")                          /* SIP tech name */
95 #define OSP_TECH_IAX                    ((char*)"IAX2")                         /* IAX2 tech name */
96
97 /* SIP OSP header field name */
98 #define OSP_SIP_HEADER                  ((char*)"P-OSP-Auth-Token: ")
99
100 /* OSP Constants */
101 #define OSP_INVALID_HANDLE              ((int)-1)                                       /* Invalid OSP handle, provider, transaction etc. */
102 #define OSP_CONFIG_FILE                 ((const char*)"osp.conf")       /* OSP configuration file name */
103 #define OSP_GENERAL_CAT                 ((const char*)"general")        /* OSP global configuration context name */
104 #define OSP_DEF_PROVIDER                ((const char*)"default")        /* OSP default provider context name */
105 #define OSP_MAX_CERTS                   ((unsigned int)10)                      /* OSP max number of cacerts */
106 #define OSP_MAX_SRVS                    ((unsigned int)10)                      /* OSP max number of service points */
107 #define OSP_DEF_MAXCONNECTIONS  ((unsigned int)20)                      /* OSP default max_connections */
108 #define OSP_MIN_MAXCONNECTIONS  ((unsigned int)1)                       /* OSP min max_connections */
109 #define OSP_MAX_MAXCONNECTIONS  ((unsigned int)1000)            /* OSP max max_connections */
110 #define OSP_DEF_RETRYDELAY              ((unsigned int)0)                       /* OSP default retry delay */
111 #define OSP_MIN_RETRYDELAY              ((unsigned int)0)                       /* OSP min retry delay */
112 #define OSP_MAX_RETRYDELAY              ((unsigned int)10)                      /* OSP max retry delay */
113 #define OSP_DEF_RETRYLIMIT              ((unsigned int)2)                       /* OSP default retry times */
114 #define OSP_MIN_RETRYLIMIT              ((unsigned int)0)                       /* OSP min retry times */
115 #define OSP_MAX_RETRYLIMIT              ((unsigned int)100)                     /* OSP max retry times */
116 #define OSP_DEF_TIMEOUT                 ((unsigned int)500)                     /* OSP default timeout in ms */
117 #define OSP_MIN_TIMEOUT                 ((unsigned int)200)                     /* OSP min timeout in ms */
118 #define OSP_MAX_TIMEOUT                 ((unsigned int)10000)           /* OSP max timeout in ms */
119 #define OSP_DEF_AUTHPOLICY              ((enum osp_authpolicy)OSP_AUTH_YES)
120 #define OSP_AUDIT_URL                   ((const char*)"localhost")      /* OSP default Audit URL */
121 #define OSP_LOCAL_VALIDATION    ((int)1)                                        /* Validate OSP token locally */
122 #define OSP_SSL_LIFETIME                ((unsigned int)300)                     /* SSL life time, in seconds */
123 #define OSP_HTTP_PERSISTENCE    ((int)1)                                        /* In seconds */
124 #define OSP_CUSTOMER_ID                 ((const char*)"")                       /* OSP customer ID */
125 #define OSP_DEVICE_ID                   ((const char*)"")                       /* OSP device ID */
126 #define OSP_DEF_DESTINATIONS    ((unsigned int)5)                       /* OSP default max number of destinations */
127 #define OSP_DEF_TIMELIMIT               ((unsigned int)0)                       /* OSP default duration limit, no limit */
128 #define OSP_DEF_PROTOCOL                OSP_PROT_SIP                            /* OSP default destination protocol, SIP */
129
130 /* OSP Provider */
131 struct osp_provider {
132         char name[OSP_NORSTR_SIZE];                                             /* OSP provider context name */
133         char privatekey[OSP_NORSTR_SIZE];                               /* OSP private key file name */
134         char localcert[OSP_NORSTR_SIZE];                                /* OSP local cert file name */
135         unsigned int cacount;                                                   /* Number of cacerts */
136         char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE];   /* Cacert file names */
137         unsigned int spcount;                                                   /* Number of service points */
138         char srvpoints[OSP_MAX_SRVS][OSP_NORSTR_SIZE];  /* Service point URLs */
139         int maxconnections;                                                             /* Max number of connections */
140         int retrydelay;                                                                 /* Retry delay */
141         int retrylimit;                                                                 /* Retry limit */
142         int timeout;                                                                    /* Timeout in ms */
143         char source[OSP_NORSTR_SIZE];                                   /* IP of self */
144         enum osp_authpolicy authpolicy;                                 /* OSP authentication policy */
145         char* defaultprotocol;                                                  /* OSP default destination protocol */
146         OSPTPROVHANDLE handle;                                                  /* OSP provider handle */
147         struct osp_provider* next;                                              /* Pointer to next OSP provider */
148 };
149
150 /* Call ID */
151 struct osp_callid {
152         unsigned char buf[OSPC_CALLID_MAXSIZE];         /* Call ID string */
153         unsigned int len;                                       /* Call ID length */
154 };
155
156 /* OSP Application In/Output Results */
157 struct osp_result {
158         int inhandle;                                           /* Inbound transaction handle */
159         int outhandle;                                          /* Outbound transaction handle */
160         unsigned int intimelimit;                       /* Inbound duration limit */
161         unsigned int outtimelimit;                      /* Outbound duration limit */
162         char tech[OSP_TECHSTR_SIZE];            /* Outbound Asterisk TECH string */
163         char dest[OSP_NORSTR_SIZE];                     /* Outbound destination IP address */
164         char called[OSP_NORSTR_SIZE];           /* Outbound called number, may be translated */
165         char calling[OSP_NORSTR_SIZE];          /* Outbound calling number, may be translated */
166         char token[OSP_TOKSTR_SIZE];            /* Outbound OSP token */
167         char networkid[OSP_NORSTR_SIZE];        /* Outbound network ID */
168         unsigned int numresults;                        /* Number of remain outbound destinations */
169         struct osp_callid outcallid;            /* Outbound call ID */
170 };
171
172 /* OSP Module Global Variables */
173 AST_MUTEX_DEFINE_STATIC(osplock);                                                       /* Lock of OSP provider list */
174 static int osp_initialized = 0;                                                         /* Init flag */
175 static int osp_hardware = 0;                                                            /* Hardware accelleration flag */
176 static struct osp_provider* ospproviders = NULL;                        /* OSP provider list */
177 static unsigned int osp_tokenformat = TOKEN_ALGO_SIGNED;        /* Token format supported */
178
179 /* OSP Client Wrapper APIs */
180
181 /*!
182  * \brief Create OSP provider handle according to configuration
183  * \param cfg OSP configuration
184  * \param provider OSP provider context name
185  * \return 1 Success, 0 Failed, -1 Error
186  */
187 static int osp_create_provider(
188         struct ast_config* cfg,
189         const char* provider)
190 {
191         int res;
192         unsigned int t, i, j;
193         struct osp_provider* p;
194         struct ast_variable* v;
195         OSPTPRIVATEKEY privatekey;
196         OSPTCERT localcert;
197         const char* psrvpoints[OSP_MAX_SRVS];
198         OSPTCERT cacerts[OSP_MAX_CERTS];
199         const OSPTCERT* pcacerts[OSP_MAX_CERTS];
200         int error = OSPC_ERR_NO_ERROR;
201
202         if (!(p = ast_calloc(1, sizeof(*p)))) {
203                 ast_log(LOG_ERROR, "Out of memory\n");
204                 return -1;
205         }
206
207         ast_copy_string(p->name, provider, sizeof(p->name));
208         snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, provider);
209         snprintf(p->localcert, sizeof(p->localcert), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, provider);
210         p->maxconnections = OSP_DEF_MAXCONNECTIONS;
211         p->retrydelay = OSP_DEF_RETRYDELAY;
212         p->retrylimit = OSP_DEF_RETRYLIMIT;
213         p->timeout = OSP_DEF_TIMEOUT;
214         p->authpolicy = OSP_DEF_AUTHPOLICY;
215         p->defaultprotocol = OSP_DEF_PROTOCOL;
216         p->handle = OSP_INVALID_HANDLE;
217
218         v = ast_variable_browse(cfg, provider);
219         while(v) {
220                 if (!strcasecmp(v->name, "privatekey")) {
221                         if (v->value[0] == '/') {
222                                 ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey));
223                         } else {
224                                 snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value);
225                         }
226                         if (option_debug)
227                                 ast_log(LOG_DEBUG, "OSP: privatekey '%s'\n", p->privatekey);
228                 } else if (!strcasecmp(v->name, "localcert")) {
229                         if (v->value[0] == '/') {
230                                 ast_copy_string(p->localcert, v->value, sizeof(p->localcert));
231                         } else {
232                                 snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
233                         }
234                         if (option_debug)
235                                 ast_log(LOG_DEBUG, "OSP: localcert '%s'\n", p->localcert);
236                 } else if (!strcasecmp(v->name, "cacert")) {
237                         if (p->cacount < OSP_MAX_CERTS) {
238                                 if (v->value[0] == '/') {
239                                         ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0]));
240                                 } else {
241                                         snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
242                                 }
243                                 if (option_debug)
244                                         ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
245                                 p->cacount++;
246                         } else {
247                                 ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno);
248                         }
249                 } else if (!strcasecmp(v->name, "servicepoint")) {
250                         if (p->spcount < OSP_MAX_SRVS) {
251                                 ast_copy_string(p->srvpoints[p->spcount], v->value, sizeof(p->srvpoints[0]));
252                                 if (option_debug)
253                                         ast_log(LOG_DEBUG, "OSP: servicepoint[%d]: '%s'\n", p->spcount, p->srvpoints[p->spcount]);
254                                 p->spcount++;
255                         } else {
256                                 ast_log(LOG_WARNING, "OSP: Too many Service Points at line %d\n", v->lineno);
257                         }
258                 } else if (!strcasecmp(v->name, "maxconnections")) {
259                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_MAXCONNECTIONS) && (t <= OSP_MAX_MAXCONNECTIONS)) {
260                                 p->maxconnections = t;
261                                 if (option_debug)
262                                         ast_log(LOG_DEBUG, "OSP: maxconnections '%d'\n", t);
263                         } else {
264                                 ast_log(LOG_WARNING, "OSP: maxconnections should be an integer from %d to %d, not '%s' at line %d\n",
265                                         OSP_MIN_MAXCONNECTIONS, OSP_MAX_MAXCONNECTIONS, v->value, v->lineno);
266                         }
267                 } else if (!strcasecmp(v->name, "retrydelay")) {
268                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYDELAY) && (t <= OSP_MAX_RETRYDELAY)) {
269                                 p->retrydelay = t;
270                                 if (option_debug)
271                                         ast_log(LOG_DEBUG, "OSP: retrydelay '%d'\n", t);
272                         } else {
273                                 ast_log(LOG_WARNING, "OSP: retrydelay should be an integer from %d to %d, not '%s' at line %d\n",
274                                         OSP_MIN_RETRYDELAY, OSP_MAX_RETRYDELAY, v->value, v->lineno);
275                         }
276                 } else if (!strcasecmp(v->name, "retrylimit")) {
277                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYLIMIT) && (t <= OSP_MAX_RETRYLIMIT)) {
278                                 p->retrylimit = t;
279                                 if (option_debug)
280                                         ast_log(LOG_DEBUG, "OSP: retrylimit '%d'\n", t);
281                         } else {
282                                 ast_log(LOG_WARNING, "OSP: retrylimit should be an integer from %d to %d, not '%s' at line %d\n",
283                                         OSP_MIN_RETRYLIMIT, OSP_MAX_RETRYLIMIT, v->value, v->lineno);
284                         }
285                 } else if (!strcasecmp(v->name, "timeout")) {
286                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_TIMEOUT) && (t <= OSP_MAX_TIMEOUT)) {
287                                 p->timeout = t;
288                                 if (option_debug)
289                                         ast_log(LOG_DEBUG, "OSP: timeout '%d'\n", t);
290                         } else {
291                                 ast_log(LOG_WARNING, "OSP: timeout should be an integer from %d to %d, not '%s' at line %d\n",
292                                         OSP_MIN_TIMEOUT, OSP_MAX_TIMEOUT, v->value, v->lineno);
293                         }
294                 } else if (!strcasecmp(v->name, "source")) {
295                         ast_copy_string(p->source, v->value, sizeof(p->source));
296                         if (option_debug)
297                                 ast_log(LOG_DEBUG, "OSP: source '%s'\n", p->source);
298                 } else if (!strcasecmp(v->name, "authpolicy")) {
299                         if ((sscanf(v->value, "%d", &t) == 1) && ((t == OSP_AUTH_NO) || (t == OSP_AUTH_YES) || (t == OSP_AUTH_EXCLUSIVE))) {
300                                 p->authpolicy = t;
301                                 if (option_debug)
302                                         ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", t);
303                         } else {
304                                 ast_log(LOG_WARNING, "OSP: authpolicy should be %d, %d or %d, not '%s' at line %d\n",
305                                         OSP_AUTH_NO, OSP_AUTH_YES, OSP_AUTH_EXCLUSIVE, v->value, v->lineno);
306                         }
307                 } else if (!strcasecmp(v->name, "defaultprotocol")) {
308                         if (!strcasecmp(v->value, OSP_PROT_SIP)) {
309                                 p->defaultprotocol = OSP_PROT_SIP;
310                                 if (option_debug)
311                                         ast_log(LOG_DEBUG, "OSP: default protocol '%s'\n", p->defaultprotocol);
312                         } else if (!strcasecmp(v->value, OSP_PROT_H323)) {
313                                 p->defaultprotocol = OSP_PROT_H323;
314                                 if (option_debug)
315                                         ast_log(LOG_DEBUG, "OSP: default protocol '%s'\n", p->defaultprotocol);
316                         } else if (!strcasecmp(v->value, OSP_PROT_IAX)) {
317                                 p->defaultprotocol = OSP_PROT_IAX;
318                                 if (option_debug)
319                                         ast_log(LOG_DEBUG, "OSP: default protocol '%s'\n", p->defaultprotocol);
320                         } else {
321                                 ast_log(LOG_WARNING, "OSP: default protocol should be %s, %s, %s, or %s not '%s' at line %d\n",
322                                         OSP_PROT_SIP, OSP_PROT_H323, OSP_PROT_IAX, OSP_PROT_OTHER, v->value, v->lineno);
323                         }
324                 }
325                 v = v->next;
326         }
327
328         error = OSPPUtilLoadPEMPrivateKey((unsigned char*)p->privatekey, &privatekey);
329         if (error != OSPC_ERR_NO_ERROR) {
330                 ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s', error '%d'\n", p->privatekey, error);
331                 free(p);
332                 return 0;
333         }
334
335         error = OSPPUtilLoadPEMCert((unsigned char*)p->localcert, &localcert);
336         if (error != OSPC_ERR_NO_ERROR) {
337                 ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s', error '%d'\n", p->localcert, error);
338                 if (privatekey.PrivateKeyData) {
339                         free(privatekey.PrivateKeyData);
340                 }
341                 free(p);
342                 return 0;
343         }
344
345         if (p->cacount < 1) {
346                 snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, provider);
347                 if (option_debug)
348                         ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
349                 p->cacount++;
350         }
351         for (i = 0; i < p->cacount; i++) {
352                 error = OSPPUtilLoadPEMCert((unsigned char*)p->cacerts[i], &cacerts[i]);
353                 if (error != OSPC_ERR_NO_ERROR) {
354                         ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s', error '%d'\n", p->cacerts[i], error);
355                         for (j = 0; j < i; j++) {
356                                 if (cacerts[j].CertData) {
357                                         free(cacerts[j].CertData);
358                                 }
359                         }
360                         if (localcert.CertData) {
361                                 free(localcert.CertData);
362                         }
363                         if (privatekey.PrivateKeyData) {
364                                 free(privatekey.PrivateKeyData);
365                         }
366                         free(p);
367                         return 0;
368                 }
369                 pcacerts[i] = &cacerts[i];
370         }
371
372         for (i = 0; i < p->spcount; i++) {
373                 psrvpoints[i] = p->srvpoints[i];
374         }
375
376         error = OSPPProviderNew(
377                                 p->spcount,
378                                 psrvpoints,
379                                 NULL,
380                                 OSP_AUDIT_URL,
381                                 &privatekey,
382                                 &localcert,
383                                 p->cacount,
384                                 pcacerts,
385                                 OSP_LOCAL_VALIDATION,
386                                 OSP_SSL_LIFETIME,
387                                 p->maxconnections,
388                                 OSP_HTTP_PERSISTENCE,
389                                 p->retrydelay,
390                                 p->retrylimit,
391                                 p->timeout,
392                                 OSP_CUSTOMER_ID,
393                                 OSP_DEVICE_ID,
394                                 &p->handle);
395         if (error != OSPC_ERR_NO_ERROR) {
396                 ast_log(LOG_WARNING, "OSP: Unable to create provider '%s', error '%d'\n", provider, error);
397                 free(p);
398                 res = -1;
399         } else {
400                 if (option_debug)
401                         ast_log(LOG_DEBUG, "OSP: provider '%s'\n", provider);
402                 ast_mutex_lock(&osplock);
403                 p->next = ospproviders;
404                 ospproviders = p;
405                 ast_mutex_unlock(&osplock);
406                 res = 1;
407         }
408
409         for (i = 0; i < p->cacount; i++) {
410                 if (cacerts[i].CertData) {
411                         free(cacerts[i].CertData);
412                 }
413         }
414         if (localcert.CertData) {
415                 free(localcert.CertData);
416         }
417         if (privatekey.PrivateKeyData) {
418                 free(privatekey.PrivateKeyData);
419         }
420
421         return res;
422 }
423
424 /*!
425  * \brief Get OSP provider by name
426  * \param name OSP provider context name
427  * \param provider OSP provider structure
428  * \return 1 Success, 0 Failed, -1 Error
429  */
430 static int osp_get_provider(
431         const char* name,
432         struct osp_provider** provider)
433 {
434         int res = 0;
435         struct osp_provider* p;
436
437         ast_mutex_lock(&osplock);
438         p = ospproviders;
439         while(p) {
440                 if (!strcasecmp(p->name, name)) {
441                         *provider = p;
442                         if (option_debug)
443                                 ast_log(LOG_DEBUG, "OSP: find provider '%s'\n", name);
444                         res = 1;
445                         break;
446                 }
447                 p = p->next;
448         }
449         ast_mutex_unlock(&osplock);
450
451         return res;
452 }
453
454 /*!
455  * \brief Create OSP transaction handle
456  * \param provider OSP provider context name
457  * \param transaction OSP transaction handle, output
458  * \param sourcesize Size of source buffer, in/output
459  * \param source Source of provider, output
460  * \return 1 Success, 0 Failed, -1 Error
461  */
462 static int osp_create_transaction(
463         const char* provider,
464         int* transaction,
465         unsigned int sourcesize,
466         char* source)
467 {
468         int res = 0;
469         struct osp_provider* p;
470         int error;
471
472         ast_mutex_lock(&osplock);
473         p = ospproviders;
474         while(p) {
475                 if (!strcasecmp(p->name, provider)) {
476                         error = OSPPTransactionNew(p->handle, transaction);
477                         if (error == OSPC_ERR_NO_ERROR) {
478                                 if (option_debug)
479                                         ast_log(LOG_DEBUG, "OSP: transaction '%d'\n", *transaction);
480                                 ast_copy_string(source, p->source, sourcesize);
481                                 if (option_debug)
482                                         ast_log(LOG_DEBUG, "OSP: source '%s'\n", source);
483                                 res = 1;
484                         } else {
485                                 *transaction = OSP_INVALID_HANDLE;
486                                 if (option_debug)
487                                         ast_log(LOG_DEBUG, "OSP: Unable to create transaction handle, error '%d'\n", error);
488                                 res = -1;
489                         }
490                         break;
491                 }
492                 p = p->next;
493         }
494         ast_mutex_unlock(&osplock);
495
496         return res;
497 }
498
499 /*!
500  * \brief Convert address to "[x.x.x.x]" or "host.domain" format
501  * \param src Source address string
502  * \param dst Destination address string
503  * \param buffersize Size of dst buffer
504  */
505 static void osp_convert_address(
506         const char* src,
507         char* dst,
508         int buffersize)
509 {
510         struct in_addr inp;
511
512         if (inet_aton(src, &inp) != 0) {
513                 snprintf(dst, buffersize, "[%s]", src);
514         } else {
515                 snprintf(dst, buffersize, "%s", src);
516         }
517 }
518
519 /*!
520  * \brief Validate OSP token of inbound call
521  * \param transaction OSP transaction handle
522  * \param source Source of inbound call
523  * \param destination Destination of inbound call
524  * \param calling Calling number
525  * \param called Called number
526  * \param token OSP token, may be empty
527  * \param timelimit Call duration limit, output
528  * \return 1 Success, 0 Failed, -1 Error
529  */
530 static int osp_validate_token(
531         int transaction,
532         const char* source,
533         const char* destination,
534         const char* calling,
535         const char* called,
536         const char* token,
537         unsigned int* timelimit)
538 {
539         int res;
540         int tokenlen;
541         unsigned char tokenstr[OSP_TOKSTR_SIZE];
542         char src[OSP_TOKSTR_SIZE];
543         char dst[OSP_TOKSTR_SIZE];
544         unsigned int authorised;
545         unsigned int dummy = 0;
546         int error;
547
548         tokenlen = ast_base64decode(tokenstr, token, strlen(token));
549         osp_convert_address(source, src, sizeof(src));
550         osp_convert_address(destination, dst, sizeof(dst));
551         error = OSPPTransactionValidateAuthorisation(
552                                 transaction,
553                                 src,
554                                 dst,
555                                 NULL,
556                                 NULL,
557                                 calling ? calling : "",
558                                 OSPC_E164,
559                                 called,
560                                 OSPC_E164,
561                                 0,
562                                 NULL,
563                                 tokenlen,
564                                 (char*)tokenstr,
565                                 &authorised,
566                                 timelimit,
567                                 &dummy,
568                                 NULL,
569                                 osp_tokenformat);
570         if (error != OSPC_ERR_NO_ERROR) {
571                 if (option_debug)
572                         ast_log(LOG_DEBUG, "OSP: Unable to validate inbound token\n");
573                 res = -1;
574         } else if (authorised) {
575                 if (option_debug)
576                         ast_log(LOG_DEBUG, "OSP: Authorised\n");
577                 res = 1;
578         } else {
579                 if (option_debug)
580                         ast_log(LOG_DEBUG, "OSP: Unauthorised\n");
581                 res = 0;
582         }
583
584         return res;
585 }
586
587 /*!
588  * \brief Choose min duration limit
589  * \param in Inbound duration limit
590  * \param out Outbound duration limit
591  * \return min duration limit
592  */
593 static unsigned int osp_choose_timelimit(
594         unsigned int in,
595         unsigned int out)
596 {
597         if (in == OSP_DEF_TIMELIMIT) {
598                 return out;
599         } else if (out == OSP_DEF_TIMELIMIT) {
600                 return in;
601         } else {
602                 return in < out ? in : out;
603         }
604 }
605
606 /*!
607  * \brief Choose min duration limit
608  * \param provider OSP provider
609  * \param called Called number
610  * \param calling Calling number
611  * \param destination Destination IP in '[x.x.x.x]' format
612  * \param tokenlen OSP token length
613  * \param token OSP token
614  * \param reason Failure reason, output
615  * \param result OSP lookup results, in/output
616  * \return 1 Success, 0 Failed, -1 Error
617  */
618 static int osp_check_destination(
619         struct osp_provider* provider,
620         const char* called,
621         const char* calling,
622         char* destination,
623         unsigned int tokenlen,
624         const char* token,
625         enum OSPEFAILREASON* reason,
626         struct osp_result* result)
627 {
628         int res;
629         OSPE_DEST_OSP_ENABLED enabled;
630         OSPE_DEST_PROT protocol;
631         int error;
632
633         if (strlen(destination) <= 2) {
634                 if (option_debug)
635                         ast_log(LOG_DEBUG, "OSP: Wrong destination format '%s'\n", destination);
636                 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
637                 return -1;
638         }
639
640         if ((error = OSPPTransactionIsDestOSPEnabled(result->outhandle, &enabled)) != OSPC_ERR_NO_ERROR) {
641                 if (option_debug)
642                         ast_log(LOG_DEBUG, "OSP: Unable to get destination OSP version, error '%d'\n", error);
643                 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
644                 return -1;
645         }
646
647         if (enabled == OSPE_OSP_FALSE) {
648                 result->token[0] = '\0';
649         } else {
650                 ast_base64encode(result->token, (const unsigned char*)token, tokenlen, sizeof(result->token) - 1);
651         }
652
653         if ((error = OSPPTransactionGetDestNetworkId(result->outhandle, result->networkid)) != OSPC_ERR_NO_ERROR) {
654                 if (option_debug)
655                         ast_log(LOG_DEBUG, "OSP: Unable to get destination network ID, error '%d'\n", error);
656                 result->networkid[0] = '\0';
657         }
658
659         if ((error = OSPPTransactionGetDestProtocol(result->outhandle, &protocol)) != OSPC_ERR_NO_ERROR) {
660                 if (option_debug)
661                         ast_log(LOG_DEBUG, "OSP: Unable to get destination protocol, error '%d'\n", error);
662                 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
663                 result->token[0] = '\0';
664                 result->networkid[0] = '\0';
665                 return -1;
666         }
667
668         res = 1;
669         /* Strip leading and trailing brackets */
670         destination[strlen(destination) - 1] = '\0';
671         switch(protocol) {
672                 case OSPE_DEST_PROT_H323_SETUP:
673                         if (option_debug)
674                                 ast_log(LOG_DEBUG, "OSP: protocol '%s'\n", OSP_PROT_H323);
675                         ast_copy_string(result->tech, OSP_TECH_H323, sizeof(result->tech));
676                         ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
677                         ast_copy_string(result->called, called, sizeof(result->called));
678                         ast_copy_string(result->calling, calling, sizeof(result->calling));
679                         break;
680                 case OSPE_DEST_PROT_SIP:
681                         if (option_debug)
682                                 ast_log(LOG_DEBUG, "OSP: protocol '%s'\n", OSP_PROT_SIP);
683                         ast_copy_string(result->tech, OSP_TECH_SIP, sizeof(result->tech));
684                         ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
685                         ast_copy_string(result->called, called, sizeof(result->called));
686                         ast_copy_string(result->calling, calling, sizeof(result->calling));
687                         break;
688                 case OSPE_DEST_PROT_IAX:
689                         if (option_debug)
690                                 ast_log(LOG_DEBUG, "OSP: protocol '%s'\n", OSP_PROT_IAX);
691                         ast_copy_string(result->tech, OSP_TECH_IAX, sizeof(result->tech));
692                         ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
693                         ast_copy_string(result->called, called, sizeof(result->called));
694                         ast_copy_string(result->calling, calling, sizeof(result->calling));
695                         break;
696                 case OSPE_DEST_PROT_UNDEFINED:
697                 case OSPE_DEST_PROT_UNKNOWN:
698                         if (option_debug) {
699                                 ast_log(LOG_DEBUG, "OSP: unknown/undefined protocol '%d'\n", protocol);
700                                 ast_log(LOG_DEBUG, "OSP: use default protocol '%s'\n", provider->defaultprotocol);
701                         }
702                         ast_copy_string(result->tech, provider->defaultprotocol, sizeof(result->tech));
703                         ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
704                         ast_copy_string(result->called, called, sizeof(result->called));
705                         ast_copy_string(result->calling, calling, sizeof(result->calling));
706                         break;
707                 case OSPE_DEST_PROT_H323_LRQ:
708                 default:
709                         ast_log(LOG_WARNING, "OSP: unsupported protocol '%d'\n", protocol);
710                         *reason = OSPC_FAIL_PROTOCOL_ERROR;
711                         result->token[0] = '\0';
712                         result->networkid[0] = '\0';
713                         res = 0;
714                         break;
715         }
716
717         return res;
718 }
719
720 /*!
721  * \brief Convert Asterisk status to TC code
722  * \param cause Asterisk hangup cause
723  * \return OSP TC code
724  */
725 static enum OSPEFAILREASON asterisk2osp(
726         int cause)
727 {
728         return (enum OSPEFAILREASON)cause;
729 }
730
731 /*!
732  * \brief OSP Authentication function
733  * \param provider OSP provider context name
734  * \param transaction OSP transaction handle, output
735  * \param source Source of inbound call
736  * \param calling Calling number
737  * \param called Called number
738  * \param token OSP token, may be empty
739  * \param timelimit Call duration limit, output
740  * \return 1 Authenricated, 0 Unauthenticated, -1 Error
741  */
742 static int osp_auth(
743         const char* provider,
744         int* transaction,
745         const char* source,
746         const char* calling,
747         const char* called,
748         const char* token,
749         unsigned int* timelimit)
750 {
751         int res;
752         struct osp_provider* p;
753         char dest[OSP_NORSTR_SIZE];
754
755         *transaction = OSP_INVALID_HANDLE;
756         *timelimit = OSP_DEF_TIMELIMIT;
757
758         if ((res = osp_get_provider(provider, &p)) <= 0) {
759                 if (option_debug)
760                         ast_log(LOG_DEBUG, "OSP: Unabe to find OSP provider '%s'\n", provider);
761                 return res;
762         }
763
764         switch (p->authpolicy) {
765                 case OSP_AUTH_NO:
766                         res = 1;
767                         break;
768                 case OSP_AUTH_EXCLUSIVE:
769                         if (ast_strlen_zero(token)) {
770                                 res = 0;
771                         } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
772                                 if (option_debug)
773                                         ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
774                                 *transaction = OSP_INVALID_HANDLE;
775                                 res = 0;
776                         } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
777                                 OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
778                         }
779                         break;
780                 case OSP_AUTH_YES:
781                 default:
782                         if (ast_strlen_zero(token)) {
783                                 res = 1;
784                         } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
785                                 if (option_debug)
786                                         ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
787                                 *transaction = OSP_INVALID_HANDLE;
788                                 res = 0;
789                         } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
790                                 OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
791                         }
792                         break;
793         }
794
795         return res;
796 }
797
798 /*!
799  * \brief Create a UUID
800  * \param uuid UUID buffer
801  * \param buffersize UUID buffer size
802  * \return 1 Created, -1 Error
803  */
804 static int osp_create_uuid(
805         unsigned char* uuid,
806         unsigned int* buffersize)
807 {
808         int i, res;
809         long int* tmp;
810
811         if (*buffersize >= OSP_UUID_SIZE) {
812                 tmp = (long int*)uuid;
813                 for (i = 0; i < OSP_UUID_SIZE / sizeof(long int); i++) {
814                         tmp[i] = ast_random();
815                 }
816                 *buffersize = OSP_UUID_SIZE;
817                 res = 1;
818         } else {
819                 res = -1;
820         }
821
822         return res;
823 }
824
825 /*!
826  * \brief UUID to string
827  * \param uuid UUID
828  * \param buffer String buffer
829  * \param buffersize String buffer size
830  * \return 1 Successed, -1 Error
831  */
832 static int osp_uuid2str(
833         unsigned char* uuid,
834         char* buffer,
835         unsigned int buffersize)
836 {
837         int res;
838
839         if (buffersize > OSP_UUIDSTR_SIZE) {
840                 snprintf(buffer, buffersize, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
841                         uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
842                         uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
843                 res = 1;
844         } else {
845                 res = -1;
846         }
847
848         return res;
849 }
850
851 /*!
852  * \brief Create a call ID according to the type
853  * \param type Call ID type
854  * \param callid Call ID buffer
855  * \return 1 Created, 0 Not create, -1 Error
856  */
857 static int osp_create_callid(
858         unsigned int type,
859         struct osp_callid* callid)
860 {
861         int res;
862
863         callid->len = sizeof(callid->buf);
864         switch (type) {
865                 case OSP_CALLID_H323:
866                         res = osp_create_uuid(callid->buf, &callid->len);
867                         break;
868                 case OSP_CALLID_SIP:
869                 case OSP_CALLID_IAX:
870                         res = 0;
871                 default:
872                         res = -1;
873                         break;
874         }
875
876         if ((res != 1) && (callid->len != 0)) {
877                 callid->buf[0] = '\0';
878                 callid->len = 0;
879         }
880
881         return res;
882 }
883
884 /*!
885  * \brief OSP Lookup function
886  * \param provider OSP provider context name
887  * \param srcdev Source device of outbound call
888  * \param calling Calling number
889  * \param called Called number
890  * \param callidtypes Call ID types
891  * \param result Lookup results
892  * \return 1 Found , 0 No route, -1 Error
893  */
894 static int osp_lookup(
895         const char* provider,
896         const char* srcdev,
897         const char* calling,
898         const char* called,
899         unsigned int callidtypes,
900         struct osp_result* result)
901 {
902         int res;
903         struct osp_provider* p;
904         char source[OSP_NORSTR_SIZE];
905         char callingnum[OSP_NORSTR_SIZE];
906         char callednum[OSP_NORSTR_SIZE];
907         char destination[OSP_NORSTR_SIZE];
908         unsigned int tokenlen;
909         char token[OSP_TOKSTR_SIZE];
910         char src[OSP_NORSTR_SIZE];
911         char dev[OSP_NORSTR_SIZE];
912         unsigned int i, type;
913         struct osp_callid callid;
914         unsigned int callidnum;
915         OSPTCALLID* callids[OSP_CALLID_MAXNUM];
916         unsigned int dummy = 0;
917         enum OSPEFAILREASON reason;
918         int error;
919
920         result->outhandle = OSP_INVALID_HANDLE;
921         result->tech[0] = '\0';
922         result->dest[0] = '\0';
923         result->called[0] = '\0';
924         result->calling[0] = '\0';
925         result->token[0] = '\0';
926         result->networkid[0] = '\0';
927         result->numresults = 0;
928         result->outtimelimit = OSP_DEF_TIMELIMIT;
929
930         if ((res = osp_get_provider(provider, &p)) <= 0) {
931                 if (option_debug)
932                         ast_log(LOG_DEBUG, "OSP: Unabe to find OSP provider '%s'\n", provider);
933                 return res;
934         }
935
936         if ((res = osp_create_transaction(provider, &result->outhandle, sizeof(source), source)) <= 0) {
937                 if (option_debug)
938                         ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
939                 result->outhandle = OSP_INVALID_HANDLE;
940                 if (result->inhandle != OSP_INVALID_HANDLE) {
941                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
942                 }
943                 return -1;
944         }
945
946         callidnum = 0;
947         callids[0] = NULL;
948         for (i = 0; i < OSP_CALLID_MAXNUM; i++) {
949                 type = 1 << i;
950                 if (callidtypes & type) {
951                         error = osp_create_callid(type, &callid);
952                         if (error == 1) {
953                                 callids[callidnum] = OSPPCallIdNew(callid.len, callid.buf);
954                                 callidnum++;
955                         }
956                 }
957         }
958
959         osp_convert_address(source, src, sizeof(src));
960         osp_convert_address(srcdev, dev, sizeof(dev));
961         result->numresults = OSP_DEF_DESTINATIONS;
962         error = OSPPTransactionRequestAuthorisation(
963                                 result->outhandle,
964                                 src,
965                                 dev,
966                                 calling ? calling : "",
967                                 OSPC_E164,
968                                 called,
969                                 OSPC_E164,
970                                 NULL,
971                                 callidnum,
972                                 callids,
973                                 NULL,
974                                 &result->numresults,
975                                 &dummy,
976                                 NULL);
977
978         for (i = 0; i < callidnum; i++) {
979                 OSPPCallIdDelete(&callids[i]);
980         }
981
982         if (error != OSPC_ERR_NO_ERROR) {
983                 if (option_debug)
984                         ast_log(LOG_DEBUG, "OSP: Unable to request authorization\n");
985                 result->numresults = 0;
986                 if (result->inhandle != OSP_INVALID_HANDLE) {
987                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
988                 }
989                 return -1;
990         }
991
992         if (!result->numresults) {
993                 if (option_debug)
994                         ast_log(LOG_DEBUG, "OSP: No more destination\n");
995                 if (result->inhandle != OSP_INVALID_HANDLE) {
996                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
997                 }
998                 return 0;
999         }
1000
1001         result->outcallid.len = sizeof(result->outcallid.buf);
1002         tokenlen = sizeof(token);
1003         error = OSPPTransactionGetFirstDestination(
1004                                 result->outhandle,
1005                                 0,
1006                                 NULL,
1007                                 NULL,
1008                                 &result->outtimelimit,
1009                                 &result->outcallid.len,
1010                                 result->outcallid.buf,
1011                                 sizeof(callednum),
1012                                 callednum,
1013                                 sizeof(callingnum),
1014                                 callingnum,
1015                                 sizeof(destination),
1016                                 destination,
1017                                 0,
1018                                 NULL,
1019                                 &tokenlen,
1020                                 token);
1021         if (error != OSPC_ERR_NO_ERROR) {
1022                 if (option_debug)
1023                         ast_log(LOG_DEBUG, "OSP: Unable to get first route\n");
1024                 result->numresults = 0;
1025                 result->outtimelimit = OSP_DEF_TIMELIMIT;
1026                 if (result->inhandle != OSP_INVALID_HANDLE) {
1027                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1028                 }
1029                 return -1;
1030         }
1031
1032         result->numresults--;
1033         result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
1034         if (option_debug) {
1035                 ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
1036                 ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
1037                 ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
1038                 ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
1039                 ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
1040         }
1041
1042         if ((res = osp_check_destination(p, callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
1043                 return 1;
1044         }
1045
1046         if (!result->numresults) {
1047                 if (option_debug)
1048                         ast_log(LOG_DEBUG, "OSP: No more destination\n");
1049                 result->outtimelimit = OSP_DEF_TIMELIMIT;
1050                 OSPPTransactionRecordFailure(result->outhandle, reason);
1051                 if (result->inhandle != OSP_INVALID_HANDLE) {
1052                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1053                 }
1054                 return 0;
1055         }
1056
1057         while(result->numresults) {
1058                 result->outcallid.len = sizeof(result->outcallid.buf);
1059                 tokenlen = sizeof(token);
1060                 error = OSPPTransactionGetNextDestination(
1061                                         result->outhandle,
1062                                         reason,
1063                                         0,
1064                                         NULL,
1065                                         NULL,
1066                                         &result->outtimelimit,
1067                                         &result->outcallid.len,
1068                                         result->outcallid.buf,
1069                                         sizeof(callednum),
1070                                         callednum,
1071                                         sizeof(callingnum),
1072                                         callingnum,
1073                                         sizeof(destination),
1074                                         destination,
1075                                         0,
1076                                         NULL,
1077                                         &tokenlen,
1078                                         token);
1079                 if (error == OSPC_ERR_NO_ERROR) {
1080                         result->numresults--;
1081                         result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
1082                         if (option_debug) {
1083                                 ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
1084                                 ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
1085                                 ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
1086                                 ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
1087                                 ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
1088                         }
1089                         if ((res = osp_check_destination(p, callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
1090                                 break;
1091                         } else if (!result->numresults) {
1092                                 if (option_debug)
1093                                         ast_log(LOG_DEBUG, "OSP: No more destination\n");
1094                                 OSPPTransactionRecordFailure(result->outhandle, reason);
1095                                 if (result->inhandle != OSP_INVALID_HANDLE) {
1096                                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1097                                 }
1098                                 res = 0;
1099                                 break;
1100                         }
1101                 } else {
1102                         if (option_debug)
1103                                 ast_log(LOG_DEBUG, "OSP: Unable to get route, error '%d'\n", error);
1104                         result->numresults = 0;
1105                         result->outtimelimit = OSP_DEF_TIMELIMIT;
1106                         if (result->inhandle != OSP_INVALID_HANDLE) {
1107                                 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1108                         }
1109                         res = -1;
1110                         break;
1111                 }
1112         }
1113         return res;
1114 }
1115
1116 /*!
1117  * \brief OSP Lookup Next function
1118  * \param cause Asterisk hangup cuase
1119  * \param result Lookup results, in/output
1120  * \return 1 Found , 0 No route, -1 Error
1121  */
1122 static int osp_next(
1123         const char* provider,
1124         int cause,
1125         struct osp_result* result)
1126 {
1127         int res;
1128         struct osp_provider* p;
1129         char callingnum[OSP_NORSTR_SIZE];
1130         char callednum[OSP_NORSTR_SIZE];
1131         char destination[OSP_NORSTR_SIZE];
1132         unsigned int tokenlen;
1133         char token[OSP_TOKSTR_SIZE];
1134         enum OSPEFAILREASON reason;
1135         int error;
1136
1137         result->tech[0] = '\0';
1138         result->dest[0] = '\0';
1139         result->called[0] = '\0';
1140         result->calling[0] = '\0';
1141         result->token[0] = '\0';
1142         result->networkid[0] = '\0';
1143         result->outtimelimit = OSP_DEF_TIMELIMIT;
1144
1145         if ((res = osp_get_provider(provider, &p)) <= 0) {
1146                 if (option_debug)
1147                         ast_log(LOG_DEBUG, "OSP: Unabe to find OSP provider '%s'\n", provider);
1148                 return res;
1149         }
1150
1151         if (result->outhandle == OSP_INVALID_HANDLE) {
1152                 if (option_debug)
1153                         ast_log(LOG_DEBUG, "OSP: Transaction handle undefined\n");
1154                 result->numresults = 0;
1155                 if (result->inhandle != OSP_INVALID_HANDLE) {
1156                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1157                 }
1158                 return -1;
1159         }
1160
1161         reason = asterisk2osp(cause);
1162
1163         if (!result->numresults) {
1164                 if (option_debug)
1165                         ast_log(LOG_DEBUG, "OSP: No more destination\n");
1166                 OSPPTransactionRecordFailure(result->outhandle, reason);
1167                 if (result->inhandle != OSP_INVALID_HANDLE) {
1168                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1169                 }
1170                 return 0;
1171         }
1172
1173         while(result->numresults) {
1174                 result->outcallid.len = sizeof(result->outcallid.buf);
1175                 tokenlen = sizeof(token);
1176                 error = OSPPTransactionGetNextDestination(
1177                                         result->outhandle,
1178                                         reason,
1179                                         0,
1180                                         NULL,
1181                                         NULL,
1182                                         &result->outtimelimit,
1183                                         &result->outcallid.len,
1184                                         result->outcallid.buf,
1185                                         sizeof(callednum),
1186                                         callednum,
1187                                         sizeof(callingnum),
1188                                         callingnum,
1189                                         sizeof(destination),
1190                                         destination,
1191                                         0,
1192                                         NULL,
1193                                         &tokenlen,
1194                                         token);
1195                 if (error == OSPC_ERR_NO_ERROR) {
1196                         result->numresults--;
1197                         result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
1198                         if (option_debug) {
1199                                 ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
1200                                 ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
1201                                 ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
1202                                 ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
1203                                 ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
1204                         }
1205                         if ((res = osp_check_destination(p, callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
1206                                 res = 1;
1207                                 break;
1208                         } else if (!result->numresults) {
1209                                 if (option_debug)
1210                                         ast_log(LOG_DEBUG, "OSP: No more destination\n");
1211                                 OSPPTransactionRecordFailure(result->outhandle, reason);
1212                                 if (result->inhandle != OSP_INVALID_HANDLE) {
1213                                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1214                                 }
1215                                 res = 0;
1216                                 break;
1217                         }
1218                 } else {
1219                         if (option_debug)
1220                                 ast_log(LOG_DEBUG, "OSP: Unable to get route, error '%d'\n", error);
1221                         result->token[0] = '\0';
1222                         result->numresults = 0;
1223                         result->outtimelimit = OSP_DEF_TIMELIMIT;
1224                         if (result->inhandle != OSP_INVALID_HANDLE) {
1225                                 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1226                         }
1227                         res = -1;
1228                         break;
1229                 }
1230         }
1231
1232         return res;
1233 }
1234
1235 /*!
1236  * \brief OSP Finish function
1237  * \param handle OSP in/outbound transaction handle
1238  * \param recorded If failure reason has been recorded
1239  * \param cause Asterisk hangup cause
1240  * \param start Call start time
1241  * \param connect Call connect time
1242  * \param end Call end time
1243  * \param release Who release first, 0 source, 1 destination
1244  * \return 1 Success, 0 Failed, -1 Error
1245  */
1246 static int osp_finish(
1247         int handle,
1248         int recorded,
1249         int cause,
1250         time_t start,
1251         time_t connect,
1252         time_t end,
1253         unsigned int release)
1254 {
1255         int res;
1256         enum OSPEFAILREASON reason;
1257         time_t alert = 0;
1258         unsigned isPddInfoPresent = 0;
1259         unsigned pdd = 0;
1260         unsigned int dummy = 0;
1261         int error;
1262
1263         if (handle == OSP_INVALID_HANDLE) {
1264                 return 0;
1265         }
1266
1267         if (!recorded) {
1268                 reason = asterisk2osp(cause);
1269                 OSPPTransactionRecordFailure(handle, reason);
1270         }
1271
1272         error = OSPPTransactionReportUsage(
1273                                 handle,
1274                                 difftime(end, connect),
1275                                 start,
1276                                 end,
1277                                 alert,
1278                                 connect,
1279                                 isPddInfoPresent,
1280                                 pdd,
1281                                 release,
1282                                 (unsigned char*)"",
1283                                 0,
1284                                 0,
1285                                 0,
1286                                 0,
1287                                 &dummy,
1288                                 NULL);
1289         if (error == OSPC_ERR_NO_ERROR) {
1290                 if (option_debug)
1291                         ast_log(LOG_DEBUG, "OSP: Usage reported\n");
1292                 res = 1;
1293         } else {
1294                 if (option_debug)
1295                         ast_log(LOG_DEBUG, "OSP: Unable to report usage, error '%d'\n", error);
1296                 res = -1;
1297         }
1298         OSPPTransactionDelete(handle);
1299
1300         return res;
1301 }
1302
1303 /* OSP Application APIs */
1304
1305 /*!
1306  * \brief OSP Application OSPAuth
1307  * \param chan Channel
1308  * \param data Parameter
1309  * \return 0 Success, -1 Failed
1310  */
1311 static int ospauth_exec(
1312         struct ast_channel* chan,
1313         void* data)
1314 {
1315         int res;
1316         struct ast_module_user* u;
1317         const char* provider = OSP_DEF_PROVIDER;
1318         int priority_jump = 0;
1319         struct varshead* headp;
1320         struct ast_var_t* current;
1321         const char* source = "";
1322         const char* token = "";
1323         int handle;
1324         unsigned int timelimit;
1325         char buffer[OSP_INTSTR_SIZE];
1326         const char* status;
1327         char* tmp;
1328
1329         AST_DECLARE_APP_ARGS(args,
1330                 AST_APP_ARG(provider);
1331                 AST_APP_ARG(options);
1332         );
1333
1334         u = ast_module_user_add(chan);
1335
1336         if (!(tmp = ast_strdupa(data))) {
1337                 ast_log(LOG_ERROR, "Out of memory\n");
1338                 ast_module_user_remove(u);
1339                 return -1;
1340         }
1341
1342         AST_STANDARD_APP_ARGS(args, tmp);
1343
1344         if (!ast_strlen_zero(args.provider)) {
1345                 provider = args.provider;
1346         }
1347         if (option_debug)
1348                 ast_log(LOG_DEBUG, "OSPAuth: provider '%s'\n", provider);
1349
1350         if ((args.options) && (strchr(args.options, 'j'))) {
1351                 priority_jump = 1;
1352         }
1353         if (option_debug)
1354                 ast_log(LOG_DEBUG, "OSPAuth: priority jump '%d'\n", priority_jump);
1355
1356         headp = &chan->varshead;
1357         AST_LIST_TRAVERSE(headp, current, entries) {
1358                 if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
1359                         source = ast_var_value(current);
1360                 } else if (!strcasecmp(ast_var_name(current), "OSPINTOKEN")) {
1361                         token = ast_var_value(current);
1362                 }
1363         }
1364
1365         if (option_debug) {
1366                 ast_log(LOG_DEBUG, "OSPAuth: source '%s'\n", source);
1367                 ast_log(LOG_DEBUG, "OSPAuth: token size '%zd'\n", strlen(token));
1368         }
1369
1370         if ((res = osp_auth(provider, &handle, source, chan->cid.cid_num, chan->exten, token, &timelimit)) > 0) {
1371                 status = AST_OSP_SUCCESS;
1372         } else {
1373                 timelimit = OSP_DEF_TIMELIMIT;
1374                 if (!res) {
1375                         status = AST_OSP_FAILED;
1376                 } else {
1377                         status = AST_OSP_ERROR;
1378                 }
1379         }
1380
1381         snprintf(buffer, sizeof(buffer), "%d", handle);
1382         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
1383         if (option_debug)
1384                 ast_log(LOG_DEBUG, "OSPAuth: OSPINHANDLE '%s'\n", buffer);
1385         snprintf(buffer, sizeof(buffer), "%d", timelimit);
1386         pbx_builtin_setvar_helper(chan, "OSPINTIMELIMIT", buffer);
1387         if (option_debug)
1388                 ast_log(LOG_DEBUG, "OSPAuth: OSPINTIMELIMIT '%s'\n", buffer);
1389         pbx_builtin_setvar_helper(chan, "OSPAUTHSTATUS", status);
1390         if (option_debug)
1391                 ast_log(LOG_DEBUG, "OSPAuth: %s\n", status);
1392
1393         if(res <= 0) {
1394                 if (priority_jump || ast_opt_priority_jumping) {
1395                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1396                         res = 0;
1397                 } else {
1398                         res = -1;
1399                 }
1400         } else {
1401                 res = 0;
1402         }
1403
1404         ast_module_user_remove(u);
1405
1406         return res;
1407 }
1408
1409 /*!
1410  * \brief OSP Application OSPLookup
1411  * \param chan Channel
1412  * \param data Parameter
1413  * \return 0 Success, -1 Failed
1414  */
1415 static int osplookup_exec(
1416         struct ast_channel* chan,
1417         void* data)
1418 {
1419         int res, cres;
1420         struct ast_module_user* u;
1421         const char* provider = OSP_DEF_PROVIDER;
1422         int priority_jump = 0;
1423         struct varshead* headp;
1424         struct ast_var_t* current;
1425         const char* srcdev = "";
1426         const char* netid = "";
1427         char buffer[OSP_TOKSTR_SIZE];
1428         unsigned int callidtypes = OSP_CALLID_UNDEFINED;
1429         struct osp_result result;
1430         const char* status;
1431         char* tmp;
1432
1433         AST_DECLARE_APP_ARGS(args,
1434                 AST_APP_ARG(exten);
1435                 AST_APP_ARG(provider);
1436                 AST_APP_ARG(options);
1437         );
1438
1439         if (ast_strlen_zero(data)) {
1440                 ast_log(LOG_WARNING, "OSPLookup: Arg required, OSPLookup(exten[|provider[|options]])\n");
1441                 return -1;
1442         }
1443
1444         u = ast_module_user_add(chan);
1445
1446         if (!(tmp = ast_strdupa(data))) {
1447                 ast_log(LOG_ERROR, "Out of memory\n");
1448                 ast_module_user_remove(u);
1449                 return -1;
1450         }
1451
1452         AST_STANDARD_APP_ARGS(args, tmp);
1453
1454         if (option_debug)
1455                 ast_log(LOG_DEBUG, "OSPLookup: exten '%s'\n", args.exten);
1456
1457         if (!ast_strlen_zero(args.provider)) {
1458                 provider = args.provider;
1459         }
1460         if (option_debug)
1461                 ast_log(LOG_DEBUG, "OSPlookup: provider '%s'\n", provider);
1462
1463         if (args.options) {
1464                 if (strchr(args.options, 'j')) {
1465                         priority_jump = 1;
1466                 }
1467                 if (strchr(args.options, 'h')) {
1468                         callidtypes |= OSP_CALLID_H323;
1469                 }
1470                 if (strchr(args.options, 's')) {
1471                         callidtypes |= OSP_CALLID_SIP;
1472                 }
1473                 if (strchr(args.options, 'i')) {
1474                         callidtypes |= OSP_CALLID_IAX;
1475                 }
1476         }
1477         if (option_debug) {
1478                 ast_log(LOG_DEBUG, "OSPLookup: priority jump '%d'\n", priority_jump);
1479                 ast_log(LOG_DEBUG, "OSPLookup: call id types '%d'\n", callidtypes);
1480         }
1481
1482         result.inhandle = OSP_INVALID_HANDLE;
1483         result.intimelimit = OSP_DEF_TIMELIMIT;
1484
1485         headp = &chan->varshead;
1486         AST_LIST_TRAVERSE(headp, current, entries) {
1487                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1488                         if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
1489                                 result.inhandle = OSP_INVALID_HANDLE;
1490                         }
1491                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
1492                         if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
1493                                 result.intimelimit = OSP_DEF_TIMELIMIT;
1494                         }
1495                 } else if (!strcasecmp(ast_var_name(current), "OSPINNETWORKID")) {
1496                         netid = ast_var_value(current);
1497                 } else if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
1498                         srcdev = ast_var_value(current);
1499                 }
1500         }
1501         if (option_debug) {
1502                 ast_log(LOG_DEBUG, "OSPLookup: OSPINHANDLE '%d'\n", result.inhandle);
1503                 ast_log(LOG_DEBUG, "OSPLookup: OSPINTIMELIMIT '%d'\n", result.intimelimit);
1504                 ast_log(LOG_DEBUG, "OSPLookup: OSPINNETWORKID '%s'\n", netid);
1505                 ast_log(LOG_DEBUG, "OSPLookup: source device '%s'\n", srcdev);
1506         }
1507
1508         if ((cres = ast_autoservice_start(chan)) < 0) {
1509                 ast_module_user_remove(u);
1510                 return -1;
1511         }
1512
1513         if ((res = osp_lookup(provider, srcdev, chan->cid.cid_num, args.exten, callidtypes, &result)) > 0) {
1514                 status = AST_OSP_SUCCESS;
1515         } else {
1516                 result.tech[0] = '\0';
1517                 result.dest[0] = '\0';
1518                 result.called[0] = '\0';
1519                 result.calling[0] = '\0';
1520                 result.token[0] = '\0';
1521                 result.networkid[0] = '\0';
1522                 result.numresults = 0;
1523                 result.outtimelimit = OSP_DEF_TIMELIMIT;
1524                 result.outcallid.buf[0] = '\0';
1525                 result.outcallid.len = 0;
1526                 if (!res) {
1527                         status = AST_OSP_FAILED;
1528                 } else {
1529                         status = AST_OSP_ERROR;
1530                 }
1531         }
1532
1533         snprintf(buffer, sizeof(buffer), "%d", result.outhandle);
1534         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
1535         if (option_debug)
1536                 ast_log(LOG_DEBUG, "OSPLookup: OSPOUTHANDLE '%s'\n", buffer);
1537         pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
1538         if (option_debug)
1539                 ast_log(LOG_DEBUG, "OSPLookup: OSPTECH '%s'\n", result.tech);
1540         pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
1541         if (option_debug)
1542                 ast_log(LOG_DEBUG, "OSPLookup: OSPDEST '%s'\n", result.dest);
1543         pbx_builtin_setvar_helper(chan, "OSPCALLED", result.called);
1544         if (option_debug)
1545                 ast_log(LOG_DEBUG, "OSPLookup: OSPCALLED '%s'\n", result.called);
1546         pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
1547         if (option_debug)
1548                 ast_log(LOG_DEBUG, "OSPLookup: OSPCALLING '%s'\n", result.calling);
1549         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
1550         if (option_debug)
1551                 ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
1552         snprintf(buffer, sizeof(buffer), "%d", result.numresults);
1553         pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
1554         if (option_debug)
1555                 ast_log(LOG_DEBUG, "OSPLookup: OSPRESULTS '%s'\n", buffer);
1556         snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
1557         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
1558         if (option_debug)
1559                 ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTIMELIMIT '%s'\n", buffer);
1560         snprintf(buffer, sizeof(buffer), "%d", callidtypes);
1561         pbx_builtin_setvar_helper(chan, "OSPOUTCALLIDTYPES", buffer);
1562         if (option_debug)
1563                 ast_log(LOG_DEBUG, "OSPLookup: OSPOUTCALLIDTYPES '%s'\n", buffer);
1564         pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", status);
1565         if (option_debug)
1566                 ast_log(LOG_DEBUG, "OSPLookup: %s\n", status);
1567
1568         if (!strcasecmp(result.tech, OSP_TECH_H323)) {
1569                 if ((callidtypes & OSP_CALLID_H323) && (result.outcallid.len != 0)) {
1570                         osp_uuid2str(result.outcallid.buf, buffer, sizeof(buffer));
1571                 } else {
1572                         buffer[0] = '\0';
1573                 }
1574                 pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
1575                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1576                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1577         } else if (!strcasecmp(result.tech, OSP_TECH_SIP)) {
1578                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1579                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1580                 if (!ast_strlen_zero(result.token)) {
1581                         snprintf(buffer, sizeof(buffer), "%s%s", OSP_SIP_HEADER, result.token);
1582                         pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
1583                         if (option_debug)
1584                                 ast_log(LOG_DEBUG, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
1585                 }
1586         } else if (!strcasecmp(result.tech, OSP_TECH_IAX)) {
1587                 snprintf(buffer, sizeof(buffer), "%s/%s/%s", result.tech, result.dest, result.called);
1588                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1589         }
1590
1591         if ((cres = ast_autoservice_stop(chan)) < 0) {
1592                 ast_module_user_remove(u);
1593                 return -1;
1594         }
1595
1596         if(res <= 0) {
1597                 if (priority_jump || ast_opt_priority_jumping) {
1598                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1599                         res = 0;
1600                 } else {
1601                         res = -1;
1602                 }
1603         } else {
1604                 res = 0;
1605         }
1606
1607         ast_module_user_remove(u);
1608
1609         return res;
1610 }
1611
1612 /*!
1613  * \brief OSP Application OSPNext
1614  * \param chan Channel
1615  * \param data Parameter
1616  * \return 0 Success, -1 Failed
1617  */
1618 static int ospnext_exec(
1619         struct ast_channel* chan,
1620         void* data)
1621 {
1622         int res;
1623         struct ast_module_user* u;
1624         const char* provider = OSP_DEF_PROVIDER;
1625         int priority_jump = 0;
1626         int cause = 0;
1627         struct varshead* headp;
1628         struct ast_var_t* current;
1629         struct osp_result result;
1630         char buffer[OSP_TOKSTR_SIZE];
1631         unsigned int callidtypes = OSP_CALLID_UNDEFINED;
1632         const char* status;
1633         char* tmp;
1634
1635         AST_DECLARE_APP_ARGS(args,
1636                 AST_APP_ARG(cause);
1637                 AST_APP_ARG(provider);
1638                 AST_APP_ARG(options);
1639         );
1640
1641         if (ast_strlen_zero(data)) {
1642                 ast_log(LOG_WARNING, "OSPNext: Arg required, OSPNext(cause[|provider[|options]])\n");
1643                 return -1;
1644         }
1645
1646         u = ast_module_user_add(chan);
1647
1648         if (!(tmp = ast_strdupa(data))) {
1649                 ast_log(LOG_ERROR, "Out of memory\n");
1650                 ast_module_user_remove(u);
1651                 return -1;
1652         }
1653
1654         AST_STANDARD_APP_ARGS(args, tmp);
1655
1656         if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%d", &cause) != 1) {
1657                 cause = 0;
1658         }
1659         if (option_debug)
1660                 ast_log(LOG_DEBUG, "OSPNext: cause '%d'\n", cause);
1661
1662         if (!ast_strlen_zero(args.provider)) {
1663                 provider = args.provider;
1664         }
1665         if (option_debug)
1666                 ast_log(LOG_DEBUG, "OSPlookup: provider '%s'\n", provider);
1667
1668         if ((args.options) && (strchr(args.options, 'j'))) {
1669                 priority_jump = 1;
1670         }
1671         if (option_debug)
1672                 ast_log(LOG_DEBUG, "OSPNext: priority jump '%d'\n", priority_jump);
1673
1674         result.inhandle = OSP_INVALID_HANDLE;
1675         result.outhandle = OSP_INVALID_HANDLE;
1676         result.intimelimit = OSP_DEF_TIMELIMIT;
1677         result.numresults = 0;
1678
1679         headp = &chan->varshead;
1680         AST_LIST_TRAVERSE(headp, current, entries) {
1681                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1682                         if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
1683                                 result.inhandle = OSP_INVALID_HANDLE;
1684                         }
1685                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
1686                         if (sscanf(ast_var_value(current), "%d", &result.outhandle) != 1) {
1687                                 result.outhandle = OSP_INVALID_HANDLE;
1688                         }
1689                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
1690                         if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
1691                                 result.intimelimit = OSP_DEF_TIMELIMIT;
1692                         }
1693                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTCALLIDTYPES")) {
1694                         if (sscanf(ast_var_value(current), "%d", &callidtypes) != 1) {
1695                                 callidtypes = OSP_CALLID_UNDEFINED;
1696                         }
1697                 } else if (!strcasecmp(ast_var_name(current), "OSPRESULTS")) {
1698                         if (sscanf(ast_var_value(current), "%d", &result.numresults) != 1) {
1699                                 result.numresults = 0;
1700                         }
1701                 }
1702         }
1703         if (option_debug) {
1704                 ast_log(LOG_DEBUG, "OSPNext: OSPINHANDLE '%d'\n", result.inhandle);
1705                 ast_log(LOG_DEBUG, "OSPNext: OSPOUTHANDLE '%d'\n", result.outhandle);
1706                 ast_log(LOG_DEBUG, "OSPNext: OSPINTIMELIMIT '%d'\n", result.intimelimit);
1707                 ast_log(LOG_DEBUG, "OSPNext: OSPOUTCALLIDTYPES '%d'\n", callidtypes);
1708                 ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%d'\n", result.numresults);
1709         }
1710
1711         if ((res = osp_next(provider, cause, &result)) > 0) {
1712                 status = AST_OSP_SUCCESS;
1713         } else {
1714                 result.tech[0] = '\0';
1715                 result.dest[0] = '\0';
1716                 result.called[0] = '\0';
1717                 result.calling[0] = '\0';
1718                 result.token[0] = '\0';
1719                 result.networkid[0] = '\0';
1720                 result.numresults = 0;
1721                 result.outtimelimit = OSP_DEF_TIMELIMIT;
1722                 result.outcallid.buf[0] = '\0';
1723                 result.outcallid.len = 0;
1724                 if (!res) {
1725                         status = AST_OSP_FAILED;
1726                 } else {
1727                         status = AST_OSP_ERROR;
1728                 }
1729         }
1730
1731         pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
1732         if (option_debug)
1733                 ast_log(LOG_DEBUG, "OSPNext: OSPTECH '%s'\n", result.tech);
1734         pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
1735         if (option_debug)
1736                 ast_log(LOG_DEBUG, "OSPNext: OSPDEST '%s'\n", result.dest);
1737         pbx_builtin_setvar_helper(chan, "OSPCALLED", result.called);
1738         if (option_debug)
1739                 ast_log(LOG_DEBUG, "OSPNext: OSPCALLED'%s'\n", result.called);
1740         pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
1741         if (option_debug)
1742                 ast_log(LOG_DEBUG, "OSPNext: OSPCALLING '%s'\n", result.calling);
1743         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
1744         if (option_debug)
1745                 ast_log(LOG_DEBUG, "OSPNext: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
1746         snprintf(buffer, sizeof(buffer), "%d", result.numresults);
1747         pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
1748         if (option_debug)
1749                 ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%s'\n", buffer);
1750         snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
1751         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
1752         if (option_debug)
1753                 ast_log(LOG_DEBUG, "OSPNext: OSPOUTTIMELIMIT '%s'\n", buffer);
1754         pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", status);
1755         if (option_debug)
1756                 ast_log(LOG_DEBUG, "OSPNext: %s\n", status);
1757
1758         if (!strcasecmp(result.tech, OSP_TECH_H323)) {
1759                 if ((callidtypes & OSP_CALLID_H323) && (result.outcallid.len != 0)) {
1760                         osp_uuid2str(result.outcallid.buf, buffer, sizeof(buffer));
1761                 } else {
1762                         buffer[0] = '\0';
1763                 }
1764                 pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
1765                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1766                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1767         } else if (!strcasecmp(result.tech, OSP_TECH_SIP)) {
1768                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1769                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1770                 if (!ast_strlen_zero(result.token)) {
1771                         snprintf(buffer, sizeof(buffer), "%s%s", OSP_SIP_HEADER, result.token);
1772                         pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
1773                         if (option_debug)
1774                                 ast_log(LOG_DEBUG, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
1775                 }
1776         } else if (!strcasecmp(result.tech, OSP_TECH_IAX)) {
1777                 snprintf(buffer, sizeof(buffer), "%s/%s/%s", result.tech, result.dest, result.called);
1778                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1779         }
1780
1781         if(res <= 0) {
1782                 if (priority_jump || ast_opt_priority_jumping) {
1783                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1784                         res = 0;
1785                 } else {
1786                         res = -1;
1787                 }
1788         } else {
1789                 res = 0;
1790         }
1791
1792         ast_module_user_remove(u);
1793
1794         return res;
1795 }
1796
1797 /*!
1798  * \brief OSP Application OSPFinish
1799  * \param chan Channel
1800  * \param data Parameter
1801  * \return 0 Success, -1 Failed
1802  */
1803 static int ospfinished_exec(
1804         struct ast_channel* chan,
1805         void* data)
1806 {
1807         int res = 1;
1808         struct ast_module_user* u;
1809         int priority_jump = 0;
1810         int cause = 0;
1811         struct varshead* headp;
1812         struct ast_var_t* current;
1813         int inhandle = OSP_INVALID_HANDLE;
1814         int outhandle = OSP_INVALID_HANDLE;
1815         int recorded = 0;
1816         time_t start, connect, end;
1817         unsigned int release;
1818         char buffer[OSP_INTSTR_SIZE];
1819         const char* status;
1820         char* tmp;
1821
1822         AST_DECLARE_APP_ARGS(args,
1823                 AST_APP_ARG(cause);
1824                 AST_APP_ARG(options);
1825         );
1826
1827         u = ast_module_user_add(chan);
1828
1829         if (!(tmp = ast_strdupa(data))) {
1830                 ast_log(LOG_ERROR, "Out of memory\n");
1831                 ast_module_user_remove(u);
1832                 return -1;
1833         }
1834
1835         AST_STANDARD_APP_ARGS(args, tmp);
1836
1837         if ((args.options) && (strchr(args.options, 'j'))) {
1838                 priority_jump = 1;
1839         }
1840         if (option_debug)
1841                 ast_log(LOG_DEBUG, "OSPFinish: priority jump '%d'\n", priority_jump);
1842
1843         headp = &chan->varshead;
1844         AST_LIST_TRAVERSE(headp, current, entries) {
1845                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1846                         if (sscanf(ast_var_value(current), "%d", &inhandle) != 1) {
1847                                 inhandle = OSP_INVALID_HANDLE;
1848                         }
1849                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
1850                         if (sscanf(ast_var_value(current), "%d", &outhandle) != 1) {
1851                                 outhandle = OSP_INVALID_HANDLE;
1852                         }
1853                 } else if (!recorded &&
1854                         (!strcasecmp(ast_var_name(current), "OSPAUTHSTATUS") ||
1855                         !strcasecmp(ast_var_name(current), "OSPLOOKUPSTATUS") ||
1856                         !strcasecmp(ast_var_name(current), "OSPNEXTSTATUS")))
1857                 {
1858                         if (strcasecmp(ast_var_value(current), AST_OSP_SUCCESS)) {
1859                                 recorded = 1;
1860                         }
1861                 }
1862         }
1863         if (option_debug) {
1864                 ast_log(LOG_DEBUG, "OSPFinish: OSPINHANDLE '%d'\n", inhandle);
1865                 ast_log(LOG_DEBUG, "OSPFinish: OSPOUTHANDLE '%d'\n", outhandle);
1866                 ast_log(LOG_DEBUG, "OSPFinish: recorded '%d'\n", recorded);
1867         }
1868
1869         if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%d", &cause) != 1) {
1870                 cause = 0;
1871         }
1872         if (option_debug)
1873                 ast_log(LOG_DEBUG, "OSPFinish: cause '%d'\n", cause);
1874
1875         if (chan->cdr) {
1876                 start = chan->cdr->start.tv_sec;
1877                 connect = chan->cdr->answer.tv_sec;
1878                 if (connect) {
1879                         end = time(NULL);
1880                 } else {
1881                         end = connect;
1882                 }
1883         } else {
1884                 start = 0;
1885                 connect = 0;
1886                 end = 0;
1887         }
1888         if (option_debug) {
1889                 ast_log(LOG_DEBUG, "OSPFinish: start '%ld'\n", start);
1890                 ast_log(LOG_DEBUG, "OSPFinish: connect '%ld'\n", connect);
1891                 ast_log(LOG_DEBUG, "OSPFinish: end '%ld'\n", end);
1892         }
1893
1894         release = chan->_softhangup ? 0 : 1;
1895
1896         if (osp_finish(outhandle, recorded, cause, start, connect, end, release) <= 0) {
1897                 if (option_debug)
1898                         ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for outbound call\n");
1899         }
1900         switch (cause) {
1901                 case AST_CAUSE_NORMAL_CLEARING:
1902                         break;
1903                 default:
1904                         cause = AST_CAUSE_NO_ROUTE_DESTINATION;
1905                         break;
1906         }
1907         if (osp_finish(inhandle, recorded, cause, start, connect, end, release) <= 0) {
1908                 if (option_debug)
1909                         ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for inbound call\n");
1910         }
1911         snprintf(buffer, sizeof(buffer), "%d", OSP_INVALID_HANDLE);
1912         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
1913         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
1914
1915         if (res > 0) {
1916                 status = AST_OSP_SUCCESS;
1917         } else if (!res) {
1918                 status = AST_OSP_FAILED;
1919         } else {
1920                 status = AST_OSP_ERROR;
1921         }
1922         pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", status);
1923
1924         if(!res) {
1925                 if (priority_jump || ast_opt_priority_jumping) {
1926                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1927                         res = 0;
1928                 } else {
1929                         res = -1;
1930                 }
1931         } else {
1932                 res = 0;
1933         }
1934
1935         ast_module_user_remove(u);
1936
1937         return res;
1938 }
1939
1940 /* OSP Module APIs */
1941
1942 static int osp_load(void)
1943 {
1944         const char* t;
1945         unsigned int v;
1946         struct ast_config* cfg;
1947         int error = OSPC_ERR_NO_ERROR;
1948
1949         cfg = ast_config_load(OSP_CONFIG_FILE);
1950         if (cfg) {
1951                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "accelerate");
1952                 if (t && ast_true(t)) {
1953                         if ((error = OSPPInit(1)) != OSPC_ERR_NO_ERROR) {
1954                                 ast_log(LOG_WARNING, "OSP: Unable to enable hardware accelleration\n");
1955                                 OSPPInit(0);
1956                         } else {
1957                                 osp_hardware = 1;
1958                         }
1959                 } else {
1960                         OSPPInit(0);
1961                 }
1962                 if (option_debug)
1963                         ast_log(LOG_DEBUG, "OSP: osp_hardware '%d'\n", osp_hardware);
1964
1965                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat");
1966                 if (t) {
1967                         if ((sscanf(t, "%d", &v) == 1) &&
1968                                 ((v == TOKEN_ALGO_SIGNED) || (v == TOKEN_ALGO_UNSIGNED) || (v == TOKEN_ALGO_BOTH)))
1969                         {
1970                                 osp_tokenformat = v;
1971                         } else {
1972                                 ast_log(LOG_WARNING, "tokenformat should be an integer from %d, %d or %d, not '%s'\n",
1973                                         TOKEN_ALGO_SIGNED, TOKEN_ALGO_UNSIGNED, TOKEN_ALGO_BOTH, t);
1974                         }
1975                 }
1976                 if (option_debug)
1977                         ast_log(LOG_DEBUG, "OSP: osp_tokenformat '%d'\n", osp_tokenformat);
1978
1979                 t = ast_category_browse(cfg, NULL);
1980                 while(t) {
1981                         if (strcasecmp(t, OSP_GENERAL_CAT)) {
1982                                 osp_create_provider(cfg, t);
1983                         }
1984                         t = ast_category_browse(cfg, t);
1985                 }
1986
1987                 osp_initialized = 1;
1988
1989                 ast_config_destroy(cfg);
1990         } else {
1991                 ast_log(LOG_WARNING, "OSP: Unable to find configuration. OSP support disabled\n");
1992                 return 0;
1993         }
1994         if (option_debug)
1995                 ast_log(LOG_DEBUG, "OSP: osp_initialized '%d'\n", osp_initialized);
1996
1997         return 1;
1998 }
1999
2000 static int osp_unload(void)
2001 {
2002         struct osp_provider* p;
2003         struct osp_provider* next;
2004
2005         if (osp_initialized) {
2006                 ast_mutex_lock(&osplock);
2007                 p = ospproviders;
2008                 while(p) {
2009                         next = p->next;
2010                         OSPPProviderDelete(p->handle, 0);
2011                         free(p);
2012                         p = next;
2013                 }
2014                 ospproviders = NULL;
2015                 ast_mutex_unlock(&osplock);
2016
2017                 OSPPCleanup();
2018
2019                 osp_tokenformat = TOKEN_ALGO_SIGNED;
2020                 osp_hardware = 0;
2021                 osp_initialized = 0;
2022         }
2023         return 0;
2024 }
2025
2026 static int osp_show(
2027         int fd,
2028         int argc,
2029         char* argv[])
2030 {
2031         int i;
2032         int found = 0;
2033         struct osp_provider* p;
2034         const char* provider = NULL;
2035         const char* tokenalgo;
2036
2037         if ((argc < 2) || (argc > 3)) {
2038                 return RESULT_SHOWUSAGE;
2039         }
2040         if (argc > 2) {
2041                 provider = argv[2];
2042         }
2043         if (!provider) {
2044                 switch (osp_tokenformat) {
2045                         case TOKEN_ALGO_BOTH:
2046                                 tokenalgo = "Both";
2047                                 break;
2048                         case TOKEN_ALGO_UNSIGNED:
2049                                 tokenalgo = "Unsigned";
2050                                 break;
2051                         case TOKEN_ALGO_SIGNED:
2052                         default:
2053                                 tokenalgo = "Signed";
2054                                 break;
2055                 }
2056                 ast_cli(fd, "OSP: %s %s %s\n",
2057                         osp_initialized ? "Initialized" : "Uninitialized", osp_hardware ? "Accelerated" : "Normal", tokenalgo);
2058         }
2059
2060         ast_mutex_lock(&osplock);
2061         p = ospproviders;
2062         while(p) {
2063                 if (!provider || !strcasecmp(p->name, provider)) {
2064                         if (found) {
2065                                 ast_cli(fd, "\n");
2066                         }
2067                         ast_cli(fd, " == OSP Provider '%s' == \n", p->name);
2068                         ast_cli(fd, "Local Private Key: %s\n", p->privatekey);
2069                         ast_cli(fd, "Local Certificate: %s\n", p->localcert);
2070                         for (i = 0; i < p->cacount; i++) {
2071                                 ast_cli(fd, "CA Certificate %d:  %s\n", i + 1, p->cacerts[i]);
2072                         }
2073                         for (i = 0; i < p->spcount; i++) {
2074                                 ast_cli(fd, "Service Point %d:   %s\n", i + 1, p->srvpoints[i]);
2075                         }
2076                         ast_cli(fd, "Max Connections:   %d\n", p->maxconnections);
2077                         ast_cli(fd, "Retry Delay:       %d seconds\n", p->retrydelay);
2078                         ast_cli(fd, "Retry Limit:       %d\n", p->retrylimit);
2079                         ast_cli(fd, "Timeout:           %d milliseconds\n", p->timeout);
2080                         ast_cli(fd, "Source:            %s\n", strlen(p->source) ? p->source : "<unspecified>");
2081                         ast_cli(fd, "Auth Policy        %d\n", p->authpolicy);
2082                         ast_cli(fd, "Default protocol   %s\n", p->defaultprotocol);
2083                         ast_cli(fd, "OSP Handle:        %d\n", p->handle);
2084                         found++;
2085                 }
2086                 p = p->next;
2087         }
2088         ast_mutex_unlock(&osplock);
2089
2090         if (!found) {
2091                 if (provider) {
2092                         ast_cli(fd, "Unable to find OSP provider '%s'\n", provider);
2093                 } else {
2094                         ast_cli(fd, "No OSP providers configured\n");
2095                 }
2096         }
2097         return RESULT_SUCCESS;
2098 }
2099
2100 static const char* app1= "OSPAuth";
2101 static const char* synopsis1 = "OSP authentication";
2102 static const char* descrip1 =
2103 "  OSPAuth([provider[|options]]):  Authenticate a SIP INVITE by OSP and sets\n"
2104 "the variables:\n"
2105 " ${OSPINHANDLE}:  The inbound call transaction handle\n"
2106 " ${OSPINTIMELIMIT}:  The inbound call duration limit in seconds\n"
2107 "\n"
2108 "The option string may contain the following character:\n"
2109 "       'j' -- jump to n+101 priority if the authentication was NOT successful\n"
2110 "This application sets the following channel variable upon completion:\n"
2111 "       OSPAUTHSTATUS   The status of the OSP Auth attempt as a text string, one of\n"
2112 "               SUCCESS | FAILED | ERROR\n";
2113
2114 static const char* app2= "OSPLookup";
2115 static const char* synopsis2 = "Lookup destination by OSP";
2116 static const char* descrip2 =
2117 "  OSPLookup(exten[|provider[|options]]):  Looks up an extension via OSP and sets\n"
2118 "the variables, where 'n' is the number of the result beginning with 1:\n"
2119 " ${OSPOUTHANDLE}:  The OSP Handle for anything remaining\n"
2120 " ${OSPTECH}:  The technology to use for the call\n"
2121 " ${OSPDEST}:  The destination to use for the call\n"
2122 " ${OSPCALLED}:  The called number to use for the call\n"
2123 " ${OSPCALLING}:  The calling number to use for the call\n"
2124 " ${OSPDIALSTR}:  The dial command string\n"
2125 " ${OSPOUTTOKEN}:  The actual OSP token as a string\n"
2126 " ${OSPOUTTIMELIMIT}:  The outbound call duration limit in seconds\n"
2127 " ${OSPOUTCALLIDTYPES}:  The outbound call id types\n"
2128 " ${OSPOUTCALLID}:  The outbound call id\n"
2129 " ${OSPRESULTS}:  The number of OSP results total remaining\n"
2130 "\n"
2131 "The option string may contain the following character:\n"
2132 "       'j' -- jump to n+101 priority if the lookup was NOT successful\n"
2133 "       'h' -- generate H323 call id for the outbound call\n"
2134 "       's' -- generate SIP call id for the outbound call. Have not been implemented\n"
2135 "       'i' -- generate IAX call id for the outbound call. Have not been implemented\n"
2136 "This application sets the following channel variable upon completion:\n"
2137 "       OSPLOOKUPSTATUS The status of the OSP Lookup attempt as a text string, one of\n"
2138 "               SUCCESS | FAILED | ERROR\n";
2139
2140 static const char* app3 = "OSPNext";
2141 static const char* synopsis3 = "Lookup next destination by OSP";
2142 static const char* descrip3 =
2143 "  OSPNext(cause[|provider[|options]]):  Looks up the next OSP Destination for ${OSPOUTHANDLE}\n"
2144 "See OSPLookup for more information\n"
2145 "\n"
2146 "The option string may contain the following character:\n"
2147 "       'j' -- jump to n+101 priority if the lookup was NOT successful\n"
2148 "This application sets the following channel variable upon completion:\n"
2149 "       OSPNEXTSTATUS The status of the OSP Next attempt as a text string, one of\n"
2150 "               SUCCESS | FAILED | ERROR\n";
2151
2152 static const char* app4 = "OSPFinish";
2153 static const char* synopsis4 = "Record OSP entry";
2154 static const char* descrip4 =
2155 "  OSPFinish([status[|options]]):  Records call state for ${OSPINHANDLE}, according to\n"
2156 "status, which should be one of BUSY, CONGESTION, ANSWER, NOANSWER, or CHANUNAVAIL\n"
2157 "or coincidentally, just what the Dial application stores in its ${DIALSTATUS}.\n"
2158 "\n"
2159 "The option string may contain the following character:\n"
2160 "       'j' -- jump to n+101 priority if the finish attempt was NOT successful\n"
2161 "This application sets the following channel variable upon completion:\n"
2162 "       OSPFINISHSTATUS The status of the OSP Finish attempt as a text string, one of\n"
2163 "               SUCCESS | FAILED | ERROR \n";
2164
2165 static const char osp_usage[] =
2166 "Usage: osp show\n"
2167 "       Displays information on Open Settlement Protocol support\n";
2168
2169 static struct ast_cli_entry cli_osp[] = {
2170         { {"osp", "show", NULL},
2171         osp_show, "Displays OSP information",
2172         osp_usage },
2173 };
2174
2175 static int load_module(void)
2176 {
2177         int res;
2178
2179         if(!osp_load())
2180                 return AST_MODULE_LOAD_DECLINE;
2181
2182         ast_cli_register_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
2183         res = ast_register_application(app1, ospauth_exec, synopsis1, descrip1);
2184         res |= ast_register_application(app2, osplookup_exec, synopsis2, descrip2);
2185         res |= ast_register_application(app3, ospnext_exec, synopsis3, descrip3);
2186         res |= ast_register_application(app4, ospfinished_exec, synopsis4, descrip4);
2187
2188         return res;
2189 }
2190
2191 static int unload_module(void)
2192 {
2193         int res;
2194
2195         res = ast_unregister_application(app4);
2196         res |= ast_unregister_application(app3);
2197         res |= ast_unregister_application(app2);
2198         res |= ast_unregister_application(app1);
2199         ast_cli_unregister_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
2200         osp_unload();
2201
2202         ast_module_user_hangup_all();
2203
2204         return res;
2205 }
2206
2207 static int reload(void)
2208 {
2209         osp_unload();
2210         osp_load();
2211
2212         return 0;
2213 }
2214
2215 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Open Settlement Protocol Applications",
2216         .load = load_module,
2217         .unload = unload_module,
2218         .reload = reload,
2219         );