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