update asterisk to new upstream release (v1.2.1)
[openwrt.git] / openwrt / package / asterisk / patches / asterisk-1.2.0-res_mysql.patch
1 diff -ruN asterisk-1.2.0-old/configs/res_mysql.conf.sample asterisk-1.2.0-new/configs/res_mysql.conf.sample
2 --- asterisk-1.2.0-old/configs/res_mysql.conf.sample    1970-01-01 01:00:00.000000000 +0100
3 +++ asterisk-1.2.0-new/configs/res_mysql.conf.sample    2004-12-03 15:33:44.000000000 +0100
4 @@ -0,0 +1,15 @@
5 +;
6 +; Sample configuration for res_config_mysql.c
7 +;
8 +; The value of dbhost may be either a hostname or an IP address.
9 +; If dbhost is commented out or the string "localhost", a connection
10 +; to the local host is assumed and dbsock is used instead of TCP/IP
11 +; to connect to the server.
12 +;
13 +[general]
14 +;dbhost = 127.0.0.1
15 +;dbname = asterisk
16 +;dbuser = myuser
17 +;dbpass = mypass
18 +;dbport = 3306
19 +;dbsock = /tmp/mysql.sock
20 diff -ruN asterisk-1.2.0-old/res/res_config_mysql.c asterisk-1.2.0-new/res/res_config_mysql.c
21 --- asterisk-1.2.0-old/res/res_config_mysql.c   1970-01-01 01:00:00.000000000 +0100
22 +++ asterisk-1.2.0-new/res/res_config_mysql.c   2005-10-13 21:43:54.000000000 +0200
23 @@ -0,0 +1,675 @@
24 +/*
25 + * Asterisk -- A telephony toolkit for Linux.
26 + *
27 + * Copyright (C) 1999-2005, Digium, Inc.
28 + *
29 + * Mark Spencer <markster@digium.com>  - Asterisk Author
30 + * Matthew Boehm <mboehm@cytelcom.com> - MySQL RealTime Driver Author
31 + *
32 + * res_config_mysql.c <mysql plugin for RealTime configuration engine>
33 + *
34 + * v2.0   - (10-07-05) - mutex_lock fixes (bug #4973, comment #0034602)
35 + *
36 + * v1.9   - (08-19-05) - Added support to correctly honor the family database specified
37 + *                       in extconfig.conf (bug #4973)
38 + *
39 + * v1.8   - (04-21-05) - Modified return values of update_mysql to better indicate
40 + *                       what really happened.
41 + *
42 + * v1.7   - (01-28-05) - Fixed non-initialization of ast_category struct
43 + *                       in realtime_multi_mysql function which caused segfault. 
44 + *
45 + * v1.6   - (00-00-00) - Skipped to bring comments into sync with version number in CVS.
46 + *
47 + * v1.5.1 - (01-26-05) - Added better(?) locking stuff
48 + *
49 + * v1.5   - (01-26-05) - Brought up to date with new config.h changes (bug #3406)
50 + *                     - Added in extra locking provided by georg (bug #3248)
51 + *
52 + * v1.4   - (12-02-04) - Added realtime_multi_mysql function
53 + *                        This function will return an ast_config with categories,
54 + *                        unlike standard realtime_mysql which only returns
55 + *                        a linked list of ast_variables
56 + *
57 + * v1.3   - (12-01-04) - Added support other operators
58 + *                       Ex: =, !=, LIKE, NOT LIKE, RLIKE, etc...
59 + *
60 + * v1.2   - (11-DD-04) - Added reload. Updated load and unload.
61 + *                       Code beautification (doc/CODING-GUIDELINES)
62 + */
63 +
64 +#include <asterisk/channel.h>
65 +#include <asterisk/logger.h>
66 +#include <asterisk/config.h>
67 +#include <asterisk/module.h>
68 +#include <asterisk/lock.h>
69 +#include <asterisk/options.h>
70 +#include <asterisk/cli.h>
71 +#include <asterisk/utils.h>
72 +#include <stdlib.h>
73 +#include <string.h>
74 +#include <mysql.h>
75 +#include <mysql_version.h>
76 +#include <errmsg.h>
77 +
78 +static char *res_config_mysql_desc = "MySQL RealTime Configuration Driver";
79 +
80 +AST_MUTEX_DEFINE_STATIC(mysql_lock);
81 +#define RES_CONFIG_MYSQL_CONF "res_mysql.conf"
82 +MYSQL         mysql;
83 +static char   dbhost[50];
84 +static char   dbuser[50];
85 +static char   dbpass[50];
86 +static char   dbname[50];
87 +static char   dbsock[50];
88 +static int    dbport;
89 +static int    connected;
90 +static time_t connect_time;
91 +
92 +static int parse_config(void);
93 +static int mysql_reconnect(const char *database);
94 +static int realtime_mysql_status(int fd, int argc, char **argv);
95 +
96 +STANDARD_LOCAL_USER;
97 +
98 +LOCAL_USER_DECL;
99 +
100 +static char cli_realtime_mysql_status_usage[] =
101 +"Usage: realtime mysql status\n"
102 +"       Shows connection information for the MySQL RealTime driver\n";
103 +
104 +static struct ast_cli_entry cli_realtime_mysql_status = {
105 +        { "realtime", "mysql", "status", NULL }, realtime_mysql_status,
106 +        "Shows connection information for the MySQL RealTime driver", cli_realtime_mysql_status_usage, NULL };
107 +
108 +static struct ast_variable *realtime_mysql(const char *database, const char *table, va_list ap)
109 +{
110 +       MYSQL_RES *result;
111 +       MYSQL_ROW row;
112 +       MYSQL_FIELD *fields;
113 +       int numFields, i;
114 +       char sql[256];
115 +       char *stringp;
116 +       char *chunk;
117 +       char *op;
118 +       const char *newparam, *newval;
119 +       struct ast_variable *var=NULL, *prev=NULL;
120 +
121 +       if(!table) {
122 +               ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
123 +               return NULL;
124 +       }
125 +
126 +       /* Get the first parameter and first value in our list of passed paramater/value pairs */
127 +       newparam = va_arg(ap, const char *);
128 +       newval = va_arg(ap, const char *);
129 +       if(!newparam || !newval)  {
130 +               ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
131 +               mysql_close(&mysql);
132 +               return NULL;
133 +       }
134 +
135 +       /* Create the first part of the query using the first parameter/value pairs we just extracted
136 +          If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
137 +
138 +       if(!strchr(newparam, ' ')) op = " ="; else op = "";
139 +
140 +       snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, newval);
141 +       while((newparam = va_arg(ap, const char *))) {
142 +               newval = va_arg(ap, const char *);
143 +               if(!strchr(newparam, ' ')) op = " ="; else op = "";
144 +               snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam, op, newval);
145 +       }
146 +       va_end(ap);
147 +
148 +       ast_log(LOG_DEBUG, "MySQL RealTime: Retrieve SQL: %s\n", sql);
149 +
150 +       /* We now have our complete statement; Lets connect to the server and execute it. */
151 +       ast_mutex_lock(&mysql_lock);
152 +       if(!mysql_reconnect(database)) {
153 +               ast_mutex_unlock(&mysql_lock);
154 +               return NULL;
155 +       }
156 +
157 +       if(mysql_real_query(&mysql, sql, strlen(sql))) {
158 +               ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
159 +               ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
160 +               ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
161 +               ast_mutex_unlock(&mysql_lock);
162 +               return NULL;
163 +       }
164 +
165 +       if((result = mysql_store_result(&mysql))) {
166 +               numFields = mysql_num_fields(result);
167 +               fields = mysql_fetch_fields(result);
168 +
169 +               while((row = mysql_fetch_row(result))) {
170 +                       for(i = 0; i < numFields; i++) {
171 +                               stringp = row[i];
172 +                               while(stringp) {
173 +                                       chunk = strsep(&stringp, ";");
174 +                                       if(chunk && !ast_strlen_zero(ast_strip(chunk))) {
175 +                                               if(prev) {
176 +                                                       prev->next = ast_variable_new(fields[i].name, chunk);
177 +                                                       if (prev->next) {
178 +                                                               prev = prev->next;
179 +                                                       }
180 +                                               } else {
181 +                                                       prev = var = ast_variable_new(fields[i].name, chunk);
182 +                                               }
183 +                                       }
184 +                               }
185 +                       }
186 +               }
187 +       } else {                                
188 +               ast_log(LOG_WARNING, "MySQL RealTime: Could not find any rows in table %s.\n", table);
189 +       }
190 +
191 +       ast_mutex_unlock(&mysql_lock);
192 +       mysql_free_result(result);
193 +
194 +       return var;
195 +}
196 +
197 +static struct ast_config *realtime_multi_mysql(const char *database, const char *table, va_list ap)
198 +{
199 +       MYSQL_RES *result;
200 +       MYSQL_ROW row;
201 +       MYSQL_FIELD *fields;
202 +       int numFields, i;
203 +       char sql[256];
204 +       const char *initfield = NULL;
205 +       char *stringp;
206 +       char *chunk;
207 +       char *op;
208 +       const char *newparam, *newval;
209 +       struct ast_realloca ra;
210 +       struct ast_variable *var=NULL;
211 +       struct ast_config *cfg = NULL;
212 +       struct ast_category *cat = NULL;
213 +
214 +       if(!table) {
215 +               ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
216 +               return NULL;
217 +       }
218 +       
219 +       memset(&ra, 0, sizeof(ra));
220 +
221 +       cfg = ast_config_new();
222 +       if (!cfg) {
223 +               /* If I can't alloc memory at this point, why bother doing anything else? */
224 +               ast_log(LOG_WARNING, "Out of memory!\n");
225 +               return NULL;
226 +       }
227 +
228 +       /* Get the first parameter and first value in our list of passed paramater/value pairs */
229 +       newparam = va_arg(ap, const char *);
230 +       newval = va_arg(ap, const char *);
231 +       if(!newparam || !newval)  {
232 +               ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
233 +               mysql_close(&mysql);
234 +               return NULL;
235 +       }
236 +
237 +       initfield = ast_strdupa(newparam);
238 +       if(initfield && (op = strchr(initfield, ' '))) {
239 +               *op = '\0';
240 +       }
241 +
242 +       /* Create the first part of the query using the first parameter/value pairs we just extracted
243 +          If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
244 +
245 +       if(!strchr(newparam, ' ')) op = " ="; else op = "";
246 +
247 +       snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, newval);
248 +       while((newparam = va_arg(ap, const char *))) {
249 +               newval = va_arg(ap, const char *);
250 +               if(!strchr(newparam, ' ')) op = " ="; else op = "";
251 +               snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam, op, newval);
252 +       }
253 +
254 +       if(initfield) {
255 +               snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
256 +       }
257 +
258 +       va_end(ap);
259 +
260 +       ast_log(LOG_DEBUG, "MySQL RealTime: Retrieve SQL: %s\n", sql);
261 +
262 +       /* We now have our complete statement; Lets connect to the server and execute it. */
263 +       ast_mutex_lock(&mysql_lock);
264 +       if(!mysql_reconnect(database)) {
265 +               ast_mutex_unlock(&mysql_lock);
266 +               return NULL;
267 +       }
268 +
269 +       if(mysql_real_query(&mysql, sql, strlen(sql))) {
270 +               ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
271 +               ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
272 +               ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
273 +               ast_mutex_unlock(&mysql_lock);
274 +               return NULL;
275 +       }
276 +
277 +       if((result = mysql_store_result(&mysql))) {
278 +               numFields = mysql_num_fields(result);
279 +               fields = mysql_fetch_fields(result);
280 +
281 +               while((row = mysql_fetch_row(result))) {
282 +                       var = NULL;
283 +                       cat = ast_category_new("");
284 +                       if(!cat) {
285 +                               ast_log(LOG_WARNING, "Out of memory!\n");
286 +                               continue;
287 +                       }
288 +                       for(i = 0; i < numFields; i++) {
289 +                               stringp = row[i];
290 +                               while(stringp) {
291 +                                       chunk = strsep(&stringp, ";");
292 +                                       if(chunk && !ast_strlen_zero(ast_strip(chunk))) {
293 +                                               if(initfield && !strcmp(initfield, fields[i].name)) {
294 +                                                       ast_category_rename(cat, chunk);
295 +                                               }
296 +                                               var = ast_variable_new(fields[i].name, chunk);
297 +                                               ast_variable_append(cat, var);
298 +                                       }
299 +                               }
300 +                       }
301 +                       ast_category_append(cfg, cat);
302 +               }
303 +       } else {
304 +               ast_log(LOG_WARNING, "MySQL RealTime: Could not find any rows in table %s.\n", table);
305 +       }
306 +
307 +       ast_mutex_unlock(&mysql_lock);
308 +       mysql_free_result(result);
309 +
310 +       return cfg;
311 +}
312 +
313 +static int update_mysql(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
314 +{
315 +       my_ulonglong numrows;
316 +       char sql[256];
317 +       const char *newparam, *newval;
318 +
319 +       if(!table) {
320 +               ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
321 +               return -1;
322 +       }
323 +
324 +       /* Get the first parameter and first value in our list of passed paramater/value pairs */
325 +       newparam = va_arg(ap, const char *);
326 +       newval = va_arg(ap, const char *);
327 +       if(!newparam || !newval)  {
328 +               ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
329 +               mysql_close(&mysql);
330 +               return -1;
331 +       }
332 +
333 +       /* Create the first part of the query using the first parameter/value pairs we just extracted
334 +          If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
335 +
336 +       snprintf(sql, sizeof(sql), "UPDATE %s SET %s = '%s'", table, newparam, newval);
337 +       while((newparam = va_arg(ap, const char *))) {
338 +               newval = va_arg(ap, const char *);
339 +               snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s = '%s'", newparam, newval);
340 +       }
341 +       va_end(ap);
342 +       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s = '%s'", keyfield, lookup);
343 +
344 +       ast_log(LOG_DEBUG,"MySQL RealTime: Update SQL: %s\n", sql);
345 +
346 +       /* We now have our complete statement; Lets connect to the server and execute it. */
347 +       ast_mutex_lock(&mysql_lock);
348 +       if(!mysql_reconnect(database)) {
349 +               ast_mutex_unlock(&mysql_lock);
350 +               return -1;
351 +       }
352 +
353 +       if(mysql_real_query(&mysql, sql, strlen(sql))) {
354 +               ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
355 +               ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
356 +               ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
357 +               ast_mutex_unlock(&mysql_lock);
358 +               return -1;
359 +       }
360 +
361 +       numrows = mysql_affected_rows(&mysql);
362 +       ast_mutex_unlock(&mysql_lock);
363 +
364 +       ast_log(LOG_DEBUG,"MySQL RealTime: Updated %llu rows on table: %s\n", numrows, table);
365 +
366 +       /* From http://dev.mysql.com/doc/mysql/en/mysql-affected-rows.html
367 +        * An integer greater than zero indicates the number of rows affected
368 +        * Zero indicates that no records were updated
369 +        * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
370 +       */
371 +
372 +       if(numrows >= 0)
373 +               return (int)numrows;
374 +
375 +       return -1;
376 +}
377 +
378 +static struct ast_config *config_mysql(const char *database, const char *table, const char *file, struct ast_config *cfg)
379 +{
380 +       MYSQL_RES *result;
381 +       MYSQL_ROW row;
382 +       my_ulonglong num_rows;
383 +       struct ast_config *new;
384 +       struct ast_variable *cur_v, *new_v;
385 +       struct ast_category *cur_cat, *new_cat;
386 +       char sql[250] = "";
387 +       char last[80] = "";
388 +       int cat_started = 0;
389 +       int var_started = 0;
390 +       int last_cat_metric = 0;
391 +
392 +       last[0] = '\0';
393 +
394 +       if(!file || !strcmp(file, RES_CONFIG_MYSQL_CONF)) {
395 +               ast_log(LOG_WARNING, "MySQL RealTime: Cannot configure myself.\n");
396 +               return NULL;
397 +       }
398 +
399 +       snprintf(sql, sizeof(sql), "SELECT category, var_name, var_val, cat_metric FROM %s WHERE filename='%s' and commented=0 ORDER BY filename, cat_metric desc, var_metric asc, category, var_name, var_val, id", table, file);
400 +
401 +       ast_log(LOG_DEBUG, "MySQL RealTime: Static SQL: %s\n", sql);
402 +
403 +       /* We now have our complete statement; Lets connect to the server and execute it. */
404 +       ast_mutex_lock(&mysql_lock);
405 +       if(!mysql_reconnect(database)) {
406 +               ast_mutex_unlock(&mysql_lock);
407 +               return NULL;
408 +       }
409 +
410 +       if(mysql_real_query(&mysql, sql, strlen(sql))) {
411 +               ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
412 +               ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
413 +               ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
414 +               ast_mutex_unlock(&mysql_lock);
415 +               return NULL;
416 +       }
417 +
418 +       if((result = mysql_store_result(&mysql))) {
419 +               num_rows = mysql_num_rows(result);
420 +               ast_log(LOG_DEBUG, "MySQL RealTime: Found %llu rows.\n", num_rows);
421 +
422 +               /* There might exist a better way to access the column names other than counting,
423 +                   but I believe that would require another loop that we don't need. */
424 +
425 +               while((row = mysql_fetch_row(result))) {
426 +                       if(!strcmp(row[1], "#include")) {
427 +                               if (!ast_config_internal_load(row[2], cfg)) {
428 +                                       mysql_free_result(result);
429 +                                       ast_mutex_unlock(&mysql_lock);
430 +                                       return NULL;
431 +                               }
432 +                               continue;
433 +                       }
434 +
435 +                       if(strcmp(last, row[0]) || last_cat_metric != atoi(row[3])) {
436 +                               cur_cat = ast_category_new(row[0]);
437 +                               if (!cur_cat) {
438 +                                       ast_log(LOG_WARNING, "Out of memory!\n");
439 +                                       break;
440 +                               }
441 +                               strcpy(last, row[0]);
442 +                               last_cat_metric = atoi(row[3]);
443 +                               ast_category_append(cfg, cur_cat);
444 +                       }
445 +                       new_v = ast_variable_new(row[1], row[2]);
446 +                       ast_variable_append(cur_cat, new_v);
447 +               }
448 +       } else {
449 +               ast_log(LOG_WARNING, "MySQL RealTime: Could not find config '%s' in database.\n", file);
450 +       }
451 +
452 +       mysql_free_result(result);
453 +       ast_mutex_unlock(&mysql_lock);
454 +
455 +       return cfg;
456 +}
457 +
458 +static struct ast_config_engine mysql_engine = {
459 +       .name = "mysql",
460 +       .load_func = config_mysql,
461 +       .realtime_func = realtime_mysql,
462 +       .realtime_multi_func = realtime_multi_mysql,
463 +       .update_func = update_mysql
464 +};
465 +
466 +int load_module (void)
467 +{
468 +       parse_config();
469 +
470 +       ast_mutex_lock(&mysql_lock);
471 +
472 +       if(!mysql_reconnect(NULL)) {
473 +               ast_log(LOG_WARNING, "MySQL RealTime: Couldn't establish connection. Check debug.\n");
474 +               ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect: %s\n", mysql_error(&mysql));
475 +       }
476 +
477 +       ast_config_engine_register(&mysql_engine);
478 +       if(option_verbose) {
479 +               ast_verbose("MySQL RealTime driver loaded.\n");
480 +       }
481 +       ast_cli_register(&cli_realtime_mysql_status);
482 +
483 +       ast_mutex_unlock(&mysql_lock);
484 +
485 +       return 0;
486 +}
487 +
488 +int unload_module (void)
489 +{
490 +       /* Aquire control before doing anything to the module itself. */
491 +       ast_mutex_lock(&mysql_lock);
492 +
493 +       mysql_close(&mysql);
494 +       ast_cli_unregister(&cli_realtime_mysql_status);
495 +       ast_config_engine_deregister(&mysql_engine);
496 +       if(option_verbose) {
497 +               ast_verbose("MySQL RealTime unloaded.\n");
498 +       }
499 +
500 +       STANDARD_HANGUP_LOCALUSERS;
501 +
502 +       /* Unlock so something else can destroy the lock. */
503 +       ast_mutex_unlock(&mysql_lock);
504 +
505 +       return 0;
506 +}
507 +
508 +int reload (void)
509 +{
510 +       /* Aquire control before doing anything to the module itself. */
511 +       ast_mutex_lock(&mysql_lock);
512 +
513 +       mysql_close(&mysql);
514 +       connected = 0;
515 +       parse_config();
516 +
517 +       if(!mysql_reconnect(NULL)) {
518 +               ast_log(LOG_WARNING, "MySQL RealTime: Couldn't establish connection. Check debug.\n");
519 +               ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect: %s\n", mysql_error(&mysql));
520 +       }
521 +
522 +       ast_verbose(VERBOSE_PREFIX_2 "MySQL RealTime reloaded.\n");
523 +
524 +       /* Done reloading. Release lock so others can now use driver. */
525 +       ast_mutex_unlock(&mysql_lock);
526 +
527 +       return 0;
528 +}
529 +
530 +int parse_config (void)
531 +{
532 +       struct ast_config *config;
533 +       char *s;
534 +
535 +       config = ast_config_load(RES_CONFIG_MYSQL_CONF);
536 +
537 +       if(config) {
538 +               if(!(s=ast_variable_retrieve(config, "general", "dbuser"))) {
539 +                       ast_log(LOG_WARNING, "MySQL RealTime: No database user found, using 'asterisk' as default.\n");
540 +                       strncpy(dbuser, "asterisk", sizeof(dbuser) - 1);
541 +               } else {
542 +                       strncpy(dbuser, s, sizeof(dbuser) - 1);
543 +               }
544 +
545 +               if(!(s=ast_variable_retrieve(config, "general", "dbpass"))) {
546 +                        ast_log(LOG_WARNING, "MySQL RealTime: No database password found, using 'asterisk' as default.\n");
547 +                        strncpy(dbpass, "asterisk", sizeof(dbpass) - 1);
548 +                } else {
549 +                        strncpy(dbpass, s, sizeof(dbpass) - 1);
550 +                }
551 +
552 +               if(!(s=ast_variable_retrieve(config, "general", "dbhost"))) {
553 +                        ast_log(LOG_WARNING, "MySQL RealTime: No database host found, using localhost via socket.\n");
554 +                       dbhost[0] = '\0';
555 +                } else {
556 +                        strncpy(dbhost, s, sizeof(dbhost) - 1);
557 +                }
558 +
559 +               if(!(s=ast_variable_retrieve(config, "general", "dbname"))) {
560 +                        ast_log(LOG_WARNING, "MySQL RealTime: No database name found, using 'asterisk' as default.\n");
561 +                       strncpy(dbname, "asterisk", sizeof(dbname) - 1);
562 +                } else {
563 +                        strncpy(dbname, s, sizeof(dbname) - 1);
564 +                }
565 +
566 +               if(!(s=ast_variable_retrieve(config, "general", "dbport"))) {
567 +                        ast_log(LOG_WARNING, "MySQL RealTime: No database port found, using 3306 as default.\n");
568 +                       dbport = 3306;
569 +                } else {
570 +                       dbport = atoi(s);
571 +                }
572 +
573 +               if(dbhost && !(s=ast_variable_retrieve(config, "general", "dbsock"))) {
574 +                        ast_log(LOG_WARNING, "MySQL RealTime: No database socket found, using '/tmp/mysql.sock' as default.\n");
575 +                        strncpy(dbsock, "/tmp/mysql.sock", sizeof(dbsock) - 1);
576 +                } else {
577 +                        strncpy(dbsock, s, sizeof(dbsock) - 1);
578 +                }
579 +       }
580 +       ast_config_destroy(config);
581 +
582 +       if(dbhost) {
583 +               ast_log(LOG_DEBUG, "MySQL RealTime Host: %s\n", dbhost);
584 +               ast_log(LOG_DEBUG, "MySQL RealTime Port: %i\n", dbport);
585 +       } else {
586 +               ast_log(LOG_DEBUG, "MySQL RealTime Socket: %s\n", dbsock);
587 +       }
588 +       ast_log(LOG_DEBUG, "MySQL RealTime User: %s\n", dbuser);
589 +       ast_log(LOG_DEBUG, "MySQL RealTime Password: %s\n", dbpass);
590 +
591 +       return 1;
592 +}
593 +
594 +char *description (void)
595 +{
596 +       return res_config_mysql_desc;
597 +}
598 +
599 +int usecount (void)
600 +{
601 +       /* Try and get a lock. If unsuccessful, than that means another thread is using the mysql object. */
602 +       if(ast_mutex_trylock(&mysql_lock)) {
603 +               ast_log(LOG_DEBUG, "MySQL RealTime: Module usage count is 1.\n");
604 +               return 1;
605 +       }
606 +       ast_mutex_unlock(&mysql_lock);
607 +       return 0;
608 +}
609 +
610 +char *key ()
611 +{
612 +       return ASTERISK_GPL_KEY;
613 +}
614 +
615 +static int mysql_reconnect(const char *database)
616 +{
617 +       char my_database[50];
618 +
619 +       if(!database || ast_strlen_zero(database))
620 +               ast_copy_string(my_database, dbname, sizeof(my_database));
621 +       else
622 +               ast_copy_string(my_database, database, sizeof(my_database));
623 +
624 +       /* mutex lock should have been locked before calling this function. */
625 +
626 +       if((!connected) && (dbhost || dbsock) && dbuser && dbpass && my_database) {
627 +               if(!mysql_init(&mysql)) {
628 +                       ast_log(LOG_WARNING, "MySQL RealTime: Insufficient memory to allocate MySQL resource.\n");
629 +                       connected = 0;
630 +                       return 0;
631 +               }
632 +               if(mysql_real_connect(&mysql, dbhost, dbuser, dbpass, my_database, dbport, dbsock, 0)) {
633 +                       ast_log(LOG_DEBUG, "MySQL RealTime: Successfully connected to database.\n");
634 +                       connected = 1;
635 +                       connect_time = time(NULL);
636 +                       return 1;
637 +               } else {
638 +                       ast_log(LOG_ERROR, "MySQL RealTime: Failed to connect database server %s on %s. Check debug for more info.\n", dbname, dbhost);
639 +                       ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect: %s\n", mysql_error(&mysql));
640 +                       connected = 0;
641 +                       return 0;
642 +               }
643 +       } else {
644 +               if(mysql_ping(&mysql) != 0) {
645 +                       connected = 0;
646 +                       ast_log(LOG_ERROR, "MySQL RealTime: Failed to reconnect. Check debug for more info.\n");
647 +                       ast_log(LOG_DEBUG, "MySQL RealTime: Server Error: %s\n", mysql_error(&mysql));
648 +                       return 0;
649 +               }
650 +
651 +               connected = 1;
652 +
653 +               if(mysql_select_db(&mysql, my_database) != 0) {
654 +                       ast_log(LOG_WARNING, "MySQL RealTime: Unable to select database: %s. Still Connected.\n", my_database);
655 +                       ast_log(LOG_DEBUG, "MySQL RealTime: Database Select Failed: %s\n", mysql_error(&mysql));
656 +                       return 0;
657 +               }
658 +
659 +               ast_log(LOG_DEBUG, "MySQL RealTime: Everything is fine.\n");
660 +               return 1;
661 +       }
662 +}
663 +
664 +static int realtime_mysql_status(int fd, int argc, char **argv)
665 +{
666 +       char status[256], status2[100] = "";
667 +       int ctime = time(NULL) - connect_time;
668 +
669 +       if(mysql_reconnect(NULL)) {
670 +               if(dbhost) {
671 +                       snprintf(status, 255, "Connected to %s@%s, port %d", dbname, dbhost, dbport);
672 +               } else if(dbsock) {
673 +                       snprintf(status, 255, "Connected to %s on socket file %s", dbname, dbsock);
674 +               } else {
675 +                       snprintf(status, 255, "Connected to %s@%s", dbname, dbhost);
676 +               }
677 +
678 +               if(dbuser && *dbuser) {
679 +                       snprintf(status2, 99, " with username %s", dbuser);
680 +               }
681 +
682 +               if (ctime > 31536000) {
683 +                       ast_cli(fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 31536000, (ctime % 31536000) / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
684 +               } else if (ctime > 86400) {
685 +                       ast_cli(fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
686 +               } else if (ctime > 3600) {
687 +                       ast_cli(fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 3600, (ctime % 3600) / 60, ctime % 60);
688 +               } else if (ctime > 60) {
689 +                       ast_cli(fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60, ctime % 60);
690 +               } else {
691 +                       ast_cli(fd, "%s%s for %d seconds.\n", status, status2, ctime);
692 +               }
693 +
694 +               return RESULT_SUCCESS;
695 +       } else {
696 +               return RESULT_FAILURE;
697 +       }
698 +}