SIP state notify reorganization
authorDavid Vossel <dvossel@digium.com>
Thu, 16 Apr 2009 19:30:23 +0000 (19:30 +0000)
committerDavid Vossel <dvossel@digium.com>
Thu, 16 Apr 2009 19:30:23 +0000 (19:30 +0000)
What I've done here is simply break up how a state NOTIFY is built.  Originally both the XML and sip header information were built within the same function.  While this does work, it does not allow for the creation of multipart/related message bodies that can contain multiple XML entries with only one sip header.  Now a separate function builds the XML for each notify.  This patch also makes maintaining and modifying state notifications in the future much less of a pain.

Review: http://reviewboard.digium.com/r/224/

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@188742 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c

index dbbdbcf..71aabf6 100644 (file)
@@ -10351,22 +10351,14 @@ static int find_calling_channel(struct ast_channel *c, void *data) {
                        (sip_cfg.notifycid == IGNORE_CONTEXT || !strcasecmp(c->context, p->context)));
 }
 
-/*! \brief Used in the SUBSCRIBE notification subsystem (RFC3265) */
-static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout)
+/*! \brief Builds XML portion of state NOTIFY messages */
+static void state_notify_build_xml(int state, int full, const char *exten, const char *context, struct ast_str **tmp, struct sip_pvt *p, int subscribed, const char *mfrom, const char *mto)
 {
-       struct ast_str *tmp = ast_str_alloca(4000);
-       char from[256], to[256];
-       char *c, *mfrom, *mto;
-       struct sip_request req;
-       char hint[AST_MAX_EXTENSION];
-       char *statestring = "terminated";
-       const struct cfsubscription_types *subscriptiontype;
        enum state { NOTIFY_OPEN, NOTIFY_INUSE, NOTIFY_CLOSED } local_state = NOTIFY_OPEN;
-       char *pidfstate = "--";
-       char *pidfnote= "Ready";
-       
-       memset(from, 0, sizeof(from));
-       memset(to, 0, sizeof(to));
+       const char *statestring = "terminated";
+       const char *pidfstate = "--";
+       const char *pidfnote= "Ready";
+       char hint[AST_MAX_EXTENSION];
 
        switch (state) {
        case (AST_EXTENSION_RINGING | AST_EXTENSION_INUSE):
@@ -10411,10 +10403,8 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim
                break;
        }
 
-       subscriptiontype = find_subscription_type(p->subscribed);
-       
        /* Check which device/devices we are watching  and if they are registered */
-       if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, p->context, p->exten)) {
+       if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten)) {
                char *hint2 = hint, *individual_hint = NULL;
                int hint_count = 0, unavailable_count = 0;
 
@@ -10435,83 +10425,43 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim
                }
        }
 
