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