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: 366880 $")
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 ao2_ref(grhead, -1);
00169
00170 return res;
00171 }
00172
00173 static int dialgroup_refreshdb(struct ast_channel *chan, const char *cdialgroup)
00174 {
00175 int len = 500, res = 0;
00176 char *buf = NULL;
00177 char *dialgroup = ast_strdupa(cdialgroup);
00178
00179 do {
00180 len *= 2;
00181 buf = ast_realloc(buf, len);
00182
00183 if ((res = dialgroup_read(chan, "", dialgroup, buf, len)) < 0) {
00184 ast_free(buf);
00185 return -1;
00186 }
00187 } while (res == 1);
00188
00189 if (ast_strlen_zero(buf)) {
00190 ast_db_del("dialgroup", cdialgroup);
00191 } else {
00192 ast_db_put("dialgroup", cdialgroup, buf);
00193 }
00194 ast_free(buf);
00195 return 0;
00196 }
00197
00198 static int dialgroup_write(struct ast_channel *chan, const char *cmd, char *data, const char *cvalue)
00199 {
00200 struct group *grhead;
00201 struct group_entry *entry;
00202 int j, needrefresh = 1;
00203 AST_DECLARE_APP_ARGS(args,
00204 AST_APP_ARG(group);
00205 AST_APP_ARG(op);
00206 );
00207 AST_DECLARE_APP_ARGS(inter,
00208 AST_APP_ARG(faces)[100];
00209 );
00210 char *value = ast_strdupa(cvalue);
00211
00212 AST_STANDARD_APP_ARGS(args, data);
00213 AST_NONSTANDARD_APP_ARGS(inter, value, '&');
00214
00215 if (!(grhead = ao2_find(group_container, args.group, 0))) {
00216
00217 grhead = ao2_alloc(sizeof(*grhead), group_destroy);
00218 if (!grhead)
00219 return -1;
00220 grhead->entries = ao2_container_alloc(37, entry_hash_fn, entry_cmp_fn);
00221 if (!grhead->entries) {
00222 ao2_ref(grhead, -1);
00223 return -1;
00224 }
00225 ast_copy_string(grhead->name, args.group, sizeof(grhead->name));
00226 ao2_link(group_container, grhead);
00227 }
00228
00229 if (ast_strlen_zero(args.op)) {
00230
00231 args.op = "add";
00232
00233
00234 ao2_ref(grhead->entries, -1);
00235 if (!(grhead->entries = ao2_container_alloc(37, entry_hash_fn, entry_cmp_fn))) {
00236 ao2_unlink(group_container, grhead);
00237 ao2_ref(grhead, -1);
00238 return -1;
00239 }
00240 }
00241
00242 if (strcasecmp(args.op, "add") == 0) {
00243 for (j = 0; j < inter.argc; j++) {
00244
00245 if ((entry = ao2_find(grhead->entries, inter.faces[j], 0))) {
00246 ao2_ref(entry, -1);
00247 continue;
00248 }
00249 if ((entry = ao2_alloc(sizeof(*entry), NULL))) {
00250 ast_copy_string(entry->name, inter.faces[j], sizeof(entry->name));
00251 ao2_link(grhead->entries, entry);
00252 ao2_ref(entry, -1);
00253 } else {
00254 ast_log(LOG_WARNING, "Unable to add '%s' to dialgroup '%s'\n", inter.faces[j], grhead->name);
00255 }
00256 }
00257 } else if (strncasecmp(args.op, "del", 3) == 0) {
00258 for (j = 0; j < inter.argc; j++) {
00259 if ((entry = ao2_find(grhead->entries, inter.faces[j], OBJ_UNLINK))) {
00260 ao2_ref(entry, -1);
00261 } else {
00262 ast_log(LOG_WARNING, "Interface '%s' not found in dialgroup '%s'\n", inter.faces[j], grhead->name);
00263 }
00264 }
00265 } else {
00266 ast_log(LOG_ERROR, "Unrecognized operation: %s\n", args.op);
00267 needrefresh = 0;
00268 }
00269 ao2_ref(grhead, -1);
00270
00271 if (needrefresh) {
00272 dialgroup_refreshdb(chan, args.group);
00273 }
00274
00275 return 0;
00276 }
00277
00278 static struct ast_custom_function dialgroup_function = {
00279 .name = "DIALGROUP",
00280 .read = dialgroup_read,
00281 .write = dialgroup_write,
00282 };
00283
00284 static int unload_module(void)
00285 {
00286 int res = ast_custom_function_unregister(&dialgroup_function);
00287 ao2_ref(group_container, -1);
00288 return res;
00289 }
00290
00291 static int load_module(void)
00292 {
00293 struct ast_db_entry *dbtree, *tmp;
00294 char groupname[AST_MAX_EXTENSION], *ptr;
00295
00296 if ((group_container = ao2_container_alloc(37, group_hash_fn, group_cmp_fn))) {
00297
00298 if ((dbtree = ast_db_gettree("dialgroup", NULL))) {
00299 for (tmp = dbtree; tmp; tmp = tmp->next) {
00300 ast_copy_string(groupname, tmp->key, sizeof(groupname));
00301 if ((ptr = strrchr(groupname, '/'))) {
00302 ptr++;
00303 dialgroup_write(NULL, "", ptr, tmp->data);
00304 }
00305 }
00306 ast_db_freetree(dbtree);
00307 }
00308 return ast_custom_function_register(&dialgroup_function);
00309 } else {
00310 return AST_MODULE_LOAD_DECLINE;
00311 }
00312 }
00313
00314 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dialgroup dialplan function");