Added custom info support.
[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>openssl</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 #include <osp/ospb64.h>
43
44 #include "asterisk/paths.h"
45 #include "asterisk/lock.h"
46 #include "asterisk/config.h"
47 #include "asterisk/utils.h"
48 #include "asterisk/causes.h"
49 #include "asterisk/channel.h"
50 #include "asterisk/app.h"
51 #include "asterisk/module.h"
52 #include "asterisk/pbx.h"
53 #include "asterisk/cli.h"
54 #include "asterisk/astosp.h"
55
56 /*** DOCUMENTATION
57         <application name="OSPAuth" language="en_US">
58                 <synopsis>
59                         OSP Authentication.
60                 </synopsis>
61                 <syntax>
62                         <parameter name="provider" />
63                         <parameter name="options" />
64                 </syntax>
65                 <description>
66                         <para>Authenticate a call by OSP and sets the variables:</para>
67                         <variablelist>
68                                 <variable name="OSPINHANDLE">
69                                         <para>The inbound call transaction handle.</para>
70                                 </variable>
71                                 <variable name="OSPINTIMELIMIT">
72                                         <para>The inbound call duration limit in seconds.</para>
73                                 </variable>
74                         </variablelist>
75                         <para>This application sets the following channel variable upon completion:</para>
76                         <variablelist>
77                                 <variable name="OSPAUTHSTATUS">
78                                         <para>The status of the OSP Auth attempt as a text string, one of</para>
79                                         <value name="SUCCESS" />
80                                         <value name="FAILED" />
81                                         <value name="ERROR" />
82                                 </variable>
83                         </variablelist>
84                 </description>
85         </application>
86         <application name="OSPLookup" language="en_US">
87                 <synopsis>
88                         Lookup destination by OSP.
89                 </synopsis>
90                 <syntax>
91                         <parameter name="exten" required="true" />
92                         <parameter name="provider" />
93                         <parameter name="options">
94                                 <enumlist>
95                                         <enum name="h">
96                                                 <para>generate H323 call id for the outbound call</para>
97                                         </enum>
98                                         <enum name="s">
99                                                 <para>generate SIP call id for the outbound call.
100                                                 Have not been implemented</para>
101                                         </enum>
102                                         <enum name="i">
103                                                 <para>generate IAX call id for the outbound call.
104                                                 Have not been implemented</para>
105                                         </enum>
106                                 </enumlist>
107                         </parameter>
108                 </syntax>
109                 <description>
110                         <para>Looks up an extension via OSP and sets the variables, where <literal>n</literal> is the
111                         number of the result beginning with <literal>1</literal>:</para>
112                         <variablelist>
113                                 <variable name="OSPOUTHANDLE">
114                                         <para>The OSP Handle for anything remaining.</para>
115                                 </variable>
116                                 <variable name="OSPTECH">
117                                         <para>The technology to use for the call.</para>
118                                 </variable>
119                                 <variable name="OSPDESTINATION">
120                                         <para>The destination to use for the call.</para>
121                                 </variable>
122                                 <variable name="OSPOUTCALLING">
123                                         <para>The calling number to use for the call.</para>
124                                 </variable>
125                                 <variable name="OSPOUTCALLED">
126                                         <para>The called number to use for the call.</para>
127                                 </variable>
128                                 <variable name="OSPDIALSTR">
129                                         <para>The dial command string.</para>
130                                 </variable>
131                                 <variable name="OSPOUTTOKEN">
132                                         <para>The actual OSP token as a string.</para>
133                                 </variable>
134                                 <variable name="OSPOUTTIMELIMIT">
135                                         <para>The outbound call duraction limit in seconds.</para>
136                                 </variable>
137                                 <variable name="OSPOUTCALLIDTYPES">
138                                         <para>The outbound call id types.</para>
139                                 </variable>
140                                 <variable name="OSPOUTCALLID">
141                                         <para>The outbound call id.</para>
142                                 </variable>
143                                 <variable name="OSPDESTREMAILS">
144                                         <para>The number of OSP results total remaining.</para>
145                                 </variable>
146                         </variablelist>
147                         <variablelist>
148                                 <variable name="OSPLOOKUPSTATUS">
149                                         <para>This application sets the following channel variable upon completion:</para>
150                                         <value name="SUCCESS" />
151                                         <value name="FAILED" />
152                                         <value name="ERROR" />
153                                 </variable>
154                         </variablelist>
155                 </description>
156         </application>
157         <application name="OSPNext" language="en_US">
158                 <synopsis>
159                         Lookup next destination by OSP.
160                 </synopsis>
161                 <syntax>
162                         <parameter name="cause" required="true" />
163                         <parameter name="provider" />
164                         <parameter name="options" />
165                 </syntax>
166                 <description>
167                         <para>Looks up the next OSP Destination for <variable>OSPOUTHANDLE</variable>.</para>
168                         <para>This application sets the following channel variable upon completion:</para>
169                         <variablelist>
170                                 <variable name="OSPNEXTSTATUS">
171                                         <para>The status of the OSP Next attempt as a text string, one of</para>
172                                         <value name="SUCCESS" />
173                                         <value name="FAILED" />
174                                         <value name="ERROR" />
175                                 </variable>
176                         </variablelist>
177                 </description>
178                 <see-also>
179                         <ref type="application">OSPLookup</ref>
180                 </see-also>
181         </application>
182         <application name="OSPFinish" language="en_US">
183                 <synopsis>
184                         Record OSP entry.
185                 </synopsis>
186                 <syntax>
187                         <parameter name="status" />
188                         <parameter name="options" />
189                 </syntax>
190                 <description>
191                         <para>Records call state for <variable>OSPINHANDLE</variable>, according to status, which should
192                         be one of <literal>BUSY</literal>, <literal>CONGESTION</literal>, <literal>ANSWER</literal>,
193                         <literal>NOANSWER</literal>, or <literal>CHANUNAVAIL</literal> or coincidentally, just what the
194                         Dial application stores in its <variable>DIALSTATUS</variable>.</para>
195                         <para>This application sets the following channel variable upon completion:</para>
196                         <variablelist>
197                                 <variable name="OSPFINISHSTATUS">
198                                         <para>The status of the OSP Finish attempt as a text string, one of</para>
199                                         <value name="SUCCESS" />
200                                         <value name="FAILED" />
201                                         <value name="ERROR" />
202                                 </variable>
203                         </variablelist>
204                 </description>
205         </application>
206  ***/
207
208 /* OSP Buffer Sizes */
209 #define OSP_INTSTR_SIZE         ((unsigned int)16)              /* OSP signed/unsigned int string buffer size */
210 #define OSP_NORSTR_SIZE         ((unsigned int)256)             /* OSP normal string buffer size */
211 #define OSP_KEYSTR_SIZE         ((unsigned int)1024)    /* OSP certificate string buffer size */
212 #define OSP_TOKSTR_SIZE         ((unsigned int)4096)    /* OSP token string buffer size */
213 #define OSP_TECHSTR_SIZE        ((unsigned int)32)              /* OSP signed/unsigned int string buffer size */
214 #define OSP_UUID_SIZE           ((unsigned int)16)              /* UUID size */
215 #define OSP_UUIDSTR_SIZE        ((unsigned int)36)              /* UUID string size */
216 #define OSP_QOSSTR_SIZE         ((unsigned int)1024)    /* QoS string buffer size */
217
218 /* OSP Authentication Policy */
219 enum osp_authpolicy {
220         OSP_AUTH_NO,            /* Accept any call */
221         OSP_AUTH_YES,           /* Accept call with valid OSP token or without OSP token */
222         OSP_AUTH_EXCLUSIVE      /* Only accept call with valid OSP token */
223 };
224
225 /* Call ID type*/
226 #define OSP_CALLID_UNDEFINED    ((unsigned int)0)                       /* UNDEFINED */
227 #define OSP_CALLID_SIP                  ((unsigned int)(1 << 0))        /* SIP */
228 #define OSP_CALLID_H323                 ((unsigned int)(1 << 1))        /* H.323 */
229 #define OSP_CALLID_IAX                  ((unsigned int)(1 << 2))        /* IAX2 */
230 #define OSP_CALLID_MAXNUM               ((unsigned int)3)                       /* Max number of call ID type */
231
232 /* OSP Supported Destination Protocols */
233 #define OSP_PROT_SIP                    ((char*)"SIP")                          /* SIP protocol name */
234 #define OSP_PROT_H323                   ((char*)"H323")                         /* H323 Q931 protocol name*/
235 #define OSP_PROT_IAX                    ((char*)"IAX")                          /* IAX protocol name */
236 #define OSP_PROT_SKYPE                  ((char*)"SKYPE")                        /* Skype protocol name */
237
238 /* OSP supported Destination Tech */
239 #define OSP_TECH_SIP                    ((char*)"SIP")                          /* SIP tech name */
240 #define OSP_TECH_H323                   ((char*)"H323")                         /* OH323 tech name */
241 #define OSP_TECH_IAX                    ((char*)"IAX2")                         /* IAX2 tech name */
242 #define OSP_TECH_SKYPE                  ((char*)"SKYPE")                        /* Skype tech name */
243
244 /* SIP OSP header field name */
245 #define OSP_SIP_HEADER                  ((char*)"P-OSP-Auth-Token: ")
246
247 /* OSP Constants */
248 #define OSP_INVALID_HANDLE              ((int)-1)                                       /* Invalid OSP handle, provider, transaction etc. */
249 #define OSP_CONFIG_FILE                 ((const char*)"osp.conf")       /* OSP configuration file name */
250 #define OSP_GENERAL_CAT                 ((const char*)"general")        /* OSP global configuration context name */
251 #define OSP_DEF_PROVIDER                ((const char*)"default")        /* OSP default provider context name */
252 #define OSP_MAX_CERTS                   ((unsigned int)10)                      /* OSP max number of cacerts */
253 #define OSP_MAX_SRVS                    ((unsigned int)10)                      /* OSP max number of service points */
254 #define OSP_DEF_MAXCONNECTIONS  ((unsigned int)20)                      /* OSP default max_connections */
255 #define OSP_MIN_MAXCONNECTIONS  ((unsigned int)1)                       /* OSP min max_connections */
256 #define OSP_MAX_MAXCONNECTIONS  ((unsigned int)1000)            /* OSP max max_connections */
257 #define OSP_DEF_RETRYDELAY              ((unsigned int)0)                       /* OSP default retry delay */
258 #define OSP_MIN_RETRYDELAY              ((unsigned int)0)                       /* OSP min retry delay */
259 #define OSP_MAX_RETRYDELAY              ((unsigned int)10)                      /* OSP max retry delay */
260 #define OSP_DEF_RETRYLIMIT              ((unsigned int)2)                       /* OSP default retry times */
261 #define OSP_MIN_RETRYLIMIT              ((unsigned int)0)                       /* OSP min retry times */
262 #define OSP_MAX_RETRYLIMIT              ((unsigned int)100)                     /* OSP max retry times */
263 #define OSP_DEF_TIMEOUT                 ((unsigned int)500)                     /* OSP default timeout in ms */
264 #define OSP_MIN_TIMEOUT                 ((unsigned int)200)                     /* OSP min timeout in ms */
265 #define OSP_MAX_TIMEOUT                 ((unsigned int)10000)           /* OSP max timeout in ms */
266 #define OSP_DEF_AUTHPOLICY              ((enum osp_authpolicy)OSP_AUTH_YES)
267 #define OSP_AUDIT_URL                   ((const char*)"localhost")      /* OSP default Audit URL */
268 #define OSP_LOCAL_VALIDATION    ((int)1)                                        /* Validate OSP token locally */
269 #define OSP_SSL_LIFETIME                ((unsigned int)300)                     /* SSL life time, in seconds */
270 #define OSP_HTTP_PERSISTENCE    ((int)1)                                        /* In seconds */
271 #define OSP_CUSTOMER_ID                 ((const char*)"")                       /* OSP customer ID */
272 #define OSP_DEVICE_ID                   ((const char*)"")                       /* OSP device ID */
273 #define OSP_DEF_DESTINATIONS    ((unsigned int)5)                       /* OSP default max number of destinations */
274 #define OSP_DEF_TIMELIMIT               ((unsigned int)0)                       /* OSP default duration limit, no limit */
275 #define OSP_DEF_PROTOCOL                OSP_PROT_SIP                            /* OSP default destination protocol, SIP */
276 #define OSP_MAX_CUSTOMINFO              ((unsigned int)8)                       /* OSP max number of custom info */
277
278 /* OSP Provider */
279 struct osp_provider {
280         char name[OSP_NORSTR_SIZE];                                             /* OSP provider context name */
281         char privatekey[OSP_NORSTR_SIZE];                               /* OSP private key file name */
282         char localcert[OSP_NORSTR_SIZE];                                /* OSP local cert file name */
283         unsigned int cacount;                                                   /* Number of cacerts */
284         char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE];   /* Cacert file names */
285         unsigned int spcount;                                                   /* Number of service points */
286         char srvpoints[OSP_MAX_SRVS][OSP_NORSTR_SIZE];  /* Service point URLs */
287         int maxconnections;                                                             /* Max number of connections */
288         int retrydelay;                                                                 /* Retry delay */
289         int retrylimit;                                                                 /* Retry limit */
290         int timeout;                                                                    /* Timeout in ms */
291         char source[OSP_NORSTR_SIZE];                                   /* IP of self */
292         enum osp_authpolicy authpolicy;                                 /* OSP authentication policy */
293         char* defaultprotocol;                                                  /* OSP default destination protocol */
294         OSPTPROVHANDLE handle;                                                  /* OSP provider handle */
295         struct osp_provider* next;                                              /* Pointer to next OSP provider */
296 };
297
298 /* Call ID */
299 struct osp_callid {
300         unsigned char buf[OSPC_CALLID_MAXSIZE];         /* Call ID string */
301         unsigned int len;                                                       /* Call ID length */
302 };
303
304 /* Number Portability Parameters */
305 struct osp_npparam {
306         const char* rn;         /* Rounding number */
307         const char* cic;        /* Carrier Identification Code */
308         int npdi;                       /* NP Database Dip Indicator */
309 };
310
311 /* SIP Diversion Header Parameters */
312 struct osp_diversion {
313         const char* user;
314         const char* host;
315 };
316
317 /* OSP Application In/Output Results */
318 struct osp_results {
319         int inhandle;                                           /* Inbound transaction handle */
320         int outhandle;                                          /* Outbound transaction handle */
321         unsigned int intimelimit;                       /* Inbound duration limit */
322         unsigned int outtimelimit;                      /* Outbound duration limit */
323         char tech[OSP_TECHSTR_SIZE];            /* Outbound Asterisk TECH string */
324         char dest[OSP_NORSTR_SIZE];                     /* Outbound destination IP address */
325         char calling[OSP_NORSTR_SIZE];          /* Outbound calling number, may be translated */
326         char called[OSP_NORSTR_SIZE];           /* Outbound called number, may be translated */
327         char token[OSP_TOKSTR_SIZE];            /* Outbound OSP token */
328         char networkid[OSP_NORSTR_SIZE];        /* Outbound network ID */
329         char nprn[OSP_NORSTR_SIZE];                     /* Outbound NP routing number */
330         char npcic[OSP_NORSTR_SIZE];            /* Outbound NP carrier identification code */
331         int npdi;                                                       /* Outbound NP database dip indicator */
332         unsigned int numresults;                        /* Number of remain outbound destinations */
333         struct osp_callid outcallid;            /* Outbound call ID */
334 };
335
336 /* OSP Call Leg */
337 enum osp_callleg {
338         OSP_CALL_INBOUND,
339         OSP_CALL_OUTBOUND
340 };
341
342 /* OSP */
343 enum osp_direction {
344         OSP_DIR_RX = 0,
345         OSP_DIR_TX,
346         OSP_DIR_NUMBER
347 };
348
349 /* OSP Metrics */
350 struct osp_metrics {
351         int value;      /* Value */
352         float min;      /* Minimum */
353         float max;      /* Maximum */
354         float avg;      /* Average */
355         float ndev;     /* Normal deviation */
356         float sdev;     /* Standard deviation */
357 };
358
359 /* OSP Module Global Variables */
360 AST_MUTEX_DEFINE_STATIC(osplock);                                                       /* Lock of OSP provider list */
361 static int osp_initialized = 0;                                                         /* Init flag */
362 static int osp_hardware = 0;                                                            /* Hardware accelleration flag */
363 static int osp_security = 0;                                                            /* Using security features flag */
364 static struct osp_provider* ospproviders = NULL;                        /* OSP provider list */
365 static unsigned int osp_tokenformat = TOKEN_ALGO_SIGNED;        /* Token format supported */
366
367 /* OSP default certificates */
368 const char* B64PKey = "MIIBOgIBAAJBAK8t5l+PUbTC4lvwlNxV5lpl+2dwSZGW46dowTe6y133XyVEwNiiRma2YNk3xKs/TJ3Wl9Wpns2SYEAJsFfSTukCAwEAAQJAPz13vCm2GmZ8Zyp74usTxLCqSJZNyMRLHQWBM0g44Iuy4wE3vpi7Wq+xYuSOH2mu4OddnxswCP4QhaXVQavTAQIhAOBVCKXtppEw9UaOBL4vW0Ed/6EA/1D8hDW6St0h7EXJAiEAx+iRmZKhJD6VT84dtX5ZYNVk3j3dAcIOovpzUj9a0CECIEduTCapmZQ5xqAEsLXuVlxRtQgLTUD4ZxDElPn8x0MhAiBE2HlcND0+qDbvtwJQQOUzDgqg5xk3w8capboVdzAlQQIhAMC+lDL7+gDYkNAft5Mu+NObJmQs4Cr+DkDFsKqoxqrm";
369 const char* B64LCert = "MIIBeTCCASMCEHqkOHVRRWr+1COq3CR/xsowDQYJKoZIhvcNAQEEBQAwOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMB4XDTA1MDYyMzAwMjkxOFoXDTA2MDYyNDAwMjkxOFowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCvLeZfj1G0wuJb8JTcVeZaZftncEmRluOnaME3ustd918lRMDYokZmtmDZN8SrP0yd1pfVqZ7NkmBACbBX0k7pAgMBAAEwDQYJKoZIhvcNAQEEBQADQQDnV8QNFVVJx/+7IselU0wsepqMurivXZzuxOmTEmTVDzCJx1xhA8jd3vGAj7XDIYiPub1PV23eY5a2ARJuw5w9";
370 const char* B64CACert = "MIIBYDCCAQoCAQEwDQYJKoZIhvcNAQEEBQAwOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMB4XDTAyMDIwNDE4MjU1MloXDTEyMDIwMzE4MjU1MlowOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPGeGwV41EIhX0jEDFLRXQhDEr50OUQPq+f55VwQd0TQNts06BP29+UiNdRW3c3IRHdZcJdC1Cg68ME9cgeq0h8CAwEAATANBgkqhkiG9w0BAQQFAANBAGkzBSj1EnnmUxbaiG1N4xjIuLAWydun7o3bFk2tV8dBIhnuh445obYyk1EnQ27kI7eACCILBZqi2MHDOIMnoN0=";
371
372 /* OSP Client Wrapper APIs */
373
374 /*!
375  * \brief Create OSP provider handle according to configuration
376  * \param cfg OSP configuration
377  * \param provider OSP provider context name
378  * \return 1 Success, 0 Failed, -1 Error
379  */
380 static int osp_create_provider(
381         struct ast_config* cfg,
382         const char* provider)
383 {
384         int res = 0;
385         struct ast_variable* v;
386         struct osp_provider* p;
387         OSPTPRIVATEKEY privatekey;
388         OSPT_CERT localcert;
389         OSPT_CERT cacerts[OSP_MAX_CERTS];
390         const OSPT_CERT* pcacerts[OSP_MAX_CERTS];
391         const char* psrvpoints[OSP_MAX_SRVS];
392         unsigned char privatekeydata[OSP_KEYSTR_SIZE];
393         unsigned char localcertdata[OSP_KEYSTR_SIZE];
394         unsigned char cacertdata[OSP_KEYSTR_SIZE];
395         int i, t, error = OSPC_ERR_NO_ERROR;
396
397         if (!(p = ast_calloc(1, sizeof(*p)))) {
398                 ast_log(LOG_ERROR, "Out of memory\n");
399                 return -1;
400         }
401
402         /* ast_calloc has set 0 in p */
403         ast_copy_string(p->name, provider, sizeof(p->name));
404         snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, provider);
405         snprintf(p->localcert, sizeof(p->localcert), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, provider);
406         snprintf(p->cacerts[0], sizeof(p->cacerts[0]), "%s/%s-cacert_0.pem", ast_config_AST_KEY_DIR, provider);
407         p->maxconnections = OSP_DEF_MAXCONNECTIONS;
408         p->retrydelay = OSP_DEF_RETRYDELAY;
409         p->retrylimit = OSP_DEF_RETRYLIMIT;
410         p->timeout = OSP_DEF_TIMEOUT;
411         p->authpolicy = OSP_DEF_AUTHPOLICY;
412         p->defaultprotocol = OSP_DEF_PROTOCOL;
413         p->handle = OSP_INVALID_HANDLE;
414
415         v = ast_variable_browse(cfg, provider);
416         while(v) {
417                 if (!strcasecmp(v->name, "privatekey")) {
418                         if (osp_security) {
419                                 if (v->value[0] == '/') {
420                                         ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey));
421                                 } else {
422                                         snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value);
423                                 }
424                                 ast_debug(1, "OSP: privatekey '%s'\n", p->privatekey);
425                         }
426                 } else if (!strcasecmp(v->name, "localcert")) {
427                         if (osp_security) {
428                                 if (v->value[0] == '/') {
429                                         ast_copy_string(p->localcert, v->value, sizeof(p->localcert));
430                                 } else {
431                                         snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
432                                 }
433                                 ast_debug(1, "OSP: localcert '%s'\n", p->localcert);
434                         }
435                 } else if (!strcasecmp(v->name, "cacert")) {
436                         if (osp_security) {
437                                 if (p->cacount < OSP_MAX_CERTS) {
438                                         if (v->value[0] == '/') {
439                                                 ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0]));
440                                         } else {
441                                                 snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
442                                         }
443                                         ast_debug(1, "OSP: cacerts[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
444                                         p->cacount++;
445                                 } else {
446                                         ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno);
447                                 }
448                         }
449                 } else if (!strcasecmp(v->name, "servicepoint")) {
450                         if (p->spcount < OSP_MAX_SRVS) {
451                                 ast_copy_string(p->srvpoints[p->spcount], v->value, sizeof(p->srvpoints[0]));
452                                 ast_debug(1, "OSP: servicepoint[%d]: '%s'\n", p->spcount, p->srvpoints[p->spcount]);
453                                 p->spcount++;
454                         } else {
455                                 ast_log(LOG_WARNING, "OSP: Too many Service Points at line %d\n", v->lineno);
456                         }
457                 } else if (!strcasecmp(v->name, "maxconnections")) {
458                         if ((sscanf(v->value, "%30d", &t) == 1) && (t >= OSP_MIN_MAXCONNECTIONS) && (t <= OSP_MAX_MAXCONNECTIONS)) {
459                                 p->maxconnections = t;
460                                 ast_debug(1, "OSP: maxconnections '%d'\n", t);
461                         } else {
462                                 ast_log(LOG_WARNING, "OSP: maxconnections should be an integer from %d to %d, not '%s' at line %d\n",
463                                         OSP_MIN_MAXCONNECTIONS, OSP_MAX_MAXCONNECTIONS, v->value, v->lineno);
464                         }
465                 } else if (!strcasecmp(v->name, "retrydelay")) {
466                         if ((sscanf(v->value, "%30d", &t) == 1) && (t >= OSP_MIN_RETRYDELAY) && (t <= OSP_MAX_RETRYDELAY)) {
467                                 p->retrydelay = t;
468                                 ast_debug(1, "OSP: retrydelay '%d'\n", t);
469                         } else {
470                                 ast_log(LOG_WARNING, "OSP: retrydelay should be an integer from %d to %d, not '%s' at line %d\n",
471                                         OSP_MIN_RETRYDELAY, OSP_MAX_RETRYDELAY, v->value, v->lineno);
472                         }
473                 } else if (!strcasecmp(v->name, "retrylimit")) {
474                         if ((sscanf(v->value, "%30d", &t) == 1) && (t >= OSP_MIN_RETRYLIMIT) && (t <= OSP_MAX_RETRYLIMIT)) {
475                                 p->retrylimit = t;
476                                 ast_debug(1, "OSP: retrylimit '%d'\n", t);
477                         } else {
478                                 ast_log(LOG_WARNING, "OSP: retrylimit should be an integer from %d to %d, not '%s' at line %d\n",
479                                         OSP_MIN_RETRYLIMIT, OSP_MAX_RETRYLIMIT, v->value, v->lineno);
480                         }
481                 } else if (!strcasecmp(v->name, "timeout")) {
482                         if ((sscanf(v->value, "%30d", &t) == 1) && (t >= OSP_MIN_TIMEOUT) && (t <= OSP_MAX_TIMEOUT)) {
483                                 p->timeout = t;
484                                 ast_debug(1, "OSP: timeout '%d'\n", t);
485                         } else {
486                                 ast_log(LOG_WARNING, "OSP: timeout should be an integer from %d to %d, not '%s' at line %d\n",
487                                         OSP_MIN_TIMEOUT, OSP_MAX_TIMEOUT, v->value, v->lineno);
488                         }
489                 } else if (!strcasecmp(v->name, "source")) {
490                         ast_copy_string(p->source, v->value, sizeof(p->source));
491                         ast_debug(1, "OSP: source '%s'\n", p->source);
492                 } else if (!strcasecmp(v->name, "authpolicy")) {
493                         if ((sscanf(v->value, "%30d", &t) == 1) && ((t == OSP_AUTH_NO) || (t == OSP_AUTH_YES) || (t == OSP_AUTH_EXCLUSIVE))) {
494                                 p->authpolicy = t;
495                                 ast_debug(1, "OSP: authpolicy '%d'\n", t);
496                         } else {
497                                 ast_log(LOG_WARNING, "OSP: authpolicy should be %d, %d or %d, not '%s' at line %d\n",
498                                         OSP_AUTH_NO, OSP_AUTH_YES, OSP_AUTH_EXCLUSIVE, v->value, v->lineno);
499                         }
500                 } else if (!strcasecmp(v->name, "defaultprotocol")) {
501                         if (!strcasecmp(v->value, OSP_PROT_SIP)) {
502                                 p->defaultprotocol = OSP_PROT_SIP;
503                                 ast_debug(1, "OSP: default protocol SIP\n");
504                         } else if (!strcasecmp(v->value, OSP_PROT_H323)) {
505                                 p->defaultprotocol = OSP_PROT_H323;
506                                 ast_debug(1, "OSP: default protocol H.323\n");
507                         } else if (!strcasecmp(v->value, OSP_PROT_IAX)) {
508                                 p->defaultprotocol = OSP_PROT_IAX;
509                                 ast_debug(1, "OSP: default protocol IAX\n");
510                         } else if (!strcasecmp(v->value, OSP_PROT_SKYPE)) {
511                                 p->defaultprotocol = OSP_PROT_SKYPE;
512                                 ast_debug(1, "OSP: default protocol Skype\n");
513                         } else {
514                                 ast_log(LOG_WARNING, "OSP: default protocol should be %s, %s, %s or %s not '%s' at line %d\n",
515                                         OSP_PROT_SIP, OSP_PROT_H323, OSP_PROT_IAX, OSP_PROT_SKYPE, v->value, v->lineno);
516                         }
517                 }
518                 v = v->next;
519         }
520
521         if (p->cacount == 0) {
522                 p->cacount = 1;
523         }
524
525         for (i = 0; i < p->spcount; i++) {
526                 psrvpoints[i] = p->srvpoints[i];
527         }
528
529         if (osp_security) {
530                 privatekey.PrivateKeyData = NULL;
531                 privatekey.PrivateKeyLength = 0;
532
533                 localcert.CertData = NULL;
534                 localcert.CertDataLength = 0;
535
536                 for (i = 0; i < p->cacount; i++) {
537                         cacerts[i].CertData = NULL;
538                         cacerts[i].CertDataLength = 0;
539                 }
540
541                 if ((error = OSPPUtilLoadPEMPrivateKey((unsigned char*)p->privatekey, &privatekey)) != OSPC_ERR_NO_ERROR) {
542                         ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s', error '%d'\n", p->privatekey, error);
543                 } else if ((error = OSPPUtilLoadPEMCert((unsigned char*)p->localcert, &localcert)) != OSPC_ERR_NO_ERROR) {
544                         ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s', error '%d'\n", p->localcert, error);
545                 } else {
546                         for (i = 0; i < p->cacount; i++) {
547                                 if ((error = OSPPUtilLoadPEMCert((unsigned char*)p->cacerts[i], &cacerts[i])) != OSPC_ERR_NO_ERROR) {
548                                         ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s', error '%d'\n", p->cacerts[i], error);
549                                         break;
550                                 } else {
551                                         pcacerts[i] = &cacerts[i];
552                                 }
553                         }
554                 }
555         } else {
556                 privatekey.PrivateKeyData = privatekeydata;
557                 privatekey.PrivateKeyLength = sizeof(privatekeydata);
558
559                 localcert.CertData = localcertdata;
560                 localcert.CertDataLength = sizeof(localcertdata);
561
562                 cacerts[0].CertData = cacertdata;
563                 cacerts[0].CertDataLength = sizeof(cacertdata);
564                 pcacerts[0] = &cacerts[0];
565
566                 if ((error = OSPPBase64Decode(B64PKey, strlen(B64PKey), privatekey.PrivateKeyData, &privatekey.PrivateKeyLength)) != OSPC_ERR_NO_ERROR) {
567                         ast_log(LOG_WARNING, "OSP: Unable to decode private key, error '%d'\n", error);
568                 } else if ((error = OSPPBase64Decode(B64LCert, strlen(B64LCert), localcert.CertData, &localcert.CertDataLength)) != OSPC_ERR_NO_ERROR) {
569                         ast_log(LOG_WARNING, "OSP: Unable to decode local cert, error '%d'\n", error);
570                 } else if ((error = OSPPBase64Decode(B64CACert, strlen(B64CACert), cacerts[0].CertData, &cacerts[0].CertDataLength)) != OSPC_ERR_NO_ERROR) {
571                         ast_log(LOG_WARNING, "OSP: Unable to decode cacert, error '%d'\n", error);
572                 }
573         }
574
575         if (error == OSPC_ERR_NO_ERROR) {
576                 error = OSPPProviderNew(
577                         p->spcount,
578                         psrvpoints,
579                         NULL,
580                         OSP_AUDIT_URL,
581                         &privatekey,
582                         &localcert,
583                         p->cacount,
584                         pcacerts,
585                         OSP_LOCAL_VALIDATION,
586                         OSP_SSL_LIFETIME,
587                         p->maxconnections,
588                         OSP_HTTP_PERSISTENCE,
589                         p->retrydelay,
590                         p->retrylimit,
591                         p->timeout,
592                         OSP_CUSTOMER_ID,
593                         OSP_DEVICE_ID,
594                         &p->handle);
595                 if (error != OSPC_ERR_NO_ERROR) {
596                         ast_log(LOG_WARNING, "OSP: Unable to create provider '%s', error '%d'\n", provider, error);
597                         res = -1;
598                 } else {
599                         ast_debug(1, "OSP: provider '%s'\n", provider);
600                         ast_mutex_lock(&osplock);
601                         p->next = ospproviders;
602                         ospproviders = p;
603                         ast_mutex_unlock(&osplock);
604                         res = 1;
605                 }
606         }
607
608         if (osp_security) {
609                 for (i = 0; i < p->cacount; i++) {
610                         if (cacerts[i].CertData) {
611                                 ast_free(cacerts[i].CertData);
612                         }
613                 }
614                 if (localcert.CertData) {
615                         ast_free(localcert.CertData);
616                 }
617                 if (privatekey.PrivateKeyData) {
618                         ast_free(privatekey.PrivateKeyData);
619                 }
620         }
621
622         if (res != 1) {
623                 ast_free(p);
624         }
625
626         return res;
627 }
628
629 /*!
630  * \brief Get OSP provider by name
631  * \param name OSP provider context name
632  * \param provider OSP provider structure
633  * \return 1 Success, 0 Failed, -1 Error
634  */
635 static int osp_get_provider(
636         const char* name,
637         struct osp_provider** provider)
638 {
639         int res = 0;
640         struct osp_provider* p;
641
642         ast_mutex_lock(&osplock);
643         p = ospproviders;
644         while(p) {
645                 if (!strcasecmp(p->name, name)) {
646                         *provider = p;
647                         ast_debug(1, "OSP: find provider '%s'\n", name);
648                         res = 1;
649                         break;
650                 }
651                 p = p->next;
652         }
653         ast_mutex_unlock(&osplock);
654
655         return res;
656 }
657
658 /*!
659  * \brief Create OSP transaction handle
660  * \param provider OSP provider context name
661  * \param transaction OSP transaction handle, output
662  * \param source Source of provider, output
663  * \param sourcesize Size of source buffer, in
664  * \return 1 Success, 0 Failed, -1 Error
665  */
666 static int osp_create_transaction(
667         const char* provider,
668         int* transaction,
669         char* source,
670         unsigned int srcsize)
671 {
672         int res = 0;
673         struct osp_provider* p;
674         int error;
675
676         ast_mutex_lock(&osplock);
677         p = ospproviders;
678         while(p) {
679                 if (!strcasecmp(p->name, provider)) {
680                         error = OSPPTransactionNew(p->handle, transaction);
681                         if (error == OSPC_ERR_NO_ERROR) {
682                                 ast_debug(1, "OSP: transaction '%d'\n", *transaction);
683                                 ast_copy_string(source, p->source, srcsize);
684                                 ast_debug(1, "OSP: source '%s'\n", source);
685                                 res = 1;
686                         } else {
687                                 *transaction = OSP_INVALID_HANDLE;
688                                 ast_debug(1, "OSP: Unable to create transaction handle, error '%d'\n", error);
689                                 res = -1;
690                         }
691                         break;
692                 }
693                 p = p->next;
694         }
695         ast_mutex_unlock(&osplock);
696
697         return res;
698 }
699
700 /*!
701  * \brief Convert "address:port" to "[x.x.x.x]:port" or "hostname:port" format
702  * \param src Source address string
703  * \param dest Destination address string
704  * \param destsize Size of dest buffer
705  */
706 static void osp_convert_inout(
707         const char* src,
708         char* dest,
709         int destsize)
710 {
711         struct in_addr inp;
712         char buffer[OSP_NORSTR_SIZE];
713         char* port;
714
715         if (!ast_strlen_zero(src)) {
716                 ast_copy_string(buffer, src, sizeof(buffer));
717
718                 if((port = strchr(buffer, ':')) != NULL) {
719                         *port = '\0';
720                         port++;
721                 }
722
723                 if (inet_pton(AF_INET, buffer, &inp) == 1) {
724                         if (port != NULL) {
725                                 snprintf(dest, destsize, "[%s]:%s", buffer, port);
726                         } else {
727                                 snprintf(dest, destsize, "[%s]", buffer);
728                         }
729                         dest[destsize - 1] = '\0';
730                 } else {
731                         ast_copy_string(dest, src, destsize);
732                 }
733         } else {
734                 *dest = '\0';
735         }
736 }
737
738 /*!
739  * \brief Convert "[x.x.x.x]:port" or "hostname:prot" to "address:port" format
740  * \param src Source address string
741  * \param dest Destination address string
742  * \param destsize Size of dest buffer
743  */
744 static void osp_convert_outin(
745         const char* src,
746         char* dest,
747         int destsize)
748 {
749         char buffer[OSP_NORSTR_SIZE];
750         char* end;
751         char* port;
752
753         if (!ast_strlen_zero(src)) {
754                 ast_copy_string(buffer, src, sizeof(buffer));
755
756                 if (buffer[0] == '[') {
757                         if((port = strchr(buffer + 1, ':')) != NULL) {
758                                 *port = '\0';
759                                 port++;
760                         }
761
762                         if ((end = strchr(buffer + 1, ']')) != NULL) {
763                                 *end = '\0';
764                         }
765
766                         if (port != NULL) {
767                                 snprintf(dest, destsize, "%s:%s", buffer + 1, port);
768                                 dest[destsize - 1] = '\0';
769                         } else {
770                                 ast_copy_string(dest, buffer + 1, destsize);
771                         }
772                 } else {
773                         ast_copy_string(dest, src, destsize);
774                 }
775         } else {
776                 *dest = '\0';
777         }
778 }
779
780 /*!
781  * \brief Validate OSP token of inbound call
782  * \param transaction OSP transaction handle
783  * \param source Source of inbound call
784  * \param destination Destination of inbound call
785  * \param calling Calling number
786  * \param called Called number
787  * \param token OSP token, may be empty
788  * \param timelimit Call duration limit, output
789  * \return 1 Success, 0 Failed, -1 Error
790  */
791 static int osp_validate_token(
792         int transaction,
793         const char* source,
794         const char* destination,
795         const char* calling,
796         const char* called,
797         const char* token,
798         unsigned int* timelimit)
799 {
800         int res;
801         int tokenlen;
802         unsigned char tokenstr[OSP_TOKSTR_SIZE];
803         char src[OSP_NORSTR_SIZE];
804         char dest[OSP_NORSTR_SIZE];
805         unsigned int authorised;
806         unsigned int dummy = 0;
807         int error;
808
809         tokenlen = ast_base64decode(tokenstr, token, strlen(token));
810         osp_convert_inout(source, src, sizeof(src));
811         osp_convert_inout(destination, dest, sizeof(dest));
812         error = OSPPTransactionValidateAuthorisation(
813                 transaction,
814                 src,
815                 dest,
816                 NULL,
817                 NULL,
818                 calling ? calling : "",
819                 OSPC_NFORMAT_E164,
820                 called,
821                 OSPC_NFORMAT_E164,
822                 0,
823                 NULL,
824                 tokenlen,
825                 (char*)tokenstr,
826                 &authorised,
827                 timelimit,
828                 &dummy,
829                 NULL,
830                 osp_tokenformat);
831         if (error != OSPC_ERR_NO_ERROR) {
832                 ast_debug(1, "OSP: Unable to validate inbound token, error '%d'\n", error);
833                 res = -1;
834         } else if (authorised) {
835                 ast_debug(1, "OSP: Authorised\n");
836                 res = 1;
837         } else {
838                 ast_debug(1, "OSP: Unauthorised\n");
839                 res = 0;
840         }
841
842         return res;
843 }
844
845 /*!
846  * \brief Choose min duration limit
847  * \param in Inbound duration limit
848  * \param out Outbound duration limit
849  * \return min duration limit
850  */
851 static unsigned int osp_choose_timelimit(
852         unsigned int in,
853         unsigned int out)
854 {
855         if (in == OSP_DEF_TIMELIMIT) {
856                 return out;
857         } else if (out == OSP_DEF_TIMELIMIT) {
858                 return in;
859         } else {
860                 return in < out ? in : out;
861         }
862 }
863
864 /*!
865  * \brief Choose min duration limit
866  * \param provider OSP provider
867  * \param calling Calling number
868  * \param called Called number
869  * \param destination Destination IP in '[x.x.x.x]' format
870  * \param tokenlen OSP token length
871  * \param token OSP token
872  * \param reason Failure reason, output
873  * \param results OSP lookup results, in/output
874  * \return 1 Success, 0 Failed, -1 Error
875  */
876 static int osp_check_destination(
877         struct osp_provider* provider,
878         const char* calling,
879         const char* called,
880         char* destination,
881         unsigned int tokenlen,
882         const char* token,
883         OSPEFAILREASON* reason,
884         struct osp_results* results)
885 {
886         int res;
887         OSPE_DEST_OSPENABLED enabled;
888         OSPE_DEST_PROTOCOL protocol;
889         char dest[OSP_NORSTR_SIZE];
890         int error;
891
892         if ((error = OSPPTransactionIsDestOSPEnabled(results->outhandle, &enabled)) != OSPC_ERR_NO_ERROR) {
893                 ast_debug(1, "OSP: Unable to get destination OSP version, error '%d'\n", error);
894                 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
895                 return -1;
896         }
897
898         if (enabled == OSPC_DOSP_FALSE) {
899                 results->token[0] = '\0';
900         } else {
901                 ast_base64encode(results->token, (const unsigned char*)token, tokenlen, sizeof(results->token) - 1);
902         }
903
904         if ((error = OSPPTransactionGetDestNetworkId(results->outhandle, results->networkid)) != OSPC_ERR_NO_ERROR) {
905                 ast_debug(1, "OSP: Unable to get destination network ID, error '%d'\n", error);
906                 results->networkid[0] = '\0';
907         }
908
909         if ((error = OSPPTransactionGetNumberPortability(results->outhandle, results->nprn, results->npcic, &results->npdi)) != OSPC_ERR_NO_ERROR) {
910                 ast_debug(1, "OSP: Unable to get number portability parameters, error '%d'\n", error);
911                 results->nprn[0] = '\0';
912                 results->npcic[0] = '\0';
913                 results->npdi = 0;
914         }
915
916         if ((error = OSPPTransactionGetDestProtocol(results->outhandle, &protocol)) != OSPC_ERR_NO_ERROR) {
917                 ast_debug(1, "OSP: Unable to get destination protocol, error '%d'\n", error);
918                 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
919                 results->token[0] = '\0';
920                 results->networkid[0] = '\0';
921                 results->nprn[0] = '\0';
922                 results->npcic[0] = '\0';
923                 results->npdi = 0;
924                 return -1;
925         }
926
927         res = 1;
928         osp_convert_outin(destination, dest, sizeof(dest));
929         switch(protocol) {
930         case OSPC_DPROT_SIP:
931                 ast_debug(1, "OSP: protocol SIP\n");
932                 ast_copy_string(results->tech, OSP_TECH_SIP, sizeof(results->tech));
933                 ast_copy_string(results->dest, dest, sizeof(results->dest));
934                 ast_copy_string(results->calling, calling, sizeof(results->calling));
935                 ast_copy_string(results->called, called, sizeof(results->called));
936                 break;
937         case OSPC_DPROT_Q931:
938                 ast_debug(1, "OSP: protocol Q.931\n");
939                 ast_copy_string(results->tech, OSP_TECH_H323, sizeof(results->tech));
940                 ast_copy_string(results->dest, dest, sizeof(results->dest));
941                 ast_copy_string(results->calling, calling, sizeof(results->calling));
942                 ast_copy_string(results->called, called, sizeof(results->called));
943                 break;
944         case OSPC_DPROT_IAX:
945                 ast_debug(1, "OSP: protocol IAX\n");
946                 ast_copy_string(results->tech, OSP_TECH_IAX, sizeof(results->tech));
947                 ast_copy_string(results->dest, dest, sizeof(results->dest));
948                 ast_copy_string(results->calling, calling, sizeof(results->calling));
949                 ast_copy_string(results->called, called, sizeof(results->called));
950                 break;
951         case OSPC_DPROT_SKYPE:
952                 ast_debug(1, "OSP: protocol Skype\n");
953                 ast_copy_string(results->tech, OSP_TECH_SKYPE, sizeof(results->tech));
954                 ast_copy_string(results->dest, dest, sizeof(results->dest));
955                 ast_copy_string(results->calling, calling, sizeof(results->calling));
956                 ast_copy_string(results->called, called, sizeof(results->called));
957                 break;
958         case OSPC_DPROT_UNDEFINED:
959         case OSPC_DPROT_UNKNOWN:
960                 ast_debug(1, "OSP: unknown/undefined protocol '%d'\n", protocol);
961                 ast_debug(1, "OSP: use default protocol '%s'\n", provider->defaultprotocol);
962                 ast_copy_string(results->tech, provider->defaultprotocol, sizeof(results->tech));
963                 ast_copy_string(results->dest, dest, sizeof(results->dest));
964                 ast_copy_string(results->calling, calling, sizeof(results->calling));
965                 ast_copy_string(results->called, called, sizeof(results->called));
966                 break;
967         case OSPC_DPROT_LRQ:
968         case OSPC_DPROT_T37:
969         case OSPC_DPROT_T38:
970         case OSPC_DPROT_SMPP:
971         case OSPC_DPROT_XMPP:
972         default:
973                 ast_log(LOG_WARNING, "OSP: unsupported protocol '%d'\n", protocol);
974                 *reason = OSPC_FAIL_PROTOCOL_ERROR;
975                 results->token[0] = '\0';
976                 results->networkid[0] = '\0';
977                 results->nprn[0] = '\0';
978                 results->npcic[0] = '\0';
979                 results->npdi = 0;
980                 res = 0;
981                 break;
982         }
983
984         return res;
985 }
986
987 /*!
988  * \brief Convert Asterisk status to TC code
989  * \param cause Asterisk hangup cause
990  * \return OSP TC code
991  */
992 static OSPEFAILREASON asterisk2osp(
993         int cause)
994 {
995         return (OSPEFAILREASON)cause;
996 }
997
998 /*!
999  * \brief OSP Authentication function
1000  * \param provider OSP provider context name
1001  * \param transaction OSP transaction handle, output
1002  * \param source Source of inbound call
1003  * \param calling Calling number
1004  * \param called Called number
1005  * \param token OSP token, may be empty
1006  * \param timelimit Call duration limit, output
1007  * \return 1 Authenricated, 0 Unauthenticated, -1 Error
1008  */
1009 static int osp_auth(
1010         const char* provider,
1011         int* transaction,
1012         const char* source,
1013         const char* calling,
1014         const char* called,
1015         const char* token,
1016         unsigned int* timelimit)
1017 {
1018         int res;
1019         struct osp_provider* p = NULL;
1020         char dest[OSP_NORSTR_SIZE];
1021
1022         *transaction = OSP_INVALID_HANDLE;
1023         *timelimit = OSP_DEF_TIMELIMIT;
1024
1025         if ((res = osp_get_provider(provider, &p)) <= 0) {
1026                 ast_debug(1, "OSP: Unabe to find OSP provider '%s'\n", provider);
1027                 return res;
1028         }
1029
1030         switch (p->authpolicy) {
1031         case OSP_AUTH_NO:
1032                 res = 1;
1033                 break;
1034         case OSP_AUTH_EXCLUSIVE:
1035                 if (ast_strlen_zero(token)) {
1036                         res = 0;
1037                 } else if ((res = osp_create_transaction(provider, transaction, dest, sizeof(dest))) <= 0) {
1038                         ast_debug(1, "OSP: Unable to generate transaction handle\n");
1039                         *transaction = OSP_INVALID_HANDLE;
1040                         res = 0;
1041                 } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
1042                         OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
1043                 }
1044                 break;
1045         case OSP_AUTH_YES:
1046         default:
1047                 if (ast_strlen_zero(token)) {
1048                         res = 1;
1049                 } else if ((res = osp_create_transaction(provider, transaction, dest, sizeof(dest))) <= 0) {
1050                         ast_debug(1, "OSP: Unable to generate transaction handle\n");
1051                         *transaction = OSP_INVALID_HANDLE;
1052                         res = 0;
1053                 } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
1054                         OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
1055                 }
1056                 break;
1057         }
1058
1059         return res;
1060 }
1061
1062 /*!
1063  * \brief Create a UUID
1064  * \param uuid UUID buffer
1065  * \param bufsize UUID buffer size
1066  * \return 1 Created, -1 Error
1067  */
1068 static int osp_create_uuid(
1069         unsigned char* uuid,
1070         unsigned int* bufsize)
1071 {
1072         int i, res;
1073         long int tmp[OSP_UUID_SIZE / sizeof(long int)];
1074
1075         if (*bufsize >= OSP_UUID_SIZE) {
1076                 for (i = 0; i < OSP_UUID_SIZE / sizeof(long int); i++) {
1077                         tmp[i] = ast_random();
1078                 }
1079                 memcpy(uuid, tmp, OSP_UUID_SIZE);
1080                 *bufsize = OSP_UUID_SIZE;
1081                 res = 1;
1082         } else {
1083                 res = -1;
1084         }
1085
1086         return res;
1087 }
1088
1089 /*!
1090  * \brief UUID to string
1091  * \param uuid UUID
1092  * \param buffer String buffer
1093  * \param bufsize String buffer size
1094  * \return 1 Successed, -1 Error
1095  */
1096 static int osp_uuid2str(
1097         unsigned char* uuid,
1098         char* buffer,
1099         unsigned int bufsize)
1100 {
1101         int res;
1102
1103         if (bufsize > OSP_UUIDSTR_SIZE) {
1104                 snprintf(buffer, bufsize, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1105                         uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
1106                         uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
1107                 res = 1;
1108         } else {
1109                 res = -1;
1110         }
1111
1112         return res;
1113 }
1114
1115 /*!
1116  * \brief Create a call ID according to the type
1117  * \param type Call ID type
1118  * \param callid Call ID buffer
1119  * \return 1 Created, 0 Not create, -1 Error
1120  */
1121 static int osp_create_callid(
1122         unsigned int type,
1123         struct osp_callid* callid)
1124 {
1125         int res;
1126
1127         callid->len = sizeof(callid->buf);
1128         switch (type) {
1129         case OSP_CALLID_H323:
1130                 res = osp_create_uuid(callid->buf, &callid->len);
1131                 break;
1132         case OSP_CALLID_SIP:
1133         case OSP_CALLID_IAX:
1134                 res = 0;
1135         default:
1136                 res = -1;
1137                 break;
1138         }
1139
1140         if ((res != 1) && (callid->len != 0)) {
1141                 callid->buf[0] = '\0';
1142                 callid->len = 0;
1143         }
1144
1145         return res;
1146 }
1147
1148 /*!
1149  * \brief OSP Lookup function
1150  * \param provider OSP provider context name
1151  * \param callidtypes Call ID types
1152  * \param srcdev Source device of outbound call
1153  * \param calling Calling number
1154  * \param called Called number
1155  * \param snetid Source network ID
1156  * \param np NP parameters
1157  * \param div SIP Diversion header parameters
1158  * \param cinfo Custom info
1159  * \param results Lookup results
1160  * \return 1 Found , 0 No route, -1 Error
1161  */
1162 static int osp_lookup(
1163         const char* provider,
1164         unsigned int callidtypes,
1165         const char* srcdev,
1166         const char* calling,
1167         const char* called,
1168         const char* snetid,
1169         struct osp_npparam* np,
1170         struct osp_diversion* div,
1171         const char* cinfo[],
1172         struct osp_results* results)
1173 {
1174         int res;
1175         struct osp_provider* p = NULL;
1176         char source[OSP_NORSTR_SIZE];
1177         char callingnum[OSP_NORSTR_SIZE];
1178         char callednum[OSP_NORSTR_SIZE];
1179         char destination[OSP_NORSTR_SIZE];
1180         unsigned int tokenlen;
1181         char token[OSP_TOKSTR_SIZE];
1182         char src[OSP_NORSTR_SIZE];
1183         char dev[OSP_NORSTR_SIZE];
1184         char host[OSP_NORSTR_SIZE];
1185         unsigned int i, type;
1186         struct osp_callid callid;
1187         unsigned int callidnum;
1188         OSPT_CALL_ID* callids[OSP_CALLID_MAXNUM];
1189         unsigned int dummy = 0;
1190         OSPEFAILREASON reason;
1191         int error;
1192
1193         results->outhandle = OSP_INVALID_HANDLE;
1194         results->tech[0] = '\0';
1195         results->dest[0] = '\0';
1196         results->calling[0] = '\0';
1197         results->called[0] = '\0';
1198         results->token[0] = '\0';
1199         results->networkid[0] = '\0';
1200         results->nprn[0] = '\0';
1201         results->npcic[0] = '\0';
1202         results->npdi = 0;
1203         results->numresults = 0;
1204         results->outtimelimit = OSP_DEF_TIMELIMIT;
1205
1206         if ((res = osp_get_provider(provider, &p)) <= 0) {
1207                 ast_debug(1, "OSP: Unabe to find OSP provider '%s'\n", provider);
1208                 return res;
1209         }
1210
1211         if ((res = osp_create_transaction(provider, &results->outhandle, source, sizeof(source))) <= 0) {
1212                 ast_debug(1, "OSP: Unable to generate transaction handle\n");
1213                 results->outhandle = OSP_INVALID_HANDLE;
1214                 if (results->inhandle != OSP_INVALID_HANDLE) {
1215                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1216                 }
1217                 return -1;
1218         }
1219
1220         if (!ast_strlen_zero(snetid)) {
1221                 OSPPTransactionSetNetworkIds(results->outhandle, snetid, "");
1222         }
1223
1224         OSPPTransactionSetNumberPortability(results->outhandle, np->rn, np->cic, np->npdi);
1225
1226         osp_convert_inout(div->host, host, sizeof(host));
1227         OSPPTransactionSetDiversion(results->outhandle, div->user, host);
1228
1229         if (cinfo != NULL) {
1230                 for (i = 0; i < OSP_MAX_CUSTOMINFO; i++) {
1231                         if (!ast_strlen_zero(cinfo[i])) {
1232                                 OSPPTransactionSetCustomInfo(results->outhandle, i, cinfo[i]);
1233                         }
1234                 }
1235         }
1236
1237         callidnum = 0;
1238         callids[0] = NULL;
1239         for (i = 0; i < OSP_CALLID_MAXNUM; i++) {
1240                 type = 1 << i;
1241                 if (callidtypes & type) {
1242                         error = osp_create_callid(type, &callid);
1243                         if (error == 1) {
1244                                 callids[callidnum] = OSPPCallIdNew(callid.len, callid.buf);
1245                                 callidnum++;
1246                         }
1247                 }
1248         }
1249
1250         osp_convert_inout(source, src, sizeof(src));
1251         osp_convert_inout(srcdev, dev, sizeof(dev));
1252         results->numresults = OSP_DEF_DESTINATIONS;
1253         error = OSPPTransactionRequestAuthorisation(
1254                 results->outhandle,
1255                 src,
1256                 dev,
1257                 calling ? calling : "",
1258                 OSPC_NFORMAT_E164,
1259                 called,
1260                 OSPC_NFORMAT_E164,
1261                 NULL,
1262                 callidnum,
1263                 callids,
1264                 NULL,
1265                 &results->numresults,
1266                 &dummy,
1267                 NULL);
1268
1269         for (i = 0; i < callidnum; i++) {
1270                 OSPPCallIdDelete(&callids[i]);
1271         }
1272
1273         if (error != OSPC_ERR_NO_ERROR) {
1274                 ast_debug(1, "OSP: Unable to request authorization, error '%d'\n", error);
1275                 results->numresults = 0;
1276                 if (results->inhandle != OSP_INVALID_HANDLE) {
1277                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1278                 }
1279                 return -1;
1280         }
1281
1282         if (!results->numresults) {
1283                 ast_debug(1, "OSP: No more destination\n");
1284                 if (results->inhandle != OSP_INVALID_HANDLE) {
1285                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1286                 }
1287                 return 0;
1288         }
1289
1290         results->outcallid.len = sizeof(results->outcallid.buf);
1291         tokenlen = sizeof(token);
1292         error = OSPPTransactionGetFirstDestination(
1293                 results->outhandle,
1294                 0,
1295                 NULL,
1296                 NULL,
1297                 &results->outtimelimit,
1298                 &results->outcallid.len,
1299                 results->outcallid.buf,
1300                 sizeof(callednum),
1301                 callednum,
1302                 sizeof(callingnum),
1303                 callingnum,
1304                 sizeof(destination),
1305                 destination,
1306                 0,
1307                 NULL,
1308                 &tokenlen,
1309                 token);
1310         if (error != OSPC_ERR_NO_ERROR) {
1311                 ast_debug(1, "OSP: Unable to get first route, error '%d'\n", error);
1312                 results->numresults = 0;
1313                 results->outtimelimit = OSP_DEF_TIMELIMIT;
1314                 if (results->inhandle != OSP_INVALID_HANDLE) {
1315                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1316                 }
1317                 return -1;
1318         }
1319
1320         results->numresults--;
1321         results->outtimelimit = osp_choose_timelimit(results->intimelimit, results->outtimelimit);
1322         ast_debug(1, "OSP: outtimelimit '%d'\n", results->outtimelimit);
1323         ast_debug(1, "OSP: calling '%s'\n", callingnum);
1324         ast_debug(1, "OSP: called '%s'\n", callednum);
1325         ast_debug(1, "OSP: destination '%s'\n", destination);
1326         ast_debug(1, "OSP: token size '%d'\n", tokenlen);
1327
1328         if ((res = osp_check_destination(p, callingnum, callednum, destination, tokenlen, token, &reason, results)) > 0) {
1329                 return 1;
1330         }
1331
1332         if (!results->numresults) {
1333                 ast_debug(1, "OSP: No more destination\n");
1334                 results->outtimelimit = OSP_DEF_TIMELIMIT;
1335                 OSPPTransactionRecordFailure(results->outhandle, reason);
1336                 if (results->inhandle != OSP_INVALID_HANDLE) {
1337                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1338                 }
1339                 return 0;
1340         }
1341
1342         while(results->numresults) {
1343                 results->outcallid.len = sizeof(results->outcallid.buf);
1344                 tokenlen = sizeof(token);
1345                 error = OSPPTransactionGetNextDestination(
1346                         results->outhandle,
1347                         reason,
1348                         0,
1349                         NULL,
1350                         NULL,
1351                         &results->outtimelimit,
1352                         &results->outcallid.len,
1353                         results->outcallid.buf,
1354                         sizeof(callednum),
1355                         callednum,
1356                         sizeof(callingnum),
1357                         callingnum,
1358                         sizeof(destination),
1359                         destination,
1360                         0,
1361                         NULL,
1362                         &tokenlen,
1363                         token);
1364                 if (error == OSPC_ERR_NO_ERROR) {
1365                         results->numresults--;
1366                         results->outtimelimit = osp_choose_timelimit(results->intimelimit, results->outtimelimit);
1367                         ast_debug(1, "OSP: outtimelimit '%d'\n", results->outtimelimit);
1368                         ast_debug(1, "OSP: calling '%s'\n", callingnum);
1369                         ast_debug(1, "OSP: called '%s'\n", callednum);
1370                         ast_debug(1, "OSP: destination '%s'\n", destination);
1371                         ast_debug(1, "OSP: token size '%d'\n", tokenlen);
1372
1373                         if ((res = osp_check_destination(p, callingnum, callednum, destination, tokenlen, token, &reason, results)) > 0) {
1374                                 break;
1375                         } else if (!results->numresults) {
1376                                 ast_debug(1, "OSP: No more destination\n");
1377                                 OSPPTransactionRecordFailure(results->outhandle, reason);
1378                                 if (results->inhandle != OSP_INVALID_HANDLE) {
1379                                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1380                                 }
1381                                 res = 0;
1382                                 break;
1383                         }
1384                 } else {
1385                         ast_debug(1, "OSP: Unable to get route, error '%d'\n", error);
1386                         results->numresults = 0;
1387                         results->outtimelimit = OSP_DEF_TIMELIMIT;
1388                         if (results->inhandle != OSP_INVALID_HANDLE) {
1389                                 OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1390                         }
1391                         res = -1;
1392                         break;
1393                 }
1394         }
1395         return res;
1396 }
1397
1398 /*!
1399  * \brief OSP Lookup Next function
1400  * \param provider OSP provider name
1401  * \param cause Asterisk hangup cuase
1402  * \param results Lookup results, in/output
1403  * \return 1 Found , 0 No route, -1 Error
1404  */
1405 static int osp_next(
1406         const char* provider,
1407         int cause,
1408         struct osp_results* results)
1409 {
1410         int res;
1411         struct osp_provider* p = NULL;
1412         char callingnum[OSP_NORSTR_SIZE];
1413         char callednum[OSP_NORSTR_SIZE];
1414         char destination[OSP_NORSTR_SIZE];
1415         unsigned int tokenlen;
1416         char token[OSP_TOKSTR_SIZE];
1417         OSPEFAILREASON reason;
1418         int error;
1419
1420         results->tech[0] = '\0';
1421         results->dest[0] = '\0';
1422         results->calling[0] = '\0';
1423         results->called[0] = '\0';
1424         results->token[0] = '\0';
1425         results->networkid[0] = '\0';
1426         results->nprn[0] = '\0';
1427         results->npcic[0] = '\0';
1428         results->npdi = 0;
1429         results->outtimelimit = OSP_DEF_TIMELIMIT;
1430
1431         if ((res = osp_get_provider(provider, &p)) <= 0) {
1432                 ast_debug(1, "OSP: Unabe to find OSP provider '%s'\n", provider);
1433                 return res;
1434         }
1435
1436         if (results->outhandle == OSP_INVALID_HANDLE) {
1437                 ast_debug(1, "OSP: Transaction handle undefined\n");
1438                 results->numresults = 0;
1439                 if (results->inhandle != OSP_INVALID_HANDLE) {
1440                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1441                 }
1442                 return -1;
1443         }
1444
1445         reason = asterisk2osp(cause);
1446
1447         if (!results->numresults) {
1448                 ast_debug(1, "OSP: No more destination\n");
1449                 OSPPTransactionRecordFailure(results->outhandle, reason);
1450                 if (results->inhandle != OSP_INVALID_HANDLE) {
1451                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1452                 }
1453                 return 0;
1454         }
1455
1456         while(results->numresults) {
1457                 results->outcallid.len = sizeof(results->outcallid.buf);
1458                 tokenlen = sizeof(token);
1459                 error = OSPPTransactionGetNextDestination(
1460                         results->outhandle,
1461                         reason,
1462                         0,
1463                         NULL,
1464                         NULL,
1465                         &results->outtimelimit,
1466                         &results->outcallid.len,
1467                         results->outcallid.buf,
1468                         sizeof(callednum),
1469                         callednum,
1470                         sizeof(callingnum),
1471                         callingnum,
1472                         sizeof(destination),
1473                         destination,
1474                         0,
1475                         NULL,
1476                         &tokenlen,
1477                         token);
1478                 if (error == OSPC_ERR_NO_ERROR) {
1479                         results->numresults--;
1480                         results->outtimelimit = osp_choose_timelimit(results->intimelimit, results->outtimelimit);
1481                         ast_debug(1, "OSP: outtimelimit '%d'\n", results->outtimelimit);
1482                         ast_debug(1, "OSP: calling '%s'\n", callingnum);
1483                         ast_debug(1, "OSP: called '%s'\n", callednum);
1484                         ast_debug(1, "OSP: destination '%s'\n", destination);
1485                         ast_debug(1, "OSP: token size '%d'\n", tokenlen);
1486
1487                         if ((res = osp_check_destination(p, callingnum, callednum, destination, tokenlen, token, &reason, results)) > 0) {
1488                                 res = 1;
1489                                 break;
1490                         } else if (!results->numresults) {
1491                                 ast_debug(1, "OSP: No more destination\n");
1492                                 OSPPTransactionRecordFailure(results->outhandle, reason);
1493                                 if (results->inhandle != OSP_INVALID_HANDLE) {
1494                                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1495                                 }
1496                                 res = 0;
1497                                 break;
1498                         }
1499                 } else {
1500                         ast_debug(1, "OSP: Unable to get route, error '%d'\n", error);
1501                         results->token[0] = '\0';
1502                         results->numresults = 0;
1503                         results->outtimelimit = OSP_DEF_TIMELIMIT;
1504                         if (results->inhandle != OSP_INVALID_HANDLE) {
1505                                 OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1506                         }
1507                         res = -1;
1508                         break;
1509                 }
1510         }
1511
1512         return res;
1513 }
1514
1515 /*!
1516  * \brief Get integer from variable string
1517  * \param vstr Variable string
1518  * \return -1 Error
1519  */
1520 static int osp_get_varint(
1521         const char* vstr)
1522 {
1523         char* tmp;
1524         int value = -1;
1525
1526         if (!ast_strlen_zero(vstr)) {
1527                 if ((tmp = strchr(vstr, '=')) != NULL) {
1528                         tmp++;
1529                         if (sscanf(tmp, "%30d", &value) != 1) {
1530                                 value = -1;
1531                         }
1532                 }
1533         }
1534
1535         return value;
1536 }
1537
1538 /*!
1539  * \brief Get float from variable string
1540  * \param vstr Variable string
1541  * \return -1 Error
1542  */
1543 static float osp_get_varfloat(
1544         const char* vstr)
1545 {
1546         char* tmp;
1547         float value = -1;
1548
1549         if (!ast_strlen_zero(vstr)) {
1550                 if ((tmp = strchr(vstr, '=')) != NULL) {
1551                         tmp++;
1552                         if (sscanf(tmp, "%30f", &value) != 1) {
1553                                 value = -1;
1554                         }
1555                 }
1556         }
1557
1558         return value;
1559 }
1560
1561 /*!
1562  * \brief Report QoS
1563  * \param handle OSP in/outbound transaction handle
1564  * \param leg Inbound/outbound
1565  * \param qos QoS string
1566  * \return 1 Success, 0 Failed, -1 Error
1567  */
1568 static int osp_report_qos(
1569         int handle,
1570         enum osp_callleg leg,
1571         const char* qos)
1572 {
1573         int res = 0;
1574         enum osp_direction dir;
1575         char buffer[OSP_NORSTR_SIZE];
1576         char* tmp;
1577         char* item;
1578         int totalpackets[OSP_DIR_NUMBER];
1579         struct osp_metrics lost[OSP_DIR_NUMBER];
1580         struct osp_metrics jitter[OSP_DIR_NUMBER];
1581         struct osp_metrics rtt;
1582         int value;
1583
1584         if (!ast_strlen_zero(qos)) {
1585                 for (dir = OSP_DIR_RX; dir < OSP_DIR_NUMBER; dir++) {
1586                         totalpackets[dir] = -1;
1587                 }
1588
1589                 for (dir = OSP_DIR_RX; dir < OSP_DIR_NUMBER; dir++) {
1590                         lost[dir].value = -1;
1591                         lost[dir].min = -1;
1592                         lost[dir].max = -1;
1593                         lost[dir].avg = -1;
1594                         lost[dir].sdev = -1;
1595                 }
1596
1597                 for (dir = OSP_DIR_RX; dir < OSP_DIR_NUMBER; dir++) {
1598                         jitter[dir].value = -1;
1599                         jitter[dir].min = -1;
1600                         jitter[dir].max = -1;
1601                         jitter[dir].avg = -1;
1602                         jitter[dir].sdev = -1;
1603                 }
1604
1605                 rtt.value = -1;
1606                 rtt.min = -1;
1607                 rtt.max = -1;
1608                 rtt.avg = -1;
1609                 rtt.sdev = -1;
1610
1611                 ast_copy_string(buffer, qos, sizeof(buffer));
1612                 for (item = strtok_r(buffer, ";", &tmp); item; item = strtok_r(NULL, ";", &tmp)) {
1613                         if (!strncasecmp(item, "rxcount", strlen("rxcount"))) {
1614                                 totalpackets[OSP_DIR_RX] = osp_get_varint(item);
1615                         } else if (!strncasecmp(item, "txcount", strlen("txcount"))) {
1616                                 totalpackets[OSP_DIR_TX] = osp_get_varint(item);
1617                         } else if (!strncasecmp(item, "lp", strlen("lp"))) {
1618                                 lost[OSP_DIR_RX].value = osp_get_varint(item);
1619                         } else if (!strncasecmp(item, "minrxlost", strlen("minrxlost"))) {
1620                                 lost[OSP_DIR_RX].min = osp_get_varfloat(item);
1621                         } else if (!strncasecmp(item, "maxrxlost", strlen("maxrxlost"))) {
1622                                 lost[OSP_DIR_RX].max = osp_get_varfloat(item);
1623                         } else if (!strncasecmp(item, "avgrxlost", strlen("avgrxlost"))) {
1624                                 lost[OSP_DIR_RX].avg = osp_get_varfloat(item);
1625                         } else if (!strncasecmp(item, "stdevrxlost", strlen("stdevrxlost"))) {
1626                                 lost[OSP_DIR_RX].sdev = osp_get_varfloat(item);
1627                         } else if (!strncasecmp(item, "rlp", strlen("rlp"))) {
1628                                 lost[OSP_DIR_TX].value = osp_get_varint(item);
1629                         } else if (!strncasecmp(item, "reported_minlost", strlen("reported_minlost"))) {
1630                                 lost[OSP_DIR_TX].min = osp_get_varfloat(item);
1631                         } else if (!strncasecmp(item, "reported_maxlost", strlen("reported_maxlost"))) {
1632                                 lost[OSP_DIR_TX].max = osp_get_varfloat(item);
1633                         } else if (!strncasecmp(item, "reported_avglost", strlen("reported_avglost"))) {
1634                                 lost[OSP_DIR_TX].avg = osp_get_varfloat(item);
1635                         } else if (!strncasecmp(item, "reported_stdevlost", strlen("reported_stdevlost"))) {
1636                                 lost[OSP_DIR_TX].sdev = osp_get_varfloat(item);
1637                         } else if (!strncasecmp(item, "rxjitter", strlen("rxjitter"))) {
1638                                 jitter[OSP_DIR_RX].value = osp_get_varint(item);
1639                         } else if (!strncasecmp(item, "minrxjitter", strlen("minrxjitter"))) {
1640                                 jitter[OSP_DIR_RX].min = osp_get_varfloat(item);
1641                         } else if (!strncasecmp(item, "maxrxjitter", strlen("maxrxjitter"))) {
1642                                 jitter[OSP_DIR_RX].max = osp_get_varfloat(item);
1643                         } else if (!strncasecmp(item, "avgrxjitter", strlen("avgjitter"))) {
1644                                 jitter[OSP_DIR_RX].avg = osp_get_varfloat(item);
1645                         } else if (!strncasecmp(item, "stdevrxjitter", strlen("stdevjitter"))) {
1646                                 jitter[OSP_DIR_RX].sdev = osp_get_varfloat(item);
1647                         } else if (!strncasecmp(item, "txjitter", strlen("txjitter"))) {
1648                                 jitter[OSP_DIR_TX].value = osp_get_varint(item);
1649                         } else if (!strncasecmp(item, "reported_minjitter", strlen("reported_minjitter"))) {
1650                                 jitter[OSP_DIR_TX].min = osp_get_varfloat(item);
1651                         } else if (!strncasecmp(item, "reported_maxjitter", strlen("reported_maxjitter"))) {
1652                                 jitter[OSP_DIR_TX].max = osp_get_varfloat(item);
1653                         } else if (!strncasecmp(item, "reported_avgjitter", strlen("reported_avgjitter"))) {
1654                                 jitter[OSP_DIR_TX].avg = osp_get_varfloat(item);
1655                         } else if (!strncasecmp(item, "reported_stdevjitter", strlen("reported_stdevjitter"))) {
1656                                 jitter[OSP_DIR_TX].sdev = osp_get_varfloat(item);
1657                         } else if (!strncasecmp(item, "rtt", strlen("rtt"))) {
1658                                 rtt.value = osp_get_varint(item);
1659                         } else if (!strncasecmp(item, "minrtt", strlen("minrtt"))) {
1660                                 rtt.min = osp_get_varfloat(item);
1661                         } else if (!strncasecmp(item, "maxrtt", strlen("maxrtt"))) {
1662                                 rtt.max = osp_get_varfloat(item);
1663                         } else if (!strncasecmp(item, "avgrtt", strlen("avgrtt"))) {
1664                                 rtt.avg = osp_get_varfloat(item);
1665                         } else if (!strncasecmp(item, "stdevrtt", strlen("stdevrtt"))) {
1666                                 rtt.sdev = osp_get_varfloat(item);
1667                         }
1668                 }
1669
1670                 ast_debug(1, "OSP: call leg '%d'\n", leg);
1671                 ast_debug(1, "OSP: rxcount '%d'\n", totalpackets[OSP_DIR_RX]);
1672                 ast_debug(1, "OSP: txcount '%d'\n", totalpackets[OSP_DIR_TX]);
1673                 ast_debug(1, "OSP: lp '%d'\n",lost[OSP_DIR_RX].value);
1674                 ast_debug(1, "OSP: minrxlost '%f'\n", lost[OSP_DIR_RX].min);
1675                 ast_debug(1, "OSP: maxrxlost '%f'\n", lost[OSP_DIR_RX].max);
1676                 ast_debug(1, "OSP: avgrxlost '%f'\n", lost[OSP_DIR_RX].avg);
1677                 ast_debug(1, "OSP: stdevrxlost '%f'\n", lost[OSP_DIR_RX].sdev);
1678                 ast_debug(1, "OSP: rlp '%d'\n", lost[OSP_DIR_TX].value);
1679                 ast_debug(1, "OSP: reported_minlost '%f'\n", lost[OSP_DIR_TX].min);
1680                 ast_debug(1, "OSP: reported_maxlost '%f'\n", lost[OSP_DIR_TX].max);
1681                 ast_debug(1, "OSP: reported_avglost '%f'\n", lost[OSP_DIR_TX].avg);
1682                 ast_debug(1, "OSP: reported_stdevlost '%f'\n", lost[OSP_DIR_TX].sdev);
1683                 ast_debug(1, "OSP: rxjitter '%d'\n", jitter[OSP_DIR_RX].value);
1684                 ast_debug(1, "OSP: minrxjitter '%f'\n", jitter[OSP_DIR_RX].min);
1685                 ast_debug(1, "OSP: maxrxjitter '%f'\n", jitter[OSP_DIR_RX].max);
1686                 ast_debug(1, "OSP: avgrxjitter '%f'\n", jitter[OSP_DIR_RX].avg);
1687                 ast_debug(1, "OSP: stdevrxjitter '%f'\n", jitter[OSP_DIR_RX].sdev);
1688                 ast_debug(1, "OSP: txjitter '%d'\n", jitter[OSP_DIR_TX].value);
1689                 ast_debug(1, "OSP: reported_minjitter '%f'\n", jitter[OSP_DIR_TX].min);
1690                 ast_debug(1, "OSP: reported_maxjitter '%f'\n", jitter[OSP_DIR_TX].max);
1691                 ast_debug(1, "OSP: reported_avgjitter '%f'\n", jitter[OSP_DIR_TX].avg);
1692                 ast_debug(1, "OSP: reported_stdevjitter '%f'\n", jitter[OSP_DIR_TX].sdev);
1693                 ast_debug(1, "OSP: rtt '%d'\n", rtt.value);
1694                 ast_debug(1, "OSP: minrtt '%f'\n", rtt.min);
1695                 ast_debug(1, "OSP: maxrtt '%f'\n", rtt.max);
1696                 ast_debug(1, "OSP: avgrtt '%f'\n", rtt.avg);
1697                 ast_debug(1, "OSP: stdevrtt '%f'\n", rtt.sdev);
1698
1699                 if (leg == OSP_CALL_INBOUND) {
1700                         OSPPTransactionSetPackets(handle, OSPC_SMETRIC_RTP, OSPC_SFLOW_DOWNSTREAM, totalpackets[OSP_DIR_RX]);
1701                         OSPPTransactionSetPackets(handle, OSPC_SMETRIC_RTCP, OSPC_SFLOW_UPSTREAM, totalpackets[OSP_DIR_TX]);
1702                         if (lost[OSP_DIR_RX].value >= 0) {
1703                                 value = lost[OSP_DIR_RX].value;
1704                         } else {
1705                                 value = (int)lost[OSP_DIR_RX].avg;
1706                         }
1707                         OSPPTransactionSetLost(handle, OSPC_SMETRIC_RTP, OSPC_SFLOW_DOWNSTREAM, value, -1);
1708                         if (lost[OSP_DIR_TX].value >= 0) {
1709                                 value = lost[OSP_DIR_TX].value;
1710                         } else {
1711                                 value = (int)lost[OSP_DIR_TX].avg;
1712                         }
1713                         OSPPTransactionSetLost(handle, OSPC_SMETRIC_RTCP, OSPC_SFLOW_UPSTREAM, value, -1);
1714                         if (jitter[OSP_DIR_RX].value >= 0) {
1715                                 value = jitter[OSP_DIR_RX].value;
1716                         } else {
1717                                 value = (int)jitter[OSP_DIR_RX].avg;
1718                         }
1719                         OSPPTransactionSetJitter(handle, OSPC_SMETRIC_RTP, OSPC_SFLOW_DOWNSTREAM,
1720                                 -1, (int)jitter[OSP_DIR_RX].min, (int)jitter[OSP_DIR_RX].max, value, jitter[OSP_DIR_RX].sdev);
1721                         if (jitter[OSP_DIR_TX].value >= 0) {
1722                                 value = jitter[OSP_DIR_TX].value;
1723                         } else {
1724                                 value = (int)jitter[OSP_DIR_TX].avg;
1725                         }
1726                         OSPPTransactionSetJitter(handle, OSPC_SMETRIC_RTCP, OSPC_SFLOW_UPSTREAM,
1727                                 -1, (int)jitter[OSP_DIR_TX].min, (int)jitter[OSP_DIR_TX].max, value, jitter[OSP_DIR_TX].sdev);
1728                 } else {
1729                         OSPPTransactionSetPackets(handle, OSPC_SMETRIC_RTP, OSPC_SFLOW_UPSTREAM, totalpackets[OSP_DIR_RX]);
1730                         OSPPTransactionSetPackets(handle, OSPC_SMETRIC_RTCP, OSPC_SFLOW_DOWNSTREAM, totalpackets[OSP_DIR_TX]);
1731                         OSPPTransactionSetLost(handle, OSPC_SMETRIC_RTP, OSPC_SFLOW_UPSTREAM, lost[OSP_DIR_RX].value, -1);
1732                         OSPPTransactionSetLost(handle, OSPC_SMETRIC_RTCP, OSPC_SFLOW_DOWNSTREAM, lost[OSP_DIR_TX].value, -1);
1733                         if (jitter[OSP_DIR_RX].value >= 0) {
1734                                 value = jitter[OSP_DIR_RX].value;
1735                         } else {
1736                                 value = (int)jitter[OSP_DIR_RX].avg;
1737                         }
1738                         OSPPTransactionSetJitter(handle, OSPC_SMETRIC_RTP, OSPC_SFLOW_UPSTREAM,
1739                                 -1, (int)jitter[OSP_DIR_RX].min, (int)jitter[OSP_DIR_RX].max, value, jitter[OSP_DIR_RX].sdev);
1740                         if (jitter[OSP_DIR_TX].value >= 0) {
1741                                 value = jitter[OSP_DIR_TX].value;
1742                         } else {
1743                                 value = (int)jitter[OSP_DIR_TX].avg;
1744                         }
1745                         OSPPTransactionSetJitter(handle, OSPC_SMETRIC_RTCP, OSPC_SFLOW_DOWNSTREAM,
1746                                 -1, (int)jitter[OSP_DIR_TX].min, (int)jitter[OSP_DIR_TX].max, value, jitter[OSP_DIR_TX].sdev);
1747                 }
1748                 if (rtt.value >= 0) {
1749                         value = rtt.value;
1750                 } else {
1751                         value = (int)rtt.avg;
1752                 }
1753                 OSPPTransactionSetRoundTripDelay(handle, -1, (int)rtt.min, (int)rtt.max, value, rtt.sdev);
1754
1755                 res = 1;
1756         }
1757
1758         return res;
1759 }
1760
1761 /*!
1762  * \brief OSP Finish function
1763  * \param handle OSP in/outbound transaction handle
1764  * \param recorded If failure reason has been recorded
1765  * \param cause Asterisk hangup cause
1766  * \param start Call start time
1767  * \param connect Call connect time
1768  * \param end Call end time
1769  * \param release Who release first, 0 source, 1 destination
1770  * \param inqos Inbound QoS string
1771  * \param outqos Outbound QoS string
1772  * \return 1 Success, 0 Failed, -1 Error
1773  */
1774 static int osp_finish(
1775         int handle,
1776         int recorded,
1777         int cause,
1778         time_t start,
1779         time_t connect,
1780         time_t end,
1781         unsigned int release,
1782         const char* inqos,
1783         const char* outqos)
1784 {
1785         int res;
1786         OSPEFAILREASON reason;
1787         time_t alert = 0;
1788         unsigned isPddInfoPresent = 0;
1789         unsigned pdd = 0;
1790         unsigned int dummy = 0;
1791         int error;
1792
1793         if (handle == OSP_INVALID_HANDLE) {
1794                 return 0;
1795         }
1796
1797         if (!recorded) {
1798                 reason = asterisk2osp(cause);
1799                 OSPPTransactionRecordFailure(handle, reason);
1800         }
1801
1802         osp_report_qos(handle, OSP_CALL_INBOUND, inqos);
1803         osp_report_qos(handle, OSP_CALL_OUTBOUND, outqos);
1804
1805         error = OSPPTransactionReportUsage(
1806                 handle,
1807                 difftime(end, connect),
1808                 start,
1809                 end,
1810                 alert,
1811                 connect,
1812                 isPddInfoPresent,
1813                 pdd,
1814                 release,
1815                 NULL,
1816                 -1,
1817                 -1,
1818                 -1,
1819                 -1,
1820                 &dummy,
1821                 NULL);
1822         if (error == OSPC_ERR_NO_ERROR) {
1823                 ast_debug(1, "OSP: Usage reported\n");
1824                 res = 1;
1825         } else {
1826                 ast_debug(1, "OSP: Unable to report usage, error '%d'\n", error);
1827                 res = -1;
1828         }
1829         OSPPTransactionDelete(handle);
1830
1831         return res;
1832 }
1833
1834 /* OSP Application APIs */
1835
1836 /*!
1837  * \brief OSP Application OSPAuth
1838  * \param chan Channel
1839  * \param data Parameter
1840  * \return 0 Success, -1 Failed
1841  */
1842 static int ospauth_exec(
1843         struct ast_channel *chan,
1844         const char *data)
1845 {
1846         int res;
1847         const char* provider = OSP_DEF_PROVIDER;
1848         struct varshead* headp;
1849         struct ast_var_t* current;
1850         const char* source = "";
1851         const char* token = "";
1852         int handle;
1853         unsigned int timelimit;
1854         char buffer[OSP_INTSTR_SIZE];
1855         const char* status;
1856         char* tmp;
1857
1858         AST_DECLARE_APP_ARGS(args,
1859                 AST_APP_ARG(provider);
1860                 AST_APP_ARG(options);
1861         );
1862
1863         if (!(tmp = ast_strdupa(data))) {
1864                 ast_log(LOG_ERROR, "Out of memory\n");
1865                 return -1;
1866         }
1867
1868         AST_STANDARD_APP_ARGS(args, tmp);
1869
1870         if (!ast_strlen_zero(args.provider)) {
1871                 provider = args.provider;
1872         }
1873         ast_debug(1, "OSPAuth: provider '%s'\n", provider);
1874
1875         headp = &chan->varshead;
1876         AST_LIST_TRAVERSE(headp, current, entries) {
1877                 if (!strcasecmp(ast_var_name(current), "OSPINPEERIP")) {
1878                         source = ast_var_value(current);
1879                 } else if (!strcasecmp(ast_var_name(current), "OSPINTOKEN")) {
1880                         token = ast_var_value(current);
1881                 }
1882         }
1883
1884         ast_debug(1, "OSPAuth: source '%s'\n", source);
1885         ast_debug(1, "OSPAuth: token size '%zd'\n", strlen(token));
1886
1887         if ((res = osp_auth(provider, &handle, source, chan->cid.cid_num, chan->exten, token, &timelimit)) > 0) {
1888                 status = AST_OSP_SUCCESS;
1889         } else {
1890                 timelimit = OSP_DEF_TIMELIMIT;
1891                 if (!res) {
1892                         status = AST_OSP_FAILED;
1893                 } else {
1894                         status = AST_OSP_ERROR;
1895                 }
1896         }
1897
1898         snprintf(buffer, sizeof(buffer), "%d", handle);
1899         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
1900         ast_debug(1, "OSPAuth: OSPINHANDLE '%s'\n", buffer);
1901         snprintf(buffer, sizeof(buffer), "%d", timelimit);
1902         pbx_builtin_setvar_helper(chan, "OSPINTIMELIMIT", buffer);
1903         ast_debug(1, "OSPAuth: OSPINTIMELIMIT '%s'\n", buffer);
1904         pbx_builtin_setvar_helper(chan, "OSPAUTHSTATUS", status);
1905         ast_debug(1, "OSPAuth: %s\n", status);
1906
1907         if(res <= 0) {
1908                 res = -1;
1909         } else {
1910                 res = 0;
1911         }
1912
1913         return res;
1914 }
1915
1916 /*!
1917  * \brief OSP Application OSPLookup
1918  * \param chan Channel
1919  * \param data Parameter
1920  * \return 0 Success, -1 Failed
1921  */
1922 static int osplookup_exec(
1923         struct ast_channel* chan,
1924         const char * data)
1925 {
1926         int res, cres;
1927         const char* provider = OSP_DEF_PROVIDER;
1928         unsigned int callidtypes = OSP_CALLID_UNDEFINED;
1929         struct varshead* headp;
1930         struct ast_var_t* current;
1931         const char* srcdev = "";
1932         const char* snetid = "";
1933         struct osp_npparam np;
1934         struct osp_diversion div;
1935         unsigned int i;
1936         const char* cinfo[OSP_MAX_CUSTOMINFO] = { NULL };
1937         char buffer[OSP_TOKSTR_SIZE];
1938         struct osp_results results;
1939         const char* status;
1940         char* tmp;
1941
1942         AST_DECLARE_APP_ARGS(args,
1943                 AST_APP_ARG(exten);
1944                 AST_APP_ARG(provider);
1945                 AST_APP_ARG(options);
1946         );
1947
1948         if (ast_strlen_zero(data)) {
1949                 ast_log(LOG_WARNING, "OSPLookup: Arg required, OSPLookup(exten[|provider[|options]])\n");
1950                 return -1;
1951         }
1952
1953         if (!(tmp = ast_strdupa(data))) {
1954                 ast_log(LOG_ERROR, "Out of memory\n");
1955                 return -1;
1956         }
1957
1958         AST_STANDARD_APP_ARGS(args, tmp);
1959
1960         ast_debug(1, "OSPLookup: exten '%s'\n", args.exten);
1961
1962         if (!ast_strlen_zero(args.provider)) {
1963                 provider = args.provider;
1964         }
1965         ast_debug(1, "OSPlookup: provider '%s'\n", provider);
1966
1967         if (args.options) {
1968                 if (strchr(args.options, 'h')) {
1969                         callidtypes |= OSP_CALLID_H323;
1970                 }
1971                 if (strchr(args.options, 's')) {
1972                         callidtypes |= OSP_CALLID_SIP;
1973                 }
1974                 if (strchr(args.options, 'i')) {
1975                         callidtypes |= OSP_CALLID_IAX;
1976                 }
1977         }
1978         ast_debug(1, "OSPLookup: call id types '%d'\n", callidtypes);
1979
1980         np.rn = "";
1981         np.cic = "";
1982         np.npdi = 0;
1983
1984         div.user = "";
1985         div.host = "";
1986
1987         results.inhandle = OSP_INVALID_HANDLE;
1988         results.intimelimit = OSP_DEF_TIMELIMIT;
1989
1990         headp = &chan->varshead;
1991         AST_LIST_TRAVERSE(headp, current, entries) {
1992                 if (!strcasecmp(ast_var_name(current), "OSPINPEERIP")) {
1993                         srcdev = ast_var_value(current);
1994                 } else if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1995                         if (sscanf(ast_var_value(current), "%30d", &results.inhandle) != 1) {
1996                                 results.inhandle = OSP_INVALID_HANDLE;
1997                         }
1998                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
1999                         if (sscanf(ast_var_value(current), "%30d", &results.intimelimit) != 1) {
2000                                 results.intimelimit = OSP_DEF_TIMELIMIT;
2001                         }
2002                 } else if (!strcasecmp(ast_var_name(current), "OSPINNETWORKID")) {
2003                         snetid = ast_var_value(current);
2004                 } else if (!strcasecmp(ast_var_name(current), "OSPINNPRN")) {
2005                         np.rn = ast_var_value(current);
2006                 } else if (!strcasecmp(ast_var_name(current), "OSPINNPCIC")) {
2007                         np.cic = ast_var_value(current);
2008                 } else if (!strcasecmp(ast_var_name(current), "OSPINNPDI")) {
2009                         if (ast_true(ast_var_value(current))) {
2010                                 np.npdi = 1;
2011                         }
2012                 } else if (!strcasecmp(ast_var_name(current), "OSPINDIVUSER")) {
2013                         div.user = ast_var_value(current);
2014                 } else if (!strcasecmp(ast_var_name(current), "OSPINDIVHOST")) {
2015                         div.host = ast_var_value(current);
2016                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO1")) {
2017                         cinfo[0] = ast_var_value(current);
2018                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO2")) {
2019                         cinfo[1] = ast_var_value(current);
2020                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO3")) {
2021                         cinfo[2] = ast_var_value(current);
2022                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO4")) {
2023                         cinfo[3] = ast_var_value(current);
2024                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO5")) {
2025                         cinfo[4] = ast_var_value(current);
2026                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO6")) {
2027                         cinfo[5] = ast_var_value(current);
2028                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO7")) {
2029                         cinfo[6] = ast_var_value(current);
2030                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO8")) {
2031                         cinfo[7] = ast_var_value(current);
2032                 }
2033         }
2034         ast_debug(1, "OSPLookup: source device '%s'\n", srcdev);
2035         ast_debug(1, "OSPLookup: OSPINHANDLE '%d'\n", results.inhandle);
2036         ast_debug(1, "OSPLookup: OSPINTIMELIMIT '%d'\n", results.intimelimit);
2037         ast_debug(1, "OSPLookup: OSPINNETWORKID '%s'\n", snetid);
2038         ast_debug(1, "OSPLookup: OSPINNPRN '%s'\n", np.rn);
2039         ast_debug(1, "OSPLookup: OSPINNPCIC '%s'\n", np.cic);
2040         ast_debug(1, "OSPLookup: OSPINNPDI '%d'\n", np.npdi);
2041         ast_debug(1, "OSPLookup: OSPINDIVUSER '%s'\n", div.user);
2042         ast_debug(1, "OSPLookup: OSPINDIVHOST'%s'\n", div.host);
2043         for (i = 0; i < OSP_MAX_CUSTOMINFO; i++) {
2044                 if (!ast_strlen_zero(cinfo[i])) {
2045                         ast_debug(1, "OSPLookup: OSPINCUSTOMINFO%d '%s'\n", i, cinfo[i]);
2046                 }
2047         }
2048
2049         if ((cres = ast_autoservice_start(chan)) < 0) {
2050                 return -1;
2051         }
2052
2053         if ((res = osp_lookup(provider, callidtypes, srcdev, chan->cid.cid_num, args.exten, snetid, &np, &div, cinfo, &results)) > 0) {
2054                 status = AST_OSP_SUCCESS;
2055         } else {
2056                 results.tech[0] = '\0';
2057                 results.dest[0] = '\0';
2058                 results.calling[0] = '\0';
2059                 results.called[0] = '\0';
2060                 results.token[0] = '\0';
2061                 results.networkid[0] = '\0';
2062                 results.nprn[0] = '\0';
2063                 results.npcic[0] = '\0';
2064                 results.npdi = 0;
2065                 results.numresults = 0;
2066                 results.outtimelimit = OSP_DEF_TIMELIMIT;
2067                 results.outcallid.buf[0] = '\0';
2068                 results.outcallid.len = 0;
2069                 if (!res) {
2070                         status = AST_OSP_FAILED;
2071                 } else {
2072                         status = AST_OSP_ERROR;
2073                 }
2074         }
2075
2076         snprintf(buffer, sizeof(buffer), "%d", results.outhandle);
2077         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
2078         ast_debug(1, "OSPLookup: OSPOUTHANDLE '%s'\n", buffer);
2079         pbx_builtin_setvar_helper(chan, "OSPOUTTECH", results.tech);
2080         ast_debug(1, "OSPLookup: OSPOUTTECH '%s'\n", results.tech);
2081         pbx_builtin_setvar_helper(chan, "OSPDESTINATION", results.dest);
2082         ast_debug(1, "OSPLookup: OSPDESTINATION '%s'\n", results.dest);
2083         pbx_builtin_setvar_helper(chan, "OSPOUTCALLING", results.calling);
2084         ast_debug(1, "OSPLookup: OSPOUTCALLING '%s'\n", results.calling);
2085         pbx_builtin_setvar_helper(chan, "OSPOUTCALLED", results.called);
2086         ast_debug(1, "OSPLookup: OSPOUTCALLED '%s'\n", results.called);
2087         pbx_builtin_setvar_helper(chan, "OSPOUTNETWORKID", results.networkid);
2088         ast_debug(1, "OSPLookup: OSPOUTNETWORKID '%s'\n", results.networkid);
2089         pbx_builtin_setvar_helper(chan, "OSPOUTNPRN", results.nprn);
2090         ast_debug(1, "OSPLookup: OSPOUTNPRN '%s'\n", results.nprn);
2091         pbx_builtin_setvar_helper(chan, "OSPOUTNPCIC", results.npcic);
2092         ast_debug(1, "OSPLookup: OSPOUTNPCIC '%s'\n", results.npcic);
2093         snprintf(buffer, sizeof(buffer), "%d", results.npdi);
2094         pbx_builtin_setvar_helper(chan, "OSPOUTNPDI", buffer);
2095         ast_debug(1, "OSPLookup: OSPOUTNPDI'%s'\n", buffer);
2096         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", results.token);
2097         ast_debug(1, "OSPLookup: OSPOUTTOKEN size '%zd'\n", strlen(results.token));
2098         snprintf(buffer, sizeof(buffer), "%d", results.numresults);
2099         pbx_builtin_setvar_helper(chan, "OSPDESTREMAILS", buffer);
2100         ast_debug(1, "OSPLookup: OSPDESTREMAILS '%s'\n", buffer);
2101         snprintf(buffer, sizeof(buffer), "%d", results.outtimelimit);
2102         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
2103         ast_debug(1, "OSPLookup: OSPOUTTIMELIMIT '%s'\n", buffer);
2104         snprintf(buffer, sizeof(buffer), "%d", callidtypes);
2105         pbx_builtin_setvar_helper(chan, "OSPOUTCALLIDTYPES", buffer);
2106         ast_debug(1, "OSPLookup: OSPOUTCALLIDTYPES '%s'\n", buffer);
2107         pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", status);
2108         ast_debug(1, "OSPLookup: %s\n", status);
2109
2110         if (!strcasecmp(results.tech, OSP_TECH_SIP)) {
2111                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", results.tech, results.called, results.dest);
2112                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2113                 if (!ast_strlen_zero(results.token)) {
2114                         snprintf(buffer, sizeof(buffer), "%s%s", OSP_SIP_HEADER, results.token);
2115                         pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
2116                         ast_debug(1, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
2117                 }
2118         } else if (!strcasecmp(results.tech, OSP_TECH_H323)) {
2119                 if ((callidtypes & OSP_CALLID_H323) && (results.outcallid.len != 0)) {
2120                         osp_uuid2str(results.outcallid.buf, buffer, sizeof(buffer));
2121                 } else {
2122                         buffer[0] = '\0';
2123                 }
2124                 pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
2125                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", results.tech, results.called, results.dest);
2126                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2127         } else if (!strcasecmp(results.tech, OSP_TECH_IAX)) {
2128                 snprintf(buffer, sizeof(buffer), "%s/%s/%s", results.tech, results.dest, results.called);
2129                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2130         } else if (!strcasecmp(results.tech, OSP_TECH_SKYPE)) {
2131                 snprintf(buffer, sizeof(buffer), "%s/%s", results.tech, results.called);
2132                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2133         }
2134
2135         if ((cres = ast_autoservice_stop(chan)) < 0) {
2136                 return -1;
2137         }
2138
2139         if(res <= 0) {
2140                 res = -1;
2141         } else {
2142                 res = 0;
2143         }
2144
2145         return res;
2146 }
2147
2148 /*!
2149  * \brief OSP Application OSPNext
2150  * \param chan Channel
2151  * \param data Parameter
2152  * \return 0 Success, -1 Failed
2153  */
2154 static int ospnext_exec(
2155         struct ast_channel* chan,
2156         const char * data)
2157 {
2158         int res;
2159         const char* provider = OSP_DEF_PROVIDER;
2160         int cause = 0;
2161         struct varshead* headp;
2162         struct ast_var_t* current;
2163         struct osp_results results;
2164         char buffer[OSP_TOKSTR_SIZE];
2165         unsigned int callidtypes = OSP_CALLID_UNDEFINED;
2166         const char* status;
2167         char* tmp;
2168
2169         AST_DECLARE_APP_ARGS(args,
2170                 AST_APP_ARG(cause);
2171                 AST_APP_ARG(provider);
2172                 AST_APP_ARG(options);
2173         );
2174
2175         if (ast_strlen_zero(data)) {
2176                 ast_log(LOG_WARNING, "OSPNext: Arg required, OSPNext(cause[|provider[|options]])\n");
2177                 return -1;
2178         }
2179
2180         if (!(tmp = ast_strdupa(data))) {
2181                 ast_log(LOG_ERROR, "Out of memory\n");
2182                 return -1;
2183         }
2184
2185         AST_STANDARD_APP_ARGS(args, tmp);
2186
2187         if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%30d", &cause) != 1) {
2188                 cause = 0;
2189         }
2190         ast_debug(1, "OSPNext: cause '%d'\n", cause);
2191
2192         if (!ast_strlen_zero(args.provider)) {
2193                 provider = args.provider;
2194         }
2195         ast_debug(1, "OSPlookup: provider '%s'\n", provider);
2196
2197         results.inhandle = OSP_INVALID_HANDLE;
2198         results.outhandle = OSP_INVALID_HANDLE;
2199         results.intimelimit = OSP_DEF_TIMELIMIT;
2200         results.numresults = 0;
2201
2202         headp = &chan->varshead;
2203         AST_LIST_TRAVERSE(headp, current, entries) {
2204                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
2205                         if (sscanf(ast_var_value(current), "%30d", &results.inhandle) != 1) {
2206                                 results.inhandle = OSP_INVALID_HANDLE;
2207                         }
2208                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
2209                         if (sscanf(ast_var_value(current), "%30d", &results.outhandle) != 1) {
2210                                 results.outhandle = OSP_INVALID_HANDLE;
2211                         }
2212                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
2213                         if (sscanf(ast_var_value(current), "%30d", &results.intimelimit) != 1) {
2214                                 results.intimelimit = OSP_DEF_TIMELIMIT;
2215                         }
2216                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTCALLIDTYPES")) {
2217                         if (sscanf(ast_var_value(current), "%30d", &callidtypes) != 1) {
2218                                 callidtypes = OSP_CALLID_UNDEFINED;
2219                         }
2220                 } else if (!strcasecmp(ast_var_name(current), "OSPDESTREMAILS")) {
2221                         if (sscanf(ast_var_value(current), "%30d", &results.numresults) != 1) {
2222                                 results.numresults = 0;
2223                         }
2224                 }
2225         }
2226         ast_debug(1, "OSPNext: OSPINHANDLE '%d'\n", results.inhandle);
2227         ast_debug(1, "OSPNext: OSPOUTHANDLE '%d'\n", results.outhandle);
2228         ast_debug(1, "OSPNext: OSPINTIMELIMIT '%d'\n", results.intimelimit);
2229         ast_debug(1, "OSPNext: OSPOUTCALLIDTYPES '%d'\n", callidtypes);
2230         ast_debug(1, "OSPNext: OSPDESTREMAILS '%d'\n", results.numresults);
2231
2232         if ((res = osp_next(provider, cause, &results)) > 0) {
2233                 status = AST_OSP_SUCCESS;
2234         } else {
2235                 results.tech[0] = '\0';
2236                 results.dest[0] = '\0';
2237                 results.calling[0] = '\0';
2238                 results.called[0] = '\0';
2239                 results.token[0] = '\0';
2240                 results.networkid[0] = '\0';
2241                 results.nprn[0] = '\0';
2242                 results.npcic[0] = '\0';
2243                 results.npdi = 0;
2244                 results.numresults = 0;
2245                 results.outtimelimit = OSP_DEF_TIMELIMIT;
2246                 results.outcallid.buf[0] = '\0';
2247                 results.outcallid.len = 0;
2248                 if (!res) {
2249                         status = AST_OSP_FAILED;
2250                 } else {
2251                         status = AST_OSP_ERROR;
2252                 }
2253         }
2254
2255         pbx_builtin_setvar_helper(chan, "OSPOUTTECH", results.tech);
2256         ast_debug(1, "OSPNext: OSPOUTTECH '%s'\n", results.tech);
2257         pbx_builtin_setvar_helper(chan, "OSPDESTINATION", results.dest);
2258         ast_debug(1, "OSPNext: OSPDESTINATION '%s'\n", results.dest);
2259         pbx_builtin_setvar_helper(chan, "OSPOUTCALLING", results.calling);
2260         ast_debug(1, "OSPNext: OSPOUTCALLING '%s'\n", results.calling);
2261         pbx_builtin_setvar_helper(chan, "OSPOUTCALLED", results.called);
2262         ast_debug(1, "OSPNext: OSPOUTCALLED'%s'\n", results.called);
2263         pbx_builtin_setvar_helper(chan, "OSPOUTNETWORKID", results.networkid);
2264         ast_debug(1, "OSPLookup: OSPOUTNETWORKID '%s'\n", results.networkid);
2265         pbx_builtin_setvar_helper(chan, "OSPOUTNPRN", results.nprn);
2266         ast_debug(1, "OSPLookup: OSPOUTNPRN '%s'\n", results.nprn);
2267         pbx_builtin_setvar_helper(chan, "OSPOUTNPCIC", results.npcic);
2268         ast_debug(1, "OSPLookup: OSPOUTNPCIC '%s'\n", results.npcic);
2269         snprintf(buffer, sizeof(buffer), "%d", results.npdi);
2270         pbx_builtin_setvar_helper(chan, "OSPOUTNPDI", buffer);
2271         ast_debug(1, "OSPLookup: OSPOUTNPDI'%s'\n", buffer);
2272         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", results.token);
2273         ast_debug(1, "OSPNext: OSPOUTTOKEN size '%zd'\n", strlen(results.token));
2274         snprintf(buffer, sizeof(buffer), "%d", results.numresults);
2275         pbx_builtin_setvar_helper(chan, "OSPDESTREMAILS", buffer);
2276         ast_debug(1, "OSPNext: OSPDESTREMAILS '%s'\n", buffer);
2277         snprintf(buffer, sizeof(buffer), "%d", results.outtimelimit);
2278         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
2279         ast_debug(1, "OSPNext: OSPOUTTIMELIMIT '%s'\n", buffer);
2280         pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", status);
2281         ast_debug(1, "OSPNext: %s\n", status);
2282
2283         if (!strcasecmp(results.tech, OSP_TECH_SIP)) {
2284                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", results.tech, results.called, results.dest);
2285                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2286                 if (!ast_strlen_zero(results.token)) {
2287                         snprintf(buffer, sizeof(buffer), "%s%s", OSP_SIP_HEADER, results.token);
2288                         pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
2289                         ast_debug(1, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
2290                 }
2291         } else if (!strcasecmp(results.tech, OSP_TECH_H323)) {
2292                 if ((callidtypes & OSP_CALLID_H323) && (results.outcallid.len != 0)) {
2293                         osp_uuid2str(results.outcallid.buf, buffer, sizeof(buffer));
2294                 } else {
2295                         buffer[0] = '\0';
2296                 }
2297                 pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
2298                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", results.tech, results.called, results.dest);
2299                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2300         } else if (!strcasecmp(results.tech, OSP_TECH_IAX)) {
2301                 snprintf(buffer, sizeof(buffer), "%s/%s/%s", results.tech, results.dest, results.called);
2302                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2303         } else if (!strcasecmp(results.tech, OSP_TECH_SKYPE)) {
2304                 snprintf(buffer, sizeof(buffer), "%s/%s", results.tech, results.called);
2305                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2306         }
2307
2308         if(res <= 0) {
2309                 res = -1;
2310         } else {
2311                 res = 0;
2312         }
2313
2314         return res;
2315 }
2316
2317 /*!
2318  * \brief OSP Application OSPFinish
2319  * \param chan Channel
2320  * \param data Parameter
2321  * \return 0 Success, -1 Failed
2322  */
2323 static int ospfinished_exec(
2324         struct ast_channel* chan,
2325         const char * data)
2326 {
2327         int res = 1;
2328         int cause = 0;
2329         struct varshead* headp;
2330         struct ast_var_t* current;
2331         int inhandle = OSP_INVALID_HANDLE;
2332         int outhandle = OSP_INVALID_HANDLE;
2333         int recorded = 0;
2334         time_t start, connect, end;
2335         unsigned int release;
2336         char buffer[OSP_INTSTR_SIZE];
2337         char inqos[OSP_QOSSTR_SIZE] = { 0 };
2338         char outqos[OSP_QOSSTR_SIZE] = { 0 };
2339         const char* status;
2340         char* tmp;
2341
2342         AST_DECLARE_APP_ARGS(args,
2343                 AST_APP_ARG(cause);
2344                 AST_APP_ARG(options);
2345         );
2346
2347         if (!(tmp = ast_strdupa(data))) {
2348                 ast_log(LOG_ERROR, "Out of memory\n");
2349                 return -1;
2350         }
2351
2352         AST_STANDARD_APP_ARGS(args, tmp);
2353
2354         headp = &chan->varshead;
2355         AST_LIST_TRAVERSE(headp, current, entries) {
2356                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
2357                         if (sscanf(ast_var_value(current), "%30d", &inhandle) != 1) {
2358                                 inhandle = OSP_INVALID_HANDLE;
2359                         }
2360                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
2361                         if (sscanf(ast_var_value(current), "%30d", &outhandle) != 1) {
2362                                 outhandle = OSP_INVALID_HANDLE;
2363                         }
2364                 } else if (!recorded &&
2365                         (!strcasecmp(ast_var_name(current), "OSPAUTHSTATUS") ||
2366                         !strcasecmp(ast_var_name(current), "OSPLOOKUPSTATUS") ||
2367                         !strcasecmp(ast_var_name(current), "OSPNEXTSTATUS")))
2368                 {
2369                         if (strcasecmp(ast_var_value(current), AST_OSP_SUCCESS)) {
2370                                 recorded = 1;
2371                         }
2372                 } else if (!strcasecmp(ast_var_name(current), "OSPINAUDIOQOS")) {
2373                         ast_copy_string(inqos, ast_var_value(current), sizeof(inqos));
2374                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTAUDIOQOS")) {
2375                         ast_copy_string(outqos, ast_var_value(current), sizeof(outqos));
2376                 }
2377         }
2378         ast_debug(1, "OSPFinish: OSPINHANDLE '%d'\n", inhandle);
2379         ast_debug(1, "OSPFinish: OSPOUTHANDLE '%d'\n", outhandle);
2380         ast_debug(1, "OSPFinish: recorded '%d'\n", recorded);
2381         ast_debug(1, "OSPFinish: OSPINAUDIOQOS '%s'\n", inqos);
2382         ast_debug(1, "OSPFinish: OSPOUTAUDIOQOS '%s'\n", outqos);
2383
2384         if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%30d", &cause) != 1) {
2385                 cause = 0;
2386         }
2387         ast_debug(1, "OSPFinish: cause '%d'\n", cause);
2388
2389         if (chan->cdr) {
2390                 start = chan->cdr->start.tv_sec;
2391                 connect = chan->cdr->answer.tv_sec;
2392                 if (connect) {
2393                         end = time(NULL);
2394                 } else {
2395                         end = connect;
2396                 }
2397         } else {
2398                 start = 0;
2399                 connect = 0;
2400                 end = 0;
2401         }
2402         ast_debug(1, "OSPFinish: start '%ld'\n", start);
2403         ast_debug(1, "OSPFinish: connect '%ld'\n", connect);
2404         ast_debug(1, "OSPFinish: end '%ld'\n", end);
2405
2406         release = ast_check_hangup(chan) ? 0 : 1;
2407
2408         if (osp_finish(outhandle, recorded, cause, start, connect, end, release, inqos, outqos) <= 0) {
2409                 ast_debug(1, "OSPFinish: Unable to report usage for outbound call\n");
2410         }
2411         switch (cause) {
2412         case AST_CAUSE_NORMAL_CLEARING:
2413                 break;
2414         default:
2415                 cause = AST_CAUSE_NO_ROUTE_DESTINATION;
2416                 break;
2417         }
2418         if (osp_finish(inhandle, recorded, cause, start, connect, end, release, inqos, outqos) <= 0) {
2419                 ast_debug(1, "OSPFinish: Unable to report usage for inbound call\n");
2420         }
2421         snprintf(buffer, sizeof(buffer), "%d", OSP_INVALID_HANDLE);
2422         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
2423         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
2424
2425         if (res > 0) {
2426                 status = AST_OSP_SUCCESS;
2427         } else if (!res) {
2428                 status = AST_OSP_FAILED;
2429         } else {
2430                 status = AST_OSP_ERROR;
2431         }
2432         pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", status);
2433
2434         if(!res) {
2435                 res = -1;
2436         } else {
2437                 res = 0;
2438         }
2439
2440         return res;
2441 }
2442
2443 /* OSP Module APIs */
2444
2445 static int osp_unload(void);
2446 static int osp_load(int reload)
2447 {
2448         const char* t;
2449         unsigned int v;
2450         struct ast_config* cfg;
2451         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
2452         int error = OSPC_ERR_NO_ERROR;
2453
2454         if ((cfg = ast_config_load(OSP_CONFIG_FILE, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
2455                 return 0;
2456         } else if (cfg == CONFIG_STATUS_FILEINVALID) {
2457                 ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", OSP_CONFIG_FILE);
2458                 return 0;
2459         }
2460
2461         if (cfg) {
2462                 if (reload)
2463                         osp_unload();
2464
2465                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "accelerate");
2466                 if (t && ast_true(t)) {
2467                         if ((error = OSPPInit(1)) != OSPC_ERR_NO_ERROR) {
2468                                 ast_log(LOG_WARNING, "OSP: Unable to enable hardware accelleration\n");
2469                                 OSPPInit(0);
2470                         } else {
2471                                 osp_hardware = 1;
2472                         }
2473                 } else {
2474                         OSPPInit(0);
2475                 }
2476                 ast_debug(1, "OSP: osp_hardware '%d'\n", osp_hardware);
2477
2478                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "securityfeatures");
2479                 if (t && ast_true(t)) {
2480                         osp_security = 1;
2481                 }
2482                 ast_debug(1, "OSP: osp_security '%d'\n", osp_security);
2483
2484                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat");
2485                 if (t) {
2486                         if ((sscanf(t, "%30d", &v) == 1) &&
2487                                 ((v == TOKEN_ALGO_SIGNED) || (v == TOKEN_ALGO_UNSIGNED) || (v == TOKEN_ALGO_BOTH)))
2488                         {
2489                                 osp_tokenformat = v;
2490                         } else {
2491                                 ast_log(LOG_WARNING, "tokenformat should be an integer from %d, %d or %d, not '%s'\n",
2492                                         TOKEN_ALGO_SIGNED, TOKEN_ALGO_UNSIGNED, TOKEN_ALGO_BOTH, t);
2493                         }
2494                 }
2495                 ast_debug(1, "OSP: osp_tokenformat '%d'\n", osp_tokenformat);
2496
2497                 t = ast_category_browse(cfg, NULL);
2498                 while(t) {
2499                         if (strcasecmp(t, OSP_GENERAL_CAT)) {
2500                                 osp_create_provider(cfg, t);
2501                         }
2502                         t = ast_category_browse(cfg, t);
2503                 }
2504
2505                 osp_initialized = 1;
2506
2507                 ast_config_destroy(cfg);
2508         } else {
2509                 ast_log(LOG_WARNING, "OSP: Unable to find configuration. OSP support disabled\n");
2510                 return 0;
2511         }
2512         ast_debug(1, "OSP: osp_initialized '%d'\n", osp_initialized);
2513
2514         return 1;
2515 }
2516
2517 static int osp_unload(void)
2518 {
2519         struct osp_provider* p;
2520         struct osp_provider* next;
2521
2522         if (osp_initialized) {
2523                 ast_mutex_lock(&osplock);
2524                 p = ospproviders;
2525                 while(p) {
2526                         next = p->next;
2527                         OSPPProviderDelete(p->handle, 0);
2528                         ast_free(p);
2529                         p = next;
2530                 }
2531                 ospproviders = NULL;
2532                 ast_mutex_unlock(&osplock);
2533
2534                 OSPPCleanup();
2535
2536                 osp_tokenformat = TOKEN_ALGO_SIGNED;
2537                 osp_security = 0;
2538                 osp_hardware = 0;
2539                 osp_initialized = 0;
2540         }
2541         return 0;
2542 }
2543
2544 static char *handle_cli_osp_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2545 {
2546         int i;
2547         int found = 0;
2548         struct osp_provider* p;
2549         const char* provider = NULL;
2550         const char* tokenalgo;
2551
2552         switch (cmd) {
2553         case CLI_INIT:
2554                 e->command = "osp show";
2555                 e->usage =
2556                         "Usage: osp show\n"
2557                         "       Displays information on Open Settlement Protocol support\n";
2558                 return NULL;
2559         case CLI_GENERATE:
2560                 return NULL;
2561         }
2562
2563         if ((a->argc < 2) || (a->argc > 3))
2564                 return CLI_SHOWUSAGE;
2565         if (a->argc > 2)
2566                 provider = a->argv[2];
2567         if (!provider) {
2568                 switch (osp_tokenformat) {
2569                 case TOKEN_ALGO_BOTH:
2570                         tokenalgo = "Both";
2571                         break;
2572                 case TOKEN_ALGO_UNSIGNED:
2573                         tokenalgo = "Unsigned";
2574                         break;
2575                 case TOKEN_ALGO_SIGNED:
2576                 default:
2577                         tokenalgo = "Signed";
2578                         break;
2579                 }
2580                 ast_cli(a->fd, "OSP: %s/%s/%s/%s\n",
2581                         osp_initialized ? "Initialized" : "Uninitialized",
2582                         osp_hardware ? "Accelerated" : "Normal",
2583                         osp_security ? "Enabled" : "Disabled",
2584                         tokenalgo);
2585         }
2586
2587         ast_mutex_lock(&osplock);
2588         p = ospproviders;
2589         while(p) {
2590                 if (!provider || !strcasecmp(p->name, provider)) {
2591                         if (found) {
2592                                 ast_cli(a->fd, "\n");
2593                         }
2594                         ast_cli(a->fd, " == OSP Provider '%s' == \n", p->name);
2595                         if (osp_security) {
2596                                 ast_cli(a->fd, "Local Private Key: %s\n", p->privatekey);
2597                                 ast_cli(a->fd, "Local Certificate: %s\n", p->localcert);
2598                                 for (i = 0; i < p->cacount; i++) {
2599                                         ast_cli(a->fd, "CA Certificate %d:  %s\n", i + 1, p->cacerts[i]);
2600                                 }
2601                         }
2602                         for (i = 0; i < p->spcount; i++) {
2603                                 ast_cli(a->fd, "Service Point %d:   %s\n", i + 1, p->srvpoints[i]);
2604                         }
2605                         ast_cli(a->fd, "Max Connections:   %d\n", p->maxconnections);
2606                         ast_cli(a->fd, "Retry Delay:       %d seconds\n", p->retrydelay);
2607                         ast_cli(a->fd, "Retry Limit:       %d\n", p->retrylimit);
2608                         ast_cli(a->fd, "Timeout:           %d milliseconds\n", p->timeout);
2609                         ast_cli(a->fd, "Source:            %s\n", strlen(p->source) ? p->source : "<unspecified>");
2610                         ast_cli(a->fd, "Auth Policy        %d\n", p->authpolicy);
2611                         ast_cli(a->fd, "Default protocol   %s\n", p->defaultprotocol);
2612                         ast_cli(a->fd, "OSP Handle:        %d\n", p->handle);
2613                         found++;
2614                 }
2615                 p = p->next;
2616         }
2617         ast_mutex_unlock(&osplock);
2618
2619         if (!found) {
2620                 if (provider) {
2621                         ast_cli(a->fd, "Unable to find OSP provider '%s'\n", provider);
2622                 } else {
2623                         ast_cli(a->fd, "No OSP providers configured\n");
2624                 }
2625         }
2626         return CLI_SUCCESS;
2627 }
2628
2629 /* OSPAuth() dialplan application */
2630 static const char app1[] = "OSPAuth";
2631
2632 /* OSPLookup() dialplan application */
2633 static const char app2[] = "OSPLookup";
2634
2635 /* OSPNext() dialplan application */
2636 static const char app3[] = "OSPNext";
2637
2638 /* OSPFinish() dialplan application */
2639 static const char app4[] = "OSPFinish";
2640
2641 static struct ast_cli_entry cli_osp[] = {
2642         AST_CLI_DEFINE(handle_cli_osp_show, "Displays OSF information")
2643 };
2644
2645 static int load_module(void)
2646 {
2647         int res;
2648
2649         if (!osp_load(0))
2650                 return AST_MODULE_LOAD_DECLINE;
2651
2652         ast_cli_register_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
2653         res = ast_register_application_xml(app1, ospauth_exec);
2654         res |= ast_register_application_xml(app2, osplookup_exec);
2655         res |= ast_register_application_xml(app3, ospnext_exec);
2656         res |= ast_register_application_xml(app4, ospfinished_exec);
2657
2658         return res;
2659 }
2660
2661 static int unload_module(void)
2662 {
2663         int res;
2664
2665         res = ast_unregister_application(app4);
2666         res |= ast_unregister_application(app3);
2667         res |= ast_unregister_application(app2);
2668         res |= ast_unregister_application(app1);
2669         ast_cli_unregister_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
2670         osp_unload();
2671
2672         return res;
2673 }
2674
2675 static int reload(void)
2676 {
2677         osp_load(1);
2678
2679         return 0;
2680 }
2681
2682 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Open Settlement Protocol Applications",
2683         .load = load_module,
2684         .unload = unload_module,
2685         .reload = reload,
2686 );