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