00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <unistd.h>
00027 #include <string.h>
00028
00029 #include "asterisk.h"
00030
00031 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7497 $")
00032
00033 #include "asterisk/file.h"
00034 #include "asterisk/logger.h"
00035 #include "asterisk/options.h"
00036 #include "asterisk/channel.h"
00037 #include "asterisk/pbx.h"
00038 #include "asterisk/module.h"
00039 #include "asterisk/app.h"
00040
00041
00042 #define MAXRESULT 1024
00043
00044 static char *tdesc = "Cut out information from a string";
00045
00046 static char *app_cut = "Cut";
00047
00048 static char *cut_synopsis = "Splits a variable's contents using the specified delimiter";
00049
00050 static char *cut_descrip =
00051 " Cut(newvar=varname,delimiter,fieldspec): This applicaiton will split the\n"
00052 "contents of a variable based on the given delimeter and store the result in\n"
00053 "a new variable.\n"
00054 "Parameters:\n"
00055 " newvar - new variable created from result string\n"
00056 " varname - variable you want cut\n"
00057 " delimiter - defaults to '-'\n"
00058 " fieldspec - number of the field you want (1-based offset)\n"
00059 " may also be specified as a range (with -)\n"
00060 " or group of ranges and fields (with &)\n"
00061 "This application has been deprecated in favor of the CUT function.\n";
00062
00063 static char *app_sort = "Sort";
00064 static char *app_sort_synopsis = "Sorts a list of keywords and values";
00065 static char *app_sort_descrip =
00066 " Sort(newvar=key1:val1[,key2:val2[[...],keyN:valN]]): This application will\n"
00067 "sort the list provided in ascending order. The result will be stored in the\n"
00068 "specified variable name.\n"
00069 " This applicaiton has been deprecated in favor of the SORT function.\n";
00070
00071 STANDARD_LOCAL_USER;
00072
00073 LOCAL_USER_DECL;
00074
00075 struct sortable_keys {
00076 char *key;
00077 float value;
00078 };
00079
00080 static int sort_subroutine(const void *arg1, const void *arg2)
00081 {
00082 const struct sortable_keys *one=arg1, *two=arg2;
00083 if (one->value < two->value) {
00084 return -1;
00085 } else if (one->value == two->value) {
00086 return 0;
00087 } else {
00088 return 1;
00089 }
00090 }
00091
00092 #define ERROR_NOARG (-1)
00093 #define ERROR_NOMEM (-2)
00094 #define ERROR_USAGE (-3)
00095
00096 static int sort_internal(struct ast_channel *chan, char *data, char *buffer, size_t buflen)
00097 {
00098 char *strings, *ptrkey, *ptrvalue;
00099 int count=1, count2, element_count=0;
00100 struct sortable_keys *sortable_keys;
00101
00102 memset(buffer, 0, buflen);
00103
00104 if (!data) {
00105 return ERROR_NOARG;
00106 }
00107
00108 strings = ast_strdupa((char *)data);
00109 if (!strings) {
00110 return ERROR_NOMEM;
00111 }
00112
00113 for (ptrkey = strings; *ptrkey; ptrkey++) {
00114 if (*ptrkey == '|') {
00115 count++;
00116 }
00117 }
00118
00119 sortable_keys = alloca(count * sizeof(struct sortable_keys));
00120 if (!sortable_keys) {
00121 return ERROR_NOMEM;
00122 }
00123
00124 memset(sortable_keys, 0, count * sizeof(struct sortable_keys));
00125
00126
00127 count2 = 0;
00128 while ((ptrkey = strsep(&strings, "|"))) {
00129 ptrvalue = index(ptrkey, ':');
00130 if (!ptrvalue) {
00131 count--;
00132 continue;
00133 }
00134 *ptrvalue = '\0';
00135 ptrvalue++;
00136 sortable_keys[count2].key = ptrkey;
00137 sscanf(ptrvalue, "%f", &sortable_keys[count2].value);
00138 count2++;
00139 }
00140
00141
00142 qsort(sortable_keys, count, sizeof(struct sortable_keys), sort_subroutine);
00143
00144 for (count2 = 0; count2 < count; count2++) {
00145 int blen = strlen(buffer);
00146 if (element_count++) {
00147 strncat(buffer + blen, ",", buflen - blen - 1);
00148 blen++;
00149 }
00150 strncat(buffer + blen, sortable_keys[count2].key, buflen - blen - 1);
00151 }
00152
00153 return 0;
00154 }
00155
00156 static int cut_internal(struct ast_channel *chan, char *data, char *buffer, size_t buflen)
00157 {
00158 char *s, *args[3], *varname=NULL, *delimiter=NULL, *field=NULL;
00159 int args_okay = 0;
00160
00161 memset(buffer, 0, buflen);
00162
00163
00164 if (data) {
00165 s = ast_strdupa((char *)data);
00166 if (s) {
00167 ast_app_separate_args(s, '|', args, 3);
00168 varname = args[0];
00169 delimiter = args[1];
00170 field = args[2];
00171
00172 if (field) {
00173 args_okay = 1;
00174 }
00175 } else {
00176 return ERROR_NOMEM;
00177 }
00178 }
00179
00180 if (args_okay) {
00181 char d, ds[2];
00182 char *tmp = alloca(strlen(varname) + 4);
00183 char varvalue[MAXRESULT], *tmp2=varvalue;
00184
00185 if (tmp) {
00186 snprintf(tmp, strlen(varname) + 4, "${%s}", varname);
00187 memset(varvalue, 0, sizeof(varvalue));
00188 } else {
00189 return ERROR_NOMEM;
00190 }
00191
00192 if (delimiter[0])
00193 d = delimiter[0];
00194 else
00195 d = '-';
00196
00197
00198 snprintf(ds, sizeof(ds), "%c", d);
00199
00200 pbx_substitute_variables_helper(chan, tmp, tmp2, MAXRESULT - 1);
00201
00202 if (tmp2) {
00203 int curfieldnum = 1;
00204 while ((tmp2 != NULL) && (field != NULL)) {
00205 char *nextgroup = strsep(&field, "&");
00206 int num1 = 0, num2 = MAXRESULT;
00207 char trashchar;
00208
00209 if (sscanf(nextgroup, "%d-%d", &num1, &num2) == 2) {
00210
00211 } else if (sscanf(nextgroup, "-%d", &num2) == 1) {
00212
00213 num1 = 0;
00214 } else if ((sscanf(nextgroup, "%d%c", &num1, &trashchar) == 2) && (trashchar == '-')) {
00215
00216 num2 = MAXRESULT;
00217 } else if (sscanf(nextgroup, "%d", &num1) == 1) {
00218
00219 num2 = num1;
00220 } else {
00221 return ERROR_USAGE;
00222 }
00223
00224
00225 if (num1 > 0) {
00226 while ((tmp2 != (char *)NULL + 1) && (curfieldnum < num1)) {
00227 tmp2 = index(tmp2, d) + 1;
00228 curfieldnum++;
00229 }
00230 }
00231
00232
00233 if ((num1 > 0) && (curfieldnum > num1)) {
00234 ast_log(LOG_WARNING, "We're already past the field you wanted?\n");
00235 }
00236
00237
00238 if (tmp2 == (char *)NULL + 1)
00239 tmp2 = NULL;
00240
00241
00242 while ((tmp2 != NULL) && (curfieldnum <= num2)) {
00243 char *tmp3 = strsep(&tmp2, ds);
00244 int curlen = strlen(buffer);
00245
00246 if (curlen) {
00247 snprintf(buffer + curlen, buflen - curlen, "%c%s", d, tmp3);
00248 } else {
00249 snprintf(buffer, buflen, "%s", tmp3);
00250 }
00251
00252 curfieldnum++;
00253 }
00254 }
00255 }
00256 } else {
00257 return ERROR_NOARG;
00258 }
00259 return 0;
00260 }
00261
00262 static int sort_exec(struct ast_channel *chan, void *data)
00263 {
00264 int res=0;
00265 struct localuser *u;
00266 char *varname, *strings, result[512] = "";
00267 static int dep_warning=0;
00268
00269 if (!dep_warning) {
00270 ast_log(LOG_WARNING, "The application Sort is deprecated. Please use the SORT() function instead.\n");
00271 dep_warning=1;
00272 }
00273
00274 if (!data) {
00275 ast_log(LOG_ERROR, "Sort() requires an argument\n");
00276 return 0;
00277 }
00278
00279 LOCAL_USER_ADD(u);
00280
00281 strings = ast_strdupa((char *)data);
00282 if (!strings) {
00283 ast_log(LOG_ERROR, "Out of memory\n");
00284 LOCAL_USER_REMOVE(u);
00285 return 0;
00286 }
00287
00288 varname = strsep(&strings, "=");
00289 switch (sort_internal(chan, strings, result, sizeof(result))) {
00290 case ERROR_NOARG:
00291 ast_log(LOG_ERROR, "Sort() requires an argument\n");
00292 res = 0;
00293 break;
00294 case ERROR_NOMEM:
00295 ast_log(LOG_ERROR, "Out of memory\n");
00296 res = -1;
00297 break;
00298 case 0:
00299 pbx_builtin_setvar_helper(chan, varname, result);
00300 res = 0;
00301 break;
00302 default:
00303 ast_log(LOG_ERROR, "Unknown internal error\n");
00304 res = -1;
00305 }
00306 LOCAL_USER_REMOVE(u);
00307 return res;
00308 }
00309
00310 static int cut_exec(struct ast_channel *chan, void *data)
00311 {
00312 int res=0;
00313 struct localuser *u;
00314 char *s, *newvar=NULL, result[512];
00315 static int dep_warning = 0;
00316
00317 LOCAL_USER_ADD(u);
00318
00319 if (!dep_warning) {
00320 ast_log(LOG_WARNING, "The application Cut is deprecated. Please use the CUT() function instead.\n");
00321 dep_warning=1;
00322 }
00323
00324
00325 if (data) {
00326 s = ast_strdupa((char *)data);
00327 if (s) {
00328 newvar = strsep(&s, "=");
00329 } else {
00330 ast_log(LOG_ERROR, "Out of memory\n");
00331 LOCAL_USER_REMOVE(u);
00332 return -1;
00333 }
00334 }
00335
00336 switch (cut_internal(chan, s, result, sizeof(result))) {
00337 case ERROR_NOARG:
00338 ast_log(LOG_ERROR, "Cut() requires an argument\n");
00339 res = 0;
00340 break;
00341 case ERROR_NOMEM:
00342 ast_log(LOG_ERROR, "Out of memory\n");
00343 res = -1;
00344 break;
00345 case ERROR_USAGE:
00346 ast_log(LOG_ERROR, "Usage: %s\n", cut_synopsis);
00347 res = 0;
00348 break;
00349 case 0:
00350 pbx_builtin_setvar_helper(chan, newvar, result);
00351 res = 0;
00352 break;
00353 default:
00354 ast_log(LOG_ERROR, "Unknown internal error\n");
00355 res = -1;
00356 }
00357 LOCAL_USER_REMOVE(u);
00358 return res;
00359 }
00360
00361 static char *acf_sort_exec(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
00362 {
00363 struct localuser *u;
00364
00365 LOCAL_USER_ACF_ADD(u);
00366
00367 switch (sort_internal(chan, data, buf, len)) {
00368 case ERROR_NOARG:
00369 ast_log(LOG_ERROR, "SORT() requires an argument\n");
00370 break;
00371 case ERROR_NOMEM:
00372 ast_log(LOG_ERROR, "Out of memory\n");
00373 break;
00374 case 0:
00375 break;
00376 default:
00377 ast_log(LOG_ERROR, "Unknown internal error\n");
00378 }
00379 LOCAL_USER_REMOVE(u);
00380 return buf;
00381 }
00382
00383 static char *acf_cut_exec(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
00384 {
00385 struct localuser *u;
00386
00387 LOCAL_USER_ACF_ADD(u);
00388
00389 switch (cut_internal(chan, data, buf, len)) {
00390 case ERROR_NOARG:
00391 ast_log(LOG_ERROR, "CUT() requires an argument\n");
00392 break;
00393 case ERROR_NOMEM:
00394 ast_log(LOG_ERROR, "Out of memory\n");
00395 break;
00396 case ERROR_USAGE:
00397 ast_log(LOG_ERROR, "Usage: %s\n", cut_synopsis);
00398 break;
00399 case 0:
00400 break;
00401 default:
00402 ast_log(LOG_ERROR, "Unknown internal error\n");
00403 }
00404 LOCAL_USER_REMOVE(u);
00405 return buf;
00406 }
00407
00408 struct ast_custom_function acf_sort = {
00409 .name = "SORT",
00410 .synopsis = "Sorts a list of key/vals into a list of keys, based upon the vals",
00411 .syntax = "SORT(key1:val1[...][,keyN:valN])",
00412 .desc =
00413 "Takes a comma-separated list of keys and values, each separated by a colon, and returns a\n"
00414 "comma-separated list of the keys, sorted by their values. Values will be evaluated as\n"
00415 "floating-point numbers.\n",
00416 .read = acf_sort_exec,
00417 };
00418
00419 struct ast_custom_function acf_cut = {
00420 .name = "CUT",
00421 .synopsis = "Slices and dices strings, based upon a named delimiter.",
00422 .syntax = "CUT(<varname>,<char-delim>,<range-spec>)",
00423 .desc =
00424 " varname - variable you want cut\n"
00425 " char-delim - defaults to '-'\n"
00426 " range-spec - number of the field you want (1-based offset)\n"
00427 " may also be specified as a range (with -)\n"
00428 " or group of ranges and fields (with &)\n",
00429 .read = acf_cut_exec,
00430 };
00431
00432 int unload_module(void)
00433 {
00434 int res;
00435
00436 res = ast_custom_function_unregister(&acf_cut);
00437 res |= ast_custom_function_unregister(&acf_sort);
00438 res |= ast_unregister_application(app_sort);
00439 res |= ast_unregister_application(app_cut);
00440
00441 STANDARD_HANGUP_LOCALUSERS;
00442
00443 return res;
00444 }
00445
00446 int load_module(void)
00447 {
00448 int res;
00449
00450 res = ast_custom_function_register(&acf_cut);
00451 res |= ast_custom_function_register(&acf_sort);
00452 res |= ast_register_application(app_sort, sort_exec, app_sort_synopsis, app_sort_descrip);
00453 res |= ast_register_application(app_cut, cut_exec, cut_synopsis, cut_descrip);
00454
00455 return res;
00456 }
00457
00458 char *description(void)
00459 {
00460 return tdesc;
00461 }
00462
00463 int usecount(void)
00464 {
00465 int res;
00466 STANDARD_USECOUNT(res);
00467 return res;
00468 }
00469
00470 char *key()
00471 {
00472 return ASTERISK_GPL_KEY;
00473 }