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