-       ast_copy_string(from, get_header(&p->initreq, "From"), sizeof(from));
-       c = get_in_brackets(from);
-       if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5)) {
-               ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", c);
-               return -1;
-       }
-       
-       mfrom = remove_uri_parameters(c);
-
-       ast_copy_string(to, get_header(&p->initreq, "To"), sizeof(to));
-       c = get_in_brackets(to);
-       if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5)) {
-               ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", c);
-               return -1;
-       }
-       mto = remove_uri_parameters(c);
-
-       reqprep(&req, p, SIP_NOTIFY, 0, 1);
-
-       
-       add_header(&req, "Event", subscriptiontype->event);
-       add_header(&req, "Content-Type", subscriptiontype->mediatype);
-       switch(state) {
-       case AST_EXTENSION_DEACTIVATED:
-               if (timeout)
-                       add_header(&req, "Subscription-State", "terminated;reason=timeout");
-               else {
-                       add_header(&req, "Subscription-State", "terminated;reason=probation");
-                       add_header(&req, "Retry-After", "60");
-               }
-               break;
-       case AST_EXTENSION_REMOVED:
-               add_header(&req, "Subscription-State", "terminated;reason=noresource");
-               break;
-       default:
-               if (p->expiry)
-                       add_header(&req, "Subscription-State", "active");
-               else    /* Expired */
-                       add_header(&req, "Subscription-State", "terminated;reason=timeout");
-       }
-       switch (p->subscribed) {
+       switch (subscribed) {
        case XPIDF_XML:
        case CPIM_PIDF_XML:
-               ast_str_append(&tmp, 0,
+               ast_str_append(tmp, 0,
                        "<?xml version=\"1.0\"?>\n"
                        "<!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n"
                        "<presence>\n");
-               ast_str_append(&tmp, 0, "<presentity uri=\"%s;method=SUBSCRIBE\" />\n", mfrom);
-               ast_str_append(&tmp, 0, "<atom id=\"%s\">\n", p->exten);
-               ast_str_append(&tmp, 0, "<address uri=\"%s;user=ip\" priority=\"0.800000\">\n", mto);
-               ast_str_append(&tmp, 0, "<status status=\"%s\" />\n", (local_state ==  NOTIFY_OPEN) ? "open" : (local_state == NOTIFY_INUSE) ? "inuse" : "closed");
-               ast_str_append(&tmp, 0, "<msnsubstatus substatus=\"%s\" />\n", (local_state == NOTIFY_OPEN) ? "online" : (local_state == NOTIFY_INUSE) ? "onthephone" : "offline");
-               ast_str_append(&tmp, 0, "</address>\n</atom>\n</presence>\n");
+               ast_str_append(tmp, 0, "<presentity uri=\"%s;method=SUBSCRIBE\" />\n", mfrom);
+               ast_str_append(tmp, 0, "<atom id=\"%s\">\n", exten);
+               ast_str_append(tmp, 0, "<address uri=\"%s;user=ip\" priority=\"0.800000\">\n", mto);
+               ast_str_append(tmp, 0, "<status status=\"%s\" />\n", (local_state ==  NOTIFY_OPEN) ? "open" : (local_state == NOTIFY_INUSE) ? "inuse" : "closed");
+               ast_str_append(tmp, 0, "<msnsubstatus substatus=\"%s\" />\n", (local_state == NOTIFY_OPEN) ? "online" : (local_state == NOTIFY_INUSE) ? "onthephone" : "offline");
+               ast_str_append(tmp, 0, "</address>\n</atom>\n</presence>\n");
                break;
        case PIDF_XML: /* Eyebeam supports this format */
-               ast_str_append(&tmp, 0,
+               ast_str_append(tmp, 0,
                        "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
                        "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \nxmlns:pp=\"urn:ietf:params:xml:ns:pidf:person\"\nxmlns:es=\"urn:ietf:params:xml:ns:pidf:rpid:status:rpid-status\"\nxmlns:ep=\"urn:ietf:params:xml:ns:pidf:rpid:rpid-person\"\nentity=\"%s\">\n", mfrom);
-               ast_str_append(&tmp, 0, "<pp:person><status>\n");
+               ast_str_append(tmp, 0, "<pp:person><status>\n");
                if (pidfstate[0] != '-')
-                       ast_str_append(&tmp, 0, "<ep:activities><ep:%s/></ep:activities>\n", pidfstate);
-               ast_str_append(&tmp, 0, "</status></pp:person>\n");
-               ast_str_append(&tmp, 0, "<note>%s</note>\n", pidfnote); /* Note */
-               ast_str_append(&tmp, 0, "<tuple id=\"%s\">\n", p->exten); /* Tuple start */
-               ast_str_append(&tmp, 0, "<contact priority=\"1\">%s</contact>\n", mto);
+                       ast_str_append(tmp, 0, "<ep:activities><ep:%s/></ep:activities>\n", pidfstate);
+               ast_str_append(tmp, 0, "</status></pp:person>\n");
+               ast_str_append(tmp, 0, "<note>%s</note>\n", pidfnote); /* Note */
+               ast_str_append(tmp, 0, "<tuple id=\"%s\">\n", exten); /* Tuple start */
+               ast_str_append(tmp, 0, "<contact priority=\"1\">%s</contact>\n", mto);
                if (pidfstate[0] == 'b') /* Busy? Still open ... */
-                       ast_str_append(&tmp, 0, "<status><basic>open</basic></status>\n");
+                       ast_str_append(tmp, 0, "<status><basic>open</basic></status>\n");
                else
-                       ast_str_append(&tmp, 0, "<status><basic>%s</basic></status>\n", (local_state != NOTIFY_CLOSED) ? "open" : "closed");
-               ast_str_append(&tmp, 0, "</tuple>\n</presence>\n");
+                       ast_str_append(tmp, 0, "<status><basic>%s</basic></status>\n", (local_state != NOTIFY_CLOSED) ? "open" : "closed");
+               ast_str_append(tmp, 0, "</tuple>\n</presence>\n");
                break;
        case DIALOG_INFO_XML: /* SNOM subscribes in this format */
-               ast_str_append(&tmp, 0, "<?xml version=\"1.0\"?>\n");
-               ast_str_append(&tmp, 0, "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\"%d\" state=\"%s\" entity=\"%s\">\n", p->dialogver++, full ? "full" : "partial", mto);
+               ast_str_append(tmp, 0, "<?xml version=\"1.0\"?>");
+               ast_str_append(tmp, 0, "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\"%d\" state=\"%s\" entity=\"%s\">", p->dialogver, full ? "full" : "partial", mto);
                if ((state & AST_EXTENSION_RINGING) && sip_cfg.notifyringing) {
-                       const char *local_display = p->exten;
-                       char *local_target = mto;
+                       const char *local_display = exten;
+                       char *local_target = ast_strdupa(mto);
 
                        /* There are some limitations to how this works.  The primary one is that the
                           callee must be dialing the same extension that is being monitored.  Simply dialing
@@ -10531,7 +10481,7 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim
 
                        /* We create a fake call-id which the phone will send back in an INVITE
                           Replaces header which we can grab and do some magic with. */
-                       ast_str_append(&tmp, 0, 
+                       ast_str_append(tmp, 0, 
                                        "<dialog id=\"%s\" call-id=\"pickup-%s\" direction=\"recipient\">\n"
                                        "<remote>\n"
                                        /* See the limitations of this above.  Luckily the phone seems to still be
@@ -10543,17 +10493,98 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim
                                        "<identity>%s</identity>\n"
                                        "<target uri=\"%s\"/>\n"
                                        "</local>\n",
-                                       p->exten, p->callid, local_display, local_target, local_target, mto, mto);
+                                       exten, p->callid, local_display, local_target, local_target, mto, mto);
                } else {
-                       ast_str_append(&tmp, 0, "<dialog id=\"%s\">\n", p->exten);
+                       ast_str_append(tmp, 0, "<dialog id=\"%s\">", exten);
                }
-               ast_str_append(&tmp, 0, "<state>%s</state>\n", statestring);
-               if (state == AST_EXTENSION_ONHOLD) {
-                       ast_str_append(&tmp, 0, "<local>\n<target uri=\"%s\">\n"
-                                                       "<param pname=\"+sip.rendering\" pvalue=\"no\"/>\n"
-                                                       "</target>\n</local>\n", mto);
+               ast_str_append(tmp, 0, "<state>%s</state>\n", statestring);
+               if (state == AST_EXTENSION_ONHOLD) { //todohere, this seems weird
+                               ast_str_append(tmp, 0, "<local>\n<target uri=\"%s\">\n"
+                                                           "<param pname=\"+sip.rendering\" pvalue=\"no\"/>\n"
+                                                           "</target>\n</local>\n", mto);
+               }
+               ast_str_append(tmp, 0, "</dialog>\n</dialog-info>\n");
+               break;
+       case NONE:
+       default:
+               break;
+       }
+}
+
+
+/*! \brief Used in the SUBSCRIBE notification subsystem (RFC3265) */
+static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout)
+{
+       struct ast_str *tmp = ast_str_alloca(4000);
+       char from[256], to[256];
+       char *c, *mfrom, *mto;
+       struct sip_request req;
+       const struct cfsubscription_types *subscriptiontype;
+
+       memset(from, 0, sizeof(from));
+       memset(to, 0, sizeof(to));
+
+       subscriptiontype = find_subscription_type(p->subscribed);
+
+       ast_copy_string(from, get_header(&p->initreq, "From"), sizeof(from));
+       c = get_in_brackets(from);
+       if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5)) {
+               ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", c);
+               return -1;
+       }
+
+       mfrom = remove_uri_parameters(c);
+
+       ast_copy_string(to, get_header(&p->initreq, "To"), sizeof(to));
+       c = get_in_brackets(to);
+       if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5)) {
+               ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", c);
+               return -1;
+       }
+       mto = remove_uri_parameters(c);
+
+       reqprep(&req, p, SIP_NOTIFY, 0, 1);
+
+       add_header(&req, "Event", subscriptiontype->event);
+       add_header(&req, "Content-Type", subscriptiontype->mediatype);
+       switch(state) {
+       case AST_EXTENSION_DEACTIVATED:
+               if (timeout)
+                       add_header(&req, "Subscription-State", "terminated;reason=timeout");
+               else {
+                       add_header(&req, "Subscription-State", "terminated;reason=probation");
+                       add_header(&req, "Retry-After", "60");
                }
-               ast_str_append(&tmp, 0, "</dialog>\n</dialog-info>\n");
+               break;
+       case AST_EXTENSION_REMOVED:
+               add_header(&req, "Subscription-State", "terminated;reason=noresource");
+               break;
+       default:
+               if (p->expiry)
+                       add_header(&req, "Subscription-State", "active");
+               else    /* Expired */
+                       add_header(&req, "Subscription-State", "terminated;reason=timeout");
+       }
+
+       switch (p->subscribed) {
+       case XPIDF_XML:
+       case CPIM_PIDF_XML:
+               add_header(&req, "Event", subscriptiontype->event);
+               state_notify_build_xml(state, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
+               add_header(&req, "Content-Type", subscriptiontype->mediatype);
+               p->dialogver++;
+               break;
+       case PIDF_XML: /* Eyebeam supports this format */
+               add_header(&req, "Event", subscriptiontype->event);
+               state_notify_build_xml(state, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
+               add_header(&req, "Content-Type", subscriptiontype->mediatype);
+               p->dialogver++;
+               break;
+       case DIALOG_INFO_XML: /* SNOM subscribes in this format */
+               add_header(&req, "Event", subscriptiontype->event);
+               state_notify_build_xml(state, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
+               add_header(&req, "Content-Type", subscriptiontype->mediatype);
+               p->dialogver++;
                break;
        case NONE:
        default: