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