04da14072cbbd21736704fe7244dfd83df9d8999
[asterisk/asterisk.git] / apps / app_osplookup.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*!
20  * \file
21  * \brief Open Settlement Protocol (OSP) Applications
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \extref The OSP Toolkit: http://www.transnexus.com
26  * \extref OpenSSL http://www.openssl.org
27  *
28  * \ingroup applications
29  */
30
31 /*** MODULEINFO
32         <depend>osptk</depend>
33         <depend>openssl</depend>
34  ***/
35
36 #include "asterisk.h"
37
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39
40 #include <osp/osp.h>
41 #include <osp/osputils.h>
42 #include <osp/ospb64.h>
43
44 #include "asterisk/paths.h"
45 #include "asterisk/lock.h"
46 #include "asterisk/config.h"
47 #include "asterisk/utils.h"
48 #include "asterisk/causes.h"
49 #include "asterisk/channel.h"
50 #include "asterisk/app.h"
51 #include "asterisk/module.h"
52 #include "asterisk/pbx.h"
53 #include "asterisk/cli.h"
54 #include "asterisk/astosp.h"
55
56 /*** DOCUMENTATION
57         <application name="OSPAuth" language="en_US">
58                 <synopsis>
59                         OSP Authentication.
60                 </synopsis>
61                 <syntax>
62                         <parameter name="provider" />
63                         <parameter name="options" />
64                 </syntax>
65                 <description>
66                         <para>Authenticate a SIP INVITE by OSP and sets the variables:</para>
67                         <variablelist>
68                                 <variable name="OSPINHANDLE">
69                                         <para>The inbound call transaction handle.</para>
70                                 </variable>
71                                 <variable name="OSPINTIMELIMIT">
72                                         <para>The inbound call duration limit in seconds.</para>
73                                 </variable>
74                         </variablelist>
75                         <para>This application sets the following channel variable upon completion:</para>
76                         <variablelist>
77                                 <variable name="OSPAUTHSTATUS">
78                                         <para>The status of the OSP Auth attempt as a text string, one of</para>
79                                         <value name="SUCCESS" />
80                                         <value name="FAILED" />
81                                         <value name="ERROR" />
82                                 </variable>
83                         </variablelist>
84                 </description>
85         </application>
86         <application name="OSPLookup" language="en_US">
87                 <synopsis>
88                         Lookup destination by OSP.
89                 </synopsis>
90                 <syntax>
91                         <parameter name="exten" required="true" />
92                         <parameter name="provider" />
93                         <parameter name="options">
94                                 <enumlist>
95                                         <enum name="h">
96                                                 <para>generate H323 call id for the outbound call</para>
97                                         </enum>
98                                         <enum name="s">
99                                                 <para>generate SIP call id for the outbound call.
100                                                 Have not been implemented</para>
101                                         </enum>
102                                         <enum name="i">
103                                                 <para>generate IAX call id for the outbound call.
104                                                 Have not been implemented</para>
105                                         </enum>
106                                 </enumlist>
107                         </parameter>
108                 </syntax>
109                 <description>
110                         <para>Looks up an extension via OSP and sets the variables, where <literal>n</literal> is the
111                         number of the result beginning with <literal>1</literal>:</para>
112                         <variablelist>
113                                 <variable name="OSPOUTHANDLE">
114                                         <para>The OSP Handle for anything remaining.</para>
115                                 </variable>
116                                 <variable name="OSPTECH">
117                                         <para>The technology to use for the call.</para>
118                                 </variable>
119                                 <variable name="OSPDEST">
120                                         <para>The destination to use for the call.</para>
121                                 </variable>
122                                 <variable name="OSPCALLED">
123                                         <para>The called number to use for the call.</para>
124                                 </variable>
125                                 <variable name="OSPCALLING">
126                                         <para>The calling number to use for the call.</para>
127                                 </variable>
128                                 <variable name="OSPDIALSTR">
129                                         <para>The dial command string.</para>
130                                 </variable>
131                                 <variable name="OSPOUTTOKEN">
132                                         <para>The actual OSP token as a string.</para>
133                                 </variable>
134                                 <variable name="OSPOUTTIMELIMIT">
135                                         <para>The outbound call duraction limit in seconds.</para>
136                                 </variable>
137                                 <variable name="OSPOUTCALLIDTYPES">
138                                         <para>The outbound call id types.</para>
139                                 </variable>
140                                 <variable name="OSPOUTCALLID">
141                                         <para>The outbound call id.</para>
142                                 </variable>
143                                 <variable name="OSPRESULTS">
144                                         <para>The number of OSP results total remaining.</para>
145                                 </variable>
146                         </variablelist>
147                         <variablelist>
148                                 <variable name="OSPLOOKUPSTATUS">
149                                         <para>This application sets the following channel variable upon completion:</para>
150                                         <value name="SUCCESS" />
151                                         <value name="FAILED" />
152                                         <value name="ERROR" />
153                                 </variable>
154                         </variablelist>
155                 </description>
156         </application>
157         <application name="OSPNext" language="en_US">
158                 <synopsis>
159                         Lookup next destination by OSP.
160                 </synopsis>
161                 <syntax>
162                         <parameter name="cause" required="true" />
163                         <parameter name="provider" />
164                         <parameter name="options" />
165                 </syntax>
166                 <description>
167                         <para>Looks up the next OSP Destination for <variable>OSPOUTHANDLE</variable>.</para>
168                         <para>This application sets the following channel variable upon completion:</para>
169                         <variablelist>
170                                 <variable name="OSPNEXTSTATUS">
171                                         <para>The status of the OSP Next attempt as a text string, one of</para>
172                                         <value name="SUCCESS" />
173                                         <value name="FAILED" />
174                                         <value name="ERROR" />
175                                 </variable>
176                         </variablelist>
177                 </description>
178                 <see-also>
179                         <ref type="application">OSPLookup</ref>
180                 </see-also>
181         </application>
182         <application name="OSPFinish" language="en_US">
183                 <synopsis>
184                         Record OSP entry.
185                 </synopsis>
186                 <syntax>
187                         <parameter name="status" />
188                         <parameter name="options" />
189                 </syntax>
190                 <description>
191                         <para>Records call state for <variable>OSPINHANDLE</variable>, according to status, which should
192                         be one of <literal>BUSY</literal>, <literal>CONGESTION</literal>, <literal>ANSWER</literal>,
193                         <literal>NOANSWER</literal>, or <literal>CHANUNAVAIL</literal> or coincidentally, just what the
194                         Dial application stores in its <variable>DIALSTATUS</variable>.</para>
195                         <para>This application sets the following channel variable upon completion:</para>
196                         <variablelist>
197                                 <variable name="OSPFINISHSTATUS">
198                                         <para>The status of the OSP Finish attempt as a text string, one of</para>
199                                         <value name="SUCCESS" />
200                                         <value name="FAILED" />
201                                         <value name="ERROR" />
202                                 </variable>
203                         </variablelist>
204                 </description>
205         </application>
206  ***/
207
208 /* OSP Buffer Sizes */
209 #define OSP_INTSTR_SIZE         ((unsigned int)16)              /* OSP signed/unsigned int string buffer size */
210 #define OSP_NORSTR_SIZE         ((unsigned int)256)             /* OSP normal string buffer size */
211 #define OSP_KEYSTR_SIZE         ((unsigned int)1024)    /* OSP certificate string buffer size */
212 #define OSP_TOKSTR_SIZE         ((unsigned int)4096)    /* OSP token string buffer size */
213 #define OSP_TECHSTR_SIZE        ((unsigned int)32)              /* OSP signed/unsigned int string buffer size */
214 #define OSP_UUID_SIZE           ((unsigned int)16)              /* UUID size */
215 #define OSP_UUIDSTR_SIZE        ((unsigned int)36)              /* UUID string size */
216
217 /* OSP Authentication Policy */
218 enum osp_authpolicy {
219         OSP_AUTH_NO,            /* Accept any call */
220         OSP_AUTH_YES,           /* Accept call with valid OSP token or without OSP token */
221         OSP_AUTH_EXCLUSIVE      /* Only accept call with valid OSP token */
222 };
223
224 /* Call ID type*/
225 #define OSP_CALLID_UNDEFINED    ((unsigned int)0)                       /* UNDEFINED */
226 #define OSP_CALLID_H323                 ((unsigned int)(1 << 0))        /* H.323 */
227 #define OSP_CALLID_SIP                  ((unsigned int)(1 << 1))        /* SIP */
228 #define OSP_CALLID_IAX                  ((unsigned int)(1 << 2))        /* IAX2 */
229 #define OSP_CALLID_MAXNUM               ((unsigned int)3)                       /* Max number of call ID type */
230
231 /* OSP Supported Destination Protocols */
232 #define OSP_PROT_H323                   ((char*)"H323")                         /* H323 Q931 protocol name*/
233 #define OSP_PROT_SIP                    ((char*)"SIP")                          /* SIP protocol name */
234 #define OSP_PROT_IAX                    ((char*)"IAX")                          /* IAX protocol name */
235 #define OSP_PROT_OTHER                  ((char*)"OTHER")                        /* Other protocol name */
236
237 /* OSP supported Destination Tech */
238 #if 0
239 #define OSP_TECH_H323                   ((char*)"OOH323")                       /* OOH323 tech name */
240 #endif
241 #define OSP_TECH_H323                   ((char*)"H323")                         /* OH323 tech name */
242 #define OSP_TECH_SIP                    ((char*)"SIP")                          /* SIP tech name */
243 #define OSP_TECH_IAX                    ((char*)"IAX2")                         /* IAX2 tech name */
244
245 /* SIP OSP header field name */
246 #define OSP_SIP_HEADER                  ((char*)"P-OSP-Auth-Token: ")
247
248 /* OSP Constants */
249 #define OSP_INVALID_HANDLE              ((int)-1)                                       /* Invalid OSP handle, provider, transaction etc. */
250 #define OSP_CONFIG_FILE                 ((const char*)"osp.conf")       /* OSP configuration file name */
251 #define OSP_GENERAL_CAT                 ((const char*)"general")        /* OSP global configuration context name */
252 #define OSP_DEF_PROVIDER                ((const char*)"default")        /* OSP default provider context name */
253 #define OSP_MAX_CERTS                   ((unsigned int)10)                      /* OSP max number of cacerts */
254 #define OSP_MAX_SRVS                    ((unsigned int)10)                      /* OSP max number of service points */
255 #define OSP_DEF_MAXCONNECTIONS  ((unsigned int)20)                      /* OSP default max_connections */
256 #define OSP_MIN_MAXCONNECTIONS  ((unsigned int)1)                       /* OSP min max_connections */
257 #define OSP_MAX_MAXCONNECTIONS  ((unsigned int)1000)            /* OSP max max_connections */
258 #define OSP_DEF_RETRYDELAY              ((unsigned int)0)                       /* OSP default retry delay */
259 #define OSP_MIN_RETRYDELAY              ((unsigned int)0)                       /* OSP min retry delay */
260 #define OSP_MAX_RETRYDELAY              ((unsigned int)10)                      /* OSP max retry delay */
261 #define OSP_DEF_RETRYLIMIT              ((unsigned int)2)                       /* OSP default retry times */
262 #define OSP_MIN_RETRYLIMIT              ((unsigned int)0)                       /* OSP min retry times */
263 #define OSP_MAX_RETRYLIMIT              ((unsigned int)100)                     /* OSP max retry times */
264 #define OSP_DEF_TIMEOUT                 ((unsigned int)500)                     /* OSP default timeout in ms */
265 #define OSP_MIN_TIMEOUT                 ((unsigned int)200)                     /* OSP min timeout in ms */
266 #define OSP_MAX_TIMEOUT                 ((unsigned int)10000)           /* OSP max timeout in ms */
267 #define OSP_DEF_AUTHPOLICY              ((enum osp_authpolicy)OSP_AUTH_YES)
268 #define OSP_AUDIT_URL                   ((const char*)"localhost")      /* OSP default Audit URL */
269 #define OSP_LOCAL_VALIDATION    ((int)1)                                        /* Validate OSP token locally */
270 #define OSP_SSL_LIFETIME                ((unsigned int)300)                     /* SSL life time, in seconds */
271 #define OSP_HTTP_PERSISTENCE    ((int)1)                                        /* In seconds */
272 #define OSP_CUSTOMER_ID                 ((const char*)"")                       /* OSP customer ID */
273 #define OSP_DEVICE_ID                   ((const char*)"")                       /* OSP device ID */
274 #define OSP_DEF_DESTINATIONS    ((unsigned int)5)                       /* OSP default max number of destinations */
275 #define OSP_DEF_TIMELIMIT               ((unsigned int)0)                       /* OSP default duration limit, no limit */
276 #define OSP_DEF_PROTOCOL                OSP_PROT_SIP                            /* OSP default destination protocol, SIP */
277
278 /* OSP Provider */
279 struct osp_provider {
280         char name[OSP_NORSTR_SIZE];                                             /* OSP provider context name */
281         char privatekey[OSP_NORSTR_SIZE];                               /* OSP private key file name */
282         char localcert[OSP_NORSTR_SIZE];                                /* OSP local cert file name */
283         unsigned int cacount;                                                   /* Number of cacerts */
284         char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE];   /* Cacert file names */
285         unsigned int spcount;                                                   /* Number of service points */
286         char srvpoints[OSP_MAX_SRVS][OSP_NORSTR_SIZE];  /* Service point URLs */
287         int maxconnections;                                                             /* Max number of connections */
288         int retrydelay;                                                                 /* Retry delay */
289         int retrylimit;                                                                 /* Retry limit */
290         int timeout;                                                                    /* Timeout in ms */
291         char source[OSP_NORSTR_SIZE];                                   /* IP of self */
292         enum osp_authpolicy authpolicy;                                 /* OSP authentication policy */
293         char* defaultprotocol;                                                  /* OSP default destination protocol */
294         OSPTPROVHANDLE handle;                                                  /* OSP provider handle */
295         struct osp_provider* next;                                              /* Pointer to next OSP provider */
296 };
297
298 /* Call ID */
299 struct osp_callid {
300         unsigned char buf[OSPC_CALLID_MAXSIZE];         /* Call ID string */
301         unsigned int len;                                                       /* Call ID length */
302 };
303
304 /* OSP Application In/Output Results */
305 struct osp_result {
306         int inhandle;                                           /* Inbound transaction handle */
307         int outhandle;                                          /* Outbound transaction handle */
308         unsigned int intimelimit;                       /* Inbound duration limit */
309         unsigned int outtimelimit;                      /* Outbound duration limit */
310         char tech[OSP_TECHSTR_SIZE];            /* Outbound Asterisk TECH string */
311         char dest[OSP_NORSTR_SIZE];                     /* Outbound destination IP address */
312         char called[OSP_NORSTR_SIZE];           /* Outbound called number, may be translated */
313         char calling[OSP_NORSTR_SIZE];          /* Outbound calling number, may be translated */
314         char token[OSP_TOKSTR_SIZE];            /* Outbound OSP token */
315         char networkid[OSP_NORSTR_SIZE];        /* Outbound network ID */
316         unsigned int numresults;                        /* Number of remain outbound destinations */
317         struct osp_callid outcallid;            /* Outbound call ID */
318 };
319
320 /* OSP Module Global Variables */
321 AST_MUTEX_DEFINE_STATIC(osplock);                                                       /* Lock of OSP provider list */
322 static int osp_initialized = 0;                                                         /* Init flag */
323 static int osp_hardware = 0;                                                            /* Hardware accelleration flag */
324 static int osp_security = 0;                                                            /* Using security features flag */
325 static struct osp_provider* ospproviders = NULL;                        /* OSP provider list */
326 static unsigned int osp_tokenformat = TOKEN_ALGO_SIGNED;        /* Token format supported */
327
328 /* OSP default certificates */
329 const char* B64PKey = "MIIBOgIBAAJBAK8t5l+PUbTC4lvwlNxV5lpl+2dwSZGW46dowTe6y133XyVEwNiiRma2YNk3xKs/TJ3Wl9Wpns2SYEAJsFfSTukCAwEAAQJAPz13vCm2GmZ8Zyp74usTxLCqSJZNyMRLHQWBM0g44Iuy4wE3vpi7Wq+xYuSOH2mu4OddnxswCP4QhaXVQavTAQIhAOBVCKXtppEw9UaOBL4vW0Ed/6EA/1D8hDW6St0h7EXJAiEAx+iRmZKhJD6VT84dtX5ZYNVk3j3dAcIOovpzUj9a0CECIEduTCapmZQ5xqAEsLXuVlxRtQgLTUD4ZxDElPn8x0MhAiBE2HlcND0+qDbvtwJQQOUzDgqg5xk3w8capboVdzAlQQIhAMC+lDL7+gDYkNAft5Mu+NObJmQs4Cr+DkDFsKqoxqrm";
330 const char* B64LCert = "MIIBeTCCASMCEHqkOHVRRWr+1COq3CR/xsowDQYJKoZIhvcNAQEEBQAwOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMB4XDTA1MDYyMzAwMjkxOFoXDTA2MDYyNDAwMjkxOFowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCvLeZfj1G0wuJb8JTcVeZaZftncEmRluOnaME3ustd918lRMDYokZmtmDZN8SrP0yd1pfVqZ7NkmBACbBX0k7pAgMBAAEwDQYJKoZIhvcNAQEEBQADQQDnV8QNFVVJx/+7IselU0wsepqMurivXZzuxOmTEmTVDzCJx1xhA8jd3vGAj7XDIYiPub1PV23eY5a2ARJuw5w9";
331 const char* B64CACert = "MIIBYDCCAQoCAQEwDQYJKoZIhvcNAQEEBQAwOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMB4XDTAyMDIwNDE4MjU1MloXDTEyMDIwMzE4MjU1MlowOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPGeGwV41EIhX0jEDFLRXQhDEr50OUQPq+f55VwQd0TQNts06BP29+UiNdRW3c3IRHdZcJdC1Cg68ME9cgeq0h8CAwEAATANBgkqhkiG9w0BAQQFAANBAGkzBSj1EnnmUxbaiG1N4xjIuLAWydun7o3bFk2tV8dBIhnuh445obYyk1EnQ27kI7eACCILBZqi2MHDOIMnoN0=";
332
333 /* OSP Client Wrapper APIs */
334
335 /*!
336  * \brief Create OSP provider handle according to configuration
337  * \param cfg OSP configuration
338  * \param provider OSP provider context name
339  * \return 1 Success, 0 Failed, -1 Error
340  */
341 static int osp_create_provider(
342         struct ast_config* cfg,
343         const char* provider)
344 {
345         int res = 0;
346         struct ast_variable* v;
347         struct osp_provider* p;
348         OSPTPRIVATEKEY privatekey;
349         OSPT_CERT localcert;
350         OSPT_CERT cacerts[OSP_MAX_CERTS];
351         const OSPT_CERT* pcacerts[OSP_MAX_CERTS];
352         const char* psrvpoints[OSP_MAX_SRVS];
353         unsigned char privatekeydata[OSP_KEYSTR_SIZE];
354         unsigned char localcertdata[OSP_KEYSTR_SIZE];
355         unsigned char cacertdata[OSP_KEYSTR_SIZE];
356         int i, t, error = OSPC_ERR_NO_ERROR;
357
358         if (!(p = ast_calloc(1, sizeof(*p)))) {
359                 ast_log(LOG_ERROR, "Out of memory\n");
360                 return -1;
361         }
362
363         /* ast_calloc has set 0 in p */
364         ast_copy_string(p->name, provider, sizeof(p->name));
365         snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, provider);
366         snprintf(p->localcert, sizeof(p->localcert), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, provider);
367         snprintf(p->cacerts[0], sizeof(p->cacerts[0]), "%s/%s-cacert_0.pem", ast_config_AST_KEY_DIR, provider);
368         p->maxconnections = OSP_DEF_MAXCONNECTIONS;
369         p->retrydelay = OSP_DEF_RETRYDELAY;
370         p->retrylimit = OSP_DEF_RETRYLIMIT;
371         p->timeout = OSP_DEF_TIMEOUT;
372         p->authpolicy = OSP_DEF_AUTHPOLICY;
373         p->defaultprotocol = OSP_DEF_PROTOCOL;
374         p->handle = OSP_INVALID_HANDLE;
375
376         v = ast_variable_browse(cfg, provider);
377         while(v) {
378                 if (!strcasecmp(v->name, "privatekey")) {
379                         if (osp_security) {
380                                 if (v->value[0] == '/') {
381                                         ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey));
382                                 } else {
383                                         snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value);
384                                 }
385                                 ast_debug(1, "OSP: privatekey '%s'\n", p->privatekey);
386                         }
387                 } else if (!strcasecmp(v->name, "localcert")) {
388                         if (osp_security) {
389                                 if (v->value[0] == '/') {
390                                         ast_copy_string(p->localcert, v->value, sizeof(p->localcert));
391                                 } else {
392                                         snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
393                                 }
394                                 ast_debug(1, "OSP: localcert '%s'\n", p->localcert);
395                         }
396                 } else if (!strcasecmp(v->name, "cacert")) {
397                         if (osp_security) {
398                                 if (p->cacount < OSP_MAX_CERTS) {
399                                         if (v->value[0] == '/') {
400                                                 ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0]));
401                                         } else {
402                                                 snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
403                                         }
404                                         ast_debug(1, "OSP: cacerts[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
405                                         p->cacount++;
406                                 } else {
407                                         ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno);
408                                 }
409                         }
410                 } else if (!strcasecmp(v->name, "servicepoint")) {
411                         if (p->spcount < OSP_MAX_SRVS) {
412                                 ast_copy_string(p->srvpoints[p->spcount], v->value, sizeof(p->srvpoints[0]));
413                                 ast_debug(1, "OSP: servicepoint[%d]: '%s'\n", p->spcount, p->srvpoints[p->spcount]);
414                                 p->spcount++;
415                         } else {
416                                 ast_log(LOG_WARNING, "OSP: Too many Service Points at line %d\n", v->lineno);
417                         }
418                 } else if (!strcasecmp(v->name, "maxconnections")) {
419                         if ((sscanf(v->value, "%30d", &t) == 1) && (t >= OSP_MIN_MAXCONNECTIONS) && (t <= OSP_MAX_MAXCONNECTIONS)) {
420                                 p->maxconnections = t;
421                                 ast_debug(1, "OSP: maxconnections '%d'\n", t);
422                         } else {
423                                 ast_log(LOG_WARNING, "OSP: maxconnections should be an integer from %d to %d, not '%s' at line %d\n",
424                                         OSP_MIN_MAXCONNECTIONS, OSP_MAX_MAXCONNECTIONS, v->value, v->lineno);
425                         }
426                 } else if (!strcasecmp(v->name, "retrydelay")) {
427                         if ((sscanf(v->value, "%30d", &t) == 1) && (t >= OSP_MIN_RETRYDELAY) && (t <= OSP_MAX_RETRYDELAY)) {
428                                 p->retrydelay = t;
429                                 ast_debug(1, "OSP: retrydelay '%d'\n", t);
430                         } else {
431                                 ast_log(LOG_WARNING, "OSP: retrydelay should be an integer from %d to %d, not '%s' at line %d\n",
432                                         OSP_MIN_RETRYDELAY, OSP_MAX_RETRYDELAY, v->value, v->lineno);
433                         }
434                 } else if (!strcasecmp(v->name, "retrylimit")) {
435                         if ((sscanf(v->value, "%30d", &t) == 1) && (t >= OSP_MIN_RETRYLIMIT) && (t <= OSP_MAX_RETRYLIMIT)) {
436                                 p->retrylimit = t;
437                                 ast_debug(1, "OSP: retrylimit '%d'\n", t);
438                         } else {
439                                 ast_log(LOG_WARNING, "OSP: retrylimit should be an integer from %d to %d, not '%s' at line %d\n",
440                                         OSP_MIN_RETRYLIMIT, OSP_MAX_RETRYLIMIT, v->value, v->lineno);
441                         }
442                 } else if (!strcasecmp(v->name, "timeout")) {
443                         if ((sscanf(v->value, "%30d", &t) == 1) && (t >= OSP_MIN_TIMEOUT) && (t <= OSP_MAX_TIMEOUT)) {
444                                 p->timeout = t;
445                                 ast_debug(1, "OSP: timeout '%d'\n", t);
446                         } else {
447                                 ast_log(LOG_WARNING, "OSP: timeout should be an integer from %d to %d, not '%s' at line %d\n",
448                                         OSP_MIN_TIMEOUT, OSP_MAX_TIMEOUT, v->value, v->lineno);
449                         }
450                 } else if (!strcasecmp(v->name, "source")) {
451                         ast_copy_string(p->source, v->value, sizeof(p->source));
452                         ast_debug(1, "OSP: source '%s'\n", p->source);
453                 } else if (!strcasecmp(v->name, "authpolicy")) {
454                         if ((sscanf(v->value, "%30d", &t) == 1) && ((t == OSP_AUTH_NO) || (t == OSP_AUTH_YES) || (t == OSP_AUTH_EXCLUSIVE))) {
455                                 p->authpolicy = t;
456                                 ast_debug(1, "OSP: authpolicy '%d'\n", t);
457                         } else {
458                                 ast_log(LOG_WARNING, "OSP: authpolicy should be %d, %d or %d, not '%s' at line %d\n",
459                                         OSP_AUTH_NO, OSP_AUTH_YES, OSP_AUTH_EXCLUSIVE, v->value, v->lineno);
460                         }
461                 } else if (!strcasecmp(v->name, "defaultprotocol")) {
462                         if (!strcasecmp(v->value, OSP_PROT_SIP)) {
463                                 p->defaultprotocol = OSP_PROT_SIP;
464                                 ast_debug(1, "OSP: default protocol '%s'\n", p->defaultprotocol);
465                         } else if (!strcasecmp(v->value, OSP_PROT_H323)) {
466                                 p->defaultprotocol = OSP_PROT_H323;
467                                 ast_debug(1, "OSP: default protocol '%s'\n", p->defaultprotocol);
468                         } else if (!strcasecmp(v->value, OSP_PROT_IAX)) {
469                                 p->defaultprotocol = OSP_PROT_IAX;
470                                 ast_debug(1, "OSP: default protocol '%s'\n", p->defaultprotocol);
471                         } else {
472                                 ast_log(LOG_WARNING, "OSP: default protocol should be %s, %s, %s, or %s not '%s' at line %d\n",
473                                         OSP_PROT_SIP, OSP_PROT_H323, OSP_PROT_IAX, OSP_PROT_OTHER, v->value, v->lineno);
474                         }
475                 }
476                 v = v->next;
477         }
478
479         if (p->cacount == 0) {
480                 p->cacount = 1;
481         }
482
483         for (i = 0; i < p->spcount; i++) {
484                 psrvpoints[i] = p->srvpoints[i];
485         }
486
487         if (osp_security) {
488                 privatekey.PrivateKeyData = NULL;
489                 privatekey.PrivateKeyLength = 0;
490
491                 localcert.CertData = NULL;
492                 localcert.CertDataLength = 0;
493
494                 for (i = 0; i < p->cacount; i++) {
495                         cacerts[i].CertData = NULL;
496                         cacerts[i].CertDataLength = 0;
497                 }
498
499                 if ((error = OSPPUtilLoadPEMPrivateKey((unsigned char*)p->privatekey, &privatekey)) != OSPC_ERR_NO_ERROR) {
500                         ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s', error '%d'\n", p->privatekey, error);
501                 } else if ((error = OSPPUtilLoadPEMCert((unsigned char*)p->localcert, &localcert)) != OSPC_ERR_NO_ERROR) {
502                         ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s', error '%d'\n", p->localcert, error);
503                 } else {
504                         for (i = 0; i < p->cacount; i++) {
505                                 if ((error = OSPPUtilLoadPEMCert((unsigned char*)p->cacerts[i], &cacerts[i])) != OSPC_ERR_NO_ERROR) {
506                                         ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s', error '%d'\n", p->cacerts[i], error);
507                                         break;
508                                 } else {
509                                         pcacerts[i] = &cacerts[i];
510                                 }
511                         }
512                 }
513         } else {
514                 privatekey.PrivateKeyData = privatekeydata;
515                 privatekey.PrivateKeyLength = sizeof(privatekeydata);
516
517                 localcert.CertData = localcertdata;
518                 localcert.CertDataLength = sizeof(localcertdata);
519
520                 cacerts[0].CertData = cacertdata;
521                 cacerts[0].CertDataLength = sizeof(cacertdata);
522                 pcacerts[0] = &cacerts[0];
523
524                 if ((error = OSPPBase64Decode(B64PKey, strlen(B64PKey), privatekey.PrivateKeyData, &privatekey.PrivateKeyLength)) != OSPC_ERR_NO_ERROR) {
525                         ast_log(LOG_WARNING, "OSP: Unable to decode private key, error '%d'\n", error);
526                 } else if ((error = OSPPBase64Decode(B64LCert, strlen(B64LCert), localcert.CertData, &localcert.CertDataLength)) != OSPC_ERR_NO_ERROR) {
527                         ast_log(LOG_WARNING, "OSP: Unable to decode local cert, error '%d'\n", error);
528                 } else if ((error = OSPPBase64Decode(B64CACert, strlen(B64CACert), cacerts[0].CertData, &cacerts[0].CertDataLength)) != OSPC_ERR_NO_ERROR) {
529                         ast_log(LOG_WARNING, "OSP: Unable to decode cacert, error '%d'\n", error);
530                 }
531         }
532
533         if (error == OSPC_ERR_NO_ERROR) {
534                 error = OSPPProviderNew(
535                         p->spcount,
536                         psrvpoints,
537                         NULL,
538                         OSP_AUDIT_URL,
539                         &privatekey,
540                         &localcert,
541                         p->cacount,
542                         pcacerts,
543                         OSP_LOCAL_VALIDATION,
544                         OSP_SSL_LIFETIME,
545                         p->maxconnections,
546                         OSP_HTTP_PERSISTENCE,
547                         p->retrydelay,
548                         p->retrylimit,
549                         p->timeout,
550                         OSP_CUSTOMER_ID,
551                         OSP_DEVICE_ID,
552                         &p->handle);
553                 if (error != OSPC_ERR_NO_ERROR) {
554                         ast_log(LOG_WARNING, "OSP: Unable to create provider '%s', error '%d'\n", provider, error);
555                         res = -1;
556                 } else {
557                         ast_debug(1, "OSP: provider '%s'\n", provider);
558                         ast_mutex_lock(&osplock);
559                         p->next = ospproviders;
560                         ospproviders = p;
561                         ast_mutex_unlock(&osplock);
562                         res = 1;
563                 }
564         }
565
566         if (osp_security) {
567                 for (i = 0; i < p->cacount; i++) {
568                         if (cacerts[i].CertData) {
569                                 ast_free(cacerts[i].CertData);
570                         }
571                 }
572                 if (localcert.CertData) {
573                         ast_free(localcert.CertData);
574                 }
575                 if (privatekey.PrivateKeyData) {
576                         ast_free(privatekey.PrivateKeyData);
577                 }
578         }
579
580         if (res != 1) {
581                 ast_free(p);
582         }
583
584         return res;
585 }
586
587 /*!
588  * \brief Get OSP provider by name
589  * \param name OSP provider context name
590  * \param provider OSP provider structure
591  * \return 1 Success, 0 Failed, -1 Error
592  */
593 static int osp_get_provider(
594         const char* name,
595         struct osp_provider** provider)
596 {
597         int res = 0;
598         struct osp_provider* p;
599
600         ast_mutex_lock(&osplock);
601         p = ospproviders;
602         while(p) {
603                 if (!strcasecmp(p->name, name)) {
604                         *provider = p;
605                         ast_debug(1, "OSP: find provider '%s'\n", name);
606                         res = 1;
607                         break;
608                 }
609                 p = p->next;
610         }
611         ast_mutex_unlock(&osplock);
612
613         return res;
614 }
615
616 /*!
617  * \brief Create OSP transaction handle
618  * \param provider OSP provider context name
619  * \param transaction OSP transaction handle, output
620  * \param sourcesize Size of source buffer, in/output
621  * \param source Source of provider, output
622  * \return 1 Success, 0 Failed, -1 Error
623  */
624 static int osp_create_transaction(
625         const char* provider,
626         int* transaction,
627         unsigned int sourcesize,
628         char* source)
629 {
630         int res = 0;
631         struct osp_provider* p;
632         int error;
633
634         ast_mutex_lock(&osplock);
635         p = ospproviders;
636         while(p) {
637                 if (!strcasecmp(p->name, provider)) {
638                         error = OSPPTransactionNew(p->handle, transaction);
639                         if (error == OSPC_ERR_NO_ERROR) {
640                                 ast_debug(1, "OSP: transaction '%d'\n", *transaction);
641                                 ast_copy_string(source, p->source, sourcesize);
642                                 ast_debug(1, "OSP: source '%s'\n", source);
643                                 res = 1;
644                         } else {
645                                 *transaction = OSP_INVALID_HANDLE;
646                                 ast_debug(1, "OSP: Unable to create transaction handle, error '%d'\n", error);
647                                 res = -1;
648                         }
649                         break;
650                 }
651                 p = p->next;
652         }
653         ast_mutex_unlock(&osplock);
654
655         return res;
656 }
657
658 /*!
659  * \brief Convert address to "[x.x.x.x]" or "host.domain" format
660  * \param src Source address string
661  * \param dst Destination address string
662  * \param buffersize Size of dst buffer
663  */
664 static void osp_convert_address(
665         const char* src,
666         char* dst,
667         int buffersize)
668 {
669         struct in_addr inp;
670
671         if (inet_aton(src, &inp) != 0) {
672                 snprintf(dst, buffersize, "[%s]", src);
673         } else {
674                 snprintf(dst, buffersize, "%s", src);
675         }
676 }
677
678 /*!
679  * \brief Validate OSP token of inbound call
680  * \param transaction OSP transaction handle
681  * \param source Source of inbound call
682  * \param destination Destination of inbound call
683  * \param calling Calling number
684  * \param called Called number
685  * \param token OSP token, may be empty
686  * \param timelimit Call duration limit, output
687  * \return 1 Success, 0 Failed, -1 Error
688  */
689 static int osp_validate_token(
690         int transaction,
691         const char* source,
692         const char* destination,
693         const char* calling,
694         const char* called,
695         const char* token,
696         unsigned int* timelimit)
697 {
698         int res;
699         int tokenlen;
700         unsigned char tokenstr[OSP_TOKSTR_SIZE];
701         char src[OSP_NORSTR_SIZE];
702         char dst[OSP_NORSTR_SIZE];
703         unsigned int authorised;
704         unsigned int dummy = 0;
705         int error;
706
707         tokenlen = ast_base64decode(tokenstr, token, strlen(token));
708         osp_convert_address(source, src, sizeof(src));
709         osp_convert_address(destination, dst, sizeof(dst));
710         error = OSPPTransactionValidateAuthorisation(
711                 transaction,
712                 src,
713                 dst,
714                 NULL,
715                 NULL,
716                 calling ? calling : "",
717                 OSPC_NFORMAT_E164,
718                 called,
719                 OSPC_NFORMAT_E164,
720                 0,
721                 NULL,
722                 tokenlen,
723                 (char*)tokenstr,
724                 &authorised,
725                 timelimit,
726                 &dummy,
727                 NULL,
728                 osp_tokenformat);
729         if (error != OSPC_ERR_NO_ERROR) {
730                 ast_debug(1, "OSP: Unable to validate inbound token, error '%d'\n", error);
731                 res = -1;
732         } else if (authorised) {
733                 ast_debug(1, "OSP: Authorised\n");
734                 res = 1;
735         } else {
736                 ast_debug(1, "OSP: Unauthorised\n");
737                 res = 0;
738         }
739
740         return res;
741 }
742
743 /*!
744  * \brief Choose min duration limit
745  * \param in Inbound duration limit
746  * \param out Outbound duration limit
747  * \return min duration limit
748  */
749 static unsigned int osp_choose_timelimit(
750         unsigned int in,
751         unsigned int out)
752 {
753         if (in == OSP_DEF_TIMELIMIT) {
754                 return out;
755         } else if (out == OSP_DEF_TIMELIMIT) {
756                 return in;
757         } else {
758                 return in < out ? in : out;
759         }
760 }
761
762 /*!
763  * \brief Choose min duration limit
764  * \param provider OSP provider
765  * \param called Called number
766  * \param calling Calling number
767  * \param destination Destination IP in '[x.x.x.x]' format
768  * \param tokenlen OSP token length
769  * \param token OSP token
770  * \param reason Failure reason, output
771  * \param result OSP lookup results, in/output
772  * \return 1 Success, 0 Failed, -1 Error
773  */
774 static int osp_check_destination(
775         struct osp_provider* provider,
776         const char* called,
777         const char* calling,
778         char* destination,
779         unsigned int tokenlen,
780         const char* token,
781         OSPEFAILREASON* reason,
782         struct osp_result* result)
783 {
784         int res;
785         OSPE_DEST_OSPENABLED enabled;
786         OSPE_DEST_PROTOCOL protocol;
787         int error;
788
789         if (strlen(destination) <= 2) {
790                 ast_debug(1, "OSP: Wrong destination format '%s'\n", destination);
791                 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
792                 return -1;
793         }
794
795         if ((error = OSPPTransactionIsDestOSPEnabled(result->outhandle, &enabled)) != OSPC_ERR_NO_ERROR) {
796                 ast_debug(1, "OSP: Unable to get destination OSP version, error '%d'\n", error);
797                 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
798                 return -1;
799         }
800
801         if (enabled == OSPC_DOSP_FALSE) {
802                 result->token[0] = '\0';
803         } else {
804                 ast_base64encode(result->token, (const unsigned char*)token, tokenlen, sizeof(result->token) - 1);
805         }
806
807         if ((error = OSPPTransactionGetDestNetworkId(result->outhandle, result->networkid)) != OSPC_ERR_NO_ERROR) {
808                 ast_debug(1, "OSP: Unable to get destination network ID, error '%d'\n", error);
809                 result->networkid[0] = '\0';
810         }
811
812         if ((error = OSPPTransactionGetDestProtocol(result->outhandle, &protocol)) != OSPC_ERR_NO_ERROR) {
813                 ast_debug(1, "OSP: Unable to get destination protocol, error '%d'\n", error);
814                 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
815                 result->token[0] = '\0';
816                 result->networkid[0] = '\0';
817                 return -1;
818         }
819
820         res = 1;
821         /* Strip leading and trailing brackets */
822         destination[strlen(destination) - 1] = '\0';
823         switch(protocol) {
824         case OSPC_DPROT_Q931:
825                 ast_debug(1, "OSP: protocol '%s'\n", OSP_PROT_H323);
826                 ast_copy_string(result->tech, OSP_TECH_H323, sizeof(result->tech));
827                 ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
828                 ast_copy_string(result->called, called, sizeof(result->called));
829                 ast_copy_string(result->calling, calling, sizeof(result->calling));
830                 break;
831         case OSPC_DPROT_SIP:
832                 ast_debug(1, "OSP: protocol '%s'\n", OSP_PROT_SIP);
833                 ast_copy_string(result->tech, OSP_TECH_SIP, sizeof(result->tech));
834                 ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
835                 ast_copy_string(result->called, called, sizeof(result->called));
836                 ast_copy_string(result->calling, calling, sizeof(result->calling));
837                 break;
838         case OSPC_DPROT_IAX:
839                 ast_debug(1, "OSP: protocol '%s'\n", OSP_PROT_IAX);
840                 ast_copy_string(result->tech, OSP_TECH_IAX, sizeof(result->tech));
841                 ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
842                 ast_copy_string(result->called, called, sizeof(result->called));
843                 ast_copy_string(result->calling, calling, sizeof(result->calling));
844                 break;
845         case OSPC_DPROT_UNDEFINED:
846         case OSPC_DPROT_UNKNOWN:
847                 ast_debug(1, "OSP: unknown/undefined protocol '%d'\n", protocol);
848                 ast_debug(1, "OSP: use default protocol '%s'\n", provider->defaultprotocol);
849
850                 ast_copy_string(result->tech, provider->defaultprotocol, sizeof(result->tech));
851                 ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
852                 ast_copy_string(result->called, called, sizeof(result->called));
853                 ast_copy_string(result->calling, calling, sizeof(result->calling));
854                 break;
855         case OSPC_DPROT_LRQ:
856         default:
857                 ast_log(LOG_WARNING, "OSP: unsupported protocol '%d'\n", protocol);
858                 *reason = OSPC_FAIL_PROTOCOL_ERROR;
859                 result->token[0] = '\0';
860                 result->networkid[0] = '\0';
861                 res = 0;
862                 break;
863         }
864
865         return res;
866 }
867
868 /*!
869  * \brief Convert Asterisk status to TC code
870  * \param cause Asterisk hangup cause
871  * \return OSP TC code
872  */
873 static OSPEFAILREASON asterisk2osp(
874         int cause)
875 {
876         return (OSPEFAILREASON)cause;
877 }
878
879 /*!
880  * \brief OSP Authentication function
881  * \param provider OSP provider context name
882  * \param transaction OSP transaction handle, output
883  * \param source Source of inbound call
884  * \param calling Calling number
885  * \param called Called number
886  * \param token OSP token, may be empty
887  * \param timelimit Call duration limit, output
888  * \return 1 Authenricated, 0 Unauthenticated, -1 Error
889  */
890 static int osp_auth(
891         const char* provider,
892         int* transaction,
893         const char* source,
894         const char* calling,
895         const char* called,
896         const char* token,
897         unsigned int* timelimit)
898 {
899         int res;
900         struct osp_provider* p = NULL;
901         char dest[OSP_NORSTR_SIZE];
902
903         *transaction = OSP_INVALID_HANDLE;
904         *timelimit = OSP_DEF_TIMELIMIT;
905
906         if ((res = osp_get_provider(provider, &p)) <= 0) {
907                 ast_debug(1, "OSP: Unabe to find OSP provider '%s'\n", provider);
908                 return res;
909         }
910
911         switch (p->authpolicy) {
912         case OSP_AUTH_NO:
913                 res = 1;
914                 break;
915         case OSP_AUTH_EXCLUSIVE:
916                 if (ast_strlen_zero(token)) {
917                         res = 0;
918                 } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
919                         ast_debug(1, "OSP: Unable to generate transaction handle\n");
920                         *transaction = OSP_INVALID_HANDLE;
921                         res = 0;
922                 } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
923                         OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
924                 }
925                 break;
926         case OSP_AUTH_YES:
927         default:
928                 if (ast_strlen_zero(token)) {
929                         res = 1;
930                 } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
931                         ast_debug(1, "OSP: Unable to generate transaction handle\n");
932                         *transaction = OSP_INVALID_HANDLE;
933                         res = 0;
934                 } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
935                         OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
936                 }
937                 break;
938         }
939
940         return res;
941 }
942
943 /*!
944  * \brief Create a UUID
945  * \param uuid UUID buffer
946  * \param buffersize UUID buffer size
947  * \return 1 Created, -1 Error
948  */
949 static int osp_create_uuid(
950         unsigned char* uuid,
951         unsigned int* buffersize)
952 {
953         int i, res;
954         long int* tmp;
955
956         if (*buffersize >= OSP_UUID_SIZE) {
957                 tmp = (long int*)uuid;
958                 for (i = 0; i < OSP_UUID_SIZE / sizeof(long int); i++) {
959                         tmp[i] = ast_random();
960                 }
961                 *buffersize = OSP_UUID_SIZE;
962                 res = 1;
963         } else {
964                 res = -1;
965         }
966
967         return res;
968 }
969
970 /*!
971  * \brief UUID to string
972  * \param uuid UUID
973  * \param buffer String buffer
974  * \param buffersize String buffer size
975  * \return 1 Successed, -1 Error
976  */
977 static int osp_uuid2str(
978         unsigned char* uuid,
979         char* buffer,
980         unsigned int buffersize)
981 {
982         int res;
983
984         if (buffersize > OSP_UUIDSTR_SIZE) {
985                 snprintf(buffer, buffersize, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
986                         uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
987                         uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
988                 res = 1;
989         } else {
990                 res = -1;
991         }
992
993         return res;
994 }
995
996 /*!
997  * \brief Create a call ID according to the type
998  * \param type Call ID type
999  * \param callid Call ID buffer
1000  * \return 1 Created, 0 Not create, -1 Error
1001  */
1002 static int osp_create_callid(
1003         unsigned int type,
1004         struct osp_callid* callid)
1005 {
1006         int res;
1007
1008         callid->len = sizeof(callid->buf);
1009         switch (type) {
1010         case OSP_CALLID_H323:
1011                 res = osp_create_uuid(callid->buf, &callid->len);
1012                 break;
1013         case OSP_CALLID_SIP:
1014         case OSP_CALLID_IAX:
1015                 res = 0;
1016         default:
1017                 res = -1;
1018                 break;
1019         }
1020
1021         if ((res != 1) && (callid->len != 0)) {
1022                 callid->buf[0] = '\0';
1023                 callid->len = 0;
1024         }
1025
1026         return res;
1027 }
1028
1029 /*!
1030  * \brief OSP Lookup function
1031  * \param provider OSP provider context name
1032  * \param srcdev Source device of outbound call
1033  * \param calling Calling number
1034  * \param called Called number
1035  * \param snetid Source network ID
1036  * \param rnumber Routing number
1037  * \param callidtypes Call ID types
1038  * \param result Lookup results
1039  * \return 1 Found , 0 No route, -1 Error
1040  */
1041 static int osp_lookup(
1042         const char* provider,
1043         const char* srcdev,
1044         const char* calling,
1045         const char* called,
1046         const char* snetid,
1047         const char* rnumber,
1048         unsigned int callidtypes,
1049         struct osp_result* result)
1050 {
1051         int res;
1052         struct osp_provider* p = NULL;
1053         char source[OSP_NORSTR_SIZE];
1054         char callingnum[OSP_NORSTR_SIZE];
1055         char callednum[OSP_NORSTR_SIZE];
1056         char destination[OSP_NORSTR_SIZE];
1057         unsigned int tokenlen;
1058         char token[OSP_TOKSTR_SIZE];
1059         char src[OSP_NORSTR_SIZE];
1060         char dev[OSP_NORSTR_SIZE];
1061         unsigned int i, type;
1062         struct osp_callid callid;
1063         unsigned int callidnum;
1064         OSPT_CALL_ID* callids[OSP_CALLID_MAXNUM];
1065         unsigned int dummy = 0;
1066         OSPEFAILREASON reason;
1067         int error;
1068
1069         result->outhandle = OSP_INVALID_HANDLE;
1070         result->tech[0] = '\0';
1071         result->dest[0] = '\0';
1072         result->called[0] = '\0';
1073         result->calling[0] = '\0';
1074         result->token[0] = '\0';
1075         result->networkid[0] = '\0';
1076         result->numresults = 0;
1077         result->outtimelimit = OSP_DEF_TIMELIMIT;
1078
1079         if ((res = osp_get_provider(provider, &p)) <= 0) {
1080                 ast_debug(1, "OSP: Unabe to find OSP provider '%s'\n", provider);
1081                 return res;
1082         }
1083
1084         if ((res = osp_create_transaction(provider, &result->outhandle, sizeof(source), source)) <= 0) {
1085                 ast_debug(1, "OSP: Unable to generate transaction handle\n");
1086                 result->outhandle = OSP_INVALID_HANDLE;
1087                 if (result->inhandle != OSP_INVALID_HANDLE) {
1088                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1089                 }
1090                 return -1;
1091         }
1092
1093         if (!ast_strlen_zero(snetid)) {
1094                 OSPPTransactionSetNetworkIds(result->outhandle, snetid, "");
1095         }
1096
1097         if (!ast_strlen_zero(rnumber)) {
1098                 OSPPTransactionSetRoutingNumber(result->outhandle, rnumber);
1099         }
1100
1101         callidnum = 0;
1102         callids[0] = NULL;
1103         for (i = 0; i < OSP_CALLID_MAXNUM; i++) {
1104                 type = 1 << i;
1105                 if (callidtypes & type) {
1106                         error = osp_create_callid(type, &callid);
1107                         if (error == 1) {
1108                                 callids[callidnum] = OSPPCallIdNew(callid.len, callid.buf);
1109                                 callidnum++;
1110                         }
1111                 }
1112         }
1113
1114         osp_convert_address(source, src, sizeof(src));
1115         osp_convert_address(srcdev, dev, sizeof(dev));
1116         result->numresults = OSP_DEF_DESTINATIONS;
1117         error = OSPPTransactionRequestAuthorisation(
1118                 result->outhandle,
1119                 src,
1120                 dev,
1121                 calling ? calling : "",
1122                 OSPC_NFORMAT_E164,
1123                 called,
1124                 OSPC_NFORMAT_E164,
1125                 NULL,
1126                 callidnum,
1127                 callids,
1128                 NULL,
1129                 &result->numresults,
1130                 &dummy,
1131                 NULL);
1132
1133         for (i = 0; i < callidnum; i++) {
1134                 OSPPCallIdDelete(&callids[i]);
1135         }
1136
1137         if (error != OSPC_ERR_NO_ERROR) {
1138                 ast_debug(1, "OSP: Unable to request authorization, error '%d'\n", error);
1139                 result->numresults = 0;
1140                 if (result->inhandle != OSP_INVALID_HANDLE) {
1141                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1142                 }
1143                 return -1;
1144         }
1145
1146         if (!result->numresults) {
1147                 ast_debug(1, "OSP: No more destination\n");
1148                 if (result->inhandle != OSP_INVALID_HANDLE) {
1149                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1150                 }
1151                 return 0;
1152         }
1153
1154         result->outcallid.len = sizeof(result->outcallid.buf);
1155         tokenlen = sizeof(token);
1156         error = OSPPTransactionGetFirstDestination(
1157                 result->outhandle,
1158                 0,
1159                 NULL,
1160                 NULL,
1161                 &result->outtimelimit,
1162                 &result->outcallid.len,
1163                 result->outcallid.buf,
1164                 sizeof(callednum),
1165                 callednum,
1166                 sizeof(callingnum),
1167                 callingnum,
1168                 sizeof(destination),
1169                 destination,
1170                 0,
1171                 NULL,
1172                 &tokenlen,
1173                 token);
1174         if (error != OSPC_ERR_NO_ERROR) {
1175                 ast_debug(1, "OSP: Unable to get first route, error '%d'\n", error);
1176                 result->numresults = 0;
1177                 result->outtimelimit = OSP_DEF_TIMELIMIT;
1178                 if (result->inhandle != OSP_INVALID_HANDLE) {
1179                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1180                 }
1181                 return -1;
1182         }
1183
1184         result->numresults--;
1185         result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
1186         ast_debug(1, "OSP: outtimelimit '%d'\n", result->outtimelimit);
1187         ast_debug(1, "OSP: called '%s'\n", callednum);
1188         ast_debug(1, "OSP: calling '%s'\n", callingnum);
1189         ast_debug(1, "OSP: destination '%s'\n", destination);
1190         ast_debug(1, "OSP: token size '%d'\n", tokenlen);
1191
1192         if ((res = osp_check_destination(p, callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
1193                 return 1;
1194         }
1195
1196         if (!result->numresults) {
1197                 ast_debug(1, "OSP: No more destination\n");
1198                 result->outtimelimit = OSP_DEF_TIMELIMIT;
1199                 OSPPTransactionRecordFailure(result->outhandle, reason);
1200                 if (result->inhandle != OSP_INVALID_HANDLE) {
1201                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1202                 }
1203                 return 0;
1204         }
1205
1206         while(result->numresults) {
1207                 result->outcallid.len = sizeof(result->outcallid.buf);
1208                 tokenlen = sizeof(token);
1209                 error = OSPPTransactionGetNextDestination(
1210                         result->outhandle,
1211                         reason,
1212                         0,
1213                         NULL,
1214                         NULL,
1215                         &result->outtimelimit,
1216                         &result->outcallid.len,
1217                         result->outcallid.buf,
1218                         sizeof(callednum),
1219                         callednum,
1220                         sizeof(callingnum),
1221                         callingnum,
1222                         sizeof(destination),
1223                         destination,
1224                         0,
1225                         NULL,
1226                         &tokenlen,
1227                         token);
1228                 if (error == OSPC_ERR_NO_ERROR) {
1229                         result->numresults--;
1230                         result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
1231                         ast_debug(1, "OSP: outtimelimit '%d'\n", result->outtimelimit);
1232                         ast_debug(1, "OSP: called '%s'\n", callednum);
1233                         ast_debug(1, "OSP: calling '%s'\n", callingnum);
1234                         ast_debug(1, "OSP: destination '%s'\n", destination);
1235                         ast_debug(1, "OSP: token size '%d'\n", tokenlen);
1236
1237                         if ((res = osp_check_destination(p, callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
1238                                 break;
1239                         } else if (!result->numresults) {
1240                                 ast_debug(1, "OSP: No more destination\n");
1241                                 OSPPTransactionRecordFailure(result->outhandle, reason);
1242                                 if (result->inhandle != OSP_INVALID_HANDLE) {
1243                                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1244                                 }
1245                                 res = 0;
1246                                 break;
1247                         }
1248                 } else {
1249                         ast_debug(1, "OSP: Unable to get route, error '%d'\n", error);
1250                         result->numresults = 0;
1251                         result->outtimelimit = OSP_DEF_TIMELIMIT;
1252                         if (result->inhandle != OSP_INVALID_HANDLE) {
1253                                 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1254                         }
1255                         res = -1;
1256                         break;
1257                 }
1258         }
1259         return res;
1260 }
1261
1262 /*!
1263  * \brief OSP Lookup Next function
1264  * \param provider OSP provider name
1265  * \param cause Asterisk hangup cuase
1266  * \param result Lookup results, in/output
1267  * \return 1 Found , 0 No route, -1 Error
1268  */
1269 static int osp_next(
1270         const char* provider,
1271         int cause,
1272         struct osp_result* result)
1273 {
1274         int res;
1275         struct osp_provider* p = NULL;
1276         char callingnum[OSP_NORSTR_SIZE];
1277         char callednum[OSP_NORSTR_SIZE];
1278         char destination[OSP_NORSTR_SIZE];
1279         unsigned int tokenlen;
1280         char token[OSP_TOKSTR_SIZE];
1281         OSPEFAILREASON reason;
1282         int error;
1283
1284         result->tech[0] = '\0';
1285         result->dest[0] = '\0';
1286         result->called[0] = '\0';
1287         result->calling[0] = '\0';
1288         result->token[0] = '\0';
1289         result->networkid[0] = '\0';
1290         result->outtimelimit = OSP_DEF_TIMELIMIT;
1291
1292         if ((res = osp_get_provider(provider, &p)) <= 0) {
1293                 ast_debug(1, "OSP: Unabe to find OSP provider '%s'\n", provider);
1294                 return res;
1295         }
1296
1297         if (result->outhandle == OSP_INVALID_HANDLE) {
1298                 ast_debug(1, "OSP: Transaction handle undefined\n");
1299                 result->numresults = 0;
1300                 if (result->inhandle != OSP_INVALID_HANDLE) {
1301                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1302                 }
1303                 return -1;
1304         }
1305
1306         reason = asterisk2osp(cause);
1307
1308         if (!result->numresults) {
1309                 ast_debug(1, "OSP: No more destination\n");
1310                 OSPPTransactionRecordFailure(result->outhandle, reason);
1311                 if (result->inhandle != OSP_INVALID_HANDLE) {
1312                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1313                 }
1314                 return 0;
1315         }
1316
1317         while(result->numresults) {
1318                 result->outcallid.len = sizeof(result->outcallid.buf);
1319                 tokenlen = sizeof(token);
1320                 error = OSPPTransactionGetNextDestination(
1321                         result->outhandle,
1322                         reason,
1323                         0,
1324                         NULL,
1325                         NULL,
1326                         &result->outtimelimit,
1327                         &result->outcallid.len,
1328                         result->outcallid.buf,
1329                         sizeof(callednum),
1330                         callednum,
1331                         sizeof(callingnum),
1332                         callingnum,
1333                         sizeof(destination),
1334                         destination,
1335                         0,
1336                         NULL,
1337                         &tokenlen,
1338                         token);
1339                 if (error == OSPC_ERR_NO_ERROR) {
1340                         result->numresults--;
1341                         result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
1342                         ast_debug(1, "OSP: outtimelimit '%d'\n", result->outtimelimit);
1343                         ast_debug(1, "OSP: called '%s'\n", callednum);
1344                         ast_debug(1, "OSP: calling '%s'\n", callingnum);
1345                         ast_debug(1, "OSP: destination '%s'\n", destination);
1346                         ast_debug(1, "OSP: token size '%d'\n", tokenlen);
1347
1348                         if ((res = osp_check_destination(p, callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
1349                                 res = 1;
1350                                 break;
1351                         } else if (!result->numresults) {
1352                                 ast_debug(1, "OSP: No more destination\n");
1353                                 OSPPTransactionRecordFailure(result->outhandle, reason);
1354                                 if (result->inhandle != OSP_INVALID_HANDLE) {
1355                                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1356                                 }
1357                                 res = 0;
1358                                 break;
1359                         }
1360                 } else {
1361                         ast_debug(1, "OSP: Unable to get route, error '%d'\n", error);
1362                         result->token[0] = '\0';
1363                         result->numresults = 0;
1364                         result->outtimelimit = OSP_DEF_TIMELIMIT;
1365                         if (result->inhandle != OSP_INVALID_HANDLE) {
1366                                 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1367                         }
1368                         res = -1;
1369                         break;
1370                 }
1371         }
1372
1373         return res;
1374 }
1375
1376 /*!
1377  * \brief OSP Finish function
1378  * \param handle OSP in/outbound transaction handle
1379  * \param recorded If failure reason has been recorded
1380  * \param cause Asterisk hangup cause
1381  * \param start Call start time
1382  * \param connect Call connect time
1383  * \param end Call end time
1384  * \param release Who release first, 0 source, 1 destination
1385  * \return 1 Success, 0 Failed, -1 Error
1386  */
1387 static int osp_finish(
1388         int handle,
1389         int recorded,
1390         int cause,
1391         time_t start,
1392         time_t connect,
1393         time_t end,
1394         unsigned int release)
1395 {
1396         int res;
1397         OSPEFAILREASON reason;
1398         time_t alert = 0;
1399         unsigned isPddInfoPresent = 0;
1400         unsigned pdd = 0;
1401         unsigned int dummy = 0;
1402         int error;
1403
1404         if (handle == OSP_INVALID_HANDLE) {
1405                 return 0;
1406         }
1407
1408         if (!recorded) {
1409                 reason = asterisk2osp(cause);
1410                 OSPPTransactionRecordFailure(handle, reason);
1411         }
1412
1413         error = OSPPTransactionReportUsage(
1414                 handle,
1415                 difftime(end, connect),
1416                 start,
1417                 end,
1418                 alert,
1419                 connect,
1420                 isPddInfoPresent,
1421                 pdd,
1422                 release,
1423                 NULL,
1424                 -1,
1425                 -1,
1426                 -1,
1427                 -1,
1428                 &dummy,
1429                 NULL);
1430         if (error == OSPC_ERR_NO_ERROR) {
1431                 ast_debug(1, "OSP: Usage reported\n");
1432                 res = 1;
1433         } else {
1434                 ast_debug(1, "OSP: Unable to report usage, error '%d'\n", error);
1435                 res = -1;
1436         }
1437         OSPPTransactionDelete(handle);
1438
1439         return res;
1440 }
1441
1442 /* OSP Application APIs */
1443
1444 /*!
1445  * \brief OSP Application OSPAuth
1446  * \param chan Channel
1447  * \param data Parameter
1448  * \return 0 Success, -1 Failed
1449  */
1450 static int ospauth_exec(
1451         struct ast_channel *chan,
1452         const char *data)
1453 {
1454         int res;
1455         const char* provider = OSP_DEF_PROVIDER;
1456         struct varshead* headp;
1457         struct ast_var_t* current;
1458         const char* source = "";
1459         const char* token = "";
1460         int handle;
1461         unsigned int timelimit;
1462         char buffer[OSP_INTSTR_SIZE];
1463         const char* status;
1464         char* tmp;
1465
1466         AST_DECLARE_APP_ARGS(args,
1467                 AST_APP_ARG(provider);
1468                 AST_APP_ARG(options);
1469         );
1470
1471         if (!(tmp = ast_strdupa(data))) {
1472                 ast_log(LOG_ERROR, "Out of memory\n");
1473                 return -1;
1474         }
1475
1476         AST_STANDARD_APP_ARGS(args, tmp);
1477
1478         if (!ast_strlen_zero(args.provider)) {
1479                 provider = args.provider;
1480         }
1481         ast_debug(1, "OSPAuth: provider '%s'\n", provider);
1482
1483         headp = &chan->varshead;
1484         AST_LIST_TRAVERSE(headp, current, entries) {
1485                 if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
1486                         source = ast_var_value(current);
1487                 } else if (!strcasecmp(ast_var_name(current), "OSPINTOKEN")) {
1488                         token = ast_var_value(current);
1489                 }
1490         }
1491
1492         ast_debug(1, "OSPAuth: source '%s'\n", source);
1493         ast_debug(1, "OSPAuth: token size '%zd'\n", strlen(token));
1494
1495         if ((res = osp_auth(provider, &handle, source, chan->cid.cid_num, chan->exten, token, &timelimit)) > 0) {
1496                 status = AST_OSP_SUCCESS;
1497         } else {
1498                 timelimit = OSP_DEF_TIMELIMIT;
1499                 if (!res) {
1500                         status = AST_OSP_FAILED;
1501                 } else {
1502                         status = AST_OSP_ERROR;
1503                 }
1504         }
1505
1506         snprintf(buffer, sizeof(buffer), "%d", handle);
1507         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
1508         ast_debug(1, "OSPAuth: OSPINHANDLE '%s'\n", buffer);
1509         snprintf(buffer, sizeof(buffer), "%d", timelimit);
1510         pbx_builtin_setvar_helper(chan, "OSPINTIMELIMIT", buffer);
1511         ast_debug(1, "OSPAuth: OSPINTIMELIMIT '%s'\n", buffer);
1512         pbx_builtin_setvar_helper(chan, "OSPAUTHSTATUS", status);
1513         ast_debug(1, "OSPAuth: %s\n", status);
1514
1515         if(res <= 0) {
1516                 res = -1;
1517         } else {
1518                 res = 0;
1519         }
1520
1521         return res;
1522 }
1523
1524 /*!
1525  * \brief OSP Application OSPLookup
1526  * \param chan Channel
1527  * \param data Parameter
1528  * \return 0 Success, -1 Failed
1529  */
1530 static int osplookup_exec(
1531         struct ast_channel* chan,
1532         const char * data)
1533 {
1534         int res, cres;
1535         const char* provider = OSP_DEF_PROVIDER;
1536         struct varshead* headp;
1537         struct ast_var_t* current;
1538         const char* srcdev = "";
1539         const char* snetid = "";
1540         const char* rnumber = "";
1541         char buffer[OSP_TOKSTR_SIZE];
1542         unsigned int callidtypes = OSP_CALLID_UNDEFINED;
1543         struct osp_result result;
1544         const char* status;
1545         char* tmp;
1546
1547         AST_DECLARE_APP_ARGS(args,
1548                 AST_APP_ARG(exten);
1549                 AST_APP_ARG(provider);
1550                 AST_APP_ARG(options);
1551         );
1552
1553         if (ast_strlen_zero(data)) {
1554                 ast_log(LOG_WARNING, "OSPLookup: Arg required, OSPLookup(exten[|provider[|options]])\n");
1555                 return -1;
1556         }
1557
1558         if (!(tmp = ast_strdupa(data))) {
1559                 ast_log(LOG_ERROR, "Out of memory\n");
1560                 return -1;
1561         }
1562
1563         AST_STANDARD_APP_ARGS(args, tmp);
1564
1565         ast_debug(1, "OSPLookup: exten '%s'\n", args.exten);
1566
1567         if (!ast_strlen_zero(args.provider)) {
1568                 provider = args.provider;
1569         }
1570         ast_debug(1, "OSPlookup: provider '%s'\n", provider);
1571
1572         if (args.options) {
1573                 if (strchr(args.options, 'h')) {
1574                         callidtypes |= OSP_CALLID_H323;
1575                 }
1576                 if (strchr(args.options, 's')) {
1577                         callidtypes |= OSP_CALLID_SIP;
1578                 }
1579                 if (strchr(args.options, 'i')) {
1580                         callidtypes |= OSP_CALLID_IAX;
1581                 }
1582         }
1583         ast_debug(1, "OSPLookup: call id types '%d'\n", callidtypes);
1584
1585         result.inhandle = OSP_INVALID_HANDLE;
1586         result.intimelimit = OSP_DEF_TIMELIMIT;
1587
1588         headp = &chan->varshead;
1589         AST_LIST_TRAVERSE(headp, current, entries) {
1590                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1591                         if (sscanf(ast_var_value(current), "%30d", &result.inhandle) != 1) {
1592                                 result.inhandle = OSP_INVALID_HANDLE;
1593                         }
1594                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
1595                         if (sscanf(ast_var_value(current), "%30d", &result.intimelimit) != 1) {
1596                                 result.intimelimit = OSP_DEF_TIMELIMIT;
1597                         }
1598                 } else if (!strcasecmp(ast_var_name(current), "OSPINNETWORKID")) {
1599                         snetid = ast_var_value(current);
1600                 } else if (!strcasecmp(ast_var_name(current), "OSPROUTINGNUMBER")) {
1601                         rnumber = ast_var_value(current);
1602                 } else if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
1603                         srcdev = ast_var_value(current);
1604                 }
1605         }
1606         ast_debug(1, "OSPLookup: OSPINHANDLE '%d'\n", result.inhandle);
1607         ast_debug(1, "OSPLookup: OSPINTIMELIMIT '%d'\n", result.intimelimit);
1608         ast_debug(1, "OSPLookup: OSPINNETWORKID '%s'\n", snetid);
1609         ast_debug(1, "OSPLookup: OSPROUTINGNUMBER '%s'\n", rnumber);
1610         ast_debug(1, "OSPLookup: source device '%s'\n", srcdev);
1611
1612         if ((cres = ast_autoservice_start(chan)) < 0) {
1613                 return -1;
1614         }
1615
1616         if ((res = osp_lookup(provider, srcdev, chan->cid.cid_num, args.exten, snetid, rnumber, callidtypes, &result)) > 0) {
1617                 status = AST_OSP_SUCCESS;
1618         } else {
1619                 result.tech[0] = '\0';
1620                 result.dest[0] = '\0';
1621                 result.called[0] = '\0';
1622                 result.calling[0] = '\0';
1623                 result.token[0] = '\0';
1624                 result.networkid[0] = '\0';
1625                 result.numresults = 0;
1626                 result.outtimelimit = OSP_DEF_TIMELIMIT;
1627                 result.outcallid.buf[0] = '\0';
1628                 result.outcallid.len = 0;
1629                 if (!res) {
1630                         status = AST_OSP_FAILED;
1631                 } else {
1632                         status = AST_OSP_ERROR;
1633                 }
1634         }
1635
1636         snprintf(buffer, sizeof(buffer), "%d", result.outhandle);
1637         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
1638         ast_debug(1, "OSPLookup: OSPOUTHANDLE '%s'\n", buffer);
1639         pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
1640         ast_debug(1, "OSPLookup: OSPTECH '%s'\n", result.tech);
1641         pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
1642         ast_debug(1, "OSPLookup: OSPDEST '%s'\n", result.dest);
1643         pbx_builtin_setvar_helper(chan, "OSPCALLED", result.called);
1644         ast_debug(1, "OSPLookup: OSPCALLED '%s'\n", result.called);
1645         pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
1646         ast_debug(1, "OSPLookup: OSPCALLING '%s'\n", result.calling);
1647         pbx_builtin_setvar_helper(chan, "OSPOUTNETWORKID", result.networkid);
1648         ast_debug(1, "OSPLookup: OSPOUTNETWORKID '%s'\n", result.networkid);
1649         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
1650         ast_debug(1, "OSPLookup: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
1651         snprintf(buffer, sizeof(buffer), "%d", result.numresults);
1652         pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
1653         ast_debug(1, "OSPLookup: OSPRESULTS '%s'\n", buffer);
1654         snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
1655         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
1656         ast_debug(1, "OSPLookup: OSPOUTTIMELIMIT '%s'\n", buffer);
1657         snprintf(buffer, sizeof(buffer), "%d", callidtypes);
1658         pbx_builtin_setvar_helper(chan, "OSPOUTCALLIDTYPES", buffer);
1659         ast_debug(1, "OSPLookup: OSPOUTCALLIDTYPES '%s'\n", buffer);
1660         pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", status);
1661         ast_debug(1, "OSPLookup: %s\n", status);
1662
1663         if (!strcasecmp(result.tech, OSP_TECH_H323)) {
1664                 if ((callidtypes & OSP_CALLID_H323) && (result.outcallid.len != 0)) {
1665                         osp_uuid2str(result.outcallid.buf, buffer, sizeof(buffer));
1666                 } else {
1667                         buffer[0] = '\0';
1668                 }
1669                 pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
1670                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1671                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1672         } else if (!strcasecmp(result.tech, OSP_TECH_SIP)) {
1673                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1674                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1675                 if (!ast_strlen_zero(result.token)) {
1676                         snprintf(buffer, sizeof(buffer), "%s%s", OSP_SIP_HEADER, result.token);
1677                         pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
1678                         ast_debug(1, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
1679                 }
1680         } else if (!strcasecmp(result.tech, OSP_TECH_IAX)) {
1681                 snprintf(buffer, sizeof(buffer), "%s/%s/%s", result.tech, result.dest, result.called);
1682                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1683         }
1684
1685         if ((cres = ast_autoservice_stop(chan)) < 0) {
1686                 return -1;
1687         }
1688
1689         if(res <= 0) {
1690                 res = -1;
1691         } else {
1692                 res = 0;
1693         }
1694
1695         return res;
1696 }
1697
1698 /*!
1699  * \brief OSP Application OSPNext
1700  * \param chan Channel
1701  * \param data Parameter
1702  * \return 0 Success, -1 Failed
1703  */
1704 static int ospnext_exec(
1705         struct ast_channel* chan,
1706         const char * data)
1707 {
1708         int res;
1709         const char* provider = OSP_DEF_PROVIDER;
1710         int cause = 0;
1711         struct varshead* headp;
1712         struct ast_var_t* current;
1713         struct osp_result result;
1714         char buffer[OSP_TOKSTR_SIZE];
1715         unsigned int callidtypes = OSP_CALLID_UNDEFINED;
1716         const char* status;
1717         char* tmp;
1718
1719         AST_DECLARE_APP_ARGS(args,
1720                 AST_APP_ARG(cause);
1721                 AST_APP_ARG(provider);
1722                 AST_APP_ARG(options);
1723         );
1724
1725         if (ast_strlen_zero(data)) {
1726                 ast_log(LOG_WARNING, "OSPNext: Arg required, OSPNext(cause[|provider[|options]])\n");
1727                 return -1;
1728         }
1729
1730         if (!(tmp = ast_strdupa(data))) {
1731                 ast_log(LOG_ERROR, "Out of memory\n");
1732                 return -1;
1733         }
1734
1735         AST_STANDARD_APP_ARGS(args, tmp);
1736
1737         if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%30d", &cause) != 1) {
1738                 cause = 0;
1739         }
1740         ast_debug(1, "OSPNext: cause '%d'\n", cause);
1741
1742         if (!ast_strlen_zero(args.provider)) {
1743                 provider = args.provider;
1744         }
1745         ast_debug(1, "OSPlookup: provider '%s'\n", provider);
1746
1747         result.inhandle = OSP_INVALID_HANDLE;
1748         result.outhandle = OSP_INVALID_HANDLE;
1749         result.intimelimit = OSP_DEF_TIMELIMIT;
1750         result.numresults = 0;
1751
1752         headp = &chan->varshead;
1753         AST_LIST_TRAVERSE(headp, current, entries) {
1754                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1755                         if (sscanf(ast_var_value(current), "%30d", &result.inhandle) != 1) {
1756                                 result.inhandle = OSP_INVALID_HANDLE;
1757                         }
1758                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
1759                         if (sscanf(ast_var_value(current), "%30d", &result.outhandle) != 1) {
1760                                 result.outhandle = OSP_INVALID_HANDLE;
1761                         }
1762                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
1763                         if (sscanf(ast_var_value(current), "%30d", &result.intimelimit) != 1) {
1764                                 result.intimelimit = OSP_DEF_TIMELIMIT;
1765                         }
1766                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTCALLIDTYPES")) {
1767                         if (sscanf(ast_var_value(current), "%30d", &callidtypes) != 1) {
1768                                 callidtypes = OSP_CALLID_UNDEFINED;
1769                         }
1770                 } else if (!strcasecmp(ast_var_name(current), "OSPRESULTS")) {
1771                         if (sscanf(ast_var_value(current), "%30d", &result.numresults) != 1) {
1772                                 result.numresults = 0;
1773                         }
1774                 }
1775         }
1776         ast_debug(1, "OSPNext: OSPINHANDLE '%d'\n", result.inhandle);
1777         ast_debug(1, "OSPNext: OSPOUTHANDLE '%d'\n", result.outhandle);
1778         ast_debug(1, "OSPNext: OSPINTIMELIMIT '%d'\n", result.intimelimit);
1779         ast_debug(1, "OSPNext: OSPOUTCALLIDTYPES '%d'\n", callidtypes);
1780         ast_debug(1, "OSPNext: OSPRESULTS '%d'\n", result.numresults);
1781
1782         if ((res = osp_next(provider, cause, &result)) > 0) {
1783                 status = AST_OSP_SUCCESS;
1784         } else {
1785                 result.tech[0] = '\0';
1786                 result.dest[0] = '\0';
1787                 result.called[0] = '\0';
1788                 result.calling[0] = '\0';
1789                 result.token[0] = '\0';
1790                 result.networkid[0] = '\0';
1791                 result.numresults = 0;
1792                 result.outtimelimit = OSP_DEF_TIMELIMIT;
1793                 result.outcallid.buf[0] = '\0';
1794                 result.outcallid.len = 0;
1795                 if (!res) {
1796                         status = AST_OSP_FAILED;
1797                 } else {
1798                         status = AST_OSP_ERROR;
1799                 }
1800         }
1801
1802         pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
1803         ast_debug(1, "OSPNext: OSPTECH '%s'\n", result.tech);
1804         pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
1805         ast_debug(1, "OSPNext: OSPDEST '%s'\n", result.dest);
1806         pbx_builtin_setvar_helper(chan, "OSPCALLED", result.called);
1807         ast_debug(1, "OSPNext: OSPCALLED'%s'\n", result.called);
1808         pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
1809         ast_debug(1, "OSPNext: OSPCALLING '%s'\n", result.calling);
1810         pbx_builtin_setvar_helper(chan, "OSPOUTNETWORKID", result.networkid);
1811         ast_debug(1, "OSPLookup: OSPOUTNETWORKID '%s'\n", result.networkid);
1812         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
1813         ast_debug(1, "OSPNext: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
1814         snprintf(buffer, sizeof(buffer), "%d", result.numresults);
1815         pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
1816         ast_debug(1, "OSPNext: OSPRESULTS '%s'\n", buffer);
1817         snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
1818         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
1819         ast_debug(1, "OSPNext: OSPOUTTIMELIMIT '%s'\n", buffer);
1820         pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", status);
1821         ast_debug(1, "OSPNext: %s\n", status);
1822
1823         if (!strcasecmp(result.tech, OSP_TECH_H323)) {
1824                 if ((callidtypes & OSP_CALLID_H323) && (result.outcallid.len != 0)) {
1825                         osp_uuid2str(result.outcallid.buf, buffer, sizeof(buffer));
1826                 } else {
1827                         buffer[0] = '\0';
1828                 }
1829                 pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
1830                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1831                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1832         } else if (!strcasecmp(result.tech, OSP_TECH_SIP)) {
1833                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1834                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1835                 if (!ast_strlen_zero(result.token)) {
1836                         snprintf(buffer, sizeof(buffer), "%s%s", OSP_SIP_HEADER, result.token);
1837                         pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
1838                         ast_debug(1, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
1839                 }
1840         } else if (!strcasecmp(result.tech, OSP_TECH_IAX)) {
1841                 snprintf(buffer, sizeof(buffer), "%s/%s/%s", result.tech, result.dest, result.called);
1842                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1843         }
1844
1845         if(res <= 0) {
1846                 res = -1;
1847         } else {
1848                 res = 0;
1849         }
1850
1851         return res;
1852 }
1853
1854 /*!
1855  * \brief OSP Application OSPFinish
1856  * \param chan Channel
1857  * \param data Parameter
1858  * \return 0 Success, -1 Failed
1859  */
1860 static int ospfinished_exec(
1861         struct ast_channel* chan,
1862         const char * data)
1863 {
1864         int res = 1;
1865         int cause = 0;
1866         struct varshead* headp;
1867         struct ast_var_t* current;
1868         int inhandle = OSP_INVALID_HANDLE;
1869         int outhandle = OSP_INVALID_HANDLE;
1870         int recorded = 0;
1871         time_t start, connect, end;
1872         unsigned int release;
1873         char buffer[OSP_INTSTR_SIZE];
1874         const char* status;
1875         char* tmp;
1876
1877         AST_DECLARE_APP_ARGS(args,
1878                 AST_APP_ARG(cause);
1879                 AST_APP_ARG(options);
1880         );
1881
1882         if (!(tmp = ast_strdupa(data))) {
1883                 ast_log(LOG_ERROR, "Out of memory\n");
1884                 return -1;
1885         }
1886
1887         AST_STANDARD_APP_ARGS(args, tmp);
1888
1889         headp = &chan->varshead;
1890         AST_LIST_TRAVERSE(headp, current, entries) {
1891                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1892                         if (sscanf(ast_var_value(current), "%30d", &inhandle) != 1) {
1893                                 inhandle = OSP_INVALID_HANDLE;
1894                         }
1895                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
1896                         if (sscanf(ast_var_value(current), "%30d", &outhandle) != 1) {
1897                                 outhandle = OSP_INVALID_HANDLE;
1898                         }
1899                 } else if (!recorded &&
1900                         (!strcasecmp(ast_var_name(current), "OSPAUTHSTATUS") ||
1901                         !strcasecmp(ast_var_name(current), "OSPLOOKUPSTATUS") ||
1902                         !strcasecmp(ast_var_name(current), "OSPNEXTSTATUS")))
1903                 {
1904                         if (strcasecmp(ast_var_value(current), AST_OSP_SUCCESS)) {
1905                                 recorded = 1;
1906                         }
1907                 }
1908         }
1909         ast_debug(1, "OSPFinish: OSPINHANDLE '%d'\n", inhandle);
1910         ast_debug(1, "OSPFinish: OSPOUTHANDLE '%d'\n", outhandle);
1911         ast_debug(1, "OSPFinish: recorded '%d'\n", recorded);
1912
1913         if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%30d", &cause) != 1) {
1914                 cause = 0;
1915         }
1916         ast_debug(1, "OSPFinish: cause '%d'\n", cause);
1917
1918         if (chan->cdr) {
1919                 start = chan->cdr->start.tv_sec;
1920                 connect = chan->cdr->answer.tv_sec;
1921                 if (connect) {
1922                         end = time(NULL);
1923                 } else {
1924                         end = connect;
1925                 }
1926         } else {
1927                 start = 0;
1928                 connect = 0;
1929                 end = 0;
1930         }
1931         ast_debug(1, "OSPFinish: start '%ld'\n", start);
1932         ast_debug(1, "OSPFinish: connect '%ld'\n", connect);
1933         ast_debug(1, "OSPFinish: end '%ld'\n", end);
1934
1935         release = ast_check_hangup(chan) ? 0 : 1;
1936
1937         if (osp_finish(outhandle, recorded, cause, start, connect, end, release) <= 0) {
1938                 ast_debug(1, "OSPFinish: Unable to report usage for outbound call\n");
1939         }
1940         switch (cause) {
1941         case AST_CAUSE_NORMAL_CLEARING:
1942                 break;
1943         default:
1944                 cause = AST_CAUSE_NO_ROUTE_DESTINATION;
1945                 break;
1946         }
1947         if (osp_finish(inhandle, recorded, cause, start, connect, end, release) <= 0) {
1948                 ast_debug(1, "OSPFinish: Unable to report usage for inbound call\n");
1949         }
1950         snprintf(buffer, sizeof(buffer), "%d", OSP_INVALID_HANDLE);
1951         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
1952         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
1953
1954         if (res > 0) {
1955                 status = AST_OSP_SUCCESS;
1956         } else if (!res) {
1957                 status = AST_OSP_FAILED;
1958         } else {
1959                 status = AST_OSP_ERROR;
1960         }
1961         pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", status);
1962
1963         if(!res) {
1964                 res = -1;
1965         } else {
1966                 res = 0;
1967         }
1968
1969         return res;
1970 }
1971
1972 /* OSP Module APIs */
1973
1974 static int osp_unload(void);
1975 static int osp_load(int reload)
1976 {
1977         const char* t;
1978         unsigned int v;
1979         struct ast_config* cfg;
1980         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1981         int error = OSPC_ERR_NO_ERROR;
1982
1983         if ((cfg = ast_config_load(OSP_CONFIG_FILE, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
1984                 return 0;
1985         } else if (cfg == CONFIG_STATUS_FILEINVALID) {
1986                 ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", OSP_CONFIG_FILE);
1987                 return 0;
1988         }
1989
1990         if (cfg) {
1991                 if (reload)
1992                         osp_unload();
1993
1994                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "accelerate");
1995                 if (t && ast_true(t)) {
1996                         if ((error = OSPPInit(1)) != OSPC_ERR_NO_ERROR) {
1997                                 ast_log(LOG_WARNING, "OSP: Unable to enable hardware accelleration\n");
1998                                 OSPPInit(0);
1999                         } else {
2000                                 osp_hardware = 1;
2001                         }
2002                 } else {
2003                         OSPPInit(0);
2004                 }
2005                 ast_debug(1, "OSP: osp_hardware '%d'\n", osp_hardware);
2006
2007                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "securityfeatures");
2008                 if (t && ast_true(t)) {
2009                         osp_security = 1;
2010                 }
2011                 ast_debug(1, "OSP: osp_security '%d'\n", osp_security);
2012
2013                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat");
2014                 if (t) {
2015                         if ((sscanf(t, "%30d", &v) == 1) &&
2016                                 ((v == TOKEN_ALGO_SIGNED) || (v == TOKEN_ALGO_UNSIGNED) || (v == TOKEN_ALGO_BOTH)))
2017                         {
2018                                 osp_tokenformat = v;
2019                         } else {
2020                                 ast_log(LOG_WARNING, "tokenformat should be an integer from %d, %d or %d, not '%s'\n",
2021                                         TOKEN_ALGO_SIGNED, TOKEN_ALGO_UNSIGNED, TOKEN_ALGO_BOTH, t);
2022                         }
2023                 }
2024                 ast_debug(1, "OSP: osp_tokenformat '%d'\n", osp_tokenformat);
2025
2026                 t = ast_category_browse(cfg, NULL);
2027                 while(t) {
2028                         if (strcasecmp(t, OSP_GENERAL_CAT)) {
2029                                 osp_create_provider(cfg, t);
2030                         }
2031                         t = ast_category_browse(cfg, t);
2032                 }
2033
2034                 osp_initialized = 1;
2035
2036                 ast_config_destroy(cfg);
2037         } else {
2038                 ast_log(LOG_WARNING, "OSP: Unable to find configuration. OSP support disabled\n");
2039                 return 0;
2040         }
2041         ast_debug(1, "OSP: osp_initialized '%d'\n", osp_initialized);
2042
2043         return 1;
2044 }
2045
2046 static int osp_unload(void)
2047 {
2048         struct osp_provider* p;
2049         struct osp_provider* next;
2050
2051         if (osp_initialized) {
2052                 ast_mutex_lock(&osplock);
2053                 p = ospproviders;
2054                 while(p) {
2055                         next = p->next;
2056                         OSPPProviderDelete(p->handle, 0);
2057                         ast_free(p);
2058                         p = next;
2059                 }
2060                 ospproviders = NULL;
2061                 ast_mutex_unlock(&osplock);
2062
2063                 OSPPCleanup();
2064
2065                 osp_tokenformat = TOKEN_ALGO_SIGNED;
2066                 osp_security = 0;
2067                 osp_hardware = 0;
2068                 osp_initialized = 0;
2069         }
2070         return 0;
2071 }
2072
2073 static char *handle_cli_osp_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2074 {
2075         int i;
2076         int found = 0;
2077         struct osp_provider* p;
2078         const char* provider = NULL;
2079         const char* tokenalgo;
2080
2081         switch (cmd) {
2082         case CLI_INIT:
2083                 e->command = "osp show";
2084                 e->usage =
2085                         "Usage: osp show\n"
2086                         "       Displays information on Open Settlement Protocol support\n";
2087                 return NULL;
2088         case CLI_GENERATE:
2089                 return NULL;
2090         }
2091
2092         if ((a->argc < 2) || (a->argc > 3))
2093                 return CLI_SHOWUSAGE;
2094         if (a->argc > 2) 
2095                 provider = a->argv[2];
2096         if (!provider) {
2097                 switch (osp_tokenformat) {
2098                 case TOKEN_ALGO_BOTH:
2099                         tokenalgo = "Both";
2100                         break;
2101                 case TOKEN_ALGO_UNSIGNED:
2102                         tokenalgo = "Unsigned";
2103                         break;
2104                 case TOKEN_ALGO_SIGNED:
2105                 default:
2106                         tokenalgo = "Signed";
2107                         break;
2108                 }
2109                 ast_cli(a->fd, "OSP: %s/%s/%s/%s\n",
2110                         osp_initialized ? "Initialized" : "Uninitialized", 
2111                         osp_hardware ? "Accelerated" : "Normal", 
2112                         osp_security ? "Enabled" : "Disabled", 
2113                         tokenalgo);
2114         }
2115
2116         ast_mutex_lock(&osplock);
2117         p = ospproviders;
2118         while(p) {
2119                 if (!provider || !strcasecmp(p->name, provider)) {
2120                         if (found) {
2121                                 ast_cli(a->fd, "\n");
2122                         }
2123                         ast_cli(a->fd, " == OSP Provider '%s' == \n", p->name);
2124                         if (osp_security) {
2125                                 ast_cli(a->fd, "Local Private Key: %s\n", p->privatekey);
2126                                 ast_cli(a->fd, "Local Certificate: %s\n", p->localcert);
2127                                 for (i = 0; i < p->cacount; i++) {
2128                                         ast_cli(a->fd, "CA Certificate %d:  %s\n", i + 1, p->cacerts[i]);
2129                                 }
2130                         }
2131                         for (i = 0; i < p->spcount; i++) {
2132                                 ast_cli(a->fd, "Service Point %d:   %s\n", i + 1, p->srvpoints[i]);
2133                         }
2134                         ast_cli(a->fd, "Max Connections:   %d\n", p->maxconnections);
2135                         ast_cli(a->fd, "Retry Delay:       %d seconds\n", p->retrydelay);
2136                         ast_cli(a->fd, "Retry Limit:       %d\n", p->retrylimit);
2137                         ast_cli(a->fd, "Timeout:           %d milliseconds\n", p->timeout);
2138                         ast_cli(a->fd, "Source:            %s\n", strlen(p->source) ? p->source : "<unspecified>");
2139                         ast_cli(a->fd, "Auth Policy        %d\n", p->authpolicy);
2140                         ast_cli(a->fd, "Default protocol   %s\n", p->defaultprotocol);
2141                         ast_cli(a->fd, "OSP Handle:        %d\n", p->handle);
2142                         found++;
2143                 }
2144                 p = p->next;
2145         }
2146         ast_mutex_unlock(&osplock);
2147
2148         if (!found) {
2149                 if (provider) {
2150                         ast_cli(a->fd, "Unable to find OSP provider '%s'\n", provider);
2151                 } else {
2152                         ast_cli(a->fd, "No OSP providers configured\n");
2153                 }
2154         }
2155         return CLI_SUCCESS;
2156 }
2157
2158 /* OSPAuth() dialplan application */
2159 static const char app1[] = "OSPAuth";
2160
2161 /* OSPLookup() dialplan application */
2162 static const char app2[] = "OSPLookup";
2163
2164 /* OSPNext() dialplan application */
2165 static const char app3[] = "OSPNext";
2166
2167 /* OSPFinish() dialplan application */
2168 static const char app4[] = "OSPFinish";
2169
2170 static struct ast_cli_entry cli_osp[] = {
2171         AST_CLI_DEFINE(handle_cli_osp_show, "Displays OSF information")
2172 };
2173
2174 static int load_module(void)
2175 {
2176         int res;
2177
2178         if (!osp_load(0))
2179                 return AST_MODULE_LOAD_DECLINE;
2180
2181         ast_cli_register_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
2182         res = ast_register_application_xml(app1, ospauth_exec);
2183         res |= ast_register_application_xml(app2, osplookup_exec);
2184         res |= ast_register_application_xml(app3, ospnext_exec);
2185         res |= ast_register_application_xml(app4, ospfinished_exec);
2186
2187         return res;
2188 }
2189
2190 static int unload_module(void)
2191 {
2192         int res;
2193
2194         res = ast_unregister_application(app4);
2195         res |= ast_unregister_application(app3);
2196         res |= ast_unregister_application(app2);
2197         res |= ast_unregister_application(app1);
2198         ast_cli_unregister_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
2199         osp_unload();
2200
2201         return res;
2202 }
2203
2204 static int reload(void)
2205 {
2206         osp_load(1);
2207
2208         return 0;
2209 }
2210
2211 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Open Settlement Protocol Applications",
2212         .load = load_module,
2213         .unload = unload_module,
2214         .reload = reload,
2215 );