diff --git a/doc/CHANGES-staging/res_musiconhold.txt b/doc/CHANGES-staging/res_musiconhold.txt new file mode 100644 index 0000000000000000000000000000000000000000..47ef3974121bbac40ea53b57f66b551fb6cd83ea --- /dev/null +++ b/doc/CHANGES-staging/res_musiconhold.txt @@ -0,0 +1,7 @@ +Subject: res_musiconhold + +This fix allows a realtime moh class to be unregistered from the command +line. This is useful when the contents of a directory referenced by a +realtime moh class have changed. +The realtime moh class is then reloaded on the next request and uses the +new directory contents. diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index 32e77ddd0311560535e1c5c3c623b7f6aed4fb25..f7700758731fbaa89f3f384810f2adcb295519de 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -1359,6 +1359,13 @@ static int _moh_register(struct mohclass *moh, int reload, int unref, const char return 0; } +#define moh_unregister(a) _moh_unregister(a,__FILE__,__LINE__,__PRETTY_FUNCTION__) +static int _moh_unregister(struct mohclass *moh, const char *file, int line, const char *funcname) +{ + ao2_t_unlink(mohclasses, moh, "Removing class from container"); + return 0; +} + static void local_ast_moh_cleanup(struct ast_channel *chan) { struct moh_files_state *state = ast_channel_music_state(chan); @@ -1379,6 +1386,82 @@ static void local_ast_moh_cleanup(struct ast_channel *chan) } } +/*! \brief Support routing for 'moh unregister class' CLI + * This is in charge of generating all strings that match a prefix in the + * given position. As many functions of this kind, each invokation has + * O(state) time complexity so be careful in using it. + */ +static char *complete_mohclass_realtime(const char *line, const char *word, int pos, int state) +{ + int which=0; + struct mohclass *cur; + char *c = NULL; + int wordlen = strlen(word); + struct ao2_iterator i; + + if (pos != 3) { + return NULL; + } + + i = ao2_iterator_init(mohclasses, 0); + while ((cur = ao2_t_iterator_next(&i, "iterate thru mohclasses"))) { + if (cur->realtime && !strncasecmp(cur->name, word, wordlen) && ++which > state) { + c = ast_strdup(cur->name); + mohclass_unref(cur, "drop ref in iterator loop break"); + break; + } + mohclass_unref(cur, "drop ref in iterator loop"); + } + ao2_iterator_destroy(&i); + + return c; +} + +static char *handle_cli_moh_unregister_class(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + struct mohclass *cur; + int len; + int found = 0; + struct ao2_iterator i; + + switch (cmd) { + case CLI_INIT: + e->command = "moh unregister class"; + e->usage = + "Usage: moh unregister class <class>\n" + " Unregisters a realtime moh class.\n"; + return NULL; + case CLI_GENERATE: + return complete_mohclass_realtime(a->line, a->word, a->pos, a->n); + } + + if (a->argc != 4) + return CLI_SHOWUSAGE; + + len = strlen(a->argv[3]); + + i = ao2_iterator_init(mohclasses, 0); + while ((cur = ao2_t_iterator_next(&i, "iterate thru mohclasses"))) { + if (cur->realtime && len == strlen(cur->name) && !strncasecmp(cur->name, a->argv[3], len)) { + found = 1; + break; + } + mohclass_unref(cur, "drop ref in iterator loop"); + } + ao2_iterator_destroy(&i); + + if (found) { + moh_unregister(cur); + mohclass_unref(cur, "drop ref after unregister"); + } else { + ast_cli(a->fd, "No such realtime moh class '%s'\n", a->argv[3]); + } + + return CLI_SUCCESS; +} + + + static void moh_class_destructor(void *obj); #define moh_class_malloc() _moh_class_malloc(__FILE__,__LINE__,__PRETTY_FUNCTION__) @@ -1910,9 +1993,10 @@ static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struc } static struct ast_cli_entry cli_moh[] = { - AST_CLI_DEFINE(handle_cli_moh_reload, "Reload MusicOnHold"), - AST_CLI_DEFINE(handle_cli_moh_show_classes, "List MusicOnHold classes"), - AST_CLI_DEFINE(handle_cli_moh_show_files, "List MusicOnHold file-based classes") + AST_CLI_DEFINE(handle_cli_moh_reload, "Reload MusicOnHold"), + AST_CLI_DEFINE(handle_cli_moh_show_classes, "List MusicOnHold classes"), + AST_CLI_DEFINE(handle_cli_moh_show_files, "List MusicOnHold file-based classes"), + AST_CLI_DEFINE(handle_cli_moh_unregister_class, "Unregister realtime MusicOnHold class") }; static int moh_class_hash(const void *obj, const int flags)