diff --git a/apps/app_directory.c b/apps/app_directory.c index ce01bc83b80ef93bcc317e5cd93a0804805da57b..b26a09cd9777709ec837d8c4056a2fc6413f3681 100644 --- a/apps/app_directory.c +++ b/apps/app_directory.c @@ -87,6 +87,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") argument will be used for the number of characters the user should enter.</para> <argument name="n" required="true" /> </option> + <option name="a"> + <para>Allow the caller to additionally enter an alias for a user in the + directory. This option must be specified in addition to the + <literal>f</literal>, <literal>l</literal>, or <literal>b</literal> + option.</para> + </option> <option name="m"> <para>Instead of reading each name sequentially and asking for confirmation, create a menu of up to 8 names.</para> @@ -135,6 +141,7 @@ enum { OPT_LISTBYEITHER = OPT_LISTBYFIRSTNAME | OPT_LISTBYLASTNAME, OPT_PAUSE = (1 << 5), OPT_NOANSWER = (1 << 6), + OPT_ALIAS = (1 << 7), }; enum { @@ -164,6 +171,7 @@ AST_APP_OPTIONS(directory_app_options, { AST_APP_OPTION('v', OPT_FROMVOICEMAIL), AST_APP_OPTION('m', OPT_SELECTFROMMENU), AST_APP_OPTION('n', OPT_NOANSWER), + AST_APP_OPTION('a', OPT_ALIAS), }); static int compare(const char *text, const char *template) @@ -427,6 +435,8 @@ static int select_item_menu(struct ast_channel *chan, struct directory_item **it return 0; } +AST_THREADSTORAGE(commonbuf); + static struct ast_config *realtime_directory(char *context) { struct ast_config *cfg; @@ -436,8 +446,12 @@ static struct ast_config *realtime_directory(char *context) char *mailbox; const char *fullname; const char *hidefromdir, *searchcontexts = NULL; - char tmp[100]; struct ast_flags config_flags = { 0 }; + struct ast_str *tmp = ast_str_thread_get(&commonbuf, 100); + + if (!tmp) { + return NULL; + } /* Load flat file config. */ cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags); @@ -472,6 +486,7 @@ static struct ast_config *realtime_directory(char *context) mailbox = NULL; while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) { + struct ast_variable *alias; const char *ctx = ast_variable_retrieve(rtdata, mailbox, "context"); fullname = ast_variable_retrieve(rtdata, mailbox, "fullname"); @@ -480,7 +495,14 @@ static struct ast_config *realtime_directory(char *context) /* Skip hidden */ continue; } - snprintf(tmp, sizeof(tmp), "no-password,%s", S_OR(fullname, "")); + ast_str_set(&tmp, 0, "no-password,%s", S_OR(fullname, "")); + if (ast_variable_retrieve(rtdata, mailbox, "alias")) { + for (alias = ast_variable_browse(rtdata, mailbox); alias; alias = alias->next) { + if (!strcasecmp(alias->name, "alias")) { + ast_str_append(&tmp, 0, "|alias=%s", alias->value); + } + } + } /* Does the context exist within the config file? If not, make one */ if (!(cat = ast_category_get(cfg, ctx))) { @@ -495,7 +517,7 @@ static struct ast_config *realtime_directory(char *context) ast_category_append(cfg, cat); } - if ((var = ast_variable_new(mailbox, tmp, ""))) { + if ((var = ast_variable_new(mailbox, ast_str_buffer(tmp), ""))) { ast_variable_append(cat, var); } else { ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox); @@ -556,20 +578,26 @@ typedef AST_LIST_HEAD_NOLOCK(, directory_item) itemlist; static int search_directory_sub(const char *context, struct ast_config *vmcfg, struct ast_config *ucfg, const char *ext, struct ast_flags flags, itemlist *alist) { struct ast_variable *v; - char buf[AST_MAX_EXTENSION + 1], *pos, *bufptr, *cat; + struct ast_str *buf = ast_str_thread_get(&commonbuf, 100); + char *pos, *bufptr, *cat, *alias; struct directory_item *item; int res; + if (!buf) { + return -1; + } + ast_debug(2, "Pattern: %s\n", ext); for (v = ast_variable_browse(vmcfg, context); v; v = v->next) { /* Ignore hidden */ - if (strcasestr(v->value, "hidefromdir=yes")) + if (strcasestr(v->value, "hidefromdir=yes")) { continue; + } - ast_copy_string(buf, v->value, sizeof(buf)); - bufptr = buf; + ast_str_set(&buf, 0, "%s", v->value); + bufptr = ast_str_buffer(buf); /* password,Full Name,email,pager,options */ strsep(&bufptr, ","); @@ -587,11 +615,23 @@ static int search_directory_sub(const char *context, struct ast_config *vmcfg, s if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) { res = check_match(&item, context, pos, v->name, ext, 1 /* use_first_name */); } + if (!res && ast_test_flag(&flags, OPT_ALIAS) && (alias = strcasestr(bufptr, "alias="))) { + char *a; + ast_debug(1, "Found alias: %s\n", alias); + while ((a = strsep(&alias, "|"))) { + if (!strncasecmp(a, "alias=", 6)) { + if ((res = check_match(&item, context, a + 6, v->name, ext, 1))) { + break; + } + } + } + } - if (!res) + if (!res) { continue; - else if (res < 0) + } else if (res < 0) { return -1; + } AST_LIST_INSERT_TAIL(alist, item, entry); } @@ -599,15 +639,18 @@ static int search_directory_sub(const char *context, struct ast_config *vmcfg, s if (ucfg) { for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) { const char *position; - if (!strcasecmp(cat, "general")) + + if (!strcasecmp(cat, "general")) { continue; - if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory"))) + } + if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory"))) { continue; + } /* Find all candidate extensions */ - position = ast_variable_retrieve(ucfg, cat, "fullname"); - if (!position) + if (!(position = ast_variable_retrieve(ucfg, cat, "fullname"))) { continue; + } res = 0; if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) { @@ -616,11 +659,20 @@ static int search_directory_sub(const char *context, struct ast_config *vmcfg, s if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) { res = check_match(&item, context, position, cat, ext, 1 /* use_first_name */); } + if (!res && ast_test_flag(&flags, OPT_ALIAS)) { + struct ast_variable *alias; + for (alias = ast_variable_browse(ucfg, cat); alias; alias = alias->next) { + if (!strcasecmp(v->name, "alias") && (res = check_match(&item, context, v->value, cat, ext, 1))) { + break; + } + } + } - if (!res) + if (!res) { continue; - else if (res < 0) + } else if (res < 0) { return -1; + } AST_LIST_INSERT_TAIL(alist, item, entry); } diff --git a/configs/voicemail.conf.sample b/configs/voicemail.conf.sample index a92e7a1c5b88f78617bb980e01df1d566a4d861e..b776fd60d9ae4f474e244b824ee8ebaeb8da74a5 100644 --- a/configs/voicemail.conf.sample +++ b/configs/voicemail.conf.sample @@ -282,6 +282,10 @@ sendvoicemail=yes ; Allow the user to compose and send a voicemail while inside ; This is intended for use with users who wish to receive their ; voicemail ONLY by email. Note: "deletevoicemail" is provided as an ; equivalent option for Realtime configuration. +; alias=Bongo ; Use this additional string for comparison while looking + ; for a match in the Directory application. This option + ; may be specified multiple times to specify additional + ; strings [per-mailbox only] ; volgain=0.0 ; Emails bearing the voicemail may arrive in a volume too ; quiet to be heard. This parameter allows you to specify how ; much gain to add to the message when sending a voicemail. diff --git a/contrib/realtime/mysql/voicemail.sql b/contrib/realtime/mysql/voicemail.sql index bd924f4265f9680fd96077f7e72c164a80651e25..62c7fbb6ae24d1aa648a9e3dc00a15b7e0545b9b 100644 --- a/contrib/realtime/mysql/voicemail.sql +++ b/contrib/realtime/mysql/voicemail.sql @@ -10,6 +10,8 @@ CREATE TABLE voicemail ( password CHAR(80) NOT NULL, -- Used in email and for Directory app fullname CHAR(80), + -- Used for Directory app + alias CHAR(80), -- Email address (will get sound file if attach=yes) email CHAR(80), -- Email address (won't get sound file) diff --git a/res/res_xmpp.c b/res/res_xmpp.c index 77369c487a6495e5071ad2b19f513b4820ff4207..1e130e77152574d2b10f4c5676491ed3fbf027a4 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -928,7 +928,7 @@ static iks* xmpp_pubsub_iq_create(struct ast_xmpp_client *client, const char *ty * \return iks * */ static iks* xmpp_pubsub_build_publish_skeleton(struct ast_xmpp_client *client, const char *node, - const char *event_type) + const char *event_type, unsigned int cachable) { RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup); iks *request, *pubsub, *publish, *item; @@ -944,6 +944,22 @@ static iks* xmpp_pubsub_build_publish_skeleton(struct ast_xmpp_client *client, c item = iks_insert(publish, "item"); iks_insert_attrib(item, "id", node); + if (cachable == AST_DEVSTATE_NOT_CACHABLE) { + iks *options, *x, *field_form_type, *field_persist; + + options = iks_insert(pubsub, "publish-options"); + x = iks_insert(options, "x"); + iks_insert_attrib(x, "xmlns", "jabber:x:data"); + iks_insert_attrib(x, "type", "submit"); + field_form_type = iks_insert(x, "field"); + iks_insert_attrib(field_form_type, "var", "FORM_TYPE"); + iks_insert_attrib(field_form_type, "type", "hidden"); + iks_insert_cdata(iks_insert(field_form_type, "value"), "http://jabber.org/protocol/pubsub#publish-options", 0); + field_persist = iks_insert(x, "field"); + iks_insert_attrib(field_persist, "var", "pubsub#persist_items"); + iks_insert_cdata(iks_insert(field_persist, "value"), "0", 1); + } + return item; } @@ -1120,7 +1136,7 @@ static void xmpp_pubsub_publish_mwi(struct ast_xmpp_client *client, const char * snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context); - if (!(request = xmpp_pubsub_build_publish_skeleton(client, full_mailbox, "message_waiting"))) { + if (!(request = xmpp_pubsub_build_publish_skeleton(client, full_mailbox, "message_waiting", AST_DEVSTATE_CACHABLE))) { return; } @@ -1144,13 +1160,13 @@ static void xmpp_pubsub_publish_mwi(struct ast_xmpp_client *client, const char * * \return void */ static void xmpp_pubsub_publish_device_state(struct ast_xmpp_client *client, const char *device, - const char *device_state) + const char *device_state, unsigned int cachable) { RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup); iks *request, *state; - char eid_str[20]; + char eid_str[20], cachable_str[2]; - if (!cfg || !cfg->global || !(request = xmpp_pubsub_build_publish_skeleton(client, device, "device_state"))) { + if (!cfg || !cfg->global || !(request = xmpp_pubsub_build_publish_skeleton(client, device, "device_state", cachable))) { return; } @@ -1166,6 +1182,8 @@ static void xmpp_pubsub_publish_device_state(struct ast_xmpp_client *client, con state = iks_insert(request, "state"); iks_insert_attrib(state, "xmlns", "http://asterisk.org"); iks_insert_attrib(state, "eid", eid_str); + snprintf(cachable_str, sizeof(cachable_str), "%u", cachable); + iks_insert_attrib(state, "cachable", cachable_str); iks_insert_cdata(state, device_state, strlen(device_state)); ast_xmpp_client_send(client, iks_root(request)); iks_delete(request); @@ -1208,6 +1226,7 @@ static void xmpp_pubsub_devstate_cb(const struct ast_event *ast_event, void *dat { struct ast_xmpp_client *client = data; const char *device, *device_state; + unsigned int cachable; if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID))) { /* If the event didn't originate from this server, don't send it back out. */ @@ -1217,7 +1236,8 @@ static void xmpp_pubsub_devstate_cb(const struct ast_event *ast_event, void *dat device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE); device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE)); - xmpp_pubsub_publish_device_state(client, device, device_state); + cachable = ast_event_get_ie_uint(ast_event, AST_EVENT_IE_CACHABLE); + xmpp_pubsub_publish_device_state(client, device, device_state, cachable); } /*! @@ -1301,11 +1321,12 @@ static void xmpp_pubsub_subscribe(struct ast_xmpp_client *client, const char *no */ static int xmpp_pubsub_handle_event(void *data, ikspak *pak) { - char *item_id, *device_state, *context; + char *item_id, *device_state, *context, *cachable_str; int oldmsgs, newmsgs; iks *item, *item_content; struct ast_eid pubsub_eid; struct ast_event *event; + unsigned int cachable = AST_DEVSTATE_CACHABLE; item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item"); if (!item) { ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n"); @@ -1320,6 +1341,9 @@ static int xmpp_pubsub_handle_event(void *data, ikspak *pak) } if (!strcasecmp(iks_name(item_content), "state")) { device_state = iks_find_cdata(item, "state"); + if ((cachable_str = iks_find_cdata(item, "cachable"))) { + sscanf(cachable_str, "%30d", &cachable); + } if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE, AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID, @@ -1344,7 +1368,13 @@ static int xmpp_pubsub_handle_event(void *data, ikspak *pak) iks_name(item_content)); return IKS_FILTER_EAT; } - ast_event_queue_and_cache(event); + + if (cachable == AST_DEVSTATE_CACHABLE) { + ast_event_queue_and_cache(event); + } else { + ast_event_queue(event); + } + return IKS_FILTER_EAT; } @@ -1846,7 +1876,7 @@ static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, ch { RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup); RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup); - char *aux = NULL, *parse = NULL; + char *parse = NULL; int timeout, jidlen, resourcelen, found = 0; struct timeval start; long diff = 0; @@ -1960,7 +1990,7 @@ static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, ch continue; } found = 1; - aux = ast_strdupa(message->message); + ast_copy_string(buf, message->message, buflen); AST_LIST_REMOVE_CURRENT(list); xmpp_message_destroy(message); break; @@ -1984,7 +2014,6 @@ static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, ch ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid); return -1; } - ast_copy_string(buf, aux, buflen); return 0; }