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 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 298477 $")
00031
00032 #include <sys/stat.h>
00033
00034 #include "asterisk/module.h"
00035 #include "asterisk/channel.h"
00036 #include "asterisk/pbx.h"
00037 #include "asterisk/utils.h"
00038 #include "asterisk/app.h"
00039 #include "asterisk/astobj2.h"
00040 #include "asterisk/astdb.h"
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 static struct ao2_container *group_container = NULL;
00077
00078 struct group_entry {
00079 char name[AST_CHANNEL_NAME];
00080 };
00081
00082 struct group {
00083 char name[AST_MAX_EXTENSION];
00084 struct ao2_container *entries;
00085 };
00086
00087 static void group_destroy(void *vgroup)
00088 {
00089 struct group *group = vgroup;
00090 ao2_ref(group->entries, -1);
00091 }
00092
00093 static int group_hash_fn(const void *obj, const int flags)
00094 {
00095 const struct group *g = obj;
00096 return ast_str_hash(g->name);
00097 }
00098
00099 static int group_cmp_fn(void *obj1, void *name2, int flags)
00100 {
00101 struct group *g1 = obj1, *g2 = name2;
00102 char *name = name2;
00103 if (flags & OBJ_POINTER)
00104 return strcmp(g1->name, g2->name) ? 0 : CMP_MATCH | CMP_STOP;
00105 else
00106 return strcmp(g1->name, name) ? 0 : CMP_MATCH | CMP_STOP;
00107 }
00108
00109 static int entry_hash_fn(const void *obj, const int flags)
00110 {
00111 const struct group_entry *e = obj;
00112 return ast_str_hash(e->name);
00113 }
00114
00115 static int entry_cmp_fn(void *obj1, void *name2, int flags)
00116 {
00117 struct group_entry *e1 = obj1, *e2 = name2;
00118 char *name = name2;
00119 if (flags & OBJ_POINTER)
00120 return strcmp(e1->name, e2->name) ? 0 : CMP_MATCH | CMP_STOP;
00121 else
00122 return strcmp(e1->name, name) ? 0 : CMP_MATCH | CMP_STOP;
00123 }
00124
00125 static int dialgroup_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00126 {
00127 struct ao2_iterator i;
00128 struct group *grhead = ao2_find(group_container, data, 0);
00129 struct group_entry *entry;
00130 size_t bufused = 0;
00131 int trunc_warning = 0;
00132 int res = 0;
00133
00134 if (!grhead) {
00135 if (!ast_strlen_zero(cmd)) {
00136 ast_log(LOG_WARNING, "No such dialgroup '%s'\n", data);
00137 }
00138 return -1;
00139 }
00140
00141 buf[0] = '\0';
00142
00143 i = ao2_iterator_init(grhead->entries, OBJ_POINTER);
00144 while ((entry = ao2_iterator_next(&i))) {
00145 int tmp = strlen(entry->name);
00146
00147 if (len - bufused > tmp + 2) {
00148 if (bufused != 0)
00149 buf[bufused++] = '&';
00150 ast_copy_string(buf + bufused, entry->name, len - bufused);
00151 bufused += tmp;
00152 } else if (trunc_warning++ == 0) {
00153 if (!ast_strlen_zero(cmd)) {
00154 ast_log(LOG_WARNING, "Dialgroup '%s' is too large. Truncating list.\n", data);
00155 } else {
00156 res = 1;
00157 ao2_ref(entry, -1);
00158 break;
00159 }
00160 }
00161 ao2_ref(entry, -1);
00162 }
00163 ao2_iterator_destroy(&i);
00164
00165 return res;
00166 }
00167
00168 static int dialgroup_refreshdb(struct ast_channel *chan, const char *cdialgroup)
00169 {
00170 int len = 500, res = 0;
00171 char *buf = NULL;
00172 char *dialgroup = ast_strdupa(cdialgroup);
00173
00174 do {
00175 len *= 2;
00176 buf = ast_realloc(buf, len);
00177
00178 if ((res = dialgroup_read(chan, "", dialgroup, buf, len)) < 0) {
00179 ast_free(buf);
00180 return -1;
00181 }
00182 } while (res == 1);
00183
00184 if (ast_strlen_zero(buf)) {
00185 ast_db_del("dialgroup", cdialgroup);
00186 } else {
00187 ast_db_put("dialgroup", cdialgroup, buf);
00188 }
00189 ast_free(buf);
00190 return 0;
00191 }
00192
00193 static int dialgroup_write(struct ast_channel *chan, const char *cmd, char *data, const char *cvalue)
00194 {
00195 struct group *grhead;
00196 struct group_entry *entry;
00197 int j, needrefresh = 1;
00198 AST_DECLARE_APP_ARGS(args,
00199 AST_APP_ARG(group);
00200 AST_APP_ARG(op);
00201 );
00202 AST_DECLARE_APP_ARGS(inter,
00203 AST_APP_ARG(faces)[100];
00204 );
00205 char *value = ast_strdupa(cvalue);
00206
00207 AST_STANDARD_APP_ARGS(args, data);
00208 AST_NONSTANDARD_APP_ARGS(inter, value, '&');
00209
00210 if (!(grhead = ao2_find(group_container, args.group, 0))) {
00211
00212 grhead = ao2_alloc(sizeof(*grhead), group_destroy);
00213 if (!grhead)
00214 return -1;
00215 grhead->entries = ao2_container_alloc(37, entry_hash_fn, entry_cmp_fn);
00216 if (!grhead->entries) {
00217 ao2_ref(grhead, -1);
00218 return -1;
00219 }
00220 ast_copy_string(grhead->name, args.group, sizeof(grhead->name));
00221 ao2_link(group_container, grhead);
00222 }
00223
00224 if (ast_strlen_zero(args.op)) {
00225
00226 args.op = "add";
00227
00228
00229 ao2_ref(grhead->entries, -1);
00230 if (!(grhead->entries = ao2_container_alloc(37, entry_hash_fn, entry_cmp_fn))) {
00231 ao2_unlink(group_container, grhead);
00232 ao2_ref(grhead, -1);
00233 return -1;
00234 }
00235 }
00236
00237 if (strcasecmp(args.op, "add") == 0) {
00238 for (j = 0; j < inter.argc; j++) {
00239
00240 if ((entry = ao2_find(grhead->entries, inter.faces[j], 0))) {
00241 ao2_ref(entry, -1);
00242 continue;
00243 }
00244 if ((entry = ao2_alloc(sizeof(*entry), NULL))) {
00245 ast_copy_string(entry->name, inter.faces[j], sizeof(entry->name));
00246 ao2_link(grhead->entries, entry);
00247 ao2_ref(entry, -1);
00248 } else {
00249 ast_log(LOG_WARNING, "Unable to add '%s' to dialgroup '%s'\n", inter.faces[j], grhead->name);
00250 }
00251 }
00252 } else if (strncasecmp(args.op, "del", 3) == 0) {
00253 for (j = 0; j < inter.argc; j++) {
00254 if ((entry = ao2_find(grhead->entries, inter.faces[j], OBJ_UNLINK))) {
00255 ao2_ref(entry, -1);
00256 } else {
00257 ast_log(LOG_WARNING, "Interface '%s' not found in dialgroup '%s'\n", inter.faces[j], grhead->name);
00258 }
00259 }
00260 } else {
00261 ast_log(LOG_ERROR, "Unrecognized operation: %s\n", args.op);
00262 needrefresh = 0;
00263 }
00264 ao2_ref(grhead, -1);
00265
00266 if (needrefresh) {
00267 dialgroup_refreshdb(chan, args.group);
00268 }
00269
00270 return 0;
00271 }
00272
00273 static struct ast_custom_function dialgroup_function = {
00274 .name = "DIALGROUP",
00275 .read = dialgroup_read,
00276 .write = dialgroup_write,
00277 };
00278
00279 static int unload_module(void)
00280 {
00281 int res = ast_custom_function_unregister(&dialgroup_function);
00282 ao2_ref(group_container, -1);
00283 return res;
00284 }
00285
00286 static int load_module(void)
00287 {
00288 struct ast_db_entry *dbtree, *tmp;
00289 char groupname[AST_MAX_EXTENSION], *ptr;
00290
00291 if ((group_container = ao2_container_alloc(37, group_hash_fn, group_cmp_fn))) {
00292
00293 if ((dbtree = ast_db_gettree("dialgroup", NULL))) {
00294 for (tmp = dbtree; tmp; tmp = tmp->next) {
00295 ast_copy_string(groupname, tmp->key, sizeof(groupname));
00296 if ((ptr = strrchr(groupname, '/'))) {
00297 ptr++;
00298 dialgroup_write(NULL, "", ptr, tmp->data);
00299 }
00300 }
00301 ast_db_freetree(dbtree);
00302 }
00303 return ast_custom_function_register(&dialgroup_function);
00304 } else {
00305 return AST_MODULE_LOAD_DECLINE;
00306 }
00307 }
00308
00309 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dialgroup dialplan function");