Merge "Bridge system: Fix memory leaks and double frees on impart failure."
[asterisk/asterisk.git] / funcs / func_odbc.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (c) 2005, 2006 Tilghman Lesher
5  * Copyright (c) 2008, 2009 Digium, Inc.
6  *
7  * Tilghman Lesher <func_odbc__200508@the-tilghman.com>
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
19
20 /*!
21  * \file
22  *
23  * \brief ODBC lookups
24  *
25  * \author Tilghman Lesher <func_odbc__200508@the-tilghman.com>
26  *
27  * \ingroup functions
28  */
29
30 /*** MODULEINFO
31         <depend>res_odbc</depend>
32         <support_level>core</support_level>
33  ***/
34
35 #include "asterisk.h"
36
37 ASTERISK_REGISTER_FILE()
38
39 #include "asterisk/module.h"
40 #include "asterisk/file.h"
41 #include "asterisk/channel.h"
42 #include "asterisk/pbx.h"
43 #include "asterisk/config.h"
44 #include "asterisk/res_odbc.h"
45 #include "asterisk/res_odbc_transaction.h"
46 #include "asterisk/app.h"
47 #include "asterisk/cli.h"
48 #include "asterisk/strings.h"
49
50 /*** DOCUMENTATION
51         <function name="ODBC_FETCH" language="en_US">
52                 <synopsis>
53                         Fetch a row from a multirow query.
54                 </synopsis>
55                 <syntax>
56                         <parameter name="result-id" required="true" />
57                 </syntax>
58                 <description>
59                         <para>For queries which are marked as mode=multirow, the original 
60                         query returns a <replaceable>result-id</replaceable> from which results 
61                         may be fetched.  This function implements the actual fetch of the results.</para>
62                         <para>This also sets <variable>ODBC_FETCH_STATUS</variable>.</para>
63                         <variablelist>
64                                 <variable name="ODBC_FETCH_STATUS">
65                                         <value name="SUCESS">
66                                                 If rows are available.
67                                         </value>
68                                         <value name="FAILURE">
69                                                 If no rows are available.
70                                         </value>
71                                 </variable>
72                         </variablelist>
73                 </description>
74         </function>
75         <application name="ODBCFinish" language="en_US">
76                 <synopsis>
77                         Clear the resultset of a sucessful multirow query.
78                 </synopsis>
79                 <syntax>
80                         <parameter name="result-id" required="true" />
81                 </syntax>
82                 <description>
83                         <para>For queries which are marked as mode=multirow, this will clear 
84                         any remaining rows of the specified resultset.</para>
85                 </description>
86         </application>
87         <function name="SQL_ESC" language="en_US">
88                 <synopsis>
89                         Escapes single ticks for use in SQL statements.
90                 </synopsis>
91                 <syntax>
92                         <parameter name="string" required="true" />
93                 </syntax>
94                 <description>
95                         <para>Used in SQL templates to escape data which may contain single ticks 
96                         <literal>'</literal> which are otherwise used to delimit data.</para>
97                         <para>Example: SELECT foo FROM bar WHERE baz='${SQL_ESC(${ARG1})}'</para>
98                 </description>
99         </function>
100  ***/
101
102 static char *config = "func_odbc.conf";
103
104 enum odbc_option_flags {
105         OPT_ESCAPECOMMAS =      (1 << 0),
106         OPT_MULTIROW     =      (1 << 1),
107 };
108
109 struct acf_odbc_query {
110         AST_RWLIST_ENTRY(acf_odbc_query) list;
111         char readhandle[5][30];
112         char writehandle[5][30];
113         char *sql_read;
114         char *sql_write;
115         char *sql_insert;
116         unsigned int flags;
117         int rowlimit;
118         struct ast_custom_function *acf;
119 };
120
121 static void odbc_datastore_free(void *data);
122
123 static const struct ast_datastore_info odbc_info = {
124         .type = "FUNC_ODBC",
125         .destroy = odbc_datastore_free,
126 };
127
128 /* For storing each result row */
129 struct odbc_datastore_row {
130         AST_LIST_ENTRY(odbc_datastore_row) list;
131         char data[0];
132 };
133
134 /* For storing each result set */
135 struct odbc_datastore {
136         AST_LIST_HEAD(, odbc_datastore_row);
137         char names[0];
138 };
139
140 /* \brief Data source name
141  *
142  * This holds data that pertains to a DSN
143  */
144 struct dsn {
145         /*! A connection to the database */
146         struct odbc_obj *connection;
147         /*! The name of the DSN as defined in res_odbc.conf */
148         char name[0];
149 };
150
151 #define DSN_BUCKETS 37
152
153 struct ao2_container *dsns;
154
155 static int dsn_hash(const void *obj, const int flags)
156 {
157         const struct dsn *object;
158         const char *key;
159
160         switch (flags & OBJ_SEARCH_MASK) {
161         case OBJ_SEARCH_KEY:
162                 key = obj;
163                 break;
164         case OBJ_SEARCH_OBJECT:
165                 object = obj;
166                 key = object->name;
167                 break;
168         default:
169                 ast_assert(0);
170                 return 0;
171         }
172         return ast_str_hash(key);
173 }
174
175 static int dsn_cmp(void *obj, void *arg, int flags)
176 {
177         const struct dsn *object_left = obj;
178         const struct dsn *object_right = arg;
179         const char *right_key = arg;
180         int cmp;
181
182         switch (flags & OBJ_SEARCH_MASK) {
183         case OBJ_SEARCH_OBJECT:
184                 right_key = object_right->name;
185                 /* Fall through */
186         case OBJ_SEARCH_KEY:
187                 cmp = strcmp(object_left->name, right_key);
188                 break;
189         case OBJ_SEARCH_PARTIAL_KEY:
190                 cmp = strncmp(object_left->name, right_key, strlen(right_key));
191                 break;
192         default:
193                 cmp = 0;
194                 break;
195         }
196
197         if (cmp) {
198                 return 0;
199         }
200
201         return CMP_MATCH;
202 }
203
204 static void dsn_destructor(void *obj)
205 {
206         struct dsn *dsn = obj;
207
208         if (dsn->connection) {
209                 ast_odbc_release_obj(dsn->connection);
210         }
211 }
212
213 /*!
214  * \brief Create a DSN and connect to the database
215  *
216  * \param name The name of the DSN as found in res_odbc.conf
217  * \retval NULL Fail
218  * \retval non-NULL The newly-created structure
219  */
220 static struct dsn *create_dsn(const char *name)
221 {
222         struct dsn *dsn;
223
224         dsn = ao2_alloc(sizeof(*dsn) + strlen(name) + 1, dsn_destructor);
225         if (!dsn) {
226                 return NULL;
227         }
228
229         /* Safe */
230         strcpy(dsn->name, name);
231
232         dsn->connection = ast_odbc_request_obj(name, 0);
233         if (!dsn->connection) {
234                 ao2_ref(dsn, -1);
235                 return NULL;
236         }
237
238         if (!ao2_link_flags(dsns, dsn, OBJ_NOLOCK)) {
239                 ao2_ref(dsn, -1);
240                 return NULL;
241         }
242
243         return dsn;
244 }
245
246 /*!
247  * \brief Retrieve a DSN, or create it if it does not exist.
248  *
249  * The created DSN is returned locked. This should be inconsequential
250  * to callers in most cases.
251  *
252  * When finished with the returned structure, the caller must call
253  * \ref release_dsn
254  *
255  * \param name Name of the DSN as found in res_odbc.conf
256  * \retval NULL Unable to retrieve or create the DSN
257  * \retval non-NULL The retrieved/created locked DSN
258  */
259 static struct dsn *get_dsn(const char *name)
260 {
261         struct dsn *dsn;
262
263         ao2_lock(dsns);
264         dsn = ao2_find(dsns, name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
265         if (!dsn) {
266                 dsn = create_dsn(name);
267         }
268         ao2_unlock(dsns);
269
270         if (!dsn) {
271                 return NULL;
272         }
273
274         ao2_lock(dsn->connection);
275
276         return dsn;
277 }
278
279 /*!
280  * \brief Unlock and unreference a DSN
281  *
282  * \param dsn The dsn to unlock and unreference
283  * \return NULL
284  */
285 static void *release_dsn(struct dsn *dsn)
286 {
287         if (!dsn) {
288                 return NULL;
289         }
290
291         ao2_unlock(dsn->connection);
292         ao2_ref(dsn, -1);
293
294         return NULL;
295 }
296
297 static AST_RWLIST_HEAD_STATIC(queries, acf_odbc_query);
298
299 static int resultcount = 0;
300
301 AST_THREADSTORAGE(sql_buf);
302 AST_THREADSTORAGE(sql2_buf);
303 AST_THREADSTORAGE(coldata_buf);
304 AST_THREADSTORAGE(colnames_buf);
305
306 static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
307
308 static void odbc_datastore_free(void *data)
309 {
310         struct odbc_datastore *result = data;
311         struct odbc_datastore_row *row;
312
313         if (!result) {
314                 return;
315         }
316
317         AST_LIST_LOCK(result);
318         while ((row = AST_LIST_REMOVE_HEAD(result, list))) {
319                 ast_free(row);
320         }
321         AST_LIST_UNLOCK(result);
322         AST_LIST_HEAD_DESTROY(result);
323         ast_free(result);
324 }
325
326 static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data)
327 {
328         int res;
329         char *sql = data;
330         SQLHSTMT stmt;
331
332         res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
333         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
334                 ast_log(LOG_WARNING, "SQL Alloc Handle failed (%d)!\n", res);
335                 return NULL;
336         }
337
338         res = SQLExecDirect(stmt, (unsigned char *)sql, SQL_NTS);
339         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
340                 if (res == SQL_ERROR) {
341                         int i;
342                         SQLINTEGER nativeerror=0, numfields=0;
343                         SQLSMALLINT diagbytes=0;
344                         unsigned char state[10], diagnostic[256];
345
346                         SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
347                         for (i = 0; i < numfields; i++) {
348                                 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
349                                 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
350                                 if (i > 10) {
351                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
352                                         break;
353                                 }
354                         }
355                 }
356
357                 ast_log(LOG_WARNING, "SQL Exec Direct failed (%d)![%s]\n", res, sql);
358                 SQLCloseCursor(stmt);
359                 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
360                 return NULL;
361         }
362
363         return stmt;
364 }
365
366 /*
367  * Master control routine
368  */
369 static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
370 {
371         struct odbc_obj *obj = NULL;
372         struct acf_odbc_query *query;
373         char *t, varname[15];
374         int i, dsn_num, bogus_chan = 0;
375         int transactional = 0;
376         AST_DECLARE_APP_ARGS(values,
377                 AST_APP_ARG(field)[100];
378         );
379         AST_DECLARE_APP_ARGS(args,
380                 AST_APP_ARG(field)[100];
381         );
382         SQLHSTMT stmt = NULL;
383         SQLLEN rows=0;
384         struct ast_str *buf = ast_str_thread_get(&sql_buf, 16);
385         struct ast_str *insertbuf = ast_str_thread_get(&sql2_buf, 16);
386         const char *status = "FAILURE";
387         struct dsn *dsn = NULL;
388
389         if (!buf || !insertbuf) {
390                 return -1;
391         }
392
393         AST_RWLIST_RDLOCK(&queries);
394         AST_RWLIST_TRAVERSE(&queries, query, list) {
395                 if (!strcmp(query->acf->name, cmd)) {
396                         break;
397                 }
398         }
399
400         if (!query) {
401                 ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
402                 AST_RWLIST_UNLOCK(&queries);
403                 if (chan) {
404                         pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
405                 }
406                 return -1;
407         }
408
409         if (!chan) {
410                 if (!(chan = ast_dummy_channel_alloc())) {
411                         AST_RWLIST_UNLOCK(&queries);
412                         return -1;
413                 }
414                 bogus_chan = 1;
415         }
416
417         if (!bogus_chan) {
418                 ast_autoservice_start(chan);
419         }
420
421         ast_str_make_space(&buf, strlen(query->sql_write) * 2 + 300);
422         /* We only get here if sql_write is set. sql_insert is optional however. */
423         if (query->sql_insert) {
424                 ast_str_make_space(&insertbuf, strlen(query->sql_insert) * 2 + 300);
425         }
426
427         /* Parse our arguments */
428         t = value ? ast_strdupa(value) : "";
429
430         if (!s || !t) {
431                 ast_log(LOG_ERROR, "Out of memory\n");
432                 AST_RWLIST_UNLOCK(&queries);
433                 if (!bogus_chan) {
434                         ast_autoservice_stop(chan);
435                         pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
436                 } else {
437                         ast_channel_unref(chan);
438                 }
439                 return -1;
440         }
441
442         AST_STANDARD_APP_ARGS(args, s);
443         for (i = 0; i < args.argc; i++) {
444                 snprintf(varname, sizeof(varname), "ARG%d", i + 1);
445                 pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
446         }
447
448         /* Parse values, just like arguments */
449         AST_STANDARD_APP_ARGS(values, t);
450         for (i = 0; i < values.argc; i++) {
451                 snprintf(varname, sizeof(varname), "VAL%d", i + 1);
452                 pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
453         }
454
455         /* Additionally set the value as a whole (but push an empty string if value is NULL) */
456         pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : "");
457
458         ast_str_substitute_variables(&buf, 0, chan, query->sql_write);
459         if (query->sql_insert) {
460                 ast_str_substitute_variables(&insertbuf, 0, chan, query->sql_insert);
461         }
462
463         if (bogus_chan) {
464                 chan = ast_channel_unref(chan);
465         } else {
466                 /* Restore prior values */
467                 for (i = 0; i < args.argc; i++) {
468                         snprintf(varname, sizeof(varname), "ARG%d", i + 1);
469                         pbx_builtin_setvar_helper(chan, varname, NULL);
470                 }
471
472                 for (i = 0; i < values.argc; i++) {
473                         snprintf(varname, sizeof(varname), "VAL%d", i + 1);
474                         pbx_builtin_setvar_helper(chan, varname, NULL);
475                 }
476                 pbx_builtin_setvar_helper(chan, "VALUE", NULL);
477         }
478
479         /*!\note
480          * Okay, this part is confusing.  Transactions belong to a single database
481          * handle.  Therefore, when working with transactions, we CANNOT failover
482          * to multiple DSNs.  We MUST have a single handle all the way through the
483          * transaction, or else we CANNOT enforce atomicity.
484          */
485         for (dsn_num = 0; dsn_num < 5; dsn_num++) {
486                 if (!ast_strlen_zero(query->writehandle[dsn_num])) {
487                         if (transactional) {
488                                 /* This can only happen second time through or greater. */
489                                 ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
490                         }
491
492                         if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn_num]))) {
493                                 transactional = 1;
494                         } else {
495                                 dsn = get_dsn(query->writehandle[dsn_num]);
496                                 if (!dsn) {
497                                         continue;
498                                 }
499                                 obj = dsn->connection;
500                                 transactional = 0;
501                         }
502
503                         if (obj && (stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(buf)))) {
504                                 break;
505                         }
506
507                         dsn = release_dsn(dsn);
508                 }
509         }
510
511         if (stmt) {
512                 SQLRowCount(stmt, &rows);
513                 SQLCloseCursor(stmt);
514                 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
515
516                 if (rows != 0) {
517                         status = "SUCCESS";
518
519                 } else if (query->sql_insert) {
520                         dsn = release_dsn(dsn);
521
522                         for (transactional = 0, dsn_num = 0; dsn_num < 5; dsn_num++) {
523                                 if (!ast_strlen_zero(query->writehandle[dsn_num])) {
524                                         if (transactional) {
525                                                 /* This can only happen second time through or greater. */
526                                                 ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
527                                         } else if (obj) {
528                                                 dsn = release_dsn(dsn);
529                                         }
530
531                                         if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn_num]))) {
532                                                 transactional = 1;
533                                         } else {
534                                                 dsn = get_dsn(query->writehandle[dsn_num]);
535                                                 if (!dsn) {
536                                                         continue;
537                                                 }
538                                                 obj = dsn->connection;
539                                                 transactional = 0;
540                                         }
541                                         if (obj) {
542                                                 stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(insertbuf));
543                                         }
544                                 }
545                                 if (stmt) {
546                                         status = "FAILOVER";
547                                         SQLRowCount(stmt, &rows);
548                                         SQLCloseCursor(stmt);
549                                         SQLFreeHandle(SQL_HANDLE_STMT, stmt);
550                                         break;
551                                 }
552                         }
553                 }
554         }
555
556         AST_RWLIST_UNLOCK(&queries);
557
558         /* Output the affected rows, for all cases.  In the event of failure, we
559          * flag this as -1 rows.  Note that this is different from 0 affected rows
560          * which would be the case if we succeeded in our query, but the values did
561          * not change. */
562         if (!bogus_chan) {
563                 snprintf(varname, sizeof(varname), "%d", (int)rows);
564                 pbx_builtin_setvar_helper(chan, "ODBCROWS", varname);
565                 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
566         }
567
568         dsn = release_dsn(dsn);
569
570         if (!bogus_chan) {
571                 ast_autoservice_stop(chan);
572         }
573
574         return 0;
575 }
576
577 static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, char *buf, size_t len)
578 {
579         struct acf_odbc_query *query;
580         char varname[15], rowcount[12] = "-1";
581         struct ast_str *colnames = ast_str_thread_get(&colnames_buf, 16);
582         int res, x, y, buflen = 0, escapecommas, rowlimit = 1, multirow = 0, dsn_num, bogus_chan = 0;
583         AST_DECLARE_APP_ARGS(args,
584                 AST_APP_ARG(field)[100];
585         );
586         SQLHSTMT stmt = NULL;
587         SQLSMALLINT colcount=0;
588         SQLLEN indicator;
589         SQLSMALLINT collength;
590         struct odbc_datastore *resultset = NULL;
591         struct odbc_datastore_row *row = NULL;
592         struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
593         const char *status = "FAILURE";
594         struct dsn *dsn = NULL;
595
596         if (!sql || !colnames) {
597                 if (chan) {
598                         pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
599                 }
600                 return -1;
601         }
602
603         ast_str_reset(colnames);
604
605         AST_RWLIST_RDLOCK(&queries);
606         AST_RWLIST_TRAVERSE(&queries, query, list) {
607                 if (!strcmp(query->acf->name, cmd)) {
608                         break;
609                 }
610         }
611
612         if (!query) {
613                 ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
614                 AST_RWLIST_UNLOCK(&queries);
615                 if (chan) {
616                         pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
617                         pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
618                 }
619                 return -1;
620         }
621
622         if (!chan) {
623                 if (!(chan = ast_dummy_channel_alloc())) {
624                         AST_RWLIST_UNLOCK(&queries);
625                         return -1;
626                 }
627                 bogus_chan = 1;
628         }
629
630         if (!bogus_chan) {
631                 ast_autoservice_start(chan);
632         }
633
634         AST_STANDARD_APP_ARGS(args, s);
635         for (x = 0; x < args.argc; x++) {
636                 snprintf(varname, sizeof(varname), "ARG%d", x + 1);
637                 pbx_builtin_pushvar_helper(chan, varname, args.field[x]);
638         }
639
640         ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
641
642         if (bogus_chan) {
643                 chan = ast_channel_unref(chan);
644         } else {
645                 /* Restore prior values */
646                 for (x = 0; x < args.argc; x++) {
647                         snprintf(varname, sizeof(varname), "ARG%d", x + 1);
648                         pbx_builtin_setvar_helper(chan, varname, NULL);
649                 }
650         }
651
652         /* Save these flags, so we can release the lock */
653         escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS);
654         if (!bogus_chan && ast_test_flag(query, OPT_MULTIROW)) {
655                 if (!(resultset = ast_calloc(1, sizeof(*resultset)))) {
656                         pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
657                         pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
658                         ast_autoservice_stop(chan);
659                         return -1;
660                 }
661                 AST_LIST_HEAD_INIT(resultset);
662                 if (query->rowlimit) {
663                         rowlimit = query->rowlimit;
664                 } else {
665                         rowlimit = INT_MAX;
666                 }
667                 multirow = 1;
668         } else if (!bogus_chan) {
669                 if (query->rowlimit > 1) {
670                         rowlimit = query->rowlimit;
671                         if (!(resultset = ast_calloc(1, sizeof(*resultset)))) {
672                                 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
673                                 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
674                                 ast_autoservice_stop(chan);
675                                 return -1;
676                         }
677                         AST_LIST_HEAD_INIT(resultset);
678                 }
679         }
680         AST_RWLIST_UNLOCK(&queries);
681
682         for (dsn_num = 0; dsn_num < 5; dsn_num++) {
683                 if (!ast_strlen_zero(query->readhandle[dsn_num])) {
684                         dsn = get_dsn(query->readhandle[dsn_num]);
685                         if (!dsn) {
686                                 continue;
687                         }
688                         stmt = ast_odbc_direct_execute(dsn->connection, generic_execute, ast_str_buffer(sql));
689                 }
690                 if (stmt) {
691                         break;
692                 }
693                 dsn = release_dsn(dsn);
694         }
695
696         if (!stmt) {
697                 ast_log(LOG_ERROR, "Unable to execute query [%s]\n", ast_str_buffer(sql));
698                 dsn = release_dsn(dsn);
699                 if (!bogus_chan) {
700                         pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
701                         ast_autoservice_stop(chan);
702                 }
703                 odbc_datastore_free(resultset);
704                 return -1;
705         }
706
707         res = SQLNumResultCols(stmt, &colcount);
708         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
709                 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
710                 SQLCloseCursor(stmt);
711                 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
712                 dsn = release_dsn(dsn);
713                 if (!bogus_chan) {
714                         pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
715                         ast_autoservice_stop(chan);
716                 }
717                 odbc_datastore_free(resultset);
718                 return -1;
719         }
720
721         res = SQLFetch(stmt);
722         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
723                 int res1 = -1;
724                 if (res == SQL_NO_DATA) {
725                         ast_verb(4, "Found no rows [%s]\n", ast_str_buffer(sql));
726                         res1 = 0;
727                         buf[0] = '\0';
728                         ast_copy_string(rowcount, "0", sizeof(rowcount));
729                         status = "NODATA";
730                 } else {
731                         ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
732                         status = "FETCHERROR";
733                 }
734                 SQLCloseCursor(stmt);
735                 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
736                 dsn = release_dsn(dsn);
737                 if (!bogus_chan) {
738                         pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
739                         pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
740                         ast_autoservice_stop(chan);
741                 }
742                 odbc_datastore_free(resultset);
743                 return res1;
744         }
745
746         status = "SUCCESS";
747
748         for (y = 0; y < rowlimit; y++) {
749                 buf[0] = '\0';
750                 for (x = 0; x < colcount; x++) {
751                         int i;
752                         struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
753                         char *ptrcoldata;
754
755                         if (!coldata) {
756                                 odbc_datastore_free(resultset);
757                                 SQLCloseCursor(stmt);
758                                 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
759                                 dsn = release_dsn(dsn);
760                                 if (!bogus_chan) {
761                                         pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
762                                         ast_autoservice_stop(chan);
763                                 }
764                                 return -1;
765                         }
766
767                         if (y == 0) {
768                                 char colname[256];
769                                 SQLULEN maxcol = 0;
770
771                                 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL);
772                                 ast_debug(3, "Got collength of %d and maxcol of %d for column '%s' (offset %d)\n", (int)collength, (int)maxcol, colname, x);
773                                 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
774                                         snprintf(colname, sizeof(colname), "field%d", x);
775                                 }
776
777                                 ast_str_make_space(&coldata, maxcol + 1);
778
779                                 if (ast_str_strlen(colnames)) {
780                                         ast_str_append(&colnames, 0, ",");
781                                 }
782                                 ast_str_append_escapecommas(&colnames, 0, colname, sizeof(colname));
783
784                                 if (resultset) {
785                                         void *tmp = ast_realloc(resultset, sizeof(*resultset) + ast_str_strlen(colnames) + 1);
786                                         if (!tmp) {
787                                                 ast_log(LOG_ERROR, "No space for a new resultset?\n");
788                                                 odbc_datastore_free(resultset);
789                                                 SQLCloseCursor(stmt);
790                                                 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
791                                                 dsn = release_dsn(dsn);
792                                                 if (!bogus_chan) {
793                                                         pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
794                                                         pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
795                                                         ast_autoservice_stop(chan);
796                                                 }
797                                                 return -1;
798                                         }
799                                         resultset = tmp;
800                                         strcpy((char *)resultset + sizeof(*resultset), ast_str_buffer(colnames));
801                                 }
802                         }
803
804                         buflen = strlen(buf);
805                         res = ast_odbc_ast_str_SQLGetData(&coldata, -1, stmt, x + 1, SQL_CHAR, &indicator);
806                         if (indicator == SQL_NULL_DATA) {
807                                 ast_debug(3, "Got NULL data\n");
808                                 ast_str_reset(coldata);
809                                 res = SQL_SUCCESS;
810                         }
811
812                         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
813                                 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", ast_str_buffer(sql));
814                                 y = -1;
815                                 buf[0] = '\0';
816                                 goto end_acf_read;
817                         }
818
819                         ast_debug(2, "Got coldata of '%s'\n", ast_str_buffer(coldata));
820
821                         if (x) {
822                                 buf[buflen++] = ',';
823                         }
824
825                         /* Copy data, encoding '\' and ',' for the argument parser */
826                         ptrcoldata = ast_str_buffer(coldata);
827                         for (i = 0; i < ast_str_strlen(coldata); i++) {
828                                 if (escapecommas && (ptrcoldata[i] == '\\' || ptrcoldata[i] == ',')) {
829                                         buf[buflen++] = '\\';
830                                 }
831                                 buf[buflen++] = ptrcoldata[i];
832
833                                 if (buflen >= len - 2) {
834                                         break;
835                                 }
836
837                                 if (ptrcoldata[i] == '\0') {
838                                         break;
839                                 }
840                         }
841
842                         buf[buflen] = '\0';
843                         ast_debug(2, "buf is now set to '%s'\n", buf);
844                 }
845                 ast_debug(2, "buf is now set to '%s'\n", buf);
846
847                 if (resultset) {
848                         row = ast_calloc(1, sizeof(*row) + buflen + 1);
849                         if (!row) {
850                                 ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n");
851                                 status = "MEMERROR";
852                                 goto end_acf_read;
853                         }
854                         strcpy((char *)row + sizeof(*row), buf);
855                         AST_LIST_INSERT_TAIL(resultset, row, list);
856
857                         /* Get next row */
858                         res = SQLFetch(stmt);
859                         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
860                                 if (res != SQL_NO_DATA) {
861                                         ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
862                                 }
863                                 /* Number of rows in the resultset */
864                                 y++;
865                                 break;
866                         }
867                 }
868         }
869
870 end_acf_read:
871         if (!bogus_chan) {
872                 snprintf(rowcount, sizeof(rowcount), "%d", y);
873                 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
874                 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
875                 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(colnames));
876                 if (resultset) {
877                         struct ast_datastore *odbc_store;
878                         if (multirow) {
879                                 int uid;
880                                 uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1;
881                                 snprintf(buf, len, "%d", uid);
882                         } else {
883                                 /* Name of the query is name of the resultset */
884                                 ast_copy_string(buf, cmd, len);
885
886                                 /* If there's one with the same name already, free it */
887                                 ast_channel_lock(chan);
888                                 if ((odbc_store = ast_channel_datastore_find(chan, &odbc_info, buf))) {
889                                         ast_channel_datastore_remove(chan, odbc_store);
890                                         ast_datastore_free(odbc_store);
891                                 }
892                                 ast_channel_unlock(chan);
893                         }
894                         odbc_store = ast_datastore_alloc(&odbc_info, buf);
895                         if (!odbc_store) {
896                                 ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel.  Results fail.\n");
897                                 odbc_datastore_free(resultset);
898                                 SQLCloseCursor(stmt);
899                                 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
900                                 dsn = release_dsn(dsn);
901                                 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
902                                 ast_autoservice_stop(chan);
903                                 return -1;
904                         }
905                         odbc_store->data = resultset;
906                         ast_channel_lock(chan);
907                         ast_channel_datastore_add(chan, odbc_store);
908                         ast_channel_unlock(chan);
909                 }
910         }
911         SQLCloseCursor(stmt);
912         SQLFreeHandle(SQL_HANDLE_STMT, stmt);
913         dsn = release_dsn(dsn);
914         if (resultset && !multirow) {
915                 /* Fetch the first resultset */
916                 if (!acf_fetch(chan, "", buf, buf, len)) {
917                         buf[0] = '\0';
918                 }
919         }
920         if (!bogus_chan) {
921                 ast_autoservice_stop(chan);
922         }
923         return 0;
924 }
925
926 static int acf_escape(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
927 {
928         char *out = buf;
929
930         for (; *data && out - buf < len; data++) {
931                 if (*data == '\'') {
932                         *out = '\'';
933                         out++;
934                 }
935                 *out++ = *data;
936         }
937         *out = '\0';
938
939         return 0;
940 }
941
942 static struct ast_custom_function escape_function = {
943         .name = "SQL_ESC",
944         .read = acf_escape,
945         .write = NULL,
946 };
947
948 static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
949 {
950         struct ast_datastore *store;
951         struct odbc_datastore *resultset;
952         struct odbc_datastore_row *row;
953
954         if (!chan) {
955                 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
956                 return -1;
957         }
958
959         ast_channel_lock(chan);
960         store = ast_channel_datastore_find(chan, &odbc_info, data);
961         if (!store) {
962                 ast_channel_unlock(chan);
963                 pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
964                 return -1;
965         }
966         resultset = store->data;
967         AST_LIST_LOCK(resultset);
968         row = AST_LIST_REMOVE_HEAD(resultset, list);
969         AST_LIST_UNLOCK(resultset);
970         if (!row) {
971                 /* Cleanup datastore */
972                 ast_channel_datastore_remove(chan, store);
973                 ast_datastore_free(store);
974                 ast_channel_unlock(chan);
975                 pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
976                 return -1;
977         }
978         pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names);
979         ast_channel_unlock(chan);
980         ast_copy_string(buf, row->data, len);
981         ast_free(row);
982         pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "SUCCESS");
983         return 0;
984 }
985
986 static struct ast_custom_function fetch_function = {
987         .name = "ODBC_FETCH",
988         .read = acf_fetch,
989         .write = NULL,
990 };
991
992 static char *app_odbcfinish = "ODBCFinish";
993
994 static int exec_odbcfinish(struct ast_channel *chan, const char *data)
995 {
996         struct ast_datastore *store;
997
998         ast_channel_lock(chan);
999         store = ast_channel_datastore_find(chan, &odbc_info, data);
1000         if (store) {
1001                 ast_channel_datastore_remove(chan, store);
1002                 ast_datastore_free(store);
1003         }
1004         ast_channel_unlock(chan);
1005         return 0;
1006 }
1007
1008 static int free_acf_query(struct acf_odbc_query *query)
1009 {
1010         if (query) {
1011                 if (query->acf) {
1012                         if (query->acf->name)
1013                                 ast_free((char *)query->acf->name);
1014                         ast_string_field_free_memory(query->acf);
1015                         ast_free(query->acf);
1016                 }
1017                 ast_free(query->sql_read);
1018                 ast_free(query->sql_write);
1019                 ast_free(query->sql_insert);
1020                 ast_free(query);
1021         }
1022         return 0;
1023 }
1024
1025 static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
1026 {
1027         const char *tmp;
1028         const char *tmp2;
1029         int i;
1030
1031         if (!cfg || !catg) {
1032                 return EINVAL;
1033         }
1034
1035         if (!(*query = ast_calloc(1, sizeof(**query)))) {
1036                 return ENOMEM;
1037         }
1038
1039         if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) {
1040                 char *tmp2 = ast_strdupa(tmp);
1041                 AST_DECLARE_APP_ARGS(writeconf,
1042                         AST_APP_ARG(dsn)[5];
1043                 );
1044                 AST_STANDARD_APP_ARGS(writeconf, tmp2);
1045                 for (i = 0; i < 5; i++) {
1046                         if (!ast_strlen_zero(writeconf.dsn[i]))
1047                                 ast_copy_string((*query)->writehandle[i], writeconf.dsn[i], sizeof((*query)->writehandle[i]));
1048                 }
1049         }
1050
1051         if ((tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) {
1052                 char *tmp2 = ast_strdupa(tmp);
1053                 AST_DECLARE_APP_ARGS(readconf,
1054                         AST_APP_ARG(dsn)[5];
1055                 );
1056                 AST_STANDARD_APP_ARGS(readconf, tmp2);
1057                 for (i = 0; i < 5; i++) {
1058                         if (!ast_strlen_zero(readconf.dsn[i]))
1059                                 ast_copy_string((*query)->readhandle[i], readconf.dsn[i], sizeof((*query)->readhandle[i]));
1060                 }
1061         } else {
1062                 /* If no separate readhandle, then use the writehandle for reading */
1063                 for (i = 0; i < 5; i++) {
1064                         if (!ast_strlen_zero((*query)->writehandle[i]))
1065                                 ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i]));
1066                 }
1067         }
1068
1069         if ((tmp = ast_variable_retrieve(cfg, catg, "readsql")) ||
1070                         (tmp2 = ast_variable_retrieve(cfg, catg, "read"))) {
1071                 if (!tmp) {
1072                         ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s.  Please use 'readsql' instead.\n", catg);
1073                         tmp = tmp2;
1074                 }
1075                 if (*tmp != '\0') { /* non-empty string */
1076                         if (!((*query)->sql_read = ast_strdup(tmp))) {
1077                                 free_acf_query(*query);
1078                                 *query = NULL;
1079                                 return ENOMEM;
1080                         }
1081                 }
1082         }
1083
1084         if ((*query)->sql_read && ast_strlen_zero((*query)->readhandle[0])) {
1085                 free_acf_query(*query);
1086                 *query = NULL;
1087                 ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg);
1088                 return EINVAL;
1089         }
1090
1091         if ((tmp = ast_variable_retrieve(cfg, catg, "writesql")) ||
1092                         (tmp2 = ast_variable_retrieve(cfg, catg, "write"))) {
1093                 if (!tmp) {
1094                         ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s.  Please use 'writesql' instead.\n", catg);
1095                         tmp = tmp2;
1096                 }
1097                 if (*tmp != '\0') { /* non-empty string */
1098                         if (!((*query)->sql_write = ast_strdup(tmp))) {
1099                                 free_acf_query(*query);
1100                                 *query = NULL;
1101                                 return ENOMEM;
1102                         }
1103                 }
1104         }
1105
1106         if ((*query)->sql_write && ast_strlen_zero((*query)->writehandle[0])) {
1107                 free_acf_query(*query);
1108                 *query = NULL;
1109                 ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg);
1110                 return EINVAL;
1111         }
1112
1113         if ((tmp = ast_variable_retrieve(cfg, catg, "insertsql"))) {
1114                 if (*tmp != '\0') { /* non-empty string */
1115                         if (!((*query)->sql_insert = ast_strdup(tmp))) {
1116                                 free_acf_query(*query);
1117                                 *query = NULL;
1118                                 return ENOMEM;
1119                         }
1120                 }
1121         }
1122
1123         /* Allow escaping of embedded commas in fields to be turned off */
1124         ast_set_flag((*query), OPT_ESCAPECOMMAS);
1125         if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) {
1126                 if (ast_false(tmp))
1127                         ast_clear_flag((*query), OPT_ESCAPECOMMAS);
1128         }
1129
1130         if ((tmp = ast_variable_retrieve(cfg, catg, "mode"))) {
1131                 if (strcasecmp(tmp, "multirow") == 0)
1132                         ast_set_flag((*query), OPT_MULTIROW);
1133                 if ((tmp = ast_variable_retrieve(cfg, catg, "rowlimit")))
1134                         sscanf(tmp, "%30d", &((*query)->rowlimit));
1135         }
1136
1137         (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function));
1138         if (!(*query)->acf) {
1139                 free_acf_query(*query);
1140                 *query = NULL;
1141                 return ENOMEM;
1142         }
1143         if (ast_string_field_init((*query)->acf, 128)) {
1144                 free_acf_query(*query);
1145                 *query = NULL;
1146                 return ENOMEM;
1147         }
1148
1149         if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) {
1150                 if (ast_asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) {
1151                         (*query)->acf->name = NULL;
1152                 }
1153         } else {
1154                 if (ast_asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg) < 0) {
1155                         (*query)->acf->name = NULL;
1156                 }
1157         }
1158
1159         if (!(*query)->acf->name) {
1160                 free_acf_query(*query);
1161                 *query = NULL;
1162                 return ENOMEM;
1163         }
1164
1165         if ((tmp = ast_variable_retrieve(cfg, catg, "syntax")) && !ast_strlen_zero(tmp)) {
1166                 ast_string_field_build((*query)->acf, syntax, "%s(%s)", (*query)->acf->name, tmp);
1167         } else {
1168                 ast_string_field_build((*query)->acf, syntax, "%s(<arg1>[...[,<argN>]])", (*query)->acf->name);
1169         }
1170
1171         if (ast_strlen_zero((*query)->acf->syntax)) {
1172                 free_acf_query(*query);
1173                 *query = NULL;
1174                 return ENOMEM;
1175         }
1176
1177         if ((tmp = ast_variable_retrieve(cfg, catg, "synopsis")) && !ast_strlen_zero(tmp)) {
1178                 ast_string_field_set((*query)->acf, synopsis, tmp);
1179         } else {
1180                 ast_string_field_set((*query)->acf, synopsis, "Runs the referenced query with the specified arguments");
1181         }
1182
1183         if (ast_strlen_zero((*query)->acf->synopsis)) {
1184                 free_acf_query(*query);
1185                 *query = NULL;
1186                 return ENOMEM;
1187         }
1188
1189         if ((*query)->sql_read && (*query)->sql_write) {
1190                 ast_string_field_build((*query)->acf, desc,
1191                                         "Runs the following query, as defined in func_odbc.conf, performing\n"
1192                                         "substitution of the arguments into the query as specified by ${ARG1},\n"
1193                                         "${ARG2}, ... ${ARGn}.  When setting the function, the values are provided\n"
1194                                         "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
1195                                         "%s"
1196                                         "\nRead:\n%s\n\nWrite:\n%s%s%s",
1197                                         (*query)->sql_insert ?
1198                                                 "If the write query affects no rows, the insert query will be\n"
1199                                                 "performed.\n" : "",
1200                                         (*query)->sql_read,
1201                                         (*query)->sql_write,
1202                                         (*query)->sql_insert ? "\n\nInsert:\n" : "",
1203                                         (*query)->sql_insert ? (*query)->sql_insert : "");
1204         } else if ((*query)->sql_read) {
1205                 ast_string_field_build((*query)->acf, desc,
1206                                         "Runs the following query, as defined in func_odbc.conf, performing\n"
1207                                         "substitution of the arguments into the query as specified by ${ARG1},\n"
1208                                         "${ARG2}, ... ${ARGn}.  This function may only be read, not set.\n\nSQL:\n%s",
1209                                         (*query)->sql_read);
1210         } else if ((*query)->sql_write) {
1211                 ast_string_field_build((*query)->acf, desc,
1212                                         "Runs the following query, as defined in func_odbc.conf, performing\n"
1213                                         "substitution of the arguments into the query as specified by ${ARG1},\n"
1214                                         "${ARG2}, ... ${ARGn}.  The values are provided either in whole as\n"
1215                                         "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
1216                                         "This function may only be set.\n%s\nSQL:\n%s%s%s",
1217                                         (*query)->sql_insert ?
1218                                                 "If the write query affects no rows, the insert query will be\n"
1219                                                 "performed.\n" : "",
1220                                         (*query)->sql_write,
1221                                         (*query)->sql_insert ? "\n\nInsert:\n" : "",
1222                                         (*query)->sql_insert ? (*query)->sql_insert : "");
1223         } else {
1224                 free_acf_query(*query);
1225                 *query = NULL;
1226                 ast_log(LOG_WARNING, "Section '%s' was found, but there was no SQL to execute.  Ignoring.\n", catg);
1227                 return EINVAL;
1228         }
1229
1230         if (ast_strlen_zero((*query)->acf->desc)) {
1231                 free_acf_query(*query);
1232                 *query = NULL;
1233                 return ENOMEM;
1234         }
1235
1236         if ((*query)->sql_read) {
1237                 (*query)->acf->read = acf_odbc_read;
1238         }
1239
1240         if ((*query)->sql_write) {
1241                 (*query)->acf->write = acf_odbc_write;
1242         }
1243
1244         return 0;
1245 }
1246
1247 static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1248 {
1249         AST_DECLARE_APP_ARGS(args,
1250                 AST_APP_ARG(field)[100];
1251         );
1252         struct ast_str *sql;
1253         char *char_args, varname[10];
1254         struct acf_odbc_query *query;
1255         struct ast_channel *chan;
1256         int i;
1257
1258         switch (cmd) {
1259         case CLI_INIT:
1260                 e->command = "odbc read";
1261                 e->usage =
1262                         "Usage: odbc read <name> <args> [exec]\n"
1263                         "       Evaluates the SQL provided in the ODBC function <name>, and\n"
1264                         "       optionally executes the function.  This function is intended for\n"
1265                         "       testing purposes.  Remember to quote arguments containing spaces.\n";
1266                 return NULL;
1267         case CLI_GENERATE:
1268                 if (a->pos == 2) {
1269                         int wordlen = strlen(a->word), which = 0;
1270                         /* Complete function name */
1271                         AST_RWLIST_RDLOCK(&queries);
1272                         AST_RWLIST_TRAVERSE(&queries, query, list) {
1273                                 if (!strncasecmp(query->acf->name, a->word, wordlen)) {
1274                                         if (++which > a->n) {
1275                                                 char *res = ast_strdup(query->acf->name);
1276                                                 AST_RWLIST_UNLOCK(&queries);
1277                                                 return res;
1278                                         }
1279                                 }
1280                         }
1281                         AST_RWLIST_UNLOCK(&queries);
1282                         return NULL;
1283                 } else if (a->pos == 4) {
1284                         return a->n == 0 ? ast_strdup("exec") : NULL;
1285                 } else {
1286                         return NULL;
1287                 }
1288         }
1289
1290         if (a->argc < 4 || a->argc > 5) {
1291                 return CLI_SHOWUSAGE;
1292         }
1293
1294         sql = ast_str_thread_get(&sql_buf, 16);
1295         if (!sql) {
1296                 return CLI_FAILURE;
1297         }
1298
1299         AST_RWLIST_RDLOCK(&queries);
1300         AST_RWLIST_TRAVERSE(&queries, query, list) {
1301                 if (!strcmp(query->acf->name, a->argv[2])) {
1302                         break;
1303                 }
1304         }
1305
1306         if (!query) {
1307                 ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
1308                 AST_RWLIST_UNLOCK(&queries);
1309                 return CLI_SHOWUSAGE;
1310         }
1311
1312         if (!query->sql_read) {
1313                 ast_cli(a->fd, "The function %s has no readsql parameter.\n", a->argv[2]);
1314                 AST_RWLIST_UNLOCK(&queries);
1315                 return CLI_SUCCESS;
1316         }
1317
1318         ast_str_make_space(&sql, strlen(query->sql_read) * 2 + 300);
1319
1320         /* Evaluate function */
1321         char_args = ast_strdupa(a->argv[3]);
1322
1323         chan = ast_dummy_channel_alloc();
1324         if (!chan) {
1325                 AST_RWLIST_UNLOCK(&queries);
1326                 return CLI_FAILURE;
1327         }
1328
1329         AST_STANDARD_APP_ARGS(args, char_args);
1330         for (i = 0; i < args.argc; i++) {
1331                 snprintf(varname, sizeof(varname), "ARG%d", i + 1);
1332                 pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
1333         }
1334
1335         ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
1336         chan = ast_channel_unref(chan);
1337
1338         if (a->argc == 5 && !strcmp(a->argv[4], "exec")) {
1339                 /* Execute the query */
1340                 struct dsn *dsn = NULL;
1341                 int dsn_num, executed = 0;
1342                 SQLHSTMT stmt;
1343                 int rows = 0, res, x;
1344                 SQLSMALLINT colcount = 0, collength;
1345                 SQLLEN indicator;
1346                 struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
1347                 char colname[256];
1348                 SQLULEN maxcol;
1349
1350                 if (!coldata) {
1351                         AST_RWLIST_UNLOCK(&queries);
1352                         return CLI_SUCCESS;
1353                 }
1354
1355                 for (dsn_num = 0; dsn_num < 5; dsn_num++) {
1356                         if (ast_strlen_zero(query->readhandle[dsn_num])) {
1357                                 continue;
1358                         }
1359                         dsn = get_dsn(query->readhandle[dsn_num]);
1360                         if (!dsn) {
1361                                 continue;
1362                         }
1363                         ast_debug(1, "Found handle %s\n", query->readhandle[dsn_num]);
1364
1365                         if (!(stmt = ast_odbc_direct_execute(dsn->connection, generic_execute, ast_str_buffer(sql)))) {
1366                                 dsn = release_dsn(dsn);
1367                                 continue;
1368                         }
1369
1370                         executed = 1;
1371
1372                         res = SQLNumResultCols(stmt, &colcount);
1373                         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1374                                 ast_cli(a->fd, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
1375                                 SQLCloseCursor(stmt);
1376                                 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1377                                 dsn = release_dsn(dsn);
1378                                 AST_RWLIST_UNLOCK(&queries);
1379                                 return CLI_SUCCESS;
1380                         }
1381
1382                         res = SQLFetch(stmt);
1383                         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1384                                 SQLCloseCursor(stmt);
1385                                 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1386                                 dsn = release_dsn(dsn);
1387                                 if (res == SQL_NO_DATA) {
1388                                         ast_cli(a->fd, "Returned %d rows.  Query executed on handle %d:%s [%s]\n", rows, dsn_num, query->readhandle[dsn_num], ast_str_buffer(sql));
1389                                         break;
1390                                 } else {
1391                                         ast_cli(a->fd, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
1392                                 }
1393                                 AST_RWLIST_UNLOCK(&queries);
1394                                 return CLI_SUCCESS;
1395                         }
1396                         for (;;) {
1397                                 for (x = 0; x < colcount; x++) {
1398                                         maxcol = 0;
1399
1400                                         res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL);
1401                                         if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
1402                                                 snprintf(colname, sizeof(colname), "field%d", x);
1403                                         }
1404
1405                                         res = ast_odbc_ast_str_SQLGetData(&coldata, maxcol, stmt, x + 1, SQL_CHAR, &indicator);
1406                                         if (indicator == SQL_NULL_DATA) {
1407                                                 ast_str_set(&coldata, 0, "(nil)");
1408                                                 res = SQL_SUCCESS;
1409                                         }
1410
1411                                         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1412                                                 ast_cli(a->fd, "SQL Get Data error %d!\n[%s]\n\n", res, ast_str_buffer(sql));
1413                                                 SQLCloseCursor(stmt);
1414                                                 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1415                                                 dsn = release_dsn(dsn);
1416                                                 AST_RWLIST_UNLOCK(&queries);
1417                                                 return CLI_SUCCESS;
1418                                         }
1419
1420                                         ast_cli(a->fd, "%-20.20s  %s\n", colname, ast_str_buffer(coldata));
1421                                 }
1422                                 rows++;
1423
1424                                 /* Get next row */
1425                                 res = SQLFetch(stmt);
1426                                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1427                                         break;
1428                                 }
1429                                 ast_cli(a->fd, "%-20.20s  %s\n", "----------", "----------");
1430                         }
1431                         SQLCloseCursor(stmt);
1432                         SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1433                         dsn = release_dsn(dsn);
1434                         ast_cli(a->fd, "Returned %d row%s.  Query executed on handle %d [%s]\n", rows, rows == 1 ? "" : "s", dsn_num, query->readhandle[dsn_num]);
1435                         break;
1436                 }
1437                 dsn = release_dsn(dsn);
1438
1439                 if (!executed) {
1440                         ast_cli(a->fd, "Failed to execute query. [%s]\n", ast_str_buffer(sql));
1441                 }
1442         } else { /* No execution, just print out the resulting SQL */
1443                 ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
1444         }
1445         AST_RWLIST_UNLOCK(&queries);
1446         return CLI_SUCCESS;
1447 }
1448
1449 static char *cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1450 {
1451         AST_DECLARE_APP_ARGS(values,
1452                 AST_APP_ARG(field)[100];
1453         );
1454         AST_DECLARE_APP_ARGS(args,
1455                 AST_APP_ARG(field)[100];
1456         );
1457         struct ast_str *sql;
1458         char *char_args, *char_values, varname[10];
1459         struct acf_odbc_query *query;
1460         struct ast_channel *chan;
1461         int i;
1462
1463         switch (cmd) {
1464         case CLI_INIT:
1465                 e->command = "odbc write";
1466                 e->usage =
1467                         "Usage: odbc write <name> <args> <value> [exec]\n"
1468                         "       Evaluates the SQL provided in the ODBC function <name>, and\n"
1469                         "       optionally executes the function.  This function is intended for\n"
1470                         "       testing purposes.  Remember to quote arguments containing spaces.\n";
1471                 return NULL;
1472         case CLI_GENERATE:
1473                 if (a->pos == 2) {
1474                         int wordlen = strlen(a->word), which = 0;
1475                         /* Complete function name */
1476                         AST_RWLIST_RDLOCK(&queries);
1477                         AST_RWLIST_TRAVERSE(&queries, query, list) {
1478                                 if (!strncasecmp(query->acf->name, a->word, wordlen)) {
1479                                         if (++which > a->n) {
1480                                                 char *res = ast_strdup(query->acf->name);
1481                                                 AST_RWLIST_UNLOCK(&queries);
1482                                                 return res;
1483                                         }
1484                                 }
1485                         }
1486                         AST_RWLIST_UNLOCK(&queries);
1487                         return NULL;
1488                 } else if (a->pos == 5) {
1489                         return a->n == 0 ? ast_strdup("exec") : NULL;
1490                 } else {
1491                         return NULL;
1492                 }
1493         }
1494
1495         if (a->argc < 5 || a->argc > 6) {
1496                 return CLI_SHOWUSAGE;
1497         }
1498
1499         sql = ast_str_thread_get(&sql_buf, 16);
1500         if (!sql) {
1501                 return CLI_FAILURE;
1502         }
1503
1504         AST_RWLIST_RDLOCK(&queries);
1505         AST_RWLIST_TRAVERSE(&queries, query, list) {
1506                 if (!strcmp(query->acf->name, a->argv[2])) {
1507                         break;
1508                 }
1509         }
1510
1511         if (!query) {
1512                 ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
1513                 AST_RWLIST_UNLOCK(&queries);
1514                 return CLI_SHOWUSAGE;
1515         }
1516
1517         if (!query->sql_write) {
1518                 ast_cli(a->fd, "The function %s has no writesql parameter.\n", a->argv[2]);
1519                 AST_RWLIST_UNLOCK(&queries);
1520                 return CLI_SUCCESS;
1521         }
1522
1523         /* FIXME: The code below duplicates code found in acf_odbc_write but
1524          * lacks the newer sql_insert additions. */
1525
1526         ast_str_make_space(&sql, strlen(query->sql_write) * 2 + 300);
1527
1528         /* Evaluate function */
1529         char_args = ast_strdupa(a->argv[3]);
1530         char_values = ast_strdupa(a->argv[4]);
1531
1532         chan = ast_dummy_channel_alloc();
1533         if (!chan) {
1534                 AST_RWLIST_UNLOCK(&queries);
1535                 return CLI_FAILURE;
1536         }
1537
1538         AST_STANDARD_APP_ARGS(args, char_args);
1539         for (i = 0; i < args.argc; i++) {
1540                 snprintf(varname, sizeof(varname), "ARG%d", i + 1);
1541                 pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
1542         }
1543
1544         /* Parse values, just like arguments */
1545         AST_STANDARD_APP_ARGS(values, char_values);
1546         for (i = 0; i < values.argc; i++) {
1547                 snprintf(varname, sizeof(varname), "VAL%d", i + 1);
1548                 pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
1549         }
1550
1551         /* Additionally set the value as a whole (but push an empty string if value is NULL) */
1552         pbx_builtin_pushvar_helper(chan, "VALUE", S_OR(a->argv[4], ""));
1553         ast_str_substitute_variables(&sql, 0, chan, query->sql_write);
1554         ast_debug(1, "SQL is %s\n", ast_str_buffer(sql));
1555
1556         chan = ast_channel_unref(chan);
1557
1558         if (a->argc == 6 && !strcmp(a->argv[5], "exec")) {
1559                 /* Execute the query */
1560                 struct dsn *dsn;
1561                 int dsn_num, executed = 0;
1562                 SQLHSTMT stmt;
1563                 SQLLEN rows = -1;
1564
1565                 for (dsn_num = 0; dsn_num < 5; dsn_num++) {
1566                         if (ast_strlen_zero(query->writehandle[dsn_num])) {
1567                                 continue;
1568                         }
1569                         dsn = get_dsn(query->writehandle[dsn_num]);
1570                         if (!dsn) {
1571                                 continue;
1572                         }
1573                         if (!(stmt = ast_odbc_direct_execute(dsn->connection, generic_execute, ast_str_buffer(sql)))) {
1574                                 dsn = release_dsn(dsn);
1575                                 continue;
1576                         }
1577
1578                         SQLRowCount(stmt, &rows);
1579                         SQLCloseCursor(stmt);
1580                         SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1581                         dsn = release_dsn(dsn);
1582                         ast_cli(a->fd, "Affected %d rows.  Query executed on handle %d [%s]\n", (int)rows, dsn_num, query->writehandle[dsn_num]);
1583                         executed = 1;
1584                         break;
1585                 }
1586
1587                 if (!executed) {
1588                         ast_cli(a->fd, "Failed to execute query.\n");
1589                 }
1590         } else { /* No execution, just print out the resulting SQL */
1591                 ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
1592         }
1593         AST_RWLIST_UNLOCK(&queries);
1594         return CLI_SUCCESS;
1595 }
1596
1597 static struct ast_cli_entry cli_func_odbc[] = {
1598         AST_CLI_DEFINE(cli_odbc_write, "Test setting a func_odbc function"),
1599         AST_CLI_DEFINE(cli_odbc_read, "Test reading a func_odbc function"),
1600 };
1601
1602 static int load_module(void)
1603 {
1604         int res = 0;
1605         struct ast_config *cfg;
1606         char *catg;
1607         struct ast_flags config_flags = { 0 };
1608
1609         dsns = ao2_container_alloc(DSN_BUCKETS, dsn_hash, dsn_cmp);
1610         if (!dsns) {
1611                 return AST_MODULE_LOAD_DECLINE;
1612         }
1613
1614         res |= ast_custom_function_register(&fetch_function);
1615         res |= ast_register_application_xml(app_odbcfinish, exec_odbcfinish);
1616         AST_RWLIST_WRLOCK(&queries);
1617
1618         cfg = ast_config_load(config, config_flags);
1619         if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
1620                 ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config);
1621                 AST_RWLIST_UNLOCK(&queries);
1622                 ao2_ref(dsns, -1);
1623                 return AST_MODULE_LOAD_DECLINE;
1624         }
1625
1626         for (catg = ast_category_browse(cfg, NULL);
1627              catg;
1628              catg = ast_category_browse(cfg, catg)) {
1629                 struct acf_odbc_query *query = NULL;
1630                 int err;
1631
1632                 if ((err = init_acf_query(cfg, catg, &query))) {
1633                         if (err == ENOMEM)
1634                                 ast_log(LOG_ERROR, "Out of memory\n");
1635                         else if (err == EINVAL)
1636                                 ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg);
1637                         else
1638                                 ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err);
1639                 } else {
1640                         AST_RWLIST_INSERT_HEAD(&queries, query, list);
1641                         ast_custom_function_register(query->acf);
1642                 }
1643         }
1644
1645         ast_config_destroy(cfg);
1646         res |= ast_custom_function_register(&escape_function);
1647         ast_cli_register_multiple(cli_func_odbc, ARRAY_LEN(cli_func_odbc));
1648
1649         AST_RWLIST_UNLOCK(&queries);
1650         return res;
1651 }
1652
1653 static int unload_module(void)
1654 {
1655         struct acf_odbc_query *query;
1656         int res = 0;
1657
1658         AST_RWLIST_WRLOCK(&queries);
1659         while (!AST_RWLIST_EMPTY(&queries)) {
1660                 query = AST_RWLIST_REMOVE_HEAD(&queries, list);
1661                 ast_custom_function_unregister(query->acf);
1662                 free_acf_query(query);
1663         }
1664
1665         res |= ast_custom_function_unregister(&escape_function);
1666         res |= ast_custom_function_unregister(&fetch_function);
1667         res |= ast_unregister_application(app_odbcfinish);
1668         ast_cli_unregister_multiple(cli_func_odbc, ARRAY_LEN(cli_func_odbc));
1669
1670         /* Allow any threads waiting for this lock to pass (avoids a race) */
1671         AST_RWLIST_UNLOCK(&queries);
1672         usleep(1);
1673         AST_RWLIST_WRLOCK(&queries);
1674
1675         AST_RWLIST_UNLOCK(&queries);
1676
1677         ao2_ref(dsns, -1);
1678         return res;
1679 }
1680
1681 static int reload(void)
1682 {
1683         int res = 0;
1684         struct ast_config *cfg;
1685         struct acf_odbc_query *oldquery;
1686         char *catg;
1687         struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
1688
1689         cfg = ast_config_load(config, config_flags);
1690         if (cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
1691                 return 0;
1692
1693         AST_RWLIST_WRLOCK(&queries);
1694
1695         while (!AST_RWLIST_EMPTY(&queries)) {
1696                 oldquery = AST_RWLIST_REMOVE_HEAD(&queries, list);
1697                 ast_custom_function_unregister(oldquery->acf);
1698                 free_acf_query(oldquery);
1699         }
1700
1701         if (!cfg) {
1702                 ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config);
1703                 goto reload_out;
1704         }
1705
1706         for (catg = ast_category_browse(cfg, NULL);
1707              catg;
1708              catg = ast_category_browse(cfg, catg)) {
1709                 struct acf_odbc_query *query = NULL;
1710
1711                 if (init_acf_query(cfg, catg, &query)) {
1712                         ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg);
1713                 } else {
1714                         AST_RWLIST_INSERT_HEAD(&queries, query, list);
1715                         ast_custom_function_register(query->acf);
1716                 }
1717         }
1718
1719         ast_config_destroy(cfg);
1720 reload_out:
1721         AST_RWLIST_UNLOCK(&queries);
1722         return res;
1723 }
1724
1725 /* XXX need to revise usecount - set if query_lock is set */
1726
1727 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ODBC lookups",
1728         .support_level = AST_MODULE_SUPPORT_CORE,
1729         .load = load_module,
1730         .unload = unload_module,
1731         .reload = reload,
1732 );
1733