Index: channels/chan_sip.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v
retrieving revision 1.669
diff -u -r1.669 chan_sip.c
--- channels/chan_sip.c 26 Feb 2005 16:29:15 -0000 1.669
+++ channels/chan_sip.c 27 Feb 2005 17:43:07 -0000
@@ -124,9 +124,10 @@
static char default_useragent[AST_MAX_EXTENSION] = DEFAULT_USERAGENT;
#define DEFAULT_CONTEXT "default"
-static char default_context[AST_MAX_EXTENSION] = DEFAULT_CONTEXT;
+static char default_context[AST_MAX_EXTENSION]; /* Default context for calls */
+static char default_subscribecontext[AST_MAX_EXTENSION]; /* Default context for subscriptions */
-static char default_language[MAX_LANGUAGE] = "";
+static char default_language[MAX_LANGUAGE] = ""; /* Default language */
#define DEFAULT_CALLERID "asterisk"
static char default_callerid[AST_MAX_EXTENSION] = DEFAULT_CALLERID;
@@ -356,6 +357,7 @@
char from[256]; /* The From: header */
char useragent[256]; /* User agent in SIP request */
char context[AST_MAX_EXTENSION]; /* Context for this call */
+ char subscribecontext[AST_MAX_EXTENSION]; /* SubscribeContext for this call */
char fromdomain[AST_MAX_EXTENSION]; /* Domain to show in the from field */
char fromuser[AST_MAX_EXTENSION]; /* User to show in the user field */
char fromname[AST_MAX_EXTENSION]; /* Name to show in the user field */
@@ -402,7 +404,8 @@
int rtpkeepalive; /* Send RTP packets for keepalive */
int subscribed; /* Is this call a subscription? */
- int stateid;
+ int stateid; /* State ID */
+ int laststate; /* Last Known State */
int dialogver;
struct ast_dsp *vad; /* Voice Activation Detection dsp */
@@ -438,7 +441,7 @@
ASTOBJ_COMPONENTS(struct sip_user);
char secret[80]; /* Password */
char md5secret[80]; /* Password in md5 */
- char context[80]; /* Default context for incoming calls */
+ char context[AST_MAX_EXTENSION]; /* Default context for incoming calls */
char cid_num[80]; /* Caller ID num */
char cid_name[80]; /* Caller ID name */
char accountcode[20]; /* Account code */
@@ -466,7 +469,8 @@
/* peer->name is the unique name of this object */
char secret[80]; /* Password */
char md5secret[80]; /* Password in MD5 */
- char context[80]; /* Default context for incoming calls */
+ char context[AST_MAX_EXTENSION]; /* Default context for incoming calls */
+ char subscribecontext[AST_MAX_EXTENSION]; /* Context for subscriptions */
char username[80]; /* Temporary username until registration */
char accountcode[20]; /* Account code */
int amaflags; /* AMA Flags (for billing) */
@@ -591,6 +595,7 @@
/* The list of manual NOTIFY types we know how to send */
struct ast_config *notify_types;
+static void append_date(struct sip_request *req);
static struct ast_frame *sip_read(struct ast_channel *ast);
static int transmit_response(struct sip_pvt *p, char *msg, struct sip_request *req);
static int transmit_response_with_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
@@ -3166,7 +3171,8 @@
if (maddr) {
maddr += 6;
hn = strspn(maddr, "0123456789.");
- if (hn > (sizeof(hostname) - 1)) hn = sizeof(hostname) - 1;
+ if (hn > (sizeof(hostname) - 1))
+ hn = sizeof(hostname) - 1;
strncpy(hostname, maddr, hn); hostname[hn] = '\0'; /* safe */
}
@@ -3251,16 +3257,20 @@
add_header(resp, "Allow", ALLOWED_METHODS);
if (p->expiry) {
/* For registration responses, we also need expiry and
- contact info */
+ contact info, but not for subscriptions */
char contact[256];
- char tmp[256];
+
snprintf(contact, sizeof(contact), "%s;expires=%d", p->our_contact, p->expiry);
- snprintf(tmp, sizeof(tmp), "%d", p->expiry);
- add_header(resp, "Expires", tmp);
add_header(resp, "Contact", contact);
} else {
add_header(resp, "Contact", p->our_contact);
}
+ if (p->expiry) { /* Subscriptions and registrations */
+ char tmp[256];
+
+ snprintf(tmp, sizeof(tmp), "%d", p->expiry);
+ add_header(resp, "Expires", tmp);
+ }
if (p->maxforwards) {
char tmp[256];
snprintf(tmp, sizeof(tmp), "%d", p->maxforwards);
@@ -3358,7 +3368,13 @@
add_header(req, "From", ot);
add_header(req, "To", of);
}
- add_header(req, "Contact", p->our_contact);
+ if (!strcasecmp(msg, "MESSAGE")) {
+ /* Add date header to MESSAGE */
+ append_date(req);
+ } else {
+ /* Do not add Contact on MESSAGE */
+ add_header(req, "Contact", p->our_contact);
+ }
copy_header(req, orig, "Call-ID");
add_header(req, "CSeq", tmp);
@@ -4036,10 +4052,12 @@
int maxbytes = 0;
int bytes = 0;
char from[256], to[256];
- char *t, *c, *a;
+ char *t = NULL, *c, *a;
char *mfrom, *mto;
struct sip_request req;
char clen[20];
+ char hint[AST_MAX_EXTENSION];
+ int hintstate = 1;
memset(from, 0, sizeof(from));
memset(to, 0, sizeof(to));
@@ -4057,30 +4075,36 @@
reqprep(&req, p, "NOTIFY", 0, 1);
- if (p->subscribed == 1) {
- strncpy(to, get_header(&p->initreq, "To"), sizeof(to)-1);
+ /* Check which device/devices we are watching and if they are registred */
+ /* If they are not registred, we will override notification and show no availability */
+ if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, p->context, p->exten)) {
+ if(ast_device_state(hint) == AST_DEVICE_UNAVAILABLE)
+ hintstate = 0; /* Not registred */
+ }
+
+ strncpy(to, get_header(&p->initreq, "To"), sizeof(to)-1);
+ c = ditch_braces(to);
+ if (strncmp(c, "sip:", 4)) {
+ ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c);
+ return -1;
+ }
+ if ((a = strchr(c, ';'))) {
+ *a = '\0';
+ }
+ mto = c;
- c = ditch_braces(to);
- if (strncmp(c, "sip:", 4)) {
- ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c);
- return -1;
- }
- if ((a = strchr(c, ';'))) {
- *a = '\0';
- }
- mto = c;
+ if ((state==AST_EXTENSION_UNAVAILABLE) || (state==AST_EXTENSION_BUSY) || !hintstate)
+ state = 2; /* Closed */
+ else if (state==AST_EXTENSION_INUSE)
+ state = 1; /* In use */
+ else
+ state = 0; /* Open */
+ if (p->subscribed == 1 || p->subscribed == 3) {
add_header(&req, "Event", "presence");
add_header(&req, "Subscription-State", "active");
add_header(&req, "Content-Type", "application/xpidf+xml");
- if ((state==AST_EXTENSION_UNAVAILABLE) || (state==AST_EXTENSION_BUSY))
- state = 2;
- else if (state==AST_EXTENSION_INUSE)
- state = 1;
- else
- state = 0;
-
t = tmp;
maxbytes = sizeof(tmp);
bytes = snprintf(t, maxbytes, "\n");
@@ -4108,7 +4132,41 @@
t += bytes;
maxbytes -= bytes;
bytes = snprintf(t, maxbytes, "\n\n\n");
- } else {
+ } else if (p->subscribed == 4) { /* pidf+xml */
+ add_header(&req, "Event", "presence");
+ add_header(&req, "Subscription-State", "active");
+ add_header(&req, "Content-Type", "application/pidf+xml");
+ t = tmp;
+ maxbytes = sizeof(tmp);
+ bytes = snprintf(t, maxbytes, "\n");
+ t += bytes;
+ maxbytes -= bytes;
+ bytes = snprintf(t, maxbytes, "\n", mfrom);
+ t += bytes;
+ maxbytes -= bytes;
+ bytes = snprintf(t, maxbytes, "\n", p->exten);
+ t += bytes;
+ maxbytes -= bytes;
+ bytes = snprintf(t, maxbytes, "%s\n", mto);
+ t += bytes;
+ maxbytes -= bytes;
+
+ bytes = snprintf(t, maxbytes, "%s\n", !state ? "open" : "closed");
+ t += bytes;
+ maxbytes -= bytes;
+
+ bytes = snprintf(t, maxbytes, "%s", state != 0?"on-the-phone\n":"");
+ t += bytes;
+ maxbytes -= bytes;
+
+ bytes = snprintf(t, maxbytes, "%s", state == 1?"On the phone\n":"");
+ t += bytes;
+ maxbytes -= bytes;
+
+ bytes = snprintf(t, maxbytes, "\n\n");
+ t += bytes;
+ maxbytes -= bytes;
+ } else if (p->subscribed == 2) {
add_header(&req, "Event", "dialog");
add_header(&req, "Content-Type", "application/dialog-info+xml");
@@ -4127,6 +4185,8 @@
t += bytes;
maxbytes -= bytes;
bytes = snprintf(t, maxbytes, "\n\n");
+ t += bytes;
+ maxbytes -= bytes;
}
if (t > tmp + sizeof(tmp))
ast_log(LOG_WARNING, "Buffer overflow detected!! (Please file a bug report)\n");
@@ -4573,7 +4633,7 @@
manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", p->name);
register_peer_exten(p, 0);
p->expire = -1;
- ast_device_state_changed("SIP/%s", p->name);
+ ast_device_state_changed("SIP/%s", p->name); /* Activate notification */
if (ast_test_flag(p, SIP_SELFDESTRUCT) || ast_test_flag((&p->flags_page2), SIP_PAGE2_RTAUTOCLEAR)) {
ASTOBJ_MARK(p);
prune_peers();
@@ -5002,7 +5062,7 @@
#endif
)
return 0;
- if (!strcasecmp(method, "REGISTER")) {
+ if (!strcasecmp(method, "REGISTER") || !strcasecmp(method, "SUBSCRIBE")) {
/* On a REGISTER, we have to use 401 and its family of headers instead of 407 and its family
of headers -- GO SIP! Whoo hoo! Two things that do the same thing but are used in
different circumstances! What a surprise. */
@@ -5128,21 +5188,25 @@
return res;
}
-/*--- cb_extensionstate: Part of thte SUBSCRIBE support subsystem ---*/
+/*--- cb_extensionstate: Callback for the SUBSCRIBE (devicestate notification) support subsystem ---*/
+/* If you add an "hint" priority to the dial plan, you will get notifications
+ */
static int cb_extensionstate(char *context, char* exten, int state, void *data)
{
- struct sip_pvt *p = data;
- if (state == -1) {
- sip_scheddestroy(p, 15000);
- p->stateid = -1;
- return 0;
- }
-
- transmit_state_notify(p, state, 1);
+ struct sip_pvt *p = data; /* Pointer to the subscription "call" */
+
+ if (state == -1) {
+ sip_scheddestroy(p, 15000);
+ p->stateid = -1;
+ return 0;
+ }
+
+ transmit_state_notify(p, state, 1);
+ p->laststate = state;
- if (option_debug)
- ast_verbose(VERBOSE_PREFIX_1 "Extension Changed %s new state %d for Notify User %s\n", exten, state, p->username);
- return 0;
+ if (option_debug)
+ ast_verbose(VERBOSE_PREFIX_1 "Extension Changed %s new state %d for Notify User %s\n", exten, state, p->username);
+ return 0;
}
/*--- register_verify: Verify registration of user */
@@ -5154,6 +5218,7 @@
char iabuf[INET_ADDRSTRLEN];
char *name, *c;
char *t;
+
/* Terminate URI */
t = uri;
while(*t && (*t > 32) && (*t != ';'))
@@ -5162,6 +5227,7 @@
strncpy(tmp, get_header(req, "To"), sizeof(tmp) - 1);
c = ditch_braces(tmp);
+
/* Ditch ;user=phone */
name = strchr(c, ';');
if (name)
@@ -5222,7 +5288,7 @@
}
}
if (!res) {
- ast_device_state_changed("SIP/%s", peer->name);
+ ast_device_state_changed("SIP/%s", peer->name); /* Activate notification */
}
if (res < 0)
transmit_response(p, "403 Forbidden", &p->initreq);
@@ -5265,7 +5331,7 @@
char tmp[256] = "", *c, *a;
char tmpf[256]= "", *fr;
struct sip_request *req;
-
+
req = oreq;
if (!req)
req = &p->initreq;
@@ -5838,6 +5904,8 @@
strncpy(p->fullcontact, peer->fullcontact, sizeof(p->fullcontact) - 1);
if (!ast_strlen_zero(peer->context))
strncpy(p->context, peer->context, sizeof(p->context) - 1);
+ if (!ast_strlen_zero(peer->subscribecontext))
+ strncpy(p->subscribecontext, peer->subscribecontext, sizeof(p->subscribecontext) - 1);
strncpy(p->peersecret, peer->secret, sizeof(p->peersecret) - 1);
strncpy(p->peermd5secret, peer->md5secret, sizeof(p->peermd5secret) - 1);
strncpy(p->language, peer->language, sizeof(p->language) -1);
@@ -5906,14 +5974,26 @@
/*--- receive_message: Receive SIP MESSAGE method messages ---*/
-/* we handle messages within current calls currently */
+/* We only handle messages within current calls currently */
+/* Reference: RFC 3428 */
static void receive_message(struct sip_pvt *p, struct sip_request *req)
{
char buf[1024];
struct ast_frame f;
+ char *content_type;
+
+ content_type = get_header(req, "Content-Type");
+ if (strcmp(content_type, "text/plain")) {
+ /* No text/plain attachment */
+ transmit_response(p, "415 unsupported media type", req); /* Good enough or? */
+ ast_set_flag(p, SIP_NEEDDESTROY);
+ return;
+ }
if (get_msg_text(buf, sizeof(buf), req)) {
ast_log(LOG_WARNING, "Unable to retrieve text from %s\n", p->callid);
+ transmit_response(p, "202 Accepted", req);
+ ast_set_flag(p, SIP_NEEDDESTROY);
return;
}
if (p->owner) {
@@ -5926,7 +6006,15 @@
f.data = buf;
f.datalen = strlen(buf);
ast_queue_frame(p->owner, &f);
+ /* Should we respond somehow? */
+ transmit_response(p, "202 Accepted", req);
+ /* We should respond 202 accepted, since we relay the message */
+ } else {
+ ast_log(LOG_WARNING,"Received message to %s from %s, dropped it...\n Content-Type:%s\n Message: %s\n", get_header(req,"To"), get_header(req,"From"), content_type, buf);
+ transmit_response(p, "405 Method not allowed", req); /* Good enough or? */
}
+ ast_set_flag(p, SIP_NEEDDESTROY);
+ return;
}
/*--- sip_show_inuse: CLI Command to show calls within limits set by
@@ -6050,14 +6138,75 @@
#undef FORMAT
}
+static char mandescr_show_peers[] =
+"Description: Lists SIP peers in text format with details on current status.\n"
+"Variables: NONE\n";
+
+static char mandescr_xshow_peers[] =
+"Description: Lists SIP peers in XML format with details on current status.\n"
+" The XML format is under development, feedback welcome! /oej\n"
+"Variables: NONE\n";
+
+static int _sip_show_peers(int type, int fd, int argc, char *argv[]);
+
+/*--- manager_sip_show_peers: Show SIP peers in the manager API ---*/
+/* Inspired from chan_iax2 */
+static int manager_sip_show_peers( struct mansession *s, struct message *m )
+{
+ char *id = astman_get_header(m,"ActionID");
+ char *a[] = { "sip", "show", "peers" };
+ int ret;
+
+ ast_mutex_lock(&s->lock);
+ ast_cli(s->fd, "Response: Success\r\n");
+ if (id && !ast_strlen_zero(id))
+ ast_cli(s->fd, "ActionID: %s\r\n",id);
+ ret = _sip_show_peers(0, s->fd, 3, a );
+ ast_cli( s->fd, "\r\n\r\n" );
+ ast_mutex_unlock(&s->lock);
+ return ret;
+}
+
+/*--- manager_sip_xshow_peers: Show SIP peers in the manager API (XML)---*/
+static int manager_sip_xshow_peers( struct mansession *s, struct message *m )
+{
+ char *id = astman_get_header(m,"ActionID");
+ char *a[] = { "sip", "xshow", "peers" };
+ int ret;
+
+ ast_mutex_lock(&s->lock);
+ ast_cli(s->fd, "Response: Success\r\n");
+ if (id && !ast_strlen_zero(id))
+ ast_cli(s->fd, "ActionID: %s\r\n",id);
+ ast_cli(s->fd, "Content-type: text/xml\r\n");
+ ret = _sip_show_peers(1, s->fd, 3, a );
+ ast_cli( s->fd, "\r\n\r\n" );
+ ast_mutex_unlock(&s->lock);
+ return ret;
+}
+
+
/*--- sip_show_peers: CLI Show Peers command */
static int sip_show_peers(int fd, int argc, char *argv[])
{
+ return _sip_show_peers(0, fd, argc, argv);
+}
+
+/*--- sip_show_xpeers: CLI Show Peers command */
+static int sip_xshow_peers(int fd, int argc, char *argv[])
+{
+ return _sip_show_peers(1, fd, argc, argv);
+}
+
+/*--- _sip_show_peers: Execute sip show peers and xshow commands */
+static int _sip_show_peers(int type, int fd, int argc, char *argv[])
+{
regex_t regexbuf;
int havepattern = 0;
#define FORMAT2 "%-25.25s %-15.15s %-3.3s %-3.3s %-3.3s %-15.15s %-8s %-10s\n"
#define FORMAT "%-25.25s %-15.15s %-3.3s %-3.3s %-3.3s %-15.15s %-8d %-10s\n"
+#define FORMATXML "\n"
char name[256] = "";
char iabuf[INET_ADDRSTRLEN];
@@ -6076,7 +6225,11 @@
havepattern = 1;
}
- ast_cli(fd, FORMAT2, "Name/username", "Host", "Dyn", "Nat", "ACL", "Mask", "Port", "Status");
+ if (type == 0) { /* Normal list */
+ ast_cli(fd, FORMAT2, "Name/username", "Host", "Dyn", "Nat", "ACL", "Mask", "Port", "Status");
+ } else {
+ ast_cli(fd, "\n\n", havepattern?"on":"off");
+ }
ASTOBJ_CONTAINER_TRAVERSE(&peerl, 1, do {
char nm[20] = "";
@@ -6091,7 +6244,7 @@
}
ast_inet_ntoa(nm, sizeof(nm), iterator->mask);
- if (!ast_strlen_zero(iterator->username))
+ if (!ast_strlen_zero(iterator->username) && type==0)
snprintf(name, sizeof(name), "%s/%s", iterator->name, iterator->username);
else
strncpy(name, iterator->name, sizeof(name) - 1);
@@ -6131,20 +6284,36 @@
iterator->ha ? " A " : " ", /* permit/deny */
nm, ntohs(iterator->addr.sin_port), status);
- ast_cli(fd, FORMAT, name,
+ if (type == 0) {/* Normal CLI list */
+ ast_cli(fd, FORMAT, name,
iterator->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), iterator->addr.sin_addr) : "(Unspecified)",
ast_test_flag(iterator, SIP_DYNAMIC) ? " D " : " ", /* Dynamic or not? */
(ast_test_flag(iterator, SIP_NAT) & SIP_NAT_ROUTE) ? " N " : " ", /* NAT=yes? */
iterator->ha ? " A " : " ", /* permit/deny */
nm,
ntohs(iterator->addr.sin_port), status);
+ } else { /* XML format */
+ ast_cli(fd, FORMATXML, iterator->name,
+ iterator->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), iterator->addr.sin_addr) : "(Unspecified)",
+ ntohs(iterator->addr.sin_port),
+ ast_test_flag(iterator, SIP_DYNAMIC) ? "yes" : "no", /* Dynamic or not? */
+ (ast_test_flag(iterator, SIP_NAT) & SIP_NAT_ROUTE) ? "yes" : "no", /* NAT=yes? */
+ iterator->ha ? "yes" : "no", /* permit/deny */
+ nm,
+ status);
+
+ }
ASTOBJ_UNLOCK(iterator);
total_peers++;
} while(0) );
- ast_cli(fd,"%d sip peers [%d online , %d offline]\n",total_peers,peers_online,peers_offline);
+ if (type==0) {
+ ast_cli(fd,"%d sip peers [%d online , %d offline]\n",total_peers,peers_online,peers_offline);
+ } else {
+ ast_cli(fd,"\n");
+ }
if (havepattern)
regfree(®exbuf);
@@ -6228,9 +6397,59 @@
return RESULT_SUCCESS;
}
+static char mandescr_xshow_peer[] =
+"Description: Show one SIP peer in XML format with details on current status.\n"
+" The XML format is under development, feedback welcome! /oej\n"
+"Variables: \n"
+" Peer: \n";
+
+static int _sip_show_peer(int type, int fd, int argc, char *argv[]);
+
+/*--- manager_sip_xshow_peer: Show SIP peers in the manager API (xml format) ---*/
+static int manager_sip_xshow_peer( struct mansession *s, struct message *m )
+{
+ char *id = astman_get_header(m,"ActionID");
+ char *a[4];
+ char *peer;
+ int ret;
+
+ peer = astman_get_header(m,"Peer");
+ if (!peer || ast_strlen_zero(peer)) {
+ astman_send_error(s, m, "Peer: missing.\n");
+ return 0;
+ }
+ ast_mutex_lock(&s->lock);
+ a[0] = "sip";
+ a[1] = "show";
+ a[2] = "peer";
+ a[3] = peer;
+
+ /* Should respond with error if peer not found, really */
+ ast_cli(s->fd, "Response: Success\r\n");
+ if (id && !ast_strlen_zero(id))
+ ast_cli(s->fd, "ActionID: %s\r\n",id);
+ ret = _sip_show_peer(1, s->fd, 4, a );
+ ast_cli( s->fd, "\r\n\r\n" );
+ ast_mutex_unlock(&s->lock);
+ return ret;
+}
+
+
+
+/*--- sip_xshow_peer: Show one peer in detail ---*/
+static int sip_xshow_peer(int fd, int argc, char *argv[])
+{
+ return _sip_show_peer(1, fd, argc, argv);
+}
+
/*--- sip_show_peer: Show one peer in detail ---*/
static int sip_show_peer(int fd, int argc, char *argv[])
{
+ return _sip_show_peer(0, fd, argc, argv);
+}
+
+static int _sip_show_peer(int type, int fd, int argc, char *argv[])
+{
char status[30] = "";
char cbuf[256];
char iabuf[INET_ADDRSTRLEN];
@@ -6247,12 +6466,13 @@
load_realtime = (argc == 5 && !strcmp(argv[4], "load")) ? 1 : 0;
peer = find_peer(argv[3], NULL, load_realtime);
- if (peer) {
+ if (peer && type==0 ) { /* Normal listing */
ast_cli(fd,"\n\n");
ast_cli(fd, " * Name : %s\n", peer->name);
ast_cli(fd, " Secret : %s\n", ast_strlen_zero(peer->secret)?"":"");
ast_cli(fd, " MD5Secret : %s\n", ast_strlen_zero(peer->md5secret)?"":"");
ast_cli(fd, " Context : %s\n", peer->context);
+ ast_cli(fd, " SubContext : %s\n", peer->subscribecontext);
ast_cli(fd, " Language : %s\n", peer->language);
if (!ast_strlen_zero(peer->accountcode))
ast_cli(fd, " Accountcode : %s\n", peer->accountcode);
@@ -6317,7 +6537,7 @@
strncpy(status, "UNKNOWN", sizeof(status) - 1);
ast_cli(fd, "%s\n",status);
ast_cli(fd, " Useragent : %s\n", peer->useragent);
- ast_cli(fd, " Full Contact : %s\n", peer->fullcontact);
+ ast_cli(fd, " Reg. Contact : %s\n", peer->fullcontact);
if (peer->chanvars) {
ast_cli(fd, " Variables :\n");
for (v = peer->chanvars ; v ; v = v->next)
@@ -6325,6 +6545,83 @@
}
ast_cli(fd,"\n");
ASTOBJ_UNREF(peer,sip_destroy_peer);
+ } else if (peer && type == 1) { /* XML listing */
+ ast_cli(fd,"\n");
+ ast_cli(fd,"\n");
+ ast_cli(fd,"\n");
+ ast_cli(fd, "\n%s\n", peer->name);
+ ast_cli(fd, "%smd5\n", ast_strlen_zero(peer->secret)?"no":"yes");
+ ast_cli(fd, "%s\n", ast_strlen_zero(peer->md5secret)?"no":"yes");
+ ast_cli(fd, "%s\n", peer->context);
+ ast_cli(fd, "%s\n", peer->context);
+ ast_cli(fd, "%s\n", peer->language);
+ ast_cli(fd, "%s\n", peer->accountcode);
+ ast_cli(fd, "%s\n", ast_cdr_flags2str(peer->amaflags));
+ ast_cli(fd, "%s\n", peer->fromuser);
+ ast_cli(fd, "%s\n", peer->fromdomain);
+ ast_cli(fd, "");
+ print_group(fd, peer->callgroup);
+ ast_cli(fd, "\n");
+ ast_cli(fd, "");
+ print_group(fd, peer->pickupgroup);
+ ast_cli(fd, "");
+ ast_cli(fd, "%s\n", peer->mailbox);
+ ast_cli(fd, "%d\n", peer->lastmsgssent);
+ ast_cli(fd, "%d\n", peer->lastmsg);
+ ast_cli(fd, "%d\n", peer->incominglimit);
+ ast_cli(fd, "%d\n", peer->outgoinglimit);
+ ast_cli(fd, "%s\n", (ast_test_flag(peer, SIP_DYNAMIC)?"yes":"no"));
+ ast_cli(fd, "%s%s%d\n", peer->cid_name, peer->cid_num, peer->callingpres);
+ ast_cli(fd, "%d\n", peer->expire);
+ ast_cli(fd, "%d\n", peer->expiry);
+ ast_cli(fd, "%s\n", insecure2str(ast_test_flag(peer, SIP_INSECURE)));
+ ast_cli(fd, "%s\n", nat2str(ast_test_flag(peer, SIP_NAT)));
+ ast_cli(fd, "%s\n", (peer->ha?"yes":"no"));
+ ast_cli(fd, "%s\n", (ast_test_flag(peer, SIP_CAN_REINVITE)?"yes":"no"));
+ ast_cli(fd, "%s\n", (ast_test_flag(peer, SIP_PROMISCREDIR)?"yes":"no"));
+ ast_cli(fd, "%s\n", (ast_test_flag(peer, SIP_USEREQPHONE)?"yes":"no"));
+ /* - is enumerated */
+ ast_cli(fd, "%s\n", dtmfmode2str(ast_test_flag(peer, SIP_DTMF)));
+ ast_cli(fd, "%s\n", peer->tohost);
+ ast_cli(fd, "%s%d\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "", ntohs(peer->addr.sin_port));
+ ast_cli(fd, "%s%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port));
+ ast_cli(fd, "%s\n", peer->username);
+ ast_cli(fd, "");
+ ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
+ ast_cli(fd, "%s\n", codec_buf);
+ ast_cli(fd, "");
+ pref = &peer->prefs;
+ for(x = 0; x < 32 ; x++) {
+ codec = ast_codec_pref_index(pref,x);
+ if(!codec)
+ break;
+ ast_cli(fd, "%s", ast_getformatname(codec));
+ if(x < 31 && ast_codec_pref_index(pref,x+1))
+ ast_cli(fd, ",");
+ }
+ ast_cli(fd, "");
+
+ ast_cli(fd, "");
+ if (peer->lastms < 0)
+ strncpy(status, "UNREACHABLE", sizeof(status) - 1);
+ else if (peer->lastms > peer->maxms)
+ snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms);
+ else if (peer->lastms)
+ snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms);
+ else
+ strncpy(status, "UNKNOWN", sizeof(status) - 1);
+ ast_cli(fd, "%s\n",status);
+ ast_cli(fd, "%s\n", peer->useragent);
+ ast_cli(fd, "%s\n", peer->fullcontact);
+ if (peer->chanvars) {
+ ast_cli(fd, "\n");
+ for (v = peer->chanvars ; v ; v = v->next)
+ ast_cli(fd, " %s%s\n", v->name, v->value);
+ ast_cli(fd, "\n");
+ }
+ ast_cli(fd,"\n\n");
+ ASTOBJ_UNREF(peer,sip_destroy_peer);
+
} else {
ast_cli(fd,"Peer %s not found.\n", argv[3]);
ast_cli(fd,"\n");
@@ -6436,7 +6733,8 @@
static int __sip_show_channels(int fd, int argc, char *argv[], int subscriptions)
{
-#define FORMAT3 "%-15.15s %-10.10s %-21.21s %-15.15s\n"
+#define FORMAT4 "%-15.15s %-10.10s %-21.21s %-15.15s %10s\n"
+#define FORMAT3 "%-15.15s %-10.10s %-21.21s %-15.15s %2d (%d)\n"
#define FORMAT2 "%-15.15s %-10.10s %-11.11s %-11.11s %s %s\n"
#define FORMAT "%-15.15s %-10.10s %-11.11s %5.5d/%5.5d %-6.6s%s %s\n"
struct sip_pvt *cur;
@@ -6449,7 +6747,7 @@
if (!subscriptions)
ast_cli(fd, FORMAT2, "Peer", "User/ANR", "Call ID", "Seq (Tx/Rx)", "Format", "Last Msg");
else
- ast_cli(fd, FORMAT3, "Peer", "User", "Call ID", "URI");
+ ast_cli(fd, FORMAT4, "Peer", "User", "Call ID", "Extension", "Last State");
while (cur) {
if (!cur->subscribed && !subscriptions) {
ast_cli(fd, FORMAT, ast_inet_ntoa(iabuf, sizeof(iabuf), cur->sa.sin_addr),
@@ -6464,7 +6762,8 @@
if (cur->subscribed && subscriptions) {
ast_cli(fd, FORMAT3, ast_inet_ntoa(iabuf, sizeof(iabuf), cur->sa.sin_addr),
ast_strlen_zero(cur->username) ? ( ast_strlen_zero(cur->cid_num) ? "(None)" : cur->cid_num ) : cur->username,
- cur->callid, cur->uri);
+ cur->callid, cur->exten, cur->laststate, cur->subscribed);
+ numchans++;
}
cur = cur->next;
@@ -7164,6 +7463,16 @@
" Lists all known SIP peers.\n"
" Optional regular expression pattern is used to filter the peer list.\n";
+static char xshow_peers_usage[] =
+"Usage: sip xshow peers [pattern]\n"
+" Lists all known SIP peers in XML format.\n"
+" Optional regular expression pattern is used to filter the peer list.\n";
+
+static char xshow_peer_usage[] =
+"Usage: sip xshow peer [load]\n"
+" Lists all details on one SIP peer and the current status in XML format.\n"
+" Option \"load\" forces lookup of peer in realtime storage.\n";
+
static char show_peer_usage[] =
"Usage: sip show peer [load]\n"
" Lists all details on one SIP peer and the current status.\n"
@@ -7234,8 +7543,12 @@
{ { "sip", "debug", "ip", NULL }, sip_do_debug, "Enable SIP debugging on IP", debug_usage };
static struct ast_cli_entry cli_debug_peer =
{ { "sip", "debug", "peer", NULL }, sip_do_debug, "Enable SIP debugging on Peername", debug_usage, complete_sip_debug_peer };
+static struct ast_cli_entry cli_xshow_peer =
+ { { "sip", "xshow", "peer", NULL }, sip_xshow_peer, "Show details on specific SIP peer (XML format)", xshow_peer_usage, complete_sip_show_peer };
static struct ast_cli_entry cli_show_peer =
{ { "sip", "show", "peer", NULL }, sip_show_peer, "Show details on specific SIP peer", show_peer_usage, complete_sip_show_peer };
+static struct ast_cli_entry cli_xshow_peers =
+ { { "sip", "xshow", "peers", NULL }, sip_xshow_peers, "List defined SIP peers in XML format", xshow_peers_usage };
static struct ast_cli_entry cli_show_peers =
{ { "sip", "show", "peers", NULL }, sip_show_peers, "Show defined SIP peers", show_peers_usage };
static struct ast_cli_entry cli_prune_realtime =
@@ -7370,7 +7683,7 @@
peer->lastms = pingtime;
peer->call = NULL;
if (statechanged) {
- ast_device_state_changed("SIP/%s", peer->name);
+ ast_device_state_changed("SIP/%s", peer->name); /* Activate notification */
if (newstate == 2) {
manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Lagged\r\nTime: %d\r\n", peer->name, pingtime);
} else {
@@ -8279,16 +8592,12 @@
ast_set_flag(p, SIP_NEEDDESTROY);
transmit_response(p, "200 OK", req);
} else if (!strcasecmp(cmd, "MESSAGE")) {
- if (p->lastinvite) {
- if (!ignore) {
- if (debug)
- ast_verbose("Receiving message!\n");
- receive_message(p, req);
- }
- transmit_response(p, "200 OK", req);
+ if (!ignore) {
+ if (debug)
+ ast_verbose("Receiving message!\n");
+ receive_message(p, req);
} else {
- transmit_response(p, "405 Method Not Allowed", req);
- ast_set_flag(p, SIP_NEEDDESTROY);
+ transmit_response(p, "202 ACCEPTED", req);
}
} else if (!strcasecmp(cmd, "SUBSCRIBE")) {
if (!ignore) {
@@ -8316,8 +8625,11 @@
return 0;
}
/* Initialize the context if it hasn't been already */
- if (ast_strlen_zero(p->context))
+ if (p->subscribecontext && !ast_strlen_zero(p->subscribecontext)) {
+ strncpy(p->context, p->subscribecontext, sizeof(p->context) - 1);
+ } else if (ast_strlen_zero(p->context))
strncpy(p->context, default_context, sizeof(p->context) - 1);
+
/* Get destination right away */
gotdest = get_destination(p, NULL);
build_contact(p);
@@ -8328,12 +8640,34 @@
transmit_response(p, "484 Address Incomplete", req);
ast_set_flag(p, SIP_NEEDDESTROY);
} else {
+ char *event;
+ event = get_header(req, "Event"); /* Get the even pacīkage name */
+
/* Initialize tag */
p->tag = rand();
- if (!strcmp(get_header(req, "Accept"), "application/dialog-info+xml"))
- p->subscribed = 2;
- else if (!strcmp(get_header(req, "Accept"), "application/simple-message-summary")) {
- /* Looks like they actually want a mailbox */
+ if (!strcmp(event,"presence")) { /* Presence, RFC 3842 */
+ char *accept = get_header(req, "Accept");
+ /* Header from Xten Eye-beam
+ Accept: multipart/related, application/rlmi+xml, application/pidf+xml, application/xpidf+xml
+ */
+ if (strstr(accept, "application/dialog-info+xml"))
+ p->subscribed = 2;
+ /* IETF draft: draft-ietf-sipping-dialog-package-05.txt */
+ /* Should not be used for SUBSCRIBE, but anyway */
+ else if (!p->subscribed && strstr(accept, "application/pidf+xml"))
+ p->subscribed = 4; /* RFC 3863 format */
+ else if (!p->subscribed && strstr(accept, "application/xpidf+xml"))
+ p->subscribed = 1; /* Early pre-RFC 3863 format with MSN additions (Microsoft Messenger) */
+ else if (!p->subscribed && strstr(accept, "application/cpim-pidf+xml"))
+ p->subscribed = 3; /* RFC 3863 format */
+ else {
+ /* Can't find a format for events that we know about */
+ transmit_response(p, "489 Bad Event", req);
+ ast_set_flag(p, SIP_NEEDDESTROY);
+ return 0;
+ }
+ } else if (!strcmp(event, "message-summary") && !strcmp(get_header(req, "Accept"), "application/simple-message-summary")) {
+ /* Looks like they actually want a mailbox (RFC 3842) */
/* At this point, we should check if they subscribe to a mailbox that
has the same extension as the peer or the mailbox id. If we configure
@@ -8359,10 +8693,14 @@
ast_set_flag(p, SIP_NEEDDESTROY);
}
return 0;
- } else
- p->subscribed = 1;
- if (p->subscribed)
+ } else {
+ transmit_response(p, "489 Bad Event", req);
+ ast_set_flag(p, SIP_NEEDDESTROY);
+ return 0;
+ }
+ if (p->subscribed) {
p->stateid = ast_extension_state_add(p->context, p->exten, cb_extensionstate, p);
+ }
}
} else
@@ -8371,16 +8709,15 @@
if (!ignore && p)
p->lastinvite = seqno;
if (p && !ast_test_flag(p, SIP_NEEDDESTROY)) {
- if (!(p->expiry = atoi(get_header(req, "Expires")))) {
+ if (!(p->expiry = atoi(get_header(req, "Expires")))) {
transmit_response(p, "200 OK", req);
ast_set_flag(p, SIP_NEEDDESTROY);
return 0;
- }
- /* The next line can be removed if the SNOM200 Expires bug is fixed */
- if (p->subscribed == 1) {
- if (p->expiry>max_expiry)
+ }
+ if (p->subscribed != 0) {
+ if (p->expiry > max_expiry)
p->expiry = max_expiry;
- }
+ }
/* Go ahead and free RTP port */
if (p->rtp) {
ast_rtp_destroy(p->rtp);
@@ -8390,9 +8727,14 @@
ast_rtp_destroy(p->vrtp);
p->vrtp = NULL;
}
- transmit_response(p, "200 OK", req);
- sip_scheddestroy(p, (p->expiry+10)*1000);
- transmit_state_notify(p, ast_extension_state(NULL, p->context, p->exten),1);
+ if (sipdebug || option_debug > 1)
+ ast_log(LOG_DEBUG, "Adding subscription for extension %s context %s for peer %s\n", p->exten, p->context, p->username);
+
+ transmit_response(p, "200 OK", req);
+ /* Set timer for destruction of call at expiration */
+ sip_scheddestroy(p, (p->expiry+10)*1000);
+ /* Send first notification */
+ transmit_state_notify(p, ast_extension_state(NULL, p->context, p->exten),1);
}
} else if (!strcasecmp(cmd, "INFO")) {
if (!ignore) {
@@ -8750,7 +9092,7 @@
sip_destroy(peer->call);
peer->call = NULL;
peer->lastms = -1;
- ast_device_state_changed("SIP/%s", peer->name);
+ ast_device_state_changed("SIP/%s", peer->name); /* Activate notification */
/* Try again quickly */
peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_NOTOK, sip_poke_peer_s, peer);
return 0;
@@ -8845,13 +9187,35 @@
if (p) {
found++;
res = AST_DEVICE_UNAVAILABLE;
+ if (option_debug > 2)
+ ast_log(LOG_DEBUG, "Checking device state for peer %s\n", dest);
if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) &&
(!p->maxms || ((p->lastms > -1) && (p->lastms <= p->maxms)))) {
- /* peer found and valid */
- res = AST_DEVICE_UNKNOWN;
+ /* Peer is registred, or have default IP address
+ and a valid registration */
+
+
+ /* Now check if we know anything about the state. The only way is by implementing
+ call control with incominglimit=X in sip.conf where X > 0
+ Check if the device has incominglimit, and if qualify=on, if the device
+ is reachable
+ */
+ if (p->incominglimit && (p->lastms == 0 || p->lastms <= p->maxms)) {
+ /* Free for a call */
+ res = AST_DEVICE_NOT_INUSE;
+
+ if (p->inUse) { /* On a call */
+ res = AST_DEVICE_BUSY;
+ }
+ } else {
+ /* peer found and valid, state unknown */
+ res = AST_DEVICE_UNKNOWN;
+ }
}
}
if (!p && !found) {
+ if (option_debug > 2)
+ ast_log(LOG_DEBUG, "Checking device state for DNS host %s\n", dest);
hp = ast_gethostbyname(host, &ahp);
if (hp)
res = AST_DEVICE_UNKNOWN;
@@ -9216,6 +9580,7 @@
peer->chanvars = NULL;
}
strncpy(peer->context, default_context, sizeof(peer->context)-1);
+ strncpy(peer->subscribecontext, default_subscribecontext, sizeof(peer->subscribecontext)-1);
strncpy(peer->language, default_language, sizeof(peer->language)-1);
strncpy(peer->musicclass, global_musicclass, sizeof(peer->musicclass)-1);
ast_copy_flags(peer, &global_flags, SIP_USEREQPHONE);
@@ -9258,9 +9623,11 @@
strncpy(peer->md5secret, v->value, sizeof(peer->md5secret)-1);
else if (!strcasecmp(v->name, "callerid")) {
ast_callerid_split(v->value, peer->cid_name, sizeof(peer->cid_name), peer->cid_num, sizeof(peer->cid_num));
- } else if (!strcasecmp(v->name, "context"))
+ } else if (!strcasecmp(v->name, "context")) {
strncpy(peer->context, v->value, sizeof(peer->context)-1);
- else if (!strcasecmp(v->name, "fromdomain"))
+ } else if (!strcasecmp(v->name, "subscribecontext")) {
+ strncpy(peer->subscribecontext, v->value, sizeof(peer->subscribecontext)-1);
+ } else if (!strcasecmp(v->name, "fromdomain"))
strncpy(peer->fromdomain, v->value, sizeof(peer->fromdomain)-1);
else if (!strcasecmp(v->name, "usereqphone"))
ast_set2_flag(peer, ast_true(v->value), SIP_USEREQPHONE);
@@ -9456,6 +9823,7 @@
/* Initialize some reasonable defaults at SIP reload */
strncpy(default_context, DEFAULT_CONTEXT, sizeof(default_context) - 1);
+ default_subscribecontext[0] = '\0';
default_language[0] = '\0';
default_fromdomain[0] = '\0';
default_qualify = 0;
@@ -10174,7 +10542,9 @@
ast_cli_register(&cli_show_history);
ast_cli_register(&cli_prune_realtime);
ast_cli_register(&cli_show_peer);
+ ast_cli_register(&cli_xshow_peer);
ast_cli_register(&cli_show_peers);
+ ast_cli_register(&cli_xshow_peers);
ast_cli_register(&cli_show_registry);
ast_cli_register(&cli_debug);
ast_cli_register(&cli_debug_ip);
@@ -10184,6 +10554,9 @@
ast_cli_register(&cli_no_history);
ast_cli_register(&cli_sip_reload);
ast_cli_register(&cli_inuse_show);
+ ast_manager_register2( "SIPpeers", 0, manager_sip_show_peers, "List SIP Peers", mandescr_show_peers );
+ ast_manager_register2( "SIPpeers-xml", 0, manager_sip_xshow_peers, "List SIP Peers in XML format" , mandescr_xshow_peers);
+ ast_manager_register2( "SIPpeer-xml", 0, manager_sip_xshow_peer, "Show SIP Peer in XML format" , mandescr_xshow_peer);
sip_rtp.type = channeltype;
ast_rtp_proto_register(&sip_rtp);
ast_register_application(app_dtmfmode, sip_dtmfmode, synopsis_dtmfmode, descrip_dtmfmode);
@@ -10216,6 +10589,7 @@
ast_cli_unregister(&cli_prune_realtime);
ast_cli_unregister(&cli_show_peer);
ast_cli_unregister(&cli_show_peers);
+ ast_cli_unregister(&cli_xshow_peers);
ast_cli_unregister(&cli_show_registry);
ast_cli_unregister(&cli_show_subscriptions);
ast_cli_unregister(&cli_debug);
@@ -10228,6 +10602,9 @@
ast_cli_unregister(&cli_inuse_show);
ast_rtp_proto_unregister(&sip_rtp);
ast_channel_unregister(channeltype);
+ ast_manager_unregister("SIPpeers");
+ ast_manager_unregister("SIPpeers-xml");
+ ast_manager_unregister("SIPpeer-xml");
if (!ast_mutex_lock(&iflock)) {
/* Hangup all interfaces if they have an owner */
p = iflist;