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: http://svn.digium.com/svn/asterisk/trunk@78807 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
255bc22905
commit
633c98f1bc
1 changed files with 140 additions and 54 deletions
|
@ -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. */
|
||||
|
|
Reference in a new issue