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: 369937 $")
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[,matchvalue[,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,matchvalue,updatecol) - missing argument!\n", cmd);
00247 return -1;
00248 }
00249
00250 AST_STANDARD_APP_ARGS(args, data);
00251
00252 if (ast_strlen_zero(args.fieldmatch) || ast_strlen_zero(args.field)) {
00253 ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,matchvalue,updatecol) - missing argument!\n", cmd);
00254 return -1;
00255 }
00256
00257 if (chan) {
00258 ast_autoservice_start(chan);
00259 }
00260
00261 res = ast_update_realtime(args.family, args.fieldmatch, args.value, args.field, (char *)value, SENTINEL);
00262
00263 if (res < 0) {
00264 ast_log(LOG_WARNING, "Failed to update. Check the debug log for possible data repository related entries.\n");
00265 }
00266
00267 if (chan) {
00268 ast_autoservice_stop(chan);
00269 }
00270
00271 return res;
00272 }
00273
00274 static int realtimefield_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00275 {
00276 struct ast_variable *var, *head;
00277 struct ast_str *escapebuf = ast_str_thread_get(&buf1, 16);
00278 struct ast_str *fields = ast_str_thread_get(&buf2, 16);
00279 struct ast_str *values = ast_str_thread_get(&buf3, 16);
00280 int first = 0;
00281 enum { rtfield, rthash } which;
00282 AST_DECLARE_APP_ARGS(args,
00283 AST_APP_ARG(family);
00284 AST_APP_ARG(fieldmatch);
00285 AST_APP_ARG(value);
00286 AST_APP_ARG(fieldname);
00287 );
00288
00289 if (!strcmp(cmd, "REALTIME_FIELD")) {
00290 which = rtfield;
00291 } else {
00292 which = rthash;
00293 }
00294
00295 if (ast_strlen_zero(data)) {
00296 ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,matchvalue%s) - missing argument!\n", cmd, which == rtfield ? ",fieldname" : "");
00297 return -1;
00298 }
00299
00300 AST_STANDARD_APP_ARGS(args, data);
00301
00302 if ((which == rtfield && args.argc != 4) || (which == rthash && args.argc != 3)) {
00303 ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,matchvalue%s) - missing argument!\n", cmd, which == rtfield ? ",fieldname" : "");
00304 return -1;
00305 }
00306
00307 if (chan) {
00308 ast_autoservice_start(chan);
00309 }
00310
00311 if (!(head = ast_load_realtime_all(args.family, args.fieldmatch, args.value, SENTINEL))) {
00312 if (chan) {
00313 ast_autoservice_stop(chan);
00314 }
00315 return -1;
00316 }
00317
00318 ast_str_reset(fields);
00319 ast_str_reset(values);
00320
00321 for (var = head; var; var = var->next) {
00322 if (which == rtfield) {
00323 ast_debug(1, "Comparing %s to %s\n", var->name, args.fieldname);
00324 if (!strcasecmp(var->name, args.fieldname)) {
00325 ast_debug(1, "Match! Value is %s\n", var->value);
00326 ast_copy_string(buf, var->value, len);
00327 break;
00328 }
00329 } else if (which == rthash) {
00330 ast_debug(1, "Setting hash key %s to value %s\n", var->name, var->value);
00331 ast_str_append(&fields, 0, "%s%s", first ? "" : ",", ast_str_set_escapecommas(&escapebuf, 0, var->name, INT_MAX));
00332 ast_str_append(&values, 0, "%s%s", first ? "" : ",", ast_str_set_escapecommas(&escapebuf, 0, var->value, INT_MAX));
00333 first = 0;
00334 }
00335 }
00336 ast_variables_destroy(head);
00337
00338 if (which == rthash) {
00339 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields));
00340 ast_copy_string(buf, ast_str_buffer(values), len);
00341 }
00342
00343 if (chan) {
00344 ast_autoservice_stop(chan);
00345 }
00346
00347 return 0;
00348 }
00349
00350 static int function_realtime_store(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00351 {
00352 int res = 0;
00353 char storeid[32];
00354 char *valcopy;
00355 AST_DECLARE_APP_ARGS(a,
00356 AST_APP_ARG(family);
00357 AST_APP_ARG(f)[30];
00358 );
00359
00360 AST_DECLARE_APP_ARGS(v,
00361 AST_APP_ARG(v)[30];
00362 );
00363
00364 if (ast_strlen_zero(data)) {
00365 ast_log(LOG_WARNING, "Syntax: REALTIME_STORE(family,field1,field2,...,field30) - missing argument!\n");
00366 return -1;
00367 }
00368
00369 if (chan)
00370 ast_autoservice_start(chan);
00371
00372 valcopy = ast_strdupa(value);
00373 AST_STANDARD_APP_ARGS(a, data);
00374 AST_STANDARD_APP_ARGS(v, valcopy);
00375
00376 res = ast_store_realtime(a.family,
00377 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],
00378 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],
00379 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],
00380 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],
00381 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],
00382 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
00383 );
00384
00385 if (res < 0) {
00386 ast_log(LOG_WARNING, "Failed to store. Check the debug log for possible data repository related entries.\n");
00387 } else {
00388 snprintf(storeid, sizeof(storeid), "%d", res);
00389 pbx_builtin_setvar_helper(chan, "RTSTOREID", storeid);
00390 }
00391
00392 if (chan)
00393 ast_autoservice_stop(chan);
00394
00395 return 0;
00396 }
00397
00398 static int function_realtime_readdestroy(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00399 {
00400 struct ast_variable *var, *head;
00401 struct ast_str *out;
00402 size_t resultslen;
00403 int n;
00404 AST_DECLARE_APP_ARGS(args,
00405 AST_APP_ARG(family);
00406 AST_APP_ARG(fieldmatch);
00407 AST_APP_ARG(value);
00408 AST_APP_ARG(delim1);
00409 AST_APP_ARG(delim2);
00410 );
00411
00412 if (ast_strlen_zero(data)) {
00413 ast_log(LOG_WARNING, "Syntax: REALTIME_DESTROY(family,fieldmatch[,matchvalue[,delim1[,delim2]]]) - missing argument!\n");
00414 return -1;
00415 }
00416
00417 AST_STANDARD_APP_ARGS(args, data);
00418
00419 if (!args.delim1)
00420 args.delim1 = ",";
00421 if (!args.delim2)
00422 args.delim2 = "=";
00423
00424 if (chan)
00425 ast_autoservice_start(chan);
00426
00427 head = ast_load_realtime_all(args.family, args.fieldmatch, args.value, SENTINEL);
00428
00429 if (!head) {
00430 if (chan)
00431 ast_autoservice_stop(chan);
00432 return -1;
00433 }
00434
00435 resultslen = 0;
00436 n = 0;
00437 for (var = head; var; n++, var = var->next)
00438 resultslen += strlen(var->name) + strlen(var->value);
00439
00440 resultslen += n * (strlen(args.delim1) + strlen(args.delim2)) + 1;
00441
00442 out = ast_str_alloca(resultslen);
00443 for (var = head; var; var = var->next) {
00444 ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
00445 }
00446 ast_copy_string(buf, ast_str_buffer(out), len);
00447
00448 ast_destroy_realtime(args.family, args.fieldmatch, args.value, SENTINEL);
00449 ast_variables_destroy(head);
00450
00451 if (chan)
00452 ast_autoservice_stop(chan);
00453
00454 return 0;
00455 }
00456
00457 static struct ast_custom_function realtime_function = {
00458 .name = "REALTIME",
00459 .read = function_realtime_read,
00460 .write = function_realtime_write,
00461 };
00462
00463 static struct ast_custom_function realtimefield_function = {
00464 .name = "REALTIME_FIELD",
00465 .read = realtimefield_read,
00466 .write = function_realtime_write,
00467 };
00468
00469 static struct ast_custom_function realtimehash_function = {
00470 .name = "REALTIME_HASH",
00471 .read = realtimefield_read,
00472 };
00473
00474 static struct ast_custom_function realtime_store_function = {
00475 .name = "REALTIME_STORE",
00476 .write = function_realtime_store,
00477 };
00478
00479 static struct ast_custom_function realtime_destroy_function = {
00480 .name = "REALTIME_DESTROY",
00481 .read = function_realtime_readdestroy,
00482 };
00483
00484 static int unload_module(void)
00485 {
00486 int res = 0;
00487 res |= ast_custom_function_unregister(&realtime_function);
00488 res |= ast_custom_function_unregister(&realtime_store_function);
00489 res |= ast_custom_function_unregister(&realtime_destroy_function);
00490 res |= ast_custom_function_unregister(&realtimefield_function);
00491 res |= ast_custom_function_unregister(&realtimehash_function);
00492 return res;
00493 }
00494
00495 static int load_module(void)
00496 {
00497 int res = 0;
00498 res |= ast_custom_function_register(&realtime_function);
00499 res |= ast_custom_function_register(&realtime_store_function);
00500 res |= ast_custom_function_register(&realtime_destroy_function);
00501 res |= ast_custom_function_register(&realtimefield_function);
00502 res |= ast_custom_function_register(&realtimehash_function);
00503 return res;
00504 }
00505
00506 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Read/Write/Store/Destroy values from a RealTime repository");