Issue #9842 - Doxygen updates by snuffy. Thanks!
[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 provider OSP provider name
1119  * \param cause Asterisk hangup cuase
1120  * \param result Lookup results, in/output
1121  * \return 1 Found , 0 No route, -1 Error
1122  */
1123 static int osp_next(
1124         const char* provider,
1125         int cause,
1126         struct osp_result* result)
1127 {
1128         int res;
1129         struct osp_provider* p;
1130         char callingnum[OSP_NORSTR_SIZE];
1131         char callednum[OSP_NORSTR_SIZE];
1132         char destination[OSP_NORSTR_SIZE];
1133         unsigned int tokenlen;
1134         char token[OSP_TOKSTR_SIZE];
1135         enum OSPEFAILREASON reason;
1136         int error;
1137
1138         result->tech[0] = '\0';
1139         result->dest[0] = '\0';
1140         result->called[0] = '\0';
1141         result->calling[0] = '\0';
1142         result->token[0] = '\0';
1143         result->networkid[0] = '\0';
1144         result->outtimelimit = OSP_DEF_TIMELIMIT;
1145
1146         if ((res = osp_get_provider(provider, &p)) <= 0) {
1147                 if (option_debug)
1148                         ast_log(LOG_DEBUG, "OSP: Unabe to find OSP provider '%s'\n", provider);
1149                 return res;
1150         }
1151
1152         if (result->outhandle == OSP_INVALID_HANDLE) {
1153                 if (option_debug)
1154                         ast_log(LOG_DEBUG, "OSP: Transaction handle undefined\n");
1155                 result->numresults = 0;
1156                 if (result->inhandle != OSP_INVALID_HANDLE) {
1157                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1158                 }
1159                 return -1;
1160         }
1161
1162         reason = asterisk2osp(cause);
1163
1164         if (!result->numresults) {
1165                 if (option_debug)
1166                         ast_log(LOG_DEBUG, "OSP: No more destination\n");
1167                 OSPPTransactionRecordFailure(result->outhandle, reason);
1168                 if (result->inhandle != OSP_INVALID_HANDLE) {
1169                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1170                 }
1171                 return 0;
1172         }
1173
1174         while(result->numresults) {
1175                 result->outcallid.len = sizeof(result->outcallid.buf);
1176                 tokenlen = sizeof(token);
1177                 error = OSPPTransactionGetNextDestination(
1178                                         result->outhandle,
1179                                         reason,
1180                                         0,
1181                                         NULL,
1182                                         NULL,
1183                                         &result->outtimelimit,
1184                                         &result->outcallid.len,
1185                                         result->outcallid.buf,
1186                                         sizeof(callednum),
1187                                         callednum,
1188                                         sizeof(callingnum),
1189                                         callingnum,
1190                                         sizeof(destination),
1191                                         destination,
1192                                         0,
1193                                         NULL,
1194                                         &tokenlen,
1195                                         token);
1196                 if (error == OSPC_ERR_NO_ERROR) {
1197                         result->numresults--;
1198                         result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
1199                         if (option_debug) {
1200                                 ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
1201                                 ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
1202                                 ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
1203                                 ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
1204                                 ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
1205                         }
1206                         if ((res = osp_check_destination(p, callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
1207                                 res = 1;
1208                                 break;
1209                         } else if (!result->numresults) {
1210                                 if (option_debug)
1211                                         ast_log(LOG_DEBUG, "OSP: No more destination\n");
1212                                 OSPPTransactionRecordFailure(result->outhandle, reason);
1213                                 if (result->inhandle != OSP_INVALID_HANDLE) {
1214                                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1215                                 }
1216                                 res = 0;
1217                                 break;
1218                         }
1219                 } else {
1220                         if (option_debug)
1221                                 ast_log(LOG_DEBUG, "OSP: Unable to get route, error '%d'\n", error);
1222                         result->token[0] = '\0';
1223                         result->numresults = 0;
1224                         result->outtimelimit = OSP_DEF_TIMELIMIT;
1225                         if (result->inhandle != OSP_INVALID_HANDLE) {
1226                                 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1227                         }
1228                         res = -1;
1229                         break;
1230                 }
1231         }
1232
1233         return res;
1234 }
1235
1236 /*!
1237  * \brief OSP Finish function
1238  * \param handle OSP in/outbound transaction handle
1239  * \param recorded If failure reason has been recorded
1240  * \param cause Asterisk hangup cause
1241  * \param start Call start time
1242  * \param connect Call connect time
1243  * \param end Call end time
1244  * \param release Who release first, 0 source, 1 destination
1245  * \return 1 Success, 0 Failed, -1 Error
1246  */
1247 static int osp_finish(
1248         int handle,
1249         int recorded,
1250         int cause,
1251         time_t start,
1252         time_t connect,
1253         time_t end,
1254         unsigned int release)
1255 {
1256         int res;
1257         enum OSPEFAILREASON reason;
1258         time_t alert = 0;
1259         unsigned isPddInfoPresent = 0;
1260         unsigned pdd = 0;
1261         unsigned int dummy = 0;
1262         int error;
1263
1264         if (handle == OSP_INVALID_HANDLE) {
1265                 return 0;
1266         }
1267
1268         if (!recorded) {
1269                 reason = asterisk2osp(cause);
1270                 OSPPTransactionRecordFailure(handle, reason);
1271         }
1272
1273         error = OSPPTransactionReportUsage(
1274                                 handle,
1275                                 difftime(end, connect),
1276                                 start,
1277                                 end,
1278                                 alert,
1279                                 connect,
1280                                 isPddInfoPresent,
1281                                 pdd,
1282                                 release,
1283                                 (unsigned char*)"",
1284                                 0,
1285                                 0,
1286                                 0,
1287                                 0,
1288                                 &dummy,
1289                                 NULL);
1290         if (error == OSPC_ERR_NO_ERROR) {
1291                 if (option_debug)
1292                         ast_log(LOG_DEBUG, "OSP: Usage reported\n");
1293                 res = 1;
1294         } else {
1295                 if (option_debug)
1296                         ast_log(LOG_DEBUG, "OSP: Unable to report usage, error '%d'\n", error);
1297                 res = -1;
1298         }
1299         OSPPTransactionDelete(handle);
1300
1301         return res;
1302 }
1303
1304 /* OSP Application APIs */
1305
1306 /*!
1307  * \brief OSP Application OSPAuth
1308  * \param chan Channel
1309  * \param data Parameter
1310  * \return 0 Success, -1 Failed
1311  */
1312 static int ospauth_exec(
1313         struct ast_channel* chan,
1314         void* data)
1315 {
1316         int res;
1317         struct ast_module_user* u;
1318         const char* provider = OSP_DEF_PROVIDER;
1319         int priority_jump = 0;
1320         struct varshead* headp;
1321         struct ast_var_t* current;
1322         const char* source = "";
1323         const char* token = "";
1324         int handle;
1325         unsigned int timelimit;
1326         char buffer[OSP_INTSTR_SIZE];
1327         const char* status;
1328         char* tmp;
1329
1330         AST_DECLARE_APP_ARGS(args,
1331                 AST_APP_ARG(provider);
1332                 AST_APP_ARG(options);
1333         );
1334
1335         u = ast_module_user_add(chan);
1336
1337         if (!(tmp = ast_strdupa(data))) {
1338                 ast_log(LOG_ERROR, "Out of memory\n");
1339                 ast_module_user_remove(u);
1340                 return -1;
1341         }
1342
1343         AST_STANDARD_APP_ARGS(args, tmp);
1344
1345         if (!ast_strlen_zero(args.provider)) {
1346                 provider = args.provider;
1347         }
1348         if (option_debug)
1349                 ast_log(LOG_DEBUG, "OSPAuth: provider '%s'\n", provider);
1350
1351         if ((args.options) && (strchr(args.options, 'j'))) {
1352                 priority_jump = 1;
1353         }
1354         if (option_debug)
1355                 ast_log(LOG_DEBUG, "OSPAuth: priority jump '%d'\n", priority_jump);
1356
1357         headp = &chan->varshead;
1358         AST_LIST_TRAVERSE(headp, current, entries) {
1359                 if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
1360                         source = ast_var_value(current);
1361                 } else if (!strcasecmp(ast_var_name(current), "OSPINTOKEN")) {
1362                         token = ast_var_value(current);
1363                 }
1364         }
1365
1366         if (option_debug) {
1367                 ast_log(LOG_DEBUG, "OSPAuth: source '%s'\n", source);
1368                 ast_log(LOG_DEBUG, "OSPAuth: token size '%zd'\n", strlen(token));
1369         }
1370
1371         if ((res = osp_auth(provider, &handle, source, chan->cid.cid_num, chan->exten, token, &timelimit)) > 0) {
1372                 status = AST_OSP_SUCCESS;
1373         } else {
1374                 timelimit = OSP_DEF_TIMELIMIT;
1375                 if (!res) {
1376                         status = AST_OSP_FAILED;
1377                 } else {
1378                         status = AST_OSP_ERROR;
1379                 }
1380         }
1381
1382         snprintf(buffer, sizeof(buffer), "%d", handle);
1383         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
1384         if (option_debug)
1385                 ast_log(LOG_DEBUG, "OSPAuth: OSPINHANDLE '%s'\n", buffer);
1386         snprintf(buffer, sizeof(buffer), "%d", timelimit);
1387         pbx_builtin_setvar_helper(chan, "OSPINTIMELIMIT", buffer);
1388         if (option_debug)
1389                 ast_log(LOG_DEBUG, "OSPAuth: OSPINTIMELIMIT '%s'\n", buffer);
1390         pbx_builtin_setvar_helper(chan, "OSPAUTHSTATUS", status);
1391         if (option_debug)
1392                 ast_log(LOG_DEBUG, "OSPAuth: %s\n", status);
1393
1394         if(res <= 0) {
1395                 if (priority_jump || ast_opt_priority_jumping) {
1396                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1397                         res = 0;
1398                 } else {
1399                         res = -1;
1400                 }
1401         } else {
1402                 res = 0;
1403         }
1404
1405         ast_module_user_remove(u);
1406
1407         return res;
1408 }
1409
1410 /*!
1411  * \brief OSP Application OSPLookup
1412  * \param chan Channel
1413  * \param data Parameter
1414  * \return 0 Success, -1 Failed
1415  */
1416 static int osplookup_exec(
1417         struct ast_channel* chan,
1418         void* data)
1419 {
1420         int res, cres;
1421         struct ast_module_user* u;
1422         const char* provider = OSP_DEF_PROVIDER;
1423         int priority_jump = 0;
1424         struct varshead* headp;
1425         struct ast_var_t* current;
1426         const char* srcdev = "";
1427         const char* netid = "";
1428         char buffer[OSP_TOKSTR_SIZE];
1429         unsigned int callidtypes = OSP_CALLID_UNDEFINED;
1430         struct osp_result result;
1431         const char* status;
1432         char* tmp;
1433
1434         AST_DECLARE_APP_ARGS(args,
1435                 AST_APP_ARG(exten);
1436                 AST_APP_ARG(provider);
1437                 AST_APP_ARG(options);
1438         );
1439
1440         if (ast_strlen_zero(data)) {
1441                 ast_log(LOG_WARNING, "OSPLookup: Arg required, OSPLookup(exten[|provider[|options]])\n");
1442                 return -1;
1443         }
1444
1445         u = ast_module_user_add(chan);
1446
1447         if (!(tmp = ast_strdupa(data))) {
1448                 ast_log(LOG_ERROR, "Out of memory\n");
1449                 ast_module_user_remove(u);
1450                 return -1;
1451         }
1452
1453         AST_STANDARD_APP_ARGS(args, tmp);
1454
1455         if (option_debug)
1456                 ast_log(LOG_DEBUG, "OSPLookup: exten '%s'\n", args.exten);
1457
1458         if (!ast_strlen_zero(args.provider)) {
1459                 provider = args.provider;
1460         }
1461         if (option_debug)
1462                 ast_log(LOG_DEBUG, "OSPlookup: provider '%s'\n", provider);
1463
1464         if (args.options) {
1465                 if (strchr(args.options, 'j')) {
1466                         priority_jump = 1;
1467                 }
1468                 if (strchr(args.options, 'h')) {
1469                         callidtypes |= OSP_CALLID_H323;
1470                 }
1471                 if (strchr(args.options, 's')) {
1472                         callidtypes |= OSP_CALLID_SIP;
1473                 }
1474                 if (strchr(args.options, 'i')) {
1475                         callidtypes |= OSP_CALLID_IAX;
1476                 }
1477         }
1478         if (option_debug) {
1479                 ast_log(LOG_DEBUG, "OSPLookup: priority jump '%d'\n", priority_jump);
1480                 ast_log(LOG_DEBUG, "OSPLookup: call id types '%d'\n", callidtypes);
1481         }
1482
1483         result.inhandle = OSP_INVALID_HANDLE;
1484         result.intimelimit = OSP_DEF_TIMELIMIT;
1485
1486         headp = &chan->varshead;
1487         AST_LIST_TRAVERSE(headp, current, entries) {
1488                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1489                         if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
1490                                 result.inhandle = OSP_INVALID_HANDLE;
1491                         }
1492                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
1493                         if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
1494                                 result.intimelimit = OSP_DEF_TIMELIMIT;
1495                         }
1496                 } else if (!strcasecmp(ast_var_name(current), "OSPINNETWORKID")) {
1497                         netid = ast_var_value(current);
1498                 } else if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
1499                         srcdev = ast_var_value(current);
1500                 }
1501         }
1502         if (option_debug) {
1503                 ast_log(LOG_DEBUG, "OSPLookup: OSPINHANDLE '%d'\n", result.inhandle);
1504                 ast_log(LOG_DEBUG, "OSPLookup: OSPINTIMELIMIT '%d'\n", result.intimelimit);
1505                 ast_log(LOG_DEBUG, "OSPLookup: OSPINNETWORKID '%s'\n", netid);
1506                 ast_log(LOG_DEBUG, "OSPLookup: source device '%s'\n", srcdev);
1507         }
1508
1509         if ((cres = ast_autoservice_start(chan)) < 0) {
1510                 ast_module_user_remove(u);
1511                 return -1;
1512         }
1513
1514         if ((res = osp_lookup(provider, srcdev, chan->cid.cid_num, args.exten, callidtypes, &result)) > 0) {
1515                 status = AST_OSP_SUCCESS;
1516         } else {
1517                 result.tech[0] = '\0';
1518                 result.dest[0] = '\0';
1519                 result.called[0] = '\0';
1520                 result.calling[0] = '\0';
1521                 result.token[0] = '\0';
1522                 result.networkid[0] = '\0';
1523                 result.numresults = 0;
1524                 result.outtimelimit = OSP_DEF_TIMELIMIT;
1525                 result.outcallid.buf[0] = '\0';
1526                 result.outcallid.len = 0;
1527                 if (!res) {
1528                         status = AST_OSP_FAILED;
1529                 } else {
1530                         status = AST_OSP_ERROR;
1531                 }
1532         }
1533
1534         snprintf(buffer, sizeof(buffer), "%d", result.outhandle);
1535         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
1536         if (option_debug)
1537                 ast_log(LOG_DEBUG, "OSPLookup: OSPOUTHANDLE '%s'\n", buffer);
1538         pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
1539         if (option_debug)
1540                 ast_log(LOG_DEBUG, "OSPLookup: OSPTECH '%s'\n", result.tech);
1541         pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
1542         if (option_debug)
1543                 ast_log(LOG_DEBUG, "OSPLookup: OSPDEST '%s'\n", result.dest);
1544         pbx_builtin_setvar_helper(chan, "OSPCALLED", result.called);
1545         if (option_debug)
1546                 ast_log(LOG_DEBUG, "OSPLookup: OSPCALLED '%s'\n", result.called);
1547         pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
1548         if (option_debug)
1549                 ast_log(LOG_DEBUG, "OSPLookup: OSPCALLING '%s'\n", result.calling);
1550         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
1551         if (option_debug)
1552                 ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
1553         snprintf(buffer, sizeof(buffer), "%d", result.numresults);
1554         pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
1555         if (option_debug)
1556                 ast_log(LOG_DEBUG, "OSPLookup: OSPRESULTS '%s'\n", buffer);
1557         snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
1558         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
1559         if (option_debug)
1560                 ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTIMELIMIT '%s'\n", buffer);
1561         snprintf(buffer, sizeof(buffer), "%d", callidtypes);
1562         pbx_builtin_setvar_helper(chan, "OSPOUTCALLIDTYPES", buffer);
1563         if (option_debug)
1564                 ast_log(LOG_DEBUG, "OSPLookup: OSPOUTCALLIDTYPES '%s'\n", buffer);
1565         pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", status);
1566         if (option_debug)
1567                 ast_log(LOG_DEBUG, "OSPLookup: %s\n", status);
1568
1569         if (!strcasecmp(result.tech, OSP_TECH_H323)) {
1570                 if ((callidtypes & OSP_CALLID_H323) && (result.outcallid.len != 0)) {
1571                         osp_uuid2str(result.outcallid.buf, buffer, sizeof(buffer));
1572                 } else {
1573                         buffer[0] = '\0';
1574                 }
1575                 pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
1576                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1577                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1578         } else if (!strcasecmp(result.tech, OSP_TECH_SIP)) {
1579                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1580                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1581                 if (!ast_strlen_zero(result.token)) {
1582                         snprintf(buffer, sizeof(buffer), "%s%s", OSP_SIP_HEADER, result.token);
1583                         pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
1584                         if (option_debug)
1585                                 ast_log(LOG_DEBUG, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
1586                 }
1587         } else if (!strcasecmp(result.tech, OSP_TECH_IAX)) {
1588                 snprintf(buffer, sizeof(buffer), "%s/%s/%s", result.tech, result.dest, result.called);
1589                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1590         }
1591
1592         if ((cres = ast_autoservice_stop(chan)) < 0) {
1593                 ast_module_user_remove(u);
1594                 return -1;
1595         }
1596
1597         if(res <= 0) {
1598                 if (priority_jump || ast_opt_priority_jumping) {
1599                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1600                         res = 0;
1601                 } else {
1602                         res = -1;
1603                 }
1604         } else {
1605                 res = 0;
1606         }
1607
1608         ast_module_user_remove(u);
1609
1610         return res;
1611 }
1612
1613 /*!
1614  * \brief OSP Application OSPNext
1615  * \param chan Channel
1616  * \param data Parameter
1617  * \return 0 Success, -1 Failed
1618  */
1619 static int ospnext_exec(
1620         struct ast_channel* chan,
1621         void* data)
1622 {
1623         int res;
1624         struct ast_module_user* u;
1625         const char* provider = OSP_DEF_PROVIDER;
1626         int priority_jump = 0;
1627         int cause = 0;
1628         struct varshead* headp;
1629         struct ast_var_t* current;
1630         struct osp_result result;
1631         char buffer[OSP_TOKSTR_SIZE];
1632         unsigned int callidtypes = OSP_CALLID_UNDEFINED;
1633         const char* status;
1634         char* tmp;
1635
1636         AST_DECLARE_APP_ARGS(args,
1637                 AST_APP_ARG(cause);
1638                 AST_APP_ARG(provider);
1639                 AST_APP_ARG(options);
1640         );
1641
1642         if (ast_strlen_zero(data)) {
1643                 ast_log(LOG_WARNING, "OSPNext: Arg required, OSPNext(cause[|provider[|options]])\n");
1644                 return -1;
1645         }
1646
1647         u = ast_module_user_add(chan);
1648
1649         if (!(tmp = ast_strdupa(data))) {
1650                 ast_log(LOG_ERROR, "Out of memory\n");
1651                 ast_module_user_remove(u);
1652                 return -1;
1653         }
1654
1655         AST_STANDARD_APP_ARGS(args, tmp);
1656
1657         if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%d", &cause) != 1) {
1658                 cause = 0;
1659         }
1660         if (option_debug)
1661                 ast_log(LOG_DEBUG, "OSPNext: cause '%d'\n", cause);
1662
1663         if (!ast_strlen_zero(args.provider)) {
1664                 provider = args.provider;
1665         }
1666         if (option_debug)
1667                 ast_log(LOG_DEBUG, "OSPlookup: provider '%s'\n", provider);
1668
1669         if ((args.options) && (strchr(args.options, 'j'))) {
1670                 priority_jump = 1;
1671         }
1672         if (option_debug)
1673                 ast_log(LOG_DEBUG, "OSPNext: priority jump '%d'\n", priority_jump);
1674
1675         result.inhandle = OSP_INVALID_HANDLE;
1676         result.outhandle = OSP_INVALID_HANDLE;
1677         result.intimelimit = OSP_DEF_TIMELIMIT;
1678         result.numresults = 0;
1679
1680         headp = &chan->varshead;
1681         AST_LIST_TRAVERSE(headp, current, entries) {
1682                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1683                         if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
1684                                 result.inhandle = OSP_INVALID_HANDLE;
1685                         }
1686                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
1687                         if (sscanf(ast_var_value(current), "%d", &result.outhandle) != 1) {
1688                                 result.outhandle = OSP_INVALID_HANDLE;
1689                         }
1690                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
1691                         if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
1692                                 result.intimelimit = OSP_DEF_TIMELIMIT;
1693                         }
1694                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTCALLIDTYPES")) {
1695                         if (sscanf(ast_var_value(current), "%d", &callidtypes) != 1) {
1696                                 callidtypes = OSP_CALLID_UNDEFINED;
1697                         }
1698                 } else if (!strcasecmp(ast_var_name(current), "OSPRESULTS")) {
1699                         if (sscanf(ast_var_value(current), "%d", &result.numresults) != 1) {
1700                                 result.numresults = 0;
1701                         }
1702                 }
1703         }
1704         if (option_debug) {
1705                 ast_log(LOG_DEBUG, "OSPNext: OSPINHANDLE '%d'\n", result.inhandle);
1706                 ast_log(LOG_DEBUG, "OSPNext: OSPOUTHANDLE '%d'\n", result.outhandle);
1707                 ast_log(LOG_DEBUG, "OSPNext: OSPINTIMELIMIT '%d'\n", result.intimelimit);
1708                 ast_log(LOG_DEBUG, "OSPNext: OSPOUTCALLIDTYPES '%d'\n", callidtypes);
1709                 ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%d'\n", result.numresults);
1710         }
1711
1712         if ((res = osp_next(provider, cause, &result)) > 0) {
1713                 status = AST_OSP_SUCCESS;
1714         } else {
1715                 result.tech[0] = '\0';
1716                 result.dest[0] = '\0';
1717                 result.called[0] = '\0';
1718                 result.calling[0] = '\0';
1719                 result.token[0] = '\0';
1720                 result.networkid[0] = '\0';
1721                 result.numresults = 0;
1722                 result.outtimelimit = OSP_DEF_TIMELIMIT;
1723                 result.outcallid.buf[0] = '\0';
1724                 result.outcallid.len = 0;
1725                 if (!res) {
1726                         status = AST_OSP_FAILED;
1727                 } else {
1728                         status = AST_OSP_ERROR;
1729                 }
1730         }
1731
1732         pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
1733         if (option_debug)
1734                 ast_log(LOG_DEBUG, "OSPNext: OSPTECH '%s'\n", result.tech);
1735         pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
1736         if (option_debug)
1737                 ast_log(LOG_DEBUG, "OSPNext: OSPDEST '%s'\n", result.dest);
1738         pbx_builtin_setvar_helper(chan, "OSPCALLED", result.called);
1739         if (option_debug)
1740                 ast_log(LOG_DEBUG, "OSPNext: OSPCALLED'%s'\n", result.called);
1741         pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
1742         if (option_debug)
1743                 ast_log(LOG_DEBUG, "OSPNext: OSPCALLING '%s'\n", result.calling);
1744         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
1745         if (option_debug)
1746                 ast_log(LOG_DEBUG, "OSPNext: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
1747         snprintf(buffer, sizeof(buffer), "%d", result.numresults);
1748         pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
1749         if (option_debug)
1750                 ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%s'\n", buffer);
1751         snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
1752         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
1753         if (option_debug)
1754                 ast_log(LOG_DEBUG, "OSPNext: OSPOUTTIMELIMIT '%s'\n", buffer);
1755         pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", status);
1756         if (option_debug)
1757                 ast_log(LOG_DEBUG, "OSPNext: %s\n", status);
1758
1759         if (!strcasecmp(result.tech, OSP_TECH_H323)) {
1760                 if ((callidtypes & OSP_CALLID_H323) && (result.outcallid.len != 0)) {
1761                         osp_uuid2str(result.outcallid.buf, buffer, sizeof(buffer));
1762                 } else {
1763                         buffer[0] = '\0';
1764                 }
1765                 pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
1766                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1767                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1768         } else if (!strcasecmp(result.tech, OSP_TECH_SIP)) {
1769                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1770                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1771                 if (!ast_strlen_zero(result.token)) {
1772                         snprintf(buffer, sizeof(buffer), "%s%s", OSP_SIP_HEADER, result.token);
1773                         pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
1774                         if (option_debug)
1775                                 ast_log(LOG_DEBUG, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
1776                 }
1777         } else if (!strcasecmp(result.tech, OSP_TECH_IAX)) {
1778                 snprintf(buffer, sizeof(buffer), "%s/%s/%s", result.tech, result.dest, result.called);
1779                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1780         }
1781
1782         if(res <= 0) {
1783                 if (priority_jump || ast_opt_priority_jumping) {
1784                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1785                         res = 0;
1786                 } else {
1787                         res = -1;
1788                 }
1789         } else {
1790                 res = 0;
1791         }
1792
1793         ast_module_user_remove(u);
1794
1795         return res;
1796 }
1797
1798 /*!
1799  * \brief OSP Application OSPFinish
1800  * \param chan Channel
1801  * \param data Parameter
1802  * \return 0 Success, -1 Failed
1803  */
1804 static int ospfinished_exec(
1805         struct ast_channel* chan,
1806         void* data)
1807 {
1808         int res = 1;
1809         struct ast_module_user* u;
1810         int priority_jump = 0;
1811         int cause = 0;
1812         struct varshead* headp;
1813         struct ast_var_t* current;
1814         int inhandle = OSP_INVALID_HANDLE;
1815         int outhandle = OSP_INVALID_HANDLE;
1816         int recorded = 0;
1817         time_t start, connect, end;
1818         unsigned int release;
1819         char buffer[OSP_INTSTR_SIZE];
1820         const char* status;
1821         char* tmp;
1822
1823         AST_DECLARE_APP_ARGS(args,
1824                 AST_APP_ARG(cause);
1825                 AST_APP_ARG(options);
1826         );
1827
1828         u = ast_module_user_add(chan);
1829
1830         if (!(tmp = ast_strdupa(data))) {
1831                 ast_log(LOG_ERROR, "Out of memory\n");
1832                 ast_module_user_remove(u);
1833                 return -1;
1834         }
1835
1836         AST_STANDARD_APP_ARGS(args, tmp);
1837
1838         if ((args.options) && (strchr(args.options, 'j'))) {
1839                 priority_jump = 1;
1840         }
1841         if (option_debug)
1842                 ast_log(LOG_DEBUG, "OSPFinish: priority jump '%d'\n", priority_jump);
1843
1844         headp = &chan->varshead;
1845         AST_LIST_TRAVERSE(headp, current, entries) {
1846                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1847                         if (sscanf(ast_var_value(current), "%d", &inhandle) != 1) {
1848                                 inhandle = OSP_INVALID_HANDLE;
1849                         }
1850                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
1851                         if (sscanf(ast_var_value(current), "%d", &outhandle) != 1) {
1852                                 outhandle = OSP_INVALID_HANDLE;
1853                         }
1854                 } else if (!recorded &&
1855                         (!strcasecmp(ast_var_name(current), "OSPAUTHSTATUS") ||
1856                         !strcasecmp(ast_var_name(current), "OSPLOOKUPSTATUS") ||
1857                         !strcasecmp(ast_var_name(current), "OSPNEXTSTATUS")))
1858                 {
1859                         if (strcasecmp(ast_var_value(current), AST_OSP_SUCCESS)) {
1860                                 recorded = 1;
1861                         }
1862                 }
1863         }
1864         if (option_debug) {
1865                 ast_log(LOG_DEBUG, "OSPFinish: OSPINHANDLE '%d'\n", inhandle);
1866                 ast_log(LOG_DEBUG, "OSPFinish: OSPOUTHANDLE '%d'\n", outhandle);
1867                 ast_log(LOG_DEBUG, "OSPFinish: recorded '%d'\n", recorded);
1868         }
1869
1870         if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%d", &cause) != 1) {
1871                 cause = 0;
1872         }
1873         if (option_debug)
1874                 ast_log(LOG_DEBUG, "OSPFinish: cause '%d'\n", cause);
1875
1876         if (chan->cdr) {
1877                 start = chan->cdr->start.tv_sec;
1878                 connect = chan->cdr->answer.tv_sec;
1879                 if (connect) {
1880                         end = time(NULL);
1881                 } else {
1882                         end = connect;
1883                 }
1884         } else {
1885                 start = 0;
1886                 connect = 0;
1887                 end = 0;
1888         }
1889         if (option_debug) {
1890                 ast_log(LOG_DEBUG, "OSPFinish: start '%ld'\n", start);
1891                 ast_log(LOG_DEBUG, "OSPFinish: connect '%ld'\n", connect);
1892                 ast_log(LOG_DEBUG, "OSPFinish: end '%ld'\n", end);
1893         }
1894
1895         release = chan->_softhangup ? 0 : 1;
1896
1897         if (osp_finish(outhandle, recorded, cause, start, connect, end, release) <= 0) {
1898                 if (option_debug)
1899                         ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for outbound call\n");
1900         }
1901         switch (cause) {
1902                 case AST_CAUSE_NORMAL_CLEARING:
1903                         break;
1904                 default:
1905                         cause = AST_CAUSE_NO_ROUTE_DESTINATION;
1906                         break;
1907         }
1908         if (osp_finish(inhandle, recorded, cause, start, connect, end, release) <= 0) {
1909                 if (option_debug)
1910                         ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for inbound call\n");
1911         }
1912         snprintf(buffer, sizeof(buffer), "%d", OSP_INVALID_HANDLE);
1913         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
1914         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
1915
1916         if (res > 0) {
1917                 status = AST_OSP_SUCCESS;
1918         } else if (!res) {
1919                 status = AST_OSP_FAILED;
1920         } else {
1921                 status = AST_OSP_ERROR;
1922         }
1923         pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", status);
1924
1925         if(!res) {
1926                 if (priority_jump || ast_opt_priority_jumping) {
1927                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1928                         res = 0;
1929                 } else {
1930                         res = -1;
1931                 }
1932         } else {
1933                 res = 0;
1934         }
1935
1936         ast_module_user_remove(u);
1937
1938         return res;
1939 }
1940
1941 /* OSP Module APIs */
1942
1943 static int osp_load(void)
1944 {
1945         const char* t;
1946         unsigned int v;
1947         struct ast_config* cfg;
1948         int error = OSPC_ERR_NO_ERROR;
1949
1950         cfg = ast_config_load(OSP_CONFIG_FILE);
1951         if (cfg) {
1952                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "accelerate");
1953                 if (t && ast_true(t)) {
1954                         if ((error = OSPPInit(1)) != OSPC_ERR_NO_ERROR) {
1955                                 ast_log(LOG_WARNING, "OSP: Unable to enable hardware accelleration\n");
1956                                 OSPPInit(0);
1957                         } else {
1958                                 osp_hardware = 1;
1959                         }
1960                 } else {
1961                         OSPPInit(0);
1962                 }
1963                 if (option_debug)
1964                         ast_log(LOG_DEBUG, "OSP: osp_hardware '%d'\n", osp_hardware);
1965
1966                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat");
1967                 if (t) {
1968                         if ((sscanf(t, "%d", &v) == 1) &&
1969                                 ((v == TOKEN_ALGO_SIGNED) || (v == TOKEN_ALGO_UNSIGNED) || (v == TOKEN_ALGO_BOTH)))
1970                         {
1971                                 osp_tokenformat = v;
1972                         } else {
1973                                 ast_log(LOG_WARNING, "tokenformat should be an integer from %d, %d or %d, not '%s'\n",
1974                                         TOKEN_ALGO_SIGNED, TOKEN_ALGO_UNSIGNED, TOKEN_ALGO_BOTH, t);
1975                         }
1976                 }
1977                 if (option_debug)
1978                         ast_log(LOG_DEBUG, "OSP: osp_tokenformat '%d'\n", osp_tokenformat);
1979
1980                 t = ast_category_browse(cfg, NULL);
1981                 while(t) {
1982                         if (strcasecmp(t, OSP_GENERAL_CAT)) {
1983                                 osp_create_provider(cfg, t);
1984                         }
1985                         t = ast_category_browse(cfg, t);
1986                 }
1987
1988                 osp_initialized = 1;
1989
1990                 ast_config_destroy(cfg);
1991         } else {
1992                 ast_log(LOG_WARNING, "OSP: Unable to find configuration. OSP support disabled\n");
1993                 return 0;
1994         }
1995         if (option_debug)
1996                 ast_log(LOG_DEBUG, "OSP: osp_initialized '%d'\n", osp_initialized);
1997
1998         return 1;
1999 }
2000
2001 static int osp_unload(void)
2002 {
2003         struct osp_provider* p;
2004         struct osp_provider* next;
2005
2006         if (osp_initialized) {
2007                 ast_mutex_lock(&osplock);
2008                 p = ospproviders;
2009                 while(p) {
2010                         next = p->next;
2011                         OSPPProviderDelete(p->handle, 0);
2012                         free(p);
2013                         p = next;
2014                 }
2015                 ospproviders = NULL;
2016                 ast_mutex_unlock(&osplock);
2017
2018                 OSPPCleanup();
2019
2020                 osp_tokenformat = TOKEN_ALGO_SIGNED;
2021                 osp_hardware = 0;
2022                 osp_initialized = 0;
2023         }
2024         return 0;
2025 }
2026
2027 static int osp_show(
2028         int fd,
2029         int argc,
2030         char* argv[])
2031 {
2032         int i;
2033         int found = 0;
2034         struct osp_provider* p;
2035         const char* provider = NULL;
2036         const char* tokenalgo;
2037
2038         if ((argc < 2) || (argc > 3)) {
2039                 return RESULT_SHOWUSAGE;
2040         }
2041         if (argc > 2) {
2042                 provider = argv[2];
2043         }
2044         if (!provider) {
2045                 switch (osp_tokenformat) {
2046                         case TOKEN_ALGO_BOTH:
2047                                 tokenalgo = "Both";
2048                                 break;
2049                         case TOKEN_ALGO_UNSIGNED:
2050                                 tokenalgo = "Unsigned";
2051                                 break;
2052                         case TOKEN_ALGO_SIGNED:
2053                         default:
2054                                 tokenalgo = "Signed";
2055                                 break;
2056                 }
2057                 ast_cli(fd, "OSP: %s %s %s\n",
2058                         osp_initialized ? "Initialized" : "Uninitialized", osp_hardware ? "Accelerated" : "Normal", tokenalgo);
2059         }
2060
2061         ast_mutex_lock(&osplock);
2062         p = ospproviders;
2063         while(p) {
2064                 if (!provider || !strcasecmp(p->name, provider)) {
2065                         if (found) {
2066                                 ast_cli(fd, "\n");
2067                         }
2068                         ast_cli(fd, " == OSP Provider '%s' == \n", p->name);
2069                         ast_cli(fd, "Local Private Key: %s\n", p->privatekey);
2070                         ast_cli(fd, "Local Certificate: %s\n", p->localcert);
2071                         for (i = 0; i < p->cacount; i++) {
2072                                 ast_cli(fd, "CA Certificate %d:  %s\n", i + 1, p->cacerts[i]);
2073                         }
2074                         for (i = 0; i < p->spcount; i++) {
2075                                 ast_cli(fd, "Service Point %d:   %s\n", i + 1, p->srvpoints[i]);
2076                         }
2077                         ast_cli(fd, "Max Connections:   %d\n", p->maxconnections);
2078                         ast_cli(fd, "Retry Delay:       %d seconds\n", p->retrydelay);
2079                         ast_cli(fd, "Retry Limit:       %d\n", p->retrylimit);
2080                         ast_cli(fd, "Timeout:           %d milliseconds\n", p->timeout);
2081                         ast_cli(fd, "Source:            %s\n", strlen(p->source) ? p->source : "<unspecified>");
2082                         ast_cli(fd, "Auth Policy        %d\n", p->authpolicy);
2083                         ast_cli(fd, "Default protocol   %s\n", p->defaultprotocol);
2084                         ast_cli(fd, "OSP Handle:        %d\n", p->handle);
2085                         found++;
2086                 }
2087                 p = p->next;
2088         }
2089         ast_mutex_unlock(&osplock);
2090
2091         if (!found) {
2092                 if (provider) {
2093                         ast_cli(fd, "Unable to find OSP provider '%s'\n", provider);
2094                 } else {
2095                         ast_cli(fd, "No OSP providers configured\n");
2096                 }
2097         }
2098         return RESULT_SUCCESS;
2099 }
2100
2101 static const char* app1= "OSPAuth";
2102 static const char* synopsis1 = "OSP authentication";
2103 static const char* descrip1 =
2104 "  OSPAuth([provider[|options]]):  Authenticate a SIP INVITE by OSP and sets\n"
2105 "the variables:\n"
2106 " ${OSPINHANDLE}:  The inbound call transaction handle\n"
2107 " ${OSPINTIMELIMIT}:  The inbound call duration limit in seconds\n"
2108 "\n"
2109 "The option string may contain the following character:\n"
2110 "       'j' -- jump to n+101 priority if the authentication was NOT successful\n"
2111 "This application sets the following channel variable upon completion:\n"
2112 "       OSPAUTHSTATUS   The status of the OSP Auth attempt as a text string, one of\n"
2113 "               SUCCESS | FAILED | ERROR\n";
2114
2115 static const char* app2= "OSPLookup";
2116 static const char* synopsis2 = "Lookup destination by OSP";
2117 static const char* descrip2 =
2118 "  OSPLookup(exten[|provider[|options]]):  Looks up an extension via OSP and sets\n"
2119 "the variables, where 'n' is the number of the result beginning with 1:\n"
2120 " ${OSPOUTHANDLE}:  The OSP Handle for anything remaining\n"
2121 " ${OSPTECH}:  The technology to use for the call\n"
2122 " ${OSPDEST}:  The destination to use for the call\n"
2123 " ${OSPCALLED}:  The called number to use for the call\n"
2124 " ${OSPCALLING}:  The calling number to use for the call\n"
2125 " ${OSPDIALSTR}:  The dial command string\n"
2126 " ${OSPOUTTOKEN}:  The actual OSP token as a string\n"
2127 " ${OSPOUTTIMELIMIT}:  The outbound call duration limit in seconds\n"
2128 " ${OSPOUTCALLIDTYPES}:  The outbound call id types\n"
2129 " ${OSPOUTCALLID}:  The outbound call id\n"
2130 " ${OSPRESULTS}:  The number of OSP results total remaining\n"
2131 "\n"
2132 "The option string may contain the following character:\n"
2133 "       'j' -- jump to n+101 priority if the lookup was NOT successful\n"
2134 "       'h' -- generate H323 call id for the outbound call\n"
2135 "       's' -- generate SIP call id for the outbound call. Have not been implemented\n"
2136 "       'i' -- generate IAX call id for the outbound call. Have not been implemented\n"
2137 "This application sets the following channel variable upon completion:\n"
2138 "       OSPLOOKUPSTATUS The status of the OSP Lookup attempt as a text string, one of\n"
2139 "               SUCCESS | FAILED | ERROR\n";
2140
2141 static const char* app3 = "OSPNext";
2142 static const char* synopsis3 = "Lookup next destination by OSP";
2143 static const char* descrip3 =
2144 "  OSPNext(cause[|provider[|options]]):  Looks up the next OSP Destination for ${OSPOUTHANDLE}\n"
2145 "See OSPLookup for more information\n"
2146 "\n"
2147 "The option string may contain the following character:\n"
2148 "       'j' -- jump to n+101 priority if the lookup was NOT successful\n"
2149 "This application sets the following channel variable upon completion:\n"
2150 "       OSPNEXTSTATUS The status of the OSP Next attempt as a text string, one of\n"
2151 "               SUCCESS | FAILED | ERROR\n";
2152
2153 static const char* app4 = "OSPFinish";
2154 static const char* synopsis4 = "Record OSP entry";
2155 static const char* descrip4 =
2156 "  OSPFinish([status[|options]]):  Records call state for ${OSPINHANDLE}, according to\n"
2157 "status, which should be one of BUSY, CONGESTION, ANSWER, NOANSWER, or CHANUNAVAIL\n"
2158 "or coincidentally, just what the Dial application stores in its ${DIALSTATUS}.\n"
2159 "\n"
2160 "The option string may contain the following character:\n"
2161 "       'j' -- jump to n+101 priority if the finish attempt was NOT successful\n"
2162 "This application sets the following channel variable upon completion:\n"
2163 "       OSPFINISHSTATUS The status of the OSP Finish attempt as a text string, one of\n"
2164 "               SUCCESS | FAILED | ERROR \n";
2165
2166 static const char osp_usage[] =
2167 "Usage: osp show\n"
2168 "       Displays information on Open Settlement Protocol support\n";
2169
2170 static struct ast_cli_entry cli_osp[] = {
2171         { {"osp", "show", NULL},
2172         osp_show, "Displays OSP information",
2173         osp_usage },
2174 };
2175
2176 static int load_module(void)
2177 {
2178         int res;
2179
2180         if(!osp_load())
2181                 return AST_MODULE_LOAD_DECLINE;
2182
2183         ast_cli_register_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
2184         res = ast_register_application(app1, ospauth_exec, synopsis1, descrip1);
2185         res |= ast_register_application(app2, osplookup_exec, synopsis2, descrip2);
2186         res |= ast_register_application(app3, ospnext_exec, synopsis3, descrip3);
2187         res |= ast_register_application(app4, ospfinished_exec, synopsis4, descrip4);
2188
2189         return res;
2190 }
2191
2192 static int unload_module(void)
2193 {
2194         int res;
2195
2196         res = ast_unregister_application(app4);
2197         res |= ast_unregister_application(app3);
2198         res |= ast_unregister_application(app2);
2199         res |= ast_unregister_application(app1);
2200         ast_cli_unregister_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
2201         osp_unload();
2202
2203         ast_module_user_hangup_all();
2204
2205         return res;
2206 }
2207
2208 static int reload(void)
2209 {
2210         osp_unload();
2211         osp_load();
2212
2213         return 0;
2214 }
2215
2216 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Open Settlement Protocol Applications",
2217         .load = load_module,
2218         .unload = unload_module,
2219         .reload = reload,
2220         );