diff options
author | Russell Bryant <russell@russellbryant.com> | 2007-08-09 19:11:53 +0000 |
---|---|---|
committer | Russell Bryant <russell@russellbryant.com> | 2007-08-09 19:11:53 +0000 |
commit | 348ff8c3e94a6c90a37e228fc81964ad2e5d55ca (patch) | |
tree | 3fa4f41c4832c8223b7281e5f4bf7053f8b3a1b3 /channels | |
parent | 5b9f4110bceacc7ab92e668c767a6afd511d34f9 (diff) |
Restore the ability to have multiple mailboxes listed for the mailbox option
in sip.conf. chan_sip now maintains separate internal MWI subscriptions for
each one.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@78807 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_sip.c | 194 |
1 files changed, 140 insertions, 54 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index ab875b1a9..8f19c5827 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1226,6 +1226,20 @@ struct sip_user { int autoframing; }; +/*! + * \brief A peer's mailbox + * + * We could use STRINGFIELDS here, but for only two strings, it seems like + * too much effort ... + */ +struct sip_mailbox { + char *mailbox; + char *context; + /*! Associated MWI subscription */ + struct ast_event_sub *event_sub; + AST_LIST_ENTRY(sip_mailbox) entry; +}; + /*! \brief Structure for SIP peer data, we place calls to peers if registered or fixed IP address (host) */ /* XXX field 'name' must be first otherwise sip_addrcmp() will fail */ struct sip_peer { @@ -1254,7 +1268,6 @@ struct sip_peer { int busy_level; /*!< Level of active channels where we signal busy */ enum transfermodes allowtransfer; /*! SIP Refer restriction scheme */ char vmexten[AST_MAX_EXTENSION]; /*!< Dialplan extension for MWI notify message*/ - char mailbox[AST_MAX_EXTENSION]; /*!< Mailbox setting for MWI checks */ char language[MAX_LANGUAGE]; /*!< Default language for prompts */ char mohinterpret[MAX_MUSICCLASS];/*!< Music on Hold class */ char mohsuggest[MAX_MUSICCLASS];/*!< Music on Hold class */ @@ -1263,6 +1276,9 @@ struct sip_peer { int lastmsgssent; unsigned int sipoptions; /*!< Supported SIP options */ struct ast_flags flags[2]; /*!< SIP_ flags */ + + /*! Mailboxes that this peer cares about */ + AST_LIST_HEAD_NOLOCK(, sip_mailbox) mailboxes; /* things that don't belong in flags */ char is_realtime; /*!< this is a 'realtime' peer */ @@ -1293,7 +1309,6 @@ struct sip_peer { struct ast_variable *chanvars; /*!< Variables to set for channel created by user */ struct sip_pvt *mwipvt; /*!< Subscription for MWI */ int autoframing; - struct ast_event_sub *mwi_event_sub; /*!< The MWI event subscription */ }; @@ -2880,6 +2895,25 @@ static void register_peer_exten(struct sip_peer *peer, int onoff) } } +static void destroy_mailbox(struct sip_mailbox *mailbox) +{ + if (mailbox->mailbox) + ast_free(mailbox->mailbox); + if (mailbox->context) + ast_free(mailbox->context); + if (mailbox->event_sub) + ast_event_unsubscribe(mailbox->event_sub); + ast_free(mailbox); +} + +static void clear_peer_mailboxes(struct sip_peer *peer) +{ + struct sip_mailbox *mailbox; + + while ((mailbox = AST_LIST_REMOVE_HEAD(&peer->mailboxes, entry))) + destroy_mailbox(mailbox); +} + /*! \brief Destroy peer object from memory */ static void sip_destroy_peer(struct sip_peer *peer) { @@ -2896,11 +2930,6 @@ static void sip_destroy_peer(struct sip_peer *peer) if (peer->mwipvt) /* We have an active subscription, delete it */ peer->mwipvt = sip_destroy(peer->mwipvt); - if (peer->mwi_event_sub) { - ast_event_unsubscribe(peer->mwi_event_sub); - peer->mwi_event_sub = NULL; - } - if (peer->chanvars) { ast_variables_destroy(peer->chanvars); peer->chanvars = NULL; @@ -2923,6 +2952,7 @@ static void sip_destroy_peer(struct sip_peer *peer) peer->auth = NULL; if (peer->dnsmgr) ast_dnsmgr_release(peer->dnsmgr); + clear_peer_mailboxes(peer); ast_free(peer); } @@ -11098,6 +11128,19 @@ static int sip_show_peer(int fd, int argc, char *argv[]) return _sip_show_peer(0, fd, NULL, NULL, argc, (const char **) argv); } +static void peer_mailboxes_to_str(struct ast_str **mailbox_str, struct sip_peer *peer) +{ + struct sip_mailbox *mailbox; + + AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) { + ast_str_append(mailbox_str, 0, "%s%s%s%s", + mailbox->mailbox, + ast_strlen_zero(mailbox->context) ? "" : "@", + S_OR(mailbox->context, ""), + AST_LIST_NEXT(mailbox, entry) ? "," : ""); + } +} + /*! \brief Show one peer in detail (main function) */ static int _sip_show_peer(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[]) { @@ -11132,6 +11175,7 @@ static int _sip_show_peer(int type, int fd, struct mansession *s, const struct m } } if (peer && type==0 ) { /* Normal listing */ + struct ast_str *mailbox_str = ast_str_alloca(512); ast_cli(fd,"\n\n"); ast_cli(fd, " * Name : %s\n", peer->name); if (realtimepeers) { /* Realtime is enabled */ @@ -11159,7 +11203,8 @@ static int _sip_show_peer(int type, int fd, struct mansession *s, const struct m print_group(fd, peer->callgroup, 0); ast_cli(fd, " Pickupgroup : "); print_group(fd, peer->pickupgroup, 0); - ast_cli(fd, " Mailbox : %s\n", peer->mailbox); + peer_mailboxes_to_str(&mailbox_str, peer); + ast_cli(fd, " Mailbox : %s\n", mailbox_str->str); ast_cli(fd, " VM Extension : %s\n", peer->vmexten); ast_cli(fd, " LastMsgsSent : %d/%d\n", (peer->lastmsgssent & 0x7fff0000) >> 16, peer->lastmsgssent & 0xffff); ast_cli(fd, " Call limit : %d\n", peer->call_limit); @@ -11234,6 +11279,7 @@ static int _sip_show_peer(int type, int fd, struct mansession *s, const struct m unref_peer(peer); } else if (peer && type == 1) { /* manager listing */ char buf[256]; + struct ast_str *mailbox_str = ast_str_alloca(512); astman_append(s, "Channeltype: SIP\r\n"); astman_append(s, "ObjectName: %s\r\n", peer->name); astman_append(s, "ChanObjectType: peer\r\n"); @@ -11253,7 +11299,8 @@ static int _sip_show_peer(int type, int fd, struct mansession *s, const struct m astman_append(s, "%s\r\n", ast_print_group(buf, sizeof(buf), peer->callgroup)); astman_append(s, "Pickupgroup: "); astman_append(s, "%s\r\n", ast_print_group(buf, sizeof(buf), peer->pickupgroup)); - astman_append(s, "VoiceMailbox: %s\r\n", peer->mailbox); + peer_mailboxes_to_str(&mailbox_str, peer); + astman_append(s, "VoiceMailbox: %s\r\n", mailbox_str->str); astman_append(s, "TransferMode: %s\r\n", transfermode2str(peer->allowtransfer)); astman_append(s, "LastMsgsSent: %d\r\n", peer->lastmsgssent); astman_append(s, "Call-limit: %d\r\n", peer->call_limit); @@ -11656,6 +11703,9 @@ static int show_channels_cb(void *__cur, void *__arg, int flags) arg->numchans++; } if (cur->subscribed != NONE && arg->subscriptions) { + struct ast_str *mailbox_str = ast_str_alloca(512); + if (cur->subscribed == MWI_NOTIFICATION && cur->relatedpeer) + peer_mailboxes_to_str(&mailbox_str, cur->relatedpeer); ast_cli(arg->fd, FORMAT3, ast_inet_ntoa(dst->sin_addr), S_OR(cur->username, S_OR(cur->cid_num, "(None)")), cur->callid, @@ -11663,7 +11713,7 @@ static int show_channels_cb(void *__cur, void *__arg, int flags) cur->subscribed == MWI_NOTIFICATION ? "--" : cur->subscribeuri, cur->subscribed == MWI_NOTIFICATION ? "<none>" : ast_extension_state2str(cur->laststate), subscription_type2str(cur->subscribed), - cur->subscribed == MWI_NOTIFICATION ? (cur->relatedpeer ? cur->relatedpeer->mailbox : "<none>") : "<none>" + cur->subscribed == MWI_NOTIFICATION ? S_OR(mailbox_str->str, "<none>") : "<none>" ); arg->numchans++; } @@ -12700,7 +12750,9 @@ static int function_sippeer(struct ast_channel *chan, const char *cmd, char *dat } else if (!strcasecmp(colname, "useragent")) { ast_copy_string(buf, peer->useragent, len); } else if (!strcasecmp(colname, "mailbox")) { - ast_copy_string(buf, peer->mailbox, len); + struct ast_str *mailbox_str = ast_str_alloca(512); + peer_mailboxes_to_str(&mailbox_str, peer); + ast_copy_string(buf, mailbox_str->str, len); } else if (!strcasecmp(colname, "context")) { ast_copy_string(buf, peer->context, len); } else if (!strcasecmp(colname, "expire")) { @@ -15563,6 +15615,18 @@ static int handle_request_message(struct sip_pvt *p, struct sip_request *req) return 1; } +static void add_peer_mwi_subs(struct sip_peer *peer) +{ + struct sip_mailbox *mailbox; + + AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) { + mailbox->event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, peer, + AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox->mailbox, + AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, S_OR(mailbox->context, "default"), + AST_EVENT_IE_END); + } +} + /*! \brief Handle incoming SUBSCRIBE request */ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e) { @@ -15745,7 +15809,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, The subscribed URI needs to exist in the dial plan In most devices, this is configurable to the voicemailmain extension you use */ - if (!authpeer || ast_strlen_zero(authpeer->mailbox)) { + if (!authpeer || AST_LIST_EMPTY(&authpeer->mailboxes)) { transmit_response(p, "404 Not found (no mailbox)", req); p->needdestroy = 1; ast_log(LOG_NOTICE, "Received SIP subscribe for peer without mailbox: %s\n", authpeer->name); @@ -15756,15 +15820,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, p->subscribed = MWI_NOTIFICATION; if (ast_test_flag(&authpeer->flags[1], SIP_PAGE2_SUBSCRIBEMWIONLY)) { - char *mailbox, *context; - context = mailbox = ast_strdupa(authpeer->mailbox); - strsep(&context, "@"); - if (ast_strlen_zero(context)) - context = "default"; - authpeer->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, authpeer, - AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox, - AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context, - AST_EVENT_IE_END); + add_peer_mwi_subs(authpeer); } if (authpeer->mwipvt && authpeer->mwipvt != p) /* Destroy old PVT if this is a new one */ /* We only allow one subscription per peer */ @@ -15801,7 +15857,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, if (sipdebug) { if (p->subscribed == MWI_NOTIFICATION && p->relatedpeer) - ast_debug(2, "Adding subscription for mailbox notification - peer %s Mailbox %s\n", p->relatedpeer->name, p->relatedpeer->mailbox); + ast_debug(2, "Adding subscription for mailbox notification - peer %s\n", p->relatedpeer->name); else ast_debug(2, "Adding subscription for extension %s context %s for peer %s\n", p->exten, p->context, p->username); } @@ -16234,13 +16290,39 @@ static int sipsock_read(int *id, int fd, short events, void *ignore) return 1; } +/*! + * \brief Get cached MWI info + * \retval 0 At least one message is waiting + * \retval 1 no messages waiting + */ +static int get_cached_mwi(struct sip_peer *peer, int *new, int *old) +{ + struct sip_mailbox *mailbox; + + AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) { + struct ast_event *event; + event = ast_event_get_cached(AST_EVENT_MWI, + AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox->mailbox, + AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, mailbox->context, + AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS, + AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_EXISTS, + AST_EVENT_IE_END); + if (!event) + continue; + *new += ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS); + *old += ast_event_get_ie_uint(event, AST_EVENT_IE_OLDMSGS); + ast_event_destroy(event); + } + + return (*new || *old) ? 0 : 1; +} + /*! \brief Send message waiting indication to alert peer that they've got voicemail */ static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *event, int cache_only) { /* Called with peerl lock, but releases it */ struct sip_pvt *p; int newmsgs = 0, oldmsgs = 0; - struct ast_event *cache_event = NULL; if (ast_test_flag((&peer->flags[1]), SIP_PAGE2_SUBSCRIBEMWIONLY) && !peer->mwipvt) return 0; @@ -16249,30 +16331,18 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *e if (!peer->addr.sin_addr.s_addr && !peer->defaddr.sin_addr.s_addr) return 0; - if (!event) { - char *mailbox, *context = NULL; - /* Check the event cache for the mailbox info */ - context = mailbox = ast_strdupa(peer->mailbox); - strsep(&context, "@"); - if (ast_strlen_zero(context)) - context = "default"; - event = cache_event = ast_event_get_cached(AST_EVENT_MWI, - AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox, - AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context, - AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS, - AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_EXISTS, - AST_EVENT_IE_END); - } - if (event) { newmsgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS); oldmsgs = ast_event_get_ie_uint(event, AST_EVENT_IE_OLDMSGS); - if (cache_event) - ast_event_destroy(cache_event); + } else if (!get_cached_mwi(peer, &newmsgs, &oldmsgs)) { + /* got it! Don't keep looking. */ } else if (cache_only) { return 0; - } else /* Fall back to manually checking the mailbox */ - ast_app_inboxcount(peer->mailbox, &newmsgs, &oldmsgs); + } else { /* Fall back to manually checking the mailbox */ + struct ast_str *mailbox_str = ast_str_alloca(512); + peer_mailboxes_to_str(&mailbox_str, peer); + ast_app_inboxcount(mailbox_str->str, &newmsgs, &oldmsgs); + } if (peer->mwipvt) { /* Base message on subscription */ @@ -17212,11 +17282,11 @@ static void set_peer_defaults(struct sip_peer *peer) peer->fromdomain[0] = '\0'; peer->fromuser[0] = '\0'; peer->regexten[0] = '\0'; - peer->mailbox[0] = '\0'; peer->callgroup = 0; peer->pickupgroup = 0; peer->maxms = default_qualify; peer->prefs = default_prefs; + clear_peer_mailboxes(peer); } /*! \brief Create temporary peer (used in autocreatepeer mode) */ @@ -17241,6 +17311,30 @@ static struct sip_peer *temp_peer(const char *name) return peer; } +static void add_peer_mailboxes(struct sip_peer *peer, const char *value) +{ + char *next, *mbox, *context; + + next = ast_strdupa(value); + + while ((mbox = context = strsep(&next, ","))) { + struct sip_mailbox *mailbox; + + if (!(mailbox = ast_calloc(1, sizeof(*mailbox)))) + continue; + + strsep(&context, "@"); + if (ast_strlen_zero(mbox)) { + free(mailbox); + continue; + } + mailbox->mailbox = ast_strdup(mbox); + mailbox->context = ast_strdup(context); + + AST_LIST_INSERT_TAIL(&peer->mailboxes, mailbox, entry); + } +} + /*! \brief Build peer from configuration (file or realtime static/dynamic) */ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime) { @@ -17427,7 +17521,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str } else if (!strcasecmp(v->name, "mohsuggest")) { ast_copy_string(peer->mohsuggest, v->value, sizeof(peer->mohsuggest)); } else if (!strcasecmp(v->name, "mailbox")) { - ast_copy_string(peer->mailbox, v->value, sizeof(peer->mailbox)); + add_peer_mailboxes(peer, v->value); } else if (!strcasecmp(v->name, "subscribemwi")) { ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_SUBSCRIBEMWIONLY); } else if (!strcasecmp(v->name, "vmexten")) { @@ -17499,16 +17593,8 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str /* If they didn't request that MWI is sent *only* on subscribe, go ahead and * subscribe to it now. */ if (!ast_test_flag(&peer->flags[1], SIP_PAGE2_SUBSCRIBEMWIONLY) && - !ast_strlen_zero(peer->mailbox)) { - char *mailbox, *context; - context = mailbox = ast_strdupa(peer->mailbox); - strsep(&context, "@"); - if (ast_strlen_zero(context)) - context = "default"; - peer->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, peer, - AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox, - AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context, - AST_EVENT_IE_END); + !AST_LIST_EMPTY(&peer->mailboxes)) { + add_peer_mwi_subs(peer); /* Send MWI from the event cache only. This is so we can send initial * MWI if app_voicemail got loaded before chan_sip. If it is the other * way, then we will get events when app_voicemail gets loaded. */ |