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