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 #include "asterisk.h"
00028
00029 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 206808 $")
00030
00031 #include "asterisk/file.h"
00032 #include "asterisk/channel.h"
00033 #include "asterisk/pbx.h"
00034 #include "asterisk/config.h"
00035 #include "asterisk/module.h"
00036 #include "asterisk/lock.h"
00037 #include "asterisk/utils.h"
00038 #include "asterisk/app.h"
00039
00040
00041
00042
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 AST_THREADSTORAGE(buf1);
00141 AST_THREADSTORAGE(buf2);
00142 AST_THREADSTORAGE(buf3);
00143
00144 static int function_realtime_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00145 {
00146 struct ast_variable *var, *head;
00147 struct ast_str *out;
00148 size_t resultslen;
00149 int n;
00150 AST_DECLARE_APP_ARGS(args,
00151 AST_APP_ARG(family);
00152 AST_APP_ARG(fieldmatch);
00153 AST_APP_ARG(value);
00154 AST_APP_ARG(delim1);
00155 AST_APP_ARG(delim2);
00156 );
00157
00158 if (ast_strlen_zero(data)) {
00159 ast_log(LOG_WARNING, "Syntax: REALTIME(family,fieldmatch[,value[,delim1[,delim2]]]) - missing argument!\n");
00160 return -1;
00161 }
00162
00163 AST_STANDARD_APP_ARGS(args, data);
00164
00165 if (!args.delim1)
00166 args.delim1 = ",";
00167 if (!args.delim2)
00168 args.delim2 = "=";
00169
00170 if (chan)
00171 ast_autoservice_start(chan);
00172
00173 head = ast_load_realtime_all(args.family, args.fieldmatch, args.value, SENTINEL);
00174
00175 if (!head) {
00176 if (chan)
00177 ast_autoservice_stop(chan);
00178 return -1;
00179 }
00180
00181 resultslen = 0;
00182 n = 0;
00183 for (var = head; var; n++, var = var->next)
00184 resultslen += strlen(var->name) + strlen(var->value);
00185
00186 resultslen += n * (strlen(args.delim1) + strlen(args.delim2)) + 1;
00187
00188 out = ast_str_alloca(resultslen);
00189 for (var = head; var; var = var->next)
00190 ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
00191 ast_copy_string(buf, ast_str_buffer(out), len);
00192
00193 ast_variables_destroy(head);
00194
00195 if (chan)
00196 ast_autoservice_stop(chan);
00197
00198 return 0;
00199 }
00200
00201 static int function_realtime_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00202 {
00203 int res = 0;
00204 AST_DECLARE_APP_ARGS(args,
00205 AST_APP_ARG(family);
00206 AST_APP_ARG(fieldmatch);
00207 AST_APP_ARG(value);
00208 AST_APP_ARG(field);
00209 );
00210
00211 if (ast_strlen_zero(data)) {
00212 ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,value,newcol) - missing argument!\n", cmd);
00213 return -1;
00214 }
00215
00216 if (chan)
00217 ast_autoservice_start(chan);
00218
00219 AST_STANDARD_APP_ARGS(args, data);
00220
00221 res = ast_update_realtime(args.family, args.fieldmatch, args.value, args.field, (char *)value, SENTINEL);
00222
00223 if (res < 0) {
00224 ast_log(LOG_WARNING, "Failed to update. Check the debug log for possible data repository related entries.\n");
00225 }
00226
00227 if (chan)
00228 ast_autoservice_stop(chan);
00229
00230 return 0;
00231 }
00232
00233 static int realtimefield_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00234 {
00235 struct ast_variable *var, *head;
00236 struct ast_str *escapebuf = ast_str_thread_get(&buf1, 16);
00237 struct ast_str *fields = ast_str_thread_get(&buf2, 16);
00238 struct ast_str *values = ast_str_thread_get(&buf3, 16);
00239 int first = 0;
00240 enum { rtfield, rthash } which;
00241 AST_DECLARE_APP_ARGS(args,
00242 AST_APP_ARG(family);
00243 AST_APP_ARG(fieldmatch);
00244 AST_APP_ARG(value);
00245 AST_APP_ARG(fieldname);
00246 );
00247
00248 if (!strcmp(cmd, "REALTIME_FIELD")) {
00249 which = rtfield;
00250 } else {
00251 which = rthash;
00252 }
00253
00254 if (ast_strlen_zero(data)) {
00255 ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,value%s) - missing argument!\n", cmd, which == rtfield ? ",fieldname" : "");
00256 return -1;
00257 }
00258
00259 AST_STANDARD_APP_ARGS(args, data);
00260
00261 if ((which == rtfield && args.argc != 4) || (which == rthash && args.argc != 3)) {
00262 ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,value%s) - missing argument!\n", cmd, which == rtfield ? ",fieldname" : "");
00263 return -1;
00264 }
00265
00266 if (chan) {
00267 ast_autoservice_start(chan);
00268 }
00269
00270 if (!(head = ast_load_realtime_all(args.family, args.fieldmatch, args.value, SENTINEL))) {
00271 if (chan) {
00272 ast_autoservice_stop(chan);
00273 }
00274 return -1;
00275 }
00276
00277 ast_str_reset(fields);
00278 ast_str_reset(values);
00279
00280 for (var = head; var; var = var->next) {
00281 if (which == rtfield) {
00282 ast_debug(1, "Comparing %s to %s\n", var->name, args.fieldname);
00283 if (!strcasecmp(var->name, args.fieldname)) {
00284 ast_debug(1, "Match! Value is %s\n", var->value);
00285 ast_copy_string(buf, var->value, len);
00286 break;
00287 }
00288 } else if (which == rthash) {
00289 ast_debug(1, "Setting hash key %s to value %s\n", var->name, var->value);
00290 ast_str_append(&fields, 0, "%s%s", first ? "" : ",", ast_str_set_escapecommas(&escapebuf, 0, var->name, INT_MAX));
00291 ast_str_append(&values, 0, "%s%s", first ? "" : ",", ast_str_set_escapecommas(&escapebuf, 0, var->value, INT_MAX));
00292 first = 0;
00293 }
00294 }
00295 ast_variables_destroy(head);
00296
00297 if (which == rthash) {
00298 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields));
00299 ast_copy_string(buf, ast_str_buffer(values), len);
00300 }
00301
00302 if (chan) {
00303 ast_autoservice_stop(chan);
00304 }
00305
00306 return 0;
00307 }
00308
00309 static int function_realtime_store(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00310 {
00311 int res = 0;
00312 char storeid[32];
00313 char *valcopy;
00314 AST_DECLARE_APP_ARGS(a,
00315 AST_APP_ARG(family);
00316 AST_APP_ARG(f)[30];
00317 );
00318
00319 AST_DECLARE_APP_ARGS(v,
00320 AST_APP_ARG(v)[30];
00321 );
00322
00323 if (ast_strlen_zero(data)) {
00324 ast_log(LOG_WARNING, "Syntax: REALTIME_STORE(family,field1,field2,...,field30) - missing argument!\n");
00325 return -1;
00326 }
00327
00328 if (chan)
00329 ast_autoservice_start(chan);
00330
00331 valcopy = ast_strdupa(value);
00332 AST_STANDARD_APP_ARGS(a, data);
00333 AST_STANDARD_APP_ARGS(v, valcopy);
00334
00335 res = ast_store_realtime(a.family,
00336 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],
00337 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],
00338 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],
00339 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],
00340 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],
00341 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
00342 );
00343
00344 if (res < 0) {
00345 ast_log(LOG_WARNING, "Failed to store. Check the debug log for possible data repository related entries.\n");
00346 } else {
00347 snprintf(storeid, sizeof(storeid), "%d", res);
00348 pbx_builtin_setvar_helper(chan, "RTSTOREID", storeid);
00349 }
00350
00351 if (chan)
00352 ast_autoservice_stop(chan);
00353
00354 return 0;
00355 }
00356
00357 static int function_realtime_readdestroy(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00358 {
00359 struct ast_variable *var, *head;
00360 struct ast_str *out;
00361 size_t resultslen;
00362 int n;
00363 AST_DECLARE_APP_ARGS(args,
00364 AST_APP_ARG(family);
00365 AST_APP_ARG(fieldmatch);
00366 AST_APP_ARG(value);
00367 AST_APP_ARG(delim1);
00368 AST_APP_ARG(delim2);
00369 );
00370
00371 if (ast_strlen_zero(data)) {
00372 ast_log(LOG_WARNING, "Syntax: REALTIME_DESTROY(family,fieldmatch[,value[,delim1[,delim2]]]) - missing argument!\n");
00373 return -1;
00374 }
00375
00376 AST_STANDARD_APP_ARGS(args, data);
00377
00378 if (!args.delim1)
00379 args.delim1 = ",";
00380 if (!args.delim2)
00381 args.delim2 = "=";
00382
00383 if (chan)
00384 ast_autoservice_start(chan);
00385
00386 head = ast_load_realtime_all(args.family, args.fieldmatch, args.value, SENTINEL);
00387
00388 if (!head) {
00389 if (chan)
00390 ast_autoservice_stop(chan);
00391 return -1;
00392 }
00393
00394 resultslen = 0;
00395 n = 0;
00396 for (var = head; var; n++, var = var->next)
00397 resultslen += strlen(var->name) + strlen(var->value);
00398
00399 resultslen += n * (strlen(args.delim1) + strlen(args.delim2)) + 1;
00400
00401 out = ast_str_alloca(resultslen);
00402 for (var = head; var; var = var->next) {
00403 ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
00404 }
00405 ast_copy_string(buf, ast_str_buffer(out), len);
00406
00407 ast_destroy_realtime(args.family, args.fieldmatch, args.value, SENTINEL);
00408 ast_variables_destroy(head);
00409
00410 if (chan)
00411 ast_autoservice_stop(chan);
00412
00413 return 0;
00414 }
00415
00416 static struct ast_custom_function realtime_function = {
00417 .name = "REALTIME",
00418 .read = function_realtime_read,
00419 .write = function_realtime_write,
00420 };
00421
00422 static struct ast_custom_function realtimefield_function = {
00423 .name = "REALTIME_FIELD",
00424 .read = realtimefield_read,
00425 .write = function_realtime_write,
00426 };
00427
00428 static struct ast_custom_function realtimehash_function = {
00429 .name = "REALTIME_HASH",
00430 .read = realtimefield_read,
00431 };
00432
00433 static struct ast_custom_function realtime_store_function = {
00434 .name = "REALTIME_STORE",
00435 .write = function_realtime_store,
00436 };
00437
00438 static struct ast_custom_function realtime_destroy_function = {
00439 .name = "REALTIME_DESTROY",
00440 .read = function_realtime_readdestroy,
00441 };
00442
00443 static int unload_module(void)
00444 {
00445 int res = 0;
00446 res |= ast_custom_function_unregister(&realtime_function);
00447 res |= ast_custom_function_unregister(&realtime_store_function);
00448 res |= ast_custom_function_unregister(&realtime_destroy_function);
00449 res |= ast_custom_function_unregister(&realtimefield_function);
00450 res |= ast_custom_function_unregister(&realtimehash_function);
00451 return res;
00452 }
00453
00454 static int load_module(void)
00455 {
00456 int res = 0;
00457 res |= ast_custom_function_register(&realtime_function);
00458 res |= ast_custom_function_register(&realtime_store_function);
00459 res |= ast_custom_function_register(&realtime_destroy_function);
00460 res |= ast_custom_function_register(&realtimefield_function);
00461 res |= ast_custom_function_register(&realtimehash_function);
00462 return res;
00463 }
00464
00465 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Read/Write/Store/Destroy values from a RealTime repository");