Replaced two deprecated functions of OSP Toolkit.
[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 = OSPPTransactionGetDestinationNetworkId(results->outhandle, sizeof(results->networkid), 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         error = OSPPTransactionGetNumberPortabilityParameters(results->outhandle,
910                 sizeof(results->nprn),
911                 results->nprn,
912                 sizeof(results->npcic),
913                 results->npcic,
914                 &results->npdi);
915         if (error != OSPC_ERR_NO_ERROR) {
916                 ast_debug(1, "OSP: Unable to get number portability parameters, error '%d'\n", error);
917                 results->nprn[0] = '\0';
918                 results->npcic[0] = '\0';
919                 results->npdi = 0;
920         }
921
922         if ((error = OSPPTransactionGetDestProtocol(results->outhandle, &protocol)) != OSPC_ERR_NO_ERROR) {
923                 ast_debug(1, "OSP: Unable to get destination protocol, error '%d'\n", error);
924                 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
925                 results->token[0] = '\0';
926                 results->networkid[0] = '\0';
927                 results->nprn[0] = '\0';
928                 results->npcic[0] = '\0';
929                 results->npdi = 0;
930                 return -1;
931         }
932
933         res = 1;
934         osp_convert_outin(destination, dest, sizeof(dest));
935         switch(protocol) {
936         case OSPC_DPROT_SIP:
937                 ast_debug(1, "OSP: protocol SIP\n");
938                 ast_copy_string(results->tech, OSP_TECH_SIP, sizeof(results->tech));
939                 ast_copy_string(results->dest, dest, sizeof(results->dest));
940                 ast_copy_string(results->calling, calling, sizeof(results->calling));
941                 ast_copy_string(results->called, called, sizeof(results->called));
942                 break;
943         case OSPC_DPROT_Q931:
944                 ast_debug(1, "OSP: protocol Q.931\n");
945                 ast_copy_string(results->tech, OSP_TECH_H323, sizeof(results->tech));
946                 ast_copy_string(results->dest, dest, sizeof(results->dest));
947                 ast_copy_string(results->calling, calling, sizeof(results->calling));
948                 ast_copy_string(results->called, called, sizeof(results->called));
949                 break;
950         case OSPC_DPROT_IAX:
951                 ast_debug(1, "OSP: protocol IAX\n");
952                 ast_copy_string(results->tech, OSP_TECH_IAX, sizeof(results->tech));
953                 ast_copy_string(results->dest, dest, sizeof(results->dest));
954                 ast_copy_string(results->calling, calling, sizeof(results->calling));
955                 ast_copy_string(results->called, called, sizeof(results->called));
956                 break;
957         case OSPC_DPROT_SKYPE:
958                 ast_debug(1, "OSP: protocol Skype\n");
959                 ast_copy_string(results->tech, OSP_TECH_SKYPE, sizeof(results->tech));
960                 ast_copy_string(results->dest, dest, sizeof(results->dest));
961                 ast_copy_string(results->calling, calling, sizeof(results->calling));
962                 ast_copy_string(results->called, called, sizeof(results->called));
963                 break;
964         case OSPC_DPROT_UNDEFINED:
965         case OSPC_DPROT_UNKNOWN:
966                 ast_debug(1, "OSP: unknown/undefined protocol '%d'\n", protocol);
967                 ast_debug(1, "OSP: use default protocol '%s'\n", provider->defaultprotocol);
968                 ast_copy_string(results->tech, provider->defaultprotocol, sizeof(results->tech));
969                 ast_copy_string(results->dest, dest, sizeof(results->dest));
970                 ast_copy_string(results->calling, calling, sizeof(results->calling));
971                 ast_copy_string(results->called, called, sizeof(results->called));
972                 break;
973         case OSPC_DPROT_LRQ:
974         case OSPC_DPROT_T37:
975         case OSPC_DPROT_T38:
976         case OSPC_DPROT_SMPP:
977         case OSPC_DPROT_XMPP:
978         default:
979                 ast_log(LOG_WARNING, "OSP: unsupported protocol '%d'\n", protocol);
980                 *reason = OSPC_FAIL_PROTOCOL_ERROR;
981                 results->token[0] = '\0';
982                 results->networkid[0] = '\0';
983                 results->nprn[0] = '\0';
984                 results->npcic[0] = '\0';
985                 results->npdi = 0;
986                 res = 0;
987                 break;
988         }
989
990         return res;
991 }
992
993 /*!
994  * \brief Convert Asterisk status to TC code
995  * \param cause Asterisk hangup cause
996  * \return OSP TC code
997  */
998 static OSPEFAILREASON asterisk2osp(
999         int cause)
1000 {
1001         return (OSPEFAILREASON)cause;
1002 }
1003
1004 /*!
1005  * \brief OSP Authentication function
1006  * \param provider OSP provider context name
1007  * \param transaction OSP transaction handle, output
1008  * \param source Source of inbound call
1009  * \param calling Calling number
1010  * \param called Called number
1011  * \param token OSP token, may be empty
1012  * \param timelimit Call duration limit, output
1013  * \return 1 Authenricated, 0 Unauthenticated, -1 Error
1014  */
1015 static int osp_auth(
1016         const char* provider,
1017         int* transaction,
1018         const char* source,
1019         const char* calling,
1020         const char* called,
1021         const char* token,
1022         unsigned int* timelimit)
1023 {
1024         int res;
1025         struct osp_provider* p = NULL;
1026         char dest[OSP_NORSTR_SIZE];
1027
1028         *transaction = OSP_INVALID_HANDLE;
1029         *timelimit = OSP_DEF_TIMELIMIT;
1030
1031         if ((res = osp_get_provider(provider, &p)) <= 0) {
1032                 ast_debug(1, "OSP: Unabe to find OSP provider '%s'\n", provider);
1033                 return res;
1034         }
1035
1036         switch (p->authpolicy) {
1037         case OSP_AUTH_NO:
1038                 res = 1;
1039                 break;
1040         case OSP_AUTH_EXCLUSIVE:
1041                 if (ast_strlen_zero(token)) {
1042                         res = 0;
1043                 } else if ((res = osp_create_transaction(provider, transaction, dest, sizeof(dest))) <= 0) {
1044                         ast_debug(1, "OSP: Unable to generate transaction handle\n");
1045                         *transaction = OSP_INVALID_HANDLE;
1046                         res = 0;
1047                 } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
1048                         OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
1049                 }
1050                 break;
1051         case OSP_AUTH_YES:
1052         default:
1053                 if (ast_strlen_zero(token)) {
1054                         res = 1;
1055                 } else if ((res = osp_create_transaction(provider, transaction, dest, sizeof(dest))) <= 0) {
1056                         ast_debug(1, "OSP: Unable to generate transaction handle\n");
1057                         *transaction = OSP_INVALID_HANDLE;
1058                         res = 0;
1059                 } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
1060                         OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
1061                 }
1062                 break;
1063         }
1064
1065         return res;
1066 }
1067
1068 /*!
1069  * \brief Create a UUID
1070  * \param uuid UUID buffer
1071  * \param bufsize UUID buffer size
1072  * \return 1 Created, -1 Error
1073  */
1074 static int osp_create_uuid(
1075         unsigned char* uuid,
1076         unsigned int* bufsize)
1077 {
1078         int i, res;
1079         long int tmp[OSP_UUID_SIZE / sizeof(long int)];
1080
1081         if (*bufsize >= OSP_UUID_SIZE) {
1082                 for (i = 0; i < OSP_UUID_SIZE / sizeof(long int); i++) {
1083                         tmp[i] = ast_random();
1084                 }
1085                 memcpy(uuid, tmp, OSP_UUID_SIZE);
1086                 *bufsize = OSP_UUID_SIZE;
1087                 res = 1;
1088         } else {
1089                 res = -1;
1090         }
1091
1092         return res;
1093 }
1094
1095 /*!
1096  * \brief UUID to string
1097  * \param uuid UUID
1098  * \param buffer String buffer
1099  * \param bufsize String buffer size
1100  * \return 1 Successed, -1 Error
1101  */
1102 static int osp_uuid2str(
1103         unsigned char* uuid,
1104         char* buffer,
1105         unsigned int bufsize)
1106 {
1107         int res;
1108
1109         if (bufsize > OSP_UUIDSTR_SIZE) {
1110                 snprintf(buffer, bufsize, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1111                         uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
1112                         uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
1113                 res = 1;
1114         } else {
1115                 res = -1;
1116         }
1117
1118         return res;
1119 }
1120
1121 /*!
1122  * \brief Create a call ID according to the type
1123  * \param type Call ID type
1124  * \param callid Call ID buffer
1125  * \return 1 Created, 0 Not create, -1 Error
1126  */
1127 static int osp_create_callid(
1128         unsigned int type,
1129         struct osp_callid* callid)
1130 {
1131         int res;
1132
1133         callid->len = sizeof(callid->buf);
1134         switch (type) {
1135         case OSP_CALLID_H323:
1136                 res = osp_create_uuid(callid->buf, &callid->len);
1137                 break;
1138         case OSP_CALLID_SIP:
1139         case OSP_CALLID_IAX:
1140                 res = 0;
1141         default:
1142                 res = -1;
1143                 break;
1144         }
1145
1146         if ((res != 1) && (callid->len != 0)) {
1147                 callid->buf[0] = '\0';
1148                 callid->len = 0;
1149         }
1150
1151         return res;
1152 }
1153
1154 /*!
1155  * \brief OSP Lookup function
1156  * \param provider OSP provider context name
1157  * \param callidtypes Call ID types
1158  * \param srcdev Source device of outbound call
1159  * \param calling Calling number
1160  * \param called Called number
1161  * \param snetid Source network ID
1162  * \param np NP parameters
1163  * \param div SIP Diversion header parameters
1164  * \param cinfo Custom info
1165  * \param results Lookup results
1166  * \return 1 Found , 0 No route, -1 Error
1167  */
1168 static int osp_lookup(
1169         const char* provider,
1170         unsigned int callidtypes,
1171         const char* srcdev,
1172         const char* calling,
1173         const char* called,
1174         const char* snetid,
1175         struct osp_npparam* np,
1176         struct osp_diversion* div,
1177         const char* cinfo[],
1178         struct osp_results* results)
1179 {
1180         int res;
1181         struct osp_provider* p = NULL;
1182         char source[OSP_NORSTR_SIZE];
1183         char callingnum[OSP_NORSTR_SIZE];
1184         char callednum[OSP_NORSTR_SIZE];
1185         char destination[OSP_NORSTR_SIZE];
1186         unsigned int tokenlen;
1187         char token[OSP_TOKSTR_SIZE];
1188         char src[OSP_NORSTR_SIZE];
1189         char dev[OSP_NORSTR_SIZE];
1190         char host[OSP_NORSTR_SIZE];
1191         unsigned int i, type;
1192         struct osp_callid callid;
1193         unsigned int callidnum;
1194         OSPT_CALL_ID* callids[OSP_CALLID_MAXNUM];
1195         unsigned int dummy = 0;
1196         OSPEFAILREASON reason;
1197         int error;
1198
1199         results->outhandle = OSP_INVALID_HANDLE;
1200         results->tech[0] = '\0';
1201         results->dest[0] = '\0';
1202         results->calling[0] = '\0';
1203         results->called[0] = '\0';
1204         results->token[0] = '\0';
1205         results->networkid[0] = '\0';
1206         results->nprn[0] = '\0';
1207         results->npcic[0] = '\0';
1208         results->npdi = 0;
1209         results->numresults = 0;
1210         results->outtimelimit = OSP_DEF_TIMELIMIT;
1211
1212         if ((res = osp_get_provider(provider, &p)) <= 0) {
1213                 ast_debug(1, "OSP: Unabe to find OSP provider '%s'\n", provider);
1214                 return res;
1215         }
1216
1217         if ((res = osp_create_transaction(provider, &results->outhandle, source, sizeof(source))) <= 0) {
1218                 ast_debug(1, "OSP: Unable to generate transaction handle\n");
1219                 results->outhandle = OSP_INVALID_HANDLE;
1220                 if (results->inhandle != OSP_INVALID_HANDLE) {
1221                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1222                 }
1223                 return -1;
1224         }
1225
1226         if (!ast_strlen_zero(snetid)) {
1227                 OSPPTransactionSetNetworkIds(results->outhandle, snetid, "");
1228         }
1229
1230         OSPPTransactionSetNumberPortability(results->outhandle, np->rn, np->cic, np->npdi);
1231
1232         osp_convert_inout(div->host, host, sizeof(host));
1233         OSPPTransactionSetDiversion(results->outhandle, div->user, host);
1234
1235         if (cinfo != NULL) {
1236                 for (i = 0; i < OSP_MAX_CUSTOMINFO; i++) {
1237                         if (!ast_strlen_zero(cinfo[i])) {
1238                                 OSPPTransactionSetCustomInfo(results->outhandle, i, cinfo[i]);
1239                         }
1240                 }
1241         }
1242
1243         callidnum = 0;
1244         callids[0] = NULL;
1245         for (i = 0; i < OSP_CALLID_MAXNUM; i++) {
1246                 type = 1 << i;
1247                 if (callidtypes & type) {
1248                         error = osp_create_callid(type, &callid);
1249                         if (error == 1) {
1250                                 callids[callidnum] = OSPPCallIdNew(callid.len, callid.buf);
1251                                 callidnum++;
1252                         }
1253                 }
1254         }
1255
1256         osp_convert_inout(source, src, sizeof(src));
1257         osp_convert_inout(srcdev, dev, sizeof(dev));
1258         results->numresults = OSP_DEF_DESTINATIONS;
1259         error = OSPPTransactionRequestAuthorisation(
1260                 results->outhandle,
1261                 src,
1262                 dev,
1263                 calling ? calling : "",
1264                 OSPC_NFORMAT_E164,
1265                 called,
1266                 OSPC_NFORMAT_E164,
1267                 NULL,
1268                 callidnum,
1269                 callids,
1270                 NULL,
1271                 &results->numresults,
1272                 &dummy,
1273                 NULL);
1274
1275         for (i = 0; i < callidnum; i++) {
1276                 OSPPCallIdDelete(&callids[i]);
1277         }
1278
1279         if (error != OSPC_ERR_NO_ERROR) {
1280                 ast_debug(1, "OSP: Unable to request authorization, error '%d'\n", error);
1281                 results->numresults = 0;
1282                 if (results->inhandle != OSP_INVALID_HANDLE) {
1283                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1284                 }
1285                 return -1;
1286         }
1287
1288         if (!results->numresults) {
1289                 ast_debug(1, "OSP: No more destination\n");
1290                 if (results->inhandle != OSP_INVALID_HANDLE) {
1291                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1292                 }
1293                 return 0;
1294         }
1295
1296         results->outcallid.len = sizeof(results->outcallid.buf);
1297         tokenlen = sizeof(token);
1298         error = OSPPTransactionGetFirstDestination(
1299                 results->outhandle,
1300                 0,
1301                 NULL,
1302                 NULL,
1303                 &results->outtimelimit,
1304                 &results->outcallid.len,
1305                 results->outcallid.buf,
1306                 sizeof(callednum),
1307                 callednum,
1308                 sizeof(callingnum),
1309                 callingnum,
1310                 sizeof(destination),
1311                 destination,
1312                 0,
1313                 NULL,
1314                 &tokenlen,
1315                 token);
1316         if (error != OSPC_ERR_NO_ERROR) {
1317                 ast_debug(1, "OSP: Unable to get first route, error '%d'\n", error);
1318                 results->numresults = 0;
1319                 results->outtimelimit = OSP_DEF_TIMELIMIT;
1320                 if (results->inhandle != OSP_INVALID_HANDLE) {
1321                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1322                 }
1323                 return -1;
1324         }
1325
1326         results->numresults--;
1327         results->outtimelimit = osp_choose_timelimit(results->intimelimit, results->outtimelimit);
1328         ast_debug(1, "OSP: outtimelimit '%d'\n", results->outtimelimit);
1329         ast_debug(1, "OSP: calling '%s'\n", callingnum);
1330         ast_debug(1, "OSP: called '%s'\n", callednum);
1331         ast_debug(1, "OSP: destination '%s'\n", destination);
1332         ast_debug(1, "OSP: token size '%d'\n", tokenlen);
1333
1334         if ((res = osp_check_destination(p, callingnum, callednum, destination, tokenlen, token, &reason, results)) > 0) {
1335                 return 1;
1336         }
1337
1338         if (!results->numresults) {
1339                 ast_debug(1, "OSP: No more destination\n");
1340                 results->outtimelimit = OSP_DEF_TIMELIMIT;
1341                 OSPPTransactionRecordFailure(results->outhandle, reason);
1342                 if (results->inhandle != OSP_INVALID_HANDLE) {
1343                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1344                 }
1345                 return 0;
1346         }
1347
1348         while(results->numresults) {
1349                 results->outcallid.len = sizeof(results->outcallid.buf);
1350                 tokenlen = sizeof(token);
1351                 error = OSPPTransactionGetNextDestination(
1352                         results->outhandle,
1353                         reason,
1354                         0,
1355                         NULL,
1356                         NULL,
1357                         &results->outtimelimit,
1358                         &results->outcallid.len,
1359                         results->outcallid.buf,
1360                         sizeof(callednum),
1361                         callednum,
1362                         sizeof(callingnum),
1363                         callingnum,
1364                         sizeof(destination),
1365                         destination,
1366                         0,
1367                         NULL,
1368                         &tokenlen,
1369                         token);
1370                 if (error == OSPC_ERR_NO_ERROR) {
1371                         results->numresults--;
1372                         results->outtimelimit = osp_choose_timelimit(results->intimelimit, results->outtimelimit);
1373                         ast_debug(1, "OSP: outtimelimit '%d'\n", results->outtimelimit);
1374                         ast_debug(1, "OSP: calling '%s'\n", callingnum);
1375                         ast_debug(1, "OSP: called '%s'\n", callednum);
1376                         ast_debug(1, "OSP: destination '%s'\n", destination);
1377                         ast_debug(1, "OSP: token size '%d'\n", tokenlen);
1378
1379                         if ((res = osp_check_destination(p, callingnum, callednum, destination, tokenlen, token, &reason, results)) > 0) {
1380                                 break;
1381                         } else if (!results->numresults) {
1382                                 ast_debug(1, "OSP: No more destination\n");
1383                                 OSPPTransactionRecordFailure(results->outhandle, reason);
1384                                 if (results->inhandle != OSP_INVALID_HANDLE) {
1385                                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1386                                 }
1387                                 res = 0;
1388                                 break;
1389                         }
1390                 } else {
1391                         ast_debug(1, "OSP: Unable to get route, error '%d'\n", error);
1392                         results->numresults = 0;
1393                         results->outtimelimit = OSP_DEF_TIMELIMIT;
1394                         if (results->inhandle != OSP_INVALID_HANDLE) {
1395                                 OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1396                         }
1397                         res = -1;
1398                         break;
1399                 }
1400         }
1401         return res;
1402 }
1403
1404 /*!
1405  * \brief OSP Lookup Next function
1406  * \param provider OSP provider name
1407  * \param cause Asterisk hangup cuase
1408  * \param results Lookup results, in/output
1409  * \return 1 Found , 0 No route, -1 Error
1410  */
1411 static int osp_next(
1412         const char* provider,
1413         int cause,
1414         struct osp_results* results)
1415 {
1416         int res;
1417         struct osp_provider* p = NULL;
1418         char callingnum[OSP_NORSTR_SIZE];
1419         char callednum[OSP_NORSTR_SIZE];
1420         char destination[OSP_NORSTR_SIZE];
1421         unsigned int tokenlen;
1422         char token[OSP_TOKSTR_SIZE];
1423         OSPEFAILREASON reason;
1424         int error;
1425
1426         results->tech[0] = '\0';
1427         results->dest[0] = '\0';
1428         results->calling[0] = '\0';
1429         results->called[0] = '\0';
1430         results->token[0] = '\0';
1431         results->networkid[0] = '\0';
1432         results->nprn[0] = '\0';
1433         results->npcic[0] = '\0';
1434         results->npdi = 0;
1435         results->outtimelimit = OSP_DEF_TIMELIMIT;
1436
1437         if ((res = osp_get_provider(provider, &p)) <= 0) {
1438                 ast_debug(1, "OSP: Unabe to find OSP provider '%s'\n", provider);
1439                 return res;
1440         }
1441
1442         if (results->outhandle == OSP_INVALID_HANDLE) {
1443                 ast_debug(1, "OSP: Transaction handle undefined\n");
1444                 results->numresults = 0;
1445                 if (results->inhandle != OSP_INVALID_HANDLE) {
1446                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1447                 }
1448                 return -1;
1449         }
1450
1451         reason = asterisk2osp(cause);
1452
1453         if (!results->numresults) {
1454                 ast_debug(1, "OSP: No more destination\n");
1455                 OSPPTransactionRecordFailure(results->outhandle, reason);
1456                 if (results->inhandle != OSP_INVALID_HANDLE) {
1457                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1458                 }
1459                 return 0;
1460         }
1461
1462         while(results->numresults) {
1463                 results->outcallid.len = sizeof(results->outcallid.buf);
1464                 tokenlen = sizeof(token);
1465                 error = OSPPTransactionGetNextDestination(
1466                         results->outhandle,
1467                         reason,
1468                         0,
1469                         NULL,
1470                         NULL,
1471                         &results->outtimelimit,
1472                         &results->outcallid.len,
1473                         results->outcallid.buf,
1474                         sizeof(callednum),
1475                         callednum,
1476                         sizeof(callingnum),
1477                         callingnum,
1478                         sizeof(destination),
1479                         destination,
1480                         0,
1481                         NULL,
1482                         &tokenlen,
1483                         token);
1484                 if (error == OSPC_ERR_NO_ERROR) {
1485                         results->numresults--;
1486                         results->outtimelimit = osp_choose_timelimit(results->intimelimit, results->outtimelimit);
1487                         ast_debug(1, "OSP: outtimelimit '%d'\n", results->outtimelimit);
1488                         ast_debug(1, "OSP: calling '%s'\n", callingnum);
1489                         ast_debug(1, "OSP: called '%s'\n", callednum);
1490                         ast_debug(1, "OSP: destination '%s'\n", destination);
1491                         ast_debug(1, "OSP: token size '%d'\n", tokenlen);
1492
1493                         if ((res = osp_check_destination(p, callingnum, callednum, destination, tokenlen, token, &reason, results)) > 0) {
1494                                 res = 1;
1495                                 break;
1496                         } else if (!results->numresults) {
1497                                 ast_debug(1, "OSP: No more destination\n");
1498                                 OSPPTransactionRecordFailure(results->outhandle, reason);
1499                                 if (results->inhandle != OSP_INVALID_HANDLE) {
1500                                         OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1501                                 }
1502                                 res = 0;
1503                                 break;
1504                         }
1505                 } else {
1506                         ast_debug(1, "OSP: Unable to get route, error '%d'\n", error);
1507                         results->token[0] = '\0';
1508                         results->numresults = 0;
1509                         results->outtimelimit = OSP_DEF_TIMELIMIT;
1510                         if (results->inhandle != OSP_INVALID_HANDLE) {
1511                                 OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1512                         }
1513                         res = -1;
1514                         break;
1515                 }
1516         }
1517
1518         return res;
1519 }
1520
1521 /*!
1522  * \brief Get integer from variable string
1523  * \param vstr Variable string
1524  * \return -1 Error
1525  */
1526 static int osp_get_varint(
1527         const char* vstr)
1528 {
1529         char* tmp;
1530         int value = -1;
1531
1532         if (!ast_strlen_zero(vstr)) {
1533                 if ((tmp = strchr(vstr, '=')) != NULL) {
1534                         tmp++;
1535                         if (sscanf(tmp, "%30d", &value) != 1) {
1536                                 value = -1;
1537                         }
1538                 }
1539         }
1540
1541         return value;
1542 }
1543
1544 /*!
1545  * \brief Get float from variable string
1546  * \param vstr Variable string
1547  * \return -1 Error
1548  */
1549 static float osp_get_varfloat(
1550         const char* vstr)
1551 {
1552         char* tmp;
1553         float value = -1;
1554
1555         if (!ast_strlen_zero(vstr)) {
1556                 if ((tmp = strchr(vstr, '=')) != NULL) {
1557                         tmp++;
1558                         if (sscanf(tmp, "%30f", &value) != 1) {
1559                                 value = -1;
1560                         }
1561                 }
1562         }
1563
1564         return value;
1565 }
1566
1567 /*!
1568  * \brief Report QoS
1569  * \param handle OSP in/outbound transaction handle
1570  * \param leg Inbound/outbound
1571  * \param qos QoS string
1572  * \return 1 Success, 0 Failed, -1 Error
1573  */
1574 static int osp_report_qos(
1575         int handle,
1576         enum osp_callleg leg,
1577         const char* qos)
1578 {
1579         int res = 0;
1580         enum osp_direction dir;
1581         char buffer[OSP_NORSTR_SIZE];
1582         char* tmp;
1583         char* item;
1584         int totalpackets[OSP_DIR_NUMBER];
1585         struct osp_metrics lost[OSP_DIR_NUMBER];
1586         struct osp_metrics jitter[OSP_DIR_NUMBER];
1587         struct osp_metrics rtt;
1588         int value;
1589
1590         if (!ast_strlen_zero(qos)) {
1591                 for (dir = OSP_DIR_RX; dir < OSP_DIR_NUMBER; dir++) {
1592                         totalpackets[dir] = -1;
1593                 }
1594
1595                 for (dir = OSP_DIR_RX; dir < OSP_DIR_NUMBER; dir++) {
1596                         lost[dir].value = -1;
1597                         lost[dir].min = -1;
1598                         lost[dir].max = -1;
1599                         lost[dir].avg = -1;
1600                         lost[dir].sdev = -1;
1601                 }
1602
1603                 for (dir = OSP_DIR_RX; dir < OSP_DIR_NUMBER; dir++) {
1604                         jitter[dir].value = -1;
1605                         jitter[dir].min = -1;
1606                         jitter[dir].max = -1;
1607                         jitter[dir].avg = -1;
1608                         jitter[dir].sdev = -1;
1609                 }
1610
1611                 rtt.value = -1;
1612                 rtt.min = -1;
1613                 rtt.max = -1;
1614                 rtt.avg = -1;
1615                 rtt.sdev = -1;
1616
1617                 ast_copy_string(buffer, qos, sizeof(buffer));
1618                 for (item = strtok_r(buffer, ";", &tmp); item; item = strtok_r(NULL, ";", &tmp)) {
1619                         if (!strncasecmp(item, "rxcount", strlen("rxcount"))) {
1620                                 totalpackets[OSP_DIR_RX] = osp_get_varint(item);
1621                         } else if (!strncasecmp(item, "txcount", strlen("txcount"))) {
1622                                 totalpackets[OSP_DIR_TX] = osp_get_varint(item);
1623                         } else if (!strncasecmp(item, "lp", strlen("lp"))) {
1624                                 lost[OSP_DIR_RX].value = osp_get_varint(item);
1625                         } else if (!strncasecmp(item, "minrxlost", strlen("minrxlost"))) {
1626                                 lost[OSP_DIR_RX].min = osp_get_varfloat(item);
1627                         } else if (!strncasecmp(item, "maxrxlost", strlen("maxrxlost"))) {
1628                                 lost[OSP_DIR_RX].max = osp_get_varfloat(item);
1629                         } else if (!strncasecmp(item, "avgrxlost", strlen("avgrxlost"))) {
1630                                 lost[OSP_DIR_RX].avg = osp_get_varfloat(item);
1631                         } else if (!strncasecmp(item, "stdevrxlost", strlen("stdevrxlost"))) {
1632                                 lost[OSP_DIR_RX].sdev = osp_get_varfloat(item);
1633                         } else if (!strncasecmp(item, "rlp", strlen("rlp"))) {
1634                                 lost[OSP_DIR_TX].value = osp_get_varint(item);
1635                         } else if (!strncasecmp(item, "reported_minlost", strlen("reported_minlost"))) {
1636                                 lost[OSP_DIR_TX].min = osp_get_varfloat(item);
1637                         } else if (!strncasecmp(item, "reported_maxlost", strlen("reported_maxlost"))) {
1638                                 lost[OSP_DIR_TX].max = osp_get_varfloat(item);
1639                         } else if (!strncasecmp(item, "reported_avglost", strlen("reported_avglost"))) {
1640                                 lost[OSP_DIR_TX].avg = osp_get_varfloat(item);
1641                         } else if (!strncasecmp(item, "reported_stdevlost", strlen("reported_stdevlost"))) {
1642                                 lost[OSP_DIR_TX].sdev = osp_get_varfloat(item);
1643                         } else if (!strncasecmp(item, "rxjitter", strlen("rxjitter"))) {
1644                                 jitter[OSP_DIR_RX].value = osp_get_varint(item);
1645                         } else if (!strncasecmp(item, "minrxjitter", strlen("minrxjitter"))) {
1646                                 jitter[OSP_DIR_RX].min = osp_get_varfloat(item);
1647                         } else if (!strncasecmp(item, "maxrxjitter", strlen("maxrxjitter"))) {
1648                                 jitter[OSP_DIR_RX].max = osp_get_varfloat(item);
1649                         } else if (!strncasecmp(item, "avgrxjitter", strlen("avgjitter"))) {
1650                                 jitter[OSP_DIR_RX].avg = osp_get_varfloat(item);
1651                         } else if (!strncasecmp(item, "stdevrxjitter", strlen("stdevjitter"))) {
1652                                 jitter[OSP_DIR_RX].sdev = osp_get_varfloat(item);
1653                         } else if (!strncasecmp(item, "txjitter", strlen("txjitter"))) {
1654                                 jitter[OSP_DIR_TX].value = osp_get_varint(item);
1655                         } else if (!strncasecmp(item, "reported_minjitter", strlen("reported_minjitter"))) {
1656                                 jitter[OSP_DIR_TX].min = osp_get_varfloat(item);
1657                         } else if (!strncasecmp(item, "reported_maxjitter", strlen("reported_maxjitter"))) {
1658                                 jitter[OSP_DIR_TX].max = osp_get_varfloat(item);
1659                         } else if (!strncasecmp(item, "reported_avgjitter", strlen("reported_avgjitter"))) {
1660                                 jitter[OSP_DIR_TX].avg = osp_get_varfloat(item);
1661                         } else if (!strncasecmp(item, "reported_stdevjitter", strlen("reported_stdevjitter"))) {
1662                                 jitter[OSP_DIR_TX].sdev = osp_get_varfloat(item);
1663                         } else if (!strncasecmp(item, "rtt", strlen("rtt"))) {
1664                                 rtt.value = osp_get_varint(item);
1665                         } else if (!strncasecmp(item, "minrtt", strlen("minrtt"))) {
1666                                 rtt.min = osp_get_varfloat(item);
1667                         } else if (!strncasecmp(item, "maxrtt", strlen("maxrtt"))) {
1668                                 rtt.max = osp_get_varfloat(item);
1669                         } else if (!strncasecmp(item, "avgrtt", strlen("avgrtt"))) {
1670                                 rtt.avg = osp_get_varfloat(item);
1671                         } else if (!strncasecmp(item, "stdevrtt", strlen("stdevrtt"))) {
1672                                 rtt.sdev = osp_get_varfloat(item);
1673                         }
1674                 }
1675
1676                 ast_debug(1, "OSP: call leg '%d'\n", leg);
1677                 ast_debug(1, "OSP: rxcount '%d'\n", totalpackets[OSP_DIR_RX]);
1678                 ast_debug(1, "OSP: txcount '%d'\n", totalpackets[OSP_DIR_TX]);
1679                 ast_debug(1, "OSP: lp '%d'\n",lost[OSP_DIR_RX].value);
1680                 ast_debug(1, "OSP: minrxlost '%f'\n", lost[OSP_DIR_RX].min);
1681                 ast_debug(1, "OSP: maxrxlost '%f'\n", lost[OSP_DIR_RX].max);
1682                 ast_debug(1, "OSP: avgrxlost '%f'\n", lost[OSP_DIR_RX].avg);
1683                 ast_debug(1, "OSP: stdevrxlost '%f'\n", lost[OSP_DIR_RX].sdev);
1684                 ast_debug(1, "OSP: rlp '%d'\n", lost[OSP_DIR_TX].value);
1685                 ast_debug(1, "OSP: reported_minlost '%f'\n", lost[OSP_DIR_TX].min);
1686                 ast_debug(1, "OSP: reported_maxlost '%f'\n", lost[OSP_DIR_TX].max);
1687                 ast_debug(1, "OSP: reported_avglost '%f'\n", lost[OSP_DIR_TX].avg);
1688                 ast_debug(1, "OSP: reported_stdevlost '%f'\n", lost[OSP_DIR_TX].sdev);
1689                 ast_debug(1, "OSP: rxjitter '%d'\n", jitter[OSP_DIR_RX].value);
1690                 ast_debug(1, "OSP: minrxjitter '%f'\n", jitter[OSP_DIR_RX].min);
1691                 ast_debug(1, "OSP: maxrxjitter '%f'\n", jitter[OSP_DIR_RX].max);
1692                 ast_debug(1, "OSP: avgrxjitter '%f'\n", jitter[OSP_DIR_RX].avg);
1693                 ast_debug(1, "OSP: stdevrxjitter '%f'\n", jitter[OSP_DIR_RX].sdev);
1694                 ast_debug(1, "OSP: txjitter '%d'\n", jitter[OSP_DIR_TX].value);
1695                 ast_debug(1, "OSP: reported_minjitter '%f'\n", jitter[OSP_DIR_TX].min);
1696                 ast_debug(1, "OSP: reported_maxjitter '%f'\n", jitter[OSP_DIR_TX].max);
1697                 ast_debug(1, "OSP: reported_avgjitter '%f'\n", jitter[OSP_DIR_TX].avg);
1698                 ast_debug(1, "OSP: reported_stdevjitter '%f'\n", jitter[OSP_DIR_TX].sdev);
1699                 ast_debug(1, "OSP: rtt '%d'\n", rtt.value);
1700                 ast_debug(1, "OSP: minrtt '%f'\n", rtt.min);
1701                 ast_debug(1, "OSP: maxrtt '%f'\n", rtt.max);
1702                 ast_debug(1, "OSP: avgrtt '%f'\n", rtt.avg);
1703                 ast_debug(1, "OSP: stdevrtt '%f'\n", rtt.sdev);
1704
1705                 if (leg == OSP_CALL_INBOUND) {
1706                         OSPPTransactionSetPackets(handle, OSPC_SMETRIC_RTP, OSPC_SFLOW_DOWNSTREAM, totalpackets[OSP_DIR_RX]);
1707                         OSPPTransactionSetPackets(handle, OSPC_SMETRIC_RTCP, OSPC_SFLOW_UPSTREAM, totalpackets[OSP_DIR_TX]);
1708                         if (lost[OSP_DIR_RX].value >= 0) {
1709                                 value = lost[OSP_DIR_RX].value;
1710                         } else {
1711                                 value = (int)lost[OSP_DIR_RX].avg;
1712                         }
1713                         OSPPTransactionSetLost(handle, OSPC_SMETRIC_RTP, OSPC_SFLOW_DOWNSTREAM, value, -1);
1714                         if (lost[OSP_DIR_TX].value >= 0) {
1715                                 value = lost[OSP_DIR_TX].value;
1716                         } else {
1717                                 value = (int)lost[OSP_DIR_TX].avg;
1718                         }
1719                         OSPPTransactionSetLost(handle, OSPC_SMETRIC_RTCP, OSPC_SFLOW_UPSTREAM, value, -1);
1720                         if (jitter[OSP_DIR_RX].value >= 0) {
1721                                 value = jitter[OSP_DIR_RX].value;
1722                         } else {
1723                                 value = (int)jitter[OSP_DIR_RX].avg;
1724                         }
1725                         OSPPTransactionSetJitter(handle, OSPC_SMETRIC_RTP, OSPC_SFLOW_DOWNSTREAM,
1726                                 -1, (int)jitter[OSP_DIR_RX].min, (int)jitter[OSP_DIR_RX].max, value, jitter[OSP_DIR_RX].sdev);
1727                         if (jitter[OSP_DIR_TX].value >= 0) {
1728                                 value = jitter[OSP_DIR_TX].value;
1729                         } else {
1730                                 value = (int)jitter[OSP_DIR_TX].avg;
1731                         }
1732                         OSPPTransactionSetJitter(handle, OSPC_SMETRIC_RTCP, OSPC_SFLOW_UPSTREAM,
1733                                 -1, (int)jitter[OSP_DIR_TX].min, (int)jitter[OSP_DIR_TX].max, value, jitter[OSP_DIR_TX].sdev);
1734                 } else {
1735                         OSPPTransactionSetPackets(handle, OSPC_SMETRIC_RTP, OSPC_SFLOW_UPSTREAM, totalpackets[OSP_DIR_RX]);
1736                         OSPPTransactionSetPackets(handle, OSPC_SMETRIC_RTCP, OSPC_SFLOW_DOWNSTREAM, totalpackets[OSP_DIR_TX]);
1737                         OSPPTransactionSetLost(handle, OSPC_SMETRIC_RTP, OSPC_SFLOW_UPSTREAM, lost[OSP_DIR_RX].value, -1);
1738                         OSPPTransactionSetLost(handle, OSPC_SMETRIC_RTCP, OSPC_SFLOW_DOWNSTREAM, lost[OSP_DIR_TX].value, -1);
1739                         if (jitter[OSP_DIR_RX].value >= 0) {
1740                                 value = jitter[OSP_DIR_RX].value;
1741                         } else {
1742                                 value = (int)jitter[OSP_DIR_RX].avg;
1743                         }
1744                         OSPPTransactionSetJitter(handle, OSPC_SMETRIC_RTP, OSPC_SFLOW_UPSTREAM,
1745                                 -1, (int)jitter[OSP_DIR_RX].min, (int)jitter[OSP_DIR_RX].max, value, jitter[OSP_DIR_RX].sdev);
1746                         if (jitter[OSP_DIR_TX].value >= 0) {
1747                                 value = jitter[OSP_DIR_TX].value;
1748                         } else {
1749                                 value = (int)jitter[OSP_DIR_TX].avg;
1750                         }
1751                         OSPPTransactionSetJitter(handle, OSPC_SMETRIC_RTCP, OSPC_SFLOW_DOWNSTREAM,
1752                                 -1, (int)jitter[OSP_DIR_TX].min, (int)jitter[OSP_DIR_TX].max, value, jitter[OSP_DIR_TX].sdev);
1753                 }
1754                 if (rtt.value >= 0) {
1755                         value = rtt.value;
1756                 } else {
1757                         value = (int)rtt.avg;
1758                 }
1759                 OSPPTransactionSetRoundTripDelay(handle, -1, (int)rtt.min, (int)rtt.max, value, rtt.sdev);
1760
1761                 res = 1;
1762         }
1763
1764         return res;
1765 }
1766
1767 /*!
1768  * \brief OSP Finish function
1769  * \param handle OSP in/outbound transaction handle
1770  * \param recorded If failure reason has been recorded
1771  * \param cause Asterisk hangup cause
1772  * \param start Call start time
1773  * \param connect Call connect time
1774  * \param end Call end time
1775  * \param release Who release first, 0 source, 1 destination
1776  * \param inqos Inbound QoS string
1777  * \param outqos Outbound QoS string
1778  * \return 1 Success, 0 Failed, -1 Error
1779  */
1780 static int osp_finish(
1781         int handle,
1782         int recorded,
1783         int cause,
1784         time_t start,
1785         time_t connect,
1786         time_t end,
1787         unsigned int release,
1788         const char* inqos,
1789         const char* outqos)
1790 {
1791         int res;
1792         OSPEFAILREASON reason;
1793         time_t alert = 0;
1794         unsigned isPddInfoPresent = 0;
1795         unsigned pdd = 0;
1796         unsigned int dummy = 0;
1797         int error;
1798
1799         if (handle == OSP_INVALID_HANDLE) {
1800                 return 0;
1801         }
1802
1803         if (!recorded) {
1804                 reason = asterisk2osp(cause);
1805                 OSPPTransactionRecordFailure(handle, reason);
1806         }
1807
1808         osp_report_qos(handle, OSP_CALL_INBOUND, inqos);
1809         osp_report_qos(handle, OSP_CALL_OUTBOUND, outqos);
1810
1811         error = OSPPTransactionReportUsage(
1812                 handle,
1813                 difftime(end, connect),
1814                 start,
1815                 end,
1816                 alert,
1817                 connect,
1818                 isPddInfoPresent,
1819                 pdd,
1820                 release,
1821                 NULL,
1822                 -1,
1823                 -1,
1824                 -1,
1825                 -1,
1826                 &dummy,
1827                 NULL);
1828         if (error == OSPC_ERR_NO_ERROR) {
1829                 ast_debug(1, "OSP: Usage reported\n");
1830                 res = 1;
1831         } else {
1832                 ast_debug(1, "OSP: Unable to report usage, error '%d'\n", error);
1833                 res = -1;
1834         }
1835         OSPPTransactionDelete(handle);
1836
1837         return res;
1838 }
1839
1840 /* OSP Application APIs */
1841
1842 /*!
1843  * \brief OSP Application OSPAuth
1844  * \param chan Channel
1845  * \param data Parameter
1846  * \return 0 Success, -1 Failed
1847  */
1848 static int ospauth_exec(
1849         struct ast_channel *chan,
1850         const char *data)
1851 {
1852         int res;
1853         const char* provider = OSP_DEF_PROVIDER;
1854         struct varshead* headp;
1855         struct ast_var_t* current;
1856         const char* source = "";
1857         const char* token = "";
1858         int handle;
1859         unsigned int timelimit;
1860         char buffer[OSP_INTSTR_SIZE];
1861         const char* status;
1862         char* tmp;
1863
1864         AST_DECLARE_APP_ARGS(args,
1865                 AST_APP_ARG(provider);
1866                 AST_APP_ARG(options);
1867         );
1868
1869         if (!(tmp = ast_strdupa(data))) {
1870                 ast_log(LOG_ERROR, "Out of memory\n");
1871                 return -1;
1872         }
1873
1874         AST_STANDARD_APP_ARGS(args, tmp);
1875
1876         if (!ast_strlen_zero(args.provider)) {
1877                 provider = args.provider;
1878         }
1879         ast_debug(1, "OSPAuth: provider '%s'\n", provider);
1880
1881         headp = &chan->varshead;
1882         AST_LIST_TRAVERSE(headp, current, entries) {
1883                 if (!strcasecmp(ast_var_name(current), "OSPINPEERIP")) {
1884                         source = ast_var_value(current);
1885                 } else if (!strcasecmp(ast_var_name(current), "OSPINTOKEN")) {
1886                         token = ast_var_value(current);
1887                 }
1888         }
1889
1890         ast_debug(1, "OSPAuth: source '%s'\n", source);
1891         ast_debug(1, "OSPAuth: token size '%zd'\n", strlen(token));
1892
1893         if ((res = osp_auth(provider, &handle, source, chan->cid.cid_num, chan->exten, token, &timelimit)) > 0) {
1894                 status = AST_OSP_SUCCESS;
1895         } else {
1896                 timelimit = OSP_DEF_TIMELIMIT;
1897                 if (!res) {
1898                         status = AST_OSP_FAILED;
1899                 } else {
1900                         status = AST_OSP_ERROR;
1901                 }
1902         }
1903
1904         snprintf(buffer, sizeof(buffer), "%d", handle);
1905         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
1906         ast_debug(1, "OSPAuth: OSPINHANDLE '%s'\n", buffer);
1907         snprintf(buffer, sizeof(buffer), "%d", timelimit);
1908         pbx_builtin_setvar_helper(chan, "OSPINTIMELIMIT", buffer);
1909         ast_debug(1, "OSPAuth: OSPINTIMELIMIT '%s'\n", buffer);
1910         pbx_builtin_setvar_helper(chan, "OSPAUTHSTATUS", status);
1911         ast_debug(1, "OSPAuth: %s\n", status);
1912
1913         if(res <= 0) {
1914                 res = -1;
1915         } else {
1916                 res = 0;
1917         }
1918
1919         return res;
1920 }
1921
1922 /*!
1923  * \brief OSP Application OSPLookup
1924  * \param chan Channel
1925  * \param data Parameter
1926  * \return 0 Success, -1 Failed
1927  */
1928 static int osplookup_exec(
1929         struct ast_channel* chan,
1930         const char * data)
1931 {
1932         int res, cres;
1933         const char* provider = OSP_DEF_PROVIDER;
1934         unsigned int callidtypes = OSP_CALLID_UNDEFINED;
1935         struct varshead* headp;
1936         struct ast_var_t* current;
1937         const char* srcdev = "";
1938         const char* snetid = "";
1939         struct osp_npparam np;
1940         struct osp_diversion div;
1941         unsigned int i;
1942         const char* cinfo[OSP_MAX_CUSTOMINFO] = { NULL };
1943         char buffer[OSP_TOKSTR_SIZE];
1944         struct osp_results results;
1945         const char* status;
1946         char* tmp;
1947
1948         AST_DECLARE_APP_ARGS(args,
1949                 AST_APP_ARG(exten);
1950                 AST_APP_ARG(provider);
1951                 AST_APP_ARG(options);
1952         );
1953
1954         if (ast_strlen_zero(data)) {
1955                 ast_log(LOG_WARNING, "OSPLookup: Arg required, OSPLookup(exten[|provider[|options]])\n");
1956                 return -1;
1957         }
1958
1959         if (!(tmp = ast_strdupa(data))) {
1960                 ast_log(LOG_ERROR, "Out of memory\n");
1961                 return -1;
1962         }
1963
1964         AST_STANDARD_APP_ARGS(args, tmp);
1965
1966         ast_debug(1, "OSPLookup: exten '%s'\n", args.exten);
1967
1968         if (!ast_strlen_zero(args.provider)) {
1969                 provider = args.provider;
1970         }
1971         ast_debug(1, "OSPlookup: provider '%s'\n", provider);
1972
1973         if (args.options) {
1974                 if (strchr(args.options, 'h')) {
1975                         callidtypes |= OSP_CALLID_H323;
1976                 }
1977                 if (strchr(args.options, 's')) {
1978                         callidtypes |= OSP_CALLID_SIP;
1979                 }
1980                 if (strchr(args.options, 'i')) {
1981                         callidtypes |= OSP_CALLID_IAX;
1982                 }
1983         }
1984         ast_debug(1, "OSPLookup: call id types '%d'\n", callidtypes);
1985
1986         np.rn = "";
1987         np.cic = "";
1988         np.npdi = 0;
1989
1990         div.user = "";
1991         div.host = "";
1992
1993         results.inhandle = OSP_INVALID_HANDLE;
1994         results.intimelimit = OSP_DEF_TIMELIMIT;
1995
1996         headp = &chan->varshead;
1997         AST_LIST_TRAVERSE(headp, current, entries) {
1998                 if (!strcasecmp(ast_var_name(current), "OSPINPEERIP")) {
1999                         srcdev = ast_var_value(current);
2000                 } else if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
2001                         if (sscanf(ast_var_value(current), "%30d", &results.inhandle) != 1) {
2002                                 results.inhandle = OSP_INVALID_HANDLE;
2003                         }
2004                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
2005                         if (sscanf(ast_var_value(current), "%30d", &results.intimelimit) != 1) {
2006                                 results.intimelimit = OSP_DEF_TIMELIMIT;
2007                         }
2008                 } else if (!strcasecmp(ast_var_name(current), "OSPINNETWORKID")) {
2009                         snetid = ast_var_value(current);
2010                 } else if (!strcasecmp(ast_var_name(current), "OSPINNPRN")) {
2011                         np.rn = ast_var_value(current);
2012                 } else if (!strcasecmp(ast_var_name(current), "OSPINNPCIC")) {
2013                         np.cic = ast_var_value(current);
2014                 } else if (!strcasecmp(ast_var_name(current), "OSPINNPDI")) {
2015                         if (ast_true(ast_var_value(current))) {
2016                                 np.npdi = 1;
2017                         }
2018                 } else if (!strcasecmp(ast_var_name(current), "OSPINDIVUSER")) {
2019                         div.user = ast_var_value(current);
2020                 } else if (!strcasecmp(ast_var_name(current), "OSPINDIVHOST")) {
2021                         div.host = ast_var_value(current);
2022                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO1")) {
2023                         cinfo[0] = ast_var_value(current);
2024                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO2")) {
2025                         cinfo[1] = ast_var_value(current);
2026                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO3")) {
2027                         cinfo[2] = ast_var_value(current);
2028                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO4")) {
2029                         cinfo[3] = ast_var_value(current);
2030                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO5")) {
2031                         cinfo[4] = ast_var_value(current);
2032                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO6")) {
2033                         cinfo[5] = ast_var_value(current);
2034                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO7")) {
2035                         cinfo[6] = ast_var_value(current);
2036                 } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO8")) {
2037                         cinfo[7] = ast_var_value(current);
2038                 }
2039         }
2040         ast_debug(1, "OSPLookup: source device '%s'\n", srcdev);
2041         ast_debug(1, "OSPLookup: OSPINHANDLE '%d'\n", results.inhandle);
2042         ast_debug(1, "OSPLookup: OSPINTIMELIMIT '%d'\n", results.intimelimit);
2043         ast_debug(1, "OSPLookup: OSPINNETWORKID '%s'\n", snetid);
2044         ast_debug(1, "OSPLookup: OSPINNPRN '%s'\n", np.rn);
2045         ast_debug(1, "OSPLookup: OSPINNPCIC '%s'\n", np.cic);
2046         ast_debug(1, "OSPLookup: OSPINNPDI '%d'\n", np.npdi);
2047         ast_debug(1, "OSPLookup: OSPINDIVUSER '%s'\n", div.user);
2048         ast_debug(1, "OSPLookup: OSPINDIVHOST'%s'\n", div.host);
2049         for (i = 0; i < OSP_MAX_CUSTOMINFO; i++) {
2050                 if (!ast_strlen_zero(cinfo[i])) {
2051                         ast_debug(1, "OSPLookup: OSPINCUSTOMINFO%d '%s'\n", i, cinfo[i]);
2052                 }
2053         }
2054
2055         if ((cres = ast_autoservice_start(chan)) < 0) {
2056                 return -1;
2057         }
2058
2059         if ((res = osp_lookup(provider, callidtypes, srcdev, chan->cid.cid_num, args.exten, snetid, &np, &div, cinfo, &results)) > 0) {
2060                 status = AST_OSP_SUCCESS;
2061         } else {
2062                 results.tech[0] = '\0';
2063                 results.dest[0] = '\0';
2064                 results.calling[0] = '\0';
2065                 results.called[0] = '\0';
2066                 results.token[0] = '\0';
2067                 results.networkid[0] = '\0';
2068                 results.nprn[0] = '\0';
2069                 results.npcic[0] = '\0';
2070                 results.npdi = 0;
2071                 results.numresults = 0;
2072                 results.outtimelimit = OSP_DEF_TIMELIMIT;
2073                 results.outcallid.buf[0] = '\0';
2074                 results.outcallid.len = 0;
2075                 if (!res) {
2076                         status = AST_OSP_FAILED;
2077                 } else {
2078                         status = AST_OSP_ERROR;
2079                 }
2080         }
2081
2082         snprintf(buffer, sizeof(buffer), "%d", results.outhandle);
2083         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
2084         ast_debug(1, "OSPLookup: OSPOUTHANDLE '%s'\n", buffer);
2085         pbx_builtin_setvar_helper(chan, "OSPOUTTECH", results.tech);
2086         ast_debug(1, "OSPLookup: OSPOUTTECH '%s'\n", results.tech);
2087         pbx_builtin_setvar_helper(chan, "OSPDESTINATION", results.dest);
2088         ast_debug(1, "OSPLookup: OSPDESTINATION '%s'\n", results.dest);
2089         pbx_builtin_setvar_helper(chan, "OSPOUTCALLING", results.calling);
2090         ast_debug(1, "OSPLookup: OSPOUTCALLING '%s'\n", results.calling);
2091         pbx_builtin_setvar_helper(chan, "OSPOUTCALLED", results.called);
2092         ast_debug(1, "OSPLookup: OSPOUTCALLED '%s'\n", results.called);
2093         pbx_builtin_setvar_helper(chan, "OSPOUTNETWORKID", results.networkid);
2094         ast_debug(1, "OSPLookup: OSPOUTNETWORKID '%s'\n", results.networkid);
2095         pbx_builtin_setvar_helper(chan, "OSPOUTNPRN", results.nprn);
2096         ast_debug(1, "OSPLookup: OSPOUTNPRN '%s'\n", results.nprn);
2097         pbx_builtin_setvar_helper(chan, "OSPOUTNPCIC", results.npcic);
2098         ast_debug(1, "OSPLookup: OSPOUTNPCIC '%s'\n", results.npcic);
2099         snprintf(buffer, sizeof(buffer), "%d", results.npdi);
2100         pbx_builtin_setvar_helper(chan, "OSPOUTNPDI", buffer);
2101         ast_debug(1, "OSPLookup: OSPOUTNPDI'%s'\n", buffer);
2102         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", results.token);
2103         ast_debug(1, "OSPLookup: OSPOUTTOKEN size '%zd'\n", strlen(results.token));
2104         snprintf(buffer, sizeof(buffer), "%d", results.numresults);
2105         pbx_builtin_setvar_helper(chan, "OSPDESTREMAILS", buffer);
2106         ast_debug(1, "OSPLookup: OSPDESTREMAILS '%s'\n", buffer);
2107         snprintf(buffer, sizeof(buffer), "%d", results.outtimelimit);
2108         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
2109         ast_debug(1, "OSPLookup: OSPOUTTIMELIMIT '%s'\n", buffer);
2110         snprintf(buffer, sizeof(buffer), "%d", callidtypes);
2111         pbx_builtin_setvar_helper(chan, "OSPOUTCALLIDTYPES", buffer);
2112         ast_debug(1, "OSPLookup: OSPOUTCALLIDTYPES '%s'\n", buffer);
2113         pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", status);
2114         ast_debug(1, "OSPLookup: %s\n", status);
2115
2116         if (!strcasecmp(results.tech, OSP_TECH_SIP)) {
2117                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", results.tech, results.called, results.dest);
2118                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2119                 if (!ast_strlen_zero(results.token)) {
2120                         snprintf(buffer, sizeof(buffer), "%s%s", OSP_SIP_HEADER, results.token);
2121                         pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
2122                         ast_debug(1, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
2123                 }
2124         } else if (!strcasecmp(results.tech, OSP_TECH_H323)) {
2125                 if ((callidtypes & OSP_CALLID_H323) && (results.outcallid.len != 0)) {
2126                         osp_uuid2str(results.outcallid.buf, buffer, sizeof(buffer));
2127                 } else {
2128                         buffer[0] = '\0';
2129                 }
2130                 pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
2131                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", results.tech, results.called, results.dest);
2132                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2133         } else if (!strcasecmp(results.tech, OSP_TECH_IAX)) {
2134                 snprintf(buffer, sizeof(buffer), "%s/%s/%s", results.tech, results.dest, results.called);
2135                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2136         } else if (!strcasecmp(results.tech, OSP_TECH_SKYPE)) {
2137                 snprintf(buffer, sizeof(buffer), "%s/%s", results.tech, results.called);
2138                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2139         }
2140
2141         if ((cres = ast_autoservice_stop(chan)) < 0) {
2142                 return -1;
2143         }
2144
2145         if(res <= 0) {
2146                 res = -1;
2147         } else {
2148                 res = 0;
2149         }
2150
2151         return res;
2152 }
2153
2154 /*!
2155  * \brief OSP Application OSPNext
2156  * \param chan Channel
2157  * \param data Parameter
2158  * \return 0 Success, -1 Failed
2159  */
2160 static int ospnext_exec(
2161         struct ast_channel* chan,
2162         const char * data)
2163 {
2164         int res;
2165         const char* provider = OSP_DEF_PROVIDER;
2166         int cause = 0;
2167         struct varshead* headp;
2168         struct ast_var_t* current;
2169         struct osp_results results;
2170         char buffer[OSP_TOKSTR_SIZE];
2171         unsigned int callidtypes = OSP_CALLID_UNDEFINED;
2172         const char* status;
2173         char* tmp;
2174
2175         AST_DECLARE_APP_ARGS(args,
2176                 AST_APP_ARG(cause);
2177                 AST_APP_ARG(provider);
2178                 AST_APP_ARG(options);
2179         );
2180
2181         if (ast_strlen_zero(data)) {
2182                 ast_log(LOG_WARNING, "OSPNext: Arg required, OSPNext(cause[|provider[|options]])\n");
2183                 return -1;
2184         }
2185
2186         if (!(tmp = ast_strdupa(data))) {
2187                 ast_log(LOG_ERROR, "Out of memory\n");
2188                 return -1;
2189         }
2190
2191         AST_STANDARD_APP_ARGS(args, tmp);
2192
2193         if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%30d", &cause) != 1) {
2194                 cause = 0;
2195         }
2196         ast_debug(1, "OSPNext: cause '%d'\n", cause);
2197
2198         if (!ast_strlen_zero(args.provider)) {
2199                 provider = args.provider;
2200         }
2201         ast_debug(1, "OSPlookup: provider '%s'\n", provider);
2202
2203         results.inhandle = OSP_INVALID_HANDLE;
2204         results.outhandle = OSP_INVALID_HANDLE;
2205         results.intimelimit = OSP_DEF_TIMELIMIT;
2206         results.numresults = 0;
2207
2208         headp = &chan->varshead;
2209         AST_LIST_TRAVERSE(headp, current, entries) {
2210                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
2211                         if (sscanf(ast_var_value(current), "%30d", &results.inhandle) != 1) {
2212                                 results.inhandle = OSP_INVALID_HANDLE;
2213                         }
2214                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
2215                         if (sscanf(ast_var_value(current), "%30d", &results.outhandle) != 1) {
2216                                 results.outhandle = OSP_INVALID_HANDLE;
2217                         }
2218                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
2219                         if (sscanf(ast_var_value(current), "%30d", &results.intimelimit) != 1) {
2220                                 results.intimelimit = OSP_DEF_TIMELIMIT;
2221                         }
2222                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTCALLIDTYPES")) {
2223                         if (sscanf(ast_var_value(current), "%30d", &callidtypes) != 1) {
2224                                 callidtypes = OSP_CALLID_UNDEFINED;
2225                         }
2226                 } else if (!strcasecmp(ast_var_name(current), "OSPDESTREMAILS")) {
2227                         if (sscanf(ast_var_value(current), "%30d", &results.numresults) != 1) {
2228                                 results.numresults = 0;
2229                         }
2230                 }
2231         }
2232         ast_debug(1, "OSPNext: OSPINHANDLE '%d'\n", results.inhandle);
2233         ast_debug(1, "OSPNext: OSPOUTHANDLE '%d'\n", results.outhandle);
2234         ast_debug(1, "OSPNext: OSPINTIMELIMIT '%d'\n", results.intimelimit);
2235         ast_debug(1, "OSPNext: OSPOUTCALLIDTYPES '%d'\n", callidtypes);
2236         ast_debug(1, "OSPNext: OSPDESTREMAILS '%d'\n", results.numresults);
2237
2238         if ((res = osp_next(provider, cause, &results)) > 0) {
2239                 status = AST_OSP_SUCCESS;
2240         } else {
2241                 results.tech[0] = '\0';
2242                 results.dest[0] = '\0';
2243                 results.calling[0] = '\0';
2244                 results.called[0] = '\0';
2245                 results.token[0] = '\0';
2246                 results.networkid[0] = '\0';
2247                 results.nprn[0] = '\0';
2248                 results.npcic[0] = '\0';
2249                 results.npdi = 0;
2250                 results.numresults = 0;
2251                 results.outtimelimit = OSP_DEF_TIMELIMIT;
2252                 results.outcallid.buf[0] = '\0';
2253                 results.outcallid.len = 0;
2254                 if (!res) {
2255                         status = AST_OSP_FAILED;
2256                 } else {
2257                         status = AST_OSP_ERROR;
2258                 }
2259         }
2260
2261         pbx_builtin_setvar_helper(chan, "OSPOUTTECH", results.tech);
2262         ast_debug(1, "OSPNext: OSPOUTTECH '%s'\n", results.tech);
2263         pbx_builtin_setvar_helper(chan, "OSPDESTINATION", results.dest);
2264         ast_debug(1, "OSPNext: OSPDESTINATION '%s'\n", results.dest);
2265         pbx_builtin_setvar_helper(chan, "OSPOUTCALLING", results.calling);
2266         ast_debug(1, "OSPNext: OSPOUTCALLING '%s'\n", results.calling);
2267         pbx_builtin_setvar_helper(chan, "OSPOUTCALLED", results.called);
2268         ast_debug(1, "OSPNext: OSPOUTCALLED'%s'\n", results.called);
2269         pbx_builtin_setvar_helper(chan, "OSPOUTNETWORKID", results.networkid);
2270         ast_debug(1, "OSPLookup: OSPOUTNETWORKID '%s'\n", results.networkid);
2271         pbx_builtin_setvar_helper(chan, "OSPOUTNPRN", results.nprn);
2272         ast_debug(1, "OSPLookup: OSPOUTNPRN '%s'\n", results.nprn);
2273         pbx_builtin_setvar_helper(chan, "OSPOUTNPCIC", results.npcic);
2274         ast_debug(1, "OSPLookup: OSPOUTNPCIC '%s'\n", results.npcic);
2275         snprintf(buffer, sizeof(buffer), "%d", results.npdi);
2276         pbx_builtin_setvar_helper(chan, "OSPOUTNPDI", buffer);
2277         ast_debug(1, "OSPLookup: OSPOUTNPDI'%s'\n", buffer);
2278         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", results.token);
2279         ast_debug(1, "OSPNext: OSPOUTTOKEN size '%zd'\n", strlen(results.token));
2280         snprintf(buffer, sizeof(buffer), "%d", results.numresults);
2281         pbx_builtin_setvar_helper(chan, "OSPDESTREMAILS", buffer);
2282         ast_debug(1, "OSPNext: OSPDESTREMAILS '%s'\n", buffer);
2283         snprintf(buffer, sizeof(buffer), "%d", results.outtimelimit);
2284         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
2285         ast_debug(1, "OSPNext: OSPOUTTIMELIMIT '%s'\n", buffer);
2286         pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", status);
2287         ast_debug(1, "OSPNext: %s\n", status);
2288
2289         if (!strcasecmp(results.tech, OSP_TECH_SIP)) {
2290                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", results.tech, results.called, results.dest);
2291                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2292                 if (!ast_strlen_zero(results.token)) {
2293                         snprintf(buffer, sizeof(buffer), "%s%s", OSP_SIP_HEADER, results.token);
2294                         pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
2295                         ast_debug(1, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
2296                 }
2297         } else if (!strcasecmp(results.tech, OSP_TECH_H323)) {
2298                 if ((callidtypes & OSP_CALLID_H323) && (results.outcallid.len != 0)) {
2299                         osp_uuid2str(results.outcallid.buf, buffer, sizeof(buffer));
2300                 } else {
2301                         buffer[0] = '\0';
2302                 }
2303                 pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
2304                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", results.tech, results.called, results.dest);
2305                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2306         } else if (!strcasecmp(results.tech, OSP_TECH_IAX)) {
2307                 snprintf(buffer, sizeof(buffer), "%s/%s/%s", results.tech, results.dest, results.called);
2308                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2309         } else if (!strcasecmp(results.tech, OSP_TECH_SKYPE)) {
2310                 snprintf(buffer, sizeof(buffer), "%s/%s", results.tech, results.called);
2311                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
2312         }
2313
2314         if(res <= 0) {
2315                 res = -1;
2316         } else {
2317                 res = 0;
2318         }
2319
2320         return res;
2321 }
2322
2323 /*!
2324  * \brief OSP Application OSPFinish
2325  * \param chan Channel
2326  * \param data Parameter
2327  * \return 0 Success, -1 Failed
2328  */
2329 static int ospfinished_exec(
2330         struct ast_channel* chan,
2331         const char * data)
2332 {
2333         int res = 1;
2334         int cause = 0;
2335         struct varshead* headp;
2336         struct ast_var_t* current;
2337         int inhandle = OSP_INVALID_HANDLE;
2338         int outhandle = OSP_INVALID_HANDLE;
2339         int recorded = 0;
2340         time_t start, connect, end;
2341         unsigned int release;
2342         char buffer[OSP_INTSTR_SIZE];
2343         char inqos[OSP_QOSSTR_SIZE] = { 0 };
2344         char outqos[OSP_QOSSTR_SIZE] = { 0 };
2345         const char* status;
2346         char* tmp;
2347
2348         AST_DECLARE_APP_ARGS(args,
2349                 AST_APP_ARG(cause);
2350                 AST_APP_ARG(options);
2351         );
2352
2353         if (!(tmp = ast_strdupa(data))) {
2354                 ast_log(LOG_ERROR, "Out of memory\n");
2355                 return -1;
2356         }
2357
2358         AST_STANDARD_APP_ARGS(args, tmp);
2359
2360         headp = &chan->varshead;
2361         AST_LIST_TRAVERSE(headp, current, entries) {
2362                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
2363                         if (sscanf(ast_var_value(current), "%30d", &inhandle) != 1) {
2364                                 inhandle = OSP_INVALID_HANDLE;
2365                         }
2366                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
2367                         if (sscanf(ast_var_value(current), "%30d", &outhandle) != 1) {
2368                                 outhandle = OSP_INVALID_HANDLE;
2369                         }
2370                 } else if (!recorded &&
2371                         (!strcasecmp(ast_var_name(current), "OSPAUTHSTATUS") ||
2372                         !strcasecmp(ast_var_name(current), "OSPLOOKUPSTATUS") ||
2373                         !strcasecmp(ast_var_name(current), "OSPNEXTSTATUS")))
2374                 {
2375                         if (strcasecmp(ast_var_value(current), AST_OSP_SUCCESS)) {
2376                                 recorded = 1;
2377                         }
2378                 } else if (!strcasecmp(ast_var_name(current), "OSPINAUDIOQOS")) {
2379                         ast_copy_string(inqos, ast_var_value(current), sizeof(inqos));
2380                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTAUDIOQOS")) {
2381                         ast_copy_string(outqos, ast_var_value(current), sizeof(outqos));
2382                 }
2383         }
2384         ast_debug(1, "OSPFinish: OSPINHANDLE '%d'\n", inhandle);
2385         ast_debug(1, "OSPFinish: OSPOUTHANDLE '%d'\n", outhandle);
2386         ast_debug(1, "OSPFinish: recorded '%d'\n", recorded);
2387         ast_debug(1, "OSPFinish: OSPINAUDIOQOS '%s'\n", inqos);
2388         ast_debug(1, "OSPFinish: OSPOUTAUDIOQOS '%s'\n", outqos);
2389
2390         if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%30d", &cause) != 1) {
2391                 cause = 0;
2392         }
2393         ast_debug(1, "OSPFinish: cause '%d'\n", cause);
2394
2395         if (chan->cdr) {
2396                 start = chan->cdr->start.tv_sec;
2397                 connect = chan->cdr->answer.tv_sec;
2398                 if (connect) {
2399                         end = time(NULL);
2400                 } else {
2401                         end = connect;
2402                 }
2403         } else {
2404                 start = 0;
2405                 connect = 0;
2406                 end = 0;
2407         }
2408         ast_debug(1, "OSPFinish: start '%ld'\n", start);
2409         ast_debug(1, "OSPFinish: connect '%ld'\n", connect);
2410         ast_debug(1, "OSPFinish: end '%ld'\n", end);
2411
2412         release = ast_check_hangup(chan) ? 0 : 1;
2413
2414         if (osp_finish(outhandle, recorded, cause, start, connect, end, release, inqos, outqos) <= 0) {
2415                 ast_debug(1, "OSPFinish: Unable to report usage for outbound call\n");
2416         }
2417         switch (cause) {
2418         case AST_CAUSE_NORMAL_CLEARING:
2419                 break;
2420         default:
2421                 cause = AST_CAUSE_NO_ROUTE_DESTINATION;
2422                 break;
2423         }
2424         if (osp_finish(inhandle, recorded, cause, start, connect, end, release, inqos, outqos) <= 0) {
2425                 ast_debug(1, "OSPFinish: Unable to report usage for inbound call\n");
2426         }
2427         snprintf(buffer, sizeof(buffer), "%d", OSP_INVALID_HANDLE);
2428         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
2429         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
2430
2431         if (res > 0) {
2432                 status = AST_OSP_SUCCESS;
2433         } else if (!res) {
2434                 status = AST_OSP_FAILED;
2435         } else {
2436                 status = AST_OSP_ERROR;
2437         }
2438         pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", status);
2439
2440         if(!res) {
2441                 res = -1;
2442         } else {
2443                 res = 0;
2444         }
2445
2446         return res;
2447 }
2448
2449 /* OSP Module APIs */
2450
2451 static int osp_unload(void);
2452 static int osp_load(int reload)
2453 {
2454         const char* t;
2455         unsigned int v;
2456         struct ast_config* cfg;
2457         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
2458         int error = OSPC_ERR_NO_ERROR;
2459
2460         if ((cfg = ast_config_load(OSP_CONFIG_FILE, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
2461                 return 0;
2462         } else if (cfg == CONFIG_STATUS_FILEINVALID) {
2463                 ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", OSP_CONFIG_FILE);
2464                 return 0;
2465         }
2466
2467         if (cfg) {
2468                 if (reload)
2469                         osp_unload();
2470
2471                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "accelerate");
2472                 if (t && ast_true(t)) {
2473                         if ((error = OSPPInit(1)) != OSPC_ERR_NO_ERROR) {
2474                                 ast_log(LOG_WARNING, "OSP: Unable to enable hardware accelleration\n");
2475                                 OSPPInit(0);
2476                         } else {
2477                                 osp_hardware = 1;
2478                         }
2479                 } else {
2480                         OSPPInit(0);
2481                 }
2482                 ast_debug(1, "OSP: osp_hardware '%d'\n", osp_hardware);
2483
2484                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "securityfeatures");
2485                 if (t && ast_true(t)) {
2486                         osp_security = 1;
2487                 }
2488                 ast_debug(1, "OSP: osp_security '%d'\n", osp_security);
2489
2490                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat");
2491                 if (t) {
2492                         if ((sscanf(t, "%30d", &v) == 1) &&
2493                                 ((v == TOKEN_ALGO_SIGNED) || (v == TOKEN_ALGO_UNSIGNED) || (v == TOKEN_ALGO_BOTH)))
2494                         {
2495                                 osp_tokenformat = v;
2496                         } else {
2497                                 ast_log(LOG_WARNING, "tokenformat should be an integer from %d, %d or %d, not '%s'\n",
2498                                         TOKEN_ALGO_SIGNED, TOKEN_ALGO_UNSIGNED, TOKEN_ALGO_BOTH, t);
2499                         }
2500                 }
2501                 ast_debug(1, "OSP: osp_tokenformat '%d'\n", osp_tokenformat);
2502
2503                 t = ast_category_browse(cfg, NULL);
2504                 while(t) {
2505                         if (strcasecmp(t, OSP_GENERAL_CAT)) {
2506                                 osp_create_provider(cfg, t);
2507                         }
2508                         t = ast_category_browse(cfg, t);
2509                 }
2510
2511                 osp_initialized = 1;
2512
2513                 ast_config_destroy(cfg);
2514         } else {
2515                 ast_log(LOG_WARNING, "OSP: Unable to find configuration. OSP support disabled\n");
2516                 return 0;
2517         }
2518         ast_debug(1, "OSP: osp_initialized '%d'\n", osp_initialized);
2519
2520         return 1;
2521 }
2522
2523 static int osp_unload(void)
2524 {
2525         struct osp_provider* p;
2526         struct osp_provider* next;
2527
2528         if (osp_initialized) {
2529                 ast_mutex_lock(&osplock);
2530                 p = ospproviders;
2531                 while(p) {
2532                         next = p->next;
2533                         OSPPProviderDelete(p->handle, 0);
2534                         ast_free(p);
2535                         p = next;
2536                 }
2537                 ospproviders = NULL;
2538                 ast_mutex_unlock(&osplock);
2539
2540                 OSPPCleanup();
2541
2542                 osp_tokenformat = TOKEN_ALGO_SIGNED;
2543                 osp_security = 0;
2544                 osp_hardware = 0;
2545                 osp_initialized = 0;
2546         }
2547         return 0;
2548 }
2549
2550 static char *handle_cli_osp_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2551 {
2552         int i;
2553         int found = 0;
2554         struct osp_provider* p;
2555         const char* provider = NULL;
2556         const char* tokenalgo;
2557
2558         switch (cmd) {
2559         case CLI_INIT:
2560                 e->command = "osp show";
2561                 e->usage =
2562                         "Usage: osp show\n"
2563                         "       Displays information on Open Settlement Protocol support\n";
2564                 return NULL;
2565         case CLI_GENERATE:
2566                 return NULL;
2567         }
2568
2569         if ((a->argc < 2) || (a->argc > 3))
2570                 return CLI_SHOWUSAGE;
2571         if (a->argc > 2)
2572                 provider = a->argv[2];
2573         if (!provider) {
2574                 switch (osp_tokenformat) {
2575                 case TOKEN_ALGO_BOTH:
2576                         tokenalgo = "Both";
2577                         break;
2578                 case TOKEN_ALGO_UNSIGNED:
2579                         tokenalgo = "Unsigned";
2580                         break;
2581                 case TOKEN_ALGO_SIGNED:
2582                 default:
2583                         tokenalgo = "Signed";
2584                         break;
2585                 }
2586                 ast_cli(a->fd, "OSP: %s/%s/%s/%s\n",
2587                         osp_initialized ? "Initialized" : "Uninitialized",
2588                         osp_hardware ? "Accelerated" : "Normal",
2589                         osp_security ? "Enabled" : "Disabled",
2590                         tokenalgo);
2591         }
2592
2593         ast_mutex_lock(&osplock);
2594         p = ospproviders;
2595         while(p) {
2596                 if (!provider || !strcasecmp(p->name, provider)) {
2597                         if (found) {
2598                                 ast_cli(a->fd, "\n");
2599                         }
2600                         ast_cli(a->fd, " == OSP Provider '%s' == \n", p->name);
2601                         if (osp_security) {
2602                                 ast_cli(a->fd, "Local Private Key: %s\n", p->privatekey);
2603                                 ast_cli(a->fd, "Local Certificate: %s\n", p->localcert);
2604                                 for (i = 0; i < p->cacount; i++) {
2605                                         ast_cli(a->fd, "CA Certificate %d:  %s\n", i + 1, p->cacerts[i]);
2606                                 }
2607                         }
2608                         for (i = 0; i < p->spcount; i++) {
2609                                 ast_cli(a->fd, "Service Point %d:   %s\n", i + 1, p->srvpoints[i]);
2610                         }
2611                         ast_cli(a->fd, "Max Connections:   %d\n", p->maxconnections);
2612                         ast_cli(a->fd, "Retry Delay:       %d seconds\n", p->retrydelay);
2613                         ast_cli(a->fd, "Retry Limit:       %d\n", p->retrylimit);
2614                         ast_cli(a->fd, "Timeout:           %d milliseconds\n", p->timeout);
2615                         ast_cli(a->fd, "Source:            %s\n", strlen(p->source) ? p->source : "<unspecified>");
2616                         ast_cli(a->fd, "Auth Policy        %d\n", p->authpolicy);
2617                         ast_cli(a->fd, "Default protocol   %s\n", p->defaultprotocol);
2618                         ast_cli(a->fd, "OSP Handle:        %d\n", p->handle);
2619                         found++;
2620                 }
2621                 p = p->next;
2622         }
2623         ast_mutex_unlock(&osplock);
2624
2625         if (!found) {
2626                 if (provider) {
2627                         ast_cli(a->fd, "Unable to find OSP provider '%s'\n", provider);
2628                 } else {
2629                         ast_cli(a->fd, "No OSP providers configured\n");
2630                 }
2631         }
2632         return CLI_SUCCESS;
2633 }
2634
2635 /* OSPAuth() dialplan application */
2636 static const char app1[] = "OSPAuth";
2637
2638 /* OSPLookup() dialplan application */
2639 static const char app2[] = "OSPLookup";
2640
2641 /* OSPNext() dialplan application */
2642 static const char app3[] = "OSPNext";
2643
2644 /* OSPFinish() dialplan application */
2645 static const char app4[] = "OSPFinish";
2646
2647 static struct ast_cli_entry cli_osp[] = {
2648         AST_CLI_DEFINE(handle_cli_osp_show, "Displays OSF information")
2649 };
2650
2651 static int load_module(void)
2652 {
2653         int res;
2654
2655         if (!osp_load(0))
2656                 return AST_MODULE_LOAD_DECLINE;
2657
2658         ast_cli_register_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
2659         res = ast_register_application_xml(app1, ospauth_exec);
2660         res |= ast_register_application_xml(app2, osplookup_exec);
2661         res |= ast_register_application_xml(app3, ospnext_exec);
2662         res |= ast_register_application_xml(app4, ospfinished_exec);
2663
2664         return res;
2665 }
2666
2667 static int unload_module(void)
2668 {
2669         int res;
2670
2671         res = ast_unregister_application(app4);
2672         res |= ast_unregister_application(app3);
2673         res |= ast_unregister_application(app2);
2674         res |= ast_unregister_application(app1);
2675         ast_cli_unregister_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
2676         osp_unload();
2677
2678         return res;
2679 }
2680
2681 static int reload(void)
2682 {
2683         osp_load(1);
2684
2685         return 0;
2686 }
2687
2688 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Open Settlement Protocol Applications",
2689         .load = load_module,
2690         .unload = unload_module,
2691         .reload = reload,
2692 );