Compatibility issues on app_cut (bug #428)
[asterisk/asterisk.git] / apps / app_cut.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Cut application
5  *
6  * Copyright (c) 2003 Tilghman Lesher.  All rights reserved.
7  *
8  * Tilghman Lesher <app_cut__v002@the-tilghman.com>
9  *
10  * $Id$
11  *
12  * This code is released by the author with no restrictions on usage.
13  *
14  */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <asterisk/file.h>
21 #include <asterisk/logger.h>
22 #include <asterisk/options.h>
23 #include <asterisk/channel.h>
24 #include <asterisk/pbx.h>
25 #include <asterisk/module.h>
26
27 /* Maximum length of any variable */
28 #define MAXRESULT       1024
29
30 static char *tdesc = "Cuts up variables";
31
32 static char *app_cut = "Cut";
33
34 static char *cut_synopsis = "Cut(newvar=varname|delimiter|fieldspec)";
35
36 static char *cut_descrip =
37 "Cut(varname=varname,delimiter,field)\n"
38 "  newvar    - result string is set to this variable\n"
39 "  varname   - variable you want cut\n"
40 "  delimiter - defaults to -\n"
41 "  fieldspec - number of the field you want (1-based offset)\n"
42 "            may also be specified as a range (with -)\n"
43 "            or group of ranges and fields (with &)\n" 
44 "  Returns 0 or -1 on hangup or error.\n";
45
46 STANDARD_LOCAL_USER;
47
48 LOCAL_USER_DECL;
49
50 static int cut_exec(struct ast_channel *chan, void *data)
51 {
52         int res=0;
53         struct localuser *u;
54         char *s, *newvar=NULL, *varname=NULL, *delimiter=NULL, *field=NULL;
55         int args_okay = 0;
56
57         LOCAL_USER_ADD(u);
58
59         /* Check and parse arguments */
60         if (data) {
61                 s = ast_strdupa((char *)data);
62                 if (s) {
63                         newvar = strsep(&s, "=");
64                         if (newvar && (newvar[0] != '\0')) {
65                                 varname = strsep(&s, "|");
66                                 if (varname && (varname[0] != '\0')) {
67                                         delimiter = strsep(&s, "|");
68                                         if (delimiter) {
69                                                 field = strsep(&s, "|");
70                                                 if (field) {
71                                                         args_okay = 1;
72                                                 }
73                                         }
74                                 }
75                         }
76                 } else {
77                         ast_log(LOG_ERROR, "Out of memory\n");
78                         res = -1;
79                 }
80         }
81
82         if (args_okay) {
83                 char d, ds[2];
84                 char *tmp = alloca(strlen(varname) + 4);
85                 char *tmp2 = alloca(MAXRESULT);
86                 char retstring[MAXRESULT];
87
88                 memset(retstring, 0, MAXRESULT);
89
90                 if (tmp && tmp2) {
91                         snprintf(tmp, strlen(varname) + 4, "${%s}", varname);
92                         memset(tmp2, 0, sizeof(tmp2));
93                 } else {
94                         ast_log(LOG_ERROR, "Out of memory");
95                         return -1;
96                 }
97
98                 if (delimiter[0])
99                         d = delimiter[0];
100                 else
101                         d = '-';
102
103                 /* String form of the delimiter, for use with strsep(3) */
104                 sprintf(ds,"%c",d);
105
106                 pbx_substitute_variables_helper(chan, tmp, tmp2, MAXRESULT - 1);
107
108                 if (tmp2) {
109                         int curfieldnum = 1;
110                         while ((tmp2 != NULL) && (field != NULL)) {
111                                 char *nextgroup = strsep(&field, "&");
112                                 int num1 = 0, num2 = MAXRESULT;
113                                 char trashchar;
114
115                                 if (sscanf(nextgroup, "%d-%d", &num1, &num2) == 2) {
116                                         /* range with both start and end */
117                                 } else if (sscanf(nextgroup, "-%d", &num2) == 1) {
118                                         /* range with end */
119                                         num1 = 0;
120                                 } else if ((sscanf(nextgroup, "%d%c", &num1, &trashchar) == 2) && (trashchar == '-')) {
121                                         /* range with start */
122                                         num2 = MAXRESULT;
123                                 } else if (sscanf(nextgroup, "%d", &num1) == 1) {
124                                         /* single number */
125                                         num2 = num1;
126                                 } else {
127                                         ast_log(LOG_ERROR, "Cut(): Illegal range '%s'\n", nextgroup);
128                                         ast_log(LOG_ERROR, "Usage: %s\n", cut_synopsis);
129                                         return -1;
130                                 }
131
132                                 /* Get to start, if any */
133                                 if (num1 > 0) {
134                                         while ((tmp2 != (char *)NULL + 1) && (curfieldnum < num1)) {
135                                                 tmp2 = index(tmp2, d) + 1;
136                                                 curfieldnum++;
137                                         }
138                                 }
139
140                                 /* Most frequent problem is the expectation of reordering fields */
141                                 if ((num1 > 0) && (curfieldnum > num1)) {
142                                         ast_log(LOG_WARNING, "Cut(): we're already past the field you wanted?\n");
143                                 }
144
145                                 /* Re-null tmp2 if we added 1 to NULL */
146                                 if (tmp2 == (char *)NULL + 1)
147                                         tmp2 = NULL;
148
149                                 /* Output fields until we either run out of fields or num2 is reached */
150                                 while ((tmp2 != NULL) && (curfieldnum <= num2)) {
151                                         char *tmp3 = strsep(&tmp2, ds);
152                                         int curlen = strlen(retstring);
153
154                                         if (strlen(retstring)) {
155                                                 snprintf(retstring + curlen, MAXRESULT - curlen, "%c%s", d, tmp3);
156                                         } else {
157                                                 snprintf(retstring, MAXRESULT, "%s", tmp3);
158                                         }
159
160                                         curfieldnum++;
161                                 }
162                         }
163                 }
164
165                 pbx_builtin_setvar_helper(chan, newvar, retstring);
166         }
167
168         LOCAL_USER_REMOVE(u);
169         return res;
170 }
171
172 int unload_module(void)
173 {
174         STANDARD_HANGUP_LOCALUSERS;
175         return ast_unregister_application(app_cut);
176 }
177
178 int load_module(void)
179 {
180         return ast_register_application(app_cut, cut_exec, cut_synopsis, cut_descrip);
181 }
182
183 char *description(void)
184 {
185         return tdesc;
186 }
187
188 int usecount(void)
189 {
190         int res;
191         STANDARD_USECOUNT(res);
192         return res;
193 }
194
195 char *key()
196 {
197         return ASTERISK_GPL_KEY;
198 }