simplify autoconfig include mechanism (make tholo happy he can use lint again :-)
[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 Applications
22  *
23  * \author Mark Spencer <markster@digium.com>
24  * 
25  * \ingroup applications
26  */
27
28 /*** MODULEINFO
29         <depend>libosptk</depend>
30         <depend>ssl</depend>
31  ***/
32
33 #include "asterisk.h"
34
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <ctype.h>
42
43 #include "asterisk/lock.h"
44 #include "asterisk/file.h"
45 #include "asterisk/logger.h"
46 #include "asterisk/channel.h"
47 #include "asterisk/pbx.h"
48 #include "asterisk/options.h"
49 #include "asterisk/config.h"
50 #include "asterisk/module.h"
51 #include "asterisk/utils.h"
52 #include "asterisk/causes.h"
53 #include "asterisk/astosp.h"
54 #include "asterisk/app.h"
55 #include "asterisk/options.h"
56
57 static char *app1= "OSPAuth";
58 static char *synopsis1 = "OSP authentication";
59 static char *descrip1 = 
60 "  OSPAuth([provider[|options]]):  Authenticate a SIP INVITE by OSP and sets\n"
61 "the variables:\n"
62 " ${OSPINHANDLE}:  The in_bound call transaction handle\n"
63 " ${OSPINTIMELIMIT}:  The in_bound call duration limit in seconds\n"
64 "\n"
65 "The option string may contain the following character:\n"
66 "       'j' -- jump to n+101 priority if the authentication was NOT successful\n"
67 "This application sets the following channel variable upon completion:\n"
68 "       OSPAUTHSTATUS   The status of the OSP Auth attempt as a text string, one of\n"
69 "               SUCCESS | FAILED | ERROR\n";
70
71 static char *app2= "OSPLookup";
72 static char *synopsis2 = "Lookup destination by OSP";
73 static char *descrip2 = 
74 "  OSPLookup(exten[|provider[|options]]):  Looks up an extension via OSP and sets\n"
75 "the variables, where 'n' is the number of the result beginning with 1:\n"
76 " ${OSPOUTHANDLE}:  The OSP Handle for anything remaining\n"
77 " ${OSPTECH}:  The technology to use for the call\n"
78 " ${OSPDEST}:  The destination to use for the call\n"
79 " ${OSPCALLING}:  The calling number to use for the call\n"
80 " ${OSPOUTTOKEN}:  The actual OSP token as a string\n"
81 " ${OSPOUTTIMELIMIT}:  The out_bound call duration limit in seconds\n"
82 " ${OSPRESULTS}:  The number of OSP results total remaining\n"
83 "\n"
84 "The option string may contain the following character:\n"
85 "       'j' -- jump to n+101 priority if the lookup was NOT successful\n"
86 "This application sets the following channel variable upon completion:\n"
87 "       OSPLOOKUPSTATUS The status of the OSP Lookup attempt as a text string, one of\n"
88 "               SUCCESS | FAILED | ERROR\n";
89
90 static char *app3 = "OSPNext";
91 static char *synopsis3 = "Lookup next destination by OSP";
92 static char *descrip3 = 
93 "  OSPNext(cause[|options]):  Looks up the next OSP Destination for ${OSPOUTHANDLE}\n"
94 "See OSPLookup for more information\n"
95 "\n"
96 "The option string may contain the following character:\n"
97 "       'j' -- jump to n+101 priority if the lookup was NOT successful\n"
98 "This application sets the following channel variable upon completion:\n"
99 "       OSPNEXTSTATUS   The status of the OSP Next attempt as a text string, one of\n"
100 "               SUCCESS | FAILED |ERROR\n";
101
102 static char *app4 = "OSPFinish";
103 static char *synopsis4 = "Record OSP entry";
104 static char *descrip4 = 
105 "  OSPFinish([status[|options]]):  Records call state for ${OSPINHANDLE}, according to\n"
106 "status, which should be one of BUSY, CONGESTION, ANSWER, NOANSWER, or CHANUNAVAIL\n"
107 "or coincidentally, just what the Dial application stores in its ${DIALSTATUS}.\n"
108 "\n"
109 "The option string may contain the following character:\n"
110 "       'j' -- jump to n+101 priority if the finish attempt was NOT successful\n"
111 "This application sets the following channel variable upon completion:\n"
112 "       OSPFINISHSTATUS The status of the OSP Finish attempt as a text string, one of\n"
113 "               SUCCESS | FAILED |ERROR \n";
114
115 LOCAL_USER_DECL;
116
117 static int ospauth_exec(struct ast_channel *chan, void *data)
118 {
119         int res = 0;
120         struct localuser* u;
121         char* provider = OSP_DEF_PROVIDER;
122         int priority_jump = 0;
123         struct varshead* headp;
124         struct ast_var_t* current;
125         const char* source = "";
126         const char* token = "";
127         int handle;
128         unsigned int timelimit;
129         char* tmp;
130         char buffer[OSP_INTSTR_SIZE];
131         char* status;
132
133         AST_DECLARE_APP_ARGS(args,
134                 AST_APP_ARG(provider);
135                 AST_APP_ARG(options);
136         );
137
138         LOCAL_USER_ADD(u);
139
140         tmp = ast_strdupa(data);
141
142         AST_STANDARD_APP_ARGS(args, tmp);
143
144         if (!ast_strlen_zero(args.provider)) {
145                 provider = args.provider;
146         }
147         ast_log(LOG_DEBUG, "OSPAuth: provider '%s'\n", provider);
148
149         if (args.options) {
150                 if (strchr(args.options, 'j')) {
151                         priority_jump = 1;
152                 }
153         }
154         ast_log(LOG_DEBUG, "OSPAuth: priority jump '%d'\n", priority_jump);
155
156         headp = &chan->varshead;
157         AST_LIST_TRAVERSE(headp, current, entries) {
158                 if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
159                         source = ast_var_value(current);
160                 } else if (!strcasecmp(ast_var_name(current), "OSPINTOKEN")) {
161                         token = ast_var_value(current);
162                 }
163         }
164         ast_log(LOG_DEBUG, "OSPAuth: source '%s'\n", source);
165         ast_log(LOG_DEBUG, "OSPAuth: token size '%d'\n", strlen(token));
166
167         res = ast_osp_auth(provider, &handle, source, chan->cid.cid_num, chan->exten, token, &timelimit);
168         if (res > 0) {
169                 status = OSP_APP_SUCCESS;
170         } else {
171                 timelimit = OSP_DEF_TIMELIMIT;
172                 if (!res) {
173                         status = OSP_APP_FAILED;
174                 } else {
175                         handle = OSP_INVALID_HANDLE;
176                         status = OSP_APP_ERROR;
177                 }
178         }
179
180         snprintf(buffer, sizeof(buffer), "%d", handle);
181         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
182         ast_log(LOG_DEBUG, "OSPAuth: OSPINHANDLE '%s'\n", buffer);
183         snprintf(buffer, sizeof(buffer), "%d", timelimit);
184         pbx_builtin_setvar_helper(chan, "OSPINTIMELIMIT", buffer);
185         ast_log(LOG_DEBUG, "OSPAuth: OSPINTIMELIMIT '%s'\n", buffer);
186         pbx_builtin_setvar_helper(chan, "OSPAUTHSTATUS", status);
187         ast_log(LOG_DEBUG, "OSPAuth: %s\n", status);
188
189         if(!res) {
190                 if (priority_jump || ast_opt_priority_jumping) {
191                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
192                 } else {
193                         res = -1;
194                 }
195         } else if (res > 0) {
196                 res = 0;
197         }
198
199         LOCAL_USER_REMOVE(u);
200
201         return(res);
202 }
203
204 static int osplookup_exec(struct ast_channel *chan, void *data)
205 {
206         int res = 0;
207         struct localuser* u;
208         char* provider = OSP_DEF_PROVIDER;
209         int priority_jump = 0;
210         struct varshead* headp;
211         struct ast_var_t* current;
212         const char* srcdev = "";
213         char* tmp;
214         char buffer[OSP_TOKSTR_SIZE];
215         struct ast_osp_result result;
216         char* status;
217
218         AST_DECLARE_APP_ARGS(args,
219                 AST_APP_ARG(exten);
220                 AST_APP_ARG(provider);
221                 AST_APP_ARG(options);
222         );
223         
224         if (ast_strlen_zero(data)) {
225                 ast_log(LOG_WARNING, "OSPLookup: Arg required, OSPLookup(exten[|provider[|options]])\n");
226                 return(-1);
227         }
228
229         LOCAL_USER_ADD(u);
230
231         tmp = ast_strdupa(data);
232
233         AST_STANDARD_APP_ARGS(args, tmp);
234
235         ast_log(LOG_DEBUG, "OSPLookup: exten '%s'\n", args.exten);
236
237         if (!ast_strlen_zero(args.provider)) {
238                 provider = args.provider;
239         }
240         ast_log(LOG_DEBUG, "OSPlookup: provider '%s'\n", provider);
241
242         if (args.options) {
243                 if (strchr(args.options, 'j')) {
244                         priority_jump = 1;
245                 }
246         }
247         ast_log(LOG_DEBUG, "OSPLookup: priority jump '%d'\n", priority_jump);
248
249         result.inhandle = OSP_INVALID_HANDLE;
250
251         headp = &chan->varshead;
252         AST_LIST_TRAVERSE(headp, current, entries) {
253                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
254                         if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
255                                 result.inhandle = OSP_INVALID_HANDLE;
256                         }
257                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
258                         if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
259                                 result.intimelimit = OSP_DEF_TIMELIMIT;
260                         }
261                 } else if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
262                         srcdev = ast_var_value(current);
263                 }
264         }
265         ast_log(LOG_DEBUG, "OSPLookup: OSPINHANDLE '%d'\n", result.inhandle);
266         ast_log(LOG_DEBUG, "OSPLookup: OSPINTIMELIMIT '%d'\n", result.intimelimit);
267         ast_log(LOG_DEBUG, "OSPLookup: source device '%s'\n", srcdev);
268
269         res = ast_osp_lookup(provider, srcdev, chan->cid.cid_num, args.exten, &result);
270         if (res > 0) {
271                 status = OSP_APP_SUCCESS;
272         } else {
273                 result.tech[0] = '\0';
274                 result.dest[0] = '\0';
275                 result.calling[0] = '\0';
276                 result.token[0] = '\0'; 
277                 result.numresults = 0;
278                 result.outtimelimit = OSP_DEF_TIMELIMIT;
279                 if (!res) {
280                         status = OSP_APP_FAILED;
281                 } else {
282                         result.outhandle = OSP_INVALID_HANDLE;
283                         status = OSP_APP_ERROR;
284                 }
285         }
286
287         snprintf(buffer, sizeof(buffer), "%d", result.outhandle);
288         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
289         ast_log(LOG_DEBUG, "OSPLookup: OSPOUTHANDLE '%s'\n", buffer);
290         pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
291         ast_log(LOG_DEBUG, "OSPLookup: OSPTECH '%s'\n", result.tech);
292         pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
293         ast_log(LOG_DEBUG, "OSPLookup: OSPDEST '%s'\n", result.dest);
294         pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
295         ast_log(LOG_DEBUG, "OSPLookup: OSPCALLING '%s'\n", result.calling);
296         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
297         ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTOKEN size '%d'\n", strlen(result.token));
298         if (!ast_strlen_zero(result.token)) {
299                 snprintf(buffer, sizeof(buffer), "P-OSP-Auth-Token: %s", result.token);
300                 pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
301                 ast_log(LOG_DEBUG, "OSPLookup: SIPADDHEADER size '%d'\n", strlen(buffer));
302         }
303         snprintf(buffer, sizeof(buffer), "%d", result.numresults);
304         pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
305         ast_log(LOG_DEBUG, "OSPLookup: OSPRESULTS '%s'\n", buffer);
306         snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
307         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
308         ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTIMELIMIT '%s'\n", buffer);
309         pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", status);
310         ast_log(LOG_DEBUG, "OSPLookup: %s\n", status);
311
312         if(!res) {
313                 if (priority_jump || ast_opt_priority_jumping) {
314                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
315                 } else {
316                         res = -1;
317                 }
318         } else if (res > 0) {
319                 res = 0;
320         }
321
322         LOCAL_USER_REMOVE(u);
323
324         return(res);
325 }
326
327 static int str2cause(char *str)
328 {
329         int cause = AST_CAUSE_NORMAL;
330
331         if (ast_strlen_zero(str)) {
332                 cause = AST_CAUSE_NOTDEFINED;
333         } else if (!strcasecmp(str, "BUSY")) {
334                 cause = AST_CAUSE_BUSY;
335         } else if (!strcasecmp(str, "CONGESTION")) {
336                 cause = AST_CAUSE_CONGESTION;
337         } else if (!strcasecmp(str, "ANSWER")) {
338                 cause = AST_CAUSE_NORMAL;
339         } else if (!strcasecmp(str, "CANCEL")) {
340                 cause = AST_CAUSE_NORMAL;
341         } else if (!strcasecmp(str, "NOANSWER")) {
342                 cause = AST_CAUSE_NOANSWER;
343         } else if (!strcasecmp(str, "NOCHANAVAIL")) {
344                 cause = AST_CAUSE_CONGESTION;
345         } else {
346                 ast_log(LOG_WARNING, "OSP: Unknown cause '%s', using NORMAL\n", str);
347         }
348
349         return(cause);
350 }
351
352 static int ospnext_exec(struct ast_channel *chan, void *data)
353 {
354         int res=0;
355         struct localuser *u;
356         int priority_jump = 0;
357         int cause;
358         struct varshead* headp;
359         struct ast_var_t* current;
360         struct ast_osp_result result;
361         char *tmp;
362         char buffer[OSP_TOKSTR_SIZE];
363         char* status;
364
365         AST_DECLARE_APP_ARGS(args,
366                 AST_APP_ARG(cause);
367                 AST_APP_ARG(options);
368         );
369         
370         if (ast_strlen_zero(data)) {
371                 ast_log(LOG_WARNING, "OSPNext: Arg required, OSPNext(cause[|options])\n");
372                 return(-1);
373         }
374
375         LOCAL_USER_ADD(u);
376
377         tmp = ast_strdupa(data);
378
379         AST_STANDARD_APP_ARGS(args, tmp);
380
381         cause = str2cause(args.cause);
382         ast_log(LOG_DEBUG, "OSPNext: cause '%d'\n", cause);
383
384         if (args.options) {
385                 if (strchr(args.options, 'j'))
386                         priority_jump = 1;
387         }
388         ast_log(LOG_DEBUG, "OSPNext: priority jump '%d'\n", priority_jump);
389
390         result.inhandle = OSP_INVALID_HANDLE;
391         result.outhandle = OSP_INVALID_HANDLE;
392         result.numresults = 0;
393
394         headp = &chan->varshead;
395         AST_LIST_TRAVERSE(headp, current, entries) {
396                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
397                         if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
398                                 result.inhandle = OSP_INVALID_HANDLE;
399                         }
400                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
401                         if (sscanf(ast_var_value(current), "%d", &result.outhandle) != 1) {
402                                 result.outhandle = OSP_INVALID_HANDLE;
403                         }
404                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMEOUT")) {
405                         if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
406                                 result.intimelimit = OSP_DEF_TIMELIMIT;
407                         }
408                 } else if (!strcasecmp(ast_var_name(current), "OSPRESULTS")) {
409                         if (sscanf(ast_var_value(current), "%d", &result.numresults) != 1) {
410                                 result.numresults = 0;
411                         }
412                 }
413         }
414         ast_log(LOG_DEBUG, "OSPNext: OSPINHANDLE '%d'\n", result.inhandle);
415         ast_log(LOG_DEBUG, "OSPNext: OSPOUTHANDLE '%d'\n", result.outhandle);
416         ast_log(LOG_DEBUG, "OSPNext: OSPINTIMELIMIT '%d'\n", result.intimelimit);
417         ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%d'\n", result.numresults);
418
419         if ((res = ast_osp_next(cause, &result)) > 0) {
420                 status = OSP_APP_SUCCESS;
421         } else {
422                 result.tech[0] = '\0';
423                 result.dest[0] = '\0';
424                 result.calling[0] = '\0';
425                 result.token[0] = '\0'; 
426                 result.numresults = 0;
427                 result.outtimelimit = OSP_DEF_TIMELIMIT;
428                 if (!res) {
429                         status = OSP_APP_FAILED;
430                 } else {
431                         result.outhandle = OSP_INVALID_HANDLE;
432                         status = OSP_APP_ERROR;
433                 }
434         }
435
436         pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
437         ast_log(LOG_DEBUG, "OSPNext: OSPTECH '%s'\n", result.tech);
438         pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
439         ast_log(LOG_DEBUG, "OSPNext: OSPDEST '%s'\n", result.dest);
440         pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
441         ast_log(LOG_DEBUG, "OSPNext: OSPCALLING '%s'\n", result.calling);
442         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
443         ast_log(LOG_DEBUG, "OSPNext: OSPOUTTOKEN size '%d'\n", strlen(result.token));
444         if (!ast_strlen_zero(result.token)) {
445                 snprintf(buffer, sizeof(buffer), "P-OSP-Auth-Token: %s", result.token);
446                 pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
447                 ast_log(LOG_DEBUG, "OSPNext: SIPADDHEADER size '%d'\n", strlen(buffer));
448         }
449         snprintf(buffer, sizeof(buffer), "%d", result.numresults);
450         pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
451         ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%s'\n", buffer);
452         snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
453         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
454         ast_log(LOG_DEBUG, "OSPNext: OSPOUTTIMELIMIT '%s'\n", buffer);
455         pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", status);
456         ast_log(LOG_DEBUG, "OSPNext: %s\n", status);
457
458         if(!res) {
459                 if (priority_jump || ast_opt_priority_jumping) {
460                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
461                 } else {
462                         res = -1;
463                 }
464         } else if (res > 0) {
465                 res = 0;
466         }
467
468         LOCAL_USER_REMOVE(u);
469
470         return(res);
471 }
472
473 static int ospfinished_exec(struct ast_channel *chan, void *data)
474 {
475         int res = 1;
476         struct localuser* u;
477         int priority_jump = 0;
478         int cause;
479         struct varshead* headp;
480         struct ast_var_t* current;
481         int inhandle = OSP_INVALID_HANDLE;
482         int outhandle = OSP_INVALID_HANDLE;
483         int recorded = 0;
484         time_t start, connect, end;
485         char* tmp;
486         char* str = "";
487         char buffer[OSP_INTSTR_SIZE];
488         char* status;
489
490         AST_DECLARE_APP_ARGS(args,
491                 AST_APP_ARG(status);
492                 AST_APP_ARG(options);
493         );
494         
495         LOCAL_USER_ADD(u);
496
497         tmp = ast_strdupa(data);
498
499         AST_STANDARD_APP_ARGS(args, tmp);
500
501         if (args.options) {
502                 if (strchr(args.options, 'j'))
503                         priority_jump = 1;
504         }
505         ast_log(LOG_DEBUG, "OSPFinish: priority jump '%d'\n", priority_jump);
506
507         headp = &chan->varshead;
508         AST_LIST_TRAVERSE(headp, current, entries) {
509                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
510                         if (sscanf(ast_var_value(current), "%d", &inhandle) != 1) {
511                                 inhandle = OSP_INVALID_HANDLE;
512                         }
513                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
514                         if (sscanf(ast_var_value(current), "%d", &outhandle) != 1) {
515                                 outhandle = OSP_INVALID_HANDLE;
516                         }
517                 } else if (!recorded &&
518                         (!strcasecmp(ast_var_name(current), "OSPAUTHSTATUS") ||
519                         !strcasecmp(ast_var_name(current), "OSPLOOKUPSTATUS") || 
520                         !strcasecmp(ast_var_name(current), "OSPNEXTSTATUS"))) 
521                 {
522                         if (strcasecmp(ast_var_value(current), OSP_APP_SUCCESS)) {
523                                 recorded = 1;
524                         }
525                 }
526         }
527         ast_log(LOG_DEBUG, "OSPFinish: OSPINHANDLE '%d'\n", inhandle);
528         ast_log(LOG_DEBUG, "OSPFinish: OSPOUTHANDLE '%d'\n", outhandle);
529         ast_log(LOG_DEBUG, "OSPFinish: recorded '%d'\n", recorded);
530
531         if (!recorded) {
532                 str = args.status;
533         }
534         cause = str2cause(str);
535         ast_log(LOG_DEBUG, "OSPFinish: cause '%d'\n", cause);
536
537         if (chan->cdr) {
538                 start = chan->cdr->start.tv_sec;
539                 connect = chan->cdr->answer.tv_sec;
540                 if (connect) {
541                         end = time(NULL);
542                 } else {
543                         end = connect;
544                 }
545         } else {
546                 start = 0;
547                 connect = 0;
548                 end = 0;
549         }
550         ast_log(LOG_DEBUG, "OSPFinish: start '%ld'\n", start);
551         ast_log(LOG_DEBUG, "OSPFinish: connect '%ld'\n", connect);
552         ast_log(LOG_DEBUG, "OSPFinish: end '%ld'\n", end);
553
554         if (ast_osp_finish(outhandle, cause, start, connect, end) <= 0) {
555                 ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for out_bound call\n");
556         }
557         if (ast_osp_finish(inhandle, cause, start, connect, end) <= 0) {
558                 ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for in_bound call\n");
559         }
560         snprintf(buffer, sizeof(buffer), "%d", OSP_INVALID_HANDLE);
561         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
562         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
563
564         if (res > 0) {
565                 status = OSP_APP_SUCCESS;
566         } else if (!res) {
567                 status = OSP_APP_FAILED;
568         } else {
569                 status = OSP_APP_ERROR;
570         }
571         pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", status);
572
573         if(!res) {
574                 if (priority_jump || ast_opt_priority_jumping) {
575                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
576                 } else {
577                         res = -1;
578                 }
579         } else if (res > 0) {
580                 res = 0;
581         }
582
583         LOCAL_USER_REMOVE(u);
584
585         return(res);
586 }
587
588 static int load_module(void *mod)
589 {
590         int res;
591         
592         ast_osp_adduse();
593
594         res = ast_register_application(app1, ospauth_exec, synopsis1, descrip1);
595         res |= ast_register_application(app2, osplookup_exec, synopsis2, descrip2);
596         res |= ast_register_application(app3, ospnext_exec, synopsis3, descrip3);
597         res |= ast_register_application(app4, ospfinished_exec, synopsis4, descrip4);
598
599         return(res);
600 }
601
602 static int unload_module(void *mod)
603 {
604         int res;
605         
606         res = ast_unregister_application(app4);
607         res |= ast_unregister_application(app3);
608         res |= ast_unregister_application(app2);
609         res |= ast_unregister_application(app1);
610
611         STANDARD_HANGUP_LOCALUSERS;
612
613         ast_osp_deluse();
614
615         return(res);
616 }
617
618 static const char *description(void)
619 {
620         return "Open Settlement Protocol Applications";
621 }
622
623 static const char *key(void)
624 {
625         return(ASTERISK_GPL_KEY);
626 }
627
628 STD_MOD1;
629
630