00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "asterisk.h"
00032
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 340863 $")
00034
00035 #include "asterisk/file.h"
00036 #include "asterisk/channel.h"
00037 #include "asterisk/pbx.h"
00038 #include "asterisk/config.h"
00039 #include "asterisk/module.h"
00040 #include "asterisk/lock.h"
00041 #include "asterisk/utils.h"
00042 #include "asterisk/app.h"
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 AST_THREADSTORAGE(buf1);
00175 AST_THREADSTORAGE(buf2);
00176 AST_THREADSTORAGE(buf3);
00177
00178 static int function_realtime_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00179 {
00180 struct ast_variable *var, *head;
00181 struct ast_str *out;
00182 size_t resultslen;
00183 int n;
00184 AST_DECLARE_APP_ARGS(args,
00185 AST_APP_ARG(family);
00186 AST_APP_ARG(fieldmatch);
00187 AST_APP_ARG(value);
00188 AST_APP_ARG(delim1);
00189 AST_APP_ARG(delim2);
00190 );
00191
00192 if (ast_strlen_zero(data)) {
00193 ast_log(LOG_WARNING, "Syntax: REALTIME(family,fieldmatch[,value[,delim1[,delim2]]]) - missing argument!\n");
00194 return -1;
00195 }
00196
00197 AST_STANDARD_APP_ARGS(args, data);
00198
00199 if (!args.delim1)
00200 args.delim1 = ",";
00201 if (!args.delim2)
00202 args.delim2 = "=";
00203
00204 if (chan)
00205 ast_autoservice_start(chan);
00206
00207 head = ast_load_realtime_all(args.family, args.fieldmatch, args.value, SENTINEL);
00208
00209 if (!head) {
00210 if (chan)
00211 ast_autoservice_stop(chan);
00212 return -1;
00213 }
00214
00215 resultslen = 0;
00216 n = 0;
00217 for (var = head; var; n++, var = var->next)
00218 resultslen += strlen(var->name) + strlen(var->value);
00219
00220 resultslen += n * (strlen(args.delim1) + strlen(args.delim2)) + 1;
00221
00222 out = ast_str_alloca(resultslen);
00223 for (var = head; var; var = var->next)
00224 ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
00225 ast_copy_string(buf, ast_str_buffer(out), len);
00226
00227 ast_variables_destroy(head);
00228
00229 if (chan)
00230 ast_autoservice_stop(chan);
00231
00232 return 0;
00233 }
00234
00235 static int function_realtime_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00236 {
00237 int res = 0;
00238 AST_DECLARE_APP_ARGS(args,
00239 AST_APP_ARG(family);
00240 AST_APP_ARG(fieldmatch);
00241 AST_APP_ARG(value);
00242 AST_APP_ARG(field);
00243 );
00244
00245 if (ast_strlen_zero(data)) {
00246 ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,value,newcol) - missing argument!\n", cmd);
00247 return -1;
00248 }
00249
00250 if (chan)
00251 ast_autoservice_start(chan);
00252
00253 AST_STANDARD_APP_ARGS(args, data);
00254
00255 res = ast_update_realtime(args.family, args.fieldmatch, args.value, args.field, (char *)value, SENTINEL);
00256
00257 if (res < 0) {
00258 ast_log(LOG_WARNING, "Failed to update. Check the debug log for possible data repository related entries.\n");
00259 }
00260
00261 if (chan)
00262 ast_autoservice_stop(chan);
00263
00264 return 0;
00265 }
00266
00267 static int realtimefield_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00268 {
00269 struct ast_variable *var, *head;
00270 struct ast_str *escapebuf = ast_str_thread_get(&buf1, 16);
00271 struct ast_str *fields = ast_str_thread_get(&buf2, 16);
00272 struct ast_str *values = ast_str_thread_get(&buf3, 16);
00273 int first = 0;
00274 enum { rtfield, rthash } which;
00275 AST_DECLARE_APP_ARGS(args,
00276 AST_APP_ARG(family);
00277 AST_APP_ARG(fieldmatch);
00278 AST_APP_ARG(value);
00279 AST_APP_ARG(fieldname);
00280 );
00281
00282 if (!strcmp(cmd, "REALTIME_FIELD")) {
00283 which = rtfield;
00284 } else {
00285 which = rthash;
00286 }
00287
00288 if (ast_strlen_zero(data)) {
00289 ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,value%s) - missing argument!\n", cmd, which == rtfield ? ",fieldname" : "");
00290 return -1;
00291 }
00292
00293 AST_STANDARD_APP_ARGS(args, data);
00294
00295 if ((which == rtfield && args.argc != 4) || (which == rthash && args.argc != 3)) {
00296 ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,value%s) - missing argument!\n", cmd, which == rtfield ? ",fieldname" : "");
00297 return -1;
00298 }
00299
00300 if (chan) {
00301 ast_autoservice_start(chan);
00302 }
00303
00304 if (!(head = ast_load_realtime_all(args.family, args.fieldmatch, args.value, SENTINEL))) {
00305 if (chan) {
00306 ast_autoservice_stop(chan);
00307 }
00308 return -1;
00309 }
00310
00311 ast_str_reset(fields);
00312 ast_str_reset(values);
00313
00314 for (var = head; var; var = var->next) {
00315 if (which == rtfield) {
00316 ast_debug(1, "Comparing %s to %s\n", var->name, args.fieldname);
00317 if (!strcasecmp(var->name, args.fieldname)) {
00318 ast_debug(1, "Match! Value is %s\n", var->value);
00319 ast_copy_string(buf, var->value, len);
00320 break;
00321 }
00322 } else if (which == rthash) {
00323 ast_debug(1, "Setting hash key %s to value %s\n", var->name, var->value);
00324 ast_str_append(&fields, 0, "%s%s", first ? "" : ",", ast_str_set_escapecommas(&escapebuf, 0, var->name, INT_MAX));
00325 ast_str_append(&values, 0, "%s%s", first ? "" : ",", ast_str_set_escapecommas(&escapebuf, 0, var->value, INT_MAX));
00326 first = 0;
00327 }
00328 }
00329 ast_variables_destroy(head);
00330
00331 if (which == rthash) {
00332 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields));
00333 ast_copy_string(buf, ast_str_buffer(values), len);
00334 }
00335
00336 if (chan) {
00337 ast_autoservice_stop(chan);
00338 }
00339
00340 return 0;
00341 }
00342
00343 static int function_realtime_store(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00344 {
00345 int res = 0;
00346 char storeid[32];
00347 char *valcopy;
00348 AST_DECLARE_APP_ARGS(a,
00349 AST_APP_ARG(family);
00350 AST_APP_ARG(f)[30];
00351 );
00352
00353 AST_DECLARE_APP_ARGS(v,
00354 AST_APP_ARG(v)[30];
00355 );
00356
00357 if (ast_strlen_zero(data)) {
00358 ast_log(LOG_WARNING, "Syntax: REALTIME_STORE(family,field1,field2,...,field30) - missing argument!\n");
00359 return -1;
00360 }
00361
00362 if (chan)
00363 ast_autoservice_start(chan);
00364
00365 valcopy = ast_strdupa(value);
00366 AST_STANDARD_APP_ARGS(a, data);
00367 AST_STANDARD_APP_ARGS(v, valcopy);
00368
00369 res = ast_store_realtime(a.family,
00370 a.f[0], v.v[0], a.f[1], v.v[1], a.f[2], v.v[2], a.f[3], v.v[3], a.f[4], v.v[4],
00371 a.f[5], v.v[5], a.f[6], v.v[6], a.f[7], v.v[7], a.f[8], v.v[8], a.f[9], v.v[9],
00372 a.f[10], v.v[10], a.f[11], v.v[11], a.f[12], v.v[12], a.f[13], v.v[13], a.f[14], v.v[14],
00373 a.f[15], v.v[15], a.f[16], v.v[16], a.f[17], v.v[17], a.f[18], v.v[18], a.f[19], v.v[19],
00374 a.f[20], v.v[20], a.f[21], v.v[21], a.f[22], v.v[22], a.f[23], v.v[23], a.f[24], v.v[24],
00375 a.f[25], v.v[25], a.f[26], v.v[26], a.f[27], v.v[27], a.f[28], v.v[28], a.f[29], v.v[29], SENTINEL
00376 );
00377
00378 if (res < 0) {
00379 ast_log(LOG_WARNING, "Failed to store. Check the debug log for possible data repository related entries.\n");
00380 } else {
00381 snprintf(storeid, sizeof(storeid), "%d", res);
00382 pbx_builtin_setvar_helper(chan, "RTSTOREID", storeid);
00383 }
00384
00385 if (chan)
00386 ast_autoservice_stop(chan);
00387
00388 return 0;
00389 }
00390
00391 static int function_realtime_readdestroy(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00392 {
00393 struct ast_variable *var, *head;
00394 struct ast_str *out;
00395 size_t resultslen;
00396 int n;
00397 AST_DECLARE_APP_ARGS(args,
00398 AST_APP_ARG(family);
00399 AST_APP_ARG(fieldmatch);
00400 AST_APP_ARG(value);
00401 AST_APP_ARG(delim1);
00402 AST_APP_ARG(delim2);
00403 );
00404
00405 if (ast_strlen_zero(data)) {
00406 ast_log(LOG_WARNING, "Syntax: REALTIME_DESTROY(family,fieldmatch[,value[,delim1[,delim2]]]) - missing argument!\n");
00407 return -1;
00408 }
00409
00410 AST_STANDARD_APP_ARGS(args, data);
00411
00412 if (!args.delim1)
00413 args.delim1 = ",";
00414 if (!args.delim2)
00415 args.delim2 = "=";
00416
00417 if (chan)
00418 ast_autoservice_start(chan);
00419
00420 head = ast_load_realtime_all(args.family, args.fieldmatch, args.value, SENTINEL);
00421
00422 if (!head) {
00423 if (chan)
00424 ast_autoservice_stop(chan);
00425 return -1;
00426 }
00427
00428 resultslen = 0;
00429 n = 0;
00430 for (var = head; var; n++, var = var->next)
00431 resultslen += strlen(var->name) + strlen(var->value);
00432
00433 resultslen += n * (strlen(args.delim1) + strlen(args.delim2)) + 1;
00434
00435 out = ast_str_alloca(resultslen);
00436 for (var = head; var; var = var->next) {
00437 ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
00438 }
00439 ast_copy_string(buf, ast_str_buffer(out), len);
00440
00441 ast_destroy_realtime(args.family, args.fieldmatch, args.value, SENTINEL);
00442 ast_variables_destroy(head);
00443
00444 if (chan)
00445 ast_autoservice_stop(chan);
00446
00447 return 0;
00448 }
00449
00450 static struct ast_custom_function realtime_function = {
00451 .name = "REALTIME",
00452 .read = function_realtime_read,
00453 .write = function_realtime_write,
00454 };
00455
00456 static struct ast_custom_function realtimefield_function = {
00457 .name = "REALTIME_FIELD",
00458 .read = realtimefield_read,
00459 .write = function_realtime_write,
00460 };
00461
00462 static struct ast_custom_function realtimehash_function = {
00463 .name = "REALTIME_HASH",
00464 .read = realtimefield_read,
00465 };
00466
00467 static struct ast_custom_function realtime_store_function = {
00468 .name = "REALTIME_STORE",
00469 .write = function_realtime_store,
00470 };
00471
00472 static struct ast_custom_function realtime_destroy_function = {
00473 .name = "REALTIME_DESTROY",
00474 .read = function_realtime_readdestroy,
00475 };
00476
00477 static int unload_module(void)
00478 {
00479 int res = 0;
00480 res |= ast_custom_function_unregister(&realtime_function);
00481 res |= ast_custom_function_unregister(&realtime_store_function);
00482 res |= ast_custom_function_unregister(&realtime_destroy_function);
00483 res |= ast_custom_function_unregister(&realtimefield_function);
00484 res |= ast_custom_function_unregister(&realtimehash_function);
00485 return res;
00486 }
00487
00488 static int load_module(void)
00489 {
00490 int res = 0;
00491 res |= ast_custom_function_register(&realtime_function);
00492 res |= ast_custom_function_register(&realtime_store_function);
00493 res |= ast_custom_function_register(&realtime_destroy_function);
00494 res |= ast_custom_function_register(&realtimefield_function);
00495 res |= ast_custom_function_register(&realtimehash_function);
00496 return res;
00497 }
00498
00499 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Read/Write/Store/Destroy values from a RealTime repository